Merge branch 'main' into zkbesu

# Conflicts:
#	build.gradle
#	gradle/verification-metadata.xml
This commit is contained in:
Fabio Di Fabio
2024-12-13 12:23:25 +01:00
119 changed files with 3422 additions and 893 deletions

View File

@@ -7,7 +7,7 @@ assignees: ''
---
- [ ] Confirm anything outstanding for release with other maintainers on #besu-release in Discord
- [ ] Confirm at least 24 hours prior anything outstanding for release with other maintainers on #besu-release in Discord
- [ ] Update changelog if necessary, and merge a PR for it to main
- [ ] Notify maintainers about updating changelog for in-flight PRs
- [ ] Optional: for hotfixes, create a release branch and cherry-pick, e.g. `release-<version>-hotfix`

View File

@@ -3,6 +3,7 @@
## Unreleased
### Breaking Changes
- `--host-whitelist` has been deprecated since 2020 and its related option will be removed in a future release.
### Upcoming Breaking Changes
- Plugin API will be deprecating the BesuContext interface to be replaced with the ServiceManager interface.
@@ -15,11 +16,12 @@
- Proof of Work consensus
- Fast Sync
### Additions and Improvements
- Proper support for `pending` block tag when calling `eth_estimateGas` and `eth_createAccessList` [#7951](https://github.com/hyperledger/besu/pull/7951)
- Retrieve all transaction receipts for a block in one request [#6646](https://github.com/hyperledger/besu/pull/6646)
### Bug fixes
- Correct default parameters for frontier transactions in `eth_call` and `eth_estimateGas` [#7965](https://github.com/hyperledger/besu/pull/7965)
## 24.12.0
@@ -68,11 +70,13 @@
- Prometheus Java Metrics library upgraded to version 1.3.3 [#7880](https://github.com/hyperledger/besu/pull/7880)
- Add histogram to Prometheus metrics system [#7944](https://github.com/hyperledger/besu/pull/7944)
- Improve newPayload and FCU logs [#7961](https://github.com/hyperledger/besu/pull/7961)
- Proper support for `pending` block tag when calling `eth_estimateGas` and `eth_createAccessList` [#7951](https://github.com/hyperledger/besu/pull/7951)
### Bug fixes
- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825)
- Fix CVE-2024-47535 [7878](https://github.com/hyperledger/besu/pull/7878)
- Fix QBFT prepared block based proposal validation [#7875](https://github.com/hyperledger/besu/pull/7875)
- Correct default parameters for frontier transactions in `eth_call` and `eth_estimateGas` [#7965](https://github.com/hyperledger/besu/pull/7965)
- Correctly parse nonce as hex in `eth_call` account overrides [#7999](https://github.com/hyperledger/besu/pull/7999)
## 24.10.0

View File

@@ -66,7 +66,7 @@ services:
- --rpc-ws-enabled
- --rpc-ws-apis=admin,eth,miner,web3,net,priv,eea
- --rpc-ws-host=0.0.0.0
- --host-whitelist=*
- --host-allowlist=*
- --graphql-http-enabled
- --discovery-enabled=false
- --privacy-enabled=true
@@ -84,7 +84,7 @@ services:
- --rpc-ws-enabled
- --rpc-ws-apis=admin,eth,miner,web3,net,priv,eea
- --rpc-ws-host=0.0.0.0
- --host-whitelist=*
- --host-allowlist=*
- --graphql-http-enabled
- --discovery-enabled=false
- --privacy-enabled=true

View File

@@ -610,14 +610,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
defaultValue = "localhost,127.0.0.1")
private final JsonRPCAllowlistHostsProperty hostsAllowlist = new JsonRPCAllowlistHostsProperty();
@Option(
names = {"--host-whitelist"},
hidden = true,
paramLabel = "<hostname>[,<hostname>...]... or * or all",
description =
"Deprecated in favor of --host-allowlist. Comma separated list of hostnames to allow for RPC access, or * to accept any host (default: ${DEFAULT-VALUE})")
private final JsonRPCAllowlistHostsProperty hostsWhitelist = new JsonRPCAllowlistHostsProperty();
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
@Option(
names = {"--color-enabled"},
@@ -1701,15 +1693,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
unstableIpcOptions.getRpcIpcApis());
inProcessRpcConfiguration = inProcessRpcOptions.toDomainObject();
dataStorageConfiguration = getDataStorageConfiguration();
// hostsWhitelist is a hidden option. If it is specified, add the list to hostAllowlist
if (!hostsWhitelist.isEmpty()) {
// if allowlist == default values, remove the default values
if (hostsAllowlist.size() == 2
&& hostsAllowlist.containsAll(List.of("localhost", "127.0.0.1"))) {
hostsAllowlist.removeAll(List.of("localhost", "127.0.0.1"));
}
hostsAllowlist.addAll(hostsWhitelist);
}
permissioningConfiguration = permissioningConfiguration();
staticNodes = loadStaticNodes();

View File

@@ -690,9 +690,10 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
.build());
}
final EthContext ethContext = new EthContext(ethPeers, ethMessages, snapMessages, scheduler);
final PeerTaskExecutor peerTaskExecutor =
new PeerTaskExecutor(ethPeers, new PeerTaskRequestSender(), metricsSystem);
final EthContext ethContext =
new EthContext(ethPeers, ethMessages, snapMessages, scheduler, peerTaskExecutor);
final boolean fullSyncDisabled = !SyncMode.isFullSync(syncConfig.getSyncMode());
final SyncState syncState = new SyncState(blockchain, ethPeers, fullSyncDisabled, checkpoint);
@@ -718,7 +719,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
besuComponent.map(BesuComponent::getBlobCache).orElse(new BlobCache()),
miningConfiguration);
final List<PeerValidator> peerValidators = createPeerValidators(protocolSchedule);
final List<PeerValidator> peerValidators =
createPeerValidators(protocolSchedule, peerTaskExecutor);
final EthProtocolManager ethProtocolManager =
createEthProtocolManager(
@@ -947,6 +949,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
ethContext,
metricsSystem,
genesisConfigOptions,
syncConfig,
unverifiedForkchoiceSupplier,
unsubscribeForkchoiceListener);
} else {
@@ -1179,29 +1182,42 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
* Create peer validators list.
*
* @param protocolSchedule the protocol schedule
* @param peerTaskExecutor the peer task executor
* @return the list
*/
protected List<PeerValidator> createPeerValidators(final ProtocolSchedule protocolSchedule) {
protected List<PeerValidator> createPeerValidators(
final ProtocolSchedule protocolSchedule, final PeerTaskExecutor peerTaskExecutor) {
final List<PeerValidator> validators = new ArrayList<>();
final OptionalLong daoBlock = genesisConfigOptions.getDaoForkBlock();
if (daoBlock.isPresent()) {
// Setup dao validator
validators.add(
new DaoForkPeerValidator(protocolSchedule, metricsSystem, daoBlock.getAsLong()));
new DaoForkPeerValidator(
protocolSchedule, peerTaskExecutor, syncConfig, metricsSystem, daoBlock.getAsLong()));
}
final OptionalLong classicBlock = genesisConfigOptions.getClassicForkBlock();
// setup classic validator
if (classicBlock.isPresent()) {
validators.add(
new ClassicForkPeerValidator(protocolSchedule, metricsSystem, classicBlock.getAsLong()));
new ClassicForkPeerValidator(
protocolSchedule,
peerTaskExecutor,
syncConfig,
metricsSystem,
classicBlock.getAsLong()));
}
for (final Map.Entry<Long, Hash> requiredBlock : requiredBlocks.entrySet()) {
validators.add(
new RequiredBlocksPeerValidator(
protocolSchedule, metricsSystem, requiredBlock.getKey(), requiredBlock.getValue()));
protocolSchedule,
peerTaskExecutor,
syncConfig,
metricsSystem,
requiredBlock.getKey(),
requiredBlock.getValue()));
}
final CheckpointConfigOptions checkpointConfigOptions =
@@ -1210,6 +1226,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
validators.add(
new CheckpointBlocksPeerValidator(
protocolSchedule,
peerTaskExecutor,
syncConfig,
metricsSystem,
checkpointConfigOptions.getNumber().orElseThrow(),
checkpointConfigOptions.getHash().map(Hash::fromHexString).orElseThrow()));

View File

@@ -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.EthScheduler;
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.RequiredBlocksPeerValidator;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@@ -79,6 +80,7 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
new BackwardSyncContext(
protocolContext,
protocolSchedule,
syncConfig,
metricsSystem,
ethProtocolManager.ethContext(),
syncState,
@@ -235,14 +237,17 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
}
@Override
protected List<PeerValidator> createPeerValidators(final ProtocolSchedule protocolSchedule) {
List<PeerValidator> retval = super.createPeerValidators(protocolSchedule);
protected List<PeerValidator> createPeerValidators(
final ProtocolSchedule protocolSchedule, final PeerTaskExecutor peerTaskExecutor) {
List<PeerValidator> retval = super.createPeerValidators(protocolSchedule, peerTaskExecutor);
final OptionalLong powTerminalBlockNumber = genesisConfigOptions.getTerminalBlockNumber();
final Optional<Hash> powTerminalBlockHash = genesisConfigOptions.getTerminalBlockHash();
if (powTerminalBlockHash.isPresent() && powTerminalBlockNumber.isPresent()) {
retval.add(
new RequiredBlocksPeerValidator(
protocolSchedule,
peerTaskExecutor,
syncConfig,
metricsSystem,
powTerminalBlockNumber.getAsLong(),
powTerminalBlockHash.get(),

View File

@@ -119,6 +119,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
new TransitionBackwardSyncContext(
protocolContext,
transitionProtocolSchedule,
syncConfig,
metricsSystem,
ethProtocolManager.ethContext(),
syncState,

View File

@@ -23,24 +23,6 @@ import org.mockito.Mockito;
public class HostAllowlistOptionsTest extends CommandTestAbstract {
/** test deprecated CLI option * */
@Deprecated
@Test
public void rpcHttpHostWhitelistAcceptsSingleArgument() {
parseCommand("--host-whitelist", "a");
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist().size()).isEqualTo(1);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist()).contains("a");
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist())
.doesNotContain("localhost");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void rpcHttpHostAllowlistAcceptsSingleArgument() {
parseCommand("--host-allowlist", "a");
@@ -89,23 +71,6 @@ public class HostAllowlistOptionsTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Deprecated
@Test
public void rpcHttpHostWhitelistAllowlistAcceptsMultipleFlags() {
parseCommand("--host-whitelist=a", "--host-allowlist=b");
verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist().size()).isEqualTo(2);
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist()).contains("a", "b");
assertThat(jsonRpcConfigArgumentCaptor.getValue().getHostsAllowlist())
.doesNotContain("*", "localhost");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void rpcHttpHostAllowlistAcceptsMultipleFlags() {
parseCommand("--host-allowlist=a", "--host-allowlist=b");

View File

@@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableIn
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
@@ -73,6 +74,7 @@ public class TransitionControllerBuilderTest {
@Mock ProtocolContext protocolContext;
@Mock MutableBlockchain mockBlockchain;
@Mock TransactionPool transactionPool;
@Mock PeerTaskExecutor peerTaskExecutor;
@Mock SyncState syncState;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)

View File

@@ -44,7 +44,6 @@ max-peers=42
remote-connections-limit-enabled=true
remote-connections-max-percentage=60
random-peer-priority-enabled=false
host-whitelist=["all"]
host-allowlist=["all"]
engine-host-allowlist=["all"]
engine-rpc-enabled=true

View File

@@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardChain;
import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
@@ -43,6 +44,7 @@ public class TransitionBackwardSyncContext extends BackwardSyncContext {
public TransitionBackwardSyncContext(
final ProtocolContext protocolContext,
final TransitionProtocolSchedule transitionProtocolSchedule,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final EthContext ethContext,
final SyncState syncState,
@@ -50,6 +52,7 @@ public class TransitionBackwardSyncContext extends BackwardSyncContext {
super(
protocolContext,
transitionProtocolSchedule,
synchronizerConfiguration,
metricsSystem,
ethContext,
syncState,

View File

@@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -21,7 +23,6 @@ import java.util.Optional;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -84,6 +85,7 @@ public class AccountOverride {
}
/** Builder class for Account overrides */
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Builder {
private Optional<Wei> balance = Optional.empty();
private Optional<Long> nonce = Optional.empty();
@@ -110,8 +112,8 @@ public class AccountOverride {
* @param nonce the nonce override in hex
* @return the builder
*/
public Builder withNonce(final String nonce) {
this.nonce = Optional.of(Bytes.fromHexStringLenient(nonce).toLong());
public Builder withNonce(final UnsignedLongParameter nonce) {
this.nonce = Optional.of(nonce.getValue());
return this;
}

View File

@@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -291,4 +292,16 @@ public class Address extends DelegatingBytes {
return Hash.hash(this);
}
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Address)) {
return false;
}
Address other = (Address) obj;
return Arrays.equals(this.toArrayUnsafe(), other.toArrayUnsafe());
}
}

View File

@@ -12,20 +12,31 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
package org.hyperledger.besu.datatypes.parameters;
import com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.tuweni.units.bigints.UInt256;
/** A parameter that represents a UInt256 value. */
public class UInt256Parameter {
private final UInt256 value;
/**
* Create a new UInt256Parameter
*
* @param value the value
*/
@JsonCreator
public UInt256Parameter(final String value) {
this.value = UInt256.fromHexString(value);
}
/**
* Get the value
*
* @return the value
*/
public UInt256 getValue() {
return value;
}

View File

@@ -12,28 +12,44 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
package org.hyperledger.besu.datatypes.parameters;
import static com.google.common.base.Preconditions.checkArgument;
import com.fasterxml.jackson.annotation.JsonCreator;
/** A parameter that represents an unsigned int value. */
public class UnsignedIntParameter {
private final int value;
/**
* Create a new UnsignedIntParameter
*
* @param value the value
*/
@JsonCreator
public UnsignedIntParameter(final String value) {
this.value = Integer.decode(value);
checkArgument(this.value >= 0);
}
/**
* Create a new UnsignedIntParameter
*
* @param value the value
*/
@JsonCreator
public UnsignedIntParameter(final int value) {
this.value = value;
checkArgument(this.value >= 0);
}
/**
* Get the value of the parameter
*
* @return the value
*/
public int getValue() {
return value;
}

View File

@@ -12,17 +12,23 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
package org.hyperledger.besu.datatypes.parameters;
import static com.google.common.base.Preconditions.checkArgument;
import com.fasterxml.jackson.annotation.JsonCreator;
import org.checkerframework.checker.signedness.qual.Unsigned;
/** A parameter that represents an unsigned long value. */
public class UnsignedLongParameter {
@Unsigned private final long value;
/**
* Create a new UnsignedLongParameter
*
* @param value the value
*/
@JsonCreator
public UnsignedLongParameter(final String value) {
checkArgument(value != null);
@@ -33,11 +39,21 @@ public class UnsignedLongParameter {
}
}
/**
* Create a new UnsignedLongParameter
*
* @param value the value
*/
@JsonCreator
public UnsignedLongParameter(final @Unsigned long value) {
this.value = value;
}
/**
* Get the value of the parameter
*
* @return the value
*/
public @Unsigned long getValue() {
return value;
}

View File

@@ -15,11 +15,14 @@
package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLContextType;
import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.ArrayList;
import java.util.List;
@@ -122,13 +125,22 @@ public class NormalBlockAdapter extends BlockAdapterBase {
*
* <p>Each TransactionAdapter object is created by adapting a TransactionWithMetadata object.
*
* @param environment the data fetching environment.
* @return a list of TransactionAdapter objects for the transactions in the block.
*/
public List<TransactionAdapter> getTransactions() {
public List<TransactionAdapter> getTransactions(final DataFetchingEnvironment environment) {
final BlockchainQueries query = getBlockchainQueries(environment);
final Hash hash = blockWithMetaData.getHeader().getHash();
final ProtocolSchedule protocolSchedule =
environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE);
final List<TransactionWithMetadata> trans = blockWithMetaData.getTransactions();
final List<TransactionReceiptWithMetadata> transReceipts =
query.transactionReceiptsByBlockHash(hash, protocolSchedule).get();
final List<TransactionAdapter> results = new ArrayList<>();
for (final TransactionWithMetadata tran : trans) {
results.add(new TransactionAdapter(tran));
for (int i = 0; i < trans.size(); i++) {
results.add(new TransactionAdapter(trans.get(i), transReceipts.get(i)));
}
return results;
}

View File

@@ -75,7 +75,7 @@ public class PendingStateAdapter extends AdapterBase {
return transactionPool.getPendingTransactions().stream()
.map(PendingTransaction::getTransaction)
.map(TransactionWithMetadata::new)
.map(TransactionAdapter::new)
.map(tx -> new TransactionAdapter(tx, null))
.toList();
}

View File

@@ -35,6 +35,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import graphql.schema.DataFetchingEnvironment;
import org.apache.tuweni.bytes.Bytes;
@@ -65,6 +66,25 @@ public class TransactionAdapter extends AdapterBase {
this.transactionWithMetadata = transactionWithMetadata;
}
/**
* Constructs a new TransactionAdapter object with receipt.
*
* @param transactionWithMetadata the TransactionWithMetadata object to adapt.
* @param transactionReceiptWithMetadata the TransactionReceiptWithMetadata object to adapt.
*/
public TransactionAdapter(
final @Nonnull TransactionWithMetadata transactionWithMetadata,
final @Nullable TransactionReceiptWithMetadata transactionReceiptWithMetadata) {
this.transactionWithMetadata = transactionWithMetadata;
this.transactionReceiptWithMetadata = Optional.ofNullable(transactionReceiptWithMetadata);
}
/**
* Reurns the receipt of the transaction.
*
* @param environment the data fetching environment.
* @return the receipt of the transaction.
*/
private Optional<TransactionReceiptWithMetadata> getReceipt(
final DataFetchingEnvironment environment) {
if (transactionReceiptWithMetadata == null) {

View File

@@ -18,13 +18,13 @@ import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalcu
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;

View File

@@ -27,13 +27,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionRec
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionReceiptStatusResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.TransactionReceiptType;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.base.Suppliers;
@@ -70,35 +68,21 @@ public class EthGetBlockReceipts extends AbstractBlockParameterOrBlockHashMethod
}
/*
* For a given transaction, get its receipt and if it exists, wrap in a transaction receipt of the correct type
* For a given block, get receipts of transactions in the block and if they exist, wrap in transaction receipts of the correct type
*/
private Optional<TransactionReceiptResult> txReceipt(final TransactionWithMetadata tx) {
Optional<TransactionReceiptWithMetadata> receipt =
blockchainQueries
.get()
.transactionReceiptByTransactionHash(tx.getTransaction().getHash(), protocolSchedule);
if (receipt.isPresent()) {
if (receipt.get().getReceipt().getTransactionReceiptType() == TransactionReceiptType.ROOT) {
return Optional.of(new TransactionReceiptRootResult(receipt.get()));
} else {
return Optional.of(new TransactionReceiptStatusResult(receipt.get()));
}
}
return Optional.empty();
}
private BlockReceiptsResult getBlockReceiptsResult(final Hash blockHash) {
final List<TransactionReceiptResult> receiptList =
blockchainQueries
.get()
.blockByHash(blockHash)
.transactionReceiptsByBlockHash(blockHash, protocolSchedule)
.orElse(new ArrayList<TransactionReceiptWithMetadata>())
.stream()
.map(
block ->
block.getTransactions().stream()
.map(this::txReceipt)
.flatMap(Optional::stream)
.collect(Collectors.toList()))
.orElse(new ArrayList<>());
receipt ->
receipt.getReceipt().getTransactionReceiptType() == TransactionReceiptType.ROOT
? new TransactionReceiptRootResult(receipt)
: new TransactionReceiptStatusResult(receipt))
.collect(Collectors.toList());
return new BlockReceiptsResult(receiptList);
}

View File

@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.MinerDataResul
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.MinerDataResult.UncleRewardResult;
import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata;
import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@@ -91,19 +92,16 @@ public class EthGetMinerDataByBlockHash implements JsonRpcMethod {
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader);
final Wei staticBlockReward = protocolSpec.getBlockReward();
final Wei transactionFee =
block.getTransactions().stream()
blockchainQueries
.transactionReceiptsByBlockHash(blockHeader.getHash(), protocolSchedule)
.orElse(new ArrayList<TransactionReceiptWithMetadata>())
.stream()
.map(
t ->
blockchainQueries
.transactionReceiptByTransactionHash(
t.getTransaction().getHash(), protocolSchedule)
.map(
receipt ->
receipt
.getTransaction()
.getEffectiveGasPrice(receipt.getBaseFee())
.multiply(receipt.getGasUsed()))
.orElse(Wei.ZERO))
receipt ->
receipt
.getTransaction()
.getEffectivePriorityFeePerGas(receipt.getBaseFee())
.multiply(receipt.getGasUsed()))
.reduce(Wei.ZERO, BaseUInt256Value::add);
final Wei uncleInclusionReward =
staticBlockReward.multiply(block.getOmmers().size()).divide(32);

View File

@@ -16,12 +16,12 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.parameters.UInt256Parameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UInt256Parameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;

View File

@@ -15,11 +15,11 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;

View File

@@ -14,12 +14,12 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.datatypes.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionCompleteResult;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;

View File

@@ -15,11 +15,11 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;

View File

@@ -14,12 +14,12 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.datatypes.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedIntParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.UncleBlockResult;

View File

@@ -14,13 +14,13 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;

View File

@@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.core.Difficulty;
import com.fasterxml.jackson.annotation.JsonCreator;

View File

@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.evm.log.LogsBloomFilter;
import java.util.List;

View File

@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import java.util.Collections;
import java.util.List;

View File

@@ -14,11 +14,11 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.methods.WebSocketRpcRequest;

View File

@@ -631,6 +631,63 @@ public class BlockchainQueries {
return blockchain.getTransactionLocation(transactionHash);
}
/**
* Returns the transaction receipts associated with the given block hash.
*
* @param blockHash The hash of the block that corresponds to the receipts to retrieve.
* @return The transaction receipts associated with the referenced block.
*/
public Optional<List<TransactionReceiptWithMetadata>> transactionReceiptsByBlockHash(
final Hash blockHash, final ProtocolSchedule protocolSchedule) {
final Optional<Block> block = blockchain.getBlockByHash(blockHash);
if (block.isEmpty()) {
return Optional.empty();
}
final BlockHeader header = block.get().getHeader();
final List<Transaction> transactions = block.get().getBody().getTransactions();
final List<TransactionReceipt> transactionReceipts =
blockchain.getTxReceipts(blockHash).orElseThrow();
long cumulativeGasUsedUntilTx = 0;
int logIndexOffset = 0;
List<TransactionReceiptWithMetadata> receiptsResult =
new ArrayList<TransactionReceiptWithMetadata>(transactions.size());
for (int transactionIndex = 0; transactionIndex < transactions.size(); transactionIndex++) {
final Transaction transaction = transactions.get(transactionIndex);
final TransactionReceipt transactionReceipt = transactionReceipts.get(transactionIndex);
final Hash transactionHash = transaction.getHash();
long gasUsed = transactionReceipt.getCumulativeGasUsed() - cumulativeGasUsedUntilTx;
Optional<Long> maybeBlobGasUsed =
getBlobGasUsed(transaction, protocolSchedule.getByBlockHeader(header));
Optional<Wei> maybeBlobGasPrice =
getBlobGasPrice(transaction, header, protocolSchedule.getByBlockHeader(header));
receiptsResult.add(
TransactionReceiptWithMetadata.create(
transactionReceipt,
transaction,
transactionHash,
transactionIndex,
gasUsed,
header.getBaseFee(),
blockHash,
header.getNumber(),
maybeBlobGasUsed,
maybeBlobGasPrice,
logIndexOffset));
cumulativeGasUsedUntilTx = transactionReceipt.getCumulativeGasUsed();
logIndexOffset += transactionReceipt.getLogsList().size();
}
return Optional.of(receiptsResult);
}
/**
* Returns the transaction receipt associated with the given transaction hash.
*

View File

@@ -32,6 +32,7 @@ import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
@@ -104,7 +105,8 @@ public class EthCallTest {
@Test
public void someAccountOverrides() {
AccountOverrideMap expectedOverrides = new AccountOverrideMap();
AccountOverride override = new AccountOverride.Builder().withNonce("0x9e").build();
AccountOverride override =
new AccountOverride.Builder().withNonce(new UnsignedLongParameter("0x9e")).build();
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
expectedOverrides.put(address, override);

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
@@ -116,7 +117,8 @@ public class EthEstimateGasTest {
@Test
public void someAccountOverrides() {
AccountOverrideMap expectedOverrides = new AccountOverrideMap();
AccountOverride override = new AccountOverride.Builder().withNonce("0x9e").build();
AccountOverride override =
new AccountOverride.Builder().withNonce(new UnsignedLongParameter("0x9e")).build();
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
expectedOverrides.put(address, override);

View File

@@ -33,6 +33,7 @@ import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
import org.hyperledger.besu.ethereum.BlockProcessingResult;
import org.hyperledger.besu.ethereum.ProtocolContext;
@@ -40,7 +41,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;

View File

@@ -23,12 +23,12 @@ import org.hyperledger.besu.consensus.merge.MergeContext;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EngineExchangeTransitionConfigurationParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineExchangeTransitionConfigurationResult;

View File

@@ -330,6 +330,41 @@ public class BlockchainQueriesTest {
assertThat(result).contains(targetBlock.getBody().getOmmers().size());
}
@Test
public void getTransactionReceiptsByHash() {
final BlockchainWithData data = setupBlockchain(3);
final BlockchainQueries queries = data.blockchainQueries;
final Block targetBlock = data.blockData.get(1).block;
final Optional<List<TransactionReceiptWithMetadata>> receipts =
queries.transactionReceiptsByBlockHash(
targetBlock.getHash(), Mockito.mock(ProtocolSchedule.class));
assertThat(receipts).isNotEmpty();
receipts
.get()
.forEach(
receipt -> {
final long gasUsed = receipt.getGasUsed();
assertThat(gasUsed)
.isEqualTo(
targetBlock.getHeader().getGasUsed()
/ targetBlock.getBody().getTransactions().size());
});
}
@Test
public void getTransactionReceiptsByInvalidHash() {
final BlockchainWithData data = setupBlockchain(3);
final BlockchainQueries queries = data.blockchainQueries;
final Optional<List<TransactionReceiptWithMetadata>> result =
queries.transactionReceiptsByBlockHash(gen.hash(), Mockito.mock(ProtocolSchedule.class));
assertThat(result).isEmpty();
}
@Test
public void logsShouldBeFlaggedAsRemovedWhenBlockIsNotInCanonicalChain() {
// create initial blockchain

View File

@@ -0,0 +1,33 @@
{
"request": {
"id": 3,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914"
},
"latest",
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0xde0b6b3a7640000",
"nonce": 88
},
"0xb9741079a300Cb3B8f324CdDB847c0d1d273a05E": {
"stateDiff": {
"0x1cf7945003fc5b59d2f6736f0704557aa805c4f2844084ccd1173b8d56946962": "0x000000000000000000000000000000000000000000000000000000110ed03bf7"
},
"movePrecompileToAddress":null
}
}
]
},
"response": {
"jsonrpc": "2.0",
"id": 3,
"result": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"statusCode": 200
}

View File

@@ -1092,6 +1092,10 @@ public class Transaction
blobsWithCommitments.map(
withCommitments ->
blobsWithCommitmentsDetachedCopy(withCommitments, detachedVersionedHashes.get()));
final Optional<List<CodeDelegation>> detachedCodeDelegationList =
maybeCodeDelegationList.map(
codeDelegations ->
codeDelegations.stream().map(this::codeDelegationDetachedCopy).toList());
final var copiedTx =
new Transaction(
@@ -1112,7 +1116,7 @@ public class Transaction
chainId,
detachedVersionedHashes,
detachedBlobsWithCommitments,
maybeCodeDelegationList);
detachedCodeDelegationList);
// copy also the computed fields, to avoid to recompute them
copiedTx.sender = this.sender;
@@ -1129,6 +1133,15 @@ public class Transaction
return new AccessListEntry(detachedAddress, detachedStorage);
}
private CodeDelegation codeDelegationDetachedCopy(final CodeDelegation codeDelegation) {
final Address detachedAddress = Address.wrap(codeDelegation.address().copy());
return new org.hyperledger.besu.ethereum.core.CodeDelegation(
codeDelegation.chainId(),
detachedAddress,
codeDelegation.nonce(),
codeDelegation.signature());
}
private BlobsWithCommitments blobsWithCommitmentsDetachedCopy(
final BlobsWithCommitments blobsWithCommitments, final List<VersionedHash> versionedHashes) {
final var detachedCommitments =

View File

@@ -23,7 +23,7 @@ public class RequestContractAddresses {
private final Address consolidationRequestContractAddress;
public static final Address DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS =
Address.fromHexString("0x09FC772D0857550724B07B850A4323F39112AAAA");
Address.fromHexString("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA");
public static final Address DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS =
Address.fromHexString("0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB");
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =

View File

@@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.core;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
@@ -29,7 +30,8 @@ import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
public class TransactionTestFixture {
private final SECPSignature signature =
new SECPSignature(BigInteger.ONE, BigInteger.ONE, (byte) 0);
private TransactionType transactionType = TransactionType.FRONTIER;
private long nonce = 0;
@@ -56,6 +58,8 @@ public class TransactionTestFixture {
private Optional<BlobsWithCommitments> blobs = Optional.empty();
private Optional<BigInteger> v = Optional.empty();
private Optional<List<org.hyperledger.besu.datatypes.CodeDelegation>> codeDelegations =
Optional.empty();
public Transaction createTransaction(final KeyPair keys) {
final Transaction.Builder builder = Transaction.builder();
@@ -93,6 +97,12 @@ public class TransactionTestFixture {
}
break;
case DELEGATE_CODE:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
builder.codeDelegations(
codeDelegations.orElse(
List.of(new CodeDelegation(chainId.get(), sender, 0, signature))));
break;
}
@@ -183,4 +193,10 @@ public class TransactionTestFixture {
this.blobs = blobs;
return this;
}
public TransactionTestFixture codeDelegations(
final List<org.hyperledger.besu.datatypes.CodeDelegation> codeDelegations) {
this.codeDelegations = Optional.of(codeDelegations);
return this;
}
}

View File

@@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.eth.manager;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import java.util.Optional;
public class EthContext {
@@ -22,24 +24,31 @@ public class EthContext {
private final EthMessages ethMessages;
private final Optional<EthMessages> snapMessages;
private final EthScheduler scheduler;
private final PeerTaskExecutor peerTaskExecutor;
public EthContext(
final EthPeers ethPeers,
final EthMessages ethMessages,
final EthMessages snapMessages,
final EthScheduler scheduler) {
final EthScheduler scheduler,
final PeerTaskExecutor peerTaskExecutor) {
this.ethPeers = ethPeers;
this.ethMessages = ethMessages;
this.snapMessages = Optional.of(snapMessages);
this.scheduler = scheduler;
this.peerTaskExecutor = peerTaskExecutor;
}
public EthContext(
final EthPeers ethPeers, final EthMessages ethMessages, final EthScheduler scheduler) {
final EthPeers ethPeers,
final EthMessages ethMessages,
final EthScheduler scheduler,
final PeerTaskExecutor peerTaskExecutor) {
this.ethPeers = ethPeers;
this.ethMessages = ethMessages;
this.snapMessages = Optional.empty();
this.scheduler = scheduler;
this.peerTaskExecutor = peerTaskExecutor;
}
public EthPeers getEthPeers() {
@@ -57,4 +66,8 @@ public class EthContext {
public EthScheduler getScheduler() {
return scheduler;
}
public PeerTaskExecutor getPeerTaskExecutor() {
return peerTaskExecutor;
}
}

View File

@@ -20,6 +20,10 @@ public class InvalidPeerTaskResponseException extends Exception {
super();
}
public InvalidPeerTaskResponseException(final String message) {
super(message);
}
public InvalidPeerTaskResponseException(final Throwable cause) {
super(cause);
}

View File

@@ -75,9 +75,13 @@ public interface PeerTask<T> {
Predicate<EthPeer> getPeerRequirementFilter();
/**
* Checks if the supplied result is considered a success
* Performs a high level check of the results, returning a PeerTaskValidationResponse to describe
* the result of the check
*
* @return true if the supplied result is considered a success
* @param result The results of the PeerTask, as returned by processResponse
* @return a PeerTaskValidationResponse to describe the result of the check
*/
boolean isSuccess(T result);
PeerTaskValidationResponse validateResult(T result);
default void postProcessResult(final PeerTaskExecutorResult<T> result) {}
}

View File

@@ -29,12 +29,15 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Manages the execution of PeerTasks, respecting their PeerTaskRetryBehavior */
public class PeerTaskExecutor {
private static final Logger LOG = LoggerFactory.getLogger(PeerTaskExecutor.class);
private final PeerSelector peerSelector;
private final PeerTaskRequestSender requestSender;
@@ -98,8 +101,8 @@ public class PeerTaskExecutor {
if (peer.isEmpty()) {
executorResult =
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE);
continue;
Optional.empty(), PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE, Optional.empty());
break;
}
usedEthPeers.add(peer.get());
executorResult = executeAgainstPeer(peerTask, peer.get());
@@ -138,43 +141,59 @@ public class PeerTaskExecutor {
inflightRequestCountForThisTaskClass.decrementAndGet();
}
if (peerTask.isSuccess(result)) {
PeerTaskValidationResponse validationResponse = peerTask.validateResult(result);
if (validationResponse == PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD) {
peer.recordUsefulResponse();
executorResult =
new PeerTaskExecutorResult<>(
Optional.ofNullable(result), PeerTaskExecutorResponseCode.SUCCESS);
Optional.ofNullable(result),
PeerTaskExecutorResponseCode.SUCCESS,
Optional.of(peer));
peerTask.postProcessResult(executorResult);
} else {
// At this point, the result is most likely empty. Technically, this is a valid result, so
// we don't penalise the peer, but it's also a useless result, so we return
// INVALID_RESPONSE code
LOG.debug(
"Invalid response found for {} from peer {}", taskClassName, peer.getLoggableId());
validationResponse
.getDisconnectReason()
.ifPresent((disconnectReason) -> peer.disconnect(disconnectReason));
executorResult =
new PeerTaskExecutorResult<>(
Optional.ofNullable(result), PeerTaskExecutorResponseCode.INVALID_RESPONSE);
Optional.ofNullable(result),
PeerTaskExecutorResponseCode.INVALID_RESPONSE,
Optional.of(peer));
}
} catch (PeerNotConnected e) {
executorResult =
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.PEER_DISCONNECTED);
Optional.empty(),
PeerTaskExecutorResponseCode.PEER_DISCONNECTED,
Optional.of(peer));
} catch (InterruptedException | TimeoutException e) {
peer.recordRequestTimeout(requestMessageData.getCode());
timeoutCounter.labels(taskClassName).inc();
executorResult =
new PeerTaskExecutorResult<>(Optional.empty(), PeerTaskExecutorResponseCode.TIMEOUT);
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.TIMEOUT, Optional.of(peer));
} catch (InvalidPeerTaskResponseException e) {
peer.recordUselessResponse(e.getMessage());
invalidResponseCounter.labels(taskClassName).inc();
LOG.debug(
"Invalid response found for {} from peer {}", taskClassName, peer.getLoggableId(), e);
executorResult =
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.INVALID_RESPONSE);
Optional.empty(), PeerTaskExecutorResponseCode.INVALID_RESPONSE, Optional.of(peer));
} catch (ExecutionException e) {
} catch (Exception e) {
internalExceptionCounter.labels(taskClassName).inc();
LOG.error("Server error found for {} from peer {}", taskClassName, peer.getLoggableId(), e);
executorResult =
new PeerTaskExecutorResult<>(
Optional.empty(), PeerTaskExecutorResponseCode.INTERNAL_SERVER_ERROR);
Optional.empty(),
PeerTaskExecutorResponseCode.INTERNAL_SERVER_ERROR,
Optional.of(peer));
}
} while (retriesRemaining-- > 0
&& executorResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS

View File

@@ -14,7 +14,9 @@
*/
package org.hyperledger.besu.ethereum.eth.manager.peertask;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import java.util.Optional;
public record PeerTaskExecutorResult<T>(
Optional<T> result, PeerTaskExecutorResponseCode responseCode) {}
Optional<T> result, PeerTaskExecutorResponseCode responseCode, Optional<EthPeer> ethPeer) {}

View File

@@ -0,0 +1,37 @@
/*
* Copyright contributors to 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;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage;
import java.util.Optional;
public enum PeerTaskValidationResponse {
NO_RESULTS_RETURNED(null),
TOO_MANY_RESULTS_RETURNED(null),
RESULTS_DO_NOT_MATCH_QUERY(null),
NON_SEQUENTIAL_HEADERS_RETURNED(
DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL_NON_SEQUENTIAL_HEADERS),
RESULTS_VALID_AND_GOOD(null);
private final Optional<DisconnectMessage.DisconnectReason> disconnectReason;
PeerTaskValidationResponse(final DisconnectMessage.DisconnectReason disconnectReason) {
this.disconnectReason = Optional.ofNullable(disconnectReason);
}
public Optional<DisconnectMessage.DisconnectReason> getDisconnectReason() {
return disconnectReason;
}
}

View File

@@ -0,0 +1,263 @@
/*
* 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.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.manager.peertask.PeerTaskExecutorResult;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskValidationResponse;
import org.hyperledger.besu.ethereum.eth.messages.BlockHeadersMessage;
import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage;
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.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GetHeadersFromPeerTask implements PeerTask<List<BlockHeader>> {
private static final Logger LOG = LoggerFactory.getLogger(GetHeadersFromPeerTask.class);
private final long blockNumber;
private final Hash blockHash;
private final int maxHeaders;
private final int skip;
private final Direction direction;
private final int maximumRetriesAgainstDifferentPeers;
private final ProtocolSchedule protocolSchedule;
private final long requiredBlockchainHeight;
public GetHeadersFromPeerTask(
final long blockNumber,
final int maxHeaders,
final int skip,
final Direction direction,
final ProtocolSchedule protocolSchedule) {
this(blockNumber, maxHeaders, skip, direction, 5, protocolSchedule);
}
public GetHeadersFromPeerTask(
final long blockNumber,
final int maxHeaders,
final int skip,
final Direction direction,
final int maximumRetriesAgainstDifferentPeers,
final ProtocolSchedule protocolSchedule) {
this(
null,
blockNumber,
maxHeaders,
skip,
direction,
maximumRetriesAgainstDifferentPeers,
protocolSchedule);
}
public GetHeadersFromPeerTask(
final Hash blockHash,
final long blockNumber,
final int maxHeaders,
final int skip,
final Direction direction,
final ProtocolSchedule protocolSchedule) {
this(blockHash, blockNumber, maxHeaders, skip, direction, 5, protocolSchedule);
}
public GetHeadersFromPeerTask(
final Hash blockHash,
final long blockNumber,
final int maxHeaders,
final int skip,
final Direction direction,
final int maximumRetriesAgainstDifferentPeers,
final ProtocolSchedule protocolSchedule) {
LOG.debug(
"Constructing GetHeadersFromPeerTask with hash {}, number {}, maxHeaders {}, skip {}, direction {}",
blockHash,
blockNumber,
maxHeaders,
skip,
direction);
this.blockHash = blockHash;
this.blockNumber = blockNumber;
this.maxHeaders = maxHeaders;
this.skip = skip;
this.direction = direction;
this.maximumRetriesAgainstDifferentPeers = maximumRetriesAgainstDifferentPeers;
this.protocolSchedule = protocolSchedule;
requiredBlockchainHeight =
direction == Direction.FORWARD
? blockNumber + (long) (maxHeaders - 1) * (skip + 1)
: blockNumber;
}
@Override
public SubProtocol getSubProtocol() {
return EthProtocol.get();
}
@Override
public MessageData getRequestMessage() {
if (blockHash != null) {
return GetBlockHeadersMessage.create(
blockHash, maxHeaders, skip, direction == Direction.REVERSE);
} else {
return GetBlockHeadersMessage.create(
blockNumber, maxHeaders, skip, direction == Direction.REVERSE);
}
}
@Override
public List<BlockHeader> processResponse(final MessageData messageData)
throws InvalidPeerTaskResponseException {
if (messageData == null) {
throw new InvalidPeerTaskResponseException("Response MessageData is null");
}
return BlockHeadersMessage.readFrom(messageData).getHeaders(protocolSchedule);
}
@Override
public Predicate<EthPeer> getPeerRequirementFilter() {
return (ethPeer) ->
protocolSchedule.anyMatch((ps) -> ps.spec().isPoS())
|| ethPeer.chainState().getEstimatedHeight() >= requiredBlockchainHeight;
}
@Override
public PeerTaskValidationResponse validateResult(final List<BlockHeader> blockHeaders) {
if (blockHeaders.isEmpty()) {
// Message contains no data - nothing to do
LOG.debug(
"No blockheaders returned for query starting at {}",
blockHash != null ? blockHash : blockNumber);
return PeerTaskValidationResponse.NO_RESULTS_RETURNED;
}
if (blockHeaders.size() > maxHeaders) {
// Too many headers - this isn't our response
LOG.debug(
"Too many blockheaders returned for query starting at {}",
blockHash != null ? blockHash : blockNumber);
return PeerTaskValidationResponse.TOO_MANY_RESULTS_RETURNED;
}
if ((blockHash != null && !blockHeaders.getFirst().getHash().equals(blockHash))
|| (blockHash == null && blockHeaders.getFirst().getNumber() != blockNumber)) {
// This isn't our message - nothing to do
LOG.debug(
"First header returned doesn't match query starting at {}",
blockHash != null ? blockHash : blockNumber);
return PeerTaskValidationResponse.RESULTS_DO_NOT_MATCH_QUERY;
}
if (!isBlockHeadersMatchingRequest(blockHeaders)) {
LOG.debug(
"Blockheaders do not match expected headers from request for query starting at {}",
blockHash != null ? blockHash : blockNumber);
return PeerTaskValidationResponse.RESULTS_DO_NOT_MATCH_QUERY;
}
if (blockHeaders.size() >= 2 && skip == 0) {
// headers are supposed to be sequential and at least 2 have been returned, check if a chain
// is formed
for (int i = 0; i < blockHeaders.size() - 1; i++) {
BlockHeader parentHeader = null;
BlockHeader childHeader = null;
switch (direction) {
case FORWARD:
parentHeader = blockHeaders.get(i);
childHeader = blockHeaders.get(i + 1);
break;
case REVERSE:
childHeader = blockHeaders.get(i);
parentHeader = blockHeaders.get(i + 1);
break;
}
if (!parentHeader.getHash().equals(childHeader.getParentHash())) {
LOG.warn(
"Blockheaders were non-sequential for query starting at {}",
blockHash != null ? blockHash : blockNumber);
return PeerTaskValidationResponse.NON_SEQUENTIAL_HEADERS_RETURNED;
}
}
}
return PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD;
}
@Override
public void postProcessResult(final PeerTaskExecutorResult<List<BlockHeader>> result) {
final AtomicReference<BlockHeader> highestBlockHeader =
new AtomicReference<>(result.result().get().getFirst());
for (BlockHeader blockHeader : result.result().get()) {
if (highestBlockHeader.get().getNumber() < blockHeader.getNumber()) {
highestBlockHeader.set(blockHeader);
}
}
result.ethPeer().ifPresent((ethPeer) -> ethPeer.chainState().update(highestBlockHeader.get()));
}
@Override
public int getRetriesWithOtherPeer() {
return maximumRetriesAgainstDifferentPeers;
}
public Long getBlockNumber() {
return blockNumber;
}
public Hash getBlockHash() {
return blockHash;
}
public int getMaxHeaders() {
return maxHeaders;
}
public int getSkip() {
return skip;
}
public Direction getDirection() {
return direction;
}
public enum Direction {
FORWARD,
REVERSE
}
private boolean isBlockHeadersMatchingRequest(final List<BlockHeader> blockHeaders) {
BlockHeader prevBlockHeader = blockHeaders.getFirst();
final int expectedDelta = direction == Direction.REVERSE ? -(skip + 1) : (skip + 1);
BlockHeader header;
for (int i = 1; i < blockHeaders.size(); i++) {
header = blockHeaders.get(i);
if (header.getNumber() != prevBlockHeader.getNumber() + expectedDelta) {
// Skip doesn't match, this isn't our data
return false;
}
prevBlockHeader = header;
}
return true;
}
}

View File

@@ -23,6 +23,7 @@ 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.manager.peertask.PeerTaskValidationResponse;
import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
@@ -128,7 +129,16 @@ public class GetReceiptsFromPeerTask
}
@Override
public boolean isSuccess(final Map<BlockHeader, List<TransactionReceipt>> result) {
return !result.isEmpty();
public PeerTaskValidationResponse validateResult(
final Map<BlockHeader, List<TransactionReceipt>> result) {
if (result.isEmpty()) {
return PeerTaskValidationResponse.NO_RESULTS_RETURNED;
}
return PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD;
}
public Collection<BlockHeader> getBlockHeaders() {
return blockHeaders;
}
}

View File

@@ -20,6 +20,12 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.IncompleteResultsException;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.PeerDisconnectedException;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -35,6 +41,7 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
private static final Logger LOG = LoggerFactory.getLogger(GetBlockFromPeerTask.class);
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
private final Optional<Hash> hash;
private final long blockNumber;
private final MetricsSystem metricsSystem;
@@ -42,10 +49,12 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
protected GetBlockFromPeerTask(
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final Optional<Hash> hash,
final long blockNumber,
final MetricsSystem metricsSystem) {
super(ethContext, metricsSystem);
this.synchronizerConfiguration = synchronizerConfiguration;
this.blockNumber = blockNumber;
this.metricsSystem = metricsSystem;
this.protocolSchedule = protocolSchedule;
@@ -55,10 +64,12 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
public static GetBlockFromPeerTask create(
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final Optional<Hash> hash,
final long blockNumber,
final MetricsSystem metricsSystem) {
return new GetBlockFromPeerTask(protocolSchedule, ethContext, hash, blockNumber, metricsSystem);
return new GetBlockFromPeerTask(
protocolSchedule, ethContext, synchronizerConfiguration, hash, blockNumber, metricsSystem);
}
@Override
@@ -68,31 +79,22 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
"Downloading block {} from peer {}.",
blockIdentifier,
assignedPeer.map(EthPeer::toString).orElse("<any>"));
downloadHeader()
.thenCompose(this::completeBlock)
.whenComplete(
(r, t) -> {
if (t != null) {
LOG.debug(
"Failed to download block {} from peer {} with message '{}' and cause '{}'",
blockIdentifier,
assignedPeer.map(EthPeer::toString).orElse("<any>"),
t.getMessage(),
t.getCause());
result.completeExceptionally(t);
} else if (r.getResult().isEmpty()) {
r.getPeer().recordUselessResponse("Download block returned an empty result");
LOG.debug(
"Failed to download block {} from peer {} with empty result.",
blockIdentifier,
r.getPeer());
result.completeExceptionally(new IncompleteResultsException());
} else {
LOG.debug(
"Successfully downloaded block {} from peer {}.", blockIdentifier, r.getPeer());
result.complete(new PeerTaskResult<>(r.getPeer(), r.getResult().get(0)));
}
});
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
downloadHeaderUsingPeerTaskSystem()
.thenCompose(this::completeBlock)
.whenComplete((r, t) -> completeTask(r, t, blockIdentifier));
});
} else {
downloadHeader()
.thenCompose(
(peerTaskResult) -> CompletableFuture.completedFuture(peerTaskResult.getResult()))
.thenCompose(this::completeBlock)
.whenComplete((r, t) -> completeTask(r, t, blockIdentifier));
}
}
private CompletableFuture<PeerTaskResult<List<BlockHeader>>> downloadHeader() {
@@ -113,9 +115,45 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
});
}
private CompletableFuture<List<BlockHeader>> downloadHeaderUsingPeerTaskSystem() {
GetHeadersFromPeerTask task =
hash.map(
(h) ->
new GetHeadersFromPeerTask(
h, blockNumber, 1, 0, Direction.FORWARD, protocolSchedule))
.orElseGet(
() ->
new GetHeadersFromPeerTask(
blockNumber, 1, 0, Direction.FORWARD, protocolSchedule));
PeerTaskExecutorResult<List<BlockHeader>> taskResult;
if (assignedPeer.isPresent()) {
taskResult = ethContext.getPeerTaskExecutor().executeAgainstPeer(task, assignedPeer.get());
} else {
taskResult = ethContext.getPeerTaskExecutor().execute(task);
}
CompletableFuture<List<BlockHeader>> returnValue = new CompletableFuture<List<BlockHeader>>();
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.PEER_DISCONNECTED
&& taskResult.ethPeer().isPresent()) {
returnValue.completeExceptionally(new PeerDisconnectedException(taskResult.ethPeer().get()));
} else if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
String logMessage =
"Peer "
+ taskResult.ethPeer().map(EthPeer::getLoggableId).orElse("UNKNOWN")
+ " failed to successfully return requested block headers. Response code was "
+ taskResult.responseCode();
returnValue.completeExceptionally(new RuntimeException(logMessage));
LOG.debug(logMessage);
} else {
returnValue.complete(taskResult.result().get());
}
return returnValue;
}
private CompletableFuture<PeerTaskResult<List<Block>>> completeBlock(
final PeerTaskResult<List<BlockHeader>> headerResult) {
if (headerResult.getResult().isEmpty()) {
final List<BlockHeader> headers) {
if (headers.isEmpty()) {
LOG.debug("header result is empty.");
return CompletableFuture.failedFuture(new IncompleteResultsException());
}
@@ -124,9 +162,38 @@ public class GetBlockFromPeerTask extends AbstractPeerTask<Block> {
() -> {
final GetBodiesFromPeerTask task =
GetBodiesFromPeerTask.forHeaders(
protocolSchedule, ethContext, headerResult.getResult(), metricsSystem);
task.assignPeer(headerResult.getPeer());
protocolSchedule, ethContext, headers, metricsSystem);
assignedPeer.ifPresent(task::assignPeer);
return task.run();
});
}
private void completeTask(
final PeerTaskResult<List<Block>> blockTaskResult,
final Throwable throwable,
final String blockIdentifier) {
if (throwable != null) {
LOG.debug(
"Failed to download block {} from peer {} with message '{}' and cause '{}'",
blockIdentifier,
assignedPeer.map(EthPeer::toString).orElse("<any>"),
throwable.getMessage(),
throwable.getCause());
result.completeExceptionally(throwable);
} else if (blockTaskResult.getResult().isEmpty()) {
blockTaskResult.getPeer().recordUselessResponse("Download block returned an empty result");
LOG.debug(
"Failed to download block {} from peer {} with empty result.",
blockIdentifier,
blockTaskResult.getPeer());
result.completeExceptionally(new IncompleteResultsException());
} else {
LOG.debug(
"Successfully downloaded block {} from peer {}.",
blockIdentifier,
blockTaskResult.getPeer());
result.complete(
new PeerTaskResult<>(blockTaskResult.getPeer(), blockTaskResult.getResult().get(0)));
}
}
}

View File

@@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.IncompleteResultsException;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -36,18 +37,21 @@ public class RetryingGetBlockFromPeersTask
private static final Logger LOG = LoggerFactory.getLogger(RetryingGetBlockFromPeersTask.class);
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
private final Optional<Hash> maybeBlockHash;
private final long blockNumber;
protected RetryingGetBlockFromPeersTask(
final EthContext ethContext,
final ProtocolSchedule protocolSchedule,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final int maxRetries,
final Optional<Hash> maybeBlockHash,
final long blockNumber) {
super(ethContext, metricsSystem, Objects::isNull, maxRetries);
this.protocolSchedule = protocolSchedule;
this.synchronizerConfiguration = synchronizerConfiguration;
this.maybeBlockHash = maybeBlockHash;
this.blockNumber = blockNumber;
}
@@ -55,12 +59,19 @@ public class RetryingGetBlockFromPeersTask
public static RetryingGetBlockFromPeersTask create(
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final int maxRetries,
final Optional<Hash> maybeHash,
final long blockNumber) {
return new RetryingGetBlockFromPeersTask(
ethContext, protocolSchedule, metricsSystem, maxRetries, maybeHash, blockNumber);
ethContext,
protocolSchedule,
synchronizerConfiguration,
metricsSystem,
maxRetries,
maybeHash,
blockNumber);
}
@Override
@@ -68,7 +79,12 @@ public class RetryingGetBlockFromPeersTask
final EthPeer currentPeer) {
final GetBlockFromPeerTask getBlockTask =
GetBlockFromPeerTask.create(
protocolSchedule, getEthContext(), maybeBlockHash, blockNumber, getMetricsSystem());
protocolSchedule,
getEthContext(),
synchronizerConfiguration,
maybeBlockHash,
blockNumber,
getMetricsSystem());
getBlockTask.assignPeer(currentPeer);
return executeSubTask(getBlockTask::run)

View File

@@ -19,8 +19,13 @@ import static com.google.common.base.Preconditions.checkArgument;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByNumberTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -36,6 +41,8 @@ abstract class AbstractPeerBlockValidator implements PeerValidator {
static long DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER = 10L;
private final ProtocolSchedule protocolSchedule;
private final PeerTaskExecutor peerTaskExecutor;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem;
final long blockNumber;
@@ -44,11 +51,15 @@ abstract class AbstractPeerBlockValidator implements PeerValidator {
AbstractPeerBlockValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long blockNumber,
final long chainHeightEstimationBuffer) {
checkArgument(chainHeightEstimationBuffer >= 0);
this.protocolSchedule = protocolSchedule;
this.peerTaskExecutor = peerTaskExecutor;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
this.blockNumber = blockNumber;
this.chainHeightEstimationBuffer = chainHeightEstimationBuffer;
@@ -57,44 +68,76 @@ abstract class AbstractPeerBlockValidator implements PeerValidator {
@Override
public CompletableFuture<Boolean> validatePeer(
final EthContext ethContext, final EthPeer ethPeer) {
final AbstractPeerTask<List<BlockHeader>> getHeaderTask =
GetHeadersFromPeerByNumberTask.forSingleNumber(
protocolSchedule, ethContext, blockNumber, metricsSystem)
.setTimeout(Duration.ofSeconds(20))
.assignPeer(ethPeer);
return getHeaderTask
.run()
.handle(
(res, err) -> {
if (err != null) {
// Mark peer as invalid on error
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable: {}",
ethPeer,
blockNumber,
err.toString());
return false;
}
final List<BlockHeader> headers = res.getResult();
if (headers.size() == 0) {
if (blockIsRequired()) {
// If no headers are returned, fail
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable.",
ethPeer,
blockNumber);
return false;
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
blockNumber,
1,
0,
GetHeadersFromPeerTask.Direction.FORWARD,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
peerTaskExecutor.executeAgainstPeer(task, ethPeer);
CompletableFuture<Boolean> resultFuture;
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
resultFuture = CompletableFuture.completedFuture(false);
} else {
LOG.debug(
"Peer {} deemed valid because unavailable block ({}) is not required.",
ethPeer,
blockNumber);
return true;
resultFuture =
CompletableFuture.completedFuture(
validateBlockHeaders(ethPeer, taskResult.result().get()));
}
}
final BlockHeader header = headers.get(0);
return validateBlockHeader(ethPeer, header);
});
return resultFuture;
});
} else {
final AbstractPeerTask<List<BlockHeader>> getHeaderTask =
GetHeadersFromPeerByNumberTask.forSingleNumber(
protocolSchedule, ethContext, blockNumber, metricsSystem)
.setTimeout(Duration.ofSeconds(20))
.assignPeer(ethPeer);
return getHeaderTask
.run()
.handle(
(res, err) -> {
if (err != null) {
// Mark peer as invalid on error
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable: {}",
ethPeer,
blockNumber,
err.toString());
return false;
}
final List<BlockHeader> headers = res.getResult();
return validateBlockHeaders(ethPeer, headers);
});
}
}
private Boolean validateBlockHeaders(final EthPeer ethPeer, final List<BlockHeader> headers) {
boolean isValid;
if (headers.isEmpty()) {
if (blockIsRequired()) {
// If no headers are returned, fail
LOG.debug(
"Peer {} is invalid because required block ({}) is unavailable.", ethPeer, blockNumber);
isValid = false;
} else {
LOG.debug(
"Peer {} deemed valid because unavailable block ({}) is not required.",
ethPeer,
blockNumber);
isValid = true;
}
} else {
final BlockHeader header = headers.getFirst();
isValid = validateBlockHeader(ethPeer, header);
}
return isValid;
}
abstract boolean validateBlockHeader(EthPeer ethPeer, BlockHeader header);

View File

@@ -17,6 +17,8 @@ package org.hyperledger.besu.ethereum.eth.peervalidation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -24,20 +26,37 @@ public class CheckpointBlocksPeerValidator extends RequiredBlocksPeerValidator {
public CheckpointBlocksPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long blockNumber,
final Hash hash,
final long chainHeightEstimationBuffer) {
super(protocolSchedule, metricsSystem, blockNumber, hash, chainHeightEstimationBuffer);
super(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
blockNumber,
hash,
chainHeightEstimationBuffer);
}
public CheckpointBlocksPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long blockNumber,
final Hash hash) {
this(
protocolSchedule, metricsSystem, blockNumber, hash, DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
blockNumber,
hash,
DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
}
@Override

View File

@@ -16,6 +16,8 @@ package org.hyperledger.besu.ethereum.eth.peervalidation;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -28,17 +30,33 @@ public class ClassicForkPeerValidator extends AbstractPeerBlockValidator {
ClassicForkPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long daoBlockNumber,
final long chainHeightEstimationBuffer) {
super(protocolSchedule, metricsSystem, daoBlockNumber, chainHeightEstimationBuffer);
super(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
daoBlockNumber,
chainHeightEstimationBuffer);
}
public ClassicForkPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long daoBlockNumber) {
this(protocolSchedule, metricsSystem, daoBlockNumber, DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
this(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
daoBlockNumber,
DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
}
@Override

View File

@@ -16,6 +16,8 @@ package org.hyperledger.besu.ethereum.eth.peervalidation;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -28,17 +30,33 @@ public class DaoForkPeerValidator extends AbstractPeerBlockValidator {
DaoForkPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long daoBlockNumber,
final long chainHeightEstimationBuffer) {
super(protocolSchedule, metricsSystem, daoBlockNumber, chainHeightEstimationBuffer);
super(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
daoBlockNumber,
chainHeightEstimationBuffer);
}
public DaoForkPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long daoBlockNumber) {
this(protocolSchedule, metricsSystem, daoBlockNumber, DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
this(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
daoBlockNumber,
DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
}
@Override

View File

@@ -17,6 +17,8 @@ package org.hyperledger.besu.ethereum.eth.peervalidation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -30,21 +32,37 @@ public class RequiredBlocksPeerValidator extends AbstractPeerBlockValidator {
public RequiredBlocksPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long blockNumber,
final Hash hash,
final long chainHeightEstimationBuffer) {
super(protocolSchedule, metricsSystem, blockNumber, chainHeightEstimationBuffer);
super(
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
blockNumber,
chainHeightEstimationBuffer);
this.hash = hash;
}
public RequiredBlocksPeerValidator(
final ProtocolSchedule protocolSchedule,
final PeerTaskExecutor peerTaskExecutor,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final long blockNumber,
final Hash hash) {
this(
protocolSchedule, metricsSystem, blockNumber, hash, DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
protocolSchedule,
peerTaskExecutor,
synchronizerConfiguration,
metricsSystem,
blockNumber,
hash,
DEFAULT_CHAIN_HEIGHT_ESTIMATION_BUFFER);
}
@Override

View File

@@ -73,6 +73,7 @@ public abstract class AbstractSyncTargetManager {
ethContext,
bestPeer,
config.getDownloaderHeaderRequestSize(),
config,
metricsSystem)
.run()
.handle(

View File

@@ -536,6 +536,7 @@ public class BlockPropagationManager implements UnverifiedForkchoiceListener {
RetryingGetBlockFromPeersTask.create(
protocolSchedule,
ethContext,
config,
metricsSystem,
Math.max(1, ethContext.getEthPeers().peerCount()),
maybeBlockHash,

View File

@@ -19,6 +19,10 @@ import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@@ -38,28 +42,32 @@ public class ChainHeadTracker {
private final EthContext ethContext;
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem;
public ChainHeadTracker(
final EthContext ethContext,
final ProtocolSchedule protocolSchedule,
final TrailingPeerLimiter trailingPeerLimiter,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) {
this.ethContext = ethContext;
this.protocolSchedule = protocolSchedule;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
}
public static void trackChainHeadForPeers(
final EthContext ethContext,
final ProtocolSchedule protocolSchedule,
final SynchronizerConfiguration synchronizerConfiguration,
final Blockchain blockchain,
final Supplier<TrailingPeerRequirements> trailingPeerRequirementsCalculator,
final MetricsSystem metricsSystem) {
final TrailingPeerLimiter trailingPeerLimiter =
new TrailingPeerLimiter(ethContext.getEthPeers(), trailingPeerRequirementsCalculator);
final ChainHeadTracker tracker =
new ChainHeadTracker(ethContext, protocolSchedule, trailingPeerLimiter, metricsSystem);
new ChainHeadTracker(
ethContext, protocolSchedule, synchronizerConfiguration, metricsSystem);
ethContext.getEthPeers().setChainHeadTracker(tracker);
blockchain.observeBlockAdded(trailingPeerLimiter);
}
@@ -69,33 +77,78 @@ public class ChainHeadTracker {
.setMessage("Requesting chain head info from {}...")
.addArgument(peer::getLoggableId)
.log();
final CompletableFuture<AbstractPeerTask.PeerTaskResult<List<BlockHeader>>>
bestHeaderFromPeerCompletableFuture = getBestHeaderFromPeerCompletableFuture(peer);
final CompletableFuture<BlockHeader> future = new CompletableFuture<>();
bestHeaderFromPeerCompletableFuture.whenComplete(
(peerResult, error) -> {
if (peerResult != null && !peerResult.getResult().isEmpty()) {
final BlockHeader chainHeadHeader = peerResult.getResult().get(0);
peer.chainState().update(chainHeadHeader);
future.complete(chainHeadHeader);
LOG.atDebug()
.setMessage("Retrieved chain head info {} from {}...")
.addArgument(
() -> chainHeadHeader.getNumber() + " (" + chainHeadHeader.getBlockHash() + ")")
.addArgument(peer::getLoggableId)
.log();
} else {
LOG.atDebug()
.setMessage("Failed to retrieve chain head info. Disconnecting {}... {}")
.addArgument(peer::getLoggableId)
.addArgument(error != null ? error : "Empty Response")
.log();
peer.disconnect(
DisconnectMessage.DisconnectReason.USELESS_PEER_FAILED_TO_RETRIEVE_CHAIN_HEAD);
future.complete(null);
}
});
return future;
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
Hash.wrap(peer.chainState().getBestBlock().getHash()),
0,
1,
0,
Direction.FORWARD,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().executeAgainstPeer(task, peer);
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS
&& taskResult.result().isPresent()) {
BlockHeader chainHeadHeader = taskResult.result().get().getFirst();
LOG.atDebug()
.setMessage("Retrieved chain head info {} from {}...")
.addArgument(
() ->
chainHeadHeader.getNumber()
+ " ("
+ chainHeadHeader.getBlockHash()
+ ")")
.addArgument(peer::getLoggableId)
.log();
return CompletableFuture.completedFuture(chainHeadHeader);
} else {
LOG.atDebug()
.setMessage("Failed to retrieve chain head info. Disconnecting {}... {}")
.addArgument(peer::getLoggableId)
.addArgument(taskResult.responseCode())
.log();
peer.disconnect(
DisconnectMessage.DisconnectReason
.USELESS_PEER_FAILED_TO_RETRIEVE_CHAIN_HEAD);
return CompletableFuture.completedFuture(null);
}
});
} else {
final CompletableFuture<AbstractPeerTask.PeerTaskResult<List<BlockHeader>>>
bestHeaderFromPeerCompletableFuture = getBestHeaderFromPeerCompletableFuture(peer);
final CompletableFuture<BlockHeader> future = new CompletableFuture<>();
bestHeaderFromPeerCompletableFuture.whenComplete(
(peerResult, error) -> {
if (peerResult != null && !peerResult.getResult().isEmpty()) {
final BlockHeader chainHeadHeader = peerResult.getResult().get(0);
peer.chainState().update(chainHeadHeader);
future.complete(chainHeadHeader);
LOG.atDebug()
.setMessage("Retrieved chain head info {} from {}...")
.addArgument(
() ->
chainHeadHeader.getNumber() + " (" + chainHeadHeader.getBlockHash() + ")")
.addArgument(peer::getLoggableId)
.log();
} else {
LOG.atDebug()
.setMessage("Failed to retrieve chain head info. Disconnecting {}... {}")
.addArgument(peer::getLoggableId)
.addArgument(error != null ? error : "Empty Response")
.log();
peer.disconnect(
DisconnectMessage.DisconnectReason.USELESS_PEER_FAILED_TO_RETRIEVE_CHAIN_HEAD);
future.complete(null);
}
});
return future;
}
}
public CompletableFuture<AbstractPeerTask.PeerTaskResult<List<BlockHeader>>>

View File

@@ -99,6 +99,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
ChainHeadTracker.trackChainHeadForPeers(
ethContext,
protocolSchedule,
syncConfig,
protocolContext.getBlockchain(),
this::calculateTrailingPeerRequirements,
metricsSystem);
@@ -149,7 +150,6 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext,
metricsSystem,
ethContext,
peerTaskExecutor,
worldStateStorageCoordinator,
syncState,
clock,
@@ -166,7 +166,6 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext,
metricsSystem,
ethContext,
peerTaskExecutor,
worldStateStorageCoordinator,
syncState,
clock,
@@ -183,7 +182,6 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi
protocolContext,
metricsSystem,
ethContext,
peerTaskExecutor,
worldStateStorageCoordinator,
syncState,
clock,

View File

@@ -20,6 +20,9 @@ import static java.util.concurrent.CompletableFuture.completedFuture;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask;
import org.hyperledger.besu.ethereum.eth.sync.range.RangeHeaders;
@@ -44,6 +47,7 @@ public class DownloadHeadersStep
private final ProtocolContext protocolContext;
private final EthContext ethContext;
private final ValidationPolicy validationPolicy;
private final SynchronizerConfiguration synchronizerConfiguration;
private final int headerRequestSize;
private final MetricsSystem metricsSystem;
@@ -52,12 +56,14 @@ public class DownloadHeadersStep
final ProtocolContext protocolContext,
final EthContext ethContext,
final ValidationPolicy validationPolicy,
final SynchronizerConfiguration synchronizerConfiguration,
final int headerRequestSize,
final MetricsSystem metricsSystem) {
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
this.ethContext = ethContext;
this.validationPolicy = validationPolicy;
this.synchronizerConfiguration = synchronizerConfiguration;
this.headerRequestSize = headerRequestSize;
this.metricsSystem = metricsSystem;
}
@@ -85,6 +91,7 @@ public class DownloadHeadersStep
protocolSchedule,
protocolContext,
ethContext,
synchronizerConfiguration,
range.getEnd(),
range.getSegmentLengthExclusive(),
validationPolicy,
@@ -92,15 +99,39 @@ public class DownloadHeadersStep
.run();
} else {
LOG.debug("Downloading headers starting from {}", range.getStart().getNumber());
return GetHeadersFromPeerByHashTask.startingAtHash(
protocolSchedule,
ethContext,
range.getStart().getHash(),
range.getStart().getNumber(),
headerRequestSize,
metricsSystem)
.run()
.thenApply(PeerTaskResult::getResult);
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
range.getStart().getHash(),
range.getStart().getNumber(),
headerRequestSize,
0,
GetHeadersFromPeerTask.Direction.FORWARD,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().execute(task);
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
return CompletableFuture.failedFuture(
new RuntimeException("Unable to download headers for range " + range));
}
return CompletableFuture.completedFuture(taskResult.result().get());
});
} else {
return GetHeadersFromPeerByHashTask.startingAtHash(
protocolSchedule,
ethContext,
range.getStart().getHash(),
range.getStart().getNumber(),
headerRequestSize,
metricsSystem)
.run()
.thenApply(PeerTaskResult::getResult);
}
}
}

View File

@@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@@ -52,6 +53,7 @@ public class BackwardSyncContext {
protected final ProtocolContext protocolContext;
private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem;
private final SyncState syncState;
private final AtomicReference<Status> currentBackwardSyncStatus = new AtomicReference<>();
@@ -65,6 +67,7 @@ public class BackwardSyncContext {
public BackwardSyncContext(
final ProtocolContext protocolContext,
final ProtocolSchedule protocolSchedule,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final EthContext ethContext,
final SyncState syncState,
@@ -72,6 +75,7 @@ public class BackwardSyncContext {
this(
protocolContext,
protocolSchedule,
synchronizerConfiguration,
metricsSystem,
ethContext,
syncState,
@@ -83,6 +87,7 @@ public class BackwardSyncContext {
public BackwardSyncContext(
final ProtocolContext protocolContext,
final ProtocolSchedule protocolSchedule,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem,
final EthContext ethContext,
final SyncState syncState,
@@ -93,6 +98,7 @@ public class BackwardSyncContext {
this.protocolContext = protocolContext;
this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
this.syncState = syncState;
this.backwardChain = backwardChain;
@@ -431,6 +437,10 @@ public class BackwardSyncContext {
}
}
public SynchronizerConfiguration getSynchronizerConfiguration() {
return synchronizerConfiguration;
}
class Status {
private final CompletableFuture<Void> currentFuture;
private final long initialChainHeight;

View File

@@ -16,6 +16,10 @@ package org.hyperledger.besu.ethereum.eth.sync.backwardsync;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.manager.task.RetryingGetHeadersEndingAtFromPeerByHashTask;
import java.util.List;
@@ -69,29 +73,57 @@ public class BackwardSyncStep {
final int batchSize = context.getBatchSize();
LOG.trace("Requesting headers for hash {}, with batch size {}", hash, batchSize);
final RetryingGetHeadersEndingAtFromPeerByHashTask
retryingGetHeadersEndingAtFromPeerByHashTask =
RetryingGetHeadersEndingAtFromPeerByHashTask.endingAtHash(
context.getProtocolSchedule(),
context.getEthContext(),
hash,
0,
batchSize,
context.getMetricsSystem(),
context.getEthContext().getEthPeers().peerCount());
return context
.getEthContext()
.getScheduler()
.scheduleSyncWorkerTask(retryingGetHeadersEndingAtFromPeerByHashTask::run)
.thenApply(
blockHeaders -> {
LOG.atDebug()
.setMessage("Got headers {} -> {}")
.addArgument(blockHeaders.get(0)::getNumber)
.addArgument(blockHeaders.get(blockHeaders.size() - 1)::getNumber)
.log();
return blockHeaders;
});
CompletableFuture<List<BlockHeader>> headersResult;
if (context.getSynchronizerConfiguration().isPeerTaskSystemEnabled()) {
headersResult =
context
.getEthContext()
.getScheduler()
.scheduleSyncWorkerTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
hash,
0,
batchSize,
0,
Direction.REVERSE,
context.getEthContext().getEthPeers().peerCount(),
context.getProtocolSchedule());
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
context.getEthContext().getPeerTaskExecutor().execute(task);
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
throw new RuntimeException("Unable to retrieve headers");
}
return CompletableFuture.completedFuture(taskResult.result().get());
});
} else {
final RetryingGetHeadersEndingAtFromPeerByHashTask
retryingGetHeadersEndingAtFromPeerByHashTask =
RetryingGetHeadersEndingAtFromPeerByHashTask.endingAtHash(
context.getProtocolSchedule(),
context.getEthContext(),
hash,
0,
batchSize,
context.getMetricsSystem(),
context.getEthContext().getEthPeers().peerCount());
headersResult =
context
.getEthContext()
.getScheduler()
.scheduleSyncWorkerTask(retryingGetHeadersEndingAtFromPeerByHashTask::run);
}
return headersResult.thenApply(
blockHeaders -> {
LOG.atDebug()
.setMessage("Got headers {} -> {}")
.addArgument(blockHeaders.get(0)::getNumber)
.addArgument(blockHeaders.get(blockHeaders.size() - 1)::getNumber)
.log();
return blockHeaders;
});
}
@VisibleForTesting

View File

@@ -50,6 +50,7 @@ public class SyncStepStep {
RetryingGetBlockFromPeersTask.create(
context.getProtocolSchedule(),
context.getEthContext(),
context.getSynchronizerConfiguration(),
context.getMetricsSystem(),
context.getEthContext().getEthPeers().peerCount(),
Optional.of(targetHash),

View File

@@ -20,7 +20,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
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;
@@ -40,7 +39,6 @@ public class CheckpointDownloadBlockStep {
private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext;
private final PeerTaskExecutor peerTaskExecutor;
private final Checkpoint checkpoint;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem;
@@ -48,13 +46,11 @@ public class CheckpointDownloadBlockStep {
public CheckpointDownloadBlockStep(
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final Checkpoint checkpoint,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) {
this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.checkpoint = checkpoint;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
@@ -65,6 +61,7 @@ public class CheckpointDownloadBlockStep {
GetBlockFromPeerTask.create(
protocolSchedule,
ethContext,
synchronizerConfiguration,
Optional.of(hash),
checkpoint.blockNumber(),
metricsSystem);
@@ -85,7 +82,7 @@ public class CheckpointDownloadBlockStep {
GetReceiptsFromPeerTask task =
new GetReceiptsFromPeerTask(List.of(block.getHeader()), protocolSchedule);
PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> executorResult =
peerTaskExecutor.execute(task);
ethContext.getPeerTaskExecutor().execute(task);
if (executorResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS) {
List<TransactionReceipt> transactionReceipts =

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,6 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
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.fastsync.FastSyncDownloadPipelineFactory;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState;
@@ -41,17 +40,9 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final FastSyncState fastSyncState,
final MetricsSystem metricsSystem) {
super(
syncConfig,
protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
fastSyncState,
metricsSystem);
super(syncConfig, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem);
}
@Override
@@ -86,7 +77,7 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel
final CheckpointDownloadBlockStep checkPointDownloadBlockStep =
new CheckpointDownloadBlockStep(
protocolSchedule, ethContext, peerTaskExecutor, checkpoint, syncConfig, metricsSystem);
protocolSchedule, ethContext, checkpoint, syncConfig, metricsSystem);
return PipelineBuilder.createPipelineFrom(
"fetchCheckpoints",

View File

@@ -22,7 +22,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
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;
@@ -42,19 +41,16 @@ public class DownloadReceiptsStep
private final ProtocolSchedule protocolSchedule;
private final EthContext ethContext;
private final PeerTaskExecutor peerTaskExecutor;
private final SynchronizerConfiguration synchronizerConfiguration;
private 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.peerTaskExecutor = peerTaskExecutor;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
}
@@ -81,7 +77,7 @@ public class DownloadReceiptsStep
do {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(headers, protocolSchedule);
PeerTaskExecutorResult<Map<BlockHeader, List<TransactionReceipt>>> getReceiptsResult =
peerTaskExecutor.execute(task);
ethContext.getPeerTaskExecutor().execute(task);
if (getReceiptsResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS
&& getReceiptsResult.result().isPresent()) {
Map<BlockHeader, List<TransactionReceipt>> taskResult = getReceiptsResult.result().get();

View File

@@ -18,8 +18,12 @@ import static java.util.concurrent.CompletableFuture.completedFuture;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.NoAvailablePeersException;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeersTask;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
@@ -34,6 +38,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
@@ -49,7 +54,6 @@ public class FastSyncActions {
protected final ProtocolSchedule protocolSchedule;
protected final ProtocolContext protocolContext;
protected final EthContext ethContext;
protected final PeerTaskExecutor peerTaskExecutor;
protected final SyncState syncState;
protected final PivotBlockSelector pivotBlockSelector;
protected final MetricsSystem metricsSystem;
@@ -62,7 +66,6 @@ public class FastSyncActions {
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final SyncState syncState,
final PivotBlockSelector pivotBlockSelector,
final MetricsSystem metricsSystem) {
@@ -71,7 +74,6 @@ public class FastSyncActions {
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.syncState = syncState;
this.pivotBlockSelector = pivotBlockSelector;
this.metricsSystem = metricsSystem;
@@ -103,7 +105,6 @@ public class FastSyncActions {
}
private CompletableFuture<FastSyncState> selectNewPivotBlock() {
return pivotBlockSelector
.selectNewPivotBlock()
.map(CompletableFuture::completedFuture)
@@ -130,7 +131,7 @@ public class FastSyncActions {
private CompletableFuture<FastSyncState> internalDownloadPivotBlockHeader(
final FastSyncState currentState) {
if (currentState.hasPivotBlockHeader()) {
LOG.debug("Initial sync state {} already contains the block header", currentState);
LOG.info("Initial sync state {} already contains the block header", currentState);
return completedFuture(currentState);
}
@@ -146,6 +147,7 @@ public class FastSyncActions {
protocolSchedule,
ethContext,
metricsSystem,
syncConfig,
currentState.getPivotBlockNumber().getAsLong(),
syncConfig.getSyncMinimumPeerCount(),
syncConfig.getSyncPivotDistance())
@@ -168,7 +170,6 @@ public class FastSyncActions {
protocolSchedule,
protocolContext,
ethContext,
peerTaskExecutor,
syncState,
metricsSystem,
currentState,
@@ -177,13 +178,56 @@ public class FastSyncActions {
private CompletableFuture<FastSyncState> downloadPivotBlockHeader(final Hash hash) {
LOG.debug("Downloading pivot block header by hash {}", hash);
return RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule,
ethContext,
hash,
pivotBlockSelector.getMinRequiredBlockNumber(),
metricsSystem)
.getHeader()
CompletableFuture<BlockHeader> blockHeaderFuture;
if (syncConfig.isPeerTaskSystemEnabled()) {
blockHeaderFuture =
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
hash,
pivotBlockSelector.getMinRequiredBlockNumber(),
1,
0,
GetHeadersFromPeerTask.Direction.FORWARD,
ethContext.getEthPeers().peerCount(),
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().execute(task);
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.NO_PEER_AVAILABLE
|| taskResult.responseCode()
== PeerTaskExecutorResponseCode.PEER_DISCONNECTED) {
LOG.error(
"Failed to download pivot block header. Response Code was {}",
taskResult.responseCode());
return CompletableFuture.failedFuture(new NoAvailablePeersException());
} else if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
LOG.error(
"Failed to download pivot block header. Response Code was {}",
taskResult.responseCode());
return CompletableFuture.failedFuture(
new RuntimeException(
"Failed to download pivot block header. Response Code was "
+ taskResult.responseCode()));
} else {
return CompletableFuture.completedFuture(
taskResult.result().get().getFirst());
}
});
} else {
blockHeaderFuture =
RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule,
ethContext,
hash,
pivotBlockSelector.getMinRequiredBlockNumber(),
metricsSystem)
.getHeader();
}
return blockHeaderFuture
.whenComplete(
(blockHeader, throwable) -> {
if (throwable != null) {

View File

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

View File

@@ -26,7 +26,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.DownloadHeadersStep;
import org.hyperledger.besu.ethereum.eth.sync.DownloadPipelineFactory;
@@ -58,7 +57,6 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
protected final ProtocolSchedule protocolSchedule;
protected final ProtocolContext protocolContext;
protected final EthContext ethContext;
protected final PeerTaskExecutor peerTaskExecutor;
protected final FastSyncState fastSyncState;
protected final MetricsSystem metricsSystem;
protected final FastSyncValidationPolicy attachedValidationPolicy;
@@ -70,14 +68,12 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final PeerTaskExecutor peerTaskExecutor,
final FastSyncState fastSyncState,
final MetricsSystem metricsSystem) {
this.syncConfig = syncConfig;
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
this.ethContext = ethContext;
this.peerTaskExecutor = peerTaskExecutor;
this.fastSyncState = fastSyncState;
this.metricsSystem = metricsSystem;
final LabelledMetric<Counter> fastSyncValidationCounter =
@@ -138,6 +134,7 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
protocolContext,
ethContext,
detachedValidationPolicy,
syncConfig,
headerRequestSize,
metricsSystem);
final RangeHeadersValidationStep validateHeadersJoinUpStep =
@@ -145,8 +142,7 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory
final DownloadBodiesStep downloadBodiesStep =
new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem);
final DownloadReceiptsStep downloadReceiptsStep =
new DownloadReceiptsStep(
protocolSchedule, ethContext, peerTaskExecutor, syncConfig, metricsSystem);
new DownloadReceiptsStep(protocolSchedule, ethContext, syncConfig, metricsSystem);
final ImportBlocksStep importBlockStep =
new ImportBlocksStep(
protocolSchedule,

View File

@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import static org.hyperledger.besu.util.FutureUtils.exceptionallyCompose;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.MaxRetriesReachedException;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.NoAvailablePeersException;
import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException;
@@ -132,6 +133,12 @@ public class FastSyncDownloader<REQUEST> {
LOG.debug(
"A download operation reached the max number of retries, re-pivoting to newer block");
return start(FastSyncState.EMPTY_SYNC_STATE);
} else if (rootCause instanceof NoAvailablePeersException) {
LOG.debug(
"No peers available for sync. Restarting sync in {} seconds",
FAST_SYNC_RETRY_DELAY.getSeconds());
return fastSyncActions.scheduleFutureTask(
() -> start(FastSyncState.EMPTY_SYNC_STATE), FAST_SYNC_RETRY_DELAY);
} else {
LOG.error(
"Encountered an unexpected error during sync. Restarting sync in "

View File

@@ -17,8 +17,12 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask;
import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByNumberTask;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -26,8 +30,12 @@ import org.hyperledger.besu.util.FutureUtils;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@@ -52,6 +60,7 @@ class PivotBlockConfirmer {
private final EthContext ethContext;
private final MetricsSystem metricsSystem;
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
// The number of peers we need to query to confirm our pivot block
private final int numberOfPeersToQuery;
@@ -64,6 +73,7 @@ class PivotBlockConfirmer {
private final Collection<CompletableFuture<?>> runningQueries = new ConcurrentLinkedQueue<>();
private final Map<Bytes, RetryingGetHeaderFromPeerByNumberTask> pivotBlockQueriesByPeerId =
new ConcurrentHashMap<>();
private final Set<Bytes> peerIdsUsed = Collections.synchronizedSet(new HashSet<>());
private final Map<BlockHeader, AtomicInteger> pivotBlockVotes = new ConcurrentHashMap<>();
private final AtomicBoolean isStarted = new AtomicBoolean(false);
@@ -73,12 +83,14 @@ class PivotBlockConfirmer {
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final MetricsSystem metricsSystem,
final SynchronizerConfiguration synchronizerConfiguration,
final long pivotBlockNumber,
final int numberOfPeersToQuery,
final int numberOfRetriesPerPeer) {
this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext;
this.metricsSystem = metricsSystem;
this.synchronizerConfiguration = synchronizerConfiguration;
this.pivotBlockNumber = pivotBlockNumber;
this.numberOfPeersToQuery = numberOfPeersToQuery;
this.numberOfRetriesPerPeer = numberOfRetriesPerPeer;
@@ -97,8 +109,14 @@ class PivotBlockConfirmer {
private void queryPeers(final long blockNumber) {
synchronized (runningQueries) {
for (int i = 0; i < numberOfPeersToQuery; i++) {
final CompletableFuture<?> query =
executePivotQuery(blockNumber).whenComplete(this::processReceivedHeader);
final CompletableFuture<?> query;
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
query =
executePivotQueryWithPeerTaskSystem(blockNumber)
.whenComplete(this::processReceivedHeader);
} else {
query = executePivotQuery(blockNumber).whenComplete(this::processReceivedHeader);
}
runningQueries.add(query);
}
}
@@ -178,6 +196,58 @@ class PivotBlockConfirmer {
return pivotHeaderFuture;
}
private CompletableFuture<BlockHeader> executePivotQueryWithPeerTaskSystem(
final long blockNumber) {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
blockNumber, 1, 0, GetHeadersFromPeerTask.Direction.FORWARD, protocolSchedule);
Optional<EthPeer> maybeEthPeer;
final EthPeer ethPeer;
try {
do {
if (isCancelled.get()) {
return CompletableFuture.failedFuture(
new CancellationException("Pivot block confirmation has been cancelled"));
}
maybeEthPeer =
ethContext
.getEthPeers()
.getPeer(
(p) ->
task.getPeerRequirementFilter().test(p)
&& !peerIdsUsed.contains(p.nodeId()));
} while (maybeEthPeer.isEmpty() && waitForPeer());
ethPeer = maybeEthPeer.get();
peerIdsUsed.add(ethPeer.nodeId());
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
}
return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().executeAgainstPeer(task, ethPeer);
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.INTERNAL_SERVER_ERROR) {
// something is probably wrong with the request, so we won't retry as below
return CompletableFuture.failedFuture(
new RuntimeException("Unexpected internal issue"));
} else if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
// recursively call executePivotQueryWithPeerTaskSystem to retry with a different
// peer.
return executePivotQueryWithPeerTaskSystem(blockNumber);
}
return CompletableFuture.completedFuture(taskResult.result().get().getFirst());
});
}
private boolean waitForPeer() throws InterruptedException {
Thread.sleep(Duration.ofSeconds(5));
return true;
}
private Optional<RetryingGetHeaderFromPeerByNumberTask> createPivotQuery(final long blockNumber) {
return ethContext
.getEthPeers()

View File

@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.util.ExceptionUtils;
@@ -46,6 +47,7 @@ public class PivotBlockRetriever {
private final EthContext ethContext;
private final MetricsSystem metricsSystem;
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
// The number of peers we need to query to confirm our pivot block
private final int peersToQuery;
@@ -66,6 +68,7 @@ public class PivotBlockRetriever {
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final MetricsSystem metricsSystem,
final SynchronizerConfiguration synchronizerConfiguration,
final long pivotBlockNumber,
final int peersToQuery,
final long pivotBlockNumberResetDelta,
@@ -73,6 +76,7 @@ public class PivotBlockRetriever {
this.protocolSchedule = protocolSchedule;
this.ethContext = ethContext;
this.metricsSystem = metricsSystem;
this.synchronizerConfiguration = synchronizerConfiguration;
this.pivotBlockNumber = new AtomicLong(pivotBlockNumber);
this.peersToQuery = peersToQuery;
this.pivotBlockNumberResetDelta = pivotBlockNumberResetDelta;
@@ -83,6 +87,7 @@ public class PivotBlockRetriever {
final ProtocolSchedule protocolSchedule,
final EthContext ethContext,
final MetricsSystem metricsSystem,
final SynchronizerConfiguration synchronizerConfiguration,
final long pivotBlockNumber,
final int peersToQuery,
final long pivotBlockNumberResetDelta) {
@@ -90,6 +95,7 @@ public class PivotBlockRetriever {
protocolSchedule,
ethContext,
metricsSystem,
synchronizerConfiguration,
pivotBlockNumber,
peersToQuery,
pivotBlockNumberResetDelta,
@@ -111,6 +117,7 @@ public class PivotBlockRetriever {
protocolSchedule,
ethContext,
metricsSystem,
synchronizerConfiguration,
pivotBlockNumber.get(),
peersToQuery,
MAX_QUERY_RETRIES_PER_PEER);

View File

@@ -20,12 +20,17 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeersTask;
import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByHashTask;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -42,6 +47,7 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
private final EthContext ethContext;
private final MetricsSystem metricsSystem;
private final GenesisConfigOptions genesisConfig;
private final SynchronizerConfiguration synchronizerConfiguration;
private final Supplier<Optional<ForkchoiceEvent>> forkchoiceStateSupplier;
private final Runnable cleanupAction;
@@ -55,6 +61,7 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
final EthContext ethContext,
final MetricsSystem metricsSystem,
final GenesisConfigOptions genesisConfig,
final SynchronizerConfiguration synchronizerConfiguration,
final Supplier<Optional<ForkchoiceEvent>> forkchoiceStateSupplier,
final Runnable cleanupAction) {
this.protocolContext = protocolContext;
@@ -62,6 +69,7 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
this.ethContext = ethContext;
this.metricsSystem = metricsSystem;
this.genesisConfig = genesisConfig;
this.synchronizerConfiguration = synchronizerConfiguration;
this.forkchoiceStateSupplier = forkchoiceStateSupplier;
this.cleanupAction = cleanupAction;
}
@@ -142,20 +150,48 @@ public class PivotSelectorFromSafeBlock implements PivotBlockSelector {
}
private CompletableFuture<BlockHeader> downloadBlockHeader(final Hash hash) {
return RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule, ethContext, hash, 0, metricsSystem)
.getHeader()
.whenComplete(
(blockHeader, throwable) -> {
if (throwable != null) {
LOG.debug("Error downloading block header by hash {}", hash);
} else {
LOG.atDebug()
.setMessage("Successfully downloaded pivot block header by hash {}")
.addArgument(blockHeader::toLogString)
.log();
}
});
CompletableFuture<BlockHeader> resultFuture;
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
resultFuture =
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
hash,
0,
1,
0,
GetHeadersFromPeerTask.Direction.FORWARD,
ethContext.getEthPeers().peerCount(),
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().execute(task);
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
return CompletableFuture.failedFuture(
new RuntimeException("Unable to retrieve header"));
}
return CompletableFuture.completedFuture(taskResult.result().get().getFirst());
});
} else {
resultFuture =
RetryingGetHeaderFromPeerByHashTask.byHash(
protocolSchedule, ethContext, hash, 0, metricsSystem)
.getHeader();
}
return resultFuture.whenComplete(
(blockHeader, throwable) -> {
if (throwable != null) {
LOG.debug("Error downloading block header by hash {}", hash);
} else {
LOG.atDebug()
.setMessage("Successfully downloaded pivot block header by hash {}")
.addArgument(blockHeader::toLogString)
.log();
}
});
}
private CompletableFuture<Void> waitForPeers(final int count) {

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.eth.sync.fastsync;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.hyperledger.besu.ethereum.eth.sync.fastsync.PivotBlockRetriever.MAX_QUERY_RETRIES_PER_PEER;
import static org.hyperledger.besu.util.log.LogUtil.throttledLog;
import org.hyperledger.besu.ethereum.ProtocolContext;
@@ -23,6 +22,9 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.AbstractSyncTargetManager;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByNumberTask;
@@ -120,18 +122,51 @@ public class SyncTargetManager extends AbstractSyncTargetManager {
private CompletableFuture<Optional<EthPeer>> confirmPivotBlockHeader(final EthPeer bestPeer) {
final BlockHeader pivotBlockHeader = fastSyncState.getPivotBlockHeader().get();
final RetryingGetHeaderFromPeerByNumberTask task =
RetryingGetHeaderFromPeerByNumberTask.forSingleNumber(
protocolSchedule,
ethContext,
metricsSystem,
pivotBlockHeader.getNumber(),
MAX_QUERY_RETRIES_PER_PEER);
task.assignPeer(bestPeer);
return ethContext
.getScheduler()
// Task is a retrying task. Make sure that the timeout is long enough to allow for retries.
.timeout(task, Duration.ofSeconds(MAX_QUERY_RETRIES_PER_PEER * SECONDS_PER_REQUEST + 2))
CompletableFuture<List<BlockHeader>> headersFuture;
if (config.isPeerTaskSystemEnabled()) {
headersFuture =
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
pivotBlockHeader.getNumber(),
1,
0,
GetHeadersFromPeerTask.Direction.FORWARD,
PivotBlockRetriever.MAX_QUERY_RETRIES_PER_PEER,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().executeAgainstPeer(task, bestPeer);
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
return CompletableFuture.failedFuture(
new RuntimeException("Unable to retrieve requested header from peer"));
}
return CompletableFuture.completedFuture(taskResult.result().get());
});
} else {
final RetryingGetHeaderFromPeerByNumberTask task =
RetryingGetHeaderFromPeerByNumberTask.forSingleNumber(
protocolSchedule,
ethContext,
metricsSystem,
pivotBlockHeader.getNumber(),
PivotBlockRetriever.MAX_QUERY_RETRIES_PER_PEER);
task.assignPeer(bestPeer);
headersFuture =
ethContext
.getScheduler()
// Task is a retrying task. Make sure that the timeout is long enough to allow for
// retries.
.timeout(
task,
Duration.ofSeconds(
PivotBlockRetriever.MAX_QUERY_RETRIES_PER_PEER * SECONDS_PER_REQUEST + 2));
}
return headersFuture
.thenCompose(
result -> {
if (peerHasDifferentPivotBlock(result)) {

View File

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

View File

@@ -99,6 +99,7 @@ public class FullSyncDownloadPipelineFactory implements DownloadPipelineFactory
protocolContext,
ethContext,
detachedValidationPolicy,
syncConfig,
headerRequestSize,
metricsSystem);
final RangeHeadersValidationStep validateHeadersJoinUpStep =

View File

@@ -21,6 +21,10 @@ import static java.util.concurrent.CompletableFuture.completedFuture;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@@ -116,31 +120,64 @@ public class RangeHeadersFetcher {
.addArgument(referenceHeader.getNumber())
.addArgument(skip)
.log();
return GetHeadersFromPeerByHashTask.startingAtHash(
protocolSchedule,
ethContext,
referenceHeader.getHash(),
referenceHeader.getNumber(),
// + 1 because lastHeader will be returned as well.
headerCount + 1,
skip,
metricsSystem)
.assignPeer(peer)
.run()
.thenApply(PeerTaskResult::getResult)
.thenApply(
headers -> {
if (headers.size() < headerCount) {
LOG.atTrace()
.setMessage(
"Peer {} returned fewer headers than requested. Expected: {}, Actual: {}")
.addArgument(peer)
.addArgument(headerCount)
.addArgument(headers.size())
.log();
}
return stripExistingRangeHeaders(referenceHeader, headers);
});
CompletableFuture<List<BlockHeader>> headersFuture;
if (syncConfig.isPeerTaskSystemEnabled()) {
headersFuture =
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
referenceHeader.getHash(),
referenceHeader.getNumber(),
// + 1 because lastHeader will be returned as well.
headerCount + 1,
skip,
Direction.FORWARD,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
ethContext.getPeerTaskExecutor().executeAgainstPeer(task, peer);
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
LOG.warn(
"Unsuccessfully used peer task system to fetch headers. Response code was {}",
taskResult.responseCode());
return CompletableFuture.failedFuture(
new RuntimeException(
"Unable to retrieve headers. Response code was "
+ taskResult.responseCode()));
}
return CompletableFuture.completedFuture(taskResult.result().get());
});
} else {
headersFuture =
GetHeadersFromPeerByHashTask.startingAtHash(
protocolSchedule,
ethContext,
referenceHeader.getHash(),
referenceHeader.getNumber(),
// + 1 because lastHeader will be returned as well.
headerCount + 1,
skip,
metricsSystem)
.assignPeer(peer)
.run()
.thenApply(PeerTaskResult::getResult);
}
return headersFuture.thenApply(
headers -> {
if (headers.size() < headerCount) {
LOG.atTrace()
.setMessage(
"Peer {} returned fewer headers than requested. Expected: {}, Actual: {}")
.addArgument(peer)
.addArgument(headerCount)
.addArgument(headers.size())
.log();
}
return stripExistingRangeHeaders(referenceHeader, headers);
});
}
private List<BlockHeader> stripExistingRangeHeaders(

View File

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

View File

@@ -18,9 +18,15 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.PeerDisconnectedException;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractEthTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByNumberTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.util.BlockchainUtil;
import org.hyperledger.besu.plugin.services.MetricsSystem;
@@ -46,6 +52,7 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
private final ProtocolContext protocolContext;
private final EthPeer peer;
private final int headerRequestSize;
private final SynchronizerConfiguration synchronizerConfiguration;
private final MetricsSystem metricsSystem;
private long maximumPossibleCommonAncestorNumber;
@@ -59,6 +66,7 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
final EthContext ethContext,
final EthPeer peer,
final int headerRequestSize,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) {
super(metricsSystem);
this.protocolSchedule = protocolSchedule;
@@ -66,6 +74,7 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
this.protocolContext = protocolContext;
this.peer = peer;
this.headerRequestSize = headerRequestSize;
this.synchronizerConfiguration = synchronizerConfiguration;
this.metricsSystem = metricsSystem;
maximumPossibleCommonAncestorNumber =
@@ -83,9 +92,16 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
final EthContext ethContext,
final EthPeer peer,
final int headerRequestSize,
final SynchronizerConfiguration synchronizerConfiguration,
final MetricsSystem metricsSystem) {
return new DetermineCommonAncestorTask(
protocolSchedule, protocolContext, ethContext, peer, headerRequestSize, metricsSystem);
protocolSchedule,
protocolContext,
ethContext,
peer,
headerRequestSize,
synchronizerConfiguration,
metricsSystem);
}
@Override
@@ -100,16 +116,50 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
result.completeExceptionally(new IllegalStateException("No common ancestor."));
return;
}
requestHeaders()
.thenCompose(this::processHeaders)
.whenComplete(
(peerResult, error) -> {
if (error != null) {
result.completeExceptionally(error);
} else if (!result.isDone()) {
executeTaskTimed();
}
});
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
do {
PeerTaskExecutorResult<List<BlockHeader>> taskResult =
requestHeadersUsingPeerTaskSystem();
if (taskResult.responseCode() == PeerTaskExecutorResponseCode.PEER_DISCONNECTED) {
result.completeExceptionally(new PeerDisconnectedException(peer));
continue;
} else if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
result.completeExceptionally(
new RuntimeException(
"Peer failed to successfully return requested block headers"));
continue;
}
taskResult.ethPeer().ifPresent((peer) -> taskResult.result().get().getFirst());
processHeaders(taskResult.result().get());
if (maximumPossibleCommonAncestorNumber == minimumPossibleCommonAncestorNumber) {
// Bingo, we found our common ancestor.
result.complete(commonAncestorCandidate);
} else if (maximumPossibleCommonAncestorNumber < BlockHeader.GENESIS_BLOCK_NUMBER
&& !result.isDone()) {
result.completeExceptionally(new IllegalStateException("No common ancestor."));
}
} while (!result.isDone());
});
} else {
requestHeaders()
.thenApply(AbstractPeerTask.PeerTaskResult::getResult)
.thenCompose(this::processHeaders)
.whenComplete(
(peerResult, error) -> {
if (error != null) {
result.completeExceptionally(error);
} else if (!result.isDone()) {
executeTaskTimed();
}
});
}
}
@VisibleForTesting
@@ -136,6 +186,26 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
.run());
}
PeerTaskExecutorResult<List<BlockHeader>> requestHeadersUsingPeerTaskSystem() {
final long range = maximumPossibleCommonAncestorNumber - minimumPossibleCommonAncestorNumber;
final int skipInterval = initialQuery ? 0 : calculateSkipInterval(range, headerRequestSize);
final int count =
initialQuery ? headerRequestSize : calculateCount((double) range, skipInterval);
LOG.debug(
"Searching for common ancestor with {} between {} and {}",
peer,
minimumPossibleCommonAncestorNumber,
maximumPossibleCommonAncestorNumber);
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
maximumPossibleCommonAncestorNumber,
count,
skipInterval,
Direction.REVERSE,
protocolSchedule);
return ethContext.getPeerTaskExecutor().executeAgainstPeer(task, peer);
}
/**
* In the case where the remote chain contains 100 blocks, the initial count work out to 11, and
* the skip interval would be 9. This would yield the headers (0, 10, 20, 30, 40, 50, 60, 70, 80,
@@ -151,10 +221,8 @@ public class DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> {
return Math.toIntExact((long) Math.ceil(range / (skipInterval + 1)) + 1);
}
private CompletableFuture<Void> processHeaders(
final AbstractPeerTask.PeerTaskResult<List<BlockHeader>> headersResult) {
private CompletableFuture<Void> processHeaders(final List<BlockHeader> headers) {
initialQuery = false;
final List<BlockHeader> headers = headersResult.getResult();
if (headers.isEmpty()) {
// Nothing to do
return CompletableFuture.completedFuture(null);

View File

@@ -25,11 +25,15 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthContext;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractGetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractRetryingPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetBodiesFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.task.GetHeadersFromPeerByHashTask;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy;
import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException;
import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator;
@@ -61,6 +65,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
private final EthContext ethContext;
private final ProtocolContext protocolContext;
private final ProtocolSchedule protocolSchedule;
private final SynchronizerConfiguration synchronizerConfiguration;
private final BlockHeader[] headers;
private final BlockHeader referenceHeader;
@@ -75,6 +80,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final BlockHeader referenceHeader,
final int segmentLength,
final int maxRetries,
@@ -84,6 +90,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
this.ethContext = ethContext;
this.synchronizerConfiguration = synchronizerConfiguration;
this.referenceHeader = referenceHeader;
this.segmentLength = segmentLength;
this.validationPolicy = validationPolicy;
@@ -99,6 +106,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final BlockHeader referenceHeader,
final int segmentLength,
final int maxRetries,
@@ -108,6 +116,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
protocolSchedule,
protocolContext,
ethContext,
synchronizerConfiguration,
referenceHeader,
segmentLength,
maxRetries,
@@ -119,6 +128,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final EthContext ethContext,
final SynchronizerConfiguration synchronizerConfiguration,
final BlockHeader referenceHeader,
final int segmentLength,
final ValidationPolicy validationPolicy,
@@ -127,6 +137,7 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
protocolSchedule,
protocolContext,
ethContext,
synchronizerConfiguration,
referenceHeader,
segmentLength,
DEFAULT_RETRIES,
@@ -139,9 +150,15 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
final Optional<EthPeer> assignedPeer) {
LOG.debug(
"Downloading headers from {} to {}.", startingBlockNumber, referenceHeader.getNumber());
final CompletableFuture<List<BlockHeader>> task =
downloadHeaders(assignedPeer).thenCompose(this::processHeaders);
return task.whenComplete(
final CompletableFuture<List<BlockHeader>> headersFuture;
if (synchronizerConfiguration.isPeerTaskSystemEnabled()) {
headersFuture =
downloadHeadersUsingPeerTaskSystem(assignedPeer)
.thenCompose(this::processHeadersUsingPeerTask);
} else {
headersFuture = downloadHeaders(assignedPeer).thenCompose(this::processHeaders);
}
return headersFuture.whenComplete(
(r, t) -> {
// We're done if we've filled all requested headers
if (lastFilledHeaderIndex == 0) {
@@ -179,75 +196,129 @@ public class DownloadHeaderSequenceTask extends AbstractRetryingPeerTask<List<Bl
});
}
private CompletableFuture<PeerTaskExecutorResult<List<BlockHeader>>>
downloadHeadersUsingPeerTaskSystem(final Optional<EthPeer> ethPeer) {
return ethContext
.getScheduler()
.scheduleServiceTask(
() -> {
// Figure out parameters for our headers request
final boolean partiallyFilled = lastFilledHeaderIndex < segmentLength;
final BlockHeader referenceHeaderForNextRequest =
partiallyFilled ? headers[lastFilledHeaderIndex] : referenceHeader;
final Hash referenceHash = referenceHeaderForNextRequest.getHash();
final int count = partiallyFilled ? lastFilledHeaderIndex : segmentLength;
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
referenceHash,
referenceHeaderForNextRequest.getNumber(),
count + 1,
0,
GetHeadersFromPeerTask.Direction.REVERSE,
protocolSchedule);
PeerTaskExecutorResult<List<BlockHeader>> taskResult;
if (ethPeer.isPresent()) {
taskResult =
ethContext.getPeerTaskExecutor().executeAgainstPeer(task, ethPeer.get());
} else {
taskResult = ethContext.getPeerTaskExecutor().execute(task);
}
if (taskResult.responseCode() != PeerTaskExecutorResponseCode.SUCCESS
|| taskResult.result().isEmpty()) {
return CompletableFuture.failedFuture(
new RuntimeException(
"Failed to download headers. Response code was "
+ taskResult.responseCode()));
}
return CompletableFuture.completedFuture(taskResult);
});
}
@VisibleForTesting
CompletableFuture<List<BlockHeader>> processHeaders(
final PeerTaskResult<List<BlockHeader>> headersResult) {
return executeWorkerSubTask(
ethContext.getScheduler(),
() -> {
final CompletableFuture<List<BlockHeader>> future = new CompletableFuture<>();
BlockHeader child = null;
boolean firstSkipped = false;
final int previousHeaderIndex = lastFilledHeaderIndex;
for (final BlockHeader header : headersResult.getResult()) {
final int headerIndex =
Ints.checkedCast(
segmentLength - (referenceHeader.getNumber() - header.getNumber()));
if (!firstSkipped) {
// Skip over reference header
firstSkipped = true;
continue;
}
if (child == null) {
child =
(headerIndex == segmentLength - 1) ? referenceHeader : headers[headerIndex + 1];
}
final boolean foundChild = child != null;
final boolean headerInRange = checkHeaderInRange(header);
final boolean headerInvalid = foundChild && !validateHeader(child, header);
if (!headerInRange || !foundChild || headerInvalid) {
final BlockHeader invalidHeader = child;
final CompletableFuture<?> badBlockHandled =
headerInvalid
? markBadBlock(invalidHeader, headersResult.getPeer())
: CompletableFuture.completedFuture(null);
badBlockHandled.whenComplete(
(res, err) -> {
LOG.debug(
"Received invalid headers from peer (BREACH_OF_PROTOCOL), disconnecting from: {}",
headersResult.getPeer());
headersResult
.getPeer()
.disconnect(DisconnectReason.BREACH_OF_PROTOCOL_INVALID_HEADERS);
final InvalidBlockException exception;
if (invalidHeader == null) {
final String msg =
String.format(
"Received misordered blocks. Missing child of %s",
header.toLogString());
exception = InvalidBlockException.create(msg);
} else {
final String errorMsg =
headerInvalid
? "Header failed validation"
: "Out-of-range header received from peer";
exception = InvalidBlockException.fromInvalidBlock(errorMsg, invalidHeader);
}
future.completeExceptionally(exception);
});
return future;
}
headers[headerIndex] = header;
lastFilledHeaderIndex = headerIndex;
child = header;
}
future.complete(asList(headers).subList(lastFilledHeaderIndex, previousHeaderIndex));
return future;
return processHeaders(headersResult.getResult(), headersResult.getPeer());
});
}
private CompletableFuture<List<BlockHeader>> processHeadersUsingPeerTask(
final PeerTaskExecutorResult<List<BlockHeader>> headersResult) {
final List<BlockHeader> blockHeaders =
headersResult
.result()
.orElseThrow(
() -> new RuntimeException("Expected blockHeaders in PeerTaskExecutorResult"));
final EthPeer ethPeer =
headersResult
.ethPeer()
.orElseThrow(() -> new RuntimeException("Expected a peer in PeerTaskExecutorResult"));
return processHeaders(blockHeaders, ethPeer);
}
private CompletableFuture<List<BlockHeader>> processHeaders(
final List<BlockHeader> blockHeaders, final EthPeer ethPeer) {
final CompletableFuture<List<BlockHeader>> future = new CompletableFuture<>();
BlockHeader child = null;
boolean firstSkipped = false;
final int previousHeaderIndex = lastFilledHeaderIndex;
for (final BlockHeader header : blockHeaders) {
final int headerIndex =
Ints.checkedCast(segmentLength - (referenceHeader.getNumber() - header.getNumber()));
if (!firstSkipped) {
// Skip over reference header
firstSkipped = true;
continue;
}
if (child == null) {
child = (headerIndex == segmentLength - 1) ? referenceHeader : headers[headerIndex + 1];
}
final boolean foundChild = child != null;
final boolean headerInRange = checkHeaderInRange(header);
final boolean headerInvalid = foundChild && !validateHeader(child, header);
if (!headerInRange || !foundChild || headerInvalid) {
final BlockHeader invalidHeader = child;
final CompletableFuture<?> badBlockHandled =
headerInvalid
? markBadBlock(invalidHeader, ethPeer)
: CompletableFuture.completedFuture(null);
badBlockHandled.whenComplete(
(res, err) -> {
LOG.debug(
"Received invalid headers from peer (BREACH_OF_PROTOCOL), disconnecting from: {}",
ethPeer);
ethPeer.disconnect(DisconnectReason.BREACH_OF_PROTOCOL_INVALID_HEADERS);
final InvalidBlockException exception;
if (invalidHeader == null) {
final String msg =
String.format(
"Received misordered blocks. Missing child of %s", header.toLogString());
exception = InvalidBlockException.create(msg);
} else {
final String errorMsg =
headerInvalid
? "Header failed validation"
: "Out-of-range header received from peer";
exception = InvalidBlockException.fromInvalidBlock(errorMsg, invalidHeader);
}
future.completeExceptionally(exception);
});
return future;
}
headers[headerIndex] = header;
lastFilledHeaderIndex = headerIndex;
child = header;
}
future.complete(asList(headers).subList(lastFilledHeaderIndex, previousHeaderIndex));
return future;
}
private CompletableFuture<?> markBadBlock(final BlockHeader badHeader, final EthPeer badPeer) {
// even though the header is known bad we are downloading the block body for the debug_badBlocks
// RPC

View File

@@ -14,6 +14,24 @@
*/
package org.hyperledger.besu.ethereum.eth.transactions;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_ENTRY_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_STORAGE_KEY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOBS_WITH_COMMITMENTS_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.CODE_DELEGATION_ENTRY_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.EIP1559_AND_EIP4844_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_COMMITMENT_OR_PROOF_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_ACCESS_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CHAIN_ID_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_TO_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PAYLOAD_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PENDING_TRANSACTION_SHALLOW_SIZE;
import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.VERSIONED_HASH_SIZE;
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
@@ -31,21 +49,6 @@ import java.util.concurrent.atomic.AtomicLong;
public abstract class PendingTransaction
implements org.hyperledger.besu.datatypes.PendingTransaction {
static final int NOT_INITIALIZED = -1;
static final int FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE = 904;
static final int EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE = 1016;
static final int OPTIONAL_TO_MEMORY_SIZE = 112;
static final int OPTIONAL_CHAIN_ID_MEMORY_SIZE = 80;
static final int PAYLOAD_BASE_MEMORY_SIZE = 32;
static final int ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE = 32;
static final int ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE = 248;
static final int OPTIONAL_ACCESS_LIST_MEMORY_SIZE = 24;
static final int VERSIONED_HASH_SIZE = 96;
static final int BASE_LIST_SIZE = 48;
static final int BASE_OPTIONAL_SIZE = 16;
static final int KZG_COMMITMENT_OR_PROOF_SIZE = 112;
static final int BLOB_SIZE = 131136;
static final int BLOBS_WITH_COMMITMENTS_SIZE = 40;
static final int PENDING_TRANSACTION_MEMORY_SIZE = 40;
private static final AtomicLong TRANSACTIONS_ADDED = new AtomicLong();
private final Transaction transaction;
private final long addedAt;
@@ -147,20 +150,20 @@ public abstract class PendingTransaction
case ACCESS_LIST -> computeAccessListMemorySize();
case EIP1559 -> computeEIP1559MemorySize();
case BLOB -> computeBlobMemorySize();
case DELEGATE_CODE -> computeSetCodeMemorySize();
case DELEGATE_CODE -> computeDelegateCodeMemorySize();
}
+ PENDING_TRANSACTION_MEMORY_SIZE;
+ PENDING_TRANSACTION_SHALLOW_SIZE;
}
private int computeFrontierMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize();
}
private int computeAccessListMemorySize() {
return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE
return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
@@ -168,7 +171,7 @@ public abstract class PendingTransaction
}
private int computeEIP1559MemorySize() {
return EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE
return EIP1559_AND_EIP4844_SHALLOW_SIZE
+ computePayloadMemorySize()
+ computeToMemorySize()
+ computeChainIdMemorySize()
@@ -177,41 +180,41 @@ public abstract class PendingTransaction
private int computeBlobMemorySize() {
return computeEIP1559MemorySize()
+ BASE_OPTIONAL_SIZE // for the versionedHashes field
+ OPTIONAL_SHALLOW_SIZE // for the versionedHashes field
+ computeBlobWithCommitmentsMemorySize();
}
private int computeSetCodeMemorySize() {
return 0;
private int computeDelegateCodeMemorySize() {
return computeEIP1559MemorySize() + computeCodeDelegationListMemorySize();
}
private int computeBlobWithCommitmentsMemorySize() {
final int blobCount = transaction.getBlobCount();
return BASE_OPTIONAL_SIZE
return OPTIONAL_SHALLOW_SIZE
+ BLOBS_WITH_COMMITMENTS_SIZE
+ (BASE_LIST_SIZE * 4)
+ (LIST_SHALLOW_SIZE * 4)
+ (KZG_COMMITMENT_OR_PROOF_SIZE * blobCount * 2)
+ (VERSIONED_HASH_SIZE * blobCount)
+ (BLOB_SIZE * blobCount);
}
private int computePayloadMemorySize() {
return transaction.getPayload().size() > 0
? PAYLOAD_BASE_MEMORY_SIZE + transaction.getPayload().size()
return !transaction.getPayload().isEmpty()
? PAYLOAD_SHALLOW_SIZE + transaction.getPayload().size()
: 0;
}
private int computeToMemorySize() {
if (transaction.getTo().isPresent()) {
return OPTIONAL_TO_MEMORY_SIZE;
return OPTIONAL_TO_SIZE;
}
return 0;
}
private int computeChainIdMemorySize() {
if (transaction.getChainId().isPresent()) {
return OPTIONAL_CHAIN_ID_MEMORY_SIZE;
return OPTIONAL_CHAIN_ID_SIZE;
}
return 0;
}
@@ -221,11 +224,23 @@ public abstract class PendingTransaction
.getAccessList()
.map(
al -> {
int totalSize = OPTIONAL_ACCESS_LIST_MEMORY_SIZE;
totalSize += al.size() * ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE;
int totalSize = OPTIONAL_ACCESS_LIST_SHALLOW_SIZE;
totalSize += al.size() * ACCESS_LIST_ENTRY_SHALLOW_SIZE;
totalSize +=
al.stream().map(AccessListEntry::storageKeys).mapToInt(List::size).sum()
* ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE;
* ACCESS_LIST_STORAGE_KEY_SIZE;
return totalSize;
})
.orElse(0);
}
private int computeCodeDelegationListMemorySize() {
return transaction
.getCodeDelegationList()
.map(
cd -> {
int totalSize = OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE;
totalSize += cd.size() * CODE_DELEGATION_ENTRY_SIZE;
return totalSize;
})
.orElse(0);
@@ -252,7 +267,7 @@ public abstract class PendingTransaction
@Override
public int hashCode() {
return 31 * (int) (sequence ^ (sequence >>> 32));
return 31 * Long.hashCode(sequence);
}
@Override
@@ -399,4 +414,29 @@ public abstract class PendingTransaction
}
}
}
/**
* The memory size of an object is calculated using the PendingTransactionEstimatedMemorySizeTest
* look there for the details of the calculation and to adapt the code when any of the related
* class changes its structure.
*/
public interface MemorySize {
int FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE = 904;
int EIP1559_AND_EIP4844_SHALLOW_SIZE = 1016;
int OPTIONAL_TO_SIZE = 112;
int OPTIONAL_CHAIN_ID_SIZE = 80;
int PAYLOAD_SHALLOW_SIZE = 32;
int ACCESS_LIST_STORAGE_KEY_SIZE = 32;
int ACCESS_LIST_ENTRY_SHALLOW_SIZE = 248;
int OPTIONAL_ACCESS_LIST_SHALLOW_SIZE = 40;
int OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE = 40;
int CODE_DELEGATION_ENTRY_SIZE = 432;
int VERSIONED_HASH_SIZE = 96;
int LIST_SHALLOW_SIZE = 48;
int OPTIONAL_SHALLOW_SIZE = 16;
int KZG_COMMITMENT_OR_PROOF_SIZE = 112;
int BLOB_SIZE = 131136;
int BLOBS_WITH_COMMITMENTS_SIZE = 40;
int PENDING_TRANSACTION_SHALLOW_SIZE = 40;
}
}

View File

@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
@@ -63,6 +64,7 @@ public class EthProtocolManagerTestBuilder {
private List<PeerValidator> peerValidators;
private Optional<MergePeerFilter> mergePeerFilter;
private SynchronizerConfiguration synchronizerConfiguration;
private PeerTaskExecutor peerTaskExecutor;
public static EthProtocolManagerTestBuilder builder() {
return new EthProtocolManagerTestBuilder();
@@ -159,6 +161,12 @@ public class EthProtocolManagerTestBuilder {
return this;
}
public EthProtocolManagerTestBuilder setPeerTaskExecutor(
final PeerTaskExecutor peerTaskExecutor) {
this.peerTaskExecutor = peerTaskExecutor;
return this;
}
public EthProtocolManager build() {
if (protocolSchedule == null) {
protocolSchedule = DEFAULT_PROTOCOL_SCHEDULE;
@@ -215,8 +223,12 @@ public class EthProtocolManagerTestBuilder {
ethScheduler =
new DeterministicEthScheduler(DeterministicEthScheduler.TimeoutPolicy.NEVER_TIMEOUT);
}
if (peerTaskExecutor == null) {
peerTaskExecutor = mock(PeerTaskExecutor.class);
}
if (ethContext == null) {
ethContext = new EthContext(ethPeers, ethMessages, snapMessages, ethScheduler);
ethContext =
new EthContext(ethPeers, ethMessages, snapMessages, ethScheduler, peerTaskExecutor);
}
if (peerValidators == null) {
peerValidators = Collections.emptyList();

View File

@@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
@@ -64,6 +65,7 @@ import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
/**
* @param <T> The type of data being requested from the network
@@ -92,6 +94,7 @@ public abstract class AbstractMessageTaskTest<T, R> {
protected EthContext ethContext;
protected EthPeers ethPeers;
protected TransactionPool transactionPool;
protected PeerTaskExecutor peerTaskExecutor;
protected AtomicBoolean peersDoTimeout;
protected AtomicInteger peerCountToTimeout;
@@ -131,7 +134,8 @@ public abstract class AbstractMessageTaskTest<T, R> {
final EthScheduler ethScheduler =
new DeterministicEthScheduler(
() -> peerCountToTimeout.getAndDecrement() > 0 || peersDoTimeout.get());
ethContext = new EthContext(ethPeers, ethMessages, ethScheduler);
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
ethContext = new EthContext(ethPeers, ethMessages, ethScheduler, peerTaskExecutor);
final SyncState syncState = new SyncState(blockchain, ethContext.getEthPeers());
transactionPool =
TransactionPoolFactory.createTransactionPool(

View File

@@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.util.Optional;
@@ -73,7 +74,8 @@ public class PeerTaskExecutorTest {
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@@ -85,6 +87,37 @@ public class PeerTaskExecutorTest {
Assertions.assertEquals(PeerTaskExecutorResponseCode.SUCCESS, result.responseCode());
}
@Test
public void testExecuteAgainstPeerWithNoRetriesAndPeerShouldBeDisconnected()
throws PeerConnection.PeerNotConnected,
ExecutionException,
InterruptedException,
TimeoutException,
InvalidPeerTaskResponseException {
Object responseObject = new Object();
Mockito.when(peerTask.getRequestMessage()).thenReturn(requestMessageData);
Mockito.when(peerTask.getRetriesWithSamePeer()).thenReturn(0);
Mockito.when(peerTask.getSubProtocol()).thenReturn(subprotocol);
Mockito.when(subprotocol.getName()).thenReturn("subprotocol");
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.NON_SEQUENTIAL_HEADERS_RETURNED);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
Mockito.verify(ethPeer)
.disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL_NON_SEQUENTIAL_HEADERS);
Assertions.assertNotNull(result);
Assertions.assertTrue(result.result().isPresent());
Assertions.assertSame(responseObject, result.result().get());
Assertions.assertEquals(PeerTaskExecutorResponseCode.INVALID_RESPONSE, result.responseCode());
}
@Test
public void testExecuteAgainstPeerWithNoRetriesAndPartialSuccessfulFlow()
throws PeerConnection.PeerNotConnected,
@@ -102,7 +135,8 @@ public class PeerTaskExecutorTest {
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(false);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.NO_RESULTS_RETURNED);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@@ -131,7 +165,8 @@ public class PeerTaskExecutorTest {
.thenReturn(responseMessageData);
Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@@ -237,7 +272,8 @@ public class PeerTaskExecutorTest {
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer))
.thenReturn(responseMessageData);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer);
@@ -275,7 +311,8 @@ public class PeerTaskExecutorTest {
Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, peer2))
.thenReturn(responseMessageData);
Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject);
Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true);
Mockito.when(peerTask.validateResult(responseObject))
.thenReturn(PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD);
PeerTaskExecutorResult<Object> result = peerTaskExecutor.execute(peerTask);

View File

@@ -0,0 +1,88 @@
/*
* Copyright contributors to 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.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class GetHeadersFromPeerTaskExecutorAnswer
implements Answer<PeerTaskExecutorResult<List<BlockHeader>>> {
private final Blockchain otherBlockchain;
private final EthPeers ethPeers;
public GetHeadersFromPeerTaskExecutorAnswer(
final Blockchain otherBlockchain, final EthPeers ethPeers) {
this.otherBlockchain = otherBlockchain;
this.ethPeers = ethPeers;
}
@Override
public PeerTaskExecutorResult<List<BlockHeader>> answer(final InvocationOnMock invocationOnMock)
throws Throwable {
GetHeadersFromPeerTask task = invocationOnMock.getArgument(0, GetHeadersFromPeerTask.class);
List<BlockHeader> getHeadersFromPeerTaskResult = new ArrayList<>();
BlockHeader initialHeader;
if (task.getBlockHash() != null) {
initialHeader = otherBlockchain.getBlockHeader(task.getBlockHash()).orElse(null);
} else {
initialHeader = otherBlockchain.getBlockHeader(task.getBlockNumber()).orElse(null);
}
getHeadersFromPeerTaskResult.add(initialHeader);
if (initialHeader != null && task.getMaxHeaders() > 1) {
if (task.getDirection() == GetHeadersFromPeerTask.Direction.FORWARD) {
int skip = task.getSkip() + 1;
long nextHeaderNumber = initialHeader.getNumber() + skip;
long getLimit = nextHeaderNumber + ((task.getMaxHeaders() - 1) * skip);
for (long i = nextHeaderNumber; i < getLimit; i += skip) {
Optional<BlockHeader> header = otherBlockchain.getBlockHeader(i);
if (header.isPresent()) {
getHeadersFromPeerTaskResult.add(header.get());
} else {
break;
}
}
} else {
int skip = task.getSkip() + 1;
long nextHeaderNumber = initialHeader.getNumber() - skip;
long getLimit = nextHeaderNumber - ((task.getMaxHeaders() - 1) * skip);
for (long i = initialHeader.getNumber() - 1; i > getLimit; i -= skip) {
Optional<BlockHeader> header = otherBlockchain.getBlockHeader(i);
if (header.isPresent()) {
getHeadersFromPeerTaskResult.add(header.get());
} else {
break;
}
}
}
}
return new PeerTaskExecutorResult<>(
Optional.of(getHeadersFromPeerTaskResult),
PeerTaskExecutorResponseCode.SUCCESS,
ethPeers.bestPeer());
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright contributors to 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.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
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.manager.peertask.PeerTaskValidationResponse;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask.Direction;
import org.hyperledger.besu.ethereum.eth.messages.BlockHeadersMessage;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class GetHeadersFromPeerTaskTest {
@Test
public void testGetSubProtocol() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(0, 1, 0, Direction.FORWARD, null);
Assertions.assertEquals(EthProtocol.get(), task.getSubProtocol());
}
@Test
public void testGetRequestMessageForHash() {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(Hash.ZERO, 0, 1, 0, Direction.FORWARD, null);
MessageData requestMessageData = task.getRequestMessage();
Assertions.assertEquals(
"0xe4a00000000000000000000000000000000000000000000000000000000000000000018080",
requestMessageData.getData().toHexString());
}
@Test
public void testGetRequestMessageForBlockNumber() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(123, 1, 0, Direction.FORWARD, null);
MessageData requestMessageData = task.getRequestMessage();
Assertions.assertEquals("0xc47b018080", requestMessageData.getData().toHexString());
}
@Test
public void testGetRequestMessageForHashWhenBlockNumberAlsoProvided() {
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(Hash.ZERO, 123, 1, 0, Direction.FORWARD, null);
MessageData requestMessageData = task.getRequestMessage();
Assertions.assertEquals(
"0xe4a00000000000000000000000000000000000000000000000000000000000000000018080",
requestMessageData.getData().toHexString());
}
@Test
public void testProcessResponseWithNullMessageData() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(0, 1, 0, Direction.FORWARD, null);
Assertions.assertThrows(
InvalidPeerTaskResponseException.class,
() -> task.processResponse(null),
"Response MessageData is null");
}
@Test
public void testProcessResponse() throws InvalidPeerTaskResponseException {
final BlockchainSetupUtil blockchainSetupUtil =
BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST);
blockchainSetupUtil.importAllBlocks();
Blockchain blockchain = blockchainSetupUtil.getBlockchain();
BlockHeader blockHeader = blockchain.getChainHeadHeader();
BlockHeadersMessage responseMessage = BlockHeadersMessage.create(blockHeader);
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(
blockHeader.getBlockHash(),
0,
1,
0,
Direction.FORWARD,
blockchainSetupUtil.getProtocolSchedule());
Assertions.assertEquals(
List.of(blockchain.getChainHeadHeader()), task.processResponse(responseMessage));
}
@Test
public void testGetPeerRequirementFilter() {
ProtocolSchedule protocolSchedule = Mockito.mock(ProtocolSchedule.class);
Mockito.when(protocolSchedule.anyMatch(Mockito.any())).thenReturn(false);
GetHeadersFromPeerTask task =
new GetHeadersFromPeerTask(5, 1, 0, Direction.FORWARD, protocolSchedule);
EthPeer failForShortChainHeight = mockPeer(1);
EthPeer successfulCandidate = mockPeer(5);
Assertions.assertFalse(task.getPeerRequirementFilter().test(failForShortChainHeight));
Assertions.assertTrue(task.getPeerRequirementFilter().test(successfulCandidate));
}
@Test
public void testValidateResultForEmptyResult() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(5, 1, 0, Direction.FORWARD, null);
Assertions.assertEquals(
PeerTaskValidationResponse.NO_RESULTS_RETURNED,
task.validateResult(Collections.emptyList()));
}
@Test
public void testShouldDisconnectPeerForTooManyHeadersReturned() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(5, 1, 1, Direction.FORWARD, null);
BlockHeader header1 = Mockito.mock(BlockHeader.class);
BlockHeader header2 = Mockito.mock(BlockHeader.class);
BlockHeader header3 = Mockito.mock(BlockHeader.class);
Assertions.assertEquals(
PeerTaskValidationResponse.TOO_MANY_RESULTS_RETURNED,
task.validateResult(List.of(header1, header2, header3)));
}
@Test
public void testValidateResultForNonSequentialHeaders() {
GetHeadersFromPeerTask task = new GetHeadersFromPeerTask(1, 3, 0, Direction.FORWARD, null);
Hash block1Hash = Hash.fromHexStringLenient("01");
Hash block2Hash = Hash.fromHexStringLenient("02");
BlockHeader header1 = Mockito.mock(BlockHeader.class);
Mockito.when(header1.getNumber()).thenReturn(1L);
Mockito.when(header1.getHash()).thenReturn(block1Hash);
BlockHeader header2 = Mockito.mock(BlockHeader.class);
Mockito.when(header2.getNumber()).thenReturn(2L);
Mockito.when(header2.getHash()).thenReturn(block2Hash);
Mockito.when(header2.getParentHash()).thenReturn(block1Hash);
BlockHeader header3 = Mockito.mock(BlockHeader.class);
Mockito.when(header3.getNumber()).thenReturn(3L);
Mockito.when(header3.getParentHash()).thenReturn(Hash.ZERO);
Assertions.assertEquals(
PeerTaskValidationResponse.NON_SEQUENTIAL_HEADERS_RETURNED,
task.validateResult(List.of(header1, header2, header3)));
}
private EthPeer mockPeer(final long chainHeight) {
EthPeer ethPeer = Mockito.mock(EthPeer.class);
ChainState chainState = Mockito.mock(ChainState.class);
Mockito.when(ethPeer.chainState()).thenReturn(chainState);
Mockito.when(chainState.getEstimatedHeight()).thenReturn(chainHeight);
return ethPeer;
}
}

View File

@@ -21,6 +21,7 @@ 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.manager.peertask.PeerTaskValidationResponse;
import org.hyperledger.besu.ethereum.eth.messages.EthPV63;
import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
@@ -222,20 +223,23 @@ public class GetReceiptsFromPeerTaskTest {
}
@Test
public void testIsSuccessForPartialSuccess() {
public void testValidateResultForPartialSuccess() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Assertions.assertFalse(task.isSuccess(Collections.emptyMap()));
Assertions.assertEquals(
PeerTaskValidationResponse.NO_RESULTS_RETURNED,
task.validateResult(Collections.emptyMap()));
}
@Test
public void testIsSuccessForFullSuccess() {
public void testValidateResultForFullSuccess() {
GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null);
Map<BlockHeader, List<TransactionReceipt>> map = new HashMap<>();
map.put(mockBlockHeader(1), null);
Assertions.assertTrue(task.isSuccess(map));
Assertions.assertEquals(
PeerTaskValidationResponse.RESULTS_VALID_AND_GOOD, task.validateResult(map));
}
private BlockHeader mockBlockHeader(final long blockNumber) {

View File

@@ -24,6 +24,8 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.ethtaskutils.AbstractMessageTaskTest;
import org.hyperledger.besu.ethereum.eth.manager.exceptions.EthTaskException;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.util.ExceptionUtils;
import java.util.Optional;
@@ -32,6 +34,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class GetBlockFromPeerTaskTest
extends AbstractMessageTaskTest<Block, AbstractPeerTask.PeerTaskResult<Block>> {
@@ -47,9 +50,11 @@ public class GetBlockFromPeerTaskTest
@Override
protected EthTask<AbstractPeerTask.PeerTaskResult<Block>> createTask(final Block requestedData) {
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
return GetBlockFromPeerTask.create(
protocolSchedule,
ethContext,
SynchronizerConfiguration.builder().build(),
Optional.of(requestedData.getHash()),
BLOCK_NUMBER,
metricsSystem);

View File

@@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.ethtaskutils.RetryingSwitchingPeerMessageTaskTest;
import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@@ -51,6 +52,7 @@ public class RetryingGetBlockFromPeersTaskTest
return RetryingGetBlockFromPeersTask.create(
protocolSchedule,
ethContext,
SynchronizerConfiguration.builder().build(),
metricsSystem,
maxRetries,
Optional.of(requestedData.getResult().getHash()),

View File

@@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderValidator;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@@ -38,7 +39,12 @@ public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest {
@Override
AbstractPeerBlockValidator createValidator(final long blockNumber, final long buffer) {
return new DaoForkPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), blockNumber, buffer);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
blockNumber,
buffer);
}
@Test
@@ -54,7 +60,12 @@ public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest {
final PeerValidator validator =
new DaoForkPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), daoBlockNumber, 0);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
daoBlockNumber,
0);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, daoBlockNumber);
@@ -82,7 +93,12 @@ public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest {
final PeerValidator validator =
new DaoForkPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), daoBlockNumber, 0);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
daoBlockNumber,
0);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, daoBlockNumber);
@@ -107,7 +123,12 @@ public class DaoForkPeerValidatorTest extends AbstractPeerBlockValidatorTest {
final PeerValidator validator =
new DaoForkPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), daoBlockNumber, 0);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
daoBlockNumber,
0);
final RespondingEthPeer peer =
EthProtocolManagerTestUtil.createPeer(ethProtocolManager, daoBlockNumber);

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import java.util.concurrent.CompletableFuture;
@@ -37,7 +38,13 @@ public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorT
@Override
AbstractPeerBlockValidator createValidator(final long blockNumber, final long buffer) {
return new RequiredBlocksPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), blockNumber, Hash.ZERO, buffer);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
blockNumber,
Hash.ZERO,
buffer);
}
@Test
@@ -54,6 +61,8 @@ public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorT
final PeerValidator validator =
new RequiredBlocksPeerValidator(
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
requiredBlockNumber,
requiredBlock.getHash(),
@@ -86,6 +95,8 @@ public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorT
final PeerValidator validator =
new RequiredBlocksPeerValidator(
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
requiredBlockNumber,
Hash.ZERO,
@@ -113,7 +124,12 @@ public class RequiredBlocksPeerValidatorTest extends AbstractPeerBlockValidatorT
final PeerValidator validator =
new RequiredBlocksPeerValidator(
ProtocolScheduleFixture.MAINNET, new NoOpMetricsSystem(), 1, Hash.ZERO);
ProtocolScheduleFixture.MAINNET,
null,
SynchronizerConfiguration.builder().build(),
new NoOpMetricsSystem(),
1,
Hash.ZERO);
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1);

View File

@@ -656,7 +656,8 @@ public abstract class AbstractBlockPropagationManagerTest {
new ForkIdManager(
blockchain, Collections.emptyList(), Collections.emptyList(), false)),
new EthMessages(),
ethScheduler);
ethScheduler,
null);
final BlockPropagationManager blockPropagationManager =
new BlockPropagationManager(
syncConfig,
@@ -797,7 +798,8 @@ public abstract class AbstractBlockPropagationManagerTest {
new ForkIdManager(
blockchain, Collections.emptyList(), Collections.emptyList(), false)),
new EthMessages(),
ethScheduler);
ethScheduler,
null);
final BlockPropagationManager blockPropagationManager =
new BlockPropagationManager(
syncConfig,

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.eth.sync;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.datatypes.Hash;
@@ -26,10 +25,14 @@ import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule;
import org.hyperledger.besu.ethereum.eth.manager.ChainState;
import org.hyperledger.besu.ethereum.eth.manager.EthPeer;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer.Responder;
import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetHeadersFromPeerTaskExecutorAnswer;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@@ -44,6 +47,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.mockito.Mockito;
public class ChainHeadTrackerTest {
@@ -51,6 +55,10 @@ public class ChainHeadTrackerTest {
private MutableBlockchain blockchain;
private EthProtocolManager ethProtocolManager;
private RespondingEthPeer respondingPeer;
private PeerTaskExecutor peerTaskExecutor;
private SynchronizerConfiguration synchronizerConfiguration;
private ChainHeadTracker chainHeadTracker;
private final ProtocolSchedule protocolSchedule =
@@ -63,8 +71,6 @@ public class ChainHeadTrackerTest {
false,
new NoOpMetricsSystem());
private final TrailingPeerLimiter trailingPeerLimiter = mock(TrailingPeerLimiter.class);
static class ChainHeadTrackerTestArguments implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(final ExtensionContext context) {
@@ -73,10 +79,15 @@ public class ChainHeadTrackerTest {
}
}
public void setup(final DataStorageFormat storageFormat) {
public void setup(final DataStorageFormat storageFormat, final boolean isPeerTaskSystemEnabled) {
blockchainSetupUtil = BlockchainSetupUtil.forTesting(storageFormat);
blockchain = blockchainSetupUtil.getBlockchain();
ethProtocolManager = EthProtocolManagerTestBuilder.builder().setBlockchain(blockchain).build();
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
ethProtocolManager =
EthProtocolManagerTestBuilder.builder()
.setBlockchain(blockchain)
.setPeerTaskExecutor(peerTaskExecutor)
.build();
respondingPeer =
RespondingEthPeer.builder()
.ethProtocolManager(ethProtocolManager)
@@ -84,11 +95,24 @@ public class ChainHeadTrackerTest {
.totalDifficulty(blockchain.getChainHead().getTotalDifficulty())
.estimatedHeight(0)
.build();
GetHeadersFromPeerTaskExecutorAnswer getHeadersAnswer =
new GetHeadersFromPeerTaskExecutorAnswer(
blockchain, ethProtocolManager.ethContext().getEthPeers());
Mockito.when(peerTaskExecutor.execute(Mockito.any(GetHeadersFromPeerTask.class)))
.thenAnswer(getHeadersAnswer);
Mockito.when(
peerTaskExecutor.executeAgainstPeer(
Mockito.any(GetHeadersFromPeerTask.class), Mockito.any(EthPeer.class)))
.thenAnswer(getHeadersAnswer);
synchronizerConfiguration =
SynchronizerConfiguration.builder()
.isPeerTaskSystemEnabled(isPeerTaskSystemEnabled)
.build();
chainHeadTracker =
new ChainHeadTracker(
ethProtocolManager.ethContext(),
protocolSchedule,
trailingPeerLimiter,
synchronizerConfiguration,
new NoOpMetricsSystem());
}
@@ -96,7 +120,7 @@ public class ChainHeadTrackerTest {
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldRequestHeaderChainHeadWhenNewPeerConnects(
final DataStorageFormat storageFormat) {
setup(storageFormat);
setup(storageFormat, false);
final Responder responder =
RespondingEthPeer.blockchainResponder(
blockchainSetupUtil.getBlockchain(),
@@ -112,11 +136,23 @@ public class ChainHeadTrackerTest {
.isEqualTo(blockchain.getChainHeadBlockNumber());
}
@ParameterizedTest
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldRequestHeaderChainHeadWhenNewPeerConnectsUsingPeerTaskSystem(
final DataStorageFormat storageFormat) {
setup(storageFormat, true);
chainHeadTracker.getBestHeaderFromPeer(respondingPeer.getEthPeer());
Assertions.assertThat(chainHeadState().getEstimatedHeight()).isZero();
Assertions.assertThat(chainHeadState().getEstimatedHeight())
.isEqualTo(blockchain.getChainHeadBlockNumber());
}
@ParameterizedTest
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldIgnoreHeadersIfChainHeadHasAlreadyBeenUpdatedWhileWaiting(
final DataStorageFormat storageFormat) {
setup(storageFormat);
setup(storageFormat, false);
final Responder responder =
RespondingEthPeer.blockchainResponder(
blockchainSetupUtil.getBlockchain(),
@@ -132,10 +168,23 @@ public class ChainHeadTrackerTest {
Assertions.assertThat(chainHeadState().getEstimatedHeight()).isZero();
}
@ParameterizedTest
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldIgnoreHeadersIfChainHeadHasAlreadyBeenUpdatedWhileWaitingUsingPeerTaskSystem(
final DataStorageFormat storageFormat) {
setup(storageFormat, true);
chainHeadTracker.getBestHeaderFromPeer(respondingPeer.getEthPeer());
// Change the hash of the current known head
respondingPeer.getEthPeer().chainState().statusReceived(Hash.EMPTY_TRIE_HASH, Difficulty.ONE);
Assertions.assertThat(chainHeadState().getEstimatedHeight()).isZero();
}
@ParameterizedTest
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldCheckTrialingPeerLimits(final DataStorageFormat storageFormat) {
setup(storageFormat);
setup(storageFormat, false);
final Responder responder =
RespondingEthPeer.blockchainResponder(
blockchainSetupUtil.getBlockchain(),
@@ -151,6 +200,18 @@ public class ChainHeadTrackerTest {
.isEqualTo(blockchain.getChainHeadBlockNumber());
}
@ParameterizedTest
@ArgumentsSource(ChainHeadTrackerTestArguments.class)
public void shouldCheckTrialingPeerLimitsUsingPeerTaskSystem(
final DataStorageFormat storageFormat) {
setup(storageFormat, true);
chainHeadTracker.getBestHeaderFromPeer(respondingPeer.getEthPeer());
Assertions.assertThat(chainHeadState().getEstimatedHeight()).isZero();
Assertions.assertThat(chainHeadState().getEstimatedHeight())
.isEqualTo(blockchain.getChainHeadBlockNumber());
}
private ChainState chainHeadState() {
return respondingPeer.getEthPeer().chainState();
}

View File

@@ -27,6 +27,10 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.range.RangeHeaders;
import org.hyperledger.besu.ethereum.eth.sync.range.SyncTargetRange;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
@@ -37,11 +41,13 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class DownloadHeadersStepTest {
@@ -52,6 +58,7 @@ public class DownloadHeadersStepTest {
private final EthPeer syncTarget = mock(EthPeer.class);
private EthProtocolManager ethProtocolManager;
private PeerTaskExecutor peerTaskExecutor;
private DownloadHeadersStep downloader;
private SyncTargetRange checkpointRange;
@@ -66,15 +73,12 @@ public class DownloadHeadersStepTest {
@BeforeEach
public void setUp() {
ethProtocolManager = EthProtocolManagerTestBuilder.builder().setBlockchain(blockchain).build();
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
ethProtocolManager =
EthProtocolManagerTestBuilder.builder()
.setBlockchain(blockchain)
.setPeerTaskExecutor(peerTaskExecutor)
.build();
checkpointRange =
new SyncTargetRange(
@@ -83,6 +87,15 @@ public class DownloadHeadersStepTest {
@Test
public void shouldRetrieveHeadersForCheckpointRange() {
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(),
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000);
final CompletableFuture<RangeHeaders> result = downloader.apply(checkpointRange);
@@ -95,6 +108,15 @@ public class DownloadHeadersStepTest {
@Test
public void shouldCancelRequestToPeerWhenReturnedFutureIsCancelled() {
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(),
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000);
final CompletableFuture<RangeHeaders> result = this.downloader.apply(checkpointRange);
@@ -110,6 +132,15 @@ public class DownloadHeadersStepTest {
@Test
public void shouldReturnOnlyEndHeaderWhenCheckpointRangeHasLengthOfOne() {
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(),
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
final SyncTargetRange checkpointRange =
new SyncTargetRange(
syncTarget, blockchain.getBlockHeader(3).get(), blockchain.getBlockHeader(4).get());
@@ -122,6 +153,15 @@ public class DownloadHeadersStepTest {
@Test
public void shouldGetRemainingHeadersWhenRangeHasNoEnd() {
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(),
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000);
final SyncTargetRange checkpointRange =
new SyncTargetRange(peer.getEthPeer(), blockchain.getBlockHeader(3).get());
@@ -134,6 +174,48 @@ public class DownloadHeadersStepTest {
.isCompletedWithValue(new RangeHeaders(checkpointRange, headersFromChain(4, 19)));
}
@Test
public void shouldGetRemainingHeadersWhenRangeHasNoEndUsingPeerTaskSystem() {
downloader =
new DownloadHeadersStep(
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
() -> HeaderValidationMode.DETACHED_ONLY,
SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(true).build(),
HEADER_REQUEST_SIZE,
new NoOpMetricsSystem());
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000);
final SyncTargetRange checkpointRange =
new SyncTargetRange(peer.getEthPeer(), blockchain.getBlockHeader(3).get());
Mockito.when(peerTaskExecutor.execute(Mockito.any(GetHeadersFromPeerTask.class)))
.thenAnswer(
(invocationOnMock) -> {
GetHeadersFromPeerTask task =
invocationOnMock.getArgument(0, GetHeadersFromPeerTask.class);
List<BlockHeader> result = new ArrayList<>();
for (long i = task.getBlockNumber() + 1; i < task.getMaxHeaders(); i++) {
Optional<BlockHeader> blockHeader = blockchain.getBlockHeader(i);
if (blockHeader.isPresent()) {
result.add(blockHeader.get());
} else {
// we have reached the end of the blockchain, do nothing and break out of the loop
break;
}
}
return new PeerTaskExecutorResult<List<BlockHeader>>(
Optional.of(result), PeerTaskExecutorResponseCode.SUCCESS, Optional.empty());
});
final CompletableFuture<RangeHeaders> result = this.downloader.apply(checkpointRange);
peer.respond(blockchainResponder(blockchain));
assertThat(result)
.isCompletedWithValue(new RangeHeaders(checkpointRange, headersFromChain(4, 19)));
}
private List<BlockHeader> headersFromChain(final long startNumber, final long endNumber) {
final List<BlockHeader> headers = new ArrayList<>();
for (long i = startNumber; i <= endNumber; i++) {

View File

@@ -30,6 +30,10 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestBuilder;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer;
import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer.Responder;
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.GetHeadersFromPeerTask;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState;
import org.hyperledger.besu.ethereum.eth.sync.range.RangeHeadersFetcher;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
@@ -39,14 +43,18 @@ import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.testutil.DeterministicEthScheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.stubbing.Answer;
@ExtendWith(MockitoExtension.class)
public class RangeHeadersFetcherTest {
@@ -57,7 +65,27 @@ public class RangeHeadersFetcherTest {
private static ProtocolContext protocolContext;
private static final MetricsSystem metricsSystem = new NoOpMetricsSystem();
private static TransactionPool transactionPool;
private static final Answer<PeerTaskExecutorResult<List<BlockHeader>>> executeAgainstPeerAnswer =
(invocationOnMock) -> {
List<BlockHeader> resultList = new ArrayList<>();
GetHeadersFromPeerTask task = invocationOnMock.getArgument(0, GetHeadersFromPeerTask.class);
for (long i = task.getBlockNumber();
i < task.getBlockNumber() + task.getMaxHeaders() * (task.getSkip() + 1);
i += task.getSkip() + 1) {
Optional<BlockHeader> blockHeader = blockchain.getBlockHeader(i);
if (blockHeader.isPresent()) {
resultList.add(blockHeader.get());
} else {
break;
}
}
return new PeerTaskExecutorResult<List<BlockHeader>>(
Optional.of(resultList), PeerTaskExecutorResponseCode.SUCCESS, Optional.empty());
};
private EthProtocolManager ethProtocolManager;
private PeerTaskExecutor peerTaskExecutor;
private Responder responder;
private RespondingEthPeer respondingPeer;
@@ -74,6 +102,7 @@ public class RangeHeadersFetcherTest {
@BeforeEach
public void setUpTest() {
peerTaskExecutor = Mockito.mock(PeerTaskExecutor.class);
ethProtocolManager =
EthProtocolManagerTestBuilder.builder()
.setProtocolSchedule(protocolSchedule)
@@ -82,6 +111,7 @@ public class RangeHeadersFetcherTest {
.setWorldStateArchive(protocolContext.getWorldStateArchive())
.setTransactionPool(transactionPool)
.setEthereumWireProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.setPeerTaskExecutor(peerTaskExecutor)
.build();
responder =
RespondingEthPeer.blockchainResponder(
@@ -93,7 +123,7 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldRequestHeadersFromPeerAndExcludeExistingHeader() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
@@ -105,9 +135,44 @@ public class RangeHeadersFetcherTest {
assertThat(result).isCompletedWithValue(asList(header(6), header(11), header(16)));
}
@Test
public void shouldRequestHeadersFromPeerAndExcludeExistingHeaderUsingPeerTaskSystem() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(true);
Mockito.when(
peerTaskExecutor.executeAgainstPeer(
Mockito.any(GetHeadersFromPeerTask.class), Mockito.eq(respondingPeer.getEthPeer())))
.thenAnswer(executeAgainstPeerAnswer);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
respondingPeer.respond(responder);
assertThat(result).isCompletedWithValue(asList(header(6), header(11), header(16)));
}
@Test
public void shouldNotRequestHeadersBeyondTargetWhenTargetIsMultipleOfSegmentSize() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(11));
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(11), false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
respondingPeer.respond(responder);
assertThat(result).isCompletedWithValue(asList(header(6), header(11)));
}
@Test
public void
shouldNotRequestHeadersBeyondTargetWhenTargetIsMultipleOfSegmentSizeWithPeerTaskSystem() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(11), true);
Mockito.when(
peerTaskExecutor.executeAgainstPeer(
Mockito.any(GetHeadersFromPeerTask.class), Mockito.eq(respondingPeer.getEthPeer())))
.thenAnswer(executeAgainstPeerAnswer);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
@@ -119,7 +184,25 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldNotRequestHeadersBeyondTargetWhenTargetIsNotAMultipleOfSegmentSize() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15));
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15), false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
respondingPeer.respond(responder);
assertThat(result).isCompletedWithValue(asList(header(6), header(11)));
}
@Test
public void
shouldNotRequestHeadersBeyondTargetWhenTargetIsNotAMultipleOfSegmentSizeWithPeerTaskSystem() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15), true);
Mockito.when(
peerTaskExecutor.executeAgainstPeer(
Mockito.any(GetHeadersFromPeerTask.class), Mockito.eq(respondingPeer.getEthPeer())))
.thenAnswer(executeAgainstPeerAnswer);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(1));
@@ -131,7 +214,7 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldReturnOnlyTargetHeaderWhenLastHeaderIsTheRangeBeforeTarget() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15));
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15), false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(11));
@@ -141,7 +224,7 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldReturnEmptyListWhenLastHeaderIsTarget() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15));
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15), false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(15));
@@ -150,7 +233,7 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldReturnEmptyListWhenLastHeaderIsAfterTarget() {
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15));
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(header(15), false);
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(respondingPeer.getEthPeer(), header(16));
@@ -160,7 +243,7 @@ public class RangeHeadersFetcherTest {
@Test
public void nextRangeShouldEndAtChainHeadWhenNextRangeHeaderIsAfterHead() {
final long remoteChainHeight = blockchain.getChainHeadBlockNumber();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(false);
assertThat(
rangeHeaderFetcher.nextRangeEndsAtChainHead(
@@ -172,7 +255,7 @@ public class RangeHeadersFetcherTest {
public void nextRangeShouldNotEndAtChainHeadWhenAFinalRangeHeaderIsSpecified() {
final long remoteChainHeight = blockchain.getChainHeadBlockNumber();
final RangeHeadersFetcher rangeHeaderFetcher =
createRangeHeaderFetcher(header(remoteChainHeight));
createRangeHeaderFetcher(header(remoteChainHeight), false);
assertThat(
rangeHeaderFetcher.nextRangeEndsAtChainHead(
@@ -183,7 +266,7 @@ public class RangeHeadersFetcherTest {
@Test
public void shouldReturnRemoteChainHeadWhenNextRangeHeaderIsTheRemoteHead() {
final long remoteChainHeight = blockchain.getChainHeadBlockNumber();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(false);
assertThat(
rangeHeaderFetcher.nextRangeEndsAtChainHead(
@@ -199,24 +282,51 @@ public class RangeHeadersFetcherTest {
assertThat(result).isCompletedWithValue(singletonList(header(remoteChainHeight)));
}
private RangeHeadersFetcher createRangeHeaderFetcher() {
@Test
public void shouldReturnRemoteChainHeadWhenNextRangeHeaderIsTheRemoteHeadWithPeerTaskSystem() {
final long remoteChainHeight = blockchain.getChainHeadBlockNumber();
final RangeHeadersFetcher rangeHeaderFetcher = createRangeHeaderFetcher(true);
Mockito.when(
peerTaskExecutor.executeAgainstPeer(
Mockito.any(GetHeadersFromPeerTask.class), Mockito.eq(respondingPeer.getEthPeer())))
.thenAnswer(executeAgainstPeerAnswer);
assertThat(
rangeHeaderFetcher.nextRangeEndsAtChainHead(
respondingPeer.getEthPeer(), header(remoteChainHeight - SEGMENT_SIZE)))
.isFalse();
final CompletableFuture<List<BlockHeader>> result =
rangeHeaderFetcher.getNextRangeHeaders(
respondingPeer.getEthPeer(), header(remoteChainHeight - SEGMENT_SIZE));
respondingPeer.respond(responder);
assertThat(result).isCompletedWithValue(singletonList(header(remoteChainHeight)));
}
private RangeHeadersFetcher createRangeHeaderFetcher(final boolean isPeerTaskSystemEnabled) {
final EthContext ethContext = ethProtocolManager.ethContext();
return new RangeHeadersFetcher(
SynchronizerConfiguration.builder()
.downloaderChainSegmentSize(SEGMENT_SIZE)
.downloaderHeadersRequestSize(3)
.isPeerTaskSystemEnabled(isPeerTaskSystemEnabled)
.build(),
protocolSchedule,
ethContext,
metricsSystem);
}
private RangeHeadersFetcher createRangeHeaderFetcher(final BlockHeader targetHeader) {
private RangeHeadersFetcher createRangeHeaderFetcher(
final BlockHeader targetHeader, final boolean isPeerTaskSystemEnabled) {
final EthContext ethContext = ethProtocolManager.ethContext();
return new RangeHeadersFetcher(
SynchronizerConfiguration.builder()
.downloaderChainSegmentSize(SEGMENT_SIZE)
.downloaderHeadersRequestSize(3)
.isPeerTaskSystemEnabled(isPeerTaskSystemEnabled)
.build(),
protocolSchedule,
ethContext,

Some files were not shown because too many files have changed in this diff Show More