Search in sources :

Example 26 with MiningBlockHeader

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

the class BlockchainForkingTest method testSecondBlockHigherDifficultyFork.

/*-
     *
     * Recall previous forking logic worked as follows:
     *
     *          [ parent block ]
     *          /              \
     *         /                \
     *        /                  \
     *  [block_1]              [block_2]
     *  TD=101                 TD=102
     *
     * Where if block_1 had a greater timestamp (and thus lower TD) than
     * block_2, then block_2 would be accepted as the best block for
     * that particular level (until later re-orgs prove this to be untrue)
     *
     * With our changes to difficulty calculations, difficulty is calculated
     * with respect to the two previous blocks (parent, grandParent) blocks
     * in the sequence.
     *
     * This leads to the following:
     *
     *          [ parent block - 1] TD = 50
     *                  |
     *                  |
     *          [ parent block ] D = 50
     *          /              \
     *         /                \
     *        /                  \
     *    [block_1]            [block_2]
     *    TD=100               TD=100
     *
     * Where both blocks are guaranteed to have the same TD if they directly
     * branch off of the same parent. In fact, this guarantees us that the
     * first block coming in from the network (for a particular level) is
     * the de-facto best block for a short period of time.
     *
     * It is only when the block after comes in (for both chains) that a re-org
     * will happen on one of the chains (possibly)
     *
     *
     *             ...prev
     *   [block_1]              [block_2]
     *   T(n) = T(n-1) + 4      T(n) = T(n-1) + 20
     *       |                         |
     *       |                         |
     *       |                         |
     *   [block_1_2]            [block_1_2]
     *   TD = 160               TD = 140
     *
     * At which point a re-org should occur on most blocks. Remember that this reorg
     * is a minimum, given equal hashing power and particularily bad luck, two parties
     * could indefinitely stay on their respective chains, but the chances of this is
     * extraordinarily small.
     */
@Test
public void testSecondBlockHigherDifficultyFork() {
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").withDefaultAccounts().build();
    long time = System.currentTimeMillis();
    StandaloneBlockchain bc = bundle.bc;
    // generate three blocks, on the third block we get flexibility
    // for what difficulties can occur
    MiningBlock firstBlock = bc.createNewMiningBlockInternal(bc.getGenesis(), Collections.emptyList(), true, time / 1000L).block;
    assertThat(bc.tryToConnect(firstBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    Pair<Long, BlockCachingContext> cacheContext = bc.getAvmCachingContext();
    assertThat(cacheContext.getLeft()).isEqualTo(firstBlock.getNumber() - 1);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
    // now connect the second block
    MiningBlock secondBlock = bc.createNewMiningBlockInternal(firstBlock, Collections.emptyList(), true, time / 1000L).block;
    assertThat(bc.tryToConnect(secondBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // the parent
    assertThat(cacheContext.getLeft()).isEqualTo(firstBlock.getNumber());
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
    // now on the third block, we diverge with one block having higher TD than the other
    MiningBlock fasterSecondBlock = bc.createNewMiningBlockInternal(secondBlock, Collections.emptyList(), true, time / 1000L).block;
    MiningBlock slowerSecondBlock = new MiningBlock(fasterSecondBlock);
    MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(slowerSecondBlock.getHeader()).withTimestamp(time / 1000L + 100).build();
    slowerSecondBlock.updateHeader(newBlockHeader);
    assertThat(bc.tryToConnect(fasterSecondBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // the parent
    assertThat(cacheContext.getLeft()).isEqualTo(secondBlock.getNumber());
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
    assertThat(bc.tryToConnect(slowerSecondBlock)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // the parent
    assertThat(cacheContext.getLeft()).isEqualTo(secondBlock.getNumber());
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.SIDECHAIN);
    time += 100;
    MiningBlock fastBlockDescendant = bc.createNewMiningBlockInternal(fasterSecondBlock, Collections.emptyList(), true, time / 1000L).block;
    MiningBlock slowerBlockDescendant = bc.createNewMiningBlockInternal(slowerSecondBlock, Collections.emptyList(), true, time / 1000L + 100 + 1).block;
    // increment by another hundred (this is supposed to be when the slower block descendant is
    // completed)
    time += 100;
    assertThat(fastBlockDescendant.getDifficultyBI()).isGreaterThan(slowerBlockDescendant.getDifficultyBI());
    System.out.println("faster block descendant TD: " + fastBlockDescendant.getDifficultyBI());
    System.out.println("slower block descendant TD: " + slowerBlockDescendant.getDifficultyBI());
    assertThat(bc.tryToConnect(slowerBlockDescendant)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // no known parent
    assertThat(cacheContext.getLeft()).isEqualTo(0);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.DEEP_SIDECHAIN);
    assertThat(bc.tryToConnect(fastBlockDescendant)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // parent had been made side chain
    assertThat(cacheContext.getLeft()).isEqualTo(0);
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.DEEP_SIDECHAIN);
    assertThat(bc.getBestBlock()).isEqualTo(fastBlockDescendant);
    // ensuring that the caching is correct for the nest block to be added
    MiningBlock switchBlock = bc.createNewMiningBlockInternal(fastBlockDescendant, Collections.emptyList(), true, time / 1000L).block;
    assertThat(bc.tryToConnect(switchBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // common ancestor
    assertThat(cacheContext.getLeft()).isEqualTo(secondBlock.getNumber());
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.SWITCHING_MAINCHAIN);
    // ensuring that the caching is correct for the nest block to be added
    MiningBlock lastBlock = bc.createNewMiningBlockInternal(switchBlock, Collections.emptyList(), true, time / 1000L).block;
    assertThat(bc.tryToConnect(lastBlock)).isEqualTo(ImportResult.IMPORTED_BEST);
    // check that the correct caching context was used
    cacheContext = bc.getAvmCachingContext();
    // parent
    assertThat(cacheContext.getLeft()).isEqualTo(switchBlock.getNumber());
    assertThat(cacheContext.getRight()).isEqualTo(BlockCachingContext.MAINCHAIN);
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) BlockCachingContext(org.aion.zero.impl.vm.common.BlockCachingContext) MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Example 27 with MiningBlockHeader

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

the class BlockchainForkingTest method testSecondBlockHigherDifficultyFork_wExceptionOnFasterBlockAdd.

/**
 * Test fork with exception.
 */
@Test
public void testSecondBlockHigherDifficultyFork_wExceptionOnFasterBlockAdd() {
    StandaloneBlockchain.Builder builder = new StandaloneBlockchain.Builder();
    StandaloneBlockchain.Bundle bundle = builder.withValidatorConfiguration("simple").withDefaultAccounts().build();
    long time = System.currentTimeMillis();
    StandaloneBlockchain bc = bundle.bc;
    // generate three blocks, on the third block we get flexibility
    // for what difficulties can occur
    BlockContext firstBlock = bc.createNewMiningBlockInternal(bc.getGenesis(), Collections.emptyList(), true, time / 1000L);
    assertThat(bc.tryToConnect(firstBlock.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    // now connect the second block
    BlockContext secondBlock = bc.createNewMiningBlockInternal(firstBlock.block, Collections.emptyList(), true, time / 1000L);
    assertThat(bc.tryToConnect(secondBlock.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    // now on the third block, we diverge with one block having higher TD than the other
    BlockContext fasterSecondBlock = bc.createNewMiningBlockInternal(secondBlock.block, Collections.emptyList(), true, time / 1000L);
    MiningBlock slowerSecondBlock = new MiningBlock(fasterSecondBlock.block);
    MiningBlockHeader newBlockHeader = MiningBlockHeader.Builder.newInstance().withHeader(slowerSecondBlock.getHeader()).withTimestamp(time / 1000L + 100).build();
    slowerSecondBlock.updateHeader(newBlockHeader);
    assertThat(bc.tryToConnect(fasterSecondBlock.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    assertThat(bc.tryToConnect(slowerSecondBlock)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    time += 100;
    BlockContext fastBlockDescendant = bc.createNewMiningBlockInternal(fasterSecondBlock.block, Collections.emptyList(), true, time / 1000L);
    BlockContext slowerBlockDescendant = bc.createNewMiningBlockInternal(slowerSecondBlock, Collections.emptyList(), true, time / 1000L + 100 + 1);
    assertThat(fastBlockDescendant.block.getDifficultyBI()).isGreaterThan(slowerBlockDescendant.block.getDifficultyBI());
    System.out.println("faster block descendant TD: " + fastBlockDescendant.block.getDifficultyBI());
    System.out.println("slower block descendant TD: " + slowerBlockDescendant.block.getDifficultyBI());
    assertThat(bc.tryToConnect(slowerBlockDescendant.block)).isEqualTo(ImportResult.IMPORTED_BEST);
    // corrupt the parent for the fast block descendant
    ((MockDB) bc.getRepository().getStateDatabase()).deleteAndCommit(fasterSecondBlock.block.getStateRoot());
    assertThat(bc.getRepository().isValidRoot(fasterSecondBlock.block.getStateRoot())).isFalse();
    // attempt adding the fastBlockDescendant
    assertThat(bc.tryToConnect(fastBlockDescendant.block)).isEqualTo(ImportResult.INVALID_BLOCK);
    // check for correct state rollback
    assertThat(bc.getBestBlock()).isEqualTo(slowerBlockDescendant.block);
    assertThat(bc.getRepository().getRoot()).isEqualTo(slowerBlockDescendant.block.getStateRoot());
    assertThat(bc.getTotalDifficulty()).isEqualTo(bc.getTotalDifficultyForHash(slowerBlockDescendant.block.getHash()));
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) BlockContext(org.aion.zero.impl.types.BlockContext) MockDB(org.aion.db.impl.mockdb.MockDB) MiningBlock(org.aion.zero.impl.types.MiningBlock) Test(org.junit.Test)

Example 28 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 _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
 * @param _startHeight blocks are created only if a minimum height is reached
 */
private void addThread_createNewBlock(List<Runnable> _threads, StandaloneBlockchain _chain, int _id, ConcurrentLinkedQueue<MiningBlock> _queue, int _startHeight) {
    _threads.add(() -> {
        // parent will be main chain block
        Block _parent = _chain.getBestBlock();
        if (_parent.getNumber() >= _startHeight) {
            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();
            // 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 (using getBestBlock) %n", block.getShortHash(), block.getNumber(), new String(block.getExtraData()), block.getTransactionsList().size(), _parent.getShortHash(), Thread.currentThread().getName());
            }
        } else {
            if (DISPLAY_MESSAGES) {
                System.out.format("%51sParent not at minimum height. Skipping create in thread: %20s %n", " ", Thread.currentThread().getName());
            }
        }
    });
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) MiningBlock(org.aion.zero.impl.types.MiningBlock) Block(org.aion.zero.impl.types.Block) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock)

Example 29 with MiningBlockHeader

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

the class EquihashSolutionsGenerationTest210_9 method testMine_wBlockData.

@Test
@Parameters(method = "blocks")
public void testMine_wBlockData(MiningBlock block) {
    MiningBlockHeader header = block.getHeader();
    Equihash spy = spy(new Equihash(n, k));
    // mock return the known solution
    byte[] nonce = header.getNonce();
    when(spy.getSolutionsForNonce(header.getMineHash(), nonce)).thenReturn(new int[][] { EquiUtils.getIndicesFromMinimal(header.getSolution(), n / (k + 1)) });
    // use real method for mine call
    when(spy.mine(block, nonce)).thenCallRealMethod();
    AionPowSolution sol = spy.mine(block, nonce);
    assertNotNull(sol);
    assertArrayEquals(header.getNonce(), sol.getNonce());
    assertArrayEquals(header.getSolution(), sol.getSolution());
    assertArrayEquals(header.getMineHash(), sol.getBlock().getHeader().getMineHash());
}
Also used : MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) Parameters(junitparams.Parameters) 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