Reconfigure how Protocol Specs are created WRT EVM condiguration (#7245)

Make the max code size and max initcode size a part of the EVM
configuration. As part of the change we need to move the tasks
CodeFactory once handled as a static class and move it into the EVM.
This has a nice follow on effect that we don't need to pass in max EOF
versions or max code sizes anymore.

Signed-off-by: Danno Ferrin <danno@numisight.com>
pull/7264/head
Danno Ferrin 5 months ago committed by GitHub
parent af80e53ad9
commit 7e840ab640
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 141
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
  3. 175
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java
  4. 334
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  5. 68
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
  6. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  7. 9
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java
  8. 76
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java
  9. 33
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java
  10. 11
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  11. 7
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolComponent.java
  12. 16
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java
  13. 22
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java
  14. 18
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java
  15. 38
      ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java
  16. 13
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java
  17. 31
      ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java
  18. 10
      evm/src/main/java/org/hyperledger/besu/evm/Code.java
  19. 21
      evm/src/main/java/org/hyperledger/besu/evm/EVM.java
  20. 89
      evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java
  21. 109
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeFactory.java
  22. 8
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeInvalid.java
  23. 8
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeV0.java
  24. 19
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1.java
  25. 39
      evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java
  26. 6
      evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java
  27. 49
      evm/src/main/java/org/hyperledger/besu/evm/code/EOFValidator.java
  28. 61
      evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/CachedInvalidCodeRule.java
  29. 4
      evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/ContractValidationRule.java
  30. 20
      evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/EOFValidationCodeRule.java
  31. 28
      evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/MaxCodeSizeRule.java
  32. 7
      evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/PrefixCodeRule.java
  33. 22
      evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java
  34. 12
      evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java
  35. 55
      evm/src/main/java/org/hyperledger/besu/evm/internal/EvmConfiguration.java
  36. 3
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java
  37. 2
      evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java
  38. 10
      evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnContractOperation.java
  39. 7
      evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java
  40. 20
      evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java
  41. 36
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java
  42. 16
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java
  43. 16
      evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java
  44. 18
      evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java
  45. 6
      evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java
  46. 5
      evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java
  47. 20
      evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java
  48. 10
      evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java
  49. 13
      evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java
  50. 24
      evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCallOperationTest.java
  51. 41
      evm/src/test/java/org/hyperledger/besu/evm/operations/ExtDelegateCallOperationTest.java
  52. 19
      evm/src/test/java/org/hyperledger/besu/evm/operations/ExtStaticCallOperationTest.java
  53. 25
      evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java
  54. 7
      evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java
  55. 112
      evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java
  56. 3
      evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java
  57. 13
      evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java

@ -14,6 +14,7 @@
- Reduce lock contention on transaction pool when building a block [#7180](https://github.com/hyperledger/besu/pull/7180)
- Update Docker base image to Ubuntu 24.04 [#7251](https://github.com/hyperledger/besu/pull/7251)
- Add LUKSO as predefined network name [#7223](https://github.com/hyperledger/besu/pull/7223)
- Refactored how code, initcode, and max stack size are configured in forks. [#7245](https://github.com/hyperledger/besu/pull/7245)
### Bug fixes
- Validation errors ignored in accounts-allowlist and empty list [#7138](https://github.com/hyperledger/besu/issues/7138)

@ -26,7 +26,6 @@ import org.hyperledger.besu.evm.ClassicEVMs;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator;
import org.hyperledger.besu.evm.gascalculator.DieHardGasCalculator;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
@ -44,7 +43,6 @@ import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
@ -56,38 +54,28 @@ public class ClassicProtocolSpecs {
}
public static ProtocolSpecBuilder classicRecoveryInitDefinition(
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return MainnetProtocolSpecs.homesteadDefinition(
contractSizeLimit, configStackSizeLimit, evmConfiguration)
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration)
.blockHeaderValidatorBuilder(
feeMarket -> MainnetBlockHeaderValidator.createClassicValidator())
.name("ClassicRecoveryInit");
}
public static ProtocolSpecBuilder tangerineWhistleDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return MainnetProtocolSpecs.homesteadDefinition(
contractSizeLimit, configStackSizeLimit, evmConfiguration)
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration)
.isReplayProtectionSupported(true)
.gasCalculator(TangerineWhistleGasCalculator::new)
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId))
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
evm.getGasCalculator(), gasLimitCalculator, true, chainId))
.name("ClassicTangerineWhistle");
}
public static ProtocolSpecBuilder dieHardDefinition(
final Optional<BigInteger> chainId,
final OptionalInt ignoredConfigContractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return tangerineWhistleDefinition(
chainId, OptionalInt.empty(), configStackSizeLimit, evmConfiguration)
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return tangerineWhistleDefinition(chainId, evmConfiguration)
.gasCalculator(DieHardGasCalculator::new)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED)
.name("DieHard");
@ -95,11 +83,9 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder gothamDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return dieHardDefinition(chainId, contractSizeLimit, configStackSizeLimit, evmConfiguration)
return dieHardDefinition(chainId, evmConfiguration)
.blockReward(MAX_BLOCK_REWARD)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_DELAYED)
.blockProcessorBuilder(
@ -122,35 +108,23 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder defuseDifficultyBombDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return gothamDefinition(
chainId, contractSizeLimit, configStackSizeLimit, ecip1017EraRounds, evmConfiguration)
return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED)
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId))
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
evm.getGasCalculator(), gasLimitCalculator, true, chainId))
.name("DefuseDifficultyBomb");
}
public static ProtocolSpecBuilder atlantisDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit =
configContractSizeLimit.orElse(MainnetProtocolSpecs.SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return gothamDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
ecip1017EraRounds,
evmConfiguration)
return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration)
.evmBuilder(MainnetEVMs::byzantium)
.evmConfiguration(evmConfiguration)
.gasCalculator(SpuriousDragonGasCalculator::new)
@ -163,13 +137,9 @@ public class ClassicProtocolSpecs {
? ClassicProtocolSpecs::byzantiumTransactionReceiptFactoryWithReasonEnabled
: ClassicProtocolSpecs::byzantiumTransactionReceiptFactory)
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
1))
evm, true, Collections.singletonList(MaxCodeSizeRule.from(evm)), 1))
.transactionProcessorBuilder(
(gasCalculator,
feeMarket,
@ -183,7 +153,7 @@ public class ClassicProtocolSpecs {
messageCallProcessor,
true,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.frontier()))
.name("Atlantis");
@ -191,18 +161,10 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder aghartaDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return atlantisDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return atlantisDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
.evmBuilder(MainnetEVMs::constantinople)
.gasCalculator(PetersburgGasCalculator::new)
.evmBuilder(MainnetEVMs::constantinople)
@ -212,18 +174,10 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder phoenixDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return aghartaDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return aghartaDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
.gasCalculator(IstanbulGasCalculator::new)
.evmBuilder(
(gasCalculator, evmConfig) ->
@ -235,18 +189,10 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder thanosDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return phoenixDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return phoenixDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
.blockHeaderValidatorBuilder(
feeMarket ->
MainnetBlockHeaderValidator.createPgaBlockHeaderValidator(
@ -280,23 +226,15 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder magnetoDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
return thanosDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return thanosDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
.gasCalculator(BerlinGasCalculator::new)
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator,
evm.getGasCalculator(),
gasLimitCalculator,
true,
chainId,
@ -310,47 +248,24 @@ public class ClassicProtocolSpecs {
public static ProtocolSpecBuilder mystiqueDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit =
configContractSizeLimit.orElse(MainnetProtocolSpecs.SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
return magnetoDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return magnetoDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
.gasCalculator(LondonGasCalculator::new)
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), PrefixCodeRule.of()),
1))
evm, true, List.of(MaxCodeSizeRule.from(evm), PrefixCodeRule.of()), 1))
.name("Mystique");
}
public static ProtocolSpecBuilder spiralDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration) {
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return mystiqueDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
ecip1017EraRounds,
evmConfiguration)
return mystiqueDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration)
// EIP-3860
.gasCalculator(ShanghaiGasCalculator::new)
// EIP-3855
@ -372,7 +287,7 @@ public class ClassicProtocolSpecs {
messageCallProcessor,
true,
true,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.frontier()))
.name("Spiral");

@ -20,14 +20,11 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.math.BigInteger;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
public class MainnetProtocolSpecFactory {
private final Optional<BigInteger> chainId;
private final OptionalInt contractSizeLimit;
private final OptionalInt evmStackSize;
private final boolean isRevertReasonEnabled;
private final OptionalLong ecip1017EraRounds;
private final EvmConfiguration evmConfiguration;
@ -35,15 +32,11 @@ public class MainnetProtocolSpecFactory {
public MainnetProtocolSpecFactory(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt evmStackSize,
final boolean isRevertReasonEnabled,
final OptionalLong ecip1017EraRounds,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
this.chainId = chainId;
this.contractSizeLimit = contractSizeLimit;
this.evmStackSize = evmStackSize;
this.isRevertReasonEnabled = isRevertReasonEnabled;
this.ecip1017EraRounds = ecip1017EraRounds;
this.evmConfiguration = evmConfiguration;
@ -51,153 +44,98 @@ public class MainnetProtocolSpecFactory {
}
public ProtocolSpecBuilder frontierDefinition() {
return MainnetProtocolSpecs.frontierDefinition(
contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.frontierDefinition(evmConfiguration);
}
public ProtocolSpecBuilder homesteadDefinition() {
return MainnetProtocolSpecs.homesteadDefinition(
contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration);
}
public ProtocolSpecBuilder daoRecoveryInitDefinition() {
return MainnetProtocolSpecs.daoRecoveryInitDefinition(
contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.daoRecoveryInitDefinition(evmConfiguration);
}
public ProtocolSpecBuilder daoRecoveryTransitionDefinition() {
return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(
contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(evmConfiguration);
}
public ProtocolSpecBuilder tangerineWhistleDefinition() {
return MainnetProtocolSpecs.tangerineWhistleDefinition(
contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.tangerineWhistleDefinition(evmConfiguration);
}
public ProtocolSpecBuilder spuriousDragonDefinition() {
return MainnetProtocolSpecs.spuriousDragonDefinition(
chainId, contractSizeLimit, evmStackSize, evmConfiguration);
return MainnetProtocolSpecs.spuriousDragonDefinition(chainId, evmConfiguration);
}
public ProtocolSpecBuilder byzantiumDefinition() {
return MainnetProtocolSpecs.byzantiumDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder constantinopleDefinition() {
return MainnetProtocolSpecs.constantinopleDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder petersburgDefinition() {
return MainnetProtocolSpecs.petersburgDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder istanbulDefinition() {
return MainnetProtocolSpecs.istanbulDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder muirGlacierDefinition() {
return MainnetProtocolSpecs.muirGlacierDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder berlinDefinition() {
return MainnetProtocolSpecs.berlinDefinition(
chainId, contractSizeLimit, evmStackSize, isRevertReasonEnabled, evmConfiguration);
return MainnetProtocolSpecs.berlinDefinition(chainId, isRevertReasonEnabled, evmConfiguration);
}
public ProtocolSpecBuilder londonDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.londonDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder arrowGlacierDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.arrowGlacierDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder grayGlacierDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.grayGlacierDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder parisDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.parisDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder shanghaiDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.shanghaiDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder cancunDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.cancunDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder pragueDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.pragueDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.pragueEOFDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
/**
@ -213,13 +151,7 @@ public class MainnetProtocolSpecFactory {
*/
public ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.futureEipsDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
/**
@ -235,100 +167,57 @@ public class MainnetProtocolSpecFactory {
public ProtocolSpecBuilder experimentalEipsDefinition(
final GenesisConfigOptions genesisConfigOptions) {
return MainnetProtocolSpecs.experimentalEipsDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
genesisConfigOptions,
evmConfiguration,
miningParameters);
chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters);
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
// Classic Protocol Specs
public ProtocolSpecBuilder dieHardDefinition() {
return ClassicProtocolSpecs.dieHardDefinition(
chainId, contractSizeLimit, evmStackSize, evmConfiguration);
return ClassicProtocolSpecs.dieHardDefinition(chainId, evmConfiguration);
}
public ProtocolSpecBuilder gothamDefinition() {
return ClassicProtocolSpecs.gothamDefinition(
chainId, contractSizeLimit, evmStackSize, ecip1017EraRounds, evmConfiguration);
return ClassicProtocolSpecs.gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder defuseDifficultyBombDefinition() {
return ClassicProtocolSpecs.defuseDifficultyBombDefinition(
chainId, contractSizeLimit, evmStackSize, ecip1017EraRounds, evmConfiguration);
chainId, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder atlantisDefinition() {
return ClassicProtocolSpecs.atlantisDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder aghartaDefinition() {
return ClassicProtocolSpecs.aghartaDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder phoenixDefinition() {
return ClassicProtocolSpecs.phoenixDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder thanosDefinition() {
return ClassicProtocolSpecs.thanosDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder magnetoDefinition() {
return ClassicProtocolSpecs.magnetoDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder mystiqueDefinition() {
return ClassicProtocolSpecs.mystiqueDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
public ProtocolSpecBuilder spiralDefinition() {
return ClassicProtocolSpecs.spiralDefinition(
chainId,
contractSizeLimit,
evmStackSize,
isRevertReasonEnabled,
ecip1017EraRounds,
evmConfiguration);
chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration);
}
}

@ -48,7 +48,6 @@ import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.contractvalidation.EOFValidationCodeRule;
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator;
import org.hyperledger.besu.evm.gascalculator.ByzantiumGasCalculator;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
@ -74,8 +73,8 @@ import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.stream.IntStream;
@ -85,11 +84,6 @@ import io.vertx.core.json.JsonArray;
/** Provides the various {@link ProtocolSpec}s on mainnet hard forks. */
public abstract class MainnetProtocolSpecs {
public static final int FRONTIER_CONTRACT_SIZE_LIMIT = Integer.MAX_VALUE;
public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576;
public static final int SHANGHAI_INIT_CODE_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT;
private static final Address RIPEMD160_PRECOMPILE =
Address.fromHexString("0x0000000000000000000000000000000000000003");
@ -107,12 +101,7 @@ public abstract class MainnetProtocolSpecs {
private MainnetProtocolSpecs() {}
public static ProtocolSpecBuilder frontierDefinition(
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT);
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
public static ProtocolSpecBuilder frontierDefinition(final EvmConfiguration evmConfiguration) {
return new ProtocolSpecBuilder()
.gasCalculator(FrontierGasCalculator::new)
.gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator())
@ -120,17 +109,13 @@ public abstract class MainnetProtocolSpecs {
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::frontier)
.messageCallProcessorBuilder(MessageCallProcessor::new)
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
false,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
0))
evm, false, Collections.singletonList(MaxCodeSizeRule.from(evm)), 0))
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator, gasLimitCalculator, false, Optional.empty()))
evm.getGasCalculator(), gasLimitCalculator, false, Optional.empty()))
.transactionProcessorBuilder(
(gasCalculator,
feeMarket,
@ -144,7 +129,7 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
false,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier()))
.privateTransactionProcessorBuilder(
@ -157,7 +142,7 @@ public abstract class MainnetProtocolSpecs {
contractCreationProcessor,
messageCallProcessor,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
new PrivateTransactionValidator(Optional.empty())))
.difficultyCalculator(MainnetDifficultyCalculators.FRONTIER)
.blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.create())
@ -188,35 +173,25 @@ public abstract class MainnetProtocolSpecs {
return MainnetBlockValidator::new;
}
public static ProtocolSpecBuilder homesteadDefinition(
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT);
return frontierDefinition(configContractSizeLimit, configStackSizeLimit, evmConfiguration)
public static ProtocolSpecBuilder homesteadDefinition(final EvmConfiguration evmConfiguration) {
return frontierDefinition(evmConfiguration)
.gasCalculator(HomesteadGasCalculator::new)
.evmBuilder(MainnetEVMs::homestead)
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
0))
evm, true, Collections.singletonList(MaxCodeSizeRule.from(evm)), 0))
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator, gasLimitCalculator, true, Optional.empty()))
evm.getGasCalculator(), gasLimitCalculator, true, Optional.empty()))
.difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD)
.name("Homestead");
}
public static ProtocolSpecBuilder daoRecoveryInitDefinition(
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return homesteadDefinition(contractSizeLimit, configStackSizeLimit, evmConfiguration)
return homesteadDefinition(evmConfiguration)
.blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.createDaoValidator())
.blockProcessorBuilder(
(transactionProcessor,
@ -237,33 +212,22 @@ public abstract class MainnetProtocolSpecs {
}
public static ProtocolSpecBuilder daoRecoveryTransitionDefinition(
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return daoRecoveryInitDefinition(contractSizeLimit, configStackSizeLimit, evmConfiguration)
return daoRecoveryInitDefinition(evmConfiguration)
.blockProcessorBuilder(MainnetBlockProcessor::new)
.name("DaoRecoveryTransition");
}
public static ProtocolSpecBuilder tangerineWhistleDefinition(
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
return homesteadDefinition(contractSizeLimit, configStackSizeLimit, evmConfiguration)
return homesteadDefinition(evmConfiguration)
.gasCalculator(TangerineWhistleGasCalculator::new)
.name("TangerineWhistle");
}
public static ProtocolSpecBuilder spuriousDragonDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit =
configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return tangerineWhistleDefinition(OptionalInt.empty(), configStackSizeLimit, evmConfiguration)
final Optional<BigInteger> chainId, final EvmConfiguration evmConfiguration) {
return tangerineWhistleDefinition(evmConfiguration)
.isReplayProtectionSupported(true)
.gasCalculator(SpuriousDragonGasCalculator::new)
.skipZeroBlockRewards(true)
@ -274,17 +238,17 @@ public abstract class MainnetProtocolSpecs {
precompileContractRegistry,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
Collections.singletonList(MaxCodeSizeRule.from(evm)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(gasCalculator, gasLimitCalculator, true, chainId))
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
evm.getGasCalculator(), gasLimitCalculator, true, chainId))
.transactionProcessorBuilder(
(gasCalculator,
feeMarket,
@ -298,7 +262,7 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.frontier()))
.name("SpuriousDragon");
@ -306,13 +270,9 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder byzantiumDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return spuriousDragonDefinition(
chainId, contractSizeLimit, configStackSizeLimit, evmConfiguration)
return spuriousDragonDefinition(chainId, evmConfiguration)
.gasCalculator(ByzantiumGasCalculator::new)
.evmBuilder(MainnetEVMs::byzantium)
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium)
@ -333,19 +293,16 @@ public abstract class MainnetProtocolSpecs {
contractCreationProcessor,
messageCallProcessor,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
privateTransactionValidator))
.name("Byzantium");
}
public static ProtocolSpecBuilder constantinopleDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return byzantiumDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration)
return byzantiumDefinition(chainId, enableRevertReason, evmConfiguration)
.difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE)
.gasCalculator(ConstantinopleGasCalculator::new)
.evmBuilder(MainnetEVMs::constantinople)
@ -355,30 +312,18 @@ public abstract class MainnetProtocolSpecs {
public static ProtocolSpecBuilder petersburgDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return constantinopleDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration)
return constantinopleDefinition(chainId, enableRevertReason, evmConfiguration)
.gasCalculator(PetersburgGasCalculator::new)
.name("Petersburg");
}
public static ProtocolSpecBuilder istanbulDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
final int contractSizeLimit =
configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
return petersburgDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
evmConfiguration)
return petersburgDefinition(chainId, enableRevertReason, evmConfiguration)
.gasCalculator(IstanbulGasCalculator::new)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
@ -386,12 +331,11 @@ public abstract class MainnetProtocolSpecs {
gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul)
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
Collections.singletonList(MaxCodeSizeRule.from(evm)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.name("Istanbul");
@ -399,29 +343,23 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder muirGlacierDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return istanbulDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration)
return istanbulDefinition(chainId, enableRevertReason, evmConfiguration)
.difficultyCalculator(MainnetDifficultyCalculators.MUIR_GLACIER)
.name("MuirGlacier");
}
static ProtocolSpecBuilder berlinDefinition(
final Optional<BigInteger> chainId,
final OptionalInt contractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final EvmConfiguration evmConfiguration) {
return muirGlacierDefinition(
chainId, contractSizeLimit, configStackSizeLimit, enableRevertReason, evmConfiguration)
return muirGlacierDefinition(chainId, enableRevertReason, evmConfiguration)
.gasCalculator(BerlinGasCalculator::new)
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator,
evm.getGasCalculator(),
gasLimitCalculator,
true,
chainId,
@ -435,30 +373,24 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder londonDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final int contractSizeLimit =
configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
final long londonForkBlockNumber =
genesisConfigOptions.getLondonBlockNumber().orElse(Long.MAX_VALUE);
final BaseFeeMarket londonFeeMarket =
genesisConfigOptions.isZeroBaseFee()
? FeeMarket.zeroBaseFee(londonForkBlockNumber)
: genesisConfigOptions.isFixedBaseFee()
? FeeMarket.fixedBaseFee(
londonForkBlockNumber, miningParameters.getMinTransactionGasPrice())
: FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
return berlinDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
evmConfiguration)
final BaseFeeMarket londonFeeMarket;
if (genesisConfigOptions.isZeroBaseFee()) {
londonFeeMarket = FeeMarket.zeroBaseFee(londonForkBlockNumber);
} else if (genesisConfigOptions.isFixedBaseFee()) {
londonFeeMarket =
FeeMarket.fixedBaseFee(
londonForkBlockNumber, miningParameters.getMinTransactionGasPrice());
} else {
londonFeeMarket =
FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
}
return berlinDefinition(chainId, enableRevertReason, evmConfiguration)
.feeMarket(londonFeeMarket)
.gasCalculator(LondonGasCalculator::new)
.gasLimitCalculatorBuilder(
@ -466,9 +398,9 @@ public abstract class MainnetProtocolSpecs {
new LondonTargetingGasLimitCalculator(
londonForkBlockNumber, (BaseFeeMarket) feeMarket))
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator,
evm.getGasCalculator(),
gasLimitCalculator,
feeMarket,
true,
@ -491,16 +423,15 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
false,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), PrefixCodeRule.of()),
List.of(MaxCodeSizeRule.from(evm), PrefixCodeRule.of()),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.evmBuilder(
@ -521,61 +452,37 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder arrowGlacierDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
return londonDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
.difficultyCalculator(MainnetDifficultyCalculators.ARROW_GLACIER)
.name("ArrowGlacier");
}
static ProtocolSpecBuilder grayGlacierDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
return arrowGlacierDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
.difficultyCalculator(MainnetDifficultyCalculators.GRAY_GLACIER)
.name("GrayGlacier");
}
static ProtocolSpecBuilder parisDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
return grayGlacierDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
MainnetEVMs.paris(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
@ -589,24 +496,12 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder shanghaiDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
// extra variables need to support flipping the warm coinbase flag.
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return parisDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
// gas calculator has new code to support EIP-3860 limit and meter initcode
.gasCalculator(ShanghaiGasCalculator::new)
// EVM has a new operation for EIP-3855 PUSH0 instruction
@ -628,14 +523,14 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
true,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
// Contract creation rules for EIP-3860 Limit and meter intitcode
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator,
evm.getGasCalculator(),
gasLimitCalculator,
feeMarket,
true,
@ -644,7 +539,7 @@ public abstract class MainnetProtocolSpecs {
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559),
SHANGHAI_INIT_CODE_SIZE_LIMIT))
evm.getEvmVersion().getMaxInitcodeSize()))
.withdrawalsProcessor(new WithdrawalsProcessor())
.withdrawalsValidator(new WithdrawalsValidator.AllowedWithdrawals())
.name("Shanghai");
@ -652,31 +547,25 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder cancunDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L);
final BaseFeeMarket cancunFeeMarket =
genesisConfigOptions.isZeroBaseFee()
? FeeMarket.zeroBaseFee(londonForkBlockNumber)
: genesisConfigOptions.isFixedBaseFee()
? FeeMarket.fixedBaseFee(
londonForkBlockNumber, miningParameters.getMinTransactionGasPrice())
: FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
final BaseFeeMarket cancunFeeMarket;
if (genesisConfigOptions.isZeroBaseFee()) {
cancunFeeMarket = FeeMarket.zeroBaseFee(londonForkBlockNumber);
} else if (genesisConfigOptions.isFixedBaseFee()) {
cancunFeeMarket =
FeeMarket.fixedBaseFee(
londonForkBlockNumber, miningParameters.getMinTransactionGasPrice());
} else {
cancunFeeMarket =
FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
}
return shanghaiDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
.feeMarket(cancunFeeMarket)
// gas calculator for EIP-4844 blob gas
.gasCalculator(CancunGasCalculator::new)
@ -704,14 +593,14 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
true,
stackSizeLimit,
evmConfiguration.evmStackSize(),
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
// change to check for max blob gas per block for EIP-4844
.transactionValidatorFactoryBuilder(
(gasCalculator, gasLimitCalculator, feeMarket) ->
(evm, gasLimitCalculator, feeMarket) ->
new TransactionValidatorFactory(
gasCalculator,
evm.getGasCalculator(),
gasLimitCalculator,
feeMarket,
true,
@ -721,7 +610,7 @@ public abstract class MainnetProtocolSpecs {
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB),
SHANGHAI_INIT_CODE_SIZE_LIMIT))
evm.getEvmVersion().getMaxInitcodeSize()))
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun)
.blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::cancunBlockHeaderValidator)
.blockHashProcessor(new CancunBlockHashProcessor())
@ -730,8 +619,6 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder pragueDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
@ -741,13 +628,7 @@ public abstract class MainnetProtocolSpecs {
genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS);
return cancunDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
// EIP-3074 AUTH and AUTCALL gas
.gasCalculator(PragueGasCalculator::new)
// EIP-3074 AUTH and AUTCALL
@ -759,9 +640,9 @@ public abstract class MainnetProtocolSpecs {
// EIP-2537 BLS12-381 precompiles
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::prague)
// EIP-7002 Withdrawls / EIP-6610 Deposits / EIP-7685 Requests
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestsValidator(pragueRequestsValidator(depositContractAddress))
// EIP-7002 Withdrawls / EIP-6610 Deposits / EIP-7685 Requests
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestProcessorCoordinator(pragueRequestsProcessors(depositContractAddress))
// EIP-2935 Blockhash processor
@ -771,23 +652,13 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder pragueEOFDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final int contractSizeLimit =
configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
return pragueDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
// EIP-7692 EOF v1 Gas calculator
.gasCalculator(PragueEOFGasCalculator::new)
// EIP-7692 EOF v1 EVM and opcodes
@ -797,12 +668,11 @@ public abstract class MainnetProtocolSpecs {
gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
// EIP-7698 EOF v1 creation transaction
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1)),
List.of(MaxCodeSizeRule.from(evm), EOFValidationCodeRule.from(evm)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.name("PragueEOF");
@ -810,22 +680,12 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder futureEipsDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
final int contractSizeLimit =
configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT);
return pragueEOFDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
// Use Future EIP configured EVM
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
@ -833,12 +693,11 @@ public abstract class MainnetProtocolSpecs {
gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration))
// change contract call creator to accept EOF code
.contractCreationProcessorBuilder(
(gasCalculator, evm) ->
evm ->
new ContractCreationProcessor(
gasCalculator,
evm,
true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1)),
List.of(MaxCodeSizeRule.from(evm), EOFValidationCodeRule.from(evm)),
1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
// use future configured precompiled contracts
@ -848,21 +707,13 @@ public abstract class MainnetProtocolSpecs {
static ProtocolSpecBuilder experimentalEipsDefinition(
final Optional<BigInteger> chainId,
final OptionalInt configContractSizeLimit,
final OptionalInt configStackSizeLimit,
final boolean enableRevertReason,
final GenesisConfigOptions genesisConfigOptions,
final EvmConfiguration evmConfiguration,
final MiningParameters miningParameters) {
return futureEipsDefinition(
chainId,
configContractSizeLimit,
configStackSizeLimit,
enableRevertReason,
genesisConfigOptions,
evmConfiguration,
miningParameters)
chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters)
.evmBuilder(
(gasCalculator, jdCacheConfig) ->
MainnetEVMs.experimentalEips(
@ -929,13 +780,7 @@ public abstract class MainnetProtocolSpecs {
transactionProcessingResult.getRevertReason());
}
private static class DaoBlockProcessor implements BlockProcessor {
private final BlockProcessor wrapped;
public DaoBlockProcessor(final BlockProcessor wrapped) {
this.wrapped = wrapped;
}
private record DaoBlockProcessor(BlockProcessor wrapped) implements BlockProcessor {
@Override
public BlockProcessingResult processBlock(
@ -965,7 +810,8 @@ public abstract class MainnetProtocolSpecs {
final JsonArray json =
new JsonArray(
Resources.toString(
this.getClass().getResource("/daoAddresses.json"), StandardCharsets.UTF_8));
Objects.requireNonNull(this.getClass().getResource("/daoAddresses.json")),
StandardCharsets.UTF_8));
final List<Address> addresses =
IntStream.range(0, json.size())
.mapToObj(json::getString)

@ -24,6 +24,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.math.BigInteger;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.TreeMap;
import java.util.function.Function;
@ -45,8 +46,6 @@ public class ProtocolScheduleBuilder {
private final MiningParameters miningParameters;
private final BadBlockManager badBlockManager;
private DefaultProtocolSchedule protocolSchedule;
public ProtocolScheduleBuilder(
final GenesisConfigOptions config,
final BigInteger defaultChainId,
@ -107,7 +106,7 @@ public class ProtocolScheduleBuilder {
public ProtocolSchedule createProtocolSchedule() {
final Optional<BigInteger> chainId = config.getChainId().or(() -> defaultChainId);
protocolSchedule = new DefaultProtocolSchedule(chainId);
DefaultProtocolSchedule protocolSchedule = new DefaultProtocolSchedule(chainId);
initSchedule(protocolSchedule, chainId);
return protocolSchedule;
}
@ -118,18 +117,18 @@ public class ProtocolScheduleBuilder {
final MainnetProtocolSpecFactory specFactory =
new MainnetProtocolSpecFactory(
chainId,
config.getContractSizeLimit(),
config.getEvmStackSize(),
isRevertReasonEnabled,
config.getEcip1017EraRounds(),
evmConfiguration,
evmConfiguration.overrides(
config.getContractSizeLimit(), OptionalInt.empty(), config.getEvmStackSize()),
miningParameters);
validateForkOrdering();
final NavigableMap<Long, BuilderMapEntry> builders = buildMilestoneMap(specFactory);
// At this stage, all milestones are flagged with correct modifier, but ProtocolSpecs must be
// At this stage, all milestones are flagged with the correct modifier, but ProtocolSpecs must
// be
// inserted _AT_ the modifier block entry.
if (!builders.isEmpty()) {
protocolSpecAdapters.stream()
@ -143,10 +142,7 @@ public class ProtocolScheduleBuilder {
builders.put(
modifierBlock,
new BuilderMapEntry(
parent.milestoneType,
modifierBlock,
parent.getBuilder(),
entry.getValue()));
parent.milestoneType, modifierBlock, parent.builder(), entry.getValue()));
});
}
@ -158,8 +154,8 @@ public class ProtocolScheduleBuilder {
addProtocolSpec(
protocolSchedule,
e.milestoneType,
e.getBlockIdentifier(),
e.getBuilder(),
e.blockIdentifier(),
e.builder(),
e.modifier));
// NOTE: It is assumed that Daofork blocks will not be used for private networks
@ -173,8 +169,8 @@ public class ProtocolScheduleBuilder {
final ProtocolSpec originalProtocolSpec =
getProtocolSpec(
protocolSchedule,
previousSpecBuilder.getBuilder(),
previousSpecBuilder.getModifier());
previousSpecBuilder.builder(),
previousSpecBuilder.modifier());
addProtocolSpec(
protocolSchedule,
BuilderMapEntry.MilestoneType.BLOCK_NUMBER,
@ -201,14 +197,13 @@ public class ProtocolScheduleBuilder {
final ProtocolSpec originalProtocolSpec =
getProtocolSpec(
protocolSchedule,
previousSpecBuilder.getBuilder(),
previousSpecBuilder.getModifier());
previousSpecBuilder.builder(),
previousSpecBuilder.modifier());
addProtocolSpec(
protocolSchedule,
BuilderMapEntry.MilestoneType.BLOCK_NUMBER,
classicBlockNumber,
ClassicProtocolSpecs.classicRecoveryInitDefinition(
config.getContractSizeLimit(), config.getEvmStackSize(), evmConfiguration),
ClassicProtocolSpecs.classicRecoveryInitDefinition(evmConfiguration),
Function.identity());
protocolSchedule.putBlockNumberMilestone(
classicBlockNumber + 1, originalProtocolSpec);
@ -298,7 +293,7 @@ public class ProtocolScheduleBuilder {
.flatMap(Optional::stream)
.collect(
Collectors.toMap(
BuilderMapEntry::getBlockIdentifier,
BuilderMapEntry::blockIdentifier,
b -> b,
(existing, replacement) -> replacement,
TreeMap::new));
@ -413,34 +408,11 @@ public class ProtocolScheduleBuilder {
}
}
private static class BuilderMapEntry {
private final MilestoneType milestoneType;
private final long blockIdentifier;
private final ProtocolSpecBuilder builder;
private final Function<ProtocolSpecBuilder, ProtocolSpecBuilder> modifier;
public BuilderMapEntry(
final MilestoneType milestoneType,
final long blockIdentifier,
final ProtocolSpecBuilder builder,
final Function<ProtocolSpecBuilder, ProtocolSpecBuilder> modifier) {
this.milestoneType = milestoneType;
this.blockIdentifier = blockIdentifier;
this.builder = builder;
this.modifier = modifier;
}
public long getBlockIdentifier() {
return blockIdentifier;
}
public ProtocolSpecBuilder getBuilder() {
return builder;
}
public Function<ProtocolSpecBuilder, ProtocolSpecBuilder> getModifier() {
return modifier;
}
private record BuilderMapEntry(
ProtocolScheduleBuilder.BuilderMapEntry.MilestoneType milestoneType,
long blockIdentifier,
ProtocolSpecBuilder builder,
Function<ProtocolSpecBuilder, ProtocolSpecBuilder> modifier) {
private enum MilestoneType {
BLOCK_NUMBER,

@ -60,7 +60,7 @@ public class ProtocolSpecBuilder {
private Function<FeeMarket, BlockHeaderValidator.Builder> blockHeaderValidatorBuilder;
private Function<FeeMarket, BlockHeaderValidator.Builder> ommerHeaderValidatorBuilder;
private Function<ProtocolSchedule, BlockBodyValidator> blockBodyValidatorBuilder;
private BiFunction<GasCalculator, EVM, AbstractMessageProcessor> contractCreationProcessorBuilder;
private Function<EVM, AbstractMessageProcessor> contractCreationProcessorBuilder;
private Function<PrecompiledContractConfiguration, PrecompileContractRegistry>
precompileContractRegistryBuilder;
private BiFunction<EVM, PrecompileContractRegistry, AbstractMessageProcessor>
@ -155,8 +155,7 @@ public class ProtocolSpecBuilder {
}
public ProtocolSpecBuilder contractCreationProcessorBuilder(
final BiFunction<GasCalculator, EVM, AbstractMessageProcessor>
contractCreationProcessorBuilder) {
final Function<EVM, AbstractMessageProcessor> contractCreationProcessorBuilder) {
this.contractCreationProcessorBuilder = contractCreationProcessorBuilder;
return this;
}
@ -165,7 +164,7 @@ public class ProtocolSpecBuilder {
final Function<PrecompiledContractConfiguration, PrecompileContractRegistry>
precompileContractRegistryBuilder) {
this.precompileContractRegistryBuilder =
(precompiledContractConfiguration) -> {
precompiledContractConfiguration -> {
final PrecompileContractRegistry registry =
precompileContractRegistryBuilder.apply(precompiledContractConfiguration);
if (precompiledContractConfiguration.getPrivacyParameters().isEnabled()) {
@ -327,9 +326,9 @@ public class ProtocolSpecBuilder {
final PrecompiledContractConfiguration precompiledContractConfiguration =
new PrecompiledContractConfiguration(gasCalculator, privacyParameters);
final TransactionValidatorFactory transactionValidatorFactory =
transactionValidatorFactoryBuilder.apply(gasCalculator, gasLimitCalculator, feeMarket);
transactionValidatorFactoryBuilder.apply(evm, gasLimitCalculator, feeMarket);
final AbstractMessageProcessor contractCreationProcessor =
contractCreationProcessorBuilder.apply(gasCalculator, evm);
contractCreationProcessorBuilder.apply(evm);
final PrecompileContractRegistry precompileContractRegistry =
precompileContractRegistryBuilder.apply(precompiledContractConfiguration);
final AbstractMessageProcessor messageCallProcessor =
@ -507,6 +506,6 @@ public class ProtocolSpecBuilder {
public interface TransactionValidatorFactoryBuilder {
TransactionValidatorFactory apply(
GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket);
EVM evm, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket);
}
}

@ -18,7 +18,6 @@ import static org.hyperledger.besu.evmtool.BenchmarkSubCommand.COMMAND_NAME;
import static picocli.CommandLine.ScopeType.INHERIT;
import org.hyperledger.besu.BesuInfo;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evmtool.benchmarks.AltBN128Benchmark;
import org.hyperledger.besu.evmtool.benchmarks.BenchmarkExecutor;
import org.hyperledger.besu.evmtool.benchmarks.ECRecoverBenchmark;
@ -64,12 +63,6 @@ public class BenchmarkSubCommand implements Runnable {
negatable = true)
Boolean nativeCode;
@Option(
names = {"--fork"},
paramLabel = "<String>",
description = "Fork to evaluate, when it impacts gas costing.")
String fork = EvmSpecVersion.defaultVersion().getName();
@Parameters(description = "One or more of ${COMPLETION-CANDIDATES}.")
EnumSet<Benchmark> benchmarks = EnumSet.noneOf(Benchmark.class);
@ -91,7 +84,7 @@ public class BenchmarkSubCommand implements Runnable {
var benchmarksToRun = benchmarks.isEmpty() ? EnumSet.allOf(Benchmark.class) : benchmarks;
for (var benchmark : benchmarksToRun) {
System.out.println("Benchmarks for " + benchmark);
benchmark.benchmarkExecutor.runBenchmark(output, nativeCode, fork);
benchmark.benchmarkExecutor.runBenchmark(output, nativeCode, parentCommand.getFork());
}
}
}

@ -17,9 +17,12 @@ package org.hyperledger.besu.evmtool;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hyperledger.besu.evmtool.CodeValidateSubCommand.COMMAND_NAME;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.CodeV1Validation;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.code.EOFLayout;
import org.hyperledger.besu.util.LogConfigurator;
@ -27,9 +30,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -37,7 +38,9 @@ import java.util.stream.IntStream;
import org.apache.tuweni.bytes.Bytes;
import picocli.CommandLine;
import picocli.CommandLine.ParentCommand;
@SuppressWarnings({"ConstantValue", "DataFlowIssue"})
@CommandLine.Command(
name = COMMAND_NAME,
description = "Validates EVM code for fuzzing",
@ -45,8 +48,10 @@ import picocli.CommandLine;
versionProvider = VersionProvider.class)
public class CodeValidateSubCommand implements Runnable {
public static final String COMMAND_NAME = "code-validate";
private final InputStream input;
private final PrintStream output;
@ParentCommand EvmToolCommand parentCommand;
private final EVM evm;
@CommandLine.Option(
names = {"--file"},
@ -60,41 +65,46 @@ public class CodeValidateSubCommand implements Runnable {
@SuppressWarnings("unused")
public CodeValidateSubCommand() {
// PicoCLI requires this
this(System.in, System.out);
this(null);
}
CodeValidateSubCommand(final InputStream input, final PrintStream output) {
this.input = input;
this.output = output;
CodeValidateSubCommand(final EvmToolCommand parentCommand) {
this.parentCommand = parentCommand;
String fork = EvmSpecVersion.PRAGUE.getName();
if (parentCommand != null && parentCommand.hasFork()) {
fork = parentCommand.getFork();
}
ProtocolSpec protocolSpec = ReferenceTestProtocolSchedules.create().geSpecByName(fork);
evm = protocolSpec.getEvm();
}
@Override
public void run() {
LogConfigurator.setLevel("", "OFF");
if (cliCode.isEmpty() && codeFile == null) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(input, UTF_8))) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(parentCommand.in, UTF_8))) {
checkCodeFromBufferedReader(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
if (codeFile != null) {
try (BufferedReader in = new BufferedReader(new FileReader(codeFile, UTF_8))) {
checkCodeFromBufferedReader(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else if (codeFile != null) {
try (BufferedReader in = new BufferedReader(new FileReader(codeFile, UTF_8))) {
checkCodeFromBufferedReader(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
for (String code : cliCode) {
output.print(considerCode(code));
parentCommand.out.print(considerCode(code));
}
}
parentCommand.out.flush();
}
private void checkCodeFromBufferedReader(final BufferedReader in) {
try {
for (String code = in.readLine(); code != null; code = in.readLine()) {
output.print(considerCode(code));
parentCommand.out.print(considerCode(code));
}
} catch (IOException e) {
throw new RuntimeException(e);
@ -114,24 +124,22 @@ public class CodeValidateSubCommand implements Runnable {
return "";
}
EOFLayout layout = EOFLayout.parseEOF(codeBytes);
EOFLayout layout = evm.parseEOF(codeBytes);
if (!layout.isValid()) {
return "err: layout - " + layout.invalidReason() + "\n";
}
String error = CodeV1Validation.validate(layout);
if (error != null) {
return "err: " + error + "\n";
Code code = evm.getCodeUncached(codeBytes);
if (code instanceof CodeInvalid codeInvalid) {
return "err: " + codeInvalid.getInvalidReason();
} else {
return "OK "
+ IntStream.range(0, code.getCodeSectionCount())
.mapToObj(code::getCodeSection)
.map(cs -> code.getBytes().slice(cs.getEntryPoint(), cs.getLength()))
.map(Bytes::toUnprefixedHexString)
.collect(Collectors.joining(","))
+ "\n";
}
Code code = CodeFactory.createCode(codeBytes, 1);
return "OK "
+ IntStream.range(0, code.getCodeSectionCount())
.mapToObj(code::getCodeSection)
.map(cs -> layout.container().slice(cs.getEntryPoint(), cs.getLength()))
.map(Bytes::toUnprefixedHexString)
.collect(Collectors.joining(","))
+ "\n";
}
}

@ -20,13 +20,13 @@ import static org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec.TestR
import static org.hyperledger.besu.evmtool.EOFTestSubCommand.COMMAND_NAME;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec;
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec.TestResult;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.code.CodeV1;
import org.hyperledger.besu.evm.code.CodeV1Validation;
import org.hyperledger.besu.evm.code.EOFLayout;
import org.hyperledger.besu.util.LogConfigurator;
@ -57,16 +57,14 @@ public class EOFTestSubCommand implements Runnable {
// picocli does it magically
@CommandLine.Parameters private final List<Path> eofTestFiles = new ArrayList<>();
@CommandLine.Option(
names = {"--fork-name"},
description = "Limit execution to one fork.")
private String forkName = null;
@CommandLine.Option(
names = {"--test-name"},
description = "Limit execution to one test.")
private String testVectorName = null;
EVM evm;
String fork = null;
public EOFTestSubCommand() {
this(null);
}
@ -82,6 +80,14 @@ public class EOFTestSubCommand implements Runnable {
SignatureAlgorithmFactory.setDefaultInstance();
final ObjectMapper eofTestMapper = JsonUtils.createObjectMapper();
if (parentCommand.hasFork()) {
fork = parentCommand.getFork();
}
ProtocolSpec protocolSpec =
ReferenceTestProtocolSchedules.create()
.geSpecByName(fork == null ? EvmSpecVersion.PRAGUE.getName() : fork);
evm = protocolSpec.getEvm();
final JavaType javaType =
eofTestMapper
.getTypeFactory()
@ -146,7 +152,8 @@ public class EOFTestSubCommand implements Runnable {
String code = testVector.getValue().code();
for (var testResult : testVector.getValue().results().entrySet()) {
String expectedForkName = testResult.getKey();
if (forkName != null && !forkName.equals(expectedForkName)) {
if (fork != null && !fork.equals(expectedForkName)) {
System.out.println("Wrong fork - " + fork + " != " + expectedForkName);
continue;
}
TestResult expectedResult = testResult.getValue();
@ -210,16 +217,10 @@ public class EOFTestSubCommand implements Runnable {
return failed("layout - " + layout.invalidReason());
}
var code = CodeFactory.createCode(codeBytes, 1);
var code = evm.getCodeUncached(codeBytes);
if (!code.isValid()) {
return failed("validate " + ((CodeInvalid) code).getInvalidReason());
}
if (code instanceof CodeV1 codeV1) {
var result = CodeV1Validation.validate(codeV1.getEofLayout());
if (result != null) {
return (failed("deep validate error: " + result));
}
}
return passed();
}

@ -322,6 +322,14 @@ public class EvmToolCommand implements Runnable {
subCommandLine.setHelpSectionKeys(keys);
}
public String getFork() {
return daggerOptions.provideFork().orElse(EvmSpecVersion.defaultVersion().getName());
}
public boolean hasFork() {
return daggerOptions.provideFork().isPresent();
}
@Override
public void run() {
LogConfigurator.setLevel("", "OFF");
@ -340,8 +348,7 @@ public class EvmToolCommand implements Runnable {
.build();
int remainingIters = this.repeat;
final ProtocolSpec protocolSpec =
component.getProtocolSpec().apply(BlockHeaderBuilder.createDefault().buildBlockHeader());
final ProtocolSpec protocolSpec = component.getProtocolSpec();
final Transaction tx =
new Transaction.Builder()
.nonce(0)

@ -15,14 +15,13 @@
package org.hyperledger.besu.evmtool;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.metrics.MetricsConfigurationModule;
import org.hyperledger.besu.metrics.MetricsSystemModule;
import java.util.function.Function;
import javax.inject.Singleton;
import dagger.Component;
@ -40,7 +39,9 @@ import dagger.Component;
})
public interface EvmToolComponent {
Function<BlockHeader, ProtocolSpec> getProtocolSpec();
ProtocolSpec getProtocolSpec();
EVM getEVM();
WorldUpdater getWorldUpdater();

@ -27,9 +27,11 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.math.BigInteger;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
@ -68,13 +70,15 @@ class MainnetGenesisFileModule extends GenesisFileModule {
}
}
if (fork.isPresent()) {
var schedules = createSchedules();
var schedule = schedules.get(fork.map(String::toLowerCase).get());
if (schedule != null) {
return schedule.get();
}
var schedules = createSchedules();
var schedule =
schedules.get(
fork.orElse(EvmSpecVersion.defaultVersion().getName())
.toLowerCase(Locale.getDefault()));
if (schedule != null) {
return schedule.get();
}
return MainnetProtocolSchedule.fromConfig(
configOptions, evmConfiguration, MiningParameters.newDefault(), new BadBlockManager());
}

@ -16,7 +16,11 @@ package org.hyperledger.besu.evmtool;
import static org.hyperledger.besu.evmtool.PrettyPrintSubCommand.COMMAND_NAME;
import org.hyperledger.besu.evm.code.CodeV1Validation;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.code.EOFLayout;
import org.hyperledger.besu.util.LogConfigurator;
@ -63,14 +67,20 @@ public class PrettyPrintSubCommand implements Runnable {
"Pretty printing of legacy EVM is not supported. Patches welcome!");
} else {
EOFLayout layout = EOFLayout.parseEOF(container);
String fork = EvmSpecVersion.PRAGUE.getName();
if (parentCommand.hasFork()) {
fork = parentCommand.getFork();
}
ProtocolSpec protocolSpec = ReferenceTestProtocolSchedules.create().geSpecByName(fork);
EVM evm = protocolSpec.getEvm();
EOFLayout layout = evm.parseEOF(container);
if (layout.isValid()) {
String validation = CodeV1Validation.validate(layout);
if (validation == null || force) {
var validatedCode = evm.getCodeUncached(container);
if (validatedCode.isValid() || force) {
layout.prettyPrint(parentCommand.out);
}
if (validation != null) {
parentCommand.out.println("EOF code is invalid - " + validation);
if (validatedCode instanceof CodeInvalid codeInvalid) {
parentCommand.out.println("EOF code is invalid - " + codeInvalid.getInvalidReason());
}
} else {
parentCommand.out.println("EOF layout is invalid - " + layout.invalidReason());

@ -14,11 +14,11 @@
*/
package org.hyperledger.besu.evmtool;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.evm.EVM;
import java.util.function.Function;
import javax.inject.Singleton;
import dagger.Module;
@ -30,7 +30,17 @@ public class ProtocolModule {
@Provides
@Singleton
Function<BlockHeader, ProtocolSpec> getProtocolSpec(final ProtocolSchedule protocolSchedule) {
return protocolSchedule::getByBlockHeader;
ProtocolSpec getProtocolSpec(final ProtocolSchedule protocolSchedule) {
return protocolSchedule.getByBlockHeader(
BlockHeaderBuilder.createDefault()
.timestamp(Long.MAX_VALUE)
.number(Long.MAX_VALUE)
.buildBlockHeader());
}
@Provides
@Singleton
EVM getEVM(final ProtocolSpec protocolSpec) {
return protocolSpec.getEvm();
}
}

@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import org.junit.jupiter.api.Test;
import picocli.CommandLine;
@ -44,8 +44,8 @@ class CodeValidationSubCommandTest {
void testSingleValidViaInput() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(CODE_STOP_ONLY.getBytes(UTF_8));
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("OK 00\n");
}
@ -54,8 +54,8 @@ class CodeValidationSubCommandTest {
void testSingleInvalidViaInput() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(CODE_BAD_MAGIC.getBytes(UTF_8));
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8)).contains("err: layout - EOF header byte 1 incorrect\n");
}
@ -64,8 +64,8 @@ class CodeValidationSubCommandTest {
void testMultipleViaInput() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(CODE_MULTIPLE.getBytes(UTF_8));
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8))
.contains(
@ -80,8 +80,8 @@ class CodeValidationSubCommandTest {
void testSingleValidViaCli() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_STOP_ONLY);
codeValidateSubCommand.run();
@ -92,8 +92,8 @@ class CodeValidationSubCommandTest {
void testSingleInvalidViaCli() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_BAD_MAGIC);
codeValidateSubCommand.run();
@ -104,8 +104,8 @@ class CodeValidationSubCommandTest {
void testMultipleViaCli() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_STOP_ONLY, CODE_BAD_MAGIC, CODE_RETURN_ONLY);
codeValidateSubCommand.run();
@ -122,8 +122,8 @@ class CodeValidationSubCommandTest {
void testCliEclipsesInput() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(CODE_STOP_ONLY.getBytes(UTF_8));
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_RETURN_ONLY);
codeValidateSubCommand.run();
@ -134,8 +134,8 @@ class CodeValidationSubCommandTest {
void testInteriorCommentsSkipped() {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]);
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
final CommandLine cmd = new CommandLine(codeValidateSubCommand);
cmd.parseArgs(CODE_INTERIOR_COMMENTS);
codeValidateSubCommand.run();
@ -147,8 +147,8 @@ class CodeValidationSubCommandTest {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais =
new ByteArrayInputStream(("# comment\n\n#blank line\n\n" + CODE_MULTIPLE).getBytes(UTF_8));
final CodeValidateSubCommand codeValidateSubCommand =
new CodeValidateSubCommand(bais, new PrintStream(baos));
EvmToolCommand parentCommand = new EvmToolCommand(bais, new PrintWriter(baos, true, UTF_8));
final CodeValidateSubCommand codeValidateSubCommand = new CodeValidateSubCommand(parentCommand);
codeValidateSubCommand.run();
assertThat(baos.toString(UTF_8))
.isEqualTo(

@ -17,10 +17,13 @@ package org.hyperledger.besu.ethereum.referencetests;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
@ -102,6 +105,16 @@ public class ReferenceTestProtocolSchedules {
return schedules.get(name);
}
public ProtocolSpec geSpecByName(final String name) {
ProtocolSchedule schedule = getByName(name);
if (schedule == null) {
return null;
}
BlockHeader header =
new BlockHeaderTestFixture().timestamp(Long.MAX_VALUE).number(Long.MAX_VALUE).buildHeader();
return schedule.getByBlockHeader(header);
}
private static ProtocolSchedule createSchedule(final GenesisConfigOptions options) {
return new ProtocolScheduleBuilder(
options,

@ -23,12 +23,10 @@ import java.util.List;
import java.util.Map;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.code.CodeV1;
import org.hyperledger.besu.evm.code.CodeV1Validation;
import org.hyperledger.besu.evm.code.EOFLayout;
import org.hyperledger.besu.testutil.JsonTestParameters;
@ -74,7 +72,7 @@ public class EOFReferenceTestTools {
params.ignore("EOF1_undefined_opcodes_186");
// embedded containers rules changed
params.ignore("EOF1_embedded_container");
params.ignore("efValidation/EOF1_embedded_container-Prague\\[EOF1_embedded_container_\\d+\\]");
// truncated data is only allowed in embedded containers
params.ignore("ori/validInvalid-Prague\\[validInvalid_48\\]");
@ -101,19 +99,20 @@ public class EOFReferenceTestTools {
return params.generate(filePath);
}
@SuppressWarnings("java:S5960") // This is not production code, this is testing code.
public static void executeTest(
final String fork, final Bytes code, final EOFTestCaseSpec.TestResult expected) {
EvmSpecVersion evmVersion = EvmSpecVersion.fromName(fork);
assertThat(evmVersion).isNotNull();
EVM evm = ReferenceTestProtocolSchedules.create().geSpecByName(fork).getEvm();
assertThat(evm).isNotNull();
// hardwire in the magic byte transaction checks
if (evmVersion.getMaxEofVersion() < 1) {
if (evm.getMaxEOFVersion() < 1) {
assertThat(expected.exception()).isEqualTo("EOF_InvalidCode");
} else {
EOFLayout layout = EOFLayout.parseEOF(code);
if (layout.isValid()) {
Code parsedCode = CodeFactory.createCode(code, evmVersion.getMaxEofVersion());
Code parsedCode = evm.getCodeUncached(code);
assertThat(parsedCode.isValid())
.withFailMessage(
() ->
@ -125,22 +124,8 @@ public class EOFReferenceTestTools {
? null
: ((CodeInvalid) parsedCode).getInvalidReason()))
.isEqualTo(expected.result());
if (parsedCode instanceof CodeV1 codeV1) {
var deepValidate = CodeV1Validation.validate(codeV1.getEofLayout());
assertThat(deepValidate)
.withFailMessage(
() ->
codeV1.prettyPrint()
+ "\nExpected exception :"
+ expected.exception()
+ " actual exception :"
+ (parsedCode.isValid() ? null : deepValidate))
.isNull();
}
if (expected.result()) {
System.out.println(code);
System.out.println(layout.writeContainer(null));
assertThat(code)
.withFailMessage("Container round trip failed")
.isEqualTo(layout.writeContainer(null));

@ -39,6 +39,13 @@ public interface Code {
*/
int getDataSize();
/**
* Declared size of the data in bytes. For containers with aux data this may be larger.
*
* @return the declared data size
*/
int getDeclaredDataSize();
/**
* Get the bytes for the entire container, for example what EXTCODECOPY would want. For V0 it is
* the same as getCodeBytes, for V1 it is the entire container, not just the data section.
@ -107,9 +114,10 @@ public interface Code {
* @param index the index in the container to return
* @param auxData any Auxiliary data to append to the subcontainer code. If fetching an initcode
* container, pass null.
* @param evm the EVM in which we are instantiating the code
* @return Either the subcontainer, or empty.
*/
Optional<Code> getSubContainer(final int index, final Bytes auxData);
Optional<Code> getSubContainer(final int index, final Bytes auxData, EVM evm);
/**
* Loads data from the appropriate data section

@ -20,6 +20,7 @@ import static org.hyperledger.besu.evm.operation.SwapOperation.SWAP_BASE;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.EOFLayout;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.frame.MessageFrame.State;
@ -87,6 +88,7 @@ public class EVM {
private final OperationRegistry operations;
private final GasCalculator gasCalculator;
private final Operation endOfScriptStop;
private final CodeFactory codeFactory;
private final CodeCache codeCache;
private final EvmConfiguration evmConfiguration;
private final EvmSpecVersion evmSpecVersion;
@ -114,6 +116,11 @@ public class EVM {
this.codeCache = new CodeCache(evmConfiguration);
this.evmSpecVersion = evmSpecVersion;
codeFactory =
new CodeFactory(
evmSpecVersion.maxEofVersion,
evmConfiguration.maxInitcodeSizeOverride().orElse(evmSpecVersion.maxInitcodeSize));
enableShanghai = EvmSpecVersion.SHANGHAI.ordinal() <= evmSpecVersion.ordinal();
}
@ -365,7 +372,7 @@ public class EVM {
* @return the code
*/
public Code getCodeUncached(final Bytes codeBytes) {
return CodeFactory.createCode(codeBytes, evmSpecVersion.getMaxEofVersion());
return codeFactory.createCode(codeBytes);
}
/**
@ -375,6 +382,16 @@ public class EVM {
* @return the code
*/
public Code getCodeForCreation(final Bytes codeBytes) {
return CodeFactory.createCode(codeBytes, evmSpecVersion.getMaxEofVersion(), false, true);
return codeFactory.createCode(codeBytes, true);
}
/**
* Parse the EOF Layout of a byte-stream. No Code or stack validation is performed.
*
* @param bytes the bytes to parse
* @return an EOF layout represented by they byte-stream.
*/
public EOFLayout parseEOF(final Bytes bytes) {
return EOFLayout.parseEOF(bytes, true);
}
}

@ -23,49 +23,58 @@ import org.slf4j.LoggerFactory;
/** The enum Evm spec version. */
public enum EvmSpecVersion {
/** Frontier evm spec version. */
FRONTIER(0, true, "Frontier", "Finalized"),
FRONTIER(Integer.MAX_VALUE, Integer.MAX_VALUE, 0, true, "Frontier", "Finalized"),
/** Homestead evm spec version. */
HOMESTEAD(0, true, "Homestead", "Finalized"),
HOMESTEAD(Integer.MAX_VALUE, Integer.MAX_VALUE, 0, true, "Homestead", "Finalized"),
/** Tangerine Whistle evm spec version. */
TANGERINE_WHISTLE(0, true, "Tangerine Whistle", "Finalized"),
TANGERINE_WHISTLE(
Integer.MAX_VALUE, Integer.MAX_VALUE, 0, true, "Tangerine Whistle", "Finalized"),
/** Spurious Dragon evm spec version. */
SPURIOUS_DRAGON(0, true, "Spuruous Dragon", "Finalized"),
SPURIOUS_DRAGON(0x6000, Integer.MAX_VALUE, 0, true, "Spuruous Dragon", "Finalized"),
/** Byzantium evm spec version. */
BYZANTIUM(0, true, "Byzantium", "Finalized"),
BYZANTIUM(0x6000, Integer.MAX_VALUE, 0, true, "Byzantium", "Finalized"),
/** Constantinople evm spec version. */
CONSTANTINOPLE(0, true, "Constantinople", "Did not reach Mainnet"),
CONSTANTINOPLE(0x6000, Integer.MAX_VALUE, 0, true, "Constantinople", "Did not reach Mainnet"),
/** Petersburg / ConstantinopleFix evm spec version. */
PETERSBURG(0, true, "ConstantinopleFix", "Finalized (also called Petersburg)"),
PETERSBURG(
0x6000,
Integer.MAX_VALUE,
0,
true,
"ConstantinopleFix",
"Finalized (also called Petersburg)"),
/** Istanbul evm spec version. */
ISTANBUL(0, true, "Istanbul", "Finalized"),
ISTANBUL(0x6000, Integer.MAX_VALUE, 0, true, "Istanbul", "Finalized"),
/** Berlin evm spec version */
BERLIN(0, true, "Berlin", "Finalized"),
BERLIN(0x6000, Integer.MAX_VALUE, 0, true, "Berlin", "Finalized"),
/** London evm spec version. */
LONDON(0, true, "London", "Finalized"),
LONDON(0x6000, Integer.MAX_VALUE, 0, true, "London", "Finalized"),
/** Paris evm spec version. */
PARIS(0, true, "Merge", "Finalized (also called Paris)"),
PARIS(0x6000, Integer.MAX_VALUE, 0, true, "Merge", "Finalized (also called Paris)"),
/** Shanghai evm spec version. */
SHANGHAI(0, true, "Shanghai", "Finalized"),
SHANGHAI(0x6000, 0xc000, 0, true, "Shanghai", "Finalized"),
/** Cancun evm spec version. */
CANCUN(0, true, "Cancun", "Finalized"),
CANCUN(0x6000, 0xc000, 0, true, "Cancun", "Finalized"),
/** Prague evm spec version. */
PRAGUE(0, false, "Prague", "In Development"),
PRAGUE(0x6000, 0xc000, 0, false, "Prague", "In Development"),
/** PragueEOF evm spec version. */
PRAGUE_EOF(1, false, "PragueEOF", "Prague + EOF. In Development"),
PRAGUE_EOF(0x6000, 0xc000, 1, false, "PragueEOF", "Prague + EOF. In Development"),
/** Osaka evm spec version. */
OSAKA(1, false, "Osaka", "Placeholder"),
OSAKA(0x6000, 0xc000, 1, false, "Osaka", "Placeholder"),
/** Amstedam evm spec version. */
AMSTERDAM(1, false, "Amsterdam", "Placeholder"),
AMSTERDAM(0x6000, 0xc000, 1, false, "Amsterdam", "Placeholder"),
/** Bogota evm spec version. */
BOGOTA(1, false, "Bogota", "Placeholder"),
BOGOTA(0x6000, 0xc000, 1, false, "Bogota", "Placeholder"),
/** Polis evm spec version. */
POLIS(1, false, "Polis", "Placeholder"),
POLIS(0x6000, 0xc000, 1, false, "Polis", "Placeholder"),
/** Bogota evm spec version. */
BANGKOK(1, false, "Bangkok", "Placeholder"),
BANGKOK(0x6000, 0xc000, 1, false, "Bangkok", "Placeholder"),
/** Development fork for unscheduled EIPs */
FUTURE_EIPS(1, false, "Future_EIPs", "Development, for accepted and unscheduled EIPs"),
FUTURE_EIPS(
0x6000, 0xc000, 1, false, "Future_EIPs", "Development, for accepted and unscheduled EIPs"),
/** Development fork for EIPs not accepted to Mainnet */
EXPERIMENTAL_EIPS(1, false, "Experimental_EIPs", "Development, for experimental EIPs");
EXPERIMENTAL_EIPS(
0x6000, 0xc000, 1, false, "Experimental_EIPs", "Development, for experimental EIPs");
private static final Logger LOGGER = LoggerFactory.getLogger(EvmSpecVersion.class);
@ -75,6 +84,12 @@ public enum EvmSpecVersion {
/** The Max eof version. */
final int maxEofVersion;
/** Maximum size of deployed code */
final int maxCodeSize;
/** Maximum size of initcode */
final int maxInitcodeSize;
/** Public name matching execution-spec-tests name */
final String name;
@ -85,11 +100,15 @@ public enum EvmSpecVersion {
boolean versionWarned = false;
EvmSpecVersion(
final int maxCodeSize,
final int maxInitcodeSize,
final int maxEofVersion,
final boolean specFinalized,
final String name,
final String description) {
this.maxEofVersion = maxEofVersion;
this.maxCodeSize = maxCodeSize;
this.maxInitcodeSize = maxInitcodeSize;
this.specFinalized = specFinalized;
this.name = name;
this.description = description;
@ -102,7 +121,13 @@ public enum EvmSpecVersion {
* @return the current mainnet for as of the release of this version of Besu
*/
public static EvmSpecVersion defaultVersion() {
return SHANGHAI;
EvmSpecVersion answer = null;
for (EvmSpecVersion version : EvmSpecVersion.values()) {
if (version.specFinalized) {
answer = version;
}
}
return answer;
}
/**
@ -114,6 +139,24 @@ public enum EvmSpecVersion {
return maxEofVersion;
}
/**
* Gets max deployed code size this EVM supports.
*
* @return the max eof version
*/
public int getMaxCodeSize() {
return maxCodeSize;
}
/**
* Gets max initcode size this EVM supports.
*
* @return the max eof version
*/
public int getMaxInitcodeSize() {
return maxInitcodeSize;
}
/**
* Name of the fork, in execution-spec-tests form
*

@ -14,112 +14,99 @@
*/
package org.hyperledger.besu.evm.code;
import static org.hyperledger.besu.evm.code.EOFLayout.EOFContainerMode.INITCODE;
import org.hyperledger.besu.evm.Code;
import javax.annotation.Nonnull;
import com.google.errorprone.annotations.InlineMe;
import org.apache.tuweni.bytes.Bytes;
/** The Code factory. */
public final class CodeFactory {
public class CodeFactory {
/** The constant EOF_LEAD_BYTE. */
public static final byte EOF_LEAD_BYTE = -17; // 0xEF in signed byte form
private CodeFactory() {
// factory class, no instantiations.
}
/** Maximum EOF version that can be produced. Legacy is considered EOF version zero. */
protected final int maxEofVersion;
/** Maximum size of the code stream that can be produced, including all header bytes. */
protected final int maxContainerSize;
/** The EOF validator against which EOF layouts will be validated. */
EOFValidator eofValidator;
/**
* Create Code.
* Create a code factory.
*
* @param bytes the bytes
* @param maxEofVersion the max eof version
* @return the code
* @param maxEofVersion Maximum EOF version that can be set
* @param maxContainerSize Maximum size of a container that will be parsed.
*/
public static Code createCode(final Bytes bytes, final int maxEofVersion) {
return createCode(bytes, maxEofVersion, false, false);
public CodeFactory(final int maxEofVersion, final int maxContainerSize) {
this.maxEofVersion = maxEofVersion;
this.maxContainerSize = maxContainerSize;
eofValidator = new CodeV1Validation(maxContainerSize);
}
/**
* Create Code.
*
* @param bytes the bytes
* @param maxEofVersion the max eof version
* @param legacyCreation Allow some corner cases. `EF` and not `EF00` code
* @deprecated use the no boolean or two boolean variant
* @return the code
*/
@Deprecated(since = "24.4.1")
@InlineMe(
replacement = "CodeFactory.createCode(bytes, maxEofVersion, legacyCreation, false)",
imports = "org.hyperledger.besu.evm.code.CodeFactory")
public static Code createCode(
final Bytes bytes, final int maxEofVersion, final boolean legacyCreation) {
return createCode(bytes, maxEofVersion, legacyCreation, false);
public Code createCode(final Bytes bytes) {
return createCode(bytes, false);
}
/**
* Create Code.
*
* @param bytes the bytes
* @param maxEofVersion the max eof version
* @param legacyCreation Allow some corner cases. `EF` and not `EF00` code
* @param createTransaction This is in a create transaction, allow dangling data
* @return the code
*/
public static Code createCode(
final Bytes bytes,
final int maxEofVersion,
final boolean legacyCreation,
final boolean createTransaction) {
if (maxEofVersion == 0) {
return new CodeV0(bytes);
} else if (maxEofVersion == 1) {
int codeSize = bytes.size();
if (codeSize > 0 && bytes.get(0) == EOF_LEAD_BYTE) {
if (codeSize == 1 && !legacyCreation) {
return new CodeV0(bytes);
}
if (codeSize < 3) {
return new CodeInvalid(bytes, "EOF Container too short");
}
if (bytes.get(1) != 0) {
if (legacyCreation) {
// because some 0xef code made it to mainnet, this is only an error at contract create
return new CodeInvalid(bytes, "Incorrect second byte");
} else {
return new CodeV0(bytes);
}
}
int version = bytes.get(2);
if (version != 1) {
return new CodeInvalid(bytes, "Unsupported EOF Version: " + version);
}
public Code createCode(final Bytes bytes, final boolean createTransaction) {
return switch (maxEofVersion) {
case 0 -> new CodeV0(bytes);
case 1 -> createV1Code(bytes, createTransaction);
default -> new CodeInvalid(bytes, "Unsupported max code version " + maxEofVersion);
};
}
final EOFLayout layout = EOFLayout.parseEOF(bytes, !createTransaction);
private @Nonnull Code createV1Code(final Bytes bytes, final boolean createTransaction) {
int codeSize = bytes.size();
if (codeSize > 0 && bytes.get(0) == EOF_LEAD_BYTE) {
if (codeSize < 3) {
return new CodeInvalid(bytes, "EOF Container too short");
}
if (bytes.get(1) != 0) {
if (createTransaction) {
layout.containerMode().set(INITCODE);
// because some 0xef code made it to mainnet, this is only an error at contract creation
// time
return new CodeInvalid(bytes, "Incorrect second byte");
} else {
return new CodeV0(bytes);
}
return createCode(layout, createTransaction);
} else {
return new CodeV0(bytes);
}
int version = bytes.get(2);
if (version != 1) {
return new CodeInvalid(bytes, "Unsupported EOF Version: " + version);
}
final EOFLayout layout = EOFLayout.parseEOF(bytes, !createTransaction);
return createCode(layout);
} else {
return new CodeInvalid(bytes, "Unsupported max code version " + maxEofVersion);
return new CodeV0(bytes);
}
}
@Nonnull
static Code createCode(final EOFLayout layout, final boolean createTransaction) {
Code createCode(final EOFLayout layout) {
if (!layout.isValid()) {
return new CodeInvalid(layout.container(), "Invalid EOF Layout: " + layout.invalidReason());
}
final String validationError = CodeV1Validation.validate(layout);
final String validationError = eofValidator.validate(layout);
if (validationError != null) {
return new CodeInvalid(layout.container(), "EOF Code Invalid : " + validationError);
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.evm.code;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.internal.Words;
import java.util.Optional;
@ -66,6 +67,11 @@ public class CodeInvalid implements Code {
return 0;
}
@Override
public int getDeclaredDataSize() {
return 0;
}
@Override
public Bytes getBytes() {
return codeBytes;
@ -107,7 +113,7 @@ public class CodeInvalid implements Code {
}
@Override
public Optional<Code> getSubContainer(final int index, final Bytes auxData) {
public Optional<Code> getSubContainer(final int index, final Bytes auxData, final EVM evm) {
return Optional.empty();
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.evm.code;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
@ -90,6 +91,11 @@ public class CodeV0 implements Code {
return 0;
}
@Override
public int getDeclaredDataSize() {
return 0;
}
@Override
public Bytes getBytes() {
return bytes;
@ -149,7 +155,7 @@ public class CodeV0 implements Code {
}
@Override
public Optional<Code> getSubContainer(final int index, final Bytes auxData) {
public Optional<Code> getSubContainer(final int index, final Bytes auxData, final EVM evm) {
return Optional.empty();
}

@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.internal.Words;
import java.io.PrintWriter;
@ -94,22 +95,23 @@ public class CodeV1 implements Code {
}
@Override
public Optional<Code> getSubContainer(final int index, final Bytes auxData) {
public Optional<Code> getSubContainer(final int index, final Bytes auxData, final EVM evm) {
EOFLayout subcontainerLayout = eofLayout.getSubcontainer(index);
Bytes codeToLoad;
if (auxData != null && !auxData.isEmpty()) {
Bytes subcontainerWithAuxData = subcontainerLayout.writeContainer(auxData);
if (subcontainerWithAuxData == null) {
codeToLoad = subcontainerLayout.writeContainer(auxData);
if (codeToLoad == null) {
return Optional.empty();
}
subcontainerLayout = EOFLayout.parseEOF(subcontainerWithAuxData);
} else {
// if no auxdata is added we must validate data is not truncated separately
// if no auxdata is added, we must validate data is not truncated separately
if (subcontainerLayout.dataLength() != subcontainerLayout.data().size()) {
return Optional.empty();
}
codeToLoad = subcontainerLayout.container();
}
Code subContainerCode = CodeFactory.createCode(subcontainerLayout, auxData == null);
Code subContainerCode = evm.getCodeForCreation(codeToLoad);
return subContainerCode.isValid() && subContainerCode.getEofVersion() > 0
? Optional.of(subContainerCode)
@ -150,6 +152,11 @@ public class CodeV1 implements Code {
return eofLayout.data().size();
}
@Override
public int getDeclaredDataSize() {
return eofLayout.dataLength();
}
@Override
public int readBigEndianI16(final int index) {
return Words.readBigEndianI16(index, eofLayout.container().toArrayUnsafe());

@ -52,12 +52,20 @@ import javax.annotation.Nullable;
import org.apache.tuweni.bytes.Bytes;
/** Code V1 Validation */
public final class CodeV1Validation {
public class CodeV1Validation implements EOFValidator {
static final int MAX_STACK_HEIGHT = 1024;
private CodeV1Validation() {
// to prevent instantiation
/** Maximum size of the code stream that can be produced, including all header bytes. */
protected final int maxContainerSize;
/**
* Create a new container, with a configurable maximim container size.
*
* @param maxContainerSize the maximum size of any container.
*/
public CodeV1Validation(final int maxContainerSize) {
this.maxContainerSize = maxContainerSize;
}
/**
@ -69,7 +77,12 @@ public final class CodeV1Validation {
*/
@SuppressWarnings(
"ReferenceEquality") // comparison `container != layout` is deliberate and correct
public static String validate(final EOFLayout layout) {
@Override
public String validate(final EOFLayout layout) {
if (layout.container().size() > maxContainerSize) {
return "EOF container is larger than maximum size of " + maxContainerSize;
}
Queue<EOFLayout> workList = new ArrayDeque<>(layout.getSubcontainerCount());
workList.add(layout);
@ -87,12 +100,12 @@ public final class CodeV1Validation {
: " in container #" + layout.indexOfSubcontainer(container));
}
final String codeValidationError = CodeV1Validation.validateCode(container);
final String codeValidationError = validateCode(container);
if (codeValidationError != null) {
return codeValidationError;
}
final String stackValidationError = CodeV1Validation.validateStack(container);
final String stackValidationError = validateStack(container);
if (stackValidationError != null) {
return stackValidationError;
}
@ -107,13 +120,14 @@ public final class CodeV1Validation {
* @param eofLayout The EOF Layout
* @return validation code, null otherwise.
*/
public static String validateCode(final EOFLayout eofLayout) {
@Override
public String validateCode(final EOFLayout eofLayout) {
if (!eofLayout.isValid()) {
return "Invalid EOF container - " + eofLayout.invalidReason();
}
for (CodeSection cs : eofLayout.codeSections()) {
var validation =
CodeV1Validation.validateCode(
validateCode(
eofLayout.container().slice(cs.getEntryPoint(), cs.getLength()), cs, eofLayout);
if (validation != null) {
return validation;
@ -128,7 +142,7 @@ public final class CodeV1Validation {
* @param code the code section code
* @return null if valid, otherwise a string containing an error reason.
*/
static String validateCode(
String validateCode(
final Bytes code, final CodeSection thisCodeSection, final EOFLayout eofLayout) {
final int size = code.size();
final BitSet rjumpdests = new BitSet(size);
@ -359,12 +373,13 @@ public final class CodeV1Validation {
}
@Nullable
static String validateStack(final EOFLayout eofLayout) {
@Override
public String validateStack(final EOFLayout eofLayout) {
WorkList workList = new WorkList(eofLayout.getCodeSectionCount());
workList.put(0);
int sectionToValidatie = workList.take();
while (sectionToValidatie >= 0) {
var validation = CodeV1Validation.validateStack(sectionToValidatie, eofLayout, workList);
var validation = validateStack(sectionToValidatie, eofLayout, workList);
if (validation != null) {
return validation;
}
@ -388,7 +403,7 @@ public final class CodeV1Validation {
* @return null if valid, otherwise an error string providing the validation error.
*/
@Nullable
static String validateStack(
String validateStack(
final int codeSectionToValidate, final EOFLayout eofLayout, final WorkList workList) {
if (!eofLayout.isValid()) {
return "EOF Layout invalid - " + eofLayout.invalidReason();

@ -323,7 +323,7 @@ public record EOFLayout(
}
Bytes subcontainer = container.slice(pos, subcontianerSize);
pos += subcontianerSize;
EOFLayout subLayout = EOFLayout.parseEOF(subcontainer);
EOFLayout subLayout = EOFLayout.parseEOF(subcontainer, false);
if (!subLayout.isValid()) {
String invalidSubReason = subLayout.invalidReason;
return invalidLayout(
@ -349,6 +349,10 @@ public record EOFLayout(
} else {
completeContainer = container;
}
if (strictSize && dataSize != data.size()) {
return invalidLayout(
container, version, "Truncated data section when a complete section was required");
}
return new EOFLayout(completeContainer, version, codeSections, subContainers, dataSize, data);
}

@ -0,0 +1,49 @@
/*
* 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.evm.code;
import javax.annotation.Nullable;
/** Code Validation */
public interface EOFValidator {
/**
* Validates the code and stack for the EOF Layout, with optional deep consideration of the
* containers.
*
* @param layout The parsed EOFLayout of the code
* @return either null, indicating no error, or a String describing the validation error.
*/
@Nullable
String validate(final EOFLayout layout);
/**
* Performs code validation of the EOF layout.
*
* @param eofLayout The EOF Layout
* @return validation code, null otherwise.
*/
@Nullable
String validateCode(final EOFLayout eofLayout);
/**
* Performs stack validation of the EOF layout. Presumes that code validation has been perfromed
*
* @param eofLayout The EOF Layout
* @return validation code, null otherwise.
*/
@Nullable
String validateStack(final EOFLayout eofLayout);
}

@ -1,61 +0,0 @@
/*
* 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.evm.contractvalidation;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
/** The Cached invalid code rule. */
public class CachedInvalidCodeRule implements ContractValidationRule {
private final int maxEofVersion;
/**
* Instantiates a new Cached invalid code rule.
*
* @param maxEofVersion the max eof version
*/
public CachedInvalidCodeRule(final int maxEofVersion) {
this.maxEofVersion = maxEofVersion;
}
@Override
public Optional<ExceptionalHaltReason> validate(
final Bytes contractCode, final MessageFrame frame) {
final Code code = CodeFactory.createCode(contractCode, maxEofVersion);
if (!code.isValid()) {
return Optional.of(ExceptionalHaltReason.INVALID_CODE);
} else {
return Optional.empty();
}
}
/**
* Instantiate contract validation rule.
*
* @param specVersion The evm spec version
* @return the contract validation rule
*/
public static ContractValidationRule of(final EvmSpecVersion specVersion) {
return new CachedInvalidCodeRule(specVersion.getMaxEofVersion());
}
}

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.evm.contractvalidation;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -30,7 +31,8 @@ public interface ContractValidationRule {
*
* @param contractCode the contract code to validate
* @param frame the message frame to use for context
* @param evm the EVM against which the validation rule should be considered
* @return the optional halt reason
*/
Optional<ExceptionalHaltReason> validate(Bytes contractCode, MessageFrame frame);
Optional<ExceptionalHaltReason> validate(Bytes contractCode, MessageFrame frame, EVM evm);
}

@ -14,8 +14,9 @@
*/
package org.hyperledger.besu.evm.contractvalidation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -45,13 +46,14 @@ public class EOFValidationCodeRule implements ContractValidationRule {
*
* @param contractCode the contract code to validate
* @param frame the message frame to use for context
* @param evm The EVM against which the validation should be considered against
* @return Either an empty optional on success, or an optional containing one of the invalid
* reasons.
*/
@Override
public Optional<ExceptionalHaltReason> validate(
final Bytes contractCode, final MessageFrame frame) {
Code code = CodeFactory.createCode(contractCode, maxEofVersion);
final Bytes contractCode, final MessageFrame frame, final EVM evm) {
Code code = evm.getCode(Hash.hash(contractCode), contractCode);
if (!code.isValid()) {
LOG.trace("EOF Validation Error: {}", ((CodeInvalid) code).getInvalidReason());
return Optional.of(ExceptionalHaltReason.INVALID_CODE);
@ -73,8 +75,20 @@ public class EOFValidationCodeRule implements ContractValidationRule {
*
* @param maxEofVersion Maximum EOF version to validate
* @return The EOF validation contract validation rule.
* @deprecated use {@link #from(EVM)}
*/
@Deprecated(forRemoval = true, since = "24.6.1")
public static ContractValidationRule of(final int maxEofVersion) {
return new EOFValidationCodeRule(maxEofVersion);
}
/**
* Create EOF validation.
*
* @param evm The EVM for which we are enforcing the rule
* @return The EOF validation contract validation rule.
*/
public static ContractValidationRule from(final EVM evm) {
return new EOFValidationCodeRule(evm.getMaxEOFVersion());
}
}

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.evm.contractvalidation;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -41,7 +43,7 @@ public class MaxCodeSizeRule implements ContractValidationRule {
@Override
public Optional<ExceptionalHaltReason> validate(
final Bytes contractCode, final MessageFrame frame) {
final Bytes contractCode, final MessageFrame frame, final EVM evm) {
final int contractCodeSize = contractCode.size();
if (contractCodeSize <= maxCodeSize) {
return Optional.empty();
@ -55,12 +57,34 @@ public class MaxCodeSizeRule implements ContractValidationRule {
}
/**
* Instantiate ContractValidationRule.
* Fluent MaxCodeSizeRule constructor of an explicit size.
*
* @param maxCodeSize the max code size
* @return the contract validation rule
* @deprecated use {@link #from(EVM)}
*/
@Deprecated(forRemoval = true, since = "24.6.1")
public static ContractValidationRule of(final int maxCodeSize) {
return new MaxCodeSizeRule(maxCodeSize);
}
/**
* Fluent MaxCodeSizeRule from the EVM it is working with.
*
* @param evm The evm to get the size rules from.
* @return the contract validation rule
*/
public static ContractValidationRule from(final EVM evm) {
return from(evm.getEvmVersion());
}
/**
* Fluent MaxCodeSizeRule from the EVM it is working with.
*
* @param evmspec The evm spec version to get the size rules from.
* @return the contract validation rule
*/
public static ContractValidationRule from(final EvmSpecVersion evmspec) {
return new MaxCodeSizeRule(evmspec.getMaxCodeSize());
}
}

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.evm.contractvalidation;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -31,12 +32,14 @@ public class PrefixCodeRule implements ContractValidationRule {
private static final byte FORMAT_RESERVED = (byte) 0xEF;
/** Default constructor. */
public PrefixCodeRule() {}
public PrefixCodeRule() {
// This constructor exists because of JavaDoc linting rules.
}
@Override
// As per https://eips.ethereum.org/EIPS/eip-3541
public Optional<ExceptionalHaltReason> validate(
final Bytes contractCode, final MessageFrame frame) {
final Bytes contractCode, final MessageFrame frame, final EVM evm) {
if (!contractCode.isEmpty() && contractCode.get(0) == FORMAT_RESERVED) {
LOG.trace("Contract creation error: code cannot start with {}", FORMAT_RESERVED);
return Optional.of(ExceptionalHaltReason.INVALID_CODE);

@ -77,7 +77,7 @@ public class EVMExecutor {
private OperationTracer tracer = OperationTracer.NO_TRACING;
private boolean requireDeposit = true;
private List<ContractValidationRule> contractValidationRules =
List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of());
List.of(MaxCodeSizeRule.from(EvmSpecVersion.SPURIOUS_DRAGON), PrefixCodeRule.of());
private long initialNonce = 1;
private Collection<Address> forceCommitAddresses = List.of(Address.fromHexString("0x03"));
private Set<Address> accessListWarmAddresses = new BytesTrieSet<>(Address.SIZE);
@ -240,7 +240,8 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.spuriousDragon(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.frontier(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules =
List.of(MaxCodeSizeRule.from(EvmSpecVersion.SPURIOUS_DRAGON));
return executor;
}
@ -254,7 +255,7 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.byzantium(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules = List.of(MaxCodeSizeRule.from(EvmSpecVersion.BYZANTIUM));
return executor;
}
@ -268,7 +269,7 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.constantinople(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules = List.of(MaxCodeSizeRule.from(EvmSpecVersion.CONSTANTINOPLE));
return executor;
}
@ -282,7 +283,7 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.petersburg(evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.byzantium(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules = List.of(MaxCodeSizeRule.from(EvmSpecVersion.PETERSBURG));
return executor;
}
@ -317,7 +318,7 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.istanbul(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules = List.of(MaxCodeSizeRule.from(EvmSpecVersion.ISTANBUL));
return executor;
}
@ -352,7 +353,7 @@ public class EVMExecutor {
final EVMExecutor executor = new EVMExecutor(MainnetEVMs.berlin(chainId, evmConfiguration));
executor.precompileContractRegistry =
MainnetPrecompiledContracts.istanbul(executor.evm.getGasCalculator());
executor.contractValidationRules = List.of(MaxCodeSizeRule.of(0x6000));
executor.contractValidationRules = List.of(MaxCodeSizeRule.from(EvmSpecVersion.BERLIN));
return executor;
}
@ -658,12 +659,7 @@ public class EVMExecutor {
contractCreationProcessor,
() ->
new ContractCreationProcessor(
evm.getGasCalculator(),
evm,
requireDeposit,
contractValidationRules,
initialNonce,
forceCommitAddresses));
evm, requireDeposit, contractValidationRules, initialNonce, forceCommitAddresses));
}
/**

@ -63,6 +63,12 @@ public interface ExceptionalHaltReason {
/** The constant NONEXISTENT_CONTAINER */
ExceptionalHaltReason NONEXISTENT_CONTAINER = DefaultExceptionalHaltReason.NONEXISTENT_CONTAINER;
/** The constant INVALID_CONTAINER */
ExceptionalHaltReason INVALID_CONTAINER = DefaultExceptionalHaltReason.INVALID_CONTAINER;
/** The constant DATA_TOO_SMALL */
ExceptionalHaltReason DATA_TOO_SMALL = DefaultExceptionalHaltReason.DATA_TOO_SMALL;
/** The constant ADDRESS_OUT_OF_RANGE */
ExceptionalHaltReason ADDRESS_OUT_OF_RANGE = DefaultExceptionalHaltReason.ADDRESS_OUT_OF_RANGE;
@ -112,7 +118,11 @@ public interface ExceptionalHaltReason {
EOF_CREATE_VERSION_INCOMPATIBLE(
"EOF Code is attempting to create EOF code of an earlier version"),
/** Container referenced by EOFCREATE operation does not exist */
NONEXISTENT_CONTAINER("Referenced subcontainer index does not exist (too large?)"),
NONEXISTENT_CONTAINER("Referenced subcontainer index does not exist"),
/** Container referenced by EOFCREATE operation is invalid */
INVALID_CONTAINER("Referenced subcontainer index is invalid"),
/** Container referenced by EOFCREATE operation does not exist */
DATA_TOO_SMALL("Insufficient AuxData provided to a truncated container"),
/** A given address cannot be used by EOF */
ADDRESS_OUT_OF_RANGE("Address has more than 20 bytes and is out of range");

@ -14,13 +14,27 @@
*/
package org.hyperledger.besu.evm.internal;
import org.hyperledger.besu.evm.frame.MessageFrame;
import java.util.Optional;
import java.util.OptionalInt;
/**
* The type Evm configuration.
*
* @param jumpDestCacheWeightKB the jump destination cache weight in kb
* @param worldUpdaterMode the world updater mode
* @param evmStackSize the maximum evm stack size
* @param maxCodeSizeOverride An optional override of the maximum code size set by the EVM fork
* @param maxInitcodeSizeOverride An optional override of the maximum initcode size set by the EVM
* fork
*/
public record EvmConfiguration(long jumpDestCacheWeightKB, WorldUpdaterMode worldUpdaterMode) {
public record EvmConfiguration(
long jumpDestCacheWeightKB,
WorldUpdaterMode worldUpdaterMode,
Integer evmStackSize,
Optional<Integer> maxCodeSizeOverride,
Optional<Integer> maxInitcodeSizeOverride) {
/** How should the world state update be handled within transactions? */
public enum WorldUpdaterMode {
@ -36,6 +50,22 @@ public record EvmConfiguration(long jumpDestCacheWeightKB, WorldUpdaterMode worl
public static final EvmConfiguration DEFAULT =
new EvmConfiguration(32_000L, WorldUpdaterMode.STACKED);
/**
* Create an EVM Configuration without any overrides
*
* @param jumpDestCacheWeightKilobytes the jump dest cache weight (in kibibytes)
* @param worldstateUpdateMode the workd update mode
*/
public EvmConfiguration(
final Long jumpDestCacheWeightKilobytes, final WorldUpdaterMode worldstateUpdateMode) {
this(
jumpDestCacheWeightKilobytes,
worldstateUpdateMode,
MessageFrame.DEFAULT_MAX_STACK_SIZE,
Optional.empty(),
Optional.empty());
}
/**
* Gets jump dest cache weight bytes.
*
@ -44,4 +74,27 @@ public record EvmConfiguration(long jumpDestCacheWeightKB, WorldUpdaterMode worl
public long getJumpDestCacheWeightBytes() {
return jumpDestCacheWeightKB * 1024L;
}
/**
* Update the configuration with new overrides, or clearing the overrides with {@link
* Optional#empty}
*
* @param newMaxCodeSize a new max code size override
* @param newMaxInitcodeSize a new max initcode size override
* @param newEvmStackSize a new EVM stack size override
* @return the updated EVM configuration
*/
public EvmConfiguration overrides(
final OptionalInt newMaxCodeSize,
final OptionalInt newMaxInitcodeSize,
final OptionalInt newEvmStackSize) {
return new EvmConfiguration(
jumpDestCacheWeightKB,
worldUpdaterMode,
newEvmStackSize.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE),
newMaxCodeSize.isPresent() ? Optional.of(newMaxCodeSize.getAsInt()) : Optional.empty(),
newMaxInitcodeSize.isPresent()
? Optional.of(newMaxInitcodeSize.getAsInt())
: Optional.empty());
}
}

@ -22,7 +22,6 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -218,7 +217,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation {
Code outputCode =
(childFrame.getCreatedCode() != null)
? childFrame.getCreatedCode()
: CodeFactory.createCode(childFrame.getOutputData(), evm.getMaxEOFVersion());
: evm.getCodeForCreation(childFrame.getOutputData());
frame.popStackItems(getStackItemsConsumed());
if (outputCode.isValid()) {

@ -74,7 +74,7 @@ public class EOFCreateOperation extends AbstractCreateOperation {
int startIndex = frame.getPC() + 1;
final int initContainerIndex = code.readU8(startIndex);
return code.getSubContainer(initContainerIndex, null).orElse(null);
return code.getSubContainer(initContainerIndex, null, evm).orElse(null);
}
@Override

@ -64,9 +64,15 @@ public class ReturnContractOperation extends AbstractOperation {
}
Bytes auxData = frame.readMemory(from, length);
Optional<Code> newCode = code.getSubContainer(index, auxData);
if (code.getDataSize() + auxData.size() > evm.getEvmVersion().getMaxCodeSize()) {
return new OperationResult(cost, ExceptionalHaltReason.CODE_TOO_LARGE);
}
if (code.getDataSize() + auxData.size() < code.getDeclaredDataSize()) {
return new OperationResult(cost, ExceptionalHaltReason.DATA_TOO_SMALL);
}
Optional<Code> newCode = code.getSubContainer(index, auxData, evm);
if (newCode.isEmpty()) {
return new OperationResult(cost, ExceptionalHaltReason.NONEXISTENT_CONTAINER);
return new OperationResult(cost, ExceptionalHaltReason.INVALID_CONTAINER);
}
frame.setCreatedCode(newCode.get());

@ -71,7 +71,7 @@ public abstract class AbstractMessageProcessor {
// List of addresses to force delete when they are touched but empty
// when the state changes in the message are were not meant to be committed.
private final Collection<? super Address> forceDeleteAccountsWhenEmpty;
private final EVM evm;
final EVM evm;
/**
* Instantiates a new Abstract message processor.
@ -188,15 +188,12 @@ public abstract class AbstractMessageProcessor {
if (operationTracer != null) {
if (frame.getState() == MessageFrame.State.NOT_STARTED) {
operationTracer.traceContextEnter(frame);
start(frame, operationTracer);
} else {
operationTracer.traceContextReEnter(frame);
}
}
if (frame.getState() == MessageFrame.State.NOT_STARTED) {
start(frame, operationTracer);
}
if (frame.getState() == MessageFrame.State.CODE_EXECUTING) {
codeExecute(frame, operationTracer);

@ -22,7 +22,6 @@ import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.contractvalidation.ContractValidationRule;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import java.util.Collection;
@ -41,8 +40,6 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
private final boolean requireCodeDepositToSucceed;
private final GasCalculator gasCalculator;
private final long initialContractNonce;
private final List<ContractValidationRule> contractValidationRules;
@ -50,7 +47,6 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
/**
* Instantiates a new Contract creation processor.
*
* @param gasCalculator the gas calculator
* @param evm the evm
* @param requireCodeDepositToSucceed the require code deposit to succeed
* @param contractValidationRules the contract validation rules
@ -58,14 +54,12 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
* @param forceCommitAddresses the force commit addresses
*/
public ContractCreationProcessor(
final GasCalculator gasCalculator,
final EVM evm,
final boolean requireCodeDepositToSucceed,
final List<ContractValidationRule> contractValidationRules,
final long initialContractNonce,
final Collection<Address> forceCommitAddresses) {
super(evm, forceCommitAddresses);
this.gasCalculator = gasCalculator;
this.requireCodeDepositToSucceed = requireCodeDepositToSucceed;
this.contractValidationRules = contractValidationRules;
this.initialContractNonce = initialContractNonce;
@ -74,25 +68,17 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
/**
* Instantiates a new Contract creation processor.
*
* @param gasCalculator the gas calculator
* @param evm the evm
* @param requireCodeDepositToSucceed the require code deposit to succeed
* @param contractValidationRules the contract validation rules
* @param initialContractNonce the initial contract nonce
*/
public ContractCreationProcessor(
final GasCalculator gasCalculator,
final EVM evm,
final boolean requireCodeDepositToSucceed,
final List<ContractValidationRule> contractValidationRules,
final long initialContractNonce) {
this(
gasCalculator,
evm,
requireCodeDepositToSucceed,
contractValidationRules,
initialContractNonce,
Set.of());
this(evm, requireCodeDepositToSucceed, contractValidationRules, initialContractNonce, Set.of());
}
private static boolean accountExists(final Account account) {
@ -140,7 +126,7 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
final Bytes contractCode =
frame.getCreatedCode() == null ? frame.getOutputData() : frame.getCreatedCode().getBytes();
final long depositFee = gasCalculator.codeDepositGasCost(contractCode.size());
final long depositFee = evm.getGasCalculator().codeDepositGasCost(contractCode.size());
if (frame.getRemainingGas() < depositFee) {
LOG.trace(
@ -161,7 +147,7 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
} else {
final var invalidReason =
contractValidationRules.stream()
.map(rule -> rule.validate(contractCode, frame))
.map(rule -> rule.validate(contractCode, frame, evm))
.filter(Optional::isPresent)
.findFirst();
if (invalidReason.isEmpty()) {

@ -18,6 +18,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.evm.EOFTestConstants.bytesFromPrettyPrint;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.junit.jupiter.api.Test;
@ -25,12 +28,12 @@ class CodeFactoryTest {
@Test
void invalidCodeIncompleteMagic() {
invalidCode("0xEF", true);
invalidCodeForCreation("0xEF");
}
@Test
void invalidCodeInvalidMagic() {
invalidCode("0xEFFF0101000302000400600000AABBCCDD", true);
invalidCodeForCreation("0xEFFF0101000302000400600000AABBCCDD");
}
@Test
@ -180,7 +183,9 @@ class CodeFactoryTest {
@Test
void invalidDataTruncated() {
invalidCode("EF0001 010004 0200010001 040003 00 00800000 FE BEEF", "Incomplete data section");
invalidCode(
"EF0001 010004 0200010001 040003 00 00800000 FE BEEF",
"Truncated data section when a complete section was required");
}
@Test
@ -588,35 +593,28 @@ class CodeFactoryTest {
"RETURNCONTRACT is only a valid opcode in containers used for initcode");
}
// // valid subcontainer references
// // invalid subcontainer references
//
// {
// "EF0001 010004 0200010001 040003 00 00800000 FE BEEF",
// "Incomplete data section",
// "Incomplete data section",
// 1
// },
//
private static void validCode(final String str) {
Code code = CodeFactory.createCode(bytesFromPrettyPrint(str), 1);
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(bytesFromPrettyPrint(str));
assertThat(code.isValid()).isTrue();
}
private static void invalidCode(final String str, final String error) {
Code code = CodeFactory.createCode(bytesFromPrettyPrint(str), 1);
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(bytesFromPrettyPrint(str));
assertThat(code.isValid()).isFalse();
assertThat(((CodeInvalid) code).getInvalidReason()).contains(error);
}
private static void invalidCode(final String str) {
Code code = CodeFactory.createCode(bytesFromPrettyPrint(str), 1);
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(bytesFromPrettyPrint(str));
assertThat(code.isValid()).isFalse();
}
private static void invalidCode(final String str, final boolean legacy) {
Code code = CodeFactory.createCode(bytesFromPrettyPrint(str), 1, legacy, false);
private static void invalidCodeForCreation(final String str) {
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeForCreation(bytesFromPrettyPrint(str));
assertThat(code.isValid()).isFalse();
}
}

@ -24,15 +24,12 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.JumpOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import javax.annotation.Nonnull;
@ -45,24 +42,19 @@ import org.mockito.Mockito;
class CodeV0Test {
private static final IstanbulGasCalculator gasCalculator = new IstanbulGasCalculator();
private static final int CURRENT_PC = 1;
private EVM evm;
@BeforeEach
void startUp() {
final OperationRegistry registry = new OperationRegistry();
registry.put(new JumpOperation(gasCalculator));
registry.put(new JumpDestOperation(gasCalculator));
evm = new EVM(registry, gasCalculator, EvmConfiguration.DEFAULT, EvmSpecVersion.PARIS);
evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
}
@Test
void shouldReuseJumpDestMap() {
final JumpOperation operation = new JumpOperation(gasCalculator);
final JumpOperation operation = new JumpOperation(evm.getGasCalculator());
final Bytes jumpBytes = Bytes.fromHexString("0x6003565b00");
final CodeV0 getsCached = (CodeV0) spy(CodeFactory.createCode(jumpBytes, 0));
final CodeV0 getsCached = (CodeV0) spy(evm.getCodeUncached(jumpBytes));
MessageFrame frame = createJumpFrame(getsCached);
OperationResult result = operation.execute(frame, evm);

@ -15,8 +15,6 @@
package org.hyperledger.besu.evm.code;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.evm.code.CodeV1Validation.validateCode;
import static org.hyperledger.besu.evm.code.CodeV1Validation.validateStack;
import java.util.Arrays;
import java.util.List;
@ -72,7 +70,8 @@ class CodeV1Test {
final Bytes codeBytes,
final CodeSection thisCodeSection,
final EOFLayout eofLayout) {
final String validationError = validateCode(codeBytes, thisCodeSection, eofLayout);
CodeV1Validation validator = new CodeV1Validation(0xc000);
final String validationError = validator.validateCode(codeBytes, thisCodeSection, eofLayout);
if (error == null) {
assertThat(validationError).isNull();
} else {
@ -85,8 +84,8 @@ class CodeV1Test {
String codeHex =
"0xEF0001 01000C 020003 000b 0002 0008 040000 00 00800000 02010001 01000002 60016002e30001e30002f3 01e4 60005360106000e4";
final EOFLayout layout = EOFLayout.parseEOF(Bytes.fromHexString(codeHex.replace(" ", "")));
String validationError = validateCode(layout);
CodeV1Validation validator = new CodeV1Validation(0xc000);
String validationError = validator.validateCode(layout);
assertThat(validationError).isNull();
}
@ -96,8 +95,8 @@ class CodeV1Test {
String codeHex =
"0xEF0001 01000C 020003 000b 0002 0008 040000 00 00000000 02010001 01000002 60016002e30001e30002f3 01e4 60005360106000e4";
final EOFLayout layout = EOFLayout.parseEOF(Bytes.fromHexString(codeHex.replace(" ", "")));
String validationError = validateCode(layout);
CodeV1Validation validator = new CodeV1Validation(0xc000);
String validationError = validator.validateCode(layout);
assertThat(validationError)
.isEqualTo(
@ -475,8 +474,9 @@ class CodeV1Test {
+ codeData;
EOFLayout eofLayout = EOFLayout.parseEOF(Bytes.fromHexString(sb));
CodeV1Validation validator = new CodeV1Validation(0xc000);
assertThat(validateStack(sectionToTest, eofLayout, new WorkList(sectionCount)))
assertThat(validator.validateStack(sectionToTest, eofLayout, new WorkList(sectionCount)))
.isEqualTo(expectedError);
}

@ -22,7 +22,6 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -135,19 +134,6 @@ class EVMExecutorTest {
assertThat(futureEipsVM.getChainId()).contains(defaultChainId);
}
@Test
void executeCode() {
var result =
EVMExecutor.evm(EvmSpecVersion.SHANGHAI)
.worldUpdater(createSimpleWorld().updater())
.execute(
CodeFactory.createCode(Bytes.fromHexString("0x6001600255"), 1),
Bytes.EMPTY,
Wei.ZERO,
Address.ZERO);
assertThat(result).isNotNull();
}
@Test
void executeBytes() {
var result =
@ -180,7 +166,7 @@ class EVMExecutorTest {
.blobGasPrice(Wei.ONE)
.callData(Bytes.fromHexString("0x12345678"))
.ethValue(Wei.fromEth(1))
.code(CodeFactory.createCode(Bytes.fromHexString("0x6001600255"), 0))
.code(Bytes.fromHexString("0x6001600255"))
.blockValues(new SimpleBlockValues())
.difficulty(Bytes.ofUnsignedLong(1L))
.mixHash(Bytes32.ZERO)
@ -199,7 +185,7 @@ class EVMExecutorTest {
.accessListWarmStorage(
Address.ZERO, Bytes32.ZERO, Bytes32.leftPad(Bytes.ofUnsignedLong(2L)))
.messageCallProcessor(new MessageCallProcessor(null, null))
.contractCallProcessor(new ContractCreationProcessor(null, null, true, null, 1L))
.contractCallProcessor(new ContractCreationProcessor(null, true, null, 1L))
.execute();
assertThat(result).isNotNull();
}

@ -17,7 +17,8 @@ package org.hyperledger.besu.evm.internal;
import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.apache.tuweni.bytes.Bytes;
@ -29,10 +30,11 @@ class CodeCacheTest {
@Test
void testScale() {
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final Bytes contractBytes =
Bytes.fromHexString("0xDEAD" + op + "BEEF" + op + "B0B0" + op + "C0DE" + op + "FACE");
final CodeScale scale = new CodeScale();
final Code contractCode = CodeFactory.createCode(contractBytes, 0);
final Code contractCode = evm.getCodeUncached(contractBytes);
final int weight = scale.weigh(contractCode.getCodeHash(), contractCode);
assertThat(weight)
.isEqualTo(contractCode.getCodeHash().size() + (contractBytes.size() * 9 + 7) / 8);

@ -30,7 +30,6 @@ import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
@ -166,7 +165,7 @@ class AbstractCreateOperationTest {
.sender(Address.fromHexString(SENDER))
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(CodeFactory.createCode(SIMPLE_CREATE, 0))
.code(evm.getCodeUncached(SIMPLE_CREATE))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
@ -197,7 +196,7 @@ class AbstractCreateOperationTest {
operation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrameStack.peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
}

@ -29,7 +29,6 @@ import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
@ -58,7 +57,7 @@ public class Create2OperationTest {
private MessageFrame messageFrame;
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final MutableAccount account = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
private final MutableAccount newAccount = mock(MutableAccount.class);
private final Create2Operation operation =
@ -154,7 +153,7 @@ public class Create2OperationTest {
.sender(Address.fromHexString(sender))
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(CodeFactory.createCode(codeBytes, 0))
.code(evm.getCodeUncached(codeBytes))
.completer(__ -> {})
.address(Address.fromHexString(sender))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
@ -175,8 +174,6 @@ public class Create2OperationTest {
when(account.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any()))
.thenAnswer(invocation -> CodeFactory.createCode(invocation.getArgument(1), 0));
}
@ParameterizedTest
@ -190,7 +187,7 @@ public class Create2OperationTest {
setUp(sender, salt, code);
final Address targetContractAddress =
operation.targetContractAddress(
messageFrame, CodeFactory.createCode(Bytes.fromHexString(code), 0));
messageFrame, evm.getCodeUncached(Bytes.fromHexString(code)));
assertThat(targetContractAddress).isEqualTo(Address.fromHexString(expectedAddress));
}
@ -224,11 +221,11 @@ public class Create2OperationTest {
when(newAccount.isStorageEmpty()).thenReturn(true);
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = maxInitCodeOperation.execute(messageFrame, evm);
final EVM myEVM = MainnetEVMs.shanghai(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = maxInitCodeOperation.execute(messageFrame, myEVM);
final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(myEVM, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
final Log log = createFrame.getLogs().get(0);
@ -268,7 +265,7 @@ public class Create2OperationTest {
.sender(Address.fromHexString(SENDER))
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(CodeFactory.createCode(SIMPLE_CREATE, 0))
.code(evm.getCodeUncached(SIMPLE_CREATE))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
@ -298,7 +295,7 @@ public class Create2OperationTest {
final UInt256 memoryOffset = UInt256.fromHexString("0xFF");
final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size());
Code eofCode = CodeFactory.createCode(SIMPLE_EOF, 1);
Code eofCode = evm.getCodeUncached(SIMPLE_EOF);
assertThat(eofCode.isValid()).isTrue();
final MessageFrame messageFrame =
@ -315,7 +312,6 @@ public class Create2OperationTest {
when(account.getBalance()).thenReturn(Wei.ZERO);
when(worldUpdater.getAccount(any())).thenReturn(account);
final EVM evm = MainnetEVMs.cancun(DEV_NET_CHAIN_ID, EvmConfiguration.DEFAULT);
var result = operation.execute(messageFrame, evm);
assertThat(result.getHaltReason()).isEqualTo(INVALID_OPERATION);
assertThat(messageFrame.getStackItem(0).trimLeadingZeros()).isEqualTo(Bytes.EMPTY);

@ -28,7 +28,6 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
@ -59,6 +58,7 @@ class CreateOperationTest {
private final CreateOperation maxInitCodeOperation =
new CreateOperation(
new ConstantinopleGasCalculator(), MainnetEVMs.SHANGHAI_INIT_CODE_SIZE_LIMIT);
private final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
private static final String TOPIC =
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; // 32 FFs
@ -102,7 +102,7 @@ class CreateOperationTest {
operation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
final Log log = createFrame.getLogs().get(0);
@ -194,7 +194,7 @@ class CreateOperationTest {
var result = maxInitCodeOperation.execute(messageFrame, evm);
final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
final Log log = createFrame.getLogs().get(0);
@ -229,7 +229,7 @@ class CreateOperationTest {
final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size());
final MessageFrame messageFrame =
new TestMessageFrameBuilder()
.code(CodeFactory.createCode(SIMPLE_EOF, 1))
.code(evm.getCodeUncached(SIMPLE_EOF))
.pushStackItem(memoryLength)
.pushStackItem(memoryOffset)
.pushStackItem(Bytes.EMPTY)
@ -261,7 +261,7 @@ class CreateOperationTest {
.sender(Address.fromHexString(SENDER))
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(CodeFactory.createCode(SIMPLE_CREATE, 0))
.code(evm.getCodeUncached(SIMPLE_CREATE))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))

@ -29,7 +29,6 @@ import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.code.CodeInvalid;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
@ -63,7 +62,8 @@ class EofCreateOperationTest {
@Test
void innerContractIsCorrect() {
Code code = CodeFactory.createCode(INNER_CONTRACT, 1);
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = evm.getCodeUncached(INNER_CONTRACT);
assertThat(code.isValid()).isTrue();
final MessageFrame messageFrame = testMemoryFrame(code, CALL_DATA);
@ -78,11 +78,10 @@ class EofCreateOperationTest {
when(newAccount.isStorageEmpty()).thenReturn(true);
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek();
assertThat(createFrame).isNotNull();
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(evm, false, List.of(), 0, List.of());
ccp.process(createFrame, OperationTracer.NO_TRACING);
final Log log = createFrame.getLogs().get(0);
@ -93,8 +92,9 @@ class EofCreateOperationTest {
@Test
void eofCreatePassesInCallData() {
Bytes outerContract = EOF_CREATE_CONTRACT;
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
Code code = CodeFactory.createCode(outerContract, 1);
Code code = evm.getCodeUncached(outerContract);
if (!code.isValid()) {
System.out.println(outerContract);
fail(((CodeInvalid) code).getInvalidReason());
@ -112,13 +112,12 @@ class EofCreateOperationTest {
when(newAccount.isStorageEmpty()).thenReturn(true);
when(worldUpdater.updater()).thenReturn(worldUpdater);
final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
var precompiles = MainnetPrecompiledContracts.prague(evm.getGasCalculator());
final MessageFrame createFrame = messageFrame.getMessageFrameStack().peek();
assertThat(createFrame).isNotNull();
final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompiles);
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0, List.of());
new ContractCreationProcessor(evm, false, List.of(), 0, List.of());
while (!createFrame.getMessageFrameStack().isEmpty()) {
var frame = createFrame.getMessageFrameStack().peek();
assert frame != null;

@ -23,11 +23,12 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.AbstractExtCallOperation;
import org.hyperledger.besu.evm.operation.ExtCallOperation;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
@ -45,11 +46,11 @@ public class ExtCallOperationTest {
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final MutableAccount account = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
public static final Code SIMPLE_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"));
public static final Code INVALID_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"));
private static final Address CONTRACT_ADDRESS = Address.fromHexString("0xc0de");
static Iterable<Arguments> data() {
@ -130,12 +131,13 @@ public class ExtCallOperationTest {
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
}
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getCodeHash());
when(account.getCode()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(validCode ? SIMPLE_EOF : INVALID_EOF);
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(chargedGas);
assertThat(result.getHaltReason()).isEqualTo(haltReason);
@ -218,12 +220,13 @@ public class ExtCallOperationTest {
.build();
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
when(account.getBalance()).thenReturn(valueWeiHave);
when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash());
when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(SIMPLE_EOF);
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(chargedGas);
assertThat(result.getHaltReason()).isEqualTo(haltReason);
@ -251,15 +254,16 @@ public class ExtCallOperationTest {
.build();
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash());
when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(SIMPLE_EOF);
while (messageFrame.getDepth() < 1024) {
messageFrame.getMessageFrameStack().add(messageFrame);
}
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(100);
assertThat(result.getHaltReason()).isNull();

@ -23,11 +23,12 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.AbstractExtCallOperation;
import org.hyperledger.besu.evm.operation.ExtDelegateCallOperation;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
@ -46,13 +47,13 @@ public class ExtDelegateCallOperationTest {
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final MutableAccount account = mock(MutableAccount.class);
// private final MutableAccount targetAccount = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
public static final Code SIMPLE_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"), 1);
public static final Code SIMPLE_LEGACY = CodeFactory.createCode(Bytes.fromHexString("0x00"), 1);
public static final Code EMPTY_CODE = CodeFactory.createCode(Bytes.fromHexString(""), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"));
public static final Code SIMPLE_LEGACY = EOF_EVM.getCodeUncached(Bytes.fromHexString("0x00"));
public static final Code EMPTY_CODE = EOF_EVM.getCodeUncached(Bytes.fromHexString(""));
public static final Code INVALID_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"));
private static final Address CONTRACT_ADDRESS = Address.fromHexString("0xc0de");
static Iterable<Arguments> data() {
@ -134,12 +135,13 @@ public class ExtDelegateCallOperationTest {
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
}
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getCodeHash());
when(account.getCode()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(validCode ? SIMPLE_EOF : INVALID_EOF);
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(chargedGas);
assertThat(result.getHaltReason()).isEqualTo(haltReason);
@ -195,20 +197,22 @@ public class ExtDelegateCallOperationTest {
when(worldUpdater.get(TestMessageFrameBuilder.DEFAUT_ADDRESS)).thenReturn(account);
when(worldUpdater.getAccount(TestMessageFrameBuilder.DEFAUT_ADDRESS)).thenReturn(account);
Code code =
switch (name) {
case "EOF" -> SIMPLE_EOF;
case "Legacy" -> SIMPLE_LEGACY;
default -> EMPTY_CODE;
};
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn(code.getCodeHash());
when(account.getCode()).thenReturn(code.getBytes());
when(worldUpdater.get(CONTRACT_ADDRESS)).thenReturn("Empty".equals(name) ? null : account);
when(worldUpdater.getAccount(CONTRACT_ADDRESS))
.thenReturn("Empty".equals(name) ? null : account);
when(evm.getCode(any(), any()))
.thenReturn(
switch (name) {
case "EOF" -> SIMPLE_EOF;
case "Legacy" -> SIMPLE_LEGACY;
default -> EMPTY_CODE;
});
when(worldUpdater.updater()).thenReturn(worldUpdater);
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(chargedGas);
assertThat(result.getHaltReason()).isEqualTo(haltReason);
@ -235,15 +239,16 @@ public class ExtDelegateCallOperationTest {
.build();
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash());
when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(SIMPLE_EOF);
while (messageFrame.getDepth() < 1024) {
messageFrame.getMessageFrameStack().add(messageFrame);
}
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(100);
assertThat(result.getHaltReason()).isNull();

@ -23,11 +23,12 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.AbstractExtCallOperation;
import org.hyperledger.besu.evm.operation.ExtStaticCallOperation;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
@ -45,11 +46,11 @@ public class ExtStaticCallOperationTest {
private final WorldUpdater worldUpdater = mock(WorldUpdater.class);
private final MutableAccount account = mock(MutableAccount.class);
private final EVM evm = mock(EVM.class);
private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
public static final Code SIMPLE_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000"));
public static final Code INVALID_EOF =
CodeFactory.createCode(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"), 1);
EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000023"));
private static final Address CONTRACT_ADDRESS = Address.fromHexString("0xc0de");
static Iterable<Arguments> data() {
@ -130,12 +131,13 @@ public class ExtStaticCallOperationTest {
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
}
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getCodeHash());
when(account.getCode()).thenReturn((validCode ? SIMPLE_EOF : INVALID_EOF).getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(validCode ? SIMPLE_EOF : INVALID_EOF);
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(chargedGas);
assertThat(result.getHaltReason()).isEqualTo(haltReason);
@ -162,15 +164,16 @@ public class ExtStaticCallOperationTest {
.build();
messageFrame.warmUpAddress(CONTRACT_ADDRESS);
when(account.getBalance()).thenReturn(Wei.ZERO);
when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash());
when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes());
when(worldUpdater.get(any())).thenReturn(account);
when(worldUpdater.getAccount(any())).thenReturn(account);
when(worldUpdater.updater()).thenReturn(worldUpdater);
when(evm.getCode(any(), any())).thenReturn(SIMPLE_EOF);
while (messageFrame.getDepth() < 1024) {
messageFrame.getMessageFrameStack().add(messageFrame);
}
var result = operation.execute(messageFrame, evm);
var result = operation.execute(messageFrame, EOF_EVM);
assertThat(result.getGasCost()).isEqualTo(100);
assertThat(result.getHaltReason()).isNull();

@ -18,17 +18,14 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.operation.JumpDestOperation;
import org.hyperledger.besu.evm.operation.JumpOperation;
import org.hyperledger.besu.evm.operation.Operation.OperationResult;
import org.hyperledger.besu.evm.operation.OperationRegistry;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
@ -46,7 +43,8 @@ class JumpOperationTest {
private static final int CURRENT_PC = 1;
private Address address;
private final Address address =
Address.fromHexString("0xc0dec0dec0dec0dec0dec0dec0dec0dec0dec0de");
private EVM evm;
private TestMessageFrameBuilder createMessageFrameBuilder(final long initialGas) {
@ -59,12 +57,7 @@ class JumpOperationTest {
@BeforeEach
void init() {
address = Address.fromHexString("0x18675309");
final OperationRegistry registry = new OperationRegistry();
registry.put(new JumpOperation(gasCalculator));
registry.put(new JumpDestOperation(gasCalculator));
evm = new EVM(registry, gasCalculator, EvmConfiguration.DEFAULT, EvmSpecVersion.PARIS);
evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
}
@Test
@ -74,7 +67,7 @@ class JumpOperationTest {
final MessageFrame frame =
createMessageFrameBuilder(10_000L)
.pushStackItem(UInt256.fromHexString("0x03"))
.code(CodeFactory.createCode(jumpBytes, 0))
.code(evm.getCodeUncached(jumpBytes))
.build();
frame.setPC(CURRENT_PC);
@ -89,7 +82,7 @@ class JumpOperationTest {
final MessageFrame frame =
createMessageFrameBuilder(10_000L)
.pushStackItem(UInt256.fromHexString("0x03"))
.code(CodeFactory.createCode(jumpBytes, 0))
.code(evm.getCodeUncached(jumpBytes))
.build();
frame.setPC(CURRENT_PC);
@ -104,7 +97,7 @@ class JumpOperationTest {
final MessageFrame frameDestinationGreaterThanCodeSize =
createMessageFrameBuilder(100L)
.pushStackItem(UInt256.fromHexString("0xFFFFFFFF"))
.code(CodeFactory.createCode(jumpBytes, 0))
.code(evm.getCodeUncached(jumpBytes))
.build();
frameDestinationGreaterThanCodeSize.setPC(CURRENT_PC);
@ -114,7 +107,7 @@ class JumpOperationTest {
final MessageFrame frameDestinationEqualsToCodeSize =
createMessageFrameBuilder(100L)
.pushStackItem(UInt256.fromHexString("0x04"))
.code(CodeFactory.createCode(badJump, 0))
.code(evm.getCodeUncached(badJump))
.build();
frameDestinationEqualsToCodeSize.setPC(CURRENT_PC);
@ -132,7 +125,7 @@ class JumpOperationTest {
final MessageFrame longContract =
createMessageFrameBuilder(100L)
.pushStackItem(UInt256.fromHexString("0x12c"))
.code(CodeFactory.createCode(longCode, 0))
.code(evm.getCodeUncached(longCode))
.build();
longContract.setPC(255);

@ -24,11 +24,12 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.operation.SelfDestructOperation;
@ -55,7 +56,7 @@ public class SelfDestructOperationTest {
@Mock private WorldUpdater worldUpdater;
@Mock private MutableAccount accountOriginator;
@Mock private MutableAccount accountBeneficiary;
@Mock private EVM evm;
private final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
private final SelfDestructOperation frontierOperation =
new SelfDestructOperation(new ConstantinopleGasCalculator());
@ -79,7 +80,7 @@ public class SelfDestructOperationTest {
.sender(beneficiaryAddress)
.value(Wei.ZERO)
.apparentValue(Wei.ZERO)
.code(CodeFactory.createCode(SELFDESTRUCT_CODE, 0))
.code(evm.getCodeUncached(SELFDESTRUCT_CODE))
.completer(__ -> {})
.address(originatorAddress)
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))

@ -19,27 +19,25 @@ import static org.hyperledger.besu.evm.EOFTestConstants.EOF_CREATE_CONTRACT;
import static org.hyperledger.besu.evm.EOFTestConstants.INNER_CONTRACT;
import static org.hyperledger.besu.evm.frame.MessageFrame.State.COMPLETED_SUCCESS;
import static org.hyperledger.besu.evm.frame.MessageFrame.State.EXCEPTIONAL_HALT;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.code.CodeFactory;
import org.hyperledger.besu.evm.EvmSpecVersion;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.contractvalidation.EOFValidationCodeRule;
import org.hyperledger.besu.evm.contractvalidation.MaxCodeSizeRule;
import org.hyperledger.besu.evm.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import java.util.Collections;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@Nested
@ -47,8 +45,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
class ContractCreationProcessorTest
extends AbstractMessageProcessorTest<ContractCreationProcessor> {
@Mock GasCalculator gasCalculator;
@Mock EVM evm;
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
private ContractCreationProcessor processor;
@ -56,18 +53,12 @@ class ContractCreationProcessorTest
void shouldThrowAnExceptionWhenCodeContractFormatInvalidPreEOF() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(PrefixCodeRule.of()),
1,
Collections.emptyList());
evm, true, Collections.singletonList(PrefixCodeRule.of()), 1, Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("EF01010101010101");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
assertThat(messageFrame.getExceptionalHaltReason())
@ -78,18 +69,12 @@ class ContractCreationProcessorTest
void shouldNotThrowAnExceptionWhenCodeContractIsValid() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(PrefixCodeRule.of()),
1,
Collections.emptyList());
evm, true, Collections.singletonList(PrefixCodeRule.of()), 1, Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("0101010101010101");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -98,13 +83,12 @@ class ContractCreationProcessorTest
void shouldNotThrowAnExceptionWhenPrefixCodeRuleNotAdded() {
processor =
new ContractCreationProcessor(
gasCalculator, evm, true, Collections.emptyList(), 1, Collections.emptyList());
evm, true, Collections.emptyList(), 1, Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("0F01010101010101");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -113,18 +97,16 @@ class ContractCreationProcessorTest
void shouldThrowAnExceptionWhenCodeContractFormatInvalidPostEOF() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(EOFValidationCodeRule.of(1)),
Collections.singletonList(EOFValidationCodeRule.from(evm)),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("EF00010101010101");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
assertThat(messageFrame.getExceptionalHaltReason())
@ -135,18 +117,16 @@ class ContractCreationProcessorTest
void eofValidationShouldAllowLegacyDeployFromLegacyInit() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(EOFValidationCodeRule.of(1)),
Collections.singletonList(EOFValidationCodeRule.from(evm)),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("0101010101010101");
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -155,19 +135,16 @@ class ContractCreationProcessorTest
void eofValidationShouldAllowEOFCode() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(EOFValidationCodeRule.of(1)),
Collections.singletonList(EOFValidationCodeRule.from(evm)),
1,
Collections.emptyList());
final Bytes contractCode = INNER_CONTRACT;
final MessageFrame messageFrame =
new TestMessageFrameBuilder().code(CodeFactory.createCode(EOF_CREATE_CONTRACT, 1)).build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
new TestMessageFrameBuilder().code(evm.getCodeUncached(EOF_CREATE_CONTRACT)).build();
messageFrame.setOutputData(INNER_CONTRACT);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -176,18 +153,11 @@ class ContractCreationProcessorTest
void prefixValidationShouldPreventEOFCode() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(PrefixCodeRule.of()),
1,
Collections.emptyList());
final Bytes contractCode = INNER_CONTRACT;
evm, true, Collections.singletonList(PrefixCodeRule.of()), 1, Collections.emptyList());
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setOutputData(INNER_CONTRACT);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
}
@ -196,41 +166,36 @@ class ContractCreationProcessorTest
void eofValidationShouldPreventLegacyDeployFromEOFInit() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(EOFValidationCodeRule.of(1)),
Collections.singletonList(EOFValidationCodeRule.from(evm)),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("6030602001");
final Bytes initCode = EOF_CREATE_CONTRACT;
final MessageFrame messageFrame =
new TestMessageFrameBuilder().code(CodeFactory.createCode(initCode, 1)).build();
new TestMessageFrameBuilder().code(evm.getCodeForCreation(initCode)).build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
}
@Test
@Disabled("This is what's changing")
void eofValidationPreventsEOFDeployFromLegacyInit() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(EOFValidationCodeRule.of(1)),
Collections.singletonList(EOFValidationCodeRule.from(evm)),
1,
Collections.emptyList());
final Bytes contractCode = EOF_CREATE_CONTRACT;
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10600L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
}
@ -239,18 +204,17 @@ class ContractCreationProcessorTest
void shouldThrowAnExceptionWhenCodeContractTooLarge() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(24 * 1024)),
Collections.singletonList(MaxCodeSizeRule.from(EvmSpecVersion.SPURIOUS_DRAGON)),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("00".repeat(24 * 1024 + 1));
final Bytes contractCode =
Bytes.fromHexString("00".repeat(EvmSpecVersion.SPURIOUS_DRAGON.getMaxCodeSize() + 1));
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(10_000_000L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
assertThat(messageFrame.getExceptionalHaltReason())
@ -261,18 +225,17 @@ class ContractCreationProcessorTest
void shouldNotThrowAnExceptionWhenCodeContractTooLarge() {
processor =
new ContractCreationProcessor(
gasCalculator,
evm,
true,
Collections.singletonList(MaxCodeSizeRule.of(24 * 1024)),
Collections.singletonList(MaxCodeSizeRule.from(EvmSpecVersion.SPURIOUS_DRAGON)),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("00".repeat(24 * 1024));
final Bytes contractCode =
Bytes.fromHexString("00".repeat(EvmSpecVersion.SPURIOUS_DRAGON.getMaxCodeSize()));
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(5_000_000L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -281,13 +244,12 @@ class ContractCreationProcessorTest
void shouldNotThrowAnExceptionWhenCodeSizeRuleNotAdded() {
processor =
new ContractCreationProcessor(
gasCalculator, evm, true, Collections.emptyList(), 1, Collections.emptyList());
evm, true, Collections.emptyList(), 1, Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("00".repeat(24 * 1024 + 1));
final MessageFrame messageFrame = new TestMessageFrameBuilder().build();
messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(100L);
messageFrame.setGasRemaining(5_000_000L);
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(10L);
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
}
@ -295,6 +257,6 @@ class ContractCreationProcessorTest
@Override
protected ContractCreationProcessor getAbstractMessageProcessor() {
return new ContractCreationProcessor(
gasCalculator, evm, true, Collections.emptyList(), 1, Collections.emptyList());
evm, true, Collections.emptyList(), 1, Collections.emptyList());
}
}

@ -194,8 +194,7 @@ public class EvmToyCommand implements Runnable {
.build();
final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry);
final ContractCreationProcessor ccp =
new ContractCreationProcessor(evm.getGasCalculator(), evm, false, List.of(), 0);
final ContractCreationProcessor ccp = new ContractCreationProcessor(evm, false, List.of(), 0);
stopwatch.start();
Deque<MessageFrame> messageFrameStack = initialMessageFrame.getMessageFrameStack();
while (!messageFrameStack.isEmpty()) {

@ -16,14 +16,14 @@ package org.hyperledger.besu.evm.tracing;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.MainnetEVMs;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.processor.ContractCreationProcessor;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -40,8 +40,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class ExtendedOperationTracerTest {
@Mock GasCalculator gasCalculator;
@Mock EVM evm;
@Mock MessageFrame frame;
@Mock WorldUpdater worldUpdater;
@Mock MutableAccount mutableAccount;
@ -49,7 +47,6 @@ class ExtendedOperationTracerTest {
@BeforeEach
void setUp() {
when(frame.getOutputData()).thenReturn(Bytes.EMPTY);
when(gasCalculator.codeDepositGasCost(anyInt())).thenReturn(0L);
when(frame.getRemainingGas()).thenReturn(1L);
when(frame.getWorldUpdater()).thenReturn(worldUpdater);
@ -58,8 +55,9 @@ class ExtendedOperationTracerTest {
@Test
void shouldCallTraceAccountCreationResultIfIsExtendedTracing() {
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final ContractCreationProcessor contractCreationProcessor =
new ContractCreationProcessor(gasCalculator, evm, false, Collections.emptyList(), 0);
new ContractCreationProcessor(evm, false, Collections.emptyList(), 0);
final ExtendedOperationTracer tracer = new ExtendedOperationTracer();
contractCreationProcessor.codeSuccess(frame, tracer);
@ -71,8 +69,9 @@ class ExtendedOperationTracerTest {
@Test
void shouldNotCallTraceAccountCreationResultIfIsNotExtendedTracing() {
EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT);
final ContractCreationProcessor contractCreationProcessor =
new ContractCreationProcessor(gasCalculator, evm, false, Collections.emptyList(), 0);
new ContractCreationProcessor(evm, false, Collections.emptyList(), 0);
final DefaultOperationTracer tracer = new DefaultOperationTracer();
contractCreationProcessor.codeSuccess(frame, tracer);

Loading…
Cancel
Save