Search in sources :

Example 36 with BlockContext

use of org.aion.zero.impl.types.BlockContext in project aion by aionnetwork.

the class AionBlockchainImpl method createNewMiningBlockInternal.

BlockContext createNewMiningBlockInternal(Block parent, List<AionTransaction> txs, boolean waitUntilBlockTime, long currTimeSeconds) {
    BlockHeader parentHdr = parent.getHeader();
    long time = currTimeSeconds;
    if (parentHdr.getTimestamp() >= time) {
        time = parentHdr.getTimestamp() + 1;
        while (waitUntilBlockTime && TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) <= time) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
    long energyLimit = this.energyLimitStrategy.getEnergyLimit(parentHdr);
    MiningBlock block;
    try {
        MiningBlockHeader.Builder headerBuilder = MiningBlockHeader.Builder.newInstance().withParentHash(parent.getHash()).withCoinbase(minerCoinbase).withNumber(parentHdr.getNumber() + 1).withTimestamp(time).withExtraData(minerExtraData).withTxTrieRoot(calcTxTrieRoot(txs)).withEnergyLimit(energyLimit).withDefaultStateRoot().withDefaultReceiptTrieRoot().withDefaultLogsBloom().withDefaultDifficulty().withDefaultNonce().withDefaultSolution();
        block = new MiningBlock(headerBuilder.build(), txs);
    } catch (Exception e) {
        LOG.error("Construct new mining block header exception:", e);
        return null;
    }
    BlockHeader parentMiningBlock;
    BlockHeader parentMiningBlocksParent = null;
    byte[] newDiff;
    IDifficultyCalculator diffCalculator;
    // so we use a strict greater than here
    if (forkUtility.isUnityForkActive(block.getNumber())) {
        if (parentHdr.getSealType() == Seal.PROOF_OF_WORK) {
            LOG.warn("Tried to create 2 PoW blocks in a row");
            return null;
        } else {
            Block[] blockFamily = repository.getBlockStore().getTwoGenerationBlocksByHashWithInfo(parentHdr.getParentHash());
            Objects.requireNonNull(blockFamily[0]);
            parentMiningBlock = blockFamily[0].getHeader();
            parentMiningBlocksParent = blockFamily[1].getHeader();
            diffCalculator = chainConfiguration.getUnityDifficultyCalculator();
        }
    } else {
        parentMiningBlock = parentHdr;
        if (!parentMiningBlock.isGenesis()) {
            parentMiningBlocksParent = getParent(parentMiningBlock).getHeader();
        }
        diffCalculator = chainConfiguration.getPreUnityDifficultyCalculator();
    }
    newDiff = ByteUtil.bigIntegerToBytes(diffCalculator.calculateDifficulty(parentMiningBlock, parentMiningBlocksParent), DIFFICULTY_BYTES);
    block.updateHeaderDifficulty(newDiff);
    BigInteger totalTransactionFee = blockPreSeal(parentHdr, block);
    if (totalTransactionFee == null) {
        return null;
    }
    // derive base block reward
    BigInteger baseBlockReward;
    if (forkUtility.isSignatureSwapForkActive(block.getNumber())) {
        baseBlockReward = TimeVaryingRewardsCalculator.calculateReward(block.getTimestamp() - parentHdr.getTimestamp());
    } else {
        baseBlockReward = this.chainConfiguration.getRewardsCalculatorBeforeSignatureSchemeSwap(forkUtility.isUnityForkActive(block.getNumber())).calculateReward(block.getNumber());
    }
    return new BlockContext(block, baseBlockReward, totalTransactionFee);
}
Also used : BlockContext(org.aion.zero.impl.types.BlockContext) MiningBlock(org.aion.zero.impl.types.MiningBlock) IDifficultyCalculator(org.aion.zero.impl.core.IDifficultyCalculator) VmFatalException(org.aion.zero.impl.vm.common.VmFatalException) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) Block(org.aion.zero.impl.types.Block) BlockDetailsValidator.isValidBlock(org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock) GenesisStakingBlock(org.aion.zero.impl.types.GenesisStakingBlock) RetValidPreBlock(org.aion.zero.impl.types.RetValidPreBlock) MiningBlock(org.aion.zero.impl.types.MiningBlock) EventBlock(org.aion.evtmgr.impl.evt.EventBlock) StakingBlock(org.aion.zero.impl.types.StakingBlock) BigInteger(java.math.BigInteger) BlockHeader(org.aion.zero.impl.types.BlockHeader) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) StakingBlockHeader(org.aion.zero.impl.types.StakingBlockHeader)

Example 37 with BlockContext

use of org.aion.zero.impl.types.BlockContext in project aion by aionnetwork.

the class RPCMethods method getBlockTemplate.

@Override
public BlockTemplate getBlockTemplate() {
    BlockContext context = chainHolder.getBlockTemplate();
    MiningBlock block = context.block;
    return new BlockTemplate(ByteArray.wrap(block.getParentHash()), block.getNumber(), block.getHeader().getPowBoundaryBI(), ByteArray.wrap(block.getHeader().getMineHash()), context.baseBlockReward, context.transactionFee);
}
Also used : BlockContext(org.aion.zero.impl.types.BlockContext) MiningBlock(org.aion.zero.impl.types.MiningBlock) BlockTemplate(org.aion.rpc.types.RPCTypes.BlockTemplate)

Example 38 with BlockContext

use of org.aion.zero.impl.types.BlockContext in project aion by aionnetwork.

the class BlockchainImplementationTest method testIsPruneRestricted_wFullState.

/**
 * In FULL mode the state is stored for all blocks. There are no restrictions due to pruning.
 */
@Test
public void testIsPruneRestricted_wFullState() {
    // the maximum height considered by this test
    int height = 200;
    StandaloneBlockchain.Bundle bundle = new StandaloneBlockchain.Builder().withValidatorConfiguration("simple").withRepoConfig(new MockRepositoryConfig(new CfgPrune(false))).withDefaultAccounts(accounts).build();
    StandaloneBlockchain chain = bundle.bc;
    AionRepositoryImpl repo = chain.getRepository();
    BlockContext context;
    List<AionTransaction> txs;
    // creating (height) blocks
    long time = System.currentTimeMillis();
    for (int i = 0; i < height; i++) {
        txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
        context = chain.createNewMiningBlockInternal(chain.getBestBlock(), txs, true, time / 10000L);
        assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    }
    // testing restriction for unrestricted blocks
    for (int i = height; i >= 0; i--) {
        assertThat(chain.isPruneRestricted(i)).isFalse();
        // ensure the state exists
        assertThat(repo.isValidRoot(chain.getBlockByNumber(i).getStateRoot())).isTrue();
    }
}
Also used : MockRepositoryConfig(org.aion.zero.impl.db.MockRepositoryConfig) BlockContext(org.aion.zero.impl.types.BlockContext) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) CfgPrune(org.aion.zero.impl.config.CfgPrune) Test(org.junit.Test)

Example 39 with BlockContext

use of org.aion.zero.impl.types.BlockContext in project aion by aionnetwork.

the class BlockchainDataRecoveryTest method testRecoverIndexWithoutGenesis.

/**
 * Test the index recovery when the index database is empty.
 *
 * <p>Under these circumstances the recovery process will fail.
 */
@Test
public void testRecoverIndexWithoutGenesis() {
    // build a blockchain with a few blocks
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build();
    StandaloneBlockchain chain = bundle.bc;
    AionRepositoryImpl repo = chain.getRepository();
    BlockContext context;
    List<AionTransaction> txs;
    long time = System.currentTimeMillis();
    List<MiningBlock> blocksToImport = new ArrayList<>();
    for (int i = 0; i < NUMBER_OF_BLOCKS; i++) {
        txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
        context = chain.createNewMiningBlockInternal(chain.getBestBlock(), txs, true, time / 10000L);
        assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
        blocksToImport.add(context.block);
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    ByteArrayKeyValueDatabase indexDatabase = repo.getIndexDatabase();
    // 1: direct recovery call
    repo.flush();
    // deleting the entire index database
    indexDatabase.drop();
    // ensure that the index was corrupted
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isFalse();
    // call the recovery functionality
    boolean worked = chain.recoverIndexEntry(repo, bestBlock);
    // ensure that the best block is unchanged
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // check that the index recovery failed
    assertThat(worked).isFalse();
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isFalse();
    // 2: recovery at import
    repo.flush();
    // deleting the entire index database
    indexDatabase.drop();
    // ensure that the index was corrupted
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isFalse();
    // call the recovery functionality indirectly
    for (MiningBlock block : blocksToImport) {
        // index missing before import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
        assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
        // index missing after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
    }
    // ensure that the best block is unchanged
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // check that the index recovery failed
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isFalse();
}
Also used : BlockContext(org.aion.zero.impl.types.BlockContext) ArrayList(java.util.ArrayList) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock) ByteArrayKeyValueDatabase(org.aion.db.impl.ByteArrayKeyValueDatabase) MiningBlock(org.aion.zero.impl.types.MiningBlock) Block(org.aion.zero.impl.types.Block) Test(org.junit.Test)

Example 40 with BlockContext

use of org.aion.zero.impl.types.BlockContext in project aion by aionnetwork.

the class BlockchainDataRecoveryTest method testRecoverIndexWithPartialIndex_ShorterSideChain.

/**
 * Test the recovery of the index with start from the index of an ancestor block.
 */
@Test
public void testRecoverIndexWithPartialIndex_ShorterSideChain() {
    final int EVEN_NUMBER_OF_BLOCKS = NUMBER_OF_BLOCKS % 2 == 0 ? NUMBER_OF_BLOCKS : NUMBER_OF_BLOCKS + 1;
    // build a blockchain with a few blocks
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build();
    StandaloneBlockchain chain = bundle.bc;
    AionRepositoryImpl repo = chain.getRepository();
    BlockContext context;
    List<AionTransaction> txs;
    // adding common blocks
    long time = System.currentTimeMillis();
    for (int i = 0; i < EVEN_NUMBER_OF_BLOCKS / 2 - 1; i++) {
        txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
        context = chain.createNewMiningBlockInternal(chain.getBestBlock(), txs, true, time / 10000L);
        assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    }
    // splitting chains
    Block mainChainBlock, sideChainBlock;
    mainChainBlock = chain.getBestBlock();
    sideChainBlock = mainChainBlock;
    txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
    context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
    assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    mainChainBlock = context.block;
    // starting side chain
    txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
    context = chain.createNewMiningBlockInternal(sideChainBlock, txs, true, time / 10000L);
    MiningBlockHeader newHeader = MiningBlockHeader.Builder.newInstance().withHeader(context.block.getHeader()).withExtraData("other".getBytes()).build();
    context.block.updateHeader(newHeader);
    assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    sideChainBlock = context.block;
    // building chains; sidechain will have missing index
    Map<Long, byte[]> blocksToDelete = new HashMap<>();
    List<MiningBlock> blocksToImportMainChain = new ArrayList<>();
    List<MiningBlock> blocksToImportSideChain = new ArrayList<>();
    for (int i = 0; i < EVEN_NUMBER_OF_BLOCKS / 2 - 1; i++) {
        txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
        context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
        assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
        mainChainBlock = context.block;
        blocksToImportMainChain.add(context.block);
        // adding side chain
        txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
        context = chain.createNewMiningBlockInternal(sideChainBlock, txs, true, time / 10000L);
        assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
        sideChainBlock = context.block;
        blocksToDelete.put(sideChainBlock.getNumber(), sideChainBlock.getHash());
        blocksToImportSideChain.add(context.block);
    }
    // making the main chain longer
    txs = BlockchainTestUtils.generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
    context = chain.createNewMiningBlockInternal(mainChainBlock, txs, true, time / 10000L);
    assertThat(chain.tryToConnect(context.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    mainChainBlock = context.block;
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(EVEN_NUMBER_OF_BLOCKS);
    assertThat(bestBlock.getHash()).isEqualTo(mainChainBlock.getHash());
    // delete index entries from the database
    MockDB indexDatabase = (MockDB) repo.getIndexDatabase();
    // 1: direct recovery call
    repo.flush();
    Map<Long, byte[]> deletedInfo = new HashMap<>();
    for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
        byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
        // saving the data for checking recovery
        deletedInfo.put(entry.getKey(), indexDatabase.get(indexKey).get());
        // deleting the block info
        indexDatabase.deleteAndCommit(indexKey);
        // ensure that the index was corrupted
        assertThat(repo.isIndexed(entry.getValue(), entry.getKey())).isFalse();
    }
    // call the recovery functionality for the main chain subsection
    boolean worked = chain.recoverIndexEntry(repo, chain.getBlockByHash(mainChainBlock.getParentHash()));
    // ensure that the index was corrupted only for the side chain
    assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isFalse();
    assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
    assertThat(worked).isTrue();
    // call the recovery functionality
    worked = chain.recoverIndexEntry(repo, sideChainBlock);
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(worked).isTrue();
    assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isTrue();
    // check that the index information is correct
    for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
        long level = entry.getKey();
        byte[] hash = entry.getValue();
        // checking at block store level
        assertThat(repo.isIndexed(hash, level)).isTrue();
        // checking at database level
        byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
        // NOTE: this checks the correction of both main chain and side chain recovery
        assertThat(deletedInfo.get(level)).isEqualTo(indexDatabase.get(indexKey).get());
    }
    // 2: recovery at import
    repo.flush();
    for (Map.Entry<Long, byte[]> entry : blocksToDelete.entrySet()) {
        byte[] indexKey = ByteUtil.intToBytes(entry.getKey().intValue());
        // deleting the block info
        indexDatabase.deleteAndCommit(indexKey);
        // ensure that the index was corrupted
        assertThat(repo.isIndexed(entry.getValue(), entry.getKey())).isFalse();
    }
    // call the recovery functionality indirectly for main chain
    for (MiningBlock block : blocksToImportMainChain) {
        // index missing before import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
        assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
        // index present after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
    }
    // ensure that the index was corrupted only for the side chain
    assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isFalse();
    assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
    // call the recovery functionality indirectly for side chain
    for (MiningBlock block : blocksToImportSideChain) {
        // index missing before import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isFalse();
        assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
        // index present after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
    }
    // ensure that the index was corrupted only for the side chain
    assertThat(repo.isIndexed(sideChainBlock.getHash(), sideChainBlock.getNumber())).isTrue();
    assertThat(repo.isIndexed(mainChainBlock.getHash(), mainChainBlock.getNumber())).isTrue();
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // check that the index information is correct at database level
    for (Long key : blocksToDelete.keySet()) {
        // checking at database level
        byte[] indexKey = ByteUtil.intToBytes(key.intValue());
        // NOTE: this checks the correction of both main chain and side chain recovery
        assertThat(deletedInfo.get(key)).isEqualTo(indexDatabase.get(indexKey).get());
    }
}
Also used : HashMap(java.util.HashMap) BlockContext(org.aion.zero.impl.types.BlockContext) MockDB(org.aion.db.impl.mockdb.MockDB) ArrayList(java.util.ArrayList) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) MiningBlock(org.aion.zero.impl.types.MiningBlock) Block(org.aion.zero.impl.types.Block) HashMap(java.util.HashMap) Map(java.util.Map) Test(org.junit.Test)

Aggregations

BlockContext (org.aion.zero.impl.types.BlockContext)49 AionTransaction (org.aion.base.AionTransaction)42 Test (org.junit.Test)42 BigInteger (java.math.BigInteger)27 AionAddress (org.aion.types.AionAddress)25 AionTxExecSummary (org.aion.base.AionTxExecSummary)19 MiningBlock (org.aion.zero.impl.types.MiningBlock)18 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)16 RepositoryCache (org.aion.base.db.RepositoryCache)15 Block (org.aion.zero.impl.types.Block)15 ArrayList (java.util.ArrayList)13 MockDB (org.aion.db.impl.mockdb.MockDB)12 DataWord (org.aion.util.types.DataWord)11 ImportResult (org.aion.zero.impl.core.ImportResult)9 ECKey (org.aion.crypto.ECKey)8 StandaloneBlockchain (org.aion.zero.impl.blockchain.StandaloneBlockchain)8 TrieImpl (org.aion.zero.impl.trie.TrieImpl)6 HashMap (java.util.HashMap)5 Map (java.util.Map)5 Log (org.aion.types.Log)5