Search in sources :

Example 56 with MiningBlock

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

the class BlockchainForkingTest method testSameBlockDifferentNonceAndSolutionSimple.

/*-
     * Tests the case where multiple threads submit a single block (content) but
     * with different mining nonces and solutions. In this case our rules dictate
     * that all subsequent blocks are considered invalid.
     *
     *          (common ancestor)
     *          /               \
     *         /                 \
     *        /                   \
     *       (a)o                 (b)x
     *
     * Given:
     * a.td == b.td
     */
@Test
public void testSameBlockDifferentNonceAndSolutionSimple() {
    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);
    MiningBlock sameBlock = (MiningBlock) BlockUtil.newBlockFromRlp(block.getEncoded());
    ImportResult firstRes = bc.tryToConnect(block);
    // check that the returned block is the first block
    assertThat(bc.getBestBlock() == block).isTrue();
    assertThat(firstRes).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    Pair<Long, BlockCachingContext> cacheContext = bc.getAvmCachingContext();
    assertThat(cacheContext.getLeft()).isEqualTo(block.getNumber() - 1);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
    ImportResult secondRes = bc.tryToConnect(sameBlock);
    // the second block should get rejected, so check that the reference still refers
    // to the first block (we dont change the published reference)
    assertThat(bc.getBestBlock() == block).isTrue();
    assertThat(secondRes).isEqualTo(ImportResult.EXIST);
    // the caching context does not change for already known blocks
    cacheContext = bc.getAvmCachingContext();
    assertThat(cacheContext.getLeft()).isEqualTo(block.getNumber() - 1);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) BlockCachingContext(org.aion.zero.impl.vm.common.BlockCachingContext) MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Example 57 with MiningBlock

use of org.aion.zero.impl.types.MiningBlock 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 58 with MiningBlock

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

the class BlockchainAccountStateTest method testExpandAccountStorage.

/**
 * Test the effects of expanding our account storage beyond
 */
@Ignore
@Test
public void testExpandAccountStorage() {
    // manually deploy the contract bytecode
    StandaloneBlockchain.Bundle bundle = new StandaloneBlockchain.Builder().withDefaultAccounts().withValidatorConfiguration("simple").build();
    StandaloneBlockchain bc = bundle.bc;
    ECKey senderKey = bundle.privateKeys.get(0);
    // deploy the contract
    // send a total of 100 bundles,
    // given the rate we're sending this should give us
    // a 400,000 accounts (not counting the 10 pre-generated for us)
    MiningBlock previousBlock = bc.genesis;
    for (int i = 0; i < 1000; i++) {
        previousBlock = createBundleAndCheck(bc, senderKey, previousBlock);
    }
}
Also used : ECKey(org.aion.crypto.ECKey) MiningBlock(org.aion.zero.impl.types.MiningBlock) Ignore(org.junit.Ignore) Test(org.junit.Test)

Example 59 with MiningBlock

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

the class BlockchainAccountStateTest method testAccountState.

/**
 * Test the effects of growing state of a single account
 */
@Ignore
@Test
public void testAccountState() {
    StandaloneBlockchain.Bundle bundle = new StandaloneBlockchain.Builder().withDefaultAccounts().withValidatorConfiguration("simple").build();
    StandaloneBlockchain bc = bundle.bc;
    ECKey senderKey = bundle.privateKeys.get(0);
    // send a total of 100 bundles,
    // given the rate we're sending this should give us
    // a 400,000 accounts (not counting the 10 pre-generated for us)
    MiningBlock previousBlock = bc.genesis;
    for (int i = 0; i < 1000; i++) {
        previousBlock = createBundleAndCheck(bc, senderKey, previousBlock);
    }
}
Also used : ECKey(org.aion.crypto.ECKey) MiningBlock(org.aion.zero.impl.types.MiningBlock) Ignore(org.junit.Ignore) Test(org.junit.Test)

Example 60 with MiningBlock

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

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