Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7311 add get headers from peer task #7781

Open
wants to merge 227 commits into
base: main
Choose a base branch
from

Conversation

Matilda-Clerke
Copy link
Contributor

PR description

Add the GetHeadersFromPeerTask PeerTask and implement usages

Matilda-Clerke and others added 30 commits September 17, 2024 13:22
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…e available

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…tantiation

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…en initializing PeerTaskFeatureToggle multiple times

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…peertask-system' into 7311-add-cli-feature-toggle-for-peertask-system
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…PoS, remove new usages of currentProtocolSpecSupplier

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…add-GetHeadersFromPeerTask

# Conflicts:
#	ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java
#	ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java
#	ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda-Clerke <matilda.clerke@consensys.net>
…aderTest

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda-Clerke <matilda.clerke@consensys.net>
…ass for reuse in tests

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
…and improve logging

Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
@Matilda-Clerke Matilda-Clerke marked this pull request as ready for review November 7, 2024 05:11
@@ -84,6 +85,7 @@ protected MiningCoordinator createMiningCoordinator(
final ProtocolContext protocolContext,
final TransactionPool transactionPool,
final MiningConfiguration miningConfiguration,
final PeerTaskExecutor peerTaskExecutor,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we need are adding unused dependencies on peerTaskExecutor via the createMiningCoordinator method inherited from the BesuControllerBuilderInterface. Is there a way around that? Perhaps overloading the method and providing a default implementation to be used by subclasses that don't care about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I can't really find a way around it. Overloading won't help because it's called from within BesuControllerBuilder, which can't make the distinction between which subclasses need the PeerTaskExecutor and which don't

Signed-off-by: Matilda-Clerke <matilda.clerke@consensys.net>
Copy link
Contributor

@jflo jflo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying. This looks well covered with tests and protected with feature flags.

Copy link
Contributor

@jframe jframe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just blocking merging until a few more people familiar with syncing have had a chance to look at this PR

.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be using a retry of peerCount like the task is using

@@ -98,7 +101,7 @@ public <T> PeerTaskExecutorResult<T> execute(final PeerTask<T> peerTask) {
if (peer.isEmpty()) {
executorResult =
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE);
Optional.empty(), PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this null going to cause an issue somewhere? Perhaps the peer should be Optional?

protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the PeerTaskExecutor to the EthContext could be a nice home for this and save a lot of changes to wire through the PeerTaskExecutor through all the tasks.

() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
Hash.wrap(peer.chainState().getBestBlock().getHash()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be good to update this to use the block hash constructor as it's not clear whether the block number or block hash is being used

Comment on lines +123 to +130
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
LOG.info("Unable to download headers for range {}", range);
return CompletableFuture.failedFuture(
new RuntimeException("Unable to download headers for range " + range));
}
LOG.info("Successfully downloaded headers");
return CompletableFuture.completedFuture(taskResult.result().get());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a common usage pattern that could go in the PeerTaskExecutor to simplify usage

batchSize,
0,
Direction.REVERSE,
Integer.MAX_VALUE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of retries seems a bit high, using peerCount same as what is being done in the old code seems more sensible

do {
if (isCancelled.get()) {
return CompletableFuture.failedFuture(
new InterruptedException("Pivot block confirmation has been cancelled"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A CancellationException would make more sense.

});
}

private boolean waitForPeer() throws InterruptedException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What thread does this block? I think the confirmPivotBlock is called before the sync pipeline, so this might not be on an executor thread.

.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the same retries as the original task from MAX_QUERY_RETRIES_PER_PEER

if (messageData == null) {
throw new InvalidPeerTaskResponseException("Response MessageData is null");
}
return BlockHeadersMessage.readFrom(messageData).getHeaders(protocolSchedule);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should validate that the headers form a chain like the AbstractGetHeadersFromPeerTask task does

Copy link
Contributor

@pinges pinges left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the first 33 files. Will continue soon!

public Predicate<EthPeer> getPeerRequirementFilter() {
return (ethPeer) ->
ethPeer.getProtocolName().equals(getSubProtocol().getName())
&& (protocolSchedule.anyMatch((ps) -> ps.spec().isPoS())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably figure that out up front so we do not have to do that for each of the peers that we use, or use Suppliers.memoize?

@@ -132,4 +132,8 @@ public Predicate<EthPeer> getPeerRequirementFilter() {
public boolean isSuccess(final Map<BlockHeader, List<TransactionReceipt>> result) {
return !result.isEmpty();
}

public Collection<BlockHeader> getBlockHeaders() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used in a test. Can this be solved differently in the test, so we can remove that here?

private Boolean validateBlockHeaders(final EthPeer ethPeer, final List<BlockHeader> headers) {
boolean isValid;
if (headers.isEmpty()) {
if (blockIsRequired()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blockIsRequired always returns true and it is only used here. We should remove this!

PeerTaskExecutorResult<List<BlockHeader>> taskResult =
peerTaskExecutor.executeAgainstPeer(task, peer);
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS
&& taskResult.result().isPresent()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to only check one of these? Is it possible to have SUCCESS, but and empty result?

GetHeadersFromPeerTask.Direction.FORWARD,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
peerTaskExecutor.executeAgainstPeer(task, range.getSyncTarget());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not execute against the sync target! I can see that the original implementation does that, but it is wrong!!!

.getScheduler()
.scheduleServiceTask(
() -> {
LOG.info("Getting headers using peer task system");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change at least to debug!

return CompletableFuture.failedFuture(
new RuntimeException("Unable to download headers for range " + range));
}
LOG.info("Successfully downloaded headers");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change at least to debug

PeerTaskExecutorResult<List<BlockHeader>> taskResult =
peerTaskExecutor.executeAgainstPeer(task, range.getSyncTarget());
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have SUCCESS with an empty result?

taskResult.responseCode());
return CompletableFuture.failedFuture(new NoAvailablePeersException());
} else if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have SUCCESS with an empty result?

peerTaskExecutor.execute(task);
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE
|| taskResult.responseCode()
== PeerTaskExecutorResponseCode.PEER_DISCONNECTED) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try another peer if the one we tried got disconnected ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants