use of org.aion.mcf.vm.types.DataWord in project aion by aionnetwork.
the class AionContractDetailsTest method testExternalStorageTransition.
@Test
public void testExternalStorageTransition() {
Address address = Address.wrap(RandomUtils.nextBytes(Address.ADDRESS_LEN));
byte[] code = RandomUtils.nextBytes(512);
Map<DataWord, DataWord> elements = new HashMap<>();
AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
IByteArrayKeyValueDatabase externalStorage = repository.getDetailsDatabase();
AionContractDetailsImpl original = new AionContractDetailsImpl(0, 1000000);
original.setExternalStorageDataSource(externalStorage);
original.setAddress(address);
original.setCode(code);
for (int i = 0; i < IN_MEMORY_STORAGE_LIMIT / 64 + 10; i++) {
DataWord key = new DataWord(RandomUtils.nextBytes(16));
DataWord value = new DataWord(RandomUtils.nextBytes(16));
elements.put(key, value);
original.put(key, value);
}
original.syncStorage();
assertTrue(!externalStorage.isEmpty());
IContractDetails deserialized = deserialize(original.getEncoded(), externalStorage);
// adds keys for in-memory storage limit overflow
for (int i = 0; i < 10; i++) {
DataWord key = new DataWord(RandomUtils.nextBytes(16));
DataWord value = new DataWord(RandomUtils.nextBytes(16));
elements.put(key, value);
deserialized.put(key, value);
}
deserialized.syncStorage();
assertTrue(!externalStorage.isEmpty());
deserialized = deserialize(deserialized.getEncoded(), externalStorage);
Map<DataWord, DataWord> storage = deserialized.getStorage();
assertEquals(elements.size(), storage.size());
for (DataWord key : elements.keySet()) {
assertEquals(elements.get(key), storage.get(key));
}
}
use of org.aion.mcf.vm.types.DataWord 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.mcf.vm.types.DataWord in project aion by aionnetwork.
the class AionRepositoryDummy method createAccount.
public AccountState createAccount(Address addr) {
AccountState accountState = new AccountState();
worldState.put(addr.toByteArrayWrapper(), accountState);
IContractDetails<DataWord> contractDetails = this.cfg.contractDetailsImpl();
detailsDB.put(addr.toByteArrayWrapper(), contractDetails);
return accountState;
}
use of org.aion.mcf.vm.types.DataWord in project aion by aionnetwork.
the class AionRepositoryDummy method loadAccount.
public void loadAccount(Address addr, HashMap<ByteArrayWrapper, AccountState> cacheAccounts, HashMap<ByteArrayWrapper, IContractDetails<DataWord>> cacheDetails) {
AccountState account = getAccountState(addr);
IContractDetails<DataWord> details = getContractDetails(addr);
if (account == null) {
account = new AccountState();
} else {
account = new AccountState(account);
}
if (details == null) {
details = this.cfg.contractDetailsImpl();
} else {
details = details.clone();
}
cacheAccounts.put(addr.toByteArrayWrapper(), account);
cacheDetails.put(addr.toByteArrayWrapper(), details);
}
use of org.aion.mcf.vm.types.DataWord in project aion by aionnetwork.
the class AionRepositoryImpl method updateBatch.
@Override
public synchronized void updateBatch(Map<Address, AccountState> stateCache, Map<Address, IContractDetails<DataWord>> detailsCache) {
for (Map.Entry<Address, AccountState> entry : stateCache.entrySet()) {
Address address = entry.getKey();
AccountState accountState = entry.getValue();
IContractDetails<DataWord> contractDetails = detailsCache.get(address);
if (accountState.isDeleted()) {
// TODO-A: batch operations here
rwLock.readLock().lock();
try {
worldState.delete(address.toBytes());
} catch (Exception e) {
LOG.error("key deleted exception [{}]", e.toString());
} finally {
rwLock.readLock().unlock();
}
LOG.debug("key deleted <key={}>", Hex.toHexString(address.toBytes()));
} else {
if (!contractDetails.isDirty()) {
// ContractState class
if (accountState.isDirty()) {
updateAccountState(address, accountState);
if (LOG.isTraceEnabled()) {
LOG.trace("update: [{}],nonce: [{}] balance: [{}] [{}]", Hex.toHexString(address.toBytes()), accountState.getNonce(), accountState.getBalance(), contractDetails.getStorage());
}
}
continue;
}
ContractDetailsCacheImpl contractDetailsCache = (ContractDetailsCacheImpl) contractDetails;
if (contractDetailsCache.origContract == null) {
contractDetailsCache.origContract = this.cfg.contractDetailsImpl();
try {
contractDetailsCache.origContract.setAddress(address);
} catch (Exception e) {
e.printStackTrace();
LOG.error("contractDetailsCache setAddress exception [{}]", e.toString());
}
contractDetailsCache.commit();
}
contractDetails = contractDetailsCache.origContract;
updateContractDetails(address, contractDetails);
if (!Arrays.equals(accountState.getCodeHash(), EMPTY_TRIE_HASH)) {
accountState.setStateRoot(contractDetails.getStorageHash());
}
updateAccountState(address, accountState);
if (LOG.isTraceEnabled()) {
LOG.trace("update: [{}],nonce: [{}] balance: [{}] [{}]", Hex.toHexString(address.toBytes()), accountState.getNonce(), accountState.getBalance(), contractDetails.getStorage());
}
}
}
LOG.trace("updated: detailsCache.size: {}", detailsCache.size());
stateCache.clear();
detailsCache.clear();
}
Aggregations