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);
}
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));
}
}
}
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();
}
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);
}
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);
}
Aggregations