Search in sources :

Example 1 with TrieImpl

use of org.aion.zero.impl.trie.TrieImpl in project aion by aionnetwork.

the class BlockUtil method calcTxTrieRoot.

public static byte[] calcTxTrieRoot(List<AionTransaction> transactions) {
    Objects.requireNonNull(transactions);
    if (transactions.isEmpty()) {
        return ConstantUtil.EMPTY_TRIE_HASH;
    }
    Trie txsState = new TrieImpl(null);
    for (int i = 0; i < transactions.size(); i++) {
        byte[] txEncoding = transactions.get(i).getEncoded();
        if (txEncoding != null) {
            txsState.update(RLP.encodeInt(i), txEncoding);
        } else {
            return ConstantUtil.EMPTY_TRIE_HASH;
        }
    }
    return txsState.getRootHash();
}
Also used : TrieImpl(org.aion.zero.impl.trie.TrieImpl) Trie(org.aion.zero.impl.trie.Trie)

Example 2 with TrieImpl

use of org.aion.zero.impl.trie.TrieImpl in project aion by aionnetwork.

the class BlockchainDataRecoveryTest method testRecoverWorldStateWithStartFromGenesis.

/**
 * Test the recovery of the world state with start from the state of the genesis block.
 */
@Test
public void testRecoverWorldStateWithStartFromGenesis() {
    // 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();
    List<byte[]> statesToDelete = new ArrayList<>();
    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);
        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)

Example 3 with TrieImpl

use of org.aion.zero.impl.trie.TrieImpl in project aion by aionnetwork.

the class BlockchainDataRecoveryTest method testRecoverWorldState_wDeletedBlock.

@Test
public void testRecoverWorldState_wDeletedBlock() {
    // 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();
    List<byte[]> statesToDelete = new ArrayList<>();
    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);
        statesToDelete.add(context.block.getStateRoot());
        // skipping middle block
        if (context.block.getNumber() != NUMBER_OF_BLOCKS / 2) {
            blocksToImport.add(context.block);
        }
    }
    Block bestBlock = chain.getBestBlock();
    assertThat(bestBlock.getNumber()).isEqualTo(NUMBER_OF_BLOCKS);
    // delete middle block from db
    Block middle = chain.getBlockByNumber(NUMBER_OF_BLOCKS / 2);
    MockDB database = (MockDB) repo.getBlockDatabase();
    database.deleteAndCommit(middle.getHash());
    // delete some world state root entries from the database
    TrieImpl trie = (TrieImpl) repo.getWorldState();
    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
    assertThat(chain.recoverWorldState(repo, bestBlock)).isFalse();
    // ensure that the blockchain is ok
    assertThat(chain.getBestBlockHash()).isEqualTo(bestBlock.getHash());
    // ensure that the world state could not be recovered
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
    // 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);
        if (block.getNumber() < middle.getNumber()) {
            // state present after import
            assertThat(trie.isValidRoot(block.getStateRoot())).isTrue();
        } else {
            // block after missing one cannot be recovered
            assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
        }
    }
    // 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())).isFalse();
    // importing middle block
    assertThat(chain.tryToConnect(middle)).isEqualTo(ImportResult.IMPORTED_NOT_BEST);
    // call the recovery functionality indirectly
    for (MiningBlock block : blocksToImport) {
        // checking only failed blocks from before
        if (block.getNumber() > middle.getNumber()) {
            // 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)

Example 4 with TrieImpl

use of org.aion.zero.impl.trie.TrieImpl in project aion by aionnetwork.

the class BlockchainDataRecoveryTest method testRecoverWorldStateWithoutGenesis.

/**
 * Test the recovery of the world state when missing the genesis block state.
 *
 * <p>Under these circumstances the recovery will fail.
 */
@Test
public void testRecoverWorldStateWithoutGenesis() {
    // 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();
    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);
        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();
    List<byte[]> statesToDelete = new ArrayList<>();
    Iterator<byte[]> iterator = database.keys();
    while (iterator.hasNext()) {
        statesToDelete.add(iterator.next());
    }
    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 was not recovered
    assertThat(worked).isFalse();
    assertThat(trie.isValidRoot(chain.getBestBlock().getStateRoot())).isFalse();
    // 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 missing after import (because there is not genesis to recover from)
        assertThat(trie.isValidRoot(block.getStateRoot())).isFalse();
    }
    // 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())).isFalse();
}
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)

Example 5 with TrieImpl

use of org.aion.zero.impl.trie.TrieImpl in project aion by aionnetwork.

the class AionRepositoryImpl method getReferencedTrieNodes.

/**
 * Retrieves nodes referenced by a trie node value, where the size of the result is bounded by
 * the given limit.
 *
 * @param value a trie node value which may be referencing other nodes
 * @param limit the maximum number of key-value pairs to be retrieved by this method, which
 *     limits the search in the trie; zero and negative values for the limit will result in no
 *     search and an empty map will be returned
 * @param dbType the database where the value was stored and further keys should be searched for
 * @return an empty map when the value does not reference other trie nodes or the given limit is
 *     invalid, or a map containing all the referenced nodes reached while keeping within the
 *     limit on the result size
 */
public Map<ByteArrayWrapper, byte[]> getReferencedTrieNodes(byte[] value, int limit, DatabaseType dbType) {
    if (limit <= 0) {
        return Collections.emptyMap();
    } else {
        ByteArrayKeyValueDatabase db = selectDatabase(dbType);
        Trie trie = new TrieImpl(db);
        return trie.getReferencedTrieNodes(value, limit);
    }
}
Also used : TrieImpl(org.aion.zero.impl.trie.TrieImpl) ByteArrayKeyValueDatabase(org.aion.db.impl.ByteArrayKeyValueDatabase) SecureTrie(org.aion.zero.impl.trie.SecureTrie) Trie(org.aion.zero.impl.trie.Trie)

Aggregations

TrieImpl (org.aion.zero.impl.trie.TrieImpl)9 ArrayList (java.util.ArrayList)6 AionTransaction (org.aion.base.AionTransaction)6 MockDB (org.aion.db.impl.mockdb.MockDB)6 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)6 Block (org.aion.zero.impl.types.Block)6 BlockContext (org.aion.zero.impl.types.BlockContext)6 MiningBlock (org.aion.zero.impl.types.MiningBlock)6 Test (org.junit.Test)6 Trie (org.aion.zero.impl.trie.Trie)3 NetworkBestBlockCallback (org.aion.zero.impl.blockchain.AionImpl.NetworkBestBlockCallback)2 PendingTxCallback (org.aion.zero.impl.blockchain.AionImpl.PendingTxCallback)2 TransactionBroadcastCallback (org.aion.zero.impl.blockchain.AionImpl.TransactionBroadcastCallback)2 BigInteger (java.math.BigInteger)1 ByteArrayKeyValueDatabase (org.aion.db.impl.ByteArrayKeyValueDatabase)1 SecureTrie (org.aion.zero.impl.trie.SecureTrie)1