mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 13:58:02 -05:00
Merge branch 'main' into zkbesu
# Conflicts: # build.gradle # gradle/verification-metadata.xml
This commit is contained in:
2
.github/ISSUE_TEMPLATE/release-checklist.md
vendored
2
.github/ISSUE_TEMPLATE/release-checklist.md
vendored
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -119,6 +119,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder {
|
||||
new TransitionBackwardSyncContext(
|
||||
protocolContext,
|
||||
transitionProtocolSchedule,
|
||||
syncConfig,
|
||||
metricsSystem,
|
||||
ethProtocolManager.ethContext(),
|
||||
syncState,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ public class InvalidPeerTaskResponseException extends Exception {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidPeerTaskResponseException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidPeerTaskResponseException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,6 +73,7 @@ public abstract class AbstractSyncTargetManager {
|
||||
ethContext,
|
||||
bestPeer,
|
||||
config.getDownloaderHeaderRequestSize(),
|
||||
config,
|
||||
metricsSystem)
|
||||
.run()
|
||||
.handle(
|
||||
|
||||
@@ -536,6 +536,7 @@ public class BlockPropagationManager implements UnverifiedForkchoiceListener {
|
||||
RetryingGetBlockFromPeersTask.create(
|
||||
protocolSchedule,
|
||||
ethContext,
|
||||
config,
|
||||
metricsSystem,
|
||||
Math.max(1, ethContext.getEthPeers().peerCount()),
|
||||
maybeBlockHash,
|
||||
|
||||
@@ -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>>>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,6 +50,7 @@ public class SyncStepStep {
|
||||
RetryingGetBlockFromPeersTask.create(
|
||||
context.getProtocolSchedule(),
|
||||
context.getEthContext(),
|
||||
context.getSynchronizerConfiguration(),
|
||||
context.getMetricsSystem(),
|
||||
context.getEthContext().getEthPeers().peerCount(),
|
||||
Optional.of(targetHash),
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -99,6 +99,7 @@ public class FullSyncDownloadPipelineFactory implements DownloadPipelineFactory
|
||||
protocolContext,
|
||||
ethContext,
|
||||
detachedValidationPolicy,
|
||||
syncConfig,
|
||||
headerRequestSize,
|
||||
metricsSystem);
|
||||
final RangeHeadersValidationStep validateHeadersJoinUpStep =
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user