Search in sources :

Example 1 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class TaskImportBlocks method importBlocks.

static void importBlocks(final AionBlockchainImpl chain, final SyncStats syncStats, final BlocksWrapper bw, final Map<ByteArrayWrapper, Object> importedBlockHashes, final SyncHeaderRequestManager syncHeaderRequestManager) {
    Thread.currentThread().setName("sync-ib");
    long startTime = System.nanoTime();
    SyncMode syncMode = syncHeaderRequestManager.getSyncMode(bw.nodeId);
    long duration = System.nanoTime() - startTime;
    surveyLog.debug("Import Stage 2: wait for peer state, duration = {} ns.", duration);
    if (syncMode == null) {
        // ignoring these blocks
        log.warn("Peer {} sent blocks that were not requested.", bw.displayId);
    } else {
        // the peerState is not null after this
        startTime = System.nanoTime();
        List<Block> batch = filterBatch(bw.blocks, chain, importedBlockHashes);
        duration = System.nanoTime() - startTime;
        surveyLog.debug("Import Stage 3: filter batch, duration = {} ns.", duration);
        startTime = System.nanoTime();
        // process batch and update the peer state
        SyncMode newMode = processBatch(chain, importedBlockHashes, syncStats, syncMode, batch, bw.displayId);
        duration = System.nanoTime() - startTime;
        surveyLog.debug("Import Stage 4: process received and disk batches, duration = {} ns.", duration);
        // transition to recommended sync mode
        if (syncMode != newMode) {
            syncHeaderRequestManager.runInMode(bw.nodeId, newMode);
        }
        syncStats.update(getBestBlockNumber(chain));
    }
}
Also used : Block(org.aion.zero.impl.types.Block) SyncMode(org.aion.zero.impl.sync.SyncHeaderRequestManager.SyncMode)

Example 2 with Block

use of org.aion.zero.impl.types.Block 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 3 with Block

use of org.aion.zero.impl.types.Block 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 4 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class ReqBlocksBodiesHandler method receive.

@Override
public void receive(int _nodeIdHashcode, String _displayId, final byte[] _msgBytes) {
    if (isSyncOnlyNode)
        return;
    ReqBlocksBodies reqBlocks = ReqBlocksBodies.decode(_msgBytes);
    if (reqBlocks != null) {
        // limit number of blocks
        List<byte[]> hashes = reqBlocks.getBlocksHashes();
        hashes = hashes.size() > MAX_NUM_OF_BLOCKS ? hashes.subList(0, MAX_NUM_OF_BLOCKS) : hashes;
        // results
        List<byte[]> blockBodies = new ArrayList<>();
        // read from cache, then block store
        int out = 0;
        for (byte[] hash : hashes) {
            // ref for add.
            byte[] blockBytesForadd;
            byte[] blockBytes = cache.get(ByteArrayWrapper.wrap(hash));
            // if cached , add.
            if (blockBytes != null) {
                blockBytesForadd = blockBytes;
            } else {
                Block block = blockchain.getBlockByHash(hash);
                if (block != null) {
                    blockBytesForadd = block.getEncodedBody();
                    cache.put(ByteArrayWrapper.wrap(hash), block.getEncodedBody());
                } else {
                    // not found
                    break;
                }
            }
            if ((out += blockBytesForadd.length) > P2pConstant.MAX_BODY_SIZE) {
                log.debug("<req-blocks-bodies-max-size-reach size={}/{}>", out, P2pConstant.MAX_BODY_SIZE);
                break;
            }
            blockBodies.add(blockBytesForadd);
        }
        this.p2pMgr.send(_nodeIdHashcode, _displayId, new ResBlocksBodies(blockBodies.toArray()));
        this.syncMgr.getSyncStats().updateTotalBlockRequestsByPeer(_displayId, blockBodies.size());
        if (log.isDebugEnabled()) {
            this.log.debug("<req-bodies req-size={} res-size={} node={}>", reqBlocks.getBlocksHashes().size(), blockBodies.size(), _displayId);
        }
    } else {
        this.log.error("<req-bodies decode-error, unable to decode bodies from {}, len: {}>", _displayId, _msgBytes.length);
        if (this.log.isTraceEnabled()) {
            this.log.trace("req-bodies dump: {}", ByteUtil.toHexString(_msgBytes));
        }
    }
}
Also used : ResBlocksBodies(org.aion.zero.impl.sync.msg.ResBlocksBodies) ArrayList(java.util.ArrayList) Block(org.aion.zero.impl.types.Block) ReqBlocksBodies(org.aion.zero.impl.sync.msg.ReqBlocksBodies)

Example 5 with Block

use of org.aion.zero.impl.types.Block in project aion by aionnetwork.

the class ReqStatusHandler method receive.

@Override
public void receive(int _nodeIdHashcode, String _displayId, byte[] _msg) {
    long now = System.currentTimeMillis();
    if ((now - cacheTs) > this.UPDATE_INTERVAL) {
        synchronized (cache) {
            try {
                Block bestBlock = chain.getBestBlock();
                cache = new ResStatus(bestBlock.getNumber(), bestBlock.getTotalDifficulty().toByteArray(), bestBlock.getHash(), this.genesisHash, this.apiVersion, (short) this.mgr.getActiveNodes().size(), BigInteger.valueOf(this.pendingState.getPendingTxSize()).toByteArray(), this.mgr.getAvgLatency());
            } catch (Exception e) {
                if (log.isDebugEnabled()) {
                    log.debug("ReqStatus exception {}", e.toString());
                }
            }
            cacheTs = now;
        }
    }
    this.mgr.send(_nodeIdHashcode, _displayId, cache);
    if (log.isDebugEnabled()) {
        this.log.debug("<req-status node={} return-blk={}>", _displayId, cache.getBestBlockNumber());
    }
}
Also used : ResStatus(org.aion.zero.impl.sync.msg.ResStatus) Block(org.aion.zero.impl.types.Block)

Aggregations

Block (org.aion.zero.impl.types.Block)283 MiningBlock (org.aion.zero.impl.types.MiningBlock)155 Test (org.junit.Test)148 AionTransaction (org.aion.base.AionTransaction)106 ImportResult (org.aion.zero.impl.core.ImportResult)86 ArrayList (java.util.ArrayList)63 AionAddress (org.aion.types.AionAddress)61 StakingBlock (org.aion.zero.impl.types.StakingBlock)58 AionBlockSummary (org.aion.zero.impl.types.AionBlockSummary)57 BigInteger (java.math.BigInteger)55 AionRepositoryImpl (org.aion.zero.impl.db.AionRepositoryImpl)34 ByteArrayWrapper (org.aion.util.types.ByteArrayWrapper)30 AionTxReceipt (org.aion.base.AionTxReceipt)29 Hex.toHexString (org.aion.util.conversions.Hex.toHexString)28 AccountState (org.aion.base.AccountState)26 EventBlock (org.aion.evtmgr.impl.evt.EventBlock)26 JSONArray (org.json.JSONArray)26 JSONObject (org.json.JSONObject)26 MiningBlockHeader (org.aion.zero.impl.types.MiningBlockHeader)22 AionTxExecSummary (org.aion.base.AionTxExecSummary)20