Search in sources :

Example 41 with BlockContext

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

the class BlockchainDataRecoveryTest method testRecoverIndexWithStartFromGenesis.

/**
 * Test the index recovery when the index database contains only the size and genesis index.
 */
@Test
public void testRecoverIndexWithStartFromGenesis() {
    // 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;
    // all blocks will be incorrect
    long time = System.currentTimeMillis();
    Map<Long, byte[]> blocksToDelete = new HashMap<>();
    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);
        blocksToDelete.put(context.block.getNumber(), context.block.getHash());
        blocksToImport.add(context.block);
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    // 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();
    }
    // 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 blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(worked).isTrue();
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.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());
        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();
    }
    // 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 present after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
    }
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isTrue();
    // 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());
        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) 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)

Example 42 with BlockContext

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

the class BlockchainDataRecoveryTest method testRecoverIndexWithStartFromGenesisWithoutSize.

/**
 * Test the index recovery when the index database contains only the genesis index and is
 * missing the size key.
 */
@Test
public void testRecoverIndexWithStartFromGenesisWithoutSize() {
    // 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;
    // all blocks will be incorrect
    long time = System.currentTimeMillis();
    Map<Long, byte[]> blocksToDelete = new HashMap<>();
    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);
        blocksToDelete.put(context.block.getNumber(), context.block.getHash());
        blocksToImport.add(context.block);
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    // 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();
    }
    // 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 blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(worked).isTrue();
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.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());
        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();
    }
    // 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 present after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
    }
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isTrue();
    // 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());
        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) 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)

Example 43 with BlockContext

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

the class BlockchainDataRecoveryTest method testRecoverIndexWithPartialIndex_MainChain.

/**
 * Test the recovery of the index with start from the index of an ancestor block.
 */
@Test
public void testRecoverIndexWithPartialIndex_MainChain() {
    // 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;
    // first half of blocks will be correct
    long time = System.currentTimeMillis();
    for (int i = 0; i < NUMBER_OF_BLOCKS / 2; 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);
    }
    // second half of blocks will miss the index
    Map<Long, byte[]> blocksToDelete = new HashMap<>();
    List<MiningBlock> blocksToImport = new ArrayList<>();
    for (int i = 0; i < NUMBER_OF_BLOCKS / 2; 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);
        blocksToDelete.put(context.block.getNumber(), context.block.getHash());
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    // 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();
    }
    // 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 blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(worked).isTrue();
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.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());
        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();
    }
    // 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 present after import
        assertThat(repo.isIndexed(block.getHash(), block.getNumber())).isTrue();
    }
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the index was recovered
    assertThat(repo.isIndexed(bestBlock.getHash(), bestBlock.getNumber())).isTrue();
    // 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());
        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) 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)

Example 44 with BlockContext

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

the class BlockchainDataRecoveryTest method testRecoverWorldState_wRepositorySnapshot.

@Test
public void testRecoverWorldState_wRepositorySnapshot() {
    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;
    // all blocks will be incorrect
    long time = System.currentTimeMillis();
    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);
    }
    repo.flush();
    assertThat(chain.recoverWorldState(repo.getSnapshotTo(repo.getRoot()), chain.getBestBlock())).isFalse();
}
Also used : BlockContext(org.aion.zero.impl.types.BlockContext) AionRepositoryImpl(org.aion.zero.impl.db.AionRepositoryImpl) AionTransaction(org.aion.base.AionTransaction) Test(org.junit.Test)

Example 45 with BlockContext

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

the class BlockchainDataRecoveryTest method testRecoverWorldStateWithPartialWorldState.

/**
 * Test the recovery of the world state with start from the state of an ancestor block.
 */
@Test
public void testRecoverWorldStateWithPartialWorldState() {
    // 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;
    // first half of blocks will be correct
    long time = System.currentTimeMillis();
    for (int i = 0; i < NUMBER_OF_BLOCKS / 2; 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);
    }
    // second half of blocks will miss the state root
    List<byte[]> statesToDelete = new ArrayList<>();
    List<MiningBlock> blocksToImport = new ArrayList<>();
    for (int i = 0; i < NUMBER_OF_BLOCKS / 2; 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);
        statesToDelete.add(context.block.getStateRoot());
        blocksToImport.add(context.block);
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    // delete some world state root entries from the database
    TrieImpl trie = (TrieImpl) repo.getWorldState();
    MockDB database = (MockDB) repo.getStateDatabase();
    // 1: direct recovery call
    repo.flush();
    for (byte[] key : statesToDelete) {
        database.deleteAndCommit(key);
        assertThat(trie.isValidRoot(key)).isFalse();
    }
    // ensure that the world state was corrupted
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
    // call the recovery functionality
    boolean worked = chain.recoverWorldState(repo, bestBlock);
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the world state is ok
    assertThat(worked).isTrue();
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isTrue();
    // 2: recovery at import
    repo.flush();
    for (byte[] key : statesToDelete) {
        database.deleteAndCommit(key);
        assertThat(trie.isValidRoot(key)).isFalse();
    }
    // ensure that the world state was corrupted
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
    // call the recovery functionality indirectly
    for (MiningBlock block : blocksToImport) {
        // state missing before import
        assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
        assertThat(chain.tryToConnect(block)).isEqualTo(ImportResult.EXIST);
        // state present after import
        assertThat(trie.isValidRoot(block.getStateRoot())).isTrue();
    }
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the world state is ok
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isTrue();
}
Also used : 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) TrieImpl(org.aion.zero.impl.trie.TrieImpl) MiningBlock(org.aion.zero.impl.types.MiningBlock) Block(org.aion.zero.impl.types.Block) 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