Search in sources :

Example 1 with BlockHeader

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

the class SyncMgr method requestBodies.

/**
 * Requests the bodies associated to the given block headers.
 */
void requestBodies(int nodeId, String displayId) {
    Thread.currentThread().setName("sync-gb-" + Thread.currentThread().getId());
    long startTime = System.nanoTime();
    List<List<BlockHeader>> forRequests = syncHeaderRequestManager.getHeadersForBodiesRequests(nodeId);
    for (List<BlockHeader> requestHeaders : forRequests) {
        // Filter headers again in case the blockchain has advanced while this task was waiting to be executed.
        List<BlockHeader> filtered = requestHeaders.stream().filter(h -> !importedBlockHashes.containsKey(ByteArrayWrapper.wrap(h.getHash()))).collect(Collectors.toList());
        // Check the peer state and discard blocks that are under the current best (in case the hashes already dropped from the above map).
        // This check is only applicable for SyncMode.NORMAL because the other sync modes deal with side chains.
        long currentBest = chain.getBestBlock() == null ? 0L : chain.getBestBlock().getNumber();
        long firstInBatch = requestHeaders.get(0).getNumber();
        if (syncHeaderRequestManager.getSyncMode(nodeId) == SyncMode.NORMAL && firstInBatch <= currentBest) {
            // remove all blocks in the batch that are under the current best
            for (Iterator<BlockHeader> it = filtered.iterator(); it.hasNext(); ) {
                if (it.next().getNumber() <= currentBest) {
                    it.remove();
                }
            }
        }
        if (filtered.size() == requestHeaders.size()) {
            // Log bodies request before sending the request.
            log.debug("<get-bodies from-num={} to-num={} node={}>", firstInBatch, requestHeaders.get(requestHeaders.size() - 1).getNumber(), displayId);
            p2pMgr.send(nodeId, displayId, new ReqBlocksBodies(requestHeaders.stream().map(k -> k.getHash()).collect(Collectors.toList())));
            stats.updateTotalRequestsToPeer(displayId, RequestType.BODIES);
            stats.updateRequestTime(displayId, System.nanoTime(), RequestType.BODIES);
        } else {
            // Drop the headers that are already known.
            syncHeaderRequestManager.dropHeaders(nodeId, requestHeaders);
            if (!filtered.isEmpty()) {
                // Store the subset that is still useful.
                syncHeaderRequestManager.storeHeaders(nodeId, filtered);
            }
        }
    }
    long duration = System.nanoTime() - startTime;
    survey_log.debug("TaskGetBodies: make request, duration = {} ns.", duration);
}
Also used : IP2pMgr(org.aion.p2p.IP2pMgr) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) IEvent(org.aion.evtmgr.IEvent) LRUMap(org.apache.commons.collections4.map.LRUMap) ArrayList(java.util.ArrayList) BlockHeader(org.aion.zero.impl.types.BlockHeader) HashSet(java.util.HashSet) ByteArrayWrapper(org.aion.util.types.ByteArrayWrapper) IEventMgr(org.aion.evtmgr.IEventMgr) BlockUtil(org.aion.zero.impl.types.BlockUtil) Map(java.util.Map) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) INode(org.aion.p2p.INode) SharedRLPList(org.aion.rlp.SharedRLPList) SyncMode(org.aion.zero.impl.sync.SyncHeaderRequestManager.SyncMode) BigInteger(java.math.BigInteger) ReqBlocksBodies(org.aion.zero.impl.sync.msg.ReqBlocksBodies) RequestType(org.aion.zero.impl.sync.statistics.RequestType) Block(org.aion.zero.impl.types.Block) ExecutorService(java.util.concurrent.ExecutorService) AionLoggerFactory(org.aion.log.AionLoggerFactory) StringUtils.getNodeIdShort(org.aion.util.string.StringUtils.getNodeIdShort) BlockHeaderValidator(org.aion.zero.impl.valid.BlockHeaderValidator) Hex(org.aion.util.conversions.Hex) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) BlockType(org.aion.zero.impl.sync.statistics.BlockType) Set(java.util.Set) AionBlockchainImpl(org.aion.zero.impl.blockchain.AionBlockchainImpl) LinkedBlockingQueue(java.util.concurrent.LinkedBlockingQueue) Collectors(java.util.stream.Collectors) ChainConfiguration(org.aion.zero.impl.blockchain.ChainConfiguration) Executors(java.util.concurrent.Executors) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) LogEnum(org.aion.log.LogEnum) ReqStatus(org.aion.zero.impl.sync.msg.ReqStatus) StatsType(org.aion.zero.impl.config.StatsType) VisibleForTesting(com.google.common.annotations.VisibleForTesting) EventConsensus(org.aion.evtmgr.impl.evt.EventConsensus) Collections(java.util.Collections) ArrayList(java.util.ArrayList) SharedRLPList(org.aion.rlp.SharedRLPList) List(java.util.List) BlockHeader(org.aion.zero.impl.types.BlockHeader) ReqBlocksBodies(org.aion.zero.impl.sync.msg.ReqBlocksBodies)

Example 2 with BlockHeader

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

the class SyncMgr method validateAndAddHeaders.

/**
 * Validate the received batch of block headers, dispatch a request for the matching bodies and save the headers for
 * assembling the blocks when the bodies are received.
 *
 * @param nodeId the identifier of the peer that sent the block headers
 * @param displayId the display identifier for the peer that sent the block headers
 * @param headers the block headers received from the peer
 */
public void validateAndAddHeaders(int nodeId, String displayId, List<BlockHeader> headers) {
    if (headers == null || headers.isEmpty()) {
        p2pMgr.errCheck(nodeId, displayId);
        log.error("<validate-headers: received empty/null headers from node={}>", displayId);
    } else {
        log.debug("<validate-headers: received start-block={} list-size={} node={}>", headers.get(0).getNumber(), headers.size(), displayId);
        // Filter imported block headers.
        List<BlockHeader> filtered = new ArrayList<>();
        BlockHeader prev = null;
        for (BlockHeader current : headers) {
            // Stop validating this batch if any invalidated header. Keep and import the valid ones.
            if (!blockHeaderValidator.validate(current, log)) {
                log.debug("<validate-headers: received invalid header number={} hash={}>", current.getNumber(), current.getHashWrapper());
                // Print header to allow debugging.
                log.trace("<validate-headers: received invalid header {}>", current.toString());
                break;
            }
            // Break if non-sequential blocks.
            if (prev != null && (current.getNumber() != (prev.getNumber() + 1) || !current.getParentHashWrapper().equals(prev.getHashWrapper()))) {
                log.debug("<validate-headers: received non-sequential block headers node={} block-number={} expected-number={} parent-hash={} previous-hash={}>", displayId, current.getNumber(), prev.getNumber() + 1, current.getParentHashWrapper(), prev.getHashWrapper());
                break;
            }
            // Check for already imported blocks.
            if (!importedBlockHashes.containsKey(current.getHashWrapper())) {
                filtered.add(current);
            }
            prev = current;
        }
        // Request bodies for the remaining headers (which are still a sequential list).
        if (!filtered.isEmpty()) {
            // Save headers for future bodies requests and matching with the received bodies.
            syncHeaderRequestManager.storeHeaders(nodeId, filtered);
            syncExecutors.execute(() -> requestBodies(nodeId, displayId));
        }
    }
}
Also used : ArrayList(java.util.ArrayList) BlockHeader(org.aion.zero.impl.types.BlockHeader)

Example 3 with BlockHeader

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

the class SyncMgrTest method testRequestBodies_withFilteringOnBlockHash.

@Test
public void testRequestBodies_withFilteringOnBlockHash() {
    BlockHeader header = mock(BlockHeader.class);
    when(header.getNumber()).thenReturn(100L);
    byte[] hash = Hex.decode("6fd8dae3304a9864f460ec7aec21bc94e14e34876e5dddd0a74d9c68ac7bc9ed");
    when(header.getHash()).thenReturn(hash);
    when(header.getTxTrieRootWrapper()).thenReturn(EMPTY_TRIE_HASH);
    List<BlockHeader> list = new ArrayList<>();
    list.add(header);
    syncMgr.syncHeaderRequestManager.storeHeaders(1, list);
    syncMgr.importedBlockHashes.put(ByteArrayWrapper.wrap(hash), true);
    syncMgr.requestBodies(1, "peer1");
    // ensure that 1 request was sent
    verify(p2pMgr, never()).send(anyInt(), anyString(), any(ReqBlocksBodies.class));
    assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(1, 1, EMPTY_TRIE_HASH)).isNull();
}
Also used : ArrayList(java.util.ArrayList) BlockHeader(org.aion.zero.impl.types.BlockHeader) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) ReqBlocksBodies(org.aion.zero.impl.sync.msg.ReqBlocksBodies) Test(org.junit.Test)

Example 4 with BlockHeader

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

the class SyncMgrTest method testValidateAndAddHeaders_withImportedBlocks.

@Test
public void testValidateAndAddHeaders_withImportedBlocks() {
    int nodeId = 1;
    String displayId = "peer1";
    List<BlockHeader> importedBlocks = new ArrayList<>();
    importedBlocks.add(consecutiveHeaders.get(0));
    importedBlocks.add(consecutiveHeaders.get(1));
    syncMgr.importedBlockHashes.put(importedBlocks.get(0).getHashWrapper(), true);
    syncMgr.importedBlockHashes.put(importedBlocks.get(1).getHashWrapper(), true);
    List<BlockHeader> newHeaders = new ArrayList<>();
    newHeaders.add(consecutiveHeaders.get(2));
    newHeaders.add(consecutiveHeaders.get(3));
    newHeaders.add(consecutiveHeaders.get(4));
    List<BlockHeader> headers = new ArrayList<>();
    headers.addAll(importedBlocks);
    headers.addAll(newHeaders);
    syncMgr.validateAndAddHeaders(nodeId, displayId, headers);
    verify(p2pMgr, never()).errCheck(nodeId, displayId);
    // Check that the sequential subset of headers was stored.
    assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, importedBlocks.size(), importedBlocks.get(0).getTxTrieRootWrapper())).isNull();
    assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, headers.size(), headers.get(0).getTxTrieRootWrapper())).isNull();
    List<BlockHeader> stored = syncMgr.syncHeaderRequestManager.matchAndDropHeaders(nodeId, newHeaders.size(), newHeaders.get(0).getTxTrieRootWrapper());
    assertThat(stored.size()).isEqualTo(newHeaders.size());
    assertThat(stored).containsAllIn(newHeaders);
}
Also used : ArrayList(java.util.ArrayList) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) BlockHeader(org.aion.zero.impl.types.BlockHeader) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) Test(org.junit.Test)

Example 5 with BlockHeader

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

the class SyncMgrTest method testRequestBodies_withTwoRequests.

@Test
public void testRequestBodies_withTwoRequests() {
    BlockHeader header1 = mock(BlockHeader.class);
    when(header1.getNumber()).thenReturn(101L);
    byte[] hash1 = Hex.decode("6fd8dae3304a9864f460ec7aec21bc94e14e34876e5dddd0a74d9c68ac7bc9ed");
    when(header1.getHash()).thenReturn(hash1);
    when(header1.getTxTrieRootWrapper()).thenReturn(EMPTY_TRIE_HASH);
    List<BlockHeader> list1 = new ArrayList<>();
    list1.add(header1);
    syncMgr.syncHeaderRequestManager.storeHeaders(1, list1);
    BlockHeader header2 = mock(BlockHeader.class);
    when(header2.getNumber()).thenReturn(102L);
    byte[] hash2 = Hex.decode("f2652dde61042e9306dce95ecdc41a1be2be7eb374f19427aef2a79101b471ea");
    when(header2.getHash()).thenReturn(hash2);
    when(header2.getTxTrieRootWrapper()).thenReturn(EMPTY_TRIE_HASH);
    List<BlockHeader> list2 = new ArrayList<>();
    list2.add(header1);
    list2.add(header2);
    syncMgr.syncHeaderRequestManager.storeHeaders(1, list2);
    syncMgr.requestBodies(1, "peer1");
    // ensure that 1 request was sent
    verify(p2pMgr, times(2)).send(anyInt(), anyString(), any(ReqBlocksBodies.class));
    // both lists are still stored and can be retrieved in order
    assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(1, 1, EMPTY_TRIE_HASH)).isEqualTo(list1);
    assertThat(syncMgr.syncHeaderRequestManager.matchAndDropHeaders(1, 2, EMPTY_TRIE_HASH)).isEqualTo(list2);
}
Also used : ArrayList(java.util.ArrayList) BlockHeader(org.aion.zero.impl.types.BlockHeader) MiningBlockHeader(org.aion.zero.impl.types.MiningBlockHeader) ReqBlocksBodies(org.aion.zero.impl.sync.msg.ReqBlocksBodies) Test(org.junit.Test)

Aggregations

BlockHeader (org.aion.zero.impl.types.BlockHeader)29 Test (org.junit.Test)18 ArrayList (java.util.ArrayList)17 MiningBlockHeader (org.aion.zero.impl.types.MiningBlockHeader)14 ReqBlocksBodies (org.aion.zero.impl.sync.msg.ReqBlocksBodies)8 Block (org.aion.zero.impl.types.Block)7 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)4 BigInteger (java.math.BigInteger)3 EventBlock (org.aion.evtmgr.impl.evt.EventBlock)3 INode (org.aion.p2p.INode)3 SharedRLPList (org.aion.rlp.SharedRLPList)3 GenesisStakingBlock (org.aion.zero.impl.types.GenesisStakingBlock)3 MiningBlock (org.aion.zero.impl.types.MiningBlock)3 RetValidPreBlock (org.aion.zero.impl.types.RetValidPreBlock)3 StakingBlock (org.aion.zero.impl.types.StakingBlock)3 StakingBlockHeader (org.aion.zero.impl.types.StakingBlockHeader)3 BlockDetailsValidator.isValidBlock (org.aion.zero.impl.valid.BlockDetailsValidator.isValidBlock)3 List (java.util.List)2 ByteArrayWrapper (org.aion.util.types.ByteArrayWrapper)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1