Search in sources :

Example 1 with ImportResult

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;
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) Set(java.util.Set) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) Block(org.aion.zero.impl.types.Block) SyncMode(org.aion.zero.impl.sync.SyncHeaderRequestManager.SyncMode)

Example 2 with ImportResult

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;
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) Set(java.util.Set) ArrayList(java.util.ArrayList) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) Block(org.aion.zero.impl.types.Block) ArrayList(java.util.ArrayList) List(java.util.List) Map(java.util.Map)

Example 3 with ImportResult

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;
}
Also used : BlockWrapper(org.aion.zero.impl.blockchain.BlockWrapper) AionLoggerFactory(org.aion.log.AionLoggerFactory) IP2pMgr(org.aion.p2p.IP2pMgr) BlockHeaderValidator(org.aion.zero.impl.valid.BlockHeaderValidator) Logger(org.slf4j.Logger) BlockWrapper(org.aion.zero.impl.blockchain.BlockWrapper) IAionBlockchain(org.aion.zero.impl.blockchain.IAionBlockchain) ImportResult(org.aion.zero.impl.core.ImportResult) BroadcastNewBlock(org.aion.zero.impl.sync.msg.BroadcastNewBlock) BlockType(org.aion.zero.impl.sync.statistics.BlockType) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) LRUMap(org.apache.commons.collections4.map.LRUMap) AionPendingStateImpl(org.aion.zero.impl.pendingState.AionPendingStateImpl) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) LogEnum(org.aion.log.LogEnum) SyncStats(org.aion.zero.impl.sync.SyncStats) Map(java.util.Map) ResStatus(org.aion.zero.impl.sync.msg.ResStatus) BigInteger(java.math.BigInteger) Block(org.aion.zero.impl.types.Block) CfgAion(org.aion.zero.impl.config.CfgAion) ImportResult(org.aion.zero.impl.core.ImportResult) ResStatus(org.aion.zero.impl.sync.msg.ResStatus) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) BroadcastNewBlock(org.aion.zero.impl.sync.msg.BroadcastNewBlock) Block(org.aion.zero.impl.types.Block) BigInteger(java.math.BigInteger)

Example 4 with ImportResult

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());
        }
    }
}
Also used : ImportResult(org.aion.zero.impl.core.ImportResult) MiningBlock(org.aion.zero.impl.types.MiningBlock)

Example 5 with ImportResult

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();
}
Also used : AionAddress(org.aion.types.AionAddress) ImportResult(org.aion.zero.impl.core.ImportResult) AionTransaction(org.aion.base.AionTransaction) MiningBlock(org.aion.zero.impl.types.MiningBlock) AionBlockSummary(org.aion.zero.impl.types.AionBlockSummary) IAvmResourceFactory(org.aion.avm.stub.IAvmResourceFactory) BigInteger(java.math.BigInteger) AionRepositoryCache(org.aion.zero.impl.db.AionRepositoryCache) RepositoryCache(org.aion.base.db.RepositoryCache) AionTxReceipt(org.aion.base.AionTxReceipt) AvmVersion(org.aion.avm.stub.AvmVersion) Test(org.junit.Test)

Aggregations

ImportResult (org.aion.zero.impl.core.ImportResult)166 Test (org.junit.Test)127 AionTransaction (org.aion.base.AionTransaction)114 AionAddress (org.aion.types.AionAddress)106 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)95 MiningBlock (org.aion.zero.impl.types.MiningBlock)90 Block (org.aion.zero.impl.types.Block)80 BigInteger (java.math.BigInteger)75 AionTxReceipt (org.aion.base.AionTxReceipt)50 AionTxExecSummary (org.aion.base.AionTxExecSummary)31 ECKey (org.aion.crypto.ECKey)28 RepositoryCache (org.aion.base.db.RepositoryCache)22 StandaloneBlockchain (org.aion.zero.impl.blockchain.StandaloneBlockchain)22 InternalTransaction (org.aion.types.InternalTransaction)20 AccountState (org.aion.base.AccountState)18 ArrayList (java.util.ArrayList)17 AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock (org.aion.zero.impl.blockchain.AionBlockchainImpl.getPostExecutionWorkForGeneratePreBlock)16 Builder (org.aion.zero.impl.blockchain.StandaloneBlockchain.Builder)14 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)10 BlockContext (org.aion.zero.impl.types.BlockContext)9