class AccountStateServiceImpl implements AccountStateService {

    @Override
	public Fun.Tuple2<Block, Transaction> generateGenesisBlock(String initialAddress, BigInteger initialValue, AppState state, AppContext context) {
        logger.traceEntry("params: {} {} {} {}", initialAddress, initialValue, state, context);

        PrivateKey privateKey = context.getPrivateKey();

        Util.check(!(initialAddress == null || initialAddress.isEmpty()), "initialAddress!=null");
        Util.check(!(initialValue.compareTo(BigInteger.ZERO) < 0), "initialValue is less than zero");
        Util.check(privateKey != null, "privateKey!=null");

        if (initialValue.compareTo(Util.VALUE_MINTING) > 0) {
            initialValue = Util.VALUE_MINTING;
        }

        PrivateKey mintingPrivateKey = AppServiceProvider.getShardingService().getPrivateKeyForMinting(state.getShard());
        PublicKey mintingPublicKey = AppServiceProvider.getShardingService().getPublicKeyForMinting(state.getShard());

        logger.trace("Creating mint transaction...");
        Transaction transactionMint = AppServiceProvider.getTransactionService().generateTransaction(mintingPublicKey,
                new PublicKey(Util.hexStringToByteArray(initialAddress)), initialValue, BigInteger.ZERO);
        logger.trace("Signing mint transaction...");
        AppServiceProvider.getTransactionService().signTransaction(transactionMint, mintingPrivateKey.getValue(), mintingPublicKey.getValue());

        logger.trace("Generating genesis block...");
        Block genesisBlock = new Block();
        genesisBlock.setShard(state.getShard());
        genesisBlock.setNonce(BigInteger.ZERO);

        BlockUtil.addTransactionInBlock(genesisBlock, transactionMint);

        logger.trace("Setting timestamp and round...");
        NTPClient ntpClient = state.getNtpClient();
        genesisBlock.setTimestamp(AppServiceProvider.getChronologyService().getSynchronizedTime(ntpClient));
        genesisBlock.setRoundIndex(0);

        List<String> nodeList = new ArrayList<>();

        String self = state.getConnection().getPeer().peerID().toString();
        nodeList.add(self);

        genesisBlock.setPeers(nodeList);

        logger.debug("done added {} peers to genesis block", genesisBlock.getPeers());

        logger.trace("Computing state root hash...");
        try {

            AccountsContext accountsContext = new AccountsContext();
            accountsContext.setShard(state.getShard());
            Accounts accountsTemp = new Accounts(accountsContext, new AccountsPersistenceUnit<>(accountsContext.getDatabasePath()));

            ExecutionService executionService = AppServiceProvider.getExecutionService();
            ExecutionReport executionReport = executionService.processTransaction(transactionMint, accountsTemp);
            if (!executionReport.isOk()) {
                return logger.traceExit((Fun.Tuple2<Block, Transaction>) null);
            }
            genesisBlock.setAppStateHash(accountsTemp.getAccountsPersistenceUnit().getRootHash());
            AppBlockManager.instance().signBlock(genesisBlock, privateKey);
            accountsTemp.getAccountsPersistenceUnit().close();
            logger.trace("Genesis block created!");
        } catch (Exception ex) {
            logger.catching(ex);
            logger.traceExit((Fun.Tuple2<Block, Transaction>) null);
        }

        return logger.traceExit(new Fun.Tuple2<>(genesisBlock, transactionMint));
    }

}