use of org.aion.zero.impl.core.ImportResult in project aion by aionnetwork.
the class TaskImportBlocks method processBatch.
/**
* @implNote This method is called only when state is not null.
*/
private static SyncMode processBatch(AionBlockchainImpl chain, Map<ByteArrayWrapper, Object> importedBlockHashes, SyncStats syncStats, SyncMode syncMode, List<Block> batch, String displayId) {
// for runtime survey information
long startTime, duration;
// interpreted as repeated work
if (batch.isEmpty()) {
log.debug("Empty batch received from node = {} in mode = {}.", displayId, syncMode);
// we therefore reset this peer to (possibly) do something other than its previous mode
return NORMAL;
}
// check last block in batch to see if we can skip batch
if (syncMode != BACKWARD) {
Block b = batch.get(batch.size() - 1);
// implies the full batch was already imported (but not filtered by the queue)
if (chain.isBlockStored(b.getHash(), b.getNumber())) {
// keeping track of the last block check
importedBlockHashes.put(ByteArrayWrapper.wrap(b.getHash()), true);
// skipping the batch
log.debug("Skip {} blocks from node = {} in mode = {}.", batch.size(), displayId, syncMode);
batch.clear();
if (syncMode == FORWARD) {
return FORWARD;
} else {
return NORMAL;
}
}
}
// remembering imported range
Block firstInBatch = batch.get(0);
long first = firstInBatch.getNumber(), last = -1L, currentBest;
ImportResult importResult = null;
SyncMode returnMode = syncMode;
startTime = System.nanoTime();
try {
long importDuration = System.currentTimeMillis();
Triple<Long, Set<ByteArrayWrapper>, ImportResult> resultTriple = chain.tryToConnect(batch, displayId);
importDuration = System.currentTimeMillis() - importDuration;
currentBest = resultTriple.getLeft();
Set<ByteArrayWrapper> importedHashes = resultTriple.getMiddle();
importResult = resultTriple.getRight();
int count = importedHashes.size();
if (currentBest >= first) {
last = currentBest + 1;
importedHashes.stream().forEach(v -> importedBlockHashes.put(v, true));
syncStats.updatePeerBlocks(displayId, count, BlockType.IMPORTED);
log.info("<import-status: node = {}, from = #{}, to = #{}, time elapsed = {} ms>", displayId, first, currentBest, importDuration);
}
} catch (Exception e) {
log.error("<import-block throw> ", e);
if (e.getMessage() != null && e.getMessage().contains("No space left on device")) {
log.error("Shutdown due to lack of disk space.", e);
System.exit(SystemExitCodes.OUT_OF_DISK_SPACE);
}
}
// if any block results in NO_PARENT, all subsequent blocks will too
if (importResult == ImportResult.NO_PARENT) {
int stored = chain.storePendingBlockRange(batch, log);
syncStats.updatePeerBlocks(displayId, stored, BlockType.STORED);
// check if it is below the current importable blocks
if (firstInBatch.getNumber() <= getBestBlockNumber(chain) + 1) {
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.A: import received batch, duration = {} ns.", duration);
return BACKWARD;
}
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.A: import received batch, duration = {} ns.", duration);
return returnMode;
} else if (importResult.isStored()) {
if (syncMode == BACKWARD) {
returnMode = FORWARD;
} else if (syncMode == FORWARD && importResult.isBest()) {
returnMode = NORMAL;
}
}
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.A: import received batch, duration = {} ns.", duration);
startTime = System.nanoTime();
// check for stored blocks
if (first < last) {
returnMode = importFromStorage(chain, importedBlockHashes, returnMode, first, last);
}
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.B: process all disk batches, duration = {} ns.", duration);
return returnMode;
}
use of org.aion.zero.impl.core.ImportResult in project aion by aionnetwork.
the class TaskImportBlocks method importFromStorage.
/**
* Imports blocks from storage as long as there are blocks to import.
*
* @return the total number of imported blocks from all iterations
*/
private static SyncMode importFromStorage(AionBlockchainImpl chain, Map<ByteArrayWrapper, Object> importedBlockHashes, SyncMode givenMode, long first, long last) {
// for runtime survey information
long startTime, duration;
ImportResult importResult = ImportResult.NO_PARENT;
int imported = 0, batch;
long level = first;
while (level <= last) {
startTime = System.nanoTime();
// get blocks stored for level
Map<ByteArrayWrapper, List<Block>> levelFromDisk = chain.loadPendingBlocksAtLevel(level, log);
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.B.i: load batch from disk, duration = {} ns.", duration);
if (levelFromDisk.isEmpty()) {
// move on to next level
level++;
continue;
}
List<ByteArrayWrapper> importedQueues = new ArrayList<>(levelFromDisk.keySet());
for (Map.Entry<ByteArrayWrapper, List<Block>> entry : levelFromDisk.entrySet()) {
// initialize batch counter
batch = 0;
List<Block> batchFromDisk = entry.getValue();
startTime = System.nanoTime();
// filter already imported blocks
batchFromDisk = filterBatch(batchFromDisk, chain, importedBlockHashes);
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.B.ii: filter batch from disk, duration = {} ns.", duration);
if (!batchFromDisk.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("{} {} left after filtering out imported blocks.", batchFromDisk.size(), (batchFromDisk.size() == 1 ? "block" : "blocks"));
}
} else {
if (log.isDebugEnabled()) {
log.debug("No blocks left after filtering out imported blocks.");
}
// this queue will be deleted from storage
continue;
}
startTime = System.nanoTime();
try {
first = batchFromDisk.get(0).getNumber();
long importDuration = System.currentTimeMillis();
Triple<Long, Set<ByteArrayWrapper>, ImportResult> resultTriple = chain.tryToConnect(batchFromDisk, "STORAGE");
importDuration = System.currentTimeMillis() - importDuration;
long currentBest = resultTriple.getLeft();
Set<ByteArrayWrapper> importedHashes = resultTriple.getMiddle();
importResult = resultTriple.getRight();
batch = importedHashes.size();
if (currentBest >= first) {
last = currentBest + 1;
importedHashes.stream().forEach(v -> importedBlockHashes.put(v, true));
log.info("<import-status: node = {}, from = #{}, to = #{}, time elapsed = {} ms>", "STORAGE", first, currentBest, importDuration);
} else {
// do not delete queue from storage
importedQueues.remove(entry.getKey());
// stop importing this queue
break;
}
} catch (Exception e) {
log.error("<import-block throw> ", e);
if (e.getMessage() != null && e.getMessage().contains("No space left on device")) {
log.error("Shutdown due to lack of disk space.", e);
System.exit(SystemExitCodes.OUT_OF_DISK_SPACE);
}
}
duration = System.nanoTime() - startTime;
surveyLog.debug("Import Stage 4.B.iii: import batch from disk, duration = {} ns.", duration);
imported += batch;
}
// remove imported data from storage
chain.dropImported(level, importedQueues, levelFromDisk, log);
// increment level
level++;
}
log.debug("Imported {} blocks from storage.", imported);
// switch to NORMAL if in FORWARD mode
if (importResult.isBest()) {
return NORMAL;
} else if (importResult.isStored() && givenMode == BACKWARD) {
return FORWARD;
}
return givenMode;
}
use of org.aion.zero.impl.core.ImportResult in project aion by aionnetwork.
the class BlockPropagationHandler method processIncomingBlock.
public PropStatus processIncomingBlock(final int nodeId, final String displayId, final Block block) {
if (block == null)
return PropStatus.DROPPED;
ByteArrayWrapper hashWrapped = block.getHashWrapper();
if (!this.blockHeaderValidator.validate(block.getHeader(), log))
return PropStatus.DROPPED;
// guarantees if multiple requests of same block appears, only one goes through
synchronized (this.cacheMap) {
if (this.cacheMap.get(hashWrapped) != null) {
if (log.isTraceEnabled()) {
log.trace("block {} already cached", block.getShortHash());
}
return PropStatus.DROPPED;
}
// regardless if block processing is successful, place into cache
this.cacheMap.put(hashWrapped, true);
}
// process
long t1 = System.currentTimeMillis();
ImportResult result;
if (this.blockchain.skipTryToConnect(block.getNumber())) {
result = ImportResult.NO_PARENT;
if (log.isInfoEnabled()) {
log.info("<import-status: node = {}, hash = {}, number = {}, txs = {}, result = NOT_IN_RANGE>", displayId, block.getShortHash(), block.getNumber(), block.getTransactionsList().size(), result);
} else if (log.isDebugEnabled()) {
log.debug("<import-status: node = {}, hash = {}, number = {}, txs = {}, block time = {}, result = NOT_IN_RANGE>", displayId, block.getShortHash(), block.getNumber(), block.getTransactionsList().size(), block.getTimestamp(), result);
}
} else {
result = this.blockchain.tryToConnect(new BlockWrapper(block));
long t2 = System.currentTimeMillis();
if (result.isStored()) {
this.syncStats.updatePeerBlocks(displayId, 1, BlockType.IMPORTED);
}
if (log.isInfoEnabled()) {
log.info("<import-status: node = {}, hash = {}, number = {}, txs = {}, result = {}, time elapsed = {} ms>", displayId, block.getShortHash(), block.getNumber(), block.getTransactionsList().size(), result, t2 - t1);
} else if (log.isDebugEnabled()) {
log.debug("<import-status: node = {}, hash = {}, number = {}, td = {}, txs = {}, block time = {}, result = {}, time elapsed = {} ms>", displayId, block.getShortHash(), block.getNumber(), blockchain.getTotalDifficulty(), block.getTransactionsList().size(), block.getTimestamp(), result, t2 - t1);
}
}
// send
boolean sent = result.isBest() && send(block, nodeId);
// notify higher td peers in order to limit the rebroadcast on delay of res status updating
if (result.isBest()) {
Block bestBlock = blockchain.getBestBlock();
BigInteger td = bestBlock.getTotalDifficulty();
ResStatus rs = new ResStatus(bestBlock.getNumber(), td.toByteArray(), bestBlock.getHash(), genesis, apiVersion, (short) p2pManager.getActiveNodes().size(), BigInteger.valueOf(this.pendingState.getPendingTxSize()).toByteArray(), p2pManager.getAvgLatency());
this.p2pManager.getActiveNodes().values().stream().filter(n -> n.getIdHash() != nodeId).filter(n -> n.getTotalDifficulty().compareTo(td) >= 0).forEach(n -> {
log.debug("<push-status blk={} hash={} to-node={} dd={} import-result={}>", block.getNumber(), block.getShortHash(), n.getIdShort(), td.longValue() - n.getTotalDifficulty().longValue(), result.name());
this.p2pManager.send(n.getIdHash(), n.getIdShort(), rs);
});
}
// process resulting state
if (sent && result.isSuccessful())
return PropStatus.PROP_CONNECTED;
if (result.isSuccessful())
return PropStatus.CONNECTED;
if (sent)
return PropStatus.PROPAGATED;
// gets dropped when the result is not valid
return PropStatus.DROPPED;
}
use of org.aion.zero.impl.core.ImportResult in project aion by aionnetwork.
the class AionPoW method processSolution.
/**
* Processes a received solution.
*
* @param solution The generated equihash solution
*/
private synchronized void processSolution(AionPowSolution solution) {
if (!shutDown.get()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Best block num [{}]", blockchain.getBestBlock().getNumber());
LOG.debug("Best block hash [{}]", Hex.toHexString(blockchain.getBestBlock().getHash()));
}
MiningBlock block = solution.getBlock();
if (!Arrays.equals(block.getHeader().getNonce(), new byte[32]) && !(block.getHeader().getNonce().length == 0)) {
// block has been processed
return;
}
// set the nonce and solution
try {
block.seal(solution.getNonce(), solution.getSolution());
} catch (Exception e) {
LOG.error("seal block failed!", e);
return;
}
// This can be improved
ImportResult importResult = AionImpl.inst().addNewBlock(block);
// Check that the new block was successfully added
if (importResult.isSuccessful()) {
if (importResult == IMPORTED_BEST) {
LOG.info("block sealed <num={}, hash={}, diff={}, tx={}>", block.getNumber(), block.getShortHash(), block.getHeader().getDifficultyBI().toString(), block.getTransactionsList().size());
} else {
LOG.debug("block sealed <num={}, hash={}, diff={}, td={}, tx={}, result={}>", block.getNumber(), block.getShortHash(), block.getHeader().getDifficultyBI().toString(), blockchain.getTotalDifficulty(), block.getTransactionsList().size(), importResult);
}
// TODO: fire block mined event
} else {
LOG.info("Unable to import a new mined block; restarting mining.\n" + "Mined block import result is " + importResult + " : " + block.getShortHash());
}
}
}
use of org.aion.zero.impl.core.ImportResult in project aion by aionnetwork.
the class ContractIntegTest method testDeployAvmContractToAnExistedAccount.
@Test
public void testDeployAvmContractToAnExistedAccount() {
AvmVersion version = AvmVersion.VERSION_1;
if (txType == TransactionTypes.DEFAULT) {
return;
}
long nrg = 1_000_000;
long nrgPrice = energyPrice;
BigInteger value = BigInteger.ONE;
AionAddress avmAddress = TxUtil.calculateContractAddress(deployer.toByteArray(), deployerNonce);
// create a tx the sender send some balance to the account the deployer will deploy in the
// feature.
AionTransaction tx = AionTransaction.create(senderKey, senderNonce.toByteArray(), avmAddress, value.toByteArray(), new byte[0], nrg, nrgPrice, TransactionTypes.DEFAULT, null);
assertFalse(tx.isContractCreationTransaction());
MiningBlock block = makeBlock(tx);
assertEquals(1, block.getTransactionsList().size());
Pair<ImportResult, AionBlockSummary> result = blockchain.tryToConnectAndFetchSummary(block);
assertTrue(result.getLeft().isSuccessful());
RepositoryCache repo = blockchain.getRepository().startTracking();
assertEquals(BigInteger.ONE, repo.getBalance(avmAddress));
BigInteger txCost = BigInteger.valueOf(nrgPrice).multiply(BigInteger.valueOf(result.getRight().getReceipts().get(0).getEnergyUsed()));
assertEquals(senderBalance.subtract(BigInteger.ONE).subtract(txCost), repo.getBalance(sender));
senderNonce = senderNonce.add(BigInteger.ONE);
AionAddress avmDeployedAddress = deployAvmContract(version, deployerNonce);
assertNotNull(avmAddress);
assertEquals(avmAddress, avmDeployedAddress);
repo = blockchain.getRepository().startTracking();
IAvmResourceFactory factory = (version == AvmVersion.VERSION_1) ? this.resourceProvider.factoryForVersion1 : this.resourceProvider.factoryForVersion2;
byte[] avmCode = factory.newContractFactory().getJarBytes(AvmContract.HELLO_WORLD);
assertArrayEquals(avmCode, repo.getCode(avmAddress));
assertEquals(BigInteger.ONE, repo.getBalance(avmAddress));
byte[] call = getCallArguments(version);
tx = AionTransaction.create(deployerKey, deployerNonce.add(BigInteger.ONE).toByteArray(), avmAddress, BigInteger.ZERO.toByteArray(), call, 2_000_000, nrgPrice, TransactionTypes.DEFAULT, null);
block = this.blockchain.createNewMiningBlock(this.blockchain.getBestBlock(), Collections.singletonList(tx), false);
Pair<ImportResult, AionBlockSummary> connectResult = this.blockchain.tryToConnectAndFetchSummary(block);
AionTxReceipt receipt = connectResult.getRight().getReceipts().get(0);
// Check the block was imported and the transaction was successful.
assertThat(connectResult.getLeft()).isEqualTo(ImportResult.IMPORTED_BEST);
assertThat(receipt.isSuccessful()).isTrue();
}
Aggregations