Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement eth/67 sub protocol (EIP-4938) #4646

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Upgrade RocksDB version from 7.6.0 to 7.7.3
- Added new RPC endpoints `debug_setHead` & `debug_replayBlock [4580](https://github.com/hyperledger/besu/pull/4580)
- Upgrade OpenTelemetry to version 1.19.0 [#3675](https://github.com/hyperledger/besu/pull/3675)
- Implement Eth/67 sub-protocol [#4596](https://github.com/hyperledger/besu/issues/4596)

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
public class EthProtocol implements SubProtocol {
public static final String NAME = "eth";
private static final EthProtocol INSTANCE = new EthProtocol();

public static final Capability ETH62 = Capability.create(NAME, EthProtocolVersion.V62);
public static final Capability ETH63 = Capability.create(NAME, EthProtocolVersion.V63);
public static final Capability ETH64 = Capability.create(NAME, EthProtocolVersion.V64);
public static final Capability ETH65 = Capability.create(NAME, EthProtocolVersion.V65);
public static final Capability ETH66 = Capability.create(NAME, EthProtocolVersion.V66);
public static final Capability ETH67 = Capability.create(NAME, EthProtocolVersion.V67);

public static boolean requestIdCompatible(final int code) {
return Set.of(
Expand Down Expand Up @@ -66,6 +66,7 @@ public int messageSpace(final int protocolVersion) {
case EthProtocolVersion.V64:
case EthProtocolVersion.V65:
case EthProtocolVersion.V66:
case EthProtocolVersion.V67:
// same number of messages in each range, eth65 defines messages in the middle of the
// range defined by eth63 and eth64 defines no new ranges.
return 17;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class EthProtocolVersion {
public static final int V64 = 64;
public static final int V65 = 65;
public static final int V66 = 66;
public static final int V67 = 67;

/** eth/62 (2015) */
private static final List<Integer> eth62Messages =
Expand Down Expand Up @@ -89,6 +90,27 @@ public class EthProtocolVersion {
EthPV65.GET_POOLED_TRANSACTIONS,
EthPV65.POOLED_TRANSACTIONS);

/**
* eth/67 (EIP-4938, March 2022)
*
* <p>Version 67 removed the GetNodeData and NodeData messages.
*/
private static final List<Integer> eth67Messages =
List.of(
EthPV62.STATUS,
EthPV62.NEW_BLOCK_HASHES,
EthPV62.TRANSACTIONS,
EthPV62.GET_BLOCK_HEADERS,
EthPV62.BLOCK_HEADERS,
EthPV62.GET_BLOCK_BODIES,
EthPV62.BLOCK_BODIES,
EthPV62.NEW_BLOCK,
EthPV63.GET_RECEIPTS,
EthPV63.RECEIPTS,
EthPV65.NEW_POOLED_TRANSACTION_HASHES,
EthPV65.GET_POOLED_TRANSACTIONS,
EthPV65.POOLED_TRANSACTIONS);

/**
* Returns a list of integers containing the supported messages given the protocol version
*
Expand All @@ -105,6 +127,8 @@ public static List<Integer> getSupportedMessages(final int protocolVersion) {
case EthProtocolVersion.V65:
case EthProtocolVersion.V66:
return eth65Messages;
case EthProtocolVersion.V67:
return eth67Messages;
default:
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -210,6 +211,14 @@ private List<Capability> calculateCapabilities(
capabilities.add(EthProtocol.ETH65);
capabilities.add(EthProtocol.ETH66);

// Version 67 removes the GetNodeData and NodeData
// Fast sync depends on GetNodeData and NodeData
// Do not add eth/67 if fast sync is enabled
// see https://eips.ethereum.org/EIPS/eip-4938
if (!Objects.equals(SyncMode.FAST, synchronizerConfiguration.getSyncMode())) {
macfarla marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious to know why you are using Object.equals instead of just doing SyncMode.FAST == synchronizerConfiguration.getSyncMode()

capabilities.add(EthProtocol.ETH67);
}

return capabilities.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class EthProtocolTest {
@Test
public void eth66CheckShouldReturnTrueForCompatibleProtocols() {
assertThat(EthProtocol.isEth66Compatible(EthProtocol.ETH66)).isTrue();
assertThat(EthProtocol.isEth66Compatible(EthProtocol.ETH67)).isTrue();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage;
import org.hyperledger.besu.ethereum.eth.messages.StatusMessage;
import org.hyperledger.besu.ethereum.eth.messages.TransactionsMessage;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
Expand All @@ -80,6 +82,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -1117,4 +1120,40 @@ public void forkIdForChainHeadMayBeNull() {
assertThat(ethManager.getForkIdAsBytesList()).isEmpty();
}
}

@Test
public void shouldUseRightCapabilityDependingOnSyncMode() {
assertHighestCapability(SyncMode.X_SNAP, EthProtocol.ETH67);
assertHighestCapability(SyncMode.FULL, EthProtocol.ETH67);
assertHighestCapability(SyncMode.X_CHECKPOINT, EthProtocol.ETH67);
/* Eth67 does not support fast sync, see EIP-4938 */
assertHighestCapability(SyncMode.FAST, EthProtocol.ETH66);
macfarla marked this conversation as resolved.
Show resolved Hide resolved
}

private void assertHighestCapability(final SyncMode syncMode, final Capability capability) {
final SynchronizerConfiguration syncConfig = mock(SynchronizerConfiguration.class);
when(syncConfig.getSyncMode()).thenReturn(syncMode);
try (final EthProtocolManager ethManager =
new EthProtocolManager(
blockchain,
BigInteger.ONE,
mock(WorldStateArchive.class),
transactionPool,
EthProtocolConfiguration.defaultConfig(),
mock(EthPeers.class),
mock(EthMessages.class),
mock(EthContext.class),
Collections.emptyList(),
Optional.empty(),
syncConfig,
mock(EthScheduler.class),
mock(ForkIdManager.class))) {

final Capability highestCapability =
ethManager.getSupportedCapabilities().stream()
.max(Comparator.comparing(Capability::getVersion))
.get();
assertThat(capability.equals(highestCapability)).isTrue();
}
}
}