7311: add GetReceiptsFromPeerTask (#7638)

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
pull/7837/head
Matilda-Clerke 3 weeks ago committed by GitHub
parent f9f721c10e
commit db29df7c8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  2. 3
      besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java
  3. 30
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  4. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java
  5. 1
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java
  6. 15
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java
  7. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTask.java
  8. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java
  9. 135
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTask.java
  10. 5
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java
  11. 53
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java
  12. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java
  13. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java
  14. 10
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java
  15. 14
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncDownloadPipelineFactory.java
  16. 80
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java
  17. 5
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java
  18. 10
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java
  19. 7
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java
  20. 3
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java
  21. 3
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java
  22. 12
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.java
  23. 264
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java
  24. 137
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java
  25. 73
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java
  26. 7
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java
  27. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java
  28. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java

@ -55,6 +55,8 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter;
import org.hyperledger.besu.ethereum.eth.manager.MonitoredExecutors; import org.hyperledger.besu.ethereum.eth.manager.MonitoredExecutors;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskRequestSender;
import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager;
import org.hyperledger.besu.ethereum.eth.peervalidation.CheckpointBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.CheckpointBlocksPeerValidator;
import org.hyperledger.besu.ethereum.eth.peervalidation.ClassicForkPeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.ClassicForkPeerValidator;
@ -653,6 +655,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
} }
final EthContext ethContext = new EthContext(ethPeers, ethMessages, snapMessages, scheduler); final EthContext ethContext = new EthContext(ethPeers, ethMessages, snapMessages, scheduler);
final PeerTaskExecutor peerTaskExecutor =
new PeerTaskExecutor(ethPeers, new PeerTaskRequestSender(), metricsSystem);
final boolean fullSyncDisabled = !SyncMode.isFullSync(syncConfig.getSyncMode()); final boolean fullSyncDisabled = !SyncMode.isFullSync(syncConfig.getSyncMode());
final SyncState syncState = new SyncState(blockchain, ethPeers, fullSyncDisabled, checkpoint); final SyncState syncState = new SyncState(blockchain, ethPeers, fullSyncDisabled, checkpoint);
@ -704,6 +708,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
worldStateStorageCoordinator, worldStateStorageCoordinator,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
ethProtocolManager, ethProtocolManager,
pivotBlockSelector); pivotBlockSelector);
@ -830,6 +835,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
* @param worldStateStorageCoordinator the world state storage * @param worldStateStorageCoordinator the world state storage
* @param protocolContext the protocol context * @param protocolContext the protocol context
* @param ethContext the eth context * @param ethContext the eth context
* @param peerTaskExecutor the PeerTaskExecutor
* @param syncState the sync state * @param syncState the sync state
* @param ethProtocolManager the eth protocol manager * @param ethProtocolManager the eth protocol manager
* @param pivotBlockSelector the pivot block selector * @param pivotBlockSelector the pivot block selector
@ -840,6 +846,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final EthProtocolManager ethProtocolManager, final EthProtocolManager ethProtocolManager,
final PivotBlockSelector pivotBlockSelector) { final PivotBlockSelector pivotBlockSelector) {
@ -851,6 +858,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
worldStateStorageCoordinator, worldStateStorageCoordinator,
ethProtocolManager.getBlockBroadcaster(), ethProtocolManager.getBlockBroadcaster(),
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
dataDirectory, dataDirectory,
storageProvider, storageProvider,

@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator;
import org.hyperledger.besu.ethereum.eth.sync.DefaultSynchronizer; import org.hyperledger.besu.ethereum.eth.sync.DefaultSynchronizer;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
@ -225,6 +226,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final EthProtocolManager ethProtocolManager, final EthProtocolManager ethProtocolManager,
final PivotBlockSelector pivotBlockSelector) { final PivotBlockSelector pivotBlockSelector) {
@ -235,6 +237,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
worldStateStorageCoordinator, worldStateStorageCoordinator,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
ethProtocolManager, ethProtocolManager,
pivotBlockSelector); pivotBlockSelector);

@ -153,7 +153,15 @@ public final class RunnerTest {
// set merge flag to false, otherwise this test can fail if a merge test runs first // set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfiguration.setMergeEnabled(false); MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FULL, getFastSyncGenesis()); syncFromGenesis(SyncMode.FULL, getFastSyncGenesis(), false);
}
@Test
public void fullSyncFromGenesisUsingPeerTaskSystem() throws Exception {
// set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FULL, getFastSyncGenesis(), true);
} }
@Test @Test
@ -161,10 +169,21 @@ public final class RunnerTest {
// set merge flag to false, otherwise this test can fail if a merge test runs first // set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfiguration.setMergeEnabled(false); MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FAST, getFastSyncGenesis()); syncFromGenesis(SyncMode.FAST, getFastSyncGenesis(), false);
} }
private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesisConfig) @Test
public void fastSyncFromGenesisUsingPeerTaskSystem() throws Exception {
// set merge flag to false, otherwise this test can fail if a merge test runs first
MergeConfiguration.setMergeEnabled(false);
syncFromGenesis(SyncMode.FAST, getFastSyncGenesis(), true);
}
private void syncFromGenesis(
final SyncMode mode,
final GenesisConfigFile genesisConfig,
final boolean isPeerTaskSystemEnabled)
throws Exception { throws Exception {
final Path dataDirAhead = Files.createTempDirectory(temp, "db-ahead"); final Path dataDirAhead = Files.createTempDirectory(temp, "db-ahead");
final Path dbAhead = dataDirAhead.resolve("database"); final Path dbAhead = dataDirAhead.resolve("database");
@ -172,7 +191,10 @@ public final class RunnerTest {
final NodeKey aheadDbNodeKey = NodeKeyUtils.createFrom(KeyPairUtil.loadKeyPair(dataDirAhead)); final NodeKey aheadDbNodeKey = NodeKeyUtils.createFrom(KeyPairUtil.loadKeyPair(dataDirAhead));
final NodeKey behindDbNodeKey = NodeKeyUtils.generate(); final NodeKey behindDbNodeKey = NodeKeyUtils.generate();
final SynchronizerConfiguration syncConfigAhead = final SynchronizerConfiguration syncConfigAhead =
SynchronizerConfiguration.builder().syncMode(SyncMode.FULL).build(); SynchronizerConfiguration.builder()
.syncMode(SyncMode.FULL)
.isPeerTaskSystemEnabled(isPeerTaskSystemEnabled)
.build();
final ObservableMetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); final ObservableMetricsSystem noOpMetricsSystem = new NoOpMetricsSystem();
final var miningParameters = MiningParameters.newDefault(); final var miningParameters = MiningParameters.newDefault();
final var dataStorageConfiguration = DataStorageConfiguration.DEFAULT_FOREST_CONFIG; final var dataStorageConfiguration = DataStorageConfiguration.DEFAULT_FOREST_CONFIG;

@ -104,9 +104,9 @@ public class JsonRpcExecutor {
private Optional<RpcErrorType> validateMethodAvailability(final JsonRpcRequest request) { private Optional<RpcErrorType> validateMethodAvailability(final JsonRpcRequest request) {
final String name = request.getMethod(); final String name = request.getMethod();
if (LOG.isDebugEnabled()) { if (LOG.isTraceEnabled()) {
final JsonArray params = JsonObject.mapFrom(request).getJsonArray("params"); final JsonArray params = JsonObject.mapFrom(request).getJsonArray("params");
LOG.debug("JSON-RPC request -> {} {}", name, params); LOG.trace("JSON-RPC request -> {} {}", name, params);
} }
final JsonRpcMethod method = rpcMethods.get(name); final JsonRpcMethod method = rpcMethods.get(name);

@ -337,7 +337,6 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver {
public void handleNewConnection(final PeerConnection connection) { public void handleNewConnection(final PeerConnection connection) {
ethPeers.registerNewConnection(connection, peerValidators); ethPeers.registerNewConnection(connection, peerValidators);
final EthPeer peer = ethPeers.peer(connection); final EthPeer peer = ethPeers.peer(connection);
final Capability cap = connection.capability(getSupportedProtocol()); final Capability cap = connection.capability(getSupportedProtocol());
final ForkId latestForkId = final ForkId latestForkId =
cap.getVersion() >= 64 ? forkIdManager.getForkIdForChainHead() : null; cap.getVersion() >= 64 ? forkIdManager.getForkIdForChainHead() : null;

@ -145,7 +145,7 @@ public class EthScheduler {
servicesExecutor.execute(command); servicesExecutor.execute(command);
} }
public <T> CompletableFuture<Void> scheduleServiceTask(final Runnable task) { public CompletableFuture<Void> scheduleServiceTask(final Runnable task) {
return CompletableFuture.runAsync(task, servicesExecutor); return CompletableFuture.runAsync(task, servicesExecutor);
} }
@ -156,6 +156,19 @@ public class EthScheduler {
return serviceFuture; return serviceFuture;
} }
public <T> CompletableFuture<T> scheduleServiceTask(final Supplier<CompletableFuture<T>> future) {
final CompletableFuture<T> promise = new CompletableFuture<>();
final Future<?> workerFuture = servicesExecutor.submit(() -> propagateResult(future, promise));
// If returned promise is cancelled, cancel the worker future
promise.whenComplete(
(r, t) -> {
if (t instanceof CancellationException) {
workerFuture.cancel(false);
}
});
return promise;
}
public CompletableFuture<Void> startPipeline(final Pipeline<?> pipeline) { public CompletableFuture<Void> startPipeline(final Pipeline<?> pipeline) {
final CompletableFuture<Void> pipelineFuture = pipeline.start(servicesExecutor); final CompletableFuture<Void> pipelineFuture = pipeline.start(servicesExecutor);
pendingFutures.add(pipelineFuture); pendingFutures.add(pipelineFuture);

@ -41,13 +41,13 @@ public interface PeerTask<T> {
MessageData getRequestMessage(); MessageData getRequestMessage();
/** /**
* Parses the MessageData response from the EthPeer * Parses and processes the MessageData response from the EthPeer
* *
* @param messageData the response MessageData to be parsed * @param messageData the response MessageData to be parsed
* @return a T built from the response MessageData * @return a T built from the response MessageData
* @throws InvalidPeerTaskResponseException if the response messageData is invalid * @throws InvalidPeerTaskResponseException if the response messageData is invalid
*/ */
T parseResponse(MessageData messageData) throws InvalidPeerTaskResponseException; T processResponse(MessageData messageData) throws InvalidPeerTaskResponseException;
/** /**
* Gets the number of times this task may be attempted against other peers * Gets the number of times this task may be attempted against other peers

@ -133,7 +133,7 @@ public class PeerTaskExecutor {
MessageData responseMessageData = MessageData responseMessageData =
requestSender.sendRequest(peerTask.getSubProtocol(), requestMessageData, peer); requestSender.sendRequest(peerTask.getSubProtocol(), requestMessageData, peer);
result = peerTask.parseResponse(responseMessageData); result = peerTask.processResponse(responseMessageData);
} finally { } finally {
inflightRequestCountForThisTaskClass.decrementAndGet(); inflightRequestCountForThisTaskClass.decrementAndGet();
} }

@ -0,0 +1,135 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.manager.peertask.task;
import static java.util.Collections.emptyList;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTask;
import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public class GetReceiptsFromPeerTask
implements PeerTask<Map<BlockHeader, List<TransactionReceipt>>> {
private final Collection<BlockHeader> blockHeaders;
private final ProtocolSchedule protocolSchedule;
private final Map<BlockHeader, List<TransactionReceipt>> receiptsByBlockHeader = new HashMap<>();
private final Map<Hash, List<BlockHeader>> headersByReceiptsRoot = new HashMap<>();
private final long requiredBlockchainHeight;
public GetReceiptsFromPeerTask(
final Collection<BlockHeader> blockHeaders, final ProtocolSchedule protocolSchedule) {
this.blockHeaders = new ArrayList<>(blockHeaders);
this.protocolSchedule = protocolSchedule;
// pre-fill any headers with an empty receipts root into the result map
this.blockHeaders.stream()
.filter(header -> header.getReceiptsRoot().equals(Hash.EMPTY_TRIE_HASH))
.forEach(header -> receiptsByBlockHeader.put(header, emptyList()));
this.blockHeaders.removeAll(receiptsByBlockHeader.keySet());
// group headers by their receipts root hash to reduce total number of receipts hashes requested
// for
this.blockHeaders.forEach(
header ->
headersByReceiptsRoot
.computeIfAbsent(header.getReceiptsRoot(), key -> new ArrayList<>())
.add(header));
// calculate the minimum required blockchain height a peer will need to be able to fulfil this
// request
requiredBlockchainHeight =
this.blockHeaders.stream()
.mapToLong(BlockHeader::getNumber)
.max()
.orElse(BlockHeader.GENESIS_BLOCK_NUMBER);
}
@Override
public SubProtocol getSubProtocol() {
return EthProtocol.get();
}
@Override
public MessageData getRequestMessage() {
// Since we have to match up the data by receipt root, we only need to request receipts
// for one of the headers with each unique receipt root.
final List<Hash> blockHashes =
headersByReceiptsRoot.values().stream()
.map(headers -> headers.getFirst().getHash())
.toList();
return GetReceiptsMessage.create(blockHashes);
}
@Override
public Map<BlockHeader, List<TransactionReceipt>> processResponse(final MessageData messageData)
throws InvalidPeerTaskResponseException {
if (messageData == null) {
throw new InvalidPeerTaskResponseException();
}
final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(messageData);
final List<List<TransactionReceipt>> receiptsByBlock = receiptsMessage.receipts();
// take a copy of the pre-filled receiptsByBlockHeader, to ensure idempotency of subsequent
// calls to processResponse
final Map<BlockHeader, List<TransactionReceipt>> receiptsByHeader =
new HashMap<>(receiptsByBlockHeader);
if (!blockHeaders.isEmpty()) {
if (receiptsByBlock.isEmpty() || receiptsByBlock.size() > blockHeaders.size()) {
throw new InvalidPeerTaskResponseException();
}
for (final List<TransactionReceipt> receiptsInBlock : receiptsByBlock) {
final List<BlockHeader> blockHeaders =
headersByReceiptsRoot.get(BodyValidation.receiptsRoot(receiptsInBlock));
if (blockHeaders == null) {
// Contains receipts that we didn't request, so mustn't be the response we're looking for.
throw new InvalidPeerTaskResponseException();
}
blockHeaders.forEach(header -> receiptsByHeader.put(header, receiptsInBlock));
}
}
return receiptsByHeader;
}
@Override
public Predicate<EthPeer> getPeerRequirementFilter() {
return (ethPeer) ->
ethPeer.getProtocolName().equals(getSubProtocol().getName())
&& (protocolSchedule.anyMatch((ps) -> ps.spec().isPoS())
|| ethPeer.chainState().getEstimatedHeight() >= requiredBlockchainHeight);
}
@Override
public boolean isSuccess(final Map<BlockHeader, List<TransactionReceipt>> result) {
return !result.isEmpty();
}
}

@ -22,6 +22,7 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.checkpointsync.CheckpointDownloaderFactory; import org.hyperledger.besu.ethereum.eth.sync.checkpointsync.CheckpointDownloaderFactory;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloader; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloader;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState;
@ -82,6 +83,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final BlockBroadcaster blockBroadcaster, final BlockBroadcaster blockBroadcaster,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final Path dataDirectory, final Path dataDirectory,
final StorageProvider storageProvider, final StorageProvider storageProvider,
@ -147,6 +149,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -163,6 +166,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -179,6 +183,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,

@ -16,17 +16,23 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.manager.task.GetBlockFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.GetBlockFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.Checkpoint; import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.Checkpoint;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -34,17 +40,23 @@ public class CheckpointDownloadBlockStep {
private final ProtocolSchedule protocolSchedule; private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext; private final EthContext ethContext;
private final PeerTaskExecutor peerTaskExecutor;
private final Checkpoint checkpoint; private final Checkpoint checkpoint;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem; private final MetricsSystem metricsSystem;
public CheckpointDownloadBlockStep( public CheckpointDownloadBlockStep(
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final Checkpoint checkpoint, final Checkpoint checkpoint,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext; this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.checkpoint = checkpoint; this.checkpoint = checkpoint;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem; this.metricsSystem = metricsSystem;
} }
@ -65,8 +77,42 @@ public class CheckpointDownloadBlockStep {
private CompletableFuture<Optional<BlockWithReceipts>> downloadReceipts( private CompletableFuture<Optional<BlockWithReceipts>> downloadReceipts(
final PeerTaskResult<Block> peerTaskResult) { final PeerTaskResult<Block> peerTaskResult) {
final Block block = peerTaskResult.getResult(); final Block block = peerTaskResult.getResult();
final GetReceiptsFromPeerTask getReceiptsFromPeerTask = if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
GetReceiptsFromPeerTask.forHeaders(ethContext, List.of(block.getHeader()), metricsSystem); return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(List.of(block.getHeader()), protocolSchedule);
PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> executorResult =
peerTaskExecutor.execute(task);
if (executorResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS) {
List<TransactionReceipt> transactionReceipts =
executorResult
.result()
.map((map) -> map.get(block.getHeader()))
.orElseThrow(
() ->
new IllegalStateException(
"PeerTask response code was success, but empty"));
if (block.getBody().getTransactions().size() != transactionReceipts.size()) {
throw new IllegalStateException(
"PeerTask response code was success, but incorrect number of receipts returned");
}
BlockWithReceipts blockWithReceipts =
new BlockWithReceipts(block, transactionReceipts);
return CompletableFuture.completedFuture(Optional.of(blockWithReceipts));
} else {
return CompletableFuture.completedFuture(Optional.empty());
}
});
} else {
final org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask
getReceiptsFromPeerTask =
org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask.forHeaders(
ethContext, List.of(block.getHeader()), metricsSystem);
return getReceiptsFromPeerTask return getReceiptsFromPeerTask
.run() .run()
.thenCompose( .thenCompose(
@ -79,3 +125,4 @@ public class CheckpointDownloadBlockStep {
.exceptionally(throwable -> Optional.empty()); .exceptionally(throwable -> Optional.empty());
} }
} }
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -61,6 +62,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory {
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final SyncState syncState, final SyncState syncState,
final Clock clock, final Clock clock,
@ -110,6 +112,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
pivotBlockSelector, pivotBlockSelector,
metricsSystem); metricsSystem);
@ -127,6 +130,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
pivotBlockSelector, pivotBlockSelector,
metricsSystem); metricsSystem);

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -34,6 +35,7 @@ public class CheckpointSyncActions extends FastSyncActions {
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final PivotBlockSelector pivotBlockSelector, final PivotBlockSelector pivotBlockSelector,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
@ -43,6 +45,7 @@ public class CheckpointSyncActions extends FastSyncActions {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
pivotBlockSelector, pivotBlockSelector,
metricsSystem); metricsSystem);
@ -57,6 +60,7 @@ public class CheckpointSyncActions extends FastSyncActions {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
metricsSystem, metricsSystem,
currentState, currentState,

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -36,6 +37,7 @@ public class CheckpointSyncChainDownloader extends FastSyncChainDownloader {
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final FastSyncState fastSyncState, final FastSyncState fastSyncState,
@ -55,7 +57,13 @@ public class CheckpointSyncChainDownloader extends FastSyncChainDownloader {
syncState, syncState,
syncTargetManager, syncTargetManager,
new CheckpointSyncDownloadPipelineFactory( new CheckpointSyncDownloadPipelineFactory(
config, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem), config,
protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
fastSyncState,
metricsSystem),
ethContext.getScheduler(), ethContext.getScheduler(),
metricsSystem, metricsSystem,
syncDurationMetrics); syncDurationMetrics);

@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloadPipelineFactory; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloadPipelineFactory;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState;
@ -40,9 +41,17 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final FastSyncState fastSyncState, final FastSyncState fastSyncState,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
super(syncConfig, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem); super(
syncConfig,
protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
fastSyncState,
metricsSystem);
} }
@Override @Override
@ -76,7 +85,8 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel
checkPointSource, checkpoint, protocolContext.getBlockchain()); checkPointSource, checkpoint, protocolContext.getBlockchain());
final CheckpointDownloadBlockStep checkPointDownloadBlockStep = final CheckpointDownloadBlockStep checkPointDownloadBlockStep =
new CheckpointDownloadBlockStep(protocolSchedule, ethContext, checkpoint, metricsSystem); new CheckpointDownloadBlockStep(
protocolSchedule, ethContext, peerTaskExecutor, checkpoint, syncConfig, metricsSystem);
return PipelineBuilder.createPipelineFrom( return PipelineBuilder.createPipelineFrom(
"fetchCheckpoints", "fetchCheckpoints",

@ -22,10 +22,16 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.tasks.GetReceiptsForHeadersTask; import org.hyperledger.besu.ethereum.eth.sync.tasks.GetReceiptsForHeadersTask;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.util.FutureUtils;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -33,24 +39,69 @@ import java.util.function.Function;
public class DownloadReceiptsStep public class DownloadReceiptsStep
implements Function<List<Block>, CompletableFuture<List<BlockWithReceipts>>> { implements Function<List<Block>, CompletableFuture<List<BlockWithReceipts>>> {
private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext; private final EthContext ethContext;
private final PeerTaskExecutor peerTaskExecutor;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem; private final MetricsSystem metricsSystem;
public DownloadReceiptsStep(final EthContext ethContext, final MetricsSystem metricsSystem) { public DownloadReceiptsStep(
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) {
this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext; this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem; this.metricsSystem = metricsSystem;
} }
@Override @Override
public CompletableFuture<List<BlockWithReceipts>> apply(final List<Block> blocks) { public CompletableFuture<List<BlockWithReceipts>> apply(final List<Block> blocks) {
final List<BlockHeader> headers = blocks.stream().map(Block::getHeader).collect(toList()); final List<BlockHeader> headers = blocks.stream().map(Block::getHeader).collect(toList());
final CompletableFuture<Map<BlockHeader, List<TransactionReceipt>>> getReceipts = if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
GetReceiptsForHeadersTask.forHeaders(ethContext, headers, metricsSystem).run(); return ethContext
final CompletableFuture<List<BlockWithReceipts>> combineWithBlocks = .getScheduler()
getReceipts.thenApply( .scheduleServiceTask(() -> getReceiptsWithPeerTaskSystem(headers))
receiptsByHeader -> combineBlocksAndReceipts(blocks, receiptsByHeader)); .thenApply((receipts) -> combineBlocksAndReceipts(blocks, receipts));
FutureUtils.propagateCancellation(combineWithBlocks, getReceipts);
return combineWithBlocks; } else {
return GetReceiptsForHeadersTask.forHeaders(ethContext, headers, metricsSystem)
.run()
.thenApply((receipts) -> combineBlocksAndReceipts(blocks, receipts));
}
}
private CompletableFuture<Map<BlockHeader, List<TransactionReceipt>>>
getReceiptsWithPeerTaskSystem(final List<BlockHeader> headers) {
Map<BlockHeader, List<TransactionReceipt>> getReceipts = new HashMap<>();
do {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(headers, protocolSchedule);
PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> getReceiptsResult =
peerTaskExecutor.execute(task);
if (getReceiptsResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS
&& getReceiptsResult.result().isPresent()) {
Map<BlockHeader, List<TransactionReceipt>> taskResult = getReceiptsResult.result().get();
taskResult
.keySet()
.forEach(
(blockHeader) ->
getReceipts.merge(
blockHeader,
taskResult.get(blockHeader),
(initialReceipts, newReceipts) -> {
throw new IllegalStateException(
"Unexpectedly got receipts for block header already populated!");
}));
// remove all the headers we found receipts for
headers.removeAll(getReceipts.keySet());
}
// repeat until all headers have receipts
} while (!headers.isEmpty());
return CompletableFuture.completedFuture(getReceipts);
} }
private List<BlockWithReceipts> combineBlocksAndReceipts( private List<BlockWithReceipts> combineBlocksAndReceipts(
@ -60,8 +111,17 @@ public class DownloadReceiptsStep
block -> { block -> {
final List<TransactionReceipt> receipts = final List<TransactionReceipt> receipts =
receiptsByHeader.getOrDefault(block.getHeader(), emptyList()); receiptsByHeader.getOrDefault(block.getHeader(), emptyList());
if (block.getBody().getTransactions().size() != receipts.size()) {
throw new IllegalStateException(
"PeerTask response code was success, but incorrect number of receipts returned. Header hash: "
+ block.getHeader().getHash()
+ ", Transactions: "
+ block.getBody().getTransactions().size()
+ ", receipts: "
+ receipts.size());
}
return new BlockWithReceipts(block, receipts); return new BlockWithReceipts(block, receipts);
}) })
.collect(toList()); .toList();
} }
} }

@ -19,6 +19,7 @@ import static java.util.concurrent.CompletableFuture.completedFuture;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeersTask; import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeersTask;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
@ -48,6 +49,7 @@ public class FastSyncActions {
protected final ProtocolSchedule protocolSchedule; protected final ProtocolSchedule protocolSchedule;
protected final ProtocolContext protocolContext; protected final ProtocolContext protocolContext;
protected final EthContext ethContext; protected final EthContext ethContext;
protected final PeerTaskExecutor peerTaskExecutor;
protected final SyncState syncState; protected final SyncState syncState;
protected final PivotBlockSelector pivotBlockSelector; protected final PivotBlockSelector pivotBlockSelector;
protected final MetricsSystem metricsSystem; protected final MetricsSystem metricsSystem;
@ -60,6 +62,7 @@ public class FastSyncActions {
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final PivotBlockSelector pivotBlockSelector, final PivotBlockSelector pivotBlockSelector,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
@ -68,6 +71,7 @@ public class FastSyncActions {
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext; this.protocolContext = protocolContext;
this.ethContext = ethContext; this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.syncState = syncState; this.syncState = syncState;
this.pivotBlockSelector = pivotBlockSelector; this.pivotBlockSelector = pivotBlockSelector;
this.metricsSystem = metricsSystem; this.metricsSystem = metricsSystem;
@ -164,6 +168,7 @@ public class FastSyncActions {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
metricsSystem, metricsSystem,
currentState, currentState,

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -35,6 +36,7 @@ public class FastSyncChainDownloader {
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState, final SyncState syncState,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final FastSyncState fastSyncState, final FastSyncState fastSyncState,
@ -53,7 +55,13 @@ public class FastSyncChainDownloader {
syncState, syncState,
syncTargetManager, syncTargetManager,
new FastSyncDownloadPipelineFactory( new FastSyncDownloadPipelineFactory(
config, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem), config,
protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
fastSyncState,
metricsSystem),
ethContext.getScheduler(), ethContext.getScheduler(),
metricsSystem, metricsSystem,
syncDurationMetrics); syncDurationMetrics);

@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.DownloadBodiesStep; import org.hyperledger.besu.ethereum.eth.sync.DownloadBodiesStep;
import org.hyperledger.besu.ethereum.eth.sync.DownloadHeadersStep; import org.hyperledger.besu.ethereum.eth.sync.DownloadHeadersStep;
import org.hyperledger.besu.ethereum.eth.sync.DownloadPipelineFactory; import org.hyperledger.besu.ethereum.eth.sync.DownloadPipelineFactory;
@ -58,6 +59,7 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
protected final ProtocolSchedule protocolSchedule; protected final ProtocolSchedule protocolSchedule;
protected final ProtocolContext protocolContext; protected final ProtocolContext protocolContext;
protected final EthContext ethContext; protected final EthContext ethContext;
protected final PeerTaskExecutor peerTaskExecutor;
protected final FastSyncState fastSyncState; protected final FastSyncState fastSyncState;
protected final MetricsSystem metricsSystem; protected final MetricsSystem metricsSystem;
protected final FastSyncValidationPolicy attachedValidationPolicy; protected final FastSyncValidationPolicy attachedValidationPolicy;
@ -69,12 +71,14 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
final ProtocolSchedule protocolSchedule, final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final FastSyncState fastSyncState, final FastSyncState fastSyncState,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
this.syncConfig = syncConfig; this.syncConfig = syncConfig;
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext; this.protocolContext = protocolContext;
this.ethContext = ethContext; this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.fastSyncState = fastSyncState; this.fastSyncState = fastSyncState;
this.metricsSystem = metricsSystem; this.metricsSystem = metricsSystem;
final LabelledMetric<Counter> fastSyncValidationCounter = final LabelledMetric<Counter> fastSyncValidationCounter =
@ -145,7 +149,8 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
final DownloadBodiesStep downloadBodiesStep = final DownloadBodiesStep downloadBodiesStep =
new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem); new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem);
final DownloadReceiptsStep downloadReceiptsStep = final DownloadReceiptsStep downloadReceiptsStep =
new DownloadReceiptsStep(ethContext, metricsSystem); new DownloadReceiptsStep(
protocolSchedule, ethContext, peerTaskExecutor, syncConfig, metricsSystem);
final ImportBlocksStep importBlockStep = final ImportBlocksStep importBlockStep =
new ImportBlocksStep( new ImportBlocksStep(
protocolSchedule, protocolSchedule,

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -59,6 +60,7 @@ public class FastDownloaderFactory {
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final SyncState syncState, final SyncState syncState,
final Clock clock, final Clock clock,
@ -126,6 +128,7 @@ public class FastDownloaderFactory {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
pivotBlockSelector, pivotBlockSelector,
metricsSystem), metricsSystem),

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -57,6 +58,7 @@ public class SnapDownloaderFactory extends FastDownloaderFactory {
final ProtocolContext protocolContext, final ProtocolContext protocolContext,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final EthContext ethContext, final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final SyncState syncState, final SyncState syncState,
final Clock clock, final Clock clock,
@ -121,6 +123,7 @@ public class SnapDownloaderFactory extends FastDownloaderFactory {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
pivotBlockSelector, pivotBlockSelector,
metricsSystem), metricsSystem),

@ -72,7 +72,7 @@ public class PeerTaskExecutorTest {
Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(subprotocol.getName()).thenReturn("subprotocol");
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@ -101,7 +101,7 @@ public class PeerTaskExecutorTest {
Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(subprotocol.getName()).thenReturn("subprotocol");
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(false); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(false);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@ -130,7 +130,7 @@ public class PeerTaskExecutorTest {
.thenThrow(new TimeoutException()) .thenThrow(new TimeoutException())
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode); Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode);
Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@ -204,7 +204,7 @@ public class PeerTaskExecutorTest {
Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(subprotocol.getName()).thenReturn("subprotocol");
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(peerTask.parseResponse(responseMessageData)) Mockito.when(peerTask.processResponse(responseMessageData))
.thenThrow(new InvalidPeerTaskResponseException()); .thenThrow(new InvalidPeerTaskResponseException());
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@ -236,7 +236,7 @@ public class PeerTaskExecutorTest {
Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(subprotocol.getName()).thenReturn("subprotocol");
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@ -274,7 +274,7 @@ public class PeerTaskExecutorTest {
Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode); Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode);
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, peer2)) Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, peer2))
.thenReturn(responseMessageData); .thenReturn(responseMessageData);
Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.execute(peerTask); PeerTaskExecutorResult<Object> result = peerTaskExecutor.execute(peerTask);

@ -0,0 +1,264 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.manager.peertask.task;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.EthProtocol;
import org.hyperledger.besu.ethereum.eth.manager.ChainState;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException;
import org.hyperledger.besu.ethereum.eth.messages.EthPV63;
import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class GetReceiptsFromPeerTaskTest {
@Test
public void testGetSubProtocol() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Assertions.assertEquals(EthProtocol.get(), task.getSubProtocol());
}
@Test
public void testGetRequestMessage() {
BlockHeader blockHeader1 = mockBlockHeader(1);
TransactionReceipt receiptForBlock1 =
new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader1.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1)));
BlockHeader blockHeader2 = mockBlockHeader(2);
TransactionReceipt receiptForBlock2 =
new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader2.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2)));
BlockHeader blockHeader3 = mockBlockHeader(3);
TransactionReceipt receiptForBlock3 =
new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader3.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3)));
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(List.of(blockHeader1, blockHeader2, blockHeader3), null);
MessageData messageData = task.getRequestMessage();
GetReceiptsMessage getReceiptsMessage = GetReceiptsMessage.readFrom(messageData);
Assertions.assertEquals(EthPV63.GET_RECEIPTS, getReceiptsMessage.getCode());
Iterable<Hash> hashesInMessage = getReceiptsMessage.hashes();
List<Hash> expectedHashes =
List.of(
Hash.fromHexString(StringUtils.repeat("00", 31) + "11"),
Hash.fromHexString(StringUtils.repeat("00", 31) + "21"),
Hash.fromHexString(StringUtils.repeat("00", 31) + "31"));
List<Hash> actualHashes = new ArrayList<>();
hashesInMessage.forEach(actualHashes::add);
Assertions.assertEquals(3, actualHashes.size());
Assertions.assertEquals(
expectedHashes.stream().sorted().toList(), actualHashes.stream().sorted().toList());
}
@Test
public void testParseResponseWithNullResponseMessage() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Assertions.assertThrows(
InvalidPeerTaskResponseException.class, () -> task.processResponse(null));
}
@Test
public void testParseResponseForInvalidResponse() {
BlockHeader blockHeader1 = mockBlockHeader(1);
TransactionReceipt receiptForBlock1 =
new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader1.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1)));
BlockHeader blockHeader2 = mockBlockHeader(2);
TransactionReceipt receiptForBlock2 =
new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader2.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2)));
BlockHeader blockHeader3 = mockBlockHeader(3);
TransactionReceipt receiptForBlock3 =
new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader3.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3)));
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(List.of(blockHeader1, blockHeader2, blockHeader3), null);
ReceiptsMessage receiptsMessage =
ReceiptsMessage.create(
List.of(
List.of(receiptForBlock1),
List.of(receiptForBlock2),
List.of(receiptForBlock3),
List.of(
new TransactionReceipt(1, 101112, Collections.emptyList(), Optional.empty()))));
Assertions.assertThrows(
InvalidPeerTaskResponseException.class, () -> task.processResponse(receiptsMessage));
}
@Test
public void testParseResponse() throws InvalidPeerTaskResponseException {
BlockHeader blockHeader1 = mockBlockHeader(1);
TransactionReceipt receiptForBlock1 =
new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader1.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1)));
BlockHeader blockHeader2 = mockBlockHeader(2);
TransactionReceipt receiptForBlock2 =
new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader2.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2)));
BlockHeader blockHeader3 = mockBlockHeader(3);
TransactionReceipt receiptForBlock3 =
new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader3.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3)));
BlockHeader blockHeader4 = mockBlockHeader(4);
Mockito.when(blockHeader4.getReceiptsRoot()).thenReturn(Hash.EMPTY_TRIE_HASH);
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(
List.of(blockHeader1, blockHeader2, blockHeader3, blockHeader4), null);
ReceiptsMessage receiptsMessage =
ReceiptsMessage.create(
List.of(
List.of(receiptForBlock1), List.of(receiptForBlock2), List.of(receiptForBlock3)));
Map<BlockHeader, List<TransactionReceipt>> resultMap = task.processResponse(receiptsMessage);
Assertions.assertEquals(4, resultMap.size());
Assertions.assertEquals(Collections.emptyList(), resultMap.get(blockHeader4));
Assertions.assertEquals(List.of(receiptForBlock1), resultMap.get(blockHeader1));
Assertions.assertEquals(List.of(receiptForBlock2), resultMap.get(blockHeader2));
Assertions.assertEquals(List.of(receiptForBlock3), resultMap.get(blockHeader3));
}
@Test
public void testParseResponseForOnlyPrefilledEmptyTrieReceiptsRoots()
throws InvalidPeerTaskResponseException {
BlockHeader blockHeader1 = mockBlockHeader(1);
Mockito.when(blockHeader1.getReceiptsRoot()).thenReturn(Hash.EMPTY_TRIE_HASH);
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(List.of(blockHeader1), null);
ReceiptsMessage receiptsMessage = ReceiptsMessage.create(Collections.emptyList());
Map<BlockHeader, List<TransactionReceipt>> resultMap = task.processResponse(receiptsMessage);
Assertions.assertEquals(1, resultMap.size());
Assertions.assertEquals(Collections.emptyList(), resultMap.get(blockHeader1));
}
@Test
public void testGetPeerRequirementFilter() {
BlockHeader blockHeader1 = mockBlockHeader(1);
TransactionReceipt receiptForBlock1 =
new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader1.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1)));
BlockHeader blockHeader2 = mockBlockHeader(2);
TransactionReceipt receiptForBlock2 =
new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader2.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2)));
BlockHeader blockHeader3 = mockBlockHeader(3);
TransactionReceipt receiptForBlock3 =
new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty());
Mockito.when(blockHeader3.getReceiptsRoot())
.thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3)));
ProtocolSchedule protocolSchedule = Mockito.mock(ProtocolSchedule.class);
Mockito.when(protocolSchedule.anyMatch(Mockito.any())).thenReturn(false);
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(
List.of(blockHeader1, blockHeader2, blockHeader3), protocolSchedule);
EthPeer failForIncorrectProtocol = mockPeer("incorrectProtocol", 5);
EthPeer failForShortChainHeight = mockPeer("incorrectProtocol", 1);
EthPeer successfulCandidate = mockPeer(EthProtocol.NAME, 5);
Assertions.assertFalse(task.getPeerRequirementFilter().test(failForIncorrectProtocol));
Assertions.assertFalse(task.getPeerRequirementFilter().test(failForShortChainHeight));
Assertions.assertTrue(task.getPeerRequirementFilter().test(successfulCandidate));
}
@Test
public void testIsSuccessForPartialSuccess() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Assertions.assertFalse(task.isSuccess(Collections.emptyMap()));
}
@Test
public void testIsSuccessForFullSuccess() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Map<BlockHeader, List<TransactionReceipt>> map = new HashMap<>();
map.put(mockBlockHeader(1), null);
Assertions.assertTrue(task.isSuccess(map));
}
private BlockHeader mockBlockHeader(final long blockNumber) {
BlockHeader blockHeader = Mockito.mock(BlockHeader.class);
Mockito.when(blockHeader.getNumber()).thenReturn(blockNumber);
// second to last hex digit indicates the blockNumber, last hex digit indicates the usage of the
// hash
Mockito.when(blockHeader.getHash())
.thenReturn(Hash.fromHexString(StringUtils.repeat("00", 31) + blockNumber + "1"));
return blockHeader;
}
private EthPeer mockPeer(final String protocol, final long chainHeight) {
EthPeer ethPeer = Mockito.mock(EthPeer.class);
ChainState chainState = Mockito.mock(ChainState.class);
Mockito.when(ethPeer.getProtocolName()).thenReturn(protocol);
Mockito.when(ethPeer.chainState()).thenReturn(chainState);
Mockito.when(chainState.getEstimatedHeight()).thenReturn(chainHeight);
return ethPeer;
}
}

@ -22,13 +22,19 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState;
@ -44,8 +50,15 @@ import org.hyperledger.besu.metrics.SyncDurationMetrics;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
@ -55,12 +68,16 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.ArgumentsSource;
import org.junit.platform.commons.util.ReflectionUtils;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class CheckPointSyncChainDownloaderTest { public class CheckPointSyncChainDownloaderTest {
protected ProtocolSchedule protocolSchedule; protected ProtocolSchedule protocolSchedule;
protected EthProtocolManager ethProtocolManager; protected EthProtocolManager ethProtocolManager;
protected EthContext ethContext; protected EthContext ethContext;
private PeerTaskExecutor peerTaskExecutor;
protected ProtocolContext protocolContext; protected ProtocolContext protocolContext;
private SyncState syncState; private SyncState syncState;
@ -100,6 +117,7 @@ public class CheckPointSyncChainDownloaderTest {
localBlockchain = localBlockchainSetup.getBlockchain(); localBlockchain = localBlockchainSetup.getBlockchain();
otherBlockchainSetup = BlockchainSetupUtil.forTesting(dataStorageFormat); otherBlockchainSetup = BlockchainSetupUtil.forTesting(dataStorageFormat);
otherBlockchain = otherBlockchainSetup.getBlockchain(); otherBlockchain = otherBlockchainSetup.getBlockchain();
otherBlockchainSetup.importFirstBlocks(30);
protocolSchedule = localBlockchainSetup.getProtocolSchedule(); protocolSchedule = localBlockchainSetup.getProtocolSchedule();
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = ethProtocolManager =
@ -123,6 +141,41 @@ public class CheckPointSyncChainDownloaderTest {
ethContext.getEthPeers(), ethContext.getEthPeers(),
true, true,
Optional.of(checkpoint)); Optional.of(checkpoint));
peerTaskExecutor = mock(PeerTaskExecutor.class);
when(peerTaskExecutor.execute(any(GetReceiptsFromPeerTask.class)))
.thenAnswer(
new Answer<PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>>>() {
@Override
public PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> answer(
final InvocationOnMock invocationOnMock) throws Throwable {
GetReceiptsFromPeerTask task =
invocationOnMock.getArgument(0, GetReceiptsFromPeerTask.class);
return processTask(task);
}
});
}
@SuppressWarnings("unchecked")
private PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> processTask(
final GetReceiptsFromPeerTask task) throws IllegalAccessException {
Map<BlockHeader, List<TransactionReceipt>> getReceiptsFromPeerTaskResult = new HashMap<>();
List<Field> fields =
ReflectionUtils.findFields(
task.getClass(),
(field) -> field.getName().equals("blockHeaders"),
ReflectionUtils.HierarchyTraversalMode.TOP_DOWN);
fields.forEach((f) -> f.setAccessible(true));
Collection<BlockHeader> blockHeaders = (Collection<BlockHeader>) fields.getFirst().get(task);
blockHeaders.forEach(
(bh) ->
getReceiptsFromPeerTaskResult.put(
bh, otherBlockchain.getTxReceipts(bh.getHash()).get()));
return new PeerTaskExecutorResult<>(
Optional.of(getReceiptsFromPeerTaskResult), PeerTaskExecutorResponseCode.SUCCESS);
} }
@AfterEach @AfterEach
@ -140,6 +193,7 @@ public class CheckPointSyncChainDownloaderTest {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
peerTaskExecutor,
syncState, syncState,
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()), new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()),
@ -148,9 +202,9 @@ public class CheckPointSyncChainDownloaderTest {
@ParameterizedTest @ParameterizedTest
@ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class)
public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat) { public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat)
throws IllegalAccessException {
setup(storageFormat); setup(storageFormat);
otherBlockchainSetup.importFirstBlocks(30);
final RespondingEthPeer peer = final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain);
@ -161,6 +215,7 @@ public class CheckPointSyncChainDownloaderTest {
SynchronizerConfiguration.builder() SynchronizerConfiguration.builder()
.downloaderChainSegmentSize(5) .downloaderChainSegmentSize(5)
.downloaderHeadersRequestSize(3) .downloaderHeadersRequestSize(3)
.isPeerTaskSystemEnabled(false)
.build(); .build();
final long pivotBlockNumber = 25; final long pivotBlockNumber = 25;
ethContext ethContext
@ -184,9 +239,9 @@ public class CheckPointSyncChainDownloaderTest {
@ParameterizedTest @ParameterizedTest
@ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class)
public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat) { public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat)
throws IllegalAccessException {
setup(storageFormat); setup(storageFormat);
otherBlockchainSetup.importFirstBlocks(30);
final RespondingEthPeer peer = final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain);
@ -194,7 +249,79 @@ public class CheckPointSyncChainDownloaderTest {
RespondingEthPeer.blockchainResponder(otherBlockchain); RespondingEthPeer.blockchainResponder(otherBlockchain);
final long pivotBlockNumber = 10; final long pivotBlockNumber = 10;
final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder().build(); final SynchronizerConfiguration syncConfig =
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build();
ethContext
.getEthPeers()
.streamAvailablePeers()
.forEach(
ethPeer -> {
ethPeer.setCheckpointHeader(
otherBlockchainSetup.getBlocks().get((int) checkpoint.blockNumber()).getHeader());
});
final ChainDownloader downloader = downloader(syncConfig, pivotBlockNumber);
final CompletableFuture<Void> result = downloader.start();
peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone());
assertThat(result).isCompleted();
assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(pivotBlockNumber);
assertThat(localBlockchain.getChainHeadHeader())
.isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get());
}
@ParameterizedTest
@ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class)
public void shouldSyncToPivotBlockInMultipleSegmentsWithPeerTaskSystem(
final DataStorageFormat storageFormat)
throws IllegalAccessException, ExecutionException, InterruptedException, TimeoutException {
setup(storageFormat);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain);
final RespondingEthPeer.Responder responder =
RespondingEthPeer.blockchainResponder(otherBlockchain);
final SynchronizerConfiguration syncConfig =
SynchronizerConfiguration.builder()
.downloaderChainSegmentSize(5)
.downloaderHeadersRequestSize(3)
.isPeerTaskSystemEnabled(true)
.build();
final long pivotBlockNumber = 25;
ethContext
.getEthPeers()
.streamAvailablePeers()
.forEach(
ethPeer -> {
ethPeer.setCheckpointHeader(
otherBlockchainSetup.getBlocks().get((int) checkpoint.blockNumber()).getHeader());
});
final ChainDownloader downloader = downloader(syncConfig, pivotBlockNumber);
final CompletableFuture<Void> result = downloader.start();
peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone());
assertThat(result).isCompleted();
assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(pivotBlockNumber);
assertThat(localBlockchain.getChainHeadHeader())
.isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get());
}
@ParameterizedTest
@ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class)
public void shouldSyncToPivotBlockInSingleSegmentWithPeerTaskSystem(
final DataStorageFormat storageFormat) throws IllegalAccessException {
setup(storageFormat);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain);
final RespondingEthPeer.Responder responder =
RespondingEthPeer.blockchainResponder(otherBlockchain);
final long pivotBlockNumber = 10;
final SynchronizerConfiguration syncConfig =
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(true).build();
ethContext ethContext
.getEthPeers() .getEthPeers()
.streamAvailablePeers() .streamAvailablePeers()

@ -18,47 +18,64 @@ import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class DownloadReceiptsStepTest { public class DownloadReceiptsStepTest {
private static ProtocolContext protocolContext; private static ProtocolContext protocolContext;
private static ProtocolSchedule protocolSchedule;
private static MutableBlockchain blockchain; private static MutableBlockchain blockchain;
private PeerTaskExecutor peerTaskExecutor;
private EthProtocolManager ethProtocolManager; private EthProtocolManager ethProtocolManager;
private DownloadReceiptsStep downloadReceiptsStep;
@BeforeAll @BeforeAll
public static void setUpClass() { public static void setUpClass() {
final BlockchainSetupUtil setupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST); final BlockchainSetupUtil setupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST);
setupUtil.importFirstBlocks(20); setupUtil.importFirstBlocks(20);
protocolContext = setupUtil.getProtocolContext(); protocolContext = setupUtil.getProtocolContext();
protocolSchedule = setupUtil.getProtocolSchedule();
blockchain = setupUtil.getBlockchain(); blockchain = setupUtil.getBlockchain();
} }
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
peerTaskExecutor = mock(PeerTaskExecutor.class);
TransactionPool transactionPool = mock(TransactionPool.class); TransactionPool transactionPool = mock(TransactionPool.class);
ethProtocolManager = ethProtocolManager =
EthProtocolManagerTestUtil.create( EthProtocolManagerTestUtil.create(
@ -68,12 +85,17 @@ public class DownloadReceiptsStepTest {
protocolContext.getWorldStateArchive(), protocolContext.getWorldStateArchive(),
transactionPool, transactionPool,
EthProtocolConfiguration.defaultConfig()); EthProtocolConfiguration.defaultConfig());
downloadReceiptsStep =
new DownloadReceiptsStep(ethProtocolManager.ethContext(), new NoOpMetricsSystem());
} }
@Test @Test
public void shouldDownloadReceiptsForBlocks() { public void shouldDownloadReceiptsForBlocks() {
DownloadReceiptsStep downloadReceiptsStep =
new DownloadReceiptsStep(
protocolSchedule,
ethProtocolManager.ethContext(),
peerTaskExecutor,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(),
new NoOpMetricsSystem());
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000);
final List<Block> blocks = asList(block(1), block(2), block(3), block(4)); final List<Block> blocks = asList(block(1), block(2), block(3), block(4));
@ -90,6 +112,39 @@ public class DownloadReceiptsStepTest {
blockWithReceipts(4))); blockWithReceipts(4)));
} }
@Test
public void shouldDownloadReceiptsForBlocksUsingPeerTaskSystem()
throws ExecutionException, InterruptedException {
DownloadReceiptsStep downloadReceiptsStep =
new DownloadReceiptsStep(
protocolSchedule,
ethProtocolManager.ethContext(),
peerTaskExecutor,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(true).build(),
new NoOpMetricsSystem());
final List<Block> blocks = asList(mockBlock(), mockBlock(), mockBlock(), mockBlock());
Map<BlockHeader, List<TransactionReceipt>> receiptsMap = new HashMap<>();
blocks.forEach(
(b) -> receiptsMap.put(b.getHeader(), List.of(Mockito.mock(TransactionReceipt.class))));
PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> peerTaskResult =
new PeerTaskExecutorResult<>(
Optional.of(receiptsMap), PeerTaskExecutorResponseCode.SUCCESS);
Mockito.when(peerTaskExecutor.execute(Mockito.any(GetReceiptsFromPeerTask.class)))
.thenReturn(peerTaskResult);
final CompletableFuture<List<BlockWithReceipts>> result = downloadReceiptsStep.apply(blocks);
assertThat(result.get().get(0).getBlock()).isEqualTo(blocks.get(0));
assertThat(result.get().get(0).getReceipts().size()).isEqualTo(1);
assertThat(result.get().get(1).getBlock()).isEqualTo(blocks.get(1));
assertThat(result.get().get(1).getReceipts().size()).isEqualTo(1);
assertThat(result.get().get(2).getBlock()).isEqualTo(blocks.get(2));
assertThat(result.get().get(2).getReceipts().size()).isEqualTo(1);
assertThat(result.get().get(3).getBlock()).isEqualTo(blocks.get(3));
assertThat(result.get().get(3).getReceipts().size()).isEqualTo(1);
}
private Block block(final long number) { private Block block(final long number) {
final BlockHeader header = blockchain.getBlockHeader(number).get(); final BlockHeader header = blockchain.getBlockHeader(number).get();
return new Block(header, blockchain.getBlockBody(header.getHash()).get()); return new Block(header, blockchain.getBlockBody(header.getHash()).get());
@ -100,4 +155,16 @@ public class DownloadReceiptsStepTest {
final List<TransactionReceipt> receipts = blockchain.getTxReceipts(block.getHash()).get(); final List<TransactionReceipt> receipts = blockchain.getTxReceipts(block.getHash()).get();
return new BlockWithReceipts(block, receipts); return new BlockWithReceipts(block, receipts);
} }
private Block mockBlock() {
final Block block = Mockito.mock(Block.class);
final BlockHeader blockHeader = Mockito.mock(BlockHeader.class);
Mockito.when(block.getHeader()).thenAnswer((invocationOnMock) -> blockHeader);
Mockito.when(blockHeader.getReceiptsRoot()).thenReturn(Hash.fromHexStringLenient("DEADBEEF"));
final BlockBody blockBody = Mockito.mock(BlockBody.class);
Mockito.when(block.getBody()).thenAnswer((invocationOnMock) -> blockBody);
Mockito.when(blockBody.getTransactions())
.thenAnswer((invocationOnMock) -> List.of(Mockito.mock(Transaction.class)));
return block;
}
} }

@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@ -71,6 +72,7 @@ public class FastDownloaderFactoryTest {
@Mock private ProtocolContext protocolContext; @Mock private ProtocolContext protocolContext;
@Mock private MetricsSystem metricsSystem; @Mock private MetricsSystem metricsSystem;
@Mock private EthContext ethContext; @Mock private EthContext ethContext;
@Mock private PeerTaskExecutor peerTaskExecutor;
@Mock private SyncState syncState; @Mock private SyncState syncState;
@Mock private Clock clock; @Mock private Clock clock;
@Mock private Path dataDirectory; @Mock private Path dataDirectory;
@ -114,6 +116,7 @@ public class FastDownloaderFactoryTest {
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -139,6 +142,7 @@ public class FastDownloaderFactoryTest {
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -167,6 +171,7 @@ public class FastDownloaderFactoryTest {
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -202,6 +207,7 @@ public class FastDownloaderFactoryTest {
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,
@ -239,6 +245,7 @@ public class FastDownloaderFactoryTest {
protocolContext, protocolContext,
metricsSystem, metricsSystem,
ethContext, ethContext,
peerTaskExecutor,
worldStateStorageCoordinator, worldStateStorageCoordinator,
syncState, syncState,
clock, clock,

@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
@ -536,6 +537,7 @@ public class FastSyncActionsTest {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
new PeerTaskExecutor(null, null, new NoOpMetricsSystem()),
new SyncState(blockchain, ethContext.getEthPeers(), true, Optional.empty()), new SyncState(blockchain, ethContext.getEthPeers(), true, Optional.empty()),
pivotBlockSelector, pivotBlockSelector,
new NoOpMetricsSystem()); new NoOpMetricsSystem());

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.EthPV62;
import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage; import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
@ -110,6 +111,7 @@ public class FastSyncChainDownloaderTest {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethContext, ethContext,
new PeerTaskExecutor(null, null, new NoOpMetricsSystem()),
syncState, syncState,
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()), new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()),

Loading…
Cancel
Save