EIP-6122 Timestamp based fork IDs (#4841)

Signed-off-by: Jason Frame <jason.frame@consensys.net>
Co-authored-by: Jiri Peinlich <jiri.peinlich@gmail.com>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
pull/4854/head
Jason Frame 2 years ago committed by GitHub
parent 13213e2c7d
commit 38316ef188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  2. 3
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  3. 18
      besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java
  4. 3
      besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java
  5. 8
      config/src/main/java/org/hyperledger/besu/config/GenesisConfigFile.java
  6. 4
      config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java
  7. 15
      config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
  8. 7
      config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
  9. 22
      config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java
  10. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  11. 107
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java
  12. 15
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java
  13. 297
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTest.java
  14. 79
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdTestUtil.java
  15. 3
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/LegacyForkIdManager.java
  16. 9
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java
  17. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java
  18. 4
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTestUtil.java
  19. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java
  20. 17
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetwork.java
  21. 5
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/DefaultP2PNetworkTest.java
  22. 3
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/NetworkingServiceLifecycleTest.java
  23. 3
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PNetworkTest.java
  24. 3
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/network/P2PPlainNetworkTest.java

@ -498,7 +498,8 @@ public class RunnerBuilder {
.storageProvider(storageProvider)
.p2pTLSConfiguration(p2pTLSConfiguration)
.blockchain(context.getBlockchain())
.forks(besuController.getGenesisConfigOptions().getForks())
.blockNumberForks(besuController.getGenesisConfigOptions().getForkBlockNumbers())
.timestampForks(besuController.getGenesisConfigOptions().getForkBlockTimestamps())
.build();
final NetworkRunner networkRunner =

@ -636,7 +636,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
mergePeerFilter,
synchronizerConfiguration,
scheduler,
genesisConfig.getForks());
genesisConfig.getForkBlockNumbers(),
genesisConfig.getForkTimestamps());
}
protected ProtocolContext createProtocolContext(

@ -26,10 +26,10 @@ import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.MutableProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -47,7 +47,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Enclosed.class)
public class ForkIdsTest {
public class ForkIdsNetworkConfigTest {
public static class NotParameterized {
@Test
@ -192,19 +192,23 @@ public class ForkIdsTest {
MainnetProtocolSchedule.fromConfig(configOptions, EvmConfiguration.DEFAULT);
final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, schedule);
final Blockchain mockBlockchain = mock(Blockchain.class);
final BlockHeader mockBlockHeader = mock(BlockHeader.class);
when(mockBlockchain.getGenesisBlock()).thenReturn(genesisState.getBlock());
final AtomicLong blockNumber = new AtomicLong();
when(mockBlockchain.getChainHeadBlockNumber()).thenAnswer(o -> blockNumber.get());
when(mockBlockchain.getChainHeadHeader()).thenReturn(mockBlockHeader);
when(mockBlockHeader.getNumber()).thenAnswer(o -> blockNumber.get());
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain, genesisConfigFile.getForks(), false);
new ForkIdManager(
mockBlockchain,
genesisConfigFile.getForkBlockNumbers(),
genesisConfigFile.getForkTimestamps(),
false);
final var actualForkIds =
Streams.concat(
((MutableProtocolSchedule) schedule).streamMilestoneBlocks(),
Stream.of(Long.MAX_VALUE))
Streams.concat(schedule.streamMilestoneBlocks(), Stream.of(Long.MAX_VALUE))
.map(
block -> {
blockNumber.set(block);

@ -136,7 +136,8 @@ public final class RunnerBuilderTest {
when(besuController.getMiningCoordinator()).thenReturn(mock(MiningCoordinator.class));
when(besuController.getMiningCoordinator()).thenReturn(mock(MergeMiningCoordinator.class));
final GenesisConfigOptions genesisConfigOptions = mock(GenesisConfigOptions.class);
when(genesisConfigOptions.getForks()).thenReturn(Collections.emptyList());
when(genesisConfigOptions.getForkBlockNumbers()).thenReturn(Collections.emptyList());
when(genesisConfigOptions.getForkBlockTimestamps()).thenReturn(Collections.emptyList());
when(besuController.getGenesisConfigOptions()).thenReturn(genesisConfigOptions);
}

@ -199,7 +199,11 @@ public class GenesisConfigFile {
}
}
public List<Long> getForks() {
return getConfigOptions().getForks();
public List<Long> getForkBlockNumbers() {
return getConfigOptions().getForkBlockNumbers();
}
public List<Long> getForkTimestamps() {
return getConfigOptions().getForkBlockTimestamps();
}
}

@ -104,7 +104,9 @@ public interface GenesisConfigOptions {
Optional<Hash> getTerminalBlockHash();
List<Long> getForks();
List<Long> getForkBlockNumbers();
List<Long> getForkBlockTimestamps();
/**
* Block number for the Dao Fork, this value is used to tell node to connect with peer that did

@ -552,7 +552,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
}
@Override
public List<Long> getForks() {
public List<Long> getForkBlockNumbers() {
Stream<OptionalLong> forkBlockNumbers =
Stream.of(
getHomesteadBlockNumber(),
@ -590,4 +590,17 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
.sorted()
.collect(Collectors.toList());
}
@Override
public List<Long> getForkBlockTimestamps() {
Stream<OptionalLong> forkBlockTimestamps = Stream.of(getShanghaiTime(), getCancunTime());
// when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json
return forkBlockTimestamps
.filter(OptionalLong::isPresent)
.map(OptionalLong::getAsLong)
.distinct()
.sorted()
.collect(Collectors.toList());
}
}

@ -426,7 +426,12 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
}
@Override
public List<Long> getForks() {
public List<Long> getForkBlockNumbers() {
return Collections.emptyList();
}
@Override
public List<Long> getForkBlockTimestamps() {
return Collections.emptyList();
}

@ -252,7 +252,7 @@ public class GenesisConfigFileTest {
GenesisConfigFile mergeNetSplitGenesis =
GenesisConfigFile.fromConfig(
"{\"config\":{\"mergeNetsplitBlock\":11},\"baseFeePerGas\":\"0xa\"}");
assertThat(mergeNetSplitGenesis.getForks()).hasSize(1);
assertThat(mergeNetSplitGenesis.getForkBlockNumbers()).hasSize(1);
assertThat(mergeNetSplitGenesis.getConfigOptions().getMergeNetSplitBlockNumber()).isPresent();
assertThat(mergeNetSplitGenesis.getConfigOptions().getMergeNetSplitBlockNumber().getAsLong())
.isEqualTo(11L);
@ -260,7 +260,7 @@ public class GenesisConfigFileTest {
// assert empty if not present:
GenesisConfigFile londonGenesis =
GenesisConfigFile.fromConfig("{\"config\":{\"londonBlock\":11},\"baseFeePerGas\":\"0xa\"}");
assertThat(londonGenesis.getForks()).hasSize(1);
assertThat(londonGenesis.getForkBlockNumbers()).hasSize(1);
assertThat(londonGenesis.getConfigOptions().getMergeNetSplitBlockNumber()).isEmpty();
}
@ -355,7 +355,7 @@ public class GenesisConfigFileTest {
override.put("chainId", bigBlockString);
override.put("contractSizeLimit", bigBlockString);
assertThat(config.getForks()).isNotEmpty();
assertThat(config.getForkBlockNumbers()).isNotEmpty();
assertThat(config.getConfigOptions(override).getIstanbulBlockNumber()).hasValue(bigBlock);
assertThat(config.getConfigOptions(override).getChainId())
.hasValue(BigInteger.valueOf(bigBlock));
@ -370,7 +370,7 @@ public class GenesisConfigFileTest {
override.put("chainId", null);
override.put("contractSizeLimit", null);
assertThat(config.getForks()).isNotEmpty();
assertThat(config.getForkBlockNumbers()).isNotEmpty();
assertThat(config.getConfigOptions(override).getIstanbulBlockNumber()).isNotPresent();
assertThat(config.getConfigOptions(override).getChainId()).isNotPresent();
assertThat(config.getConfigOptions(override).getContractSizeLimit()).isNotPresent();
@ -454,7 +454,7 @@ public class GenesisConfigFileTest {
final GenesisConfigFile config = fromConfig(configNode);
assertThat(config.getForks()).containsExactly(1L, 2L, 3L, 1035301L, 2222222L);
assertThat(config.getForkBlockNumbers()).containsExactly(1L, 2L, 3L, 1035301L, 2222222L);
assertThat(config.getConfigOptions().getChainId()).hasValue(BigInteger.valueOf(4));
}
@ -474,7 +474,7 @@ public class GenesisConfigFileTest {
StandardCharsets.UTF_8)));
final GenesisConfigFile config = fromConfig(configNode);
assertThat(config.getForks()).containsExactly(1L, 2L, 3L, 1035301L);
assertThat(config.getForkBlockNumbers()).containsExactly(1L, 2L, 3L, 1035301L);
assertThat(config.getConfigOptions().getChainId()).hasValue(BigInteger.valueOf(61));
}
@ -522,10 +522,12 @@ public class GenesisConfigFileTest {
final GenesisConfigFile configFileMultipleUnexpectedForks =
fromConfig(configMultipleUnexpectedForks);
assertThat(configFileNoUnexpectedForks.getForks()).containsExactly(1L, 2L, 3L, 1035301L);
assertThat(configFileNoUnexpectedForks.getForks()).isEqualTo(configFileClassicFork.getForks());
assertThat(configFileNoUnexpectedForks.getForks())
.isEqualTo(configFileMultipleUnexpectedForks.getForks());
assertThat(configFileNoUnexpectedForks.getForkBlockNumbers())
.containsExactly(1L, 2L, 3L, 1035301L);
assertThat(configFileNoUnexpectedForks.getForkBlockNumbers())
.isEqualTo(configFileClassicFork.getForkBlockNumbers());
assertThat(configFileNoUnexpectedForks.getForkBlockNumbers())
.isEqualTo(configFileMultipleUnexpectedForks.getForkBlockNumbers());
assertThat(configFileNoUnexpectedForks.getConfigOptions().getChainId())
.hasValue(BigInteger.valueOf(61));
}

@ -278,7 +278,8 @@ public class JsonRpcHttpServiceRpcApisTest {
.metricsSystem(new NoOpMetricsSystem())
.storageProvider(new InMemoryKeyValueStorageProvider())
.blockchain(blockchain)
.forks(Collections.emptyList())
.blockNumberForks(Collections.emptyList())
.timestampForks(Collections.emptyList())
.build();
p2pNetwork.start();

@ -19,12 +19,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.util.EndianUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.CRC32;
import com.google.common.annotations.VisibleForTesting;
@ -34,10 +36,14 @@ import org.apache.tuweni.bytes.Bytes32;
public class ForkIdManager {
private final Hash genesisHash;
private final List<ForkId> forkIds;
private final List<ForkId> blockNumbersForkIds;
private final List<ForkId> timestampsForkIds;
private final List<ForkId> allForkIds;
private final List<Long> forkBlockNumbers;
private final LongSupplier chainHeadSupplier;
private final List<Long> blockNumberForks;
private final List<Long> timestampForks;
private final Supplier<BlockHeader> chainHeadSupplier;
private final long forkNext;
private final boolean onlyZerosForkBlocks;
private final long highestKnownFork;
@ -45,41 +51,66 @@ public class ForkIdManager {
private final boolean legacyEth64;
public ForkIdManager(
final Blockchain blockchain, final List<Long> nonFilteredForks, final boolean legacyEth64) {
final Blockchain blockchain,
final List<Long> blockNumberForks,
final List<Long> timestampForks,
final boolean legacyEth64) {
checkNotNull(blockchain);
checkNotNull(nonFilteredForks);
this.chainHeadSupplier = blockchain::getChainHeadBlockNumber;
checkNotNull(blockNumberForks);
this.chainHeadSupplier = blockchain::getChainHeadHeader;
this.genesisHash = blockchain.getGenesisBlock().getHash();
this.forkIds = new ArrayList<>();
this.blockNumbersForkIds = new ArrayList<>();
this.timestampsForkIds = new ArrayList<>();
this.legacyEth64 = legacyEth64;
this.forkBlockNumbers =
nonFilteredForks.stream()
this.blockNumberForks =
blockNumberForks.stream()
.filter(fork -> fork > 0L)
.distinct()
.sorted()
.collect(Collectors.toUnmodifiableList());
this.timestampForks =
timestampForks.stream()
.filter(fork -> fork > 0L)
.distinct()
.sorted()
.collect(Collectors.toUnmodifiableList());
this.onlyZerosForkBlocks = nonFilteredForks.stream().allMatch(value -> 0L == value);
final List<Long> allForkNumbers =
Stream.concat(blockNumberForks.stream(), timestampForks.stream())
.collect(Collectors.toList());
this.onlyZerosForkBlocks = allForkNumbers.stream().allMatch(value -> 0L == value);
this.forkNext = createForkIds();
this.allForkIds =
Stream.concat(blockNumbersForkIds.stream(), timestampsForkIds.stream())
.collect(Collectors.toList());
this.highestKnownFork =
!forkBlockNumbers.isEmpty() ? forkBlockNumbers.get(forkBlockNumbers.size() - 1) : 0L;
!allForkNumbers.isEmpty() ? allForkNumbers.get(allForkNumbers.size() - 1) : 0L;
}
public ForkId getForkIdForChainHead() {
if (legacyEth64) {
return forkIds.isEmpty() ? null : forkIds.get(forkIds.size() - 1);
return blockNumbersForkIds.isEmpty()
? null
: blockNumbersForkIds.get(blockNumbersForkIds.size() - 1);
}
final BlockHeader header = chainHeadSupplier.get();
for (final ForkId forkId : blockNumbersForkIds) {
if (header.getNumber() < forkId.getNext()) {
return forkId;
}
}
final long head = chainHeadSupplier.getAsLong();
for (final ForkId forkId : forkIds) {
if (head < forkId.getNext()) {
for (final ForkId forkId : timestampsForkIds) {
if (header.getTimestamp() < forkId.getNext()) {
return forkId;
}
}
return forkIds.isEmpty() ? new ForkId(genesisHashCrc, 0) : forkIds.get(forkIds.size() - 1);
return allForkIds.isEmpty()
? new ForkId(genesisHashCrc, 0)
: allForkIds.get(allForkIds.size() - 1);
}
@VisibleForTesting
public List<ForkId> getForkIds() {
return this.forkIds;
public List<ForkId> getAllForkIds() {
return allForkIds;
}
public static ForkId readFrom(final RLPInput in) {
@ -119,7 +150,12 @@ public class ForkIdManager {
if (!isHashKnown(forkId.getHash())) {
return false;
}
return chainHeadSupplier.getAsLong() < forkNext
final BlockHeader header = chainHeadSupplier.get();
final long forkValue =
blockNumberForks.contains(forkNext) ? header.getNumber() : header.getTimestamp();
return forkValue < forkNext
|| (isForkKnown(forkId.getNext())
&& isRemoteAwareOfPresent(forkId.getHash(), forkId.getNext()));
}
@ -135,16 +171,16 @@ public class ForkIdManager {
}
private boolean isHashKnown(final Bytes forkHash) {
return forkIds.stream().map(ForkId::getHash).anyMatch(hash -> hash.equals(forkHash));
return allForkIds.stream().map(ForkId::getHash).anyMatch(hash -> hash.equals(forkHash));
}
private boolean isForkKnown(final Long nextFork) {
return highestKnownFork < nextFork
|| forkIds.stream().map(ForkId::getNext).anyMatch(fork -> fork.equals(nextFork));
|| allForkIds.stream().map(ForkId::getNext).anyMatch(fork -> fork.equals(nextFork));
}
private boolean isRemoteAwareOfPresent(final Bytes forkHash, final Long nextFork) {
for (final ForkId j : forkIds) {
for (final ForkId j : getAllForkIds()) {
if (forkHash.equals(j.getHash())) {
if (nextFork.equals(j.getNext())) {
return true;
@ -163,20 +199,33 @@ public class ForkIdManager {
crc.update(genesisHash.toArray());
genesisHashCrc = getCurrentCrcHash(crc);
final List<Bytes> forkHashes = new ArrayList<>(List.of(genesisHashCrc));
forkBlockNumbers.forEach(
blockNumberForks.forEach(
fork -> {
updateCrc(crc, fork);
forkHashes.add(getCurrentCrcHash(crc));
});
timestampForks.forEach(
fork -> {
updateCrc(crc, fork);
forkHashes.add(getCurrentCrcHash(crc));
});
// This loop is for all the fork hashes that have an associated "next fork"
for (int i = 0; i < forkBlockNumbers.size(); i++) {
forkIds.add(new ForkId(forkHashes.get(i), forkBlockNumbers.get(i)));
for (int i = 0; i < blockNumberForks.size(); i++) {
blockNumbersForkIds.add(new ForkId(forkHashes.get(i), blockNumberForks.get(i)));
}
for (int i = 0; i < timestampForks.size(); i++) {
timestampsForkIds.add(
new ForkId(forkHashes.get(blockNumberForks.size() + i), timestampForks.get(i)));
}
long forkNext = 0;
if (!forkBlockNumbers.isEmpty()) {
forkNext = forkIds.get(forkIds.size() - 1).getNext();
forkIds.add(new ForkId(forkHashes.get(forkHashes.size() - 1), 0));
if (!timestampForks.isEmpty()) {
forkNext = timestampForks.get(timestampForks.size() - 1);
timestampsForkIds.add(new ForkId(forkHashes.get(forkHashes.size() - 1), 0));
} else if (!blockNumberForks.isEmpty()) {
forkNext = blockNumbersForkIds.get(blockNumbersForkIds.size() - 1).getNext();
blockNumbersForkIds.add(new ForkId(forkHashes.get(forkHashes.size() - 1), 0));
}
return forkNext;
}

@ -12,17 +12,15 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth;
package org.hyperledger.besu.ethereum.forkid;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.GenesisHash;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.mockBlockchain;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.GenesisHash;
import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.mockBlockchain;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
@ -117,10 +115,11 @@ public class ForkIdBackwardCompatibilityTest {
public void assertBackwardCompatibilityWorks() {
LOG.info("Running test case {}", name);
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain(genesisHash, head), forks, legacyEth64);
new ForkIdManager(
mockBlockchain(genesisHash, head, 0), forks, Collections.emptyList(), legacyEth64);
final ForkId legacyForkId =
legacyEth64
? new LegacyForkIdManager(mockBlockchain(genesisHash, head), forks).getLatestForkId()
? new LegacyForkIdManager(mockBlockchain(genesisHash, head, 0), forks).getLatestForkId()
: null;
assertThat(forkIdManager.getForkIdForChainHead())
.isEqualTo(legacyEth64 ? legacyForkId : wantForkId);

@ -12,21 +12,19 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth.manager;
package org.hyperledger.besu.ethereum.forkid;
import static com.google.common.primitives.Longs.asList;
import static java.util.Collections.emptyList;
import static java.util.Optional.empty;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.mockBlockchain;
import static org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.wantPeerCheck;
import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.mockBlockchain;
import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.wantPeerCheck;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.ForkIds;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.GenesisHash;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.Network;
import org.hyperledger.besu.ethereum.eth.ForkIdTestUtil.PeerCheckCase;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.forkid.ForkIdManager;
import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.ForkIds;
import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.GenesisHash;
import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.Network;
import org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.PeerCheckCase;
import java.util.Arrays;
import java.util.Collection;
@ -42,8 +40,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(Parameterized.class)
public class EIP2124Test {
private static final Logger LOG = LoggerFactory.getLogger(EIP2124Test.class);
public class ForkIdTest {
private static final Logger LOG = LoggerFactory.getLogger(ForkIdTest.class);
@Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() {
@ -54,6 +52,7 @@ public class EIP2124Test {
"Mainnet // Unsynced",
Network.MAINNET,
0L,
0L,
ForkIdTestUtil.wantForkId("0xfc64ec04", 1150000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -62,6 +61,7 @@ public class EIP2124Test {
"Mainnet // First Homestead block",
Network.MAINNET,
1150000L,
0L,
ForkIdTestUtil.wantForkId("0x97c2c34c", 1920000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -70,6 +70,7 @@ public class EIP2124Test {
"Mainnet // Last Homestead block",
Network.MAINNET,
1919999L,
0L,
ForkIdTestUtil.wantForkId("0x97c2c34c", 1920000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -78,6 +79,7 @@ public class EIP2124Test {
"Mainnet // First DAO block",
Network.MAINNET,
1920000L,
0L,
ForkIdTestUtil.wantForkId("0x91d1f948", 2463000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -86,6 +88,7 @@ public class EIP2124Test {
"Mainnet // Last DAO block",
Network.MAINNET,
2462999L,
0L,
ForkIdTestUtil.wantForkId("0x91d1f948", 2463000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -94,6 +97,7 @@ public class EIP2124Test {
"Mainnet // First Tangerine block",
Network.MAINNET,
2463000L,
0L,
ForkIdTestUtil.wantForkId("0x7a64da13", 2675000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -102,6 +106,7 @@ public class EIP2124Test {
"Mainnet // Last Tangerine block",
Network.MAINNET,
2674999L,
0L,
ForkIdTestUtil.wantForkId("0x7a64da13", 2675000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -110,6 +115,7 @@ public class EIP2124Test {
"Mainnet // First Spurious block",
Network.MAINNET,
2675000L,
0L,
ForkIdTestUtil.wantForkId("0x3edd5b10", 4370000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -118,6 +124,7 @@ public class EIP2124Test {
"Mainnet // Last Spurious block",
Network.MAINNET,
4369999L,
0L,
ForkIdTestUtil.wantForkId("0x3edd5b10", 4370000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -126,6 +133,7 @@ public class EIP2124Test {
"Mainnet // First Byzantium block",
Network.MAINNET,
4370000L,
0L,
ForkIdTestUtil.wantForkId("0xa00bc324", 7280000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -134,6 +142,7 @@ public class EIP2124Test {
"Mainnet // Last Byzantium block",
Network.MAINNET,
7279999L,
0L,
ForkIdTestUtil.wantForkId("0xa00bc324", 7280000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -142,6 +151,7 @@ public class EIP2124Test {
"Mainnet // First and last Constantinople, first Petersburg block",
Network.MAINNET,
7280000L,
0L,
ForkIdTestUtil.wantForkId("0x668db0af", 9069000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -150,6 +160,7 @@ public class EIP2124Test {
"Mainnet // Last Petersburg block",
Network.MAINNET,
9068999L,
0L,
ForkIdTestUtil.wantForkId("0x668db0af", 9069000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -158,6 +169,7 @@ public class EIP2124Test {
"Mainnet // First Istanbul block",
Network.MAINNET,
9069000L,
0L,
ForkIdTestUtil.wantForkId("0x879d6e30", 9200000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -166,6 +178,7 @@ public class EIP2124Test {
"Mainnet // Last Istanbul block",
Network.MAINNET,
9199999L,
0L,
ForkIdTestUtil.wantForkId("0x879d6e30", 9200000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -174,6 +187,7 @@ public class EIP2124Test {
"Mainnet // First Muir Glacier block",
Network.MAINNET,
9200000L,
0L,
ForkIdTestUtil.wantForkId("0xe029e991", 12244000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -182,6 +196,7 @@ public class EIP2124Test {
"Mainnet // Last Muir Glacier block",
Network.MAINNET,
12243999L,
0L,
ForkIdTestUtil.wantForkId("0xe029e991", 12244000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -190,6 +205,7 @@ public class EIP2124Test {
"Mainnet // First Berlin block",
Network.MAINNET,
12244000L,
0L,
ForkIdTestUtil.wantForkId("0x0eb440f6", 12965000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -198,6 +214,7 @@ public class EIP2124Test {
"Mainnet // Last Berlin block",
Network.MAINNET,
12964999L,
0L,
ForkIdTestUtil.wantForkId("0x0eb440f6", 12965000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -206,6 +223,7 @@ public class EIP2124Test {
"Mainnet // First London block",
Network.MAINNET,
12965000L,
0L,
ForkIdTestUtil.wantForkId("0xb715077d", 13773000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -214,6 +232,7 @@ public class EIP2124Test {
"Mainnet // Last London block",
Network.MAINNET,
13772999L,
0L,
ForkIdTestUtil.wantForkId("0xb715077d", 13773000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -222,6 +241,7 @@ public class EIP2124Test {
"Mainnet // First Arrow Glacier block",
Network.MAINNET,
13773000L,
0L,
ForkIdTestUtil.wantForkId("0x20c327fc", 15050000L),
Optional.of(ForkIds.MAINNET),
empty()
@ -230,6 +250,7 @@ public class EIP2124Test {
"Mainnet // First Gray Glacier block",
Network.MAINNET,
15050000L,
0L,
ForkIdTestUtil.wantForkId("0xf0afd0e3", 0L),
Optional.of(ForkIds.MAINNET),
empty()
@ -238,15 +259,55 @@ public class EIP2124Test {
"Mainnet // Future Gray Glacier block",
Network.MAINNET,
20000000L,
0L,
ForkIdTestUtil.wantForkId("0xf0afd0e3", 0L),
Optional.of(ForkIds.MAINNET),
empty()
},
// Fork ID test cases with block number and timestamp based forks
// Withdrawals test cases
{
"Mainnet Withdrawals // First Merge Start block",
Network.MAINNET_WITH_SHANGHAI,
18000000L,
0L,
ForkIdTestUtil.wantForkId("0x4fb8a872", 1668000000L),
Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS),
empty()
},
{
"Mainnet Withdrawals // Last Merge Start block",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
0L,
ForkIdTestUtil.wantForkId("0x4fb8a872", 1668000000L),
Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS),
empty()
},
{
"Mainnet Withdrawals // First Shanghai block",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000000L,
ForkIdTestUtil.wantForkId("0xc1fdf181", 0L),
Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS),
empty()
},
{
"Mainnet Withdrawals // Last Shanghai block",
Network.MAINNET_WITH_SHANGHAI,
20100000L,
2669000000L,
ForkIdTestUtil.wantForkId("0xc1fdf181", 0L),
Optional.of(ForkIdTestUtil.ForkIds.WITHDRAWALS),
empty()
},
// Ropsten test cases
{
"Ropsten // Unsynced, last Frontier, Homestead and first Tangerine block",
Network.ROPSTEN,
0L,
0L,
ForkIdTestUtil.wantForkId("0x30c7ddbc", 10L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -255,6 +316,7 @@ public class EIP2124Test {
"Ropsten // Last Tangerine block",
Network.ROPSTEN,
9L,
0L,
ForkIdTestUtil.wantForkId("0x30c7ddbc", 10L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -263,6 +325,7 @@ public class EIP2124Test {
"Ropsten // First Spurious block",
Network.ROPSTEN,
10L,
0L,
ForkIdTestUtil.wantForkId("0x63760190", 1700000L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -271,6 +334,7 @@ public class EIP2124Test {
"Ropsten // Last Spurious block",
Network.ROPSTEN,
1699999L,
0L,
ForkIdTestUtil.wantForkId("0x63760190", 1700000L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -279,6 +343,7 @@ public class EIP2124Test {
"Ropsten // First Byzantium block",
Network.ROPSTEN,
1700000L,
0L,
ForkIdTestUtil.wantForkId("0x3ea159c7", 4230000L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -287,6 +352,7 @@ public class EIP2124Test {
"Ropsten // First Byzantium block",
Network.ROPSTEN,
4229999L,
0L,
ForkIdTestUtil.wantForkId("0x3ea159c7", 4230000L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -295,6 +361,7 @@ public class EIP2124Test {
"Ropsten // First Constantinople block",
Network.ROPSTEN,
4230000L,
0L,
ForkIdTestUtil.wantForkId("0x97b544f3", 4939394L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -303,6 +370,7 @@ public class EIP2124Test {
"Ropsten // Last Constantinople block",
Network.ROPSTEN,
4939393L,
0L,
ForkIdTestUtil.wantForkId("0x97b544f3", 4939394L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -311,6 +379,7 @@ public class EIP2124Test {
"Ropsten // First Petersburg block",
Network.ROPSTEN,
4939394L,
0L,
ForkIdTestUtil.wantForkId("0xd6e2149b", 6485846L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -319,6 +388,7 @@ public class EIP2124Test {
"Ropsten // Last Petersburg block",
Network.ROPSTEN,
6485845L,
0L,
ForkIdTestUtil.wantForkId("0xd6e2149b", 6485846L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -327,6 +397,7 @@ public class EIP2124Test {
"Ropsten // First Istanbul block",
Network.ROPSTEN,
6485846L,
0L,
ForkIdTestUtil.wantForkId("0x4bc66396", 7117117L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -335,6 +406,7 @@ public class EIP2124Test {
"Ropsten // Last Istanbul block",
Network.ROPSTEN,
7117116L,
0L,
ForkIdTestUtil.wantForkId("0x4bc66396", 7117117L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -343,6 +415,7 @@ public class EIP2124Test {
"Ropsten // First Muir Glacier block",
Network.ROPSTEN,
7117117L,
0L,
ForkIdTestUtil.wantForkId("0x6727ef90", 0L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -351,6 +424,7 @@ public class EIP2124Test {
"Ropsten // Future",
Network.ROPSTEN,
7500000L,
0L,
ForkIdTestUtil.wantForkId("0x6727ef90", 0L),
Optional.of(ForkIds.ROPSTEN),
empty()
@ -360,6 +434,7 @@ public class EIP2124Test {
"Sepolia // mergenetsplit block",
Network.SEPOLIA,
0L,
0L,
ForkIdTestUtil.wantForkId("0xfe3366e7", 1735371L),
Optional.of(ForkIds.SEPOLIA),
empty()
@ -368,6 +443,7 @@ public class EIP2124Test {
"Sepolia // Future",
Network.SEPOLIA,
1735371L,
0L,
ForkIdTestUtil.wantForkId("0xb96cbd13", 0L),
Optional.of(ForkIds.SEPOLIA),
empty()
@ -377,6 +453,7 @@ public class EIP2124Test {
"Rinkeby // Unsynced, last Frontier block",
Network.RINKEBY,
0L,
0L,
ForkIdTestUtil.wantForkId("0x3b8e0691", 1L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -385,6 +462,7 @@ public class EIP2124Test {
"Rinkeby // First and last Homestead block",
Network.RINKEBY,
1L,
0L,
ForkIdTestUtil.wantForkId("0x60949295", 2L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -393,6 +471,7 @@ public class EIP2124Test {
"Rinkeby // First and last Tangerine block",
Network.RINKEBY,
2L,
0L,
ForkIdTestUtil.wantForkId("0x8bde40dd", 3L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -401,6 +480,7 @@ public class EIP2124Test {
"Rinkeby // First Spurious block",
Network.RINKEBY,
3L,
0L,
ForkIdTestUtil.wantForkId("0xcb3a64bb", 1035301L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -409,6 +489,7 @@ public class EIP2124Test {
"Rinkeby // Last Spurious block",
Network.RINKEBY,
1035300L,
0L,
ForkIdTestUtil.wantForkId("0xcb3a64bb", 1035301L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -417,6 +498,7 @@ public class EIP2124Test {
"Rinkeby // First Byzantium block",
Network.RINKEBY,
1035301L,
0L,
ForkIdTestUtil.wantForkId("0x8d748b57", 3660663L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -425,6 +507,7 @@ public class EIP2124Test {
"Rinkeby // Last Byzantium block",
Network.RINKEBY,
3660662L,
0L,
ForkIdTestUtil.wantForkId("0x8d748b57", 3660663L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -433,6 +516,7 @@ public class EIP2124Test {
"Rinkeby // First Constantinople block",
Network.RINKEBY,
3660663L,
0L,
ForkIdTestUtil.wantForkId("0xe49cab14", 4321234L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -441,6 +525,7 @@ public class EIP2124Test {
"Rinkeby // Last Constantinople block",
Network.RINKEBY,
4321233L,
0L,
ForkIdTestUtil.wantForkId("0xe49cab14", 4321234L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -449,6 +534,7 @@ public class EIP2124Test {
"Rinkeby // First Petersburg block",
Network.RINKEBY,
4321234L,
0L,
ForkIdTestUtil.wantForkId("0xafec6b27", 5435345L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -457,6 +543,7 @@ public class EIP2124Test {
"Rinkeby // Last Petersburg block",
Network.RINKEBY,
5435344L,
0L,
ForkIdTestUtil.wantForkId("0xafec6b27", 5435345L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -465,6 +552,7 @@ public class EIP2124Test {
"Rinkeby // First Istanbul block",
Network.RINKEBY,
5435345L,
0L,
ForkIdTestUtil.wantForkId("0xcbdb8838", 0L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -473,6 +561,7 @@ public class EIP2124Test {
"Rinkeby // Future Istanbul block",
Network.RINKEBY,
6000000L,
0L,
ForkIdTestUtil.wantForkId("0xcbdb8838", 0L),
Optional.of(ForkIds.RINKEBY),
empty()
@ -482,6 +571,7 @@ public class EIP2124Test {
"Goerli // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block",
Network.GOERLI,
0L,
0L,
ForkIdTestUtil.wantForkId("0xa3f5ab08", 1561651L),
Optional.of(ForkIds.GOERLI),
empty()
@ -490,6 +580,7 @@ public class EIP2124Test {
"Goerli // Last Petersburg block",
Network.GOERLI,
1561650L,
0L,
ForkIdTestUtil.wantForkId("0xa3f5ab08", 1561651L),
Optional.of(ForkIds.GOERLI),
empty()
@ -498,6 +589,7 @@ public class EIP2124Test {
"Goerli // First Istanbul block",
Network.GOERLI,
1561651L,
0L,
ForkIdTestUtil.wantForkId("0xc25efa5c", 0L),
Optional.of(ForkIds.GOERLI),
empty()
@ -506,6 +598,7 @@ public class EIP2124Test {
"Goerli // Future Istanbul block",
Network.GOERLI,
2000000L,
0L,
ForkIdTestUtil.wantForkId("0xc25efa5c", 0L),
Optional.of(ForkIds.GOERLI),
empty()
@ -515,6 +608,7 @@ public class EIP2124Test {
"Shandong // Unsynced",
Network.SHANDONG,
0L,
0L,
ForkIdTestUtil.wantForkId("0xc42480d3", 0L),
empty(),
empty()
@ -523,6 +617,7 @@ public class EIP2124Test {
"Shandong // First block",
Network.SHANDONG,
1L,
0L,
ForkIdTestUtil.wantForkId("0xc42480d3", 0L),
empty(),
empty()
@ -531,6 +626,7 @@ public class EIP2124Test {
"Shandong // Future block",
Network.SHANDONG,
1000000L,
0L,
ForkIdTestUtil.wantForkId("0xc42480d3", 0L),
empty(),
empty()
@ -540,6 +636,7 @@ public class EIP2124Test {
"Private // Unsynced",
Network.PRIVATE,
0L,
0L,
ForkIdTestUtil.wantForkId("0x190a55ad", 0L),
empty(),
empty()
@ -548,6 +645,7 @@ public class EIP2124Test {
"Private // First block",
Network.PRIVATE,
1L,
0L,
ForkIdTestUtil.wantForkId("0x190a55ad", 0L),
empty(),
empty()
@ -556,6 +654,7 @@ public class EIP2124Test {
"Private // Future block",
Network.PRIVATE,
1000000L,
0L,
ForkIdTestUtil.wantForkId("0x190a55ad", 0L),
empty(),
empty()
@ -565,6 +664,7 @@ public class EIP2124Test {
"check1PetersburgWithRemoteAnnouncingTheSame",
Network.MAINNET,
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0x668db0af", 0L, true)
@ -573,6 +673,7 @@ public class EIP2124Test {
"check2PetersburgWithRemoteAnnouncingTheSameAndNextFork",
Network.MAINNET,
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0x668db0af", Long.MAX_VALUE, true)
@ -581,6 +682,7 @@ public class EIP2124Test {
"check3ByzantiumAwareOfPetersburgRemoteUnawareOfPetersburg",
Network.MAINNET,
7279999L,
0L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, true)
@ -589,6 +691,7 @@ public class EIP2124Test {
"check4ByzantiumAwareOfPetersburgRemoteAwareOfPetersburg",
Network.MAINNET,
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 7280000L, true)
@ -597,6 +700,7 @@ public class EIP2124Test {
"check5ByzantiumAwareOfPetersburgRemoteAnnouncingUnknownFork",
Network.MAINNET,
7279999L,
0L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true)
@ -605,6 +709,7 @@ public class EIP2124Test {
"check6PetersburgWithRemoteAnnouncingByzantiumAwareOfPetersburg",
Network.MAINNET,
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0x668db0af", 7280000L, true)
@ -613,6 +718,7 @@ public class EIP2124Test {
"check7PetersburgWithRemoteAnnouncingSpuriousAwareOfByzantiumRemoteMayNeedUpdate",
Network.MAINNET,
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0x3edd5b10", 4370000L, true)
@ -621,6 +727,7 @@ public class EIP2124Test {
"check8ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync",
Network.MAINNET,
727999L,
0L,
empty(),
empty(),
wantPeerCheck("0x668db0af", 0L, true)
@ -629,6 +736,7 @@ public class EIP2124Test {
"check9SpuriousWithRemoteAnnouncingByzantiumRemoteUnawareOfPetersburg",
Network.MAINNET,
4369999L,
0L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, true)
@ -637,8 +745,10 @@ public class EIP2124Test {
"check10PetersburgWithRemoteAnnouncingByzantiumRemoteUnawareOfAdditionalForks",
Network.network(
GenesisHash.MAINNET,
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)),
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L),
emptyList()),
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, false)
@ -647,8 +757,10 @@ public class EIP2124Test {
"check11PetersburgWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate",
Network.network(
GenesisHash.MAINNET,
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)),
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L),
emptyList()),
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0x5cddc0e1", 0L, false)
@ -657,8 +769,10 @@ public class EIP2124Test {
"check12ByzantiumWithRemoteAnnouncingPetersburgAndFutureForkLocalNeedsUpdate",
ForkIdTestUtil.Network.network(
GenesisHash.MAINNET,
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)),
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L),
emptyList()),
7279999L,
0L,
empty(),
empty(),
wantPeerCheck("0x5cddc0e1", 0L, false)
@ -667,11 +781,149 @@ public class EIP2124Test {
"check13ByzantiumWithRemoteAnnouncingRinkebyPetersburg",
Network.network(
GenesisHash.MAINNET,
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L)),
asList(1150000L, 1920000L, 2463000L, 2675000L, 4370000L, 7280000L),
emptyList()),
7987396L,
0L,
empty(),
empty(),
wantPeerCheck("0xafec6b27", 0L, false)
},
// Timestamp based peer check cases adapted from EIP-6122 test cases
{
"withdrawalsCheck1ShanghaiWithRemoteAnnouncingTheSame",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xc1fdf181", 0L, true)
},
{
"withdrawalsCheck2ShanghaiWithRemoteAnnouncingSameAndNextFork",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xc1fdf181", Long.MAX_VALUE, true)
},
{
"withdrawalsCheck3ByzantiumWithRemoteAnnouncingByzantiumNotAwareOfPetersburg",
Network.MAINNET_WITH_SHANGHAI,
7279999L,
1667999999L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, true)
},
{
"withdrawalsCheck4ByzantiumWithRemoteAnnouncingByzantiumAwareOfPetersburg",
Network.MAINNET_WITH_SHANGHAI,
7279999L,
1667999999L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 7280000L, true)
},
{
"withdrawalsCheck5ByzantiumWithRemoteAnnouncingByzantiumAwareOfUnknownFork",
Network.MAINNET_WITH_SHANGHAI,
7279999L,
1667999999L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", Long.MAX_VALUE, true)
},
{
"withdrawalsCheck6ExactlyShanghaiWithRemoteAnnouncingByzantiumAwareOfPetersburgRemoteOutOfSync",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000000L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 7280000L, true)
},
{
"withdrawalsCheck7ShanghaiWithRemoteAnnouncingByzantiumAwareOfPetersburgRemoteOutOfSync",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 7280000L, true)
},
{
"withdrawalsCheck8ShanghaiWithRemoteAnnouncingSpuriousAwareOfByzantium",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0x3edd5b10", 4370000, true)
},
{
"withdrawalsCheck9ByzantiumWithRemoteAnnouncingPetersburgLocalOutOfSync",
Network.MAINNET_WITH_SHANGHAI,
7279999L,
1667999999L,
empty(),
empty(),
wantPeerCheck("0x668db0af", 4370000, true)
},
{
"withdrawalsCheck10SpuriousWithRemoteAnnouncingByzantiumNotAwareOfPetersburgLocalOutOfSync",
Network.MAINNET_WITH_SHANGHAI,
4369999L,
1667999999L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, true)
},
{
"withdrawalsCheck11ShanghaiWithRemoteAnnouncingByzantiumUnawareOfAdditionalForksRemoteNeedsUpdate",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 0L, false)
},
{
"withdrawalsCheck12ShanghaiAndNotAwareOfAdditionalForksWithRemoteAnnouncingPetersburgAndUnknownFork",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0x5cddc0e1", 0L, false)
},
{
"withdrawalsCheck13ShanghaiWithRemoteAnnouncingRinkebyPetersburg",
Network.MAINNET_WITH_SHANGHAI,
20000000L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xafec6b27", 0L, false)
},
{
"withdrawalsCheck14ShanghaiWithRemoteAnnouncingUnknownFork",
Network.MAINNET_WITH_SHANGHAI,
88888888L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xf0afd0e3", 88888888L, false)
},
{
"withdrawalsCheck15ShanghaiWithRemoteInByzantiumAnnouncingUnknownFork",
Network.MAINNET_WITH_SHANGHAI,
88888888L,
1668000001L,
empty(),
empty(),
wantPeerCheck("0xa00bc324", 7279999L, false)
}
});
}
@ -679,6 +931,7 @@ public class EIP2124Test {
private final String name;
private final Network network;
private final long head;
private final long time;
private final Optional<ForkId> wantForkId;
private final Optional<List<ForkId>> wantForkIds;
private final Optional<PeerCheckCase> wantPeerCheckCase;
@ -687,11 +940,15 @@ public class EIP2124Test {
public void test() {
LOG.info("Running test case {}", name);
final ForkIdManager forkIdManager =
new ForkIdManager(mockBlockchain(network.hash, head), network.forks, false);
new ForkIdManager(
mockBlockchain(network.hash, head, time),
network.blockForks,
network.timestampForks,
false);
wantForkId.ifPresent(
forkId -> assertThat(forkIdManager.getForkIdForChainHead()).isEqualTo(forkId));
wantForkIds.ifPresent(
forkIds -> assertThat(forkIdManager.getForkIds()).containsExactlyElementsOf(forkIds));
forkIds -> assertThat(forkIdManager.getAllForkIds()).containsExactlyElementsOf(forkIds));
wantPeerCheckCase.ifPresent(
peerCheckCase ->
assertThat(
@ -702,16 +959,18 @@ public class EIP2124Test {
.isEqualTo(peerCheckCase.want));
}
public EIP2124Test(
public ForkIdTest(
final String name,
final ForkIdTestUtil.Network network,
final long head,
final long time,
final Optional<ForkId> wantForkId,
final Optional<List<ForkId>> wantForkIds,
final Optional<PeerCheckCase> wantPeerCheckCase) {
this.name = name;
this.network = network;
this.head = head;
this.time = time;
this.wantForkId = wantForkId;
this.wantForkIds = wantForkIds;
this.wantPeerCheckCase = wantPeerCheckCase;

@ -12,8 +12,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth;
package org.hyperledger.besu.ethereum.forkid;
import static java.util.Collections.emptyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -21,29 +22,36 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.LongSupplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.Streams;
import org.apache.tuweni.bytes.Bytes;
public class ForkIdTestUtil {
public static Blockchain mockBlockchain(final String genesisHash, final long chainHeight) {
return mockBlockchain(genesisHash, () -> chainHeight);
public static Blockchain mockBlockchain(
final String genesisHash, final long chainHeight, final long timestamp) {
return mockBlockchain(genesisHash, () -> chainHeight, timestamp);
}
public static Blockchain mockBlockchain(
final String genesisHash, final LongSupplier chainHeightSupplier) {
final String genesisHash, final LongSupplier chainHeightSupplier, final long timestamp) {
final Blockchain mockchain = mock(Blockchain.class);
final BlockHeader mockHeader = mock(BlockHeader.class);
final Block block = new Block(mockHeader, null);
final BlockHeader mockChainHeadHeader = mock(BlockHeader.class);
when(mockchain.getGenesisBlock()).thenReturn(block);
when(mockchain.getChainHeadBlockNumber()).thenReturn(chainHeightSupplier.getAsLong());
when(mockHeader.getHash()).thenReturn(Hash.fromHexString(genesisHash));
when(mockchain.getChainHeadHeader()).thenReturn(mockChainHeadHeader);
when(mockChainHeadHeader.getNumber()).thenReturn(chainHeightSupplier.getAsLong());
when(mockChainHeadHeader.getTimestamp()).thenReturn(timestamp);
return mockchain;
}
@ -79,6 +87,11 @@ public class ForkIdTestUtil {
public static final List<Long> SHANDONG =
Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
public static final List<Long> PRIVATE = Arrays.asList(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
public static final List<Long> MAINNET_WITH_SHANGHAI_BLOCKS =
Streams.concat(MAINNET.stream(), Stream.of(18000000L)).collect(Collectors.toList());
public static final List<Long> MAINNET_WITH_SHANGHAI_TIMESTAMPS = List.of(1668000000L);
}
public static class ForkIds {
@ -125,26 +138,58 @@ public class ForkIdTestUtil {
Arrays.asList(
new ForkId(Bytes.fromHexString("0xa3f5ab08"), 1561651L),
new ForkId(Bytes.fromHexString("0xc25efa5c"), 0L));
public static final List<ForkId> WITHDRAWALS =
Arrays.asList(
new ForkId(
Bytes.fromHexString("0xfc64ec04"), 1150000L), // Unsynced / last Frontier block
new ForkId(Bytes.fromHexString("0x97c2c34c"), 1920000L), // First Homestead block
new ForkId(Bytes.fromHexString("0x91d1f948"), 2463000L), // First DAO block
new ForkId(Bytes.fromHexString("0x7a64da13"), 2675000L), // First Tangerine block
new ForkId(Bytes.fromHexString("0x3edd5b10"), 4370000L), // First Spurious block
new ForkId(Bytes.fromHexString("0xa00bc324"), 7280000L), // First Byzantium block
new ForkId(Bytes.fromHexString("0x668db0af"), 9069000L), // First Petersburg block
new ForkId(Bytes.fromHexString("0x879d6e30"), 9200000L), // First Istanbul block
new ForkId(Bytes.fromHexString("0xe029e991"), 12244000L), // First Muir Glacier block
new ForkId(Bytes.fromHexString("0x0eb440f6"), 12965000L), // First Berlin block
new ForkId(Bytes.fromHexString("0xb715077d"), 13773000L), // First London block
new ForkId(Bytes.fromHexString("0x20c327fc"), 15050000L), // First Arrow Glacier block
new ForkId(Bytes.fromHexString("0xf0afd0e3"), 18000000L), // First Arrow Glacier block
new ForkId(Bytes.fromHexString("0x4fb8a872"), 1668000000L), // First Merge Start block
new ForkId(Bytes.fromHexString("0xc1fdf181"), 0L) // First Shanghai block
);
}
public static class Network {
public static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET);
public static final Network ROPSTEN = network(GenesisHash.ROPSTEN, Forks.ROPSTEN);
public static final Network SEPOLIA = network(GenesisHash.SEPOLIA, Forks.SEPOLIA);
public static final Network RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY);
public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI);
public static final Network SHANDONG = network(GenesisHash.SHANDONG, Forks.SHANDONG);
public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE);
public static final Network MAINNET = network(GenesisHash.MAINNET, Forks.MAINNET, emptyList());
public static final Network ROPSTEN = network(GenesisHash.ROPSTEN, Forks.ROPSTEN, emptyList());
public static final Network SEPOLIA = network(GenesisHash.SEPOLIA, Forks.SEPOLIA, emptyList());
public static final Network RINKEBY = network(GenesisHash.RINKEBY, Forks.RINKEBY, emptyList());
public static final Network GOERLI = network(GenesisHash.GOERLI, Forks.GOERLI, emptyList());
public static final Network SHANDONG =
network(GenesisHash.SHANDONG, Forks.SHANDONG, emptyList());
public static final Network PRIVATE = network(GenesisHash.PRIVATE, Forks.PRIVATE, emptyList());
public static final Network MAINNET_WITH_SHANGHAI =
network(
GenesisHash.MAINNET,
Forks.MAINNET_WITH_SHANGHAI_BLOCKS,
Forks.MAINNET_WITH_SHANGHAI_TIMESTAMPS);
public final String hash;
public final List<Long> forks;
public final List<Long> blockForks;
public final List<Long> timestampForks;
public Network(final String hash, final List<Long> forks) {
public Network(
final String hash, final List<Long> blockForks, final List<Long> timestampForks) {
this.hash = hash;
this.forks = forks;
this.blockForks = blockForks;
this.timestampForks = timestampForks;
}
public static Network network(final String hash, final List<Long> forks) {
return new Network(hash, forks);
public static Network network(
final String hash, final List<Long> blockForks, final List<Long> timestampForks) {
return new Network(hash, blockForks, timestampForks);
}
}

@ -12,11 +12,10 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.eth;
package org.hyperledger.besu.ethereum.forkid;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.forkid.ForkId;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.ArrayList;

@ -156,6 +156,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver {
new ForkIdManager(
blockchain,
Collections.emptyList(),
Collections.emptyList(),
ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()));
}
@ -172,7 +173,8 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver {
final Optional<MergePeerFilter> mergePeerFilter,
final SynchronizerConfiguration synchronizerConfiguration,
final EthScheduler scheduler,
final List<Long> forks) {
final List<Long> blockNumberForks,
final List<Long> timestampForks) {
this(
blockchain,
networkId,
@ -187,7 +189,10 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver {
synchronizerConfiguration,
scheduler,
new ForkIdManager(
blockchain, forks, ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()));
blockchain,
blockNumberForks,
timestampForks,
ethereumWireProtocolConfiguration.isLegacyEth64ForkIdEnabled()));
}
public EthContext ethContext() {

@ -1115,7 +1115,8 @@ public final class EthProtocolManagerTest {
protocolContext.getWorldStateArchive(),
transactionPool,
EthProtocolConfiguration.defaultConfig(),
new ForkIdManager(blockchain, Collections.emptyList(), true))) {
new ForkIdManager(
blockchain, Collections.emptyList(), Collections.emptyList(), true))) {
assertThat(ethManager.getForkIdAsBytesList()).isEmpty();
}

@ -92,7 +92,7 @@ public class EthProtocolManagerTestUtil {
mergePeerFilter,
mock(SynchronizerConfiguration.class),
ethScheduler,
new ForkIdManager(blockchain, Collections.emptyList(), false));
new ForkIdManager(blockchain, Collections.emptyList(), Collections.emptyList(), false));
}
public static EthProtocolManager create(
@ -113,7 +113,7 @@ public class EthProtocolManagerTestUtil {
ethPeers,
ethMessages,
ethContext,
new ForkIdManager(blockchain, Collections.emptyList(), false));
new ForkIdManager(blockchain, Collections.emptyList(), Collections.emptyList(), false));
}
public static EthProtocolManager create(

@ -180,7 +180,8 @@ public class TestNode implements Closeable {
.supportedCapabilities(capabilities)
.storageProvider(new InMemoryKeyValueStorageProvider())
.blockchain(blockchain)
.forks(Collections.emptyList())
.blockNumberForks(Collections.emptyList())
.timestampForks(Collections.emptyList())
.build())
.metricsSystem(new NoOpMetricsSystem())
.build();

@ -480,7 +480,8 @@ public class DefaultP2PNetwork implements P2PNetwork {
private StorageProvider storageProvider;
private Optional<TLSConfiguration> p2pTLSConfiguration = Optional.empty();
private Blockchain blockchain;
private List<Long> forks;
private List<Long> blockNumberForks;
private List<Long> timestampForks;
private boolean legacyForkIdEnabled = false;
public P2PNetwork build() {
@ -523,11 +524,13 @@ public class DefaultP2PNetwork implements P2PNetwork {
checkState(metricsSystem != null, "MetricsSystem must be set.");
checkState(storageProvider != null, "StorageProvider must be set.");
checkState(peerDiscoveryAgent != null || vertx != null, "Vertx must be set.");
checkState(blockNumberForks != null, "BlockNumberForks must be set.");
checkState(timestampForks != null, "TimestampForks must be set.");
}
private PeerDiscoveryAgent createDiscoveryAgent() {
final ForkIdManager forkIdManager =
new ForkIdManager(blockchain, forks, this.legacyForkIdEnabled);
new ForkIdManager(blockchain, blockNumberForks, timestampForks, this.legacyForkIdEnabled);
return new VertxPeerDiscoveryAgent(
vertx,
@ -643,9 +646,15 @@ public class DefaultP2PNetwork implements P2PNetwork {
return this;
}
public Builder forks(final List<Long> forks) {
public Builder blockNumberForks(final List<Long> forks) {
checkNotNull(forks);
this.forks = forks;
this.blockNumberForks = forks;
return this;
}
public Builder timestampForks(final List<Long> forks) {
checkNotNull(forks);
this.timestampForks = forks;
return this;
}

@ -52,6 +52,7 @@ import org.hyperledger.besu.nat.upnp.UpnpNatManager;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@ -407,6 +408,8 @@ public final class DefaultP2PNetworkTest {
.maintainedPeers(maintainedPeers)
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Capability.create("eth", 63))
.storageProvider(new InMemoryKeyValueStorageProvider());
.storageProvider(new InMemoryKeyValueStorageProvider())
.blockNumberForks(Collections.emptyList())
.timestampForks(Collections.emptyList());
}
}

@ -82,7 +82,8 @@ public class NetworkingServiceLifecycleTest {
when(blockMock.getHash()).thenReturn(Hash.ZERO);
when(blockchainMock.getGenesisBlock()).thenReturn(blockMock);
builder.blockchain(blockchainMock);
builder.forks(Collections.emptyList());
builder.blockNumberForks(Collections.emptyList());
builder.timestampForks(Collections.emptyList());
return builder;
}

@ -321,7 +321,8 @@ public class P2PNetworkTest {
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forks(Collections.emptyList())
.blockNumberForks(Collections.emptyList())
.timestampForks(Collections.emptyList())
.blockchain(blockchainMock);
}
}

@ -504,7 +504,8 @@ public class P2PPlainNetworkTest {
.metricsSystem(new NoOpMetricsSystem())
.supportedCapabilities(Arrays.asList(Capability.create("eth", 63)))
.storageProvider(new InMemoryKeyValueStorageProvider())
.forks(Collections.emptyList())
.blockNumberForks(Collections.emptyList())
.timestampForks(Collections.emptyList())
.blockchain(blockchainMock);
}
}

Loading…
Cancel
Save