use of org.aion.base.type.Address in project aion by aionnetwork.
the class AionRepositoryImplTest method testAccountStateUpdate.
@Test
public void testAccountStateUpdate() {
AionRepositoryImpl repository = AionRepositoryImpl.createForTesting(repoConfig);
byte[] originalRoot = repository.getRoot();
Address defaultAccount = Address.wrap(ByteUtil.hexStringToBytes("CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3CAF3"));
IRepositoryCache track = repository.startTracking();
track.addBalance(defaultAccount, BigInteger.valueOf(1));
track.flush();
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)));
assertThat(newRoot).isNotEqualTo(originalRoot);
}
use of org.aion.base.type.Address in project aion by aionnetwork.
the class ApiAion method sendTransaction.
public byte[] sendTransaction(ArgTxCall _params) {
Address from = _params.getFrom();
if (from == null || from.equals(Address.EMPTY_ADDRESS())) {
LOG.error("<send-transaction msg=invalid-from-address>");
return null;
}
ECKey key = this.getAccountKey(from.toString());
if (key == null) {
LOG.error("<send-transaction msg=account-not-found>");
return null;
}
try {
synchronized (pendingState) {
// TODO : temp set nrg & price to 1
byte[] nonce = (!_params.getNonce().equals(BigInteger.ZERO)) ? _params.getNonce().toByteArray() : pendingState.bestNonce(Address.wrap(key.getAddress())).toByteArray();
AionTransaction tx = new AionTransaction(nonce, _params.getTo(), _params.getValue().toByteArray(), _params.getData(), _params.getNrg(), _params.getNrgPrice());
tx.sign(key);
pendingState.addPendingTransaction(tx);
return tx.getHash();
}
} catch (Exception ex) {
return null;
}
}
use of org.aion.base.type.Address in project aion by aionnetwork.
the class AionBlockchainImpl method isValid.
/**
* This mechanism enforces a homeostasis in terms of the time between
* blocks; a smaller period between the last two blocks results in an
* increase in the difficulty level and thus additional computation
* required, lengthening the likely next period. Conversely, if the period
* is too large, the difficulty, and expected time to the next block, is
* reduced.
*/
private boolean isValid(AionBlock block) {
if (block == null) {
return false;
}
boolean isValid = true;
if (!block.isGenesis()) {
isValid = isValid(block.getHeader());
// Sanity checks
String trieHash = Hex.toHexString(block.getTxTrieRoot());
String trieListHash = Hex.toHexString(calcTxTrie(block.getTransactionsList()));
if (!trieHash.equals(trieListHash)) {
LOG.warn("Block's given Trie Hash doesn't match: {} != {}", trieHash, trieListHash);
return false;
}
List<AionTransaction> txs = block.getTransactionsList();
if (txs != null && !txs.isEmpty()) {
IRepository parentRepo = repository;
if (!Arrays.equals(getBlockStore().getBestBlock().getHash(), block.getParentHash())) {
parentRepo = repository.getSnapshotTo(getBlockByHash(block.getParentHash()).getStateRoot());
}
Map<Address, BigInteger> nonceCache = new HashMap<>();
if (txs.parallelStream().anyMatch(tx -> !TXValidator.isValid(tx))) {
LOG.error("Some transactions in the block are invalid");
return false;
}
for (AionTransaction tx : txs) {
Address txSender = tx.getFrom();
BigInteger expectedNonce = nonceCache.get(txSender);
if (expectedNonce == null) {
expectedNonce = parentRepo.getNonce(txSender);
}
BigInteger txNonce = new BigInteger(1, tx.getNonce());
if (!expectedNonce.equals(txNonce)) {
LOG.warn("Invalid transaction: Tx nonce {} != expected nonce {} (parent nonce: {}): {}", txNonce.toString(), expectedNonce.toString(), parentRepo.getNonce(txSender), tx);
return false;
}
// update cache
nonceCache.put(txSender, expectedNonce.add(BigInteger.ONE));
}
}
}
return isValid;
}
use of org.aion.base.type.Address in project aion by aionnetwork.
the class PendingTxCache method flush.
public List<AionTransaction> flush(Map<Address, BigInteger> nonceMap) {
if (nonceMap == null) {
throw new NullPointerException();
}
List<AionTransaction> processableTx = new ArrayList<>();
for (Address addr : nonceMap.keySet()) {
BigInteger bn = nonceMap.get(addr);
if (LOG.isDebugEnabled()) {
LOG.debug("cacheTx.flush addr[{}] bn[{}] size[{}], cache_size[{}]", addr.toString(), bn.toString(), cacheTxMap.get(addr).size(), currentSize.get());
}
if (cacheTxMap.get(addr) != null) {
currentSize.addAndGet(-getAccountSize(cacheTxMap.get(addr)));
cacheTxMap.get(addr).headMap(bn).clear();
currentSize.addAndGet(getAccountSize(cacheTxMap.get(addr)));
if (LOG.isDebugEnabled()) {
LOG.debug("cacheTx.flush after addr[{}] size[{}], cache_size[{}]", addr.toString(), cacheTxMap.get(addr).size(), currentSize.get());
}
if (cacheTxMap.get(addr).get(bn) != null) {
processableTx.add(cacheTxMap.get(addr).get(bn));
}
}
}
return processableTx;
}
use of org.aion.base.type.Address in project aion by aionnetwork.
the class AionRepositoryCache method flush.
/**
* @implNote To maintain intended functionality this method does not call
* the parent's {@code flush()} method. The changes are propagated
* to the parent through calling the parent's
* {@code updateBatch()} method.
*/
@Override
public synchronized void flush() {
// determine which accounts should get stored
HashMap<Address, AccountState> cleanedCacheAccounts = new HashMap<>();
for (Map.Entry<Address, AccountState> entry : cachedAccounts.entrySet()) {
AccountState account = entry.getValue();
if (account != null && account.isDirty() && account.isEmpty()) {
// ignore contract state for empty accounts at storage
cachedDetails.remove(entry.getKey());
} else {
cleanedCacheAccounts.put(entry.getKey(), entry.getValue());
}
}
// determine which contracts should get stored
for (Map.Entry<Address, IContractDetails<DataWord>> entry : cachedDetails.entrySet()) {
IContractDetails<DataWord> ctd = entry.getValue();
// different ContractDetails implementation
if (ctd != null && ctd instanceof ContractDetailsCacheImpl) {
ContractDetailsCacheImpl contractDetailsCache = (ContractDetailsCacheImpl) ctd;
contractDetailsCache.commit();
if (contractDetailsCache.origContract == null && repository.hasContractDetails(entry.getKey())) {
// in forked block the contract account might not exist thus
// it is created without
// origin, but on the main chain details can contain data
// which should be merged
// into a single storage trie so both branches with
// different stateRoots are valid
contractDetailsCache.origContract = repository.getContractDetails(entry.getKey());
contractDetailsCache.commit();
}
}
}
repository.updateBatch(cleanedCacheAccounts, cachedDetails);
cachedAccounts.clear();
cachedDetails.clear();
}
Aggregations