Search in sources :

Example 51 with MiningBlock

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

the class BlockchainConcurrentImportTest method testConcurrent.

@Test
public void testConcurrent() throws InterruptedException {
    List<Runnable> threads = new ArrayList<>();
    int start = (int) sourceChain.getBestBlock().getNumber() - 1;
    ConcurrentLinkedQueue<MiningBlock> queue = new ConcurrentLinkedQueue<>();
    ConcurrentLinkedQueue<MiningBlock> imported = new ConcurrentLinkedQueue<>();
    int blockCount = CONCURRENT_THREADS_PER_TYPE + 1;
    for (MiningBlock blk : knownBlocks) {
        // connect to known blocks
        addThread_tryToConnect(threads, testChain, blk);
        // add new blocks with known parent
        addThread_createNewBlock(threads, testChain, blk, blockCount, queue);
        blockCount++;
        // add new blocks with best block parent
        addThread_createNewBlock(threads, testChain, blockCount, queue, start);
        blockCount++;
        // connect to new blocks
        addThread_tryToConnect(threads, testChain, queue, imported);
    }
    // run threads while not at minimum height
    long height, targetHeight = sourceChain.getBestBlock().getNumber() + MAIN_CHAIN_FREQUENCY;
    boolean done = false;
    while (!done) {
        System.out.format("%nRunning the %d generated threads...%n", threads.size());
        assertConcurrent("Testing tryToConnect(...) ", threads, TIME_OUT);
        // checking height
        height = testChain.getBestBlock().getNumber();
        done = height >= targetHeight;
        System.out.format("Current height = %d. Target height = %d.%n", height, targetHeight);
    }
    // adding new blocks to source chain
    System.out.format("%nAdding new blocks to source chain for testing...%n");
    MiningBlock block = imported.poll();
    while (block != null) {
        ImportResult result = sourceChain.tryToConnect(block);
        knownBlocks.add(block);
        if (DISPLAY_MESSAGES) {
            System.out.format("Importing block with hash: %s, number: %6d, extra data: %6s, txs: %3d, status: %20s%n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), result.toString());
        }
        block = imported.poll();
    }
    // comparing total diff for the two chains
    assertThat(testChain.getTotalDifficulty()).isEqualTo(sourceChain.getTotalDifficulty());
    assertThat(testChain.getCachedTotalDifficulty()).isEqualTo(sourceChain.getCachedTotalDifficulty());
    testChain.assertEqualTotalDifficulty();
    // comparing total diff for each block of the two chains
    for (MiningBlock blk : knownBlocks) {
        assertThat(testChain.getTotalDifficultyForHash(blk.getHash())).isEqualTo(sourceChain.getTotalDifficultyForHash(blk.getHash()));
        byte[] hash = blk.getHash();
        assertThat(testChain.getTotalDifficultyForHash(hash)).isEqualTo(sourceChain.getTotalDifficultyForHash(hash));
    }
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) ArrayList(java.util.ArrayList) MiningBlock(org.aion.zero.impl.types.MiningBlock) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) Test(org.junit.Test)

Example 52 with MiningBlock

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

the class BlockchainDifficultyTest method testDifficultyThirdBlock.

@Test
public void testDifficultyThirdBlock() {
    StandaloneBlockchain.Bundle bundle = new StandaloneBlockchain.Builder().withValidatorConfiguration("simple").withDefaultAccounts().build();
    MiningBlock firstBlock = bundle.bc.createNewMiningBlock(bundle.bc.getGenesis(), Collections.emptyList(), true);
    assertThat(bundle.bc.tryToConnect(firstBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // connect second block
    MiningBlock secondBlock = bundle.bc.createNewMiningBlock(firstBlock, Collections.emptyList(), true);
    assertThat(bundle.bc.tryToConnect(secondBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // due to us timestamping the genesis at 0
    assertThat(secondBlock.getDifficultyBI()).isLessThan(firstBlock.getDifficultyBI());
    // connect second block
    MiningBlock thirdBlock = bundle.bc.createNewMiningBlock(secondBlock, Collections.emptyList(), true);
    assertThat(bundle.bc.tryToConnect(thirdBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // due to us timestamping the genesis at 0
    assertThat(thirdBlock.getDifficultyBI()).isGreaterThan(secondBlock.getDifficultyBI());
}
Also used : MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Example 53 with MiningBlock

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

the class BlockchainForkingTest method testInvalidFirstBlockDifficulty.

/*-
     * Test the general forking case, where an incoming block (b) has a greater total
     * difficulty than our current block. In this scenario, we should switch to
     * the branch (sub-tree) that has (b) at its tip.
     *
     * This is the simplest case, where the distance between (a) (our current head) and
     * (b) is 2. This implies that the common ancestor is directly adjacent to both blocks.
     *
     *          (common ancestor)
     *          /               \
     *         /                 \
     *        /                   \
     *       (a)x(low td)           (b)o(higher td)
     *
     * In this simple case:
     * b.td > a.td
     * a_worldState === b_worldState
     *
     */
@Test
public void testInvalidFirstBlockDifficulty() {
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle b = builder.withValidatorConfiguration("simple").build();
    StandaloneBlockchain bc = b.bc;
    Block bestBlock = bc.getBestBlock();
    MiningBlock standardBlock = bc.createNewMiningBlock(bc.getBestBlock(), Collections.emptyList(), true);
    ChainConfiguration cc = new ChainConfiguration();
    MiningBlock higherDifficultyBlock = new MiningBlock(standardBlock);
    MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(higherDifficultyBlock.getHeader()).withTimestamp(bestBlock.getTimestamp() + 1).build();
    higherDifficultyBlock.updateHeader(newBlockHeader);
    BigInteger difficulty = cc.getPreUnityDifficultyCalculator().calculateDifficulty(higherDifficultyBlock.getHeader(), bestBlock.getHeader());
    assertThat(difficulty).isGreaterThan(standardBlock.getDifficultyBI());
    newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(higherDifficultyBlock.getHeader()).withDifficulty(difficulty.toByteArray()).build();
    higherDifficultyBlock.updateHeader(newBlockHeader);
    System.out.println("before any processing: " + Hex.toHexString(bc.getRepository().getRoot()));
    System.out.println("trie: " + bc.getRepository().getWorldState().getTrieDump());
    ImportResult result = bc.tryToConnect(standardBlock);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    Pair<Long, BlockCachingContext> cacheContext = bc.getAvmCachingContext();
    assertThat(cacheContext.getLeft()).isEqualTo(standardBlock.getNumber() - 1);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
    // assert that the block we just inserted (best) is the instance that is returned
    assertThat(bc.getBestBlock() == standardBlock).isTrue();
    System.out.println(Hex.toHexString(bc.getRepository().getRoot()));
    ImportResult higherDifficultyResult = bc.tryToConnect(higherDifficultyBlock);
    /**
     * With our updates to difficulty verification and calculation, this block is now invalid
     */
    assertThat(higherDifficultyResult).isEqualTo(ImportResult.INVALID_BLOCK);
    assertThat(bc.getBestBlockHash()).isEqualTo(standardBlock.getHash());
    // since the block is second for that height, it is assumed as sidechain
    cacheContext = bc.getAvmCachingContext();
    assertThat(cacheContext.getLeft()).isEqualTo(standardBlock.getNumber() - 1);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.SIDECHAIN);
    // the object reference here is intentional
    assertThat(bc.getBestBlock() == standardBlock).isTrue();
    // check for correct state rollback
    assertThat(bc.getRepository().getRoot()).isEqualTo(standardBlock.getStateRoot());
    assertThat(bc.getTotalDifficulty()).isEqualTo(bc.getTotalDifficultyForHash(standardBlock.getHash()));
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) BlockCachingContext(org.aion.zero.impl.vm.common.BlockCachingContext) 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) BigInteger(java.math.BigInteger) Test(org.junit.Test)

Example 54 with MiningBlock

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

the class BlockchainForkingTest method testForkWithRevertOnSmallContractStorage.

/**
 * Test the fork case when the block being replaced had contract storage changes that differ
 * from the previous block and are replaced by new changes in the updated block.
 *
 * <p>Ensures that the output of applying the block after the fork is the same as applying the
 * block first.
 */
@Test
public void testForkWithRevertOnSmallContractStorage() {
    // ****** setup ******
    // build a blockchain with CONCURRENT_THREADS_PER_TYPE blocks
    List<ECKey> accounts = generateAccounts(10);
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain sourceChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
    StandaloneBlockchain testChain = builder.withValidatorConfiguration("simple").withDefaultAccounts(accounts).build().bc;
    assertThat(testChain).isNotEqualTo(sourceChain);
    assertThat(testChain.genesis).isEqualTo(sourceChain.genesis);
    long time = System.currentTimeMillis();
    // add a block with contract deploy
    ECKey sender = accounts.remove(0);
    AionTransaction deployTx = deployContract(sender);
    MiningBlock block = sourceChain.createNewMiningBlockInternal(sourceChain.genesis, Arrays.asList(deployTx), true, time / 10_000L).block;
    Pair<ImportResult, AionBlockSummary> connectResult = sourceChain.tryToConnectAndFetchSummary(block);
    AionTxReceipt receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(receipt.isSuccessful()).isTrue();
    ImportResult result = connectResult.getLeft();
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    result = testChain.tryToConnect(block);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(testChain.getRepository().getRoot()).isEqualTo(sourceChain.getRepository().getRoot());
    AionAddress contract = TxUtil.calculateContractAddress(receipt.getTransaction());
    // add a block with transactions to both
    List<AionTransaction> txs = generateTransactions(20, accounts, sourceChain.getRepository());
    block = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), txs, true, time / 10_000L).block;
    result = sourceChain.tryToConnect(block);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    result = testChain.tryToConnect(block);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(testChain.getRepository().getRoot()).isEqualTo(sourceChain.getRepository().getRoot());
    // create a slow / fast block distinction
    AionTransaction callTx = callSetValue2(sender, contract, 5, 6, BigInteger.ONE);
    MiningBlock fastBlock = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(callTx), true, time / 10_000L).block;
    callTx = callSetValue2(sender, contract, 1, 9, BigInteger.ONE);
    MiningBlock slowBlock = new MiningBlock(sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(callTx), true, time / 10_000L).block);
    MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(slowBlock.getHeader()).withTimestamp(time / 10_000L + 100).build();
    slowBlock.updateHeader(newBlockHeader);
    time += 100;
    // sourceChain imports only fast block
    assertThat(sourceChain.tryToConnect(fastBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // testChain imports both blocks
    assertThat(testChain.tryToConnect(fastBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(testChain.tryToConnect(slowBlock)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    // build two blocks with different contract storage calls
    // the second block gets a higher total difficulty
    callTx = callSetValue(sender, contract, 5, BigInteger.TWO);
    MiningBlock lowBlock = testChain.createNewMiningBlockInternal(slowBlock, Arrays.asList(callTx), true, time / 10_000L + 101).block;
    callTx = callSetValue(sender, contract, 9, BigInteger.TWO);
    MiningBlock highBlock = sourceChain.createNewMiningBlockInternal(fastBlock, Arrays.asList(callTx), true, time / 10_000L).block;
    // System.out.println("***highBlock TD: " + highBlock.getDifficultyBI());
    // System.out.println("***lowBlock TD: " + lowBlock.getDifficultyBI());
    assertThat(highBlock.getDifficultyBI()).isGreaterThan(lowBlock.getDifficultyBI());
    // build first chain with highBlock applied directly
    connectResult = sourceChain.tryToConnectAndFetchSummary(highBlock);
    receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(receipt.isSuccessful()).isTrue();
    result = connectResult.getLeft();
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    // collect the consensus information from the block & receipt
    AionBlockSummary blockSummary = connectResult.getRight();
    byte[] stateRoot = blockSummary.getBlock().getStateRoot();
    byte[] blockReceiptsRoot = blockSummary.getBlock().getReceiptsRoot();
    byte[] receiptTrieEncoded = receipt.getReceiptTrieEncoded();
    // ****** test fork behavior ******
    // first import lowBlock
    assertThat(testChain.tryToConnect(lowBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // next import highBlock causing the fork
    connectResult = testChain.tryToConnectAndFetchSummary(highBlock);
    receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(receipt.isSuccessful()).isTrue();
    System.out.println(receipt);
    result = connectResult.getLeft();
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    // collect the consensus information from the block & receipt
    blockSummary = connectResult.getRight();
    assertThat(testChain.getBestBlock()).isEqualTo(sourceChain.getBestBlock());
    assertThat(blockSummary.getBlock().getStateRoot()).isEqualTo(stateRoot);
    assertThat(blockSummary.getBlock().getReceiptsRoot()).isEqualTo(blockReceiptsRoot);
    assertThat(receipt.getReceiptTrieEncoded()).isEqualTo(receiptTrieEncoded);
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) AionAddress(org.aion.types.AionAddress) ECKey(org.aion.crypto.ECKey) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) AionBlockSummary(org.aion.zero.impl.types.AionBlockSummary) AionTxReceipt(org.aion.base.AionTxReceipt) Test(org.junit.Test)

Example 55 with MiningBlock

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

the class BlockchainForkingTest method testRollbackWithAddInvalidBlock.

@Test
public void testRollbackWithAddInvalidBlock() {
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle b = builder.withValidatorConfiguration("simple").build();
    StandaloneBlockchain bc = b.bc;
    MiningBlock block = bc.createNewMiningBlock(bc.getBestBlock(), Collections.emptyList(), true);
    assertThat(bc.tryToConnect(block)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the returned block is the first block
    assertThat(bc.getBestBlock() == block).isTrue();
    MiningBlock invalidBlock = bc.createNewMiningBlock(bc.getBestBlock(), Collections.emptyList(), true);
    MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(invalidBlock.getHeader()).withDifficulty(BigInteger.ONE.toByteArray()).build();
    invalidBlock.updateHeader(newBlockHeader);
    // attempting to add invalid block
    assertThat(bc.tryToConnect(invalidBlock)).isEqualTo(ImportResult.INVALID_BLOCK);
    // check for correct state rollback
    assertThat(bc.getBestBlock()).isEqualTo(block);
    assertThat(bc.getRepository().getRoot()).isEqualTo(block.getStateRoot());
    assertThat(bc.getTotalDifficulty()).isEqualTo(bc.getTotalDifficultyForHash(block.getHash()));
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Aggregations

MiningBlock (org.aion.zero.impl.types.MiningBlock)185 Test (org.junit.Test)136 AionTransaction (org.aion.base.AionTransaction)128 ImportResult (org.aion.zero.impl.core.ImportResult)81 AionAddress (org.aion.types.AionAddress)79 BigInteger (java.math.BigInteger)64 Block (org.aion.zero.impl.types.Block)63 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)59 RepositoryCache (org.aion.base.db.RepositoryCache)41 AionTxReceipt (org.aion.base.AionTxReceipt)37 ArrayList (java.util.ArrayList)36 ECKey (org.aion.crypto.ECKey)27 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)27 AionTxExecSummary (org.aion.base.AionTxExecSummary)25 AionRepositoryCache (org.aion.zero.impl.db.AionRepositoryCache)24 MiningBlockHeader (org.aion.zero.impl.types.MiningBlockHeader)22 BlockContext (org.aion.zero.impl.types.BlockContext)18 DataWord (org.aion.util.types.DataWord)13 MockDB (org.aion.db.impl.mockdb.MockDB)12 StakingBlock (org.aion.zero.impl.types.StakingBlock)11