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();
}
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();
}
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();
}
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();
}
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);
}
}
Aggregations