use of org.aion.base.db.IRepositoryCache in project aion by aionnetwork.
the class AionRepositoryImplTest method test17NodePreviousRootTest.
// test that intermediate nodes also get rolled back properly
// intermediate nodes get created when two accounts have a common substring
@Test
public void test17NodePreviousRootTest() {
// not that it matters since things are going to be hashed, but at least
// the root node should point to a node that contains references to both
final Address DOG_ACC = Address.wrap("00000000000000000000000000000dog".getBytes());
final Address DOGE_ACC = Address.wrap("0000000000000000000000000000doge".getBytes());
AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
IRepositoryCache track = repository.startTracking();
track.addBalance(DOG_ACC, BigInteger.ONE);
track.addBalance(DOGE_ACC, BigInteger.ONE);
track.flush();
final byte[] root = repository.getRoot();
repository.flush();
System.out.println("trie state after adding two accounts");
System.out.println(repository.getWorldState().getTrieDump());
track = repository.startTracking();
track.addBalance(DOG_ACC, BigInteger.ONE);
track.flush();
System.out.println("trie state after updating balance on one account");
System.out.println(repository.getWorldState().getTrieDump());
assertThat(repository.getBalance(DOG_ACC)).isEqualTo(BigInteger.TWO);
repository.flush();
repository.syncToRoot(root);
assertThat(repository.getBalance(DOG_ACC)).isEqualTo(BigInteger.ONE);
}
use of org.aion.base.db.IRepositoryCache in project aion by aionnetwork.
the class AionRepositoryImplTest method testSyncToPreviousRootWithFlush.
@Test
public void testSyncToPreviousRootWithFlush() {
final Address FIRST_ACC = Address.wrap("CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE");
AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
byte[] originalRoot = repository.getRoot();
IRepositoryCache track = repository.startTracking();
track.addBalance(FIRST_ACC, BigInteger.ONE);
track.flush();
byte[] newRoot = repository.getRoot();
System.out.println("state after add one account");
System.out.println(repository.getWorldState().getTrieDump());
// flush into cache/db
repository.flush();
track = repository.startTracking();
// total should be 2
track.addBalance(FIRST_ACC, BigInteger.ONE);
track.flush();
assertThat(repository.getBalance(FIRST_ACC)).isEqualTo(BigInteger.TWO);
System.out.println("state after adding balance to FIRST_ACC");
System.out.println(repository.getWorldState().getTrieDump());
// flush this state into cache/db
repository.flush();
repository.setRoot(newRoot);
System.out.println("state after rewinding to previous root");
System.out.println(repository.getWorldState().getTrieDump());
assertThat(repository.getBalance(FIRST_ACC)).isEqualTo(BigInteger.ONE);
}
use of org.aion.base.db.IRepositoryCache in project aion by aionnetwork.
the class AionHub method loadBlockchain.
private void loadBlockchain() {
this.repository.getBlockStore().load();
AionBlock bestBlock = this.repository.getBlockStore().getBestBlock();
boolean recovered = true;
boolean bestBlockShifted = true;
int countRecoveryAttempts = 0;
// fix the trie if necessary
while (// the best block was updated after recovery attempt
bestBlockShifted && // allow 5 recovery attempts
(countRecoveryAttempts < 5) && // recover only for non-null blocks
bestBlock != null && !this.repository.isValidRoot(bestBlock.getStateRoot())) {
long bestBlockNumber = bestBlock.getNumber();
byte[] bestBlockRoot = bestBlock.getStateRoot();
recovered = this.blockchain.recoverWorldState(this.repository, bestBlockNumber);
if (recovered) {
bestBlock = this.repository.getBlockStore().getBestBlock();
// checking is the best block has changed since attempting recovery
if (bestBlock == null) {
bestBlockShifted = true;
} else {
bestBlockShifted = // block number changed
!(bestBlockNumber == bestBlock.getNumber()) || // root hash changed
!(Arrays.equals(bestBlockRoot, bestBlock.getStateRoot()));
}
if (bestBlockShifted) {
LOG.info("Rebuilding world state SUCCEEDED by REVERTING to a previous block.");
} else {
LOG.info("Rebuilding world state SUCCEEDED.");
}
} else {
LOG.error("Rebuilding world state FAILED. " + "Stop the kernel (Ctrl+C) and use the command line revert option to move back to a valid block. " + "Check the Aion wiki for recommendations on choosing the block number.");
}
countRecoveryAttempts++;
}
// rebuild from genesis if (1) no best block (2) recovery failed
if (bestBlock == null || !recovered) {
if (bestBlock == null) {
LOG.info("DB is empty - adding Genesis");
} else {
LOG.info("DB could not be recovered - adding Genesis");
}
AionGenesis genesis = cfg.getGenesis();
// initialization section for network balance contract
IRepositoryCache track = repository.startTracking();
Address networkBalanceAddress = PrecompiledContracts.totalCurrencyAddress;
track.createAccount(networkBalanceAddress);
for (Map.Entry<Integer, BigInteger> addr : genesis.getNetworkBalances().entrySet()) {
track.addStorageRow(networkBalanceAddress, new DataWord(addr.getKey()), new DataWord(addr.getValue()));
}
for (Address addr : genesis.getPremine().keySet()) {
track.createAccount(addr);
track.addBalance(addr, genesis.getPremine().get(addr).getBalance());
}
track.flush();
repository.commitBlock(genesis.getHeader());
this.repository.getBlockStore().saveBlock(genesis, genesis.getCumulativeDifficulty(), true);
blockchain.setBestBlock(genesis);
blockchain.setTotalDifficulty(genesis.getCumulativeDifficulty());
if (this.eventMgr != null) {
List<IEvent> evts = new ArrayList<>();
evts.add(new EventBlock(EventBlock.CALLBACK.ONBLOCK0));
evts.add(new EventBlock(EventBlock.CALLBACK.ONTRACE0));
this.eventMgr.registerEvent(evts);
} else {
LOG.error("Event manager is null !!!");
System.exit(-1);
}
LOG.info("loaded genesis block <num={}, root={}>", 0, ByteUtil.toHexString(genesis.getStateRoot()));
} else {
blockchain.setBestBlock(bestBlock);
BigInteger totalDifficulty = this.repository.getBlockStore().getTotalDifficulty();
blockchain.setTotalDifficulty(totalDifficulty);
LOG.info("loaded block <num={}, root={}>", blockchain.getBestBlock().getNumber(), LogUtil.toHexF8(blockchain.getBestBlock().getStateRoot()));
}
if (!Arrays.equals(blockchain.getBestBlock().getStateRoot(), EMPTY_TRIE_HASH)) {
this.repository.syncToRoot(blockchain.getBestBlock().getStateRoot());
}
this.repository.getBlockStore().load();
}
use of org.aion.base.db.IRepositoryCache in project aion by aionnetwork.
the class AionRepositoryImplTest method testSyncToPreviousRootNoFlush.
/**
* Tests behaviour for trie when trying to revert to a previous root without
* first flushing. Note the behaviour here. Interestingly enough, it seems like
* the trie must first be flushed, so that the root node is in the caching/db layer.
*
* Otherwise the retrieval methods will not be able to find the temporal root value.
*/
@Test
public void testSyncToPreviousRootNoFlush() {
final Address FIRST_ACC = Address.wrap("CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFE");
final Address SECOND_ACC = Address.wrap("BEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEFBEEF");
final AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
byte[] originalRoot = repository.getRoot();
// now create a new account
IRepositoryCache track = repository.startTracking();
track.addBalance(FIRST_ACC, BigInteger.ONE);
track.flush();
System.out.println("after first account added");
System.out.println(repository.getWorldState().getTrieDump());
byte[] firstRoot = repository.getRoot();
track = repository.startTracking();
track.addBalance(SECOND_ACC, BigInteger.TWO);
track.flush();
byte[] secondRoot = repository.getRoot();
System.out.println("after second account added");
System.out.println(repository.getWorldState().getTrieDump());
assertThat(firstRoot).isNotEqualTo(originalRoot);
assertThat(secondRoot).isNotEqualTo(firstRoot);
repository.syncToRoot(firstRoot);
assertThat(repository.getRoot()).isEqualTo(firstRoot);
BigInteger balance = repository.getBalance(FIRST_ACC);
// notice that the first blocks balance is also zero
assertThat(balance).isEqualTo(BigInteger.ZERO);
}
use of org.aion.base.db.IRepositoryCache in project aion by aionnetwork.
the class AionRepositoryImplTest method testAccountStateUpdateStorageRow.
@Test
public void testAccountStateUpdateStorageRow() {
AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
IRepositoryCache track = repository.startTracking();
Address defaultAccount = Address.wrap(ByteUtil.hexStringToBytes("CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3"));
track.addBalance(defaultAccount, BigInteger.valueOf(1));
// Consider the original root the one after an account has been added
byte[] originalRoot = repository.getRoot();
byte[] key = HashUtil.blake128("hello".getBytes());
byte[] value = HashUtil.blake128("world".getBytes());
track.addStorageRow(defaultAccount, new DataWord(key), new DataWord(value));
track.flush();
byte[] retrievedValue = repository.getStorageValue(defaultAccount, new DataWord(key)).getNoLeadZeroesData();
assertThat(retrievedValue).isEqualTo(value);
byte[] newRoot = repository.getRoot();
System.out.println(String.format("original root: %s", ByteUtil.toHexString(originalRoot)));
System.out.println(String.format("new root: %s", ByteUtil.toHexString(newRoot)));
}
Aggregations