Temporary CancunEOF fork for EOF testing. (#7227)

Add Genesis ("CancunEOFTime") and reference test ("CancunEOF") support
for a temporary Cancun+EOF fork, in anticipation of potential devnets.

Signed-off-by: Danno Ferrin <danno@numisight.com>
pull/7264/head
Danno Ferrin 5 months ago committed by GitHub
parent cfc3e76d65
commit 0f2046d4b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  2. 7
      config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java
  3. 7
      config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java
  4. 21
      config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java
  5. 8
      config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java
  6. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java
  7. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
  8. 29
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  9. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
  10. 3
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java
  11. 18
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java
  12. 4
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-eof.json
  13. 2
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof.json
  14. 1
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java
  15. 6
      evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java
  16. 75
      evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
  17. 16
      evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
  18. 4
      evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java
  19. 4
      evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java

@ -1514,6 +1514,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
if (genesisConfigOptionsSupplier.get().getCancunTime().isPresent()
|| genesisConfigOptionsSupplier.get().getCancunEOFTime().isPresent()
|| genesisConfigOptionsSupplier.get().getPragueTime().isPresent()
|| genesisConfigOptionsSupplier.get().getPragueEOFTime().isPresent()) {
if (kzgTrustedSetupFile != null) {

@ -242,6 +242,13 @@ public interface GenesisConfigOptions {
*/
OptionalLong getCancunTime();
/**
* Gets cancun EOF time.
*
* @return the cancun EOF time
*/
OptionalLong getCancunEOFTime();
/**
* Gets prague time.
*

@ -288,6 +288,11 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
return getOptionalLong("shanghaitime");
}
@Override
public OptionalLong getCancunEOFTime() {
return getOptionalLong("cancuneoftime");
}
@Override
public OptionalLong getCancunTime() {
return getOptionalLong("cancuntime");
@ -461,6 +466,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
getMergeNetSplitBlockNumber().ifPresent(l -> builder.put("mergeNetSplitBlock", l));
getShanghaiTime().ifPresent(l -> builder.put("shanghaiTime", l));
getCancunTime().ifPresent(l -> builder.put("cancunTime", l));
getCancunEOFTime().ifPresent(l -> builder.put("cancunEOFTime", l));
getPragueTime().ifPresent(l -> builder.put("pragueTime", l));
getPragueEOFTime().ifPresent(l -> builder.put("pragueEOFTime", l));
getTerminalBlockNumber().ifPresent(l -> builder.put("terminalBlockNumber", l));
@ -610,6 +616,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
Stream.of(
getShanghaiTime(),
getCancunTime(),
getCancunEOFTime(),
getPragueTime(),
getPragueEOFTime(),
getFutureEipsTime(),

@ -48,6 +48,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable
private OptionalLong mergeNetSplitBlockNumber = OptionalLong.empty();
private OptionalLong shanghaiTime = OptionalLong.empty();
private OptionalLong cancunTime = OptionalLong.empty();
private OptionalLong cancunEOFTime = OptionalLong.empty();
private OptionalLong pragueTime = OptionalLong.empty();
private OptionalLong pragueEOFTime = OptionalLong.empty();
private OptionalLong futureEipsTime = OptionalLong.empty();
@ -82,7 +83,9 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable
private boolean fixedBaseFee = false;
/** Default constructor. */
public StubGenesisConfigOptions() {}
public StubGenesisConfigOptions() {
// Explicit default constructor because of JavaDoc linting
}
@Override
public StubGenesisConfigOptions clone() {
@ -238,6 +241,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable
return cancunTime;
}
@Override
public OptionalLong getCancunEOFTime() {
return cancunEOFTime;
}
@Override
public OptionalLong getPragueTime() {
return pragueTime;
@ -630,6 +638,17 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable
return this;
}
/**
* Cancun EOF time.
*
* @param timestamp the timestamp
* @return the stub genesis config options
*/
public StubGenesisConfigOptions cancunEOFTime(final long timestamp) {
cancunEOFTime = OptionalLong.of(timestamp);
return this;
}
/**
* Prague time.
*

@ -193,6 +193,13 @@ class GenesisConfigOptionsTest {
assertThat(config.getCancunTime()).hasValue(1670470142);
}
@Test
void shouldGetCancunEOFTime() {
final GenesisConfigOptions config =
fromConfigOptions(singletonMap("cancunEOFTime", 1670470142));
assertThat(config.getCancunEOFTime()).hasValue(1670470142);
}
@Test
void shouldGetPragueTime() {
final GenesisConfigOptions config = fromConfigOptions(singletonMap("pragueTime", 1670470143));
@ -238,6 +245,7 @@ class GenesisConfigOptionsTest {
assertThat(config.getMergeNetSplitBlockNumber()).isEmpty();
assertThat(config.getShanghaiTime()).isEmpty();
assertThat(config.getCancunTime()).isEmpty();
assertThat(config.getCancunEOFTime()).isEmpty();
assertThat(config.getPragueTime()).isEmpty();
assertThat(config.getPragueEOFTime()).isEmpty();
assertThat(config.getFutureEipsTime()).isEmpty();

@ -304,7 +304,15 @@ public final class GenesisState {
if (cancunTimestamp.isPresent()) {
return genesis.getTimestamp() >= cancunTimestamp.getAsLong();
}
return isPragueAtGenesis(genesis);
return isPragueAtGenesis(genesis) || isCancunEOFAtGenesis(genesis);
}
private static boolean isCancunEOFAtGenesis(final GenesisConfigFile genesis) {
final OptionalLong cancunEOFTimestamp = genesis.getConfigOptions().getCancunEOFTime();
if (cancunEOFTimestamp.isPresent()) {
return genesis.getTimestamp() >= cancunEOFTimestamp.getAsLong();
}
return isPragueEOFAtGenesis(genesis);
}
private static boolean isPragueAtGenesis(final GenesisConfigFile genesis) {

@ -128,6 +128,11 @@ public class MainnetProtocolSpecFactory {
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder cancunEOFDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.cancunEOFDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder pragueDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.pragueDefinition(
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);

@ -617,6 +617,19 @@ public abstract class MainnetProtocolSpecs {
.name("Cancun");
}
static ProtocolSpecBuilder cancunEOFDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
ProtocolSpecBuilder protocolSpecBuilder =
cancunDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters);
return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("CancunEOF");
}
static ProtocolSpecBuilder pragueDefinition(
final Optional<BigInteger> chainId,
final boolean enableRevertReason,
@ -657,8 +670,17 @@ public abstract class MainnetProtocolSpecs {
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
return pragueDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
ProtocolSpecBuilder protocolSpecBuilder =
pragueDefinition(
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters);
return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("PragueEOF");
}
private static ProtocolSpecBuilder addEOF(
final Optional<BigInteger> chainId,
final EvmConfiguration evmConfiguration,
final ProtocolSpecBuilder protocolSpecBuilder) {
return protocolSpecBuilder
// EIP-7692 EOF v1 Gas calculator
.gasCalculator(PragueEOFGasCalculator::new)
// EIP-7692 EOF v1 EVM and opcodes
@ -674,8 +696,7 @@ public abstract class MainnetProtocolSpecs {
true,
List.of(MaxCodeSizeRule.from(evm), EOFValidationCodeRule.from(evm)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.name("PragueEOF");
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES));
}
static ProtocolSpecBuilder futureEipsDefinition(

@ -246,6 +246,7 @@ public class ProtocolScheduleBuilder {
// Begin timestamp forks
lastForkBlock = validateForkOrder("Shanghai", config.getShanghaiTime(), lastForkBlock);
lastForkBlock = validateForkOrder("Cancun", config.getCancunTime(), lastForkBlock);
lastForkBlock = validateForkOrder("CancunEOF", config.getCancunEOFTime(), lastForkBlock);
lastForkBlock = validateForkOrder("Prague", config.getPragueTime(), lastForkBlock);
lastForkBlock = validateForkOrder("PragueEOF", config.getPragueEOFTime(), lastForkBlock);
lastForkBlock = validateForkOrder("FutureEips", config.getFutureEipsTime(), lastForkBlock);
@ -326,6 +327,7 @@ public class ProtocolScheduleBuilder {
// Timestamp Forks
timestampMilestone(config.getShanghaiTime(), specFactory.shanghaiDefinition(config)),
timestampMilestone(config.getCancunTime(), specFactory.cancunDefinition(config)),
timestampMilestone(config.getCancunEOFTime(), specFactory.cancunEOFDefinition(config)),
timestampMilestone(config.getPragueTime(), specFactory.pragueDefinition(config)),
timestampMilestone(config.getPragueEOFTime(), specFactory.pragueEOFDefinition(config)),
timestampMilestone(config.getFutureEipsTime(), specFactory.futureEipsDefinition(config)),

@ -117,6 +117,9 @@ class MainnetGenesisFileModule extends GenesisFileModule {
Map.entry(
"cancun",
createSchedule(new StubGenesisConfigOptions().cancunTime(0).baseFeePerGas(0x0a))),
Map.entry(
"cancuneof",
createSchedule(new StubGenesisConfigOptions().cancunEOFTime(0).baseFeePerGas(0x0a))),
Map.entry(
"prague",
createSchedule(new StubGenesisConfigOptions().pragueTime(0).baseFeePerGas(0x0a))),

@ -113,12 +113,12 @@ public abstract class BenchmarkExecutor {
}
timer.stop();
if (executions < 1) {
return Double.NaN;
}
if (executions > 0) {
final double elapsed = timer.elapsed(TimeUnit.NANOSECONDS) / 1.0e9D;
return elapsed / executions;
} else {
return Double.NaN;
}
}
/**
@ -143,7 +143,15 @@ public abstract class BenchmarkExecutor {
case SHANGHAI -> new ShanghaiGasCalculator();
case CANCUN -> new CancunGasCalculator();
case PRAGUE -> new PragueGasCalculator();
case PRAGUE_EOF, OSAKA, AMSTERDAM, BOGOTA, POLIS, BANGKOK, FUTURE_EIPS, EXPERIMENTAL_EIPS ->
case CANCUN_EOF,
PRAGUE_EOF,
OSAKA,
AMSTERDAM,
BOGOTA,
POLIS,
BANGKOK,
FUTURE_EIPS,
EXPERIMENTAL_EIPS ->
new PragueEOFGasCalculator();
};
}

@ -45,7 +45,7 @@
},
"out": "0x",
"post": {
"Prague": [
"CancunEOF": [
{
"hash": "0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3",
"logs": "0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940",
@ -79,7 +79,7 @@
{"pc":5,"section":0,"op":95,"gas":"0x793d71","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"},
{"pc":6,"section":0,"op":95,"gas":"0x793d6f","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH0"},
{"pc":7,"section":0,"op":238,"immediate":"0x00","gas":"0x793d6d","gasCost":"0x0","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"RETURNCONTRACT"},
{"output":"","gasUsed":"0xe433","test":"create-eof","fork":"Prague","d":0,"g":0,"v":0,"postHash":"0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3","postLogsHash":"0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940","pass":true},
{"output":"","gasUsed":"0xe433","test":"create-eof","fork":"CancunEOF","d":0,"g":0,"v":0,"postHash":"0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3","postLogsHash":"0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940","pass":true},
{"pc":0,"op":239,"gas":"0x794068","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"},
{"output":"","gasUsed":"0x7a1200","test":"create-eof","fork":"Cancun","d":0,"g":0,"v":0,"postHash":"0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":true,"error":"INVALID_OPERATION"}
]

@ -8,7 +8,7 @@
"--coinbase",
"4444588443C3A91288C5002483449ABA1054192B",
"--fork",
"pragueeof"
"CancunEOF"
],
"stdin": "",
"stdout": [

@ -84,6 +84,7 @@ public class ReferenceTestProtocolSchedules {
"ShanghaiToCancunAtTime15k",
createSchedule(genesisStub.clone().shanghaiTime(0).cancunTime(15000)));
builder.put("Cancun", createSchedule(genesisStub.clone().cancunTime(0)));
builder.put("CancunEOF", createSchedule(genesisStub.clone().cancunEOFTime(0)));
// also load KZG file for mainnet
KZGPointEvalPrecompiledContract.init();
builder.put(

@ -55,6 +55,8 @@ public enum EvmSpecVersion {
SHANGHAI(0x6000, 0xc000, 0, true, "Shanghai", "Finalized"),
/** Cancun evm spec version. */
CANCUN(0x6000, 0xc000, 0, true, "Cancun", "Finalized"),
/** Cancun evm spec version. */
CANCUN_EOF(0x6000, 0xc000, 1, false, "CancunEOF", "For Testing"),
/** Prague evm spec version. */
PRAGUE(0x6000, 0xc000, 0, false, "Prague", "In Development"),
/** PragueEOF evm spec version. */
@ -201,6 +203,10 @@ public enum EvmSpecVersion {
if ("prague".equalsIgnoreCase(name)) {
return EvmSpecVersion.PRAGUE_EOF;
}
// TODO remove once PragueEOF settles
if ("cancuneof".equalsIgnoreCase(name)) {
return EvmSpecVersion.CANCUN_EOF;
}
for (var version : EvmSpecVersion.values()) {
if (version.name().equalsIgnoreCase(name)) {
return version;

@ -897,6 +897,76 @@ public class MainnetEVMs {
registry.put(new BlobBaseFeeOperation(gasCalculator));
}
/**
* CancunEOF evm.
*
* @param evmConfiguration the evm configuration
* @return the evm
*/
public static EVM cancunEOF(final EvmConfiguration evmConfiguration) {
return cancunEOF(DEV_NET_CHAIN_ID, evmConfiguration);
}
/**
* CancunEOF evm.
*
* @param chainId the chain id
* @param evmConfiguration the evm configuration
* @return the evm
*/
public static EVM cancunEOF(final BigInteger chainId, final EvmConfiguration evmConfiguration) {
return cancunEOF(new CancunGasCalculator(), chainId, evmConfiguration);
}
/**
* CancunEOF evm.
*
* @param gasCalculator the gas calculator
* @param chainId the chain id
* @param evmConfiguration the evm configuration
* @return the evm
*/
public static EVM cancunEOF(
final GasCalculator gasCalculator,
final BigInteger chainId,
final EvmConfiguration evmConfiguration) {
return new EVM(
cancunEOFOperations(gasCalculator, chainId),
gasCalculator,
evmConfiguration,
EvmSpecVersion.CANCUN_EOF);
}
/**
* Operation registry for PragueEOF's operations.
*
* @param gasCalculator the gas calculator
* @param chainId the chain id
* @return the operation registry
*/
public static OperationRegistry cancunEOFOperations(
final GasCalculator gasCalculator, final BigInteger chainId) {
OperationRegistry operationRegistry = new OperationRegistry();
registerCancunEOFOperations(operationRegistry, gasCalculator, chainId);
return operationRegistry;
}
/**
* Register CancunEOF's operations.
*
* @param registry the registry
* @param gasCalculator the gas calculator
* @param chainID the chain id
*/
public static void registerCancunEOFOperations(
final OperationRegistry registry,
final GasCalculator gasCalculator,
final BigInteger chainID) {
registerCancunOperations(registry, gasCalculator, chainID);
registerEOFOperations(registry, gasCalculator);
}
/**
* Prague evm.
*
@ -1034,6 +1104,11 @@ public class MainnetEVMs {
final BigInteger chainID) {
registerPragueOperations(registry, gasCalculator, chainID);
registerEOFOperations(registry, gasCalculator);
}
private static void registerEOFOperations(
final OperationRegistry registry, final GasCalculator gasCalculator) {
// EIP-663 Unlimited Swap and Dup
registry.put(new DupNOperation(gasCalculator));
registry.put(new SwapNOperation(gasCalculator));

@ -160,6 +160,7 @@ public class EVMExecutor {
case PARIS -> paris(chainId, evmConfiguration);
case SHANGHAI -> shanghai(chainId, evmConfiguration);
case CANCUN -> cancun(chainId, evmConfiguration);
case CANCUN_EOF -> cancunEOF(chainId, evmConfiguration);
case PRAGUE -> prague(chainId, evmConfiguration);
case PRAGUE_EOF -> pragueEOF(chainId, evmConfiguration);
case OSAKA -> osaka(chainId, evmConfiguration);
@ -493,6 +494,21 @@ public class EVMExecutor {
return executor;
}
/**
* Instantiate Cancun EOF evm executor.
*
* @param chainId the chain ID
* @param evmConfiguration the evm configuration
* @return the evm executor
*/
public static EVMExecutor cancunEOF(
final BigInteger chainId, final EvmConfiguration evmConfiguration) {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.cancunEOF(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.cancun(executor.evm.getGasCalculator());
return executor;
}
/**
* Instantiate Prague evm executor.
*

@ -126,6 +126,10 @@ class EVMExecutorTest {
EVMExecutor cancunEVM = EVMExecutor.cancun(EvmConfiguration.DEFAULT);
assertThat(cancunEVM.getChainId()).contains(defaultChainId);
EVMExecutor cancunEOFEVM =
EVMExecutor.cancunEOF(defaultChainId.toBigInteger(), EvmConfiguration.DEFAULT);
assertThat(cancunEOFEVM.getChainId()).contains(defaultChainId);
EVMExecutor pragueEVM =
EVMExecutor.pragueEOF(defaultChainId.toBigInteger(), EvmConfiguration.DEFAULT);
assertThat(pragueEVM.getChainId()).contains(defaultChainId);

@ -62,7 +62,7 @@ class EofCreateOperationTest {
@Test
void innerContractIsCorrect() {
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final EVM evm = MainnetEVMs.cancunEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(INNER_CONTRACT);
assertThat(code.isValid()).isTrue();
@ -92,7 +92,7 @@ class EofCreateOperationTest {
@Test
void eofCreatePassesInCallData() {
Bytes outerContract = EOF_CREATE_CONTRACT;
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final EVM evm = MainnetEVMs.cancunEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(outerContract);
if (!code.isValid()) {

Loading…
Cancel
Save