Search in sources :

Example 6 with MiningBlockHeader

use of org.aion.zero.impl.types.MiningBlockHeader 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)

Example 7 with MiningBlockHeader

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

the class BlockchainForkingTest method testVmTypeRetrieval_ForkWithConflictingContractVM.

/**
 * Ensures that if a side-chain block is imported after a main-chain block creating the same
 * contract address X but using different VMs, then each chain will operate on the correct VM.
 */
@Test
public void testVmTypeRetrieval_ForkWithConflictingContractVM() throws Exception {
    TestResourceProvider resourceProvider = TestResourceProvider.initializeAndCreateNewProvider(AvmPathManager.getPathOfProjectRootDirectory());
    IAvmResourceFactory resourceFactory = resourceProvider.factoryForVersion1;
    // blocks to be built
    MiningBlock block, fastBlock, slowBlock, lowBlock, highBlock;
    // transactions used in blocks
    AionTransaction deployOnAVM, deployOnFVM, callTxOnFVM;
    // for processing block results
    Pair<ImportResult, AionBlockSummary> connectResult;
    ImportResult result;
    AionTxReceipt receipt;
    // build a blockchain
    TransactionTypeRule.allowAVMContractTransaction();
    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;
    ECKey sender = accounts.remove(0);
    assertThat(testChain).isNotEqualTo(sourceChain);
    assertThat(testChain.genesis).isEqualTo(sourceChain.genesis);
    long time = System.currentTimeMillis();
    // add a block to both chains
    block = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Collections.emptyList(), true, time / 10_000L).block;
    assertThat(sourceChain.tryToConnect(block)).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(testChain.tryToConnect(block)).isEqualTo(ImportResult.IMPORTED_BEST);
    // ****** setup side chain ******
    // deploy contracts on different VMs for the two chains
    deployOnAVM = deployStatefulnessAVMContract(resourceFactory, sender);
    fastBlock = sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(deployOnAVM), true, time / 10_000L).block;
    deployOnFVM = deployContract(sender);
    slowBlock = new MiningBlock(sourceChain.createNewMiningBlockInternal(sourceChain.getBestBlock(), Arrays.asList(deployOnFVM), 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
    connectResult = sourceChain.tryToConnectAndFetchSummary(fastBlock);
    result = connectResult.getLeft();
    receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(receipt.isSuccessful()).isTrue();
    AionAddress contract = TxUtil.calculateContractAddress(receipt.getTransaction());
    // testChain imports both blocks
    connectResult = testChain.tryToConnectAndFetchSummary(fastBlock);
    result = connectResult.getLeft();
    receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(receipt.isSuccessful()).isTrue();
    assertThat(TxUtil.calculateContractAddress(receipt.getTransaction())).isEqualTo(contract);
    connectResult = testChain.tryToConnectAndFetchSummary(slowBlock);
    result = connectResult.getLeft();
    receipt = connectResult.getRight().getReceipts().get(0);
    assertThat(result).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    assertThat(receipt.isSuccessful()).isTrue();
    assertThat(TxUtil.calculateContractAddress(receipt.getTransaction())).isEqualTo(contract);
    // ****** check that the correct contract details are kept ******
    // check that both chains have the correct vm type for the AVM contract
    byte[] codeHashAVM = sourceChain.getRepository().getAccountState(contract).getCodeHash();
    assertThat(testChain.getRepository().getVMUsed(contract, codeHashAVM)).isEqualTo(sourceChain.getRepository().getVMUsed(contract, codeHashAVM));
    // check that only the second chain has the vm type for the FVM contract
    byte[] codeHashFVM = ((AionRepositoryImpl) testChain.getRepository().getSnapshotTo(slowBlock.getStateRoot())).getAccountState(contract).getCodeHash();
    assertThat(sourceChain.getRepository().getVMUsed(contract, codeHashFVM)).isEqualTo(InternalVmType.UNKNOWN);
    assertThat(testChain.getRepository().getVMUsed(contract, codeHashFVM)).isEqualTo(InternalVmType.FVM);
    // check the stored information details
    ContractInformation infoSingleImport = sourceChain.getRepository().getIndexedContractInformation(contract);
    System.out.println("without side chain:" + infoSingleImport);
    assertThat(infoSingleImport.getVmUsed(codeHashAVM)).isEqualTo(InternalVmType.AVM);
    assertThat(infoSingleImport.getInceptionBlocks(codeHashAVM)).isEqualTo(Set.of(fastBlock.getHashWrapper()));
    assertThat(infoSingleImport.getVmUsed(codeHashFVM)).isEqualTo(InternalVmType.UNKNOWN);
    assertThat(infoSingleImport.getInceptionBlocks(codeHashFVM)).isEmpty();
    ContractInformation infoMultiImport = testChain.getRepository().getIndexedContractInformation(contract);
    System.out.println("with side chain:" + infoMultiImport);
    assertThat(infoMultiImport.getVmUsed(codeHashAVM)).isEqualTo(InternalVmType.AVM);
    assertThat(infoMultiImport.getInceptionBlocks(codeHashAVM)).isEqualTo(Set.of(fastBlock.getHashWrapper()));
    assertThat(infoMultiImport.getVmUsed(codeHashFVM)).isEqualTo(InternalVmType.FVM);
    assertThat(infoMultiImport.getInceptionBlocks(codeHashFVM)).isEqualTo(Set.of(slowBlock.getHashWrapper()));
    // build two blocks where the second block has a higher total difficulty
    callTxOnFVM = callSetValue(sender, contract, 9, BigInteger.ONE);
    lowBlock = testChain.createNewMiningBlockInternal(slowBlock, Arrays.asList(callTxOnFVM), true, time / 10_000L + 101).block;
    int expectedCount = 3;
    List<AionTransaction> callTxOnAVM = callStatefulnessAVM(resourceFactory, sender, expectedCount, BigInteger.ONE, contract);
    highBlock = sourceChain.createNewMiningBlockInternal(fastBlock, callTxOnAVM, true, time / 10_000L).block;
    assertThat(highBlock.getDifficultyBI()).isGreaterThan(lowBlock.getDifficultyBI());
    // build first chain with highBlock applied directly
    connectResult = sourceChain.tryToConnectAndFetchSummary(highBlock);
    // get last tx
    receipt = connectResult.getRight().getReceipts().get(expectedCount);
    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();
    int returnedCount = resourceFactory.newDecoder(blockSummary.getReceipts().get(expectedCount).getTransactionOutput()).decodeOneInteger();
    assertThat(returnedCount).isEqualTo(expectedCount);
    // ****** 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(expectedCount);
    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);
    returnedCount = resourceFactory.newDecoder(blockSummary.getReceipts().get(expectedCount).getTransactionOutput()).decodeOneInteger();
    assertThat(returnedCount).isEqualTo(expectedCount);
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) AionAddress(org.aion.types.AionAddress) AionTransaction(org.aion.base.AionTransaction) ECKey(org.aion.crypto.ECKey) MiningBlock(org.aion.zero.impl.types.MiningBlock) TestResourceProvider(org.aion.zero.impl.vm.TestResourceProvider) ContractInformation(org.aion.zero.impl.db.ContractInformation) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) IAvmResourceFactory(org.aion.avm.stub.IAvmResourceFactory) AionBlockSummary(org.aion.zero.impl.types.AionBlockSummary) AionTxReceipt(org.aion.base.AionTxReceipt) Test(org.junit.Test)

Example 8 with MiningBlockHeader

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

the class BlockchainConcurrentImportTest method addThread_createNewBlock.

/**
 * Adds a new thread for creating a new block with a parent among the already known blocks.
 *
 * @param _threads list of threads to be executed; the current thread will be added to this list
 * @param _chain the blockchain where the blocks will be imported
 * @param _parent the block that will be the parent of the newly created block
 * @param _id number used for identifying the block; added as extra data
 * @param _queue a queue for storing the new blocks; to be imported by a separate thread
 */
private void addThread_createNewBlock(List<Runnable> _threads, StandaloneBlockchain _chain, MiningBlock _parent, int _id, ConcurrentLinkedQueue<MiningBlock> _queue) {
    _threads.add(() -> {
        // creating block only if parent already imported
        if (_chain.isBlockStored(_parent.getHash(), _parent.getNumber())) {
            testChain.assertEqualTotalDifficulty();
            // only some of these txs may be valid
            // cannot syncToRoot due to concurrency issues
            AionRepositoryImpl repo = _chain.getRepository();
            List<AionTransaction> txs = generateTransactions(MAX_TX_PER_BLOCK, accounts, repo);
            MiningBlock block = null;
            try {
                block = _chain.createNewMiningBlock(_parent, txs, true);
                MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(block.getHeader()).withExtraData(String.valueOf(_id).getBytes()).build();
                block.updateHeader(newBlockHeader);
            } catch (Exception e) {
                e.printStackTrace();
            }
            testChain.assertEqualTotalDifficulty();
            // checking if the new block was already imported
            if (!_chain.isBlockStored(block.getHash(), block.getNumber())) {
                // still adding this block
                _queue.add(block);
                if (DISPLAY_MESSAGES) {
                    System.out.format("Create block with hash: %s, number: %6d, extra data: %6s, txs: %3d, parent: %20s in thread: %20s %n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), _parent.getShortHash(), Thread.currentThread().getName());
                }
            } else {
                if (DISPLAY_MESSAGES) {
                    System.out.format("%57sBlock already imported. Skipping create in thread: %20s %n", " ", Thread.currentThread().getName());
                }
            }
        } else {
            if (DISPLAY_MESSAGES) {
                System.out.format("%60sParent not imported. Skipping create in thread: %20s %n", " ", Thread.currentThread().getName());
            }
        }
    });
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock)

Example 9 with MiningBlockHeader

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

the class BlockchainConcurrentImportTest method generateBlocks.

private static void generateBlocks() {
    System.out.format("%nGenerating %d input blocks...%n", CONCURRENT_THREADS_PER_TYPE);
    Random rand = new Random();
    MiningBlock parent, block, mainChain;
    mainChain = sourceChain.getGenesis();
    knownBlocks.add(mainChain);
    List<AionTransaction> txs;
    AionRepositoryImpl sourceRepo = sourceChain.getRepository();
    long time = System.currentTimeMillis();
    for (int i = 0; i < CONCURRENT_THREADS_PER_TYPE; i++) {
        // ensuring that we add to the main chain at least every MAIN_CHAIN_FREQUENCY block
        if (i % MAIN_CHAIN_FREQUENCY == 0) {
            // the parent will be the main chain
            parent = mainChain;
        } else {
            // the parent is a random already imported block
            parent = knownBlocks.get(rand.nextInt(knownBlocks.size()));
        }
        // generate transactions for correct root
        byte[] originalRoot = sourceRepo.getRoot();
        sourceRepo.syncToRoot(parent.getStateRoot());
        txs = generateTransactions(MAX_TX_PER_BLOCK, accounts, sourceRepo);
        sourceRepo.syncToRoot(originalRoot);
        block = sourceChain.createNewMiningBlockInternal(parent, txs, true, time / 10000L).block;
        MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(block.getHeader()).withExtraData(String.valueOf(i).getBytes()).build();
        block.updateHeader(newBlockHeader);
        ImportResult result = sourceChain.tryToConnect(block);
        knownBlocks.add(block);
        if (result == ImportResult.IMPORTED_BEST) {
            mainChain = block;
        }
        if (DISPLAY_MESSAGES) {
            System.out.format("Created block with hash: %s, number: %6d, extra data: %6s, txs: %3d, import status: %20s %n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), result.toString());
        }
    }
    // all blocks except the genesis will be imported by the other chain
    knownBlocks.remove(sourceChain.getGenesis());
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) ImportResult(org.aion.zero.impl.core.ImportResult) Random(java.util.Random) AionTransaction(org.aion.base.AionTransaction) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) MiningBlock(org.aion.zero.impl.types.MiningBlock)

Example 10 with MiningBlockHeader

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

the class BlockchainIndexIntegrityTest method testIndexIntegrityWithCorrectData.

/**
 * Test the index integrity check and recovery when the index database is correct.
 */
@Test
public void testIndexIntegrityWithCorrectData() {
    final int NUMBER_OF_BLOCKS = 5;
    // build a blockchain with a few blocks
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").build();
    StandaloneBlockchain chain = bundle.bc;
    Block bestBlock;
    ImportResult result;
    for (int i = 0; i < NUMBER_OF_BLOCKS; i++) {
        bestBlock = chain.getBestBlock();
        MiningBlock next = chain.createNewMiningBlock(bestBlock, Collections.emptyList(), true);
        result = chain.tryToConnect(next);
        assertThat(result).isEqualTo(ImportResult.IMPORTED_BEST);
        // adding side chain
        next = chain.createNewMiningBlock(bestBlock, Collections.emptyList(), true);
        MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(next.getHeader()).withExtraData("other".getBytes()).build();
        next.updateHeader(newBlockHeader);
        result = chain.tryToConnect(next);
        assertThat(result).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    }
    bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    chain.getRepository().flush();
    AionRepositoryImpl repo = chain.getRepository();
    AionBlockStore blockStore = repo.getBlockStore();
    // check that the index recovery succeeded
    assertThat(blockStore.indexIntegrityCheck()).isEqualTo(AionBlockStore.IntegrityCheckResult.CORRECT);
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) ImportResult(org.aion.zero.impl.core.ImportResult) MiningBlock(org.aion.zero.impl.types.MiningBlock) Block(org.aion.zero.impl.types.Block) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionBlockStore(org.aion.zero.impl.db.AionBlockStore) MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Aggregations

MiningBlockHeader (org.aion.zero.impl.types.MiningBlockHeader)29 MiningBlock (org.aion.zero.impl.types.MiningBlock)23 Test (org.junit.Test)20 Block (org.aion.zero.impl.types.Block)14 AionTransaction (org.aion.base.AionTransaction)9 ImportResult (org.aion.zero.impl.core.ImportResult)9 ArrayList (java.util.ArrayList)8 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)8 List (java.util.List)5 IOException (java.io.IOException)4 Properties (java.util.Properties)4 ByteArrayWrapper (org.aion.util.types.ByteArrayWrapper)4 StakingBlock (org.aion.zero.impl.types.StakingBlock)4 BigInteger (java.math.BigInteger)3 ECKey (org.aion.crypto.ECKey)3 AionAddress (org.aion.types.AionAddress)3 BlockContext (org.aion.zero.impl.types.BlockContext)3 AionTxReceipt (org.aion.base.AionTxReceipt)2 MockDB (org.aion.db.impl.mockdb.MockDB)2 AionBlockStore (org.aion.zero.impl.db.AionBlockStore)2