diff --git a/CHANGELOG.md b/CHANGELOG.md index 2118b9abdcd..07cdf586349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index 7575c7fe314..aec844894f7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -26,7 +26,6 @@ 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.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 @@ private 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 chainId, - final OptionalInt contractSizeLimit, - final OptionalInt configStackSizeLimit, - final EvmConfiguration evmConfiguration) { - return MainnetProtocolSpecs.homesteadDefinition( - contractSizeLimit, configStackSizeLimit, evmConfiguration) + final Optional 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 chainId, - final OptionalInt ignoredConfigContractSizeLimit, - final OptionalInt configStackSizeLimit, - final EvmConfiguration evmConfiguration) { - return tangerineWhistleDefinition( - chainId, OptionalInt.empty(), configStackSizeLimit, evmConfiguration) + final Optional chainId, final EvmConfiguration evmConfiguration) { + return tangerineWhistleDefinition(chainId, evmConfiguration) .gasCalculator(DieHardGasCalculator::new) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED) .name("DieHard"); @@ -95,11 +83,9 @@ public static ProtocolSpecBuilder dieHardDefinition( public static ProtocolSpecBuilder gothamDefinition( final Optional 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 static ProtocolSpecBuilder gothamDefinition( public static ProtocolSpecBuilder defuseDifficultyBombDefinition( final Optional 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 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 static ProtocolSpecBuilder atlantisDefinition( ? 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 static ProtocolSpecBuilder atlantisDefinition( messageCallProcessor, true, false, - stackSizeLimit, + evmConfiguration.evmStackSize(), feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("Atlantis"); @@ -191,18 +161,10 @@ public static ProtocolSpecBuilder atlantisDefinition( public static ProtocolSpecBuilder aghartaDefinition( final Optional 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 static ProtocolSpecBuilder aghartaDefinition( public static ProtocolSpecBuilder phoenixDefinition( final Optional 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 static ProtocolSpecBuilder phoenixDefinition( public static ProtocolSpecBuilder thanosDefinition( final Optional 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 @@ private static TransactionReceipt byzantiumTransactionReceiptFactoryWithReasonEn public static ProtocolSpecBuilder magnetoDefinition( final Optional 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 static ProtocolSpecBuilder magnetoDefinition( public static ProtocolSpecBuilder mystiqueDefinition( final Optional 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 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 static ProtocolSpecBuilder spiralDefinition( messageCallProcessor, true, true, - stackSizeLimit, + evmConfiguration.evmStackSize(), feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("Spiral"); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java index 095a85ef53f..a902d9faa74 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java @@ -20,14 +20,11 @@ import java.math.BigInteger; import java.util.Optional; -import java.util.OptionalInt; import java.util.OptionalLong; public class MainnetProtocolSpecFactory { private final Optional 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 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 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 ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesi */ 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 ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genes 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); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 16fee28bb50..763c751e4f9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -48,7 +48,6 @@ 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.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 @@ /** 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 static ProtocolSpecBuilder frontierDefinition( .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 static ProtocolSpecBuilder frontierDefinition( messageCallProcessor, false, false, - stackSizeLimit, + evmConfiguration.evmStackSize(), FeeMarket.legacy(), CoinbaseFeePriceCalculator.frontier())) .privateTransactionProcessorBuilder( @@ -157,7 +142,7 @@ public static ProtocolSpecBuilder frontierDefinition( contractCreationProcessor, messageCallProcessor, false, - stackSizeLimit, + evmConfiguration.evmStackSize(), new PrivateTransactionValidator(Optional.empty()))) .difficultyCalculator(MainnetDifficultyCalculators.FRONTIER) .blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.create()) @@ -188,35 +173,25 @@ public static BlockValidatorBuilder blockValidatorBuilder() { 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 static ProtocolSpecBuilder daoRecoveryInitDefinition( } 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 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 chainId, final EvmConfiguration evmConfiguration) { + return tangerineWhistleDefinition(evmConfiguration) .isReplayProtectionSupported(true) .gasCalculator(SpuriousDragonGasCalculator::new) .skipZeroBlockRewards(true) @@ -274,17 +238,17 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( 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 static ProtocolSpecBuilder spuriousDragonDefinition( messageCallProcessor, true, false, - stackSizeLimit, + evmConfiguration.evmStackSize(), feeMarket, CoinbaseFeePriceCalculator.frontier())) .name("SpuriousDragon"); @@ -306,13 +270,9 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( public static ProtocolSpecBuilder byzantiumDefinition( final Optional 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 static ProtocolSpecBuilder byzantiumDefinition( contractCreationProcessor, messageCallProcessor, false, - stackSizeLimit, + evmConfiguration.evmStackSize(), privateTransactionValidator)) .name("Byzantium"); } public static ProtocolSpecBuilder constantinopleDefinition( final Optional 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 static ProtocolSpecBuilder constantinopleDefinition( public static ProtocolSpecBuilder petersburgDefinition( final Optional 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 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 static ProtocolSpecBuilder istanbulDefinition( 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 static ProtocolSpecBuilder istanbulDefinition( static ProtocolSpecBuilder muirGlacierDefinition( final Optional 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 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 @@ static ProtocolSpecBuilder berlinDefinition( static ProtocolSpecBuilder londonDefinition( final Optional 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 @@ static ProtocolSpecBuilder londonDefinition( new LondonTargetingGasLimitCalculator( londonForkBlockNumber, (BaseFeeMarket) feeMarket)) .transactionValidatorFactoryBuilder( - (gasCalculator, gasLimitCalculator, feeMarket) -> + (evm, gasLimitCalculator, feeMarket) -> new TransactionValidatorFactory( - gasCalculator, + evm.getGasCalculator(), gasLimitCalculator, feeMarket, true, @@ -491,16 +423,15 @@ static ProtocolSpecBuilder londonDefinition( 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 @@ static ProtocolSpecBuilder londonDefinition( static ProtocolSpecBuilder arrowGlacierDefinition( final Optional 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 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 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 @@ static ProtocolSpecBuilder parisDefinition( static ProtocolSpecBuilder shanghaiDefinition( final Optional 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 @@ static ProtocolSpecBuilder shanghaiDefinition( 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 @@ static ProtocolSpecBuilder shanghaiDefinition( 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 @@ static ProtocolSpecBuilder shanghaiDefinition( static ProtocolSpecBuilder cancunDefinition( final Optional 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 @@ static ProtocolSpecBuilder cancunDefinition( 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 @@ static ProtocolSpecBuilder cancunDefinition( 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 @@ static ProtocolSpecBuilder cancunDefinition( static ProtocolSpecBuilder pragueDefinition( final Optional chainId, - final OptionalInt configContractSizeLimit, - final OptionalInt configStackSizeLimit, final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, @@ -741,13 +628,7 @@ static ProtocolSpecBuilder pragueDefinition( 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 @@ static ProtocolSpecBuilder pragueDefinition( // 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 @@ static ProtocolSpecBuilder pragueDefinition( static ProtocolSpecBuilder pragueEOFDefinition( final Optional 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 @@ static ProtocolSpecBuilder pragueEOFDefinition( 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 @@ static ProtocolSpecBuilder pragueEOFDefinition( static ProtocolSpecBuilder futureEipsDefinition( final Optional 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 @@ static ProtocolSpecBuilder futureEipsDefinition( 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 @@ static ProtocolSpecBuilder futureEipsDefinition( static ProtocolSpecBuilder experimentalEipsDefinition( final Optional 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 @@ static TransactionReceipt berlinTransactionReceiptFactoryWithReasonEnabled( 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 @@ private void updateWorldStateForDao(final MutableWorldState worldState) { 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
addresses = IntStream.range(0, json.size()) .mapToObj(json::getString) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index 78198922ea4..100a4425cdd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -24,6 +24,7 @@ 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 @@ private ProtocolScheduleBuilder( public ProtocolSchedule createProtocolSchedule() { final Optional chainId = config.getChainId().or(() -> defaultChainId); - protocolSchedule = new DefaultProtocolSchedule(chainId); + DefaultProtocolSchedule protocolSchedule = new DefaultProtocolSchedule(chainId); initSchedule(protocolSchedule, chainId); return protocolSchedule; } @@ -118,18 +117,18 @@ private void initSchedule( 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 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 @@ private void initSchedule( builders.put( modifierBlock, new BuilderMapEntry( - parent.milestoneType, - modifierBlock, - parent.getBuilder(), - entry.getValue())); + parent.milestoneType, modifierBlock, parent.builder(), entry.getValue())); }); } @@ -158,8 +154,8 @@ private void initSchedule( 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 @@ private void initSchedule( final ProtocolSpec originalProtocolSpec = getProtocolSpec( protocolSchedule, - previousSpecBuilder.getBuilder(), - previousSpecBuilder.getModifier()); + previousSpecBuilder.builder(), + previousSpecBuilder.modifier()); addProtocolSpec( protocolSchedule, BuilderMapEntry.MilestoneType.BLOCK_NUMBER, @@ -201,14 +197,13 @@ private void initSchedule( 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 @@ private NavigableMap buildMilestoneMap( .flatMap(Optional::stream) .collect( Collectors.toMap( - BuilderMapEntry::getBlockIdentifier, + BuilderMapEntry::blockIdentifier, b -> b, (existing, replacement) -> replacement, TreeMap::new)); @@ -413,34 +408,11 @@ private void addProtocolSpec( } } - private static class BuilderMapEntry { - private final MilestoneType milestoneType; - private final long blockIdentifier; - private final ProtocolSpecBuilder builder; - private final Function modifier; - - public BuilderMapEntry( - final MilestoneType milestoneType, - final long blockIdentifier, - final ProtocolSpecBuilder builder, - final Function 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 getModifier() { - return modifier; - } + private record BuilderMapEntry( + ProtocolScheduleBuilder.BuilderMapEntry.MilestoneType milestoneType, + long blockIdentifier, + ProtocolSpecBuilder builder, + Function modifier) { private enum MilestoneType { BLOCK_NUMBER, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index f79c6a874bb..cd886b6c847 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -60,7 +60,7 @@ public class ProtocolSpecBuilder { private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; private Function blockBodyValidatorBuilder; - private BiFunction contractCreationProcessorBuilder; + private Function contractCreationProcessorBuilder; private Function precompileContractRegistryBuilder; private BiFunction @@ -155,8 +155,7 @@ public ProtocolSpecBuilder blockBodyValidatorBuilder( } public ProtocolSpecBuilder contractCreationProcessorBuilder( - final BiFunction - contractCreationProcessorBuilder) { + final Function contractCreationProcessorBuilder) { this.contractCreationProcessorBuilder = contractCreationProcessorBuilder; return this; } @@ -165,7 +164,7 @@ public ProtocolSpecBuilder precompileContractRegistryBuilder( final Function precompileContractRegistryBuilder) { this.precompileContractRegistryBuilder = - (precompiledContractConfiguration) -> { + precompiledContractConfiguration -> { final PrecompileContractRegistry registry = precompileContractRegistryBuilder.apply(precompiledContractConfiguration); if (precompiledContractConfiguration.getPrivacyParameters().isEnabled()) { @@ -327,9 +326,9 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { 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 interface BlockImporterBuilder { public interface TransactionValidatorFactoryBuilder { TransactionValidatorFactory apply( - GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket); + EVM evm, GasLimitCalculator gasLimitCalculator, FeeMarket feeMarket); } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java index d190e55b0df..05d90a7b358 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BenchmarkSubCommand.java @@ -18,7 +18,6 @@ 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 @@ enum Benchmark { negatable = true) Boolean nativeCode; - @Option( - names = {"--fork"}, - paramLabel = "", - description = "Fork to evaluate, when it impacts gas costing.") - String fork = EvmSpecVersion.defaultVersion().getName(); - @Parameters(description = "One or more of ${COMPLETION-CANDIDATES}.") EnumSet benchmarks = EnumSet.noneOf(Benchmark.class); @@ -91,7 +84,7 @@ public void run() { 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()); } } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java index beb51cd4a6c..10e167f4069 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java @@ -17,9 +17,12 @@ 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.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 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 @@ 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 String considerCode(final String hexCode) { 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"; } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java index cb2fbbfeb64..ab53b41e1d4 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java @@ -20,13 +20,13 @@ 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 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 void run() { 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 @@ private void executeEOFTest(final String fileName, final Map getProtocolSpec(); + ProtocolSpec getProtocolSpec(); + + EVM getEVM(); WorldUpdater getWorldUpdater(); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index 761c81811ae..dc6b6dce00e 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -27,9 +27,11 @@ 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 @@ ProtocolSchedule provideProtocolSchedule( } } - 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()); } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java index 4e03f1aa69e..10d31960a82 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java @@ -16,7 +16,11 @@ 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 void run() { "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()); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java index 13ec7d877bd..1b8f557b3b8 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java @@ -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 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(); } } diff --git a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java index 87af915f665..dd7133f862e 100644 --- a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java +++ b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/CodeValidationSubCommandTest.java @@ -19,7 +19,7 @@ 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 @@ void testSingleValidViaInput() { 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 @@ void testSingleInvalidViaInput() { 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 @@ void testMultipleViaInput() { 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 @@ void testSingleValidViaCli() { 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 @@ void testSingleInvalidViaCli() { 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 @@ void testMultipleViaCli() { 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 @@ void testCliEclipsesInput() { 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 @@ void testBlankLinesAndCommentsSkipped() { 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( diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 2ebf5f79969..0976b924213 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -17,10 +17,13 @@ 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 ProtocolSchedule getByName(final String name) { 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, diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java index 22bf3839010..58f8c025297 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java @@ -23,12 +23,10 @@ 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 static Collection generateTestParametersForConfig(final String[ 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 static void executeTest( ? 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)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/Code.java b/evm/src/main/java/org/hyperledger/besu/evm/Code.java index bcec2872498..ac269d281da 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/Code.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/Code.java @@ -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 getSubContainer(final int index, final Bytes auxData); + Optional getSubContainer(final int index, final Bytes auxData, EVM evm); /** * Loads data from the appropriate data section diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java index 03348d9ab78..f2eb7cf29df 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/EVM.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/EVM.java @@ -20,6 +20,7 @@ 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 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 Code getCode(final Hash codeHash, final Bytes codeBytes) { * @return the code */ public Code getCodeUncached(final Bytes codeBytes) { - return CodeFactory.createCode(codeBytes, evmSpecVersion.getMaxEofVersion()); + return codeFactory.createCode(codeBytes); } /** @@ -375,6 +382,16 @@ public Code getCodeUncached(final Bytes codeBytes) { * @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); } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java index e543f672df0..9bf370d0318 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java @@ -23,49 +23,58 @@ /** 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 int getMaxEofVersion() { 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 * diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeFactory.java b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeFactory.java index f9a85a20b70..a0bba703718 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeFactory.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeFactory.java @@ -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); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeInvalid.java b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeInvalid.java index be71c296aef..c7efd230f38 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeInvalid.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeInvalid.java @@ -16,6 +16,7 @@ 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 int getDataSize() { return 0; } + @Override + public int getDeclaredDataSize() { + return 0; + } + @Override public Bytes getBytes() { return codeBytes; @@ -107,7 +113,7 @@ public int getSubcontainerCount() { } @Override - public Optional getSubContainer(final int index, final Bytes auxData) { + public Optional getSubContainer(final int index, final Bytes auxData, final EVM evm) { return Optional.empty(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV0.java b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV0.java index 31a49ba15aa..45b9cb82eea 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV0.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV0.java @@ -16,6 +16,7 @@ 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 int getDataSize() { return 0; } + @Override + public int getDeclaredDataSize() { + return 0; + } + @Override public Bytes getBytes() { return bytes; @@ -149,7 +155,7 @@ public int getSubcontainerCount() { } @Override - public Optional getSubContainer(final int index, final Bytes auxData) { + public Optional getSubContainer(final int index, final Bytes auxData, final EVM evm) { return Optional.empty(); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1.java b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1.java index 2bea400ed7f..50ffdd41061 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1.java @@ -18,6 +18,7 @@ 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 int getSubcontainerCount() { } @Override - public Optional getSubContainer(final int index, final Bytes auxData) { + public Optional 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 int getDataSize() { 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()); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java index c940a7d930b..3c85bd1eb22 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/CodeV1Validation.java @@ -52,12 +52,20 @@ 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 @@ private 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 workList = new ArrayDeque<>(layout.getSubcontainerCount()); workList.add(layout); @@ -87,12 +100,12 @@ public static String validate(final EOFLayout layout) { : " 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 static String validate(final EOFLayout layout) { * @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 static String validateCode(final EOFLayout eofLayout) { * @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 @@ static String validateCode( } @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 @@ static String validateStack(final EOFLayout eofLayout) { * @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(); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java b/evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java index 1cce49b4531..8b41a979231 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/EOFLayout.java @@ -323,7 +323,7 @@ public static EOFLayout parseEOF(final Bytes container, final boolean strictSize } 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 static EOFLayout parseEOF(final Bytes container, final boolean strictSize } 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); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/code/EOFValidator.java b/evm/src/main/java/org/hyperledger/besu/evm/code/EOFValidator.java new file mode 100644 index 00000000000..3cbdb404f0c --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/code/EOFValidator.java @@ -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); +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/CachedInvalidCodeRule.java b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/CachedInvalidCodeRule.java deleted file mode 100644 index e0a7e49f416..00000000000 --- a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/CachedInvalidCodeRule.java +++ /dev/null @@ -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 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()); - } -} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/ContractValidationRule.java b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/ContractValidationRule.java index a32718e7494..c5c61dd7438 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/ContractValidationRule.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/ContractValidationRule.java @@ -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 validate(Bytes contractCode, MessageFrame frame); + Optional validate(Bytes contractCode, MessageFrame frame, EVM evm); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/EOFValidationCodeRule.java b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/EOFValidationCodeRule.java index a052bcfa83d..e61a006f0e7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/EOFValidationCodeRule.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/EOFValidationCodeRule.java @@ -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 @@ private EOFValidationCodeRule(final int maxEofVersion) { * * @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 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 Optional validate( * * @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()); + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/MaxCodeSizeRule.java b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/MaxCodeSizeRule.java index 9a82e89a6fa..794650a1390 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/MaxCodeSizeRule.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/MaxCodeSizeRule.java @@ -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 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 Optional validate( } /** - * 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()); + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/PrefixCodeRule.java b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/PrefixCodeRule.java index b596786bacf..b19c4729313 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/PrefixCodeRule.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/contractvalidation/PrefixCodeRule.java @@ -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 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); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java index 64e9653ab7a..a65bd034d52 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java @@ -77,7 +77,7 @@ public class EVMExecutor { private OperationTracer tracer = OperationTracer.NO_TRACING; private boolean requireDeposit = true; private List contractValidationRules = - List.of(MaxCodeSizeRule.of(0x6000), PrefixCodeRule.of()); + List.of(MaxCodeSizeRule.from(EvmSpecVersion.SPURIOUS_DRAGON), PrefixCodeRule.of()); private long initialNonce = 1; private Collection
forceCommitAddresses = List.of(Address.fromHexString("0x03")); private Set
accessListWarmAddresses = new BytesTrieSet<>(Address.SIZE); @@ -240,7 +240,8 @@ public static EVMExecutor spuriousDragon(final EvmConfiguration evmConfiguration 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 static EVMExecutor byzantium(final EvmConfiguration evmConfiguration) { 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 static EVMExecutor constantinople(final EvmConfiguration evmConfiguration 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 static EVMExecutor petersburg(final EvmConfiguration evmConfiguration) { 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 static EVMExecutor istanbul( 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 static EVMExecutor berlin( 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 @@ private ContractCreationProcessor thisContractCreationProcessor() { contractCreationProcessor, () -> new ContractCreationProcessor( - evm.getGasCalculator(), - evm, - requireDeposit, - contractValidationRules, - initialNonce, - forceCommitAddresses)); + evm, requireDeposit, contractValidationRules, initialNonce, forceCommitAddresses)); } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java index af121ae92fb..729d10ffa50 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/ExceptionalHaltReason.java @@ -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 @@ enum DefaultExceptionalHaltReason implements 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"); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/internal/EvmConfiguration.java b/evm/src/main/java/org/hyperledger/besu/evm/internal/EvmConfiguration.java index 1264076537b..ef7265dad9f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/internal/EvmConfiguration.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/internal/EvmConfiguration.java @@ -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 maxCodeSizeOverride, + Optional maxInitcodeSizeOverride) { /** How should the world state update be handled within transactions? */ public enum WorldUpdaterMode { @@ -36,6 +50,22 @@ public enum WorldUpdaterMode { 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 enum WorldUpdaterMode { 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()); + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index 180eac27993..f026fd7110b 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -22,7 +22,6 @@ 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 @@ private void complete(final MessageFrame frame, final MessageFrame childFrame, f Code outputCode = (childFrame.getCreatedCode() != null) ? childFrame.getCreatedCode() - : CodeFactory.createCode(childFrame.getOutputData(), evm.getMaxEOFVersion()); + : evm.getCodeForCreation(childFrame.getOutputData()); frame.popStackItems(getStackItemsConsumed()); if (outputCode.isValid()) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java index cb6b2d4e3c4..0fb1e34a745 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/EOFCreateOperation.java @@ -74,7 +74,7 @@ protected Code getInitCode(final MessageFrame frame, final EVM evm) { 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 diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnContractOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnContractOperation.java index c8031f4c4d8..97895800765 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnContractOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ReturnContractOperation.java @@ -64,9 +64,15 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) { } Bytes auxData = frame.readMemory(from, length); - Optional 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 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()); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java index 5e668326345..0d394b2f887 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/AbstractMessageProcessor.java @@ -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 forceDeleteAccountsWhenEmpty; - private final EVM evm; + final EVM evm; /** * Instantiates a new Abstract message processor. @@ -188,15 +188,12 @@ public void process(final MessageFrame frame, final OperationTracer operationTra 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); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java index 0e47db90acb..a68c304c522 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java @@ -22,7 +22,6 @@ 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 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 contractValidationRules, final long initialContractNonce, final Collection
forceCommitAddresses) { super(evm, forceCommitAddresses); - this.gasCalculator = gasCalculator; this.requireCodeDepositToSucceed = requireCodeDepositToSucceed; this.contractValidationRules = contractValidationRules; this.initialContractNonce = initialContractNonce; @@ -74,25 +68,17 @@ public ContractCreationProcessor( /** * 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 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 void codeSuccess(final MessageFrame frame, final OperationTracer operatio 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 void codeSuccess(final MessageFrame frame, final OperationTracer operatio } 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()) { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java index 75ec9eb01bf..e1f1e767d21 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java @@ -18,6 +18,9 @@ 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 @@ void invalidCodeUnknownSectionId3() { @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 @@ void invalidReturncontractReturncontract() { "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(); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java index 1bc984222b4..3b16b1c9238 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java @@ -24,15 +24,12 @@ 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 @@ 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); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java index 8eda50316fd..f32a3f48668 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV1Test.java @@ -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 @@ private static void assertValidation( 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 @@ void validCode() { 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 @@ void invalidCode() { 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 @@ void validateStackAnalysis( + 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); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java index 871d99f768d..a080f649c90 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java @@ -22,7 +22,6 @@ 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 @@ void defaultChainIdAPIs() { 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 @@ void giantExecuteStack() { .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 @@ void giantExecuteStack() { .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(); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java index 94f616898a5..7b8a74b0cd9 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java @@ -17,7 +17,8 @@ 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); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java index 79f07e11af5..3c99bd71ffc 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/AbstractCreateOperationTest.java @@ -30,7 +30,6 @@ 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 @@ private void executeOperation(final Bytes contract, final EVM evm) { .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 @@ private void executeOperation(final Bytes contract, final EVM evm) { 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); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java index eb04ccb7419..73a4abd34ab 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/Create2OperationTest.java @@ -29,7 +29,6 @@ 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 void setUp(final String sender, final String salt, final String code) { .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 void setUp(final String sender, final String salt, final String code) { 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 @@ void shouldCalculateAddress( 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 @@ void shanghaiMaxInitCodeSizeCreate() { 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 @@ private MessageFrame testMemoryFrame(final UInt256 memoryOffset, final UInt256 m .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 @@ void eofV1CannotCall() { 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 @@ void eofV1CannotCall() { 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); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java index d95875e492b..4fa5a0fdd74 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/CreateOperationTest.java @@ -28,7 +28,6 @@ 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 @@ void createFromMemoryMutationSafe() { 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 @@ void shanghaiMaxInitCodeSizeCreate() { 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 @@ void eofV1CannotCall() { 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 @@ private MessageFrame testMemoryFrame( .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))) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java index 2e41b49665b..c0a7f2bcc45 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/EofCreateOperationTest.java @@ -29,7 +29,6 @@ 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 @@ void innerContractIsCorrect() { 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 @@ void innerContractIsCorrect() { @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 @@ void eofCreatePassesInCallData() { 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; diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCallOperationTest.java index 3a2ddde7e47..984ce28027f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtCallOperationTest.java @@ -23,11 +23,12 @@ 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 data() { @@ -130,12 +131,13 @@ void gasTest( 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 @@ void callWithValueTest( .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 @@ void overflowTest() { .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(); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtDelegateCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtDelegateCallOperationTest.java index 7a46654039d..d83e9f3ddc5 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtDelegateCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtDelegateCallOperationTest.java @@ -23,11 +23,12 @@ 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 data() { @@ -134,12 +135,13 @@ void gasTest( 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 @@ void callTypes( 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 @@ void overflowTest() { .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(); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtStaticCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtStaticCallOperationTest.java index 25be1d1dfee..76f267ec538 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtStaticCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/ExtStaticCallOperationTest.java @@ -23,11 +23,12 @@ 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 data() { @@ -130,12 +131,13 @@ void gasTest( 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 @@ void overflowTest() { .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(); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java index e04b0d16f61..3c466422ed3 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/JumpOperationTest.java @@ -18,17 +18,14 @@ 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 @@ private TestMessageFrameBuilder createMessageFrameBuilder(final long initialGas) @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 @@ void shouldJumpWhenLocationIsJumpDest() { 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 @@ void shouldJumpWhenLocationIsJumpDestAndAtEndOfCode() { 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 @@ void shouldHaltWithInvalidJumDestinationWhenLocationIsOutsideOfCodeRange() { 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 @@ void shouldHaltWithInvalidJumDestinationWhenLocationIsOutsideOfCodeRange() { 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 @@ void longContractsValidate() { final MessageFrame longContract = createMessageFrameBuilder(100L) .pushStackItem(UInt256.fromHexString("0x12c")) - .code(CodeFactory.createCode(longCode, 0)) + .code(evm.getCodeUncached(longCode)) .build(); longContract.setPC(255); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java index a87c254b0ed..3b372f03a03 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/SelfDestructOperationTest.java @@ -24,11 +24,12 @@ 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 @@ void checkContractDeletionCommon( .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))) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java index 32f5ecc3238..40ef063db15 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java @@ -19,27 +19,25 @@ 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 @@ class ContractCreationProcessorTest extends AbstractMessageProcessorTest { - @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 @@ void shouldThrowAnExceptionWhenCodeContractFormatInvalidPreEOF() { 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 @@ void shouldNotThrowAnExceptionWhenCodeContractIsValid() { 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 @@ void shouldNotThrowAnExceptionWhenPrefixCodeRuleNotAdded() { 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 @@ void shouldThrowAnExceptionWhenCodeContractFormatInvalidPostEOF() { 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 @@ void eofValidationShouldAllowLegacyDeployFromLegacyInit() { 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 @@ void eofValidationShouldAllowEOFCode() { 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 @@ void prefixValidationShouldPreventEOFCode() { 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 @@ void eofValidationPreventsEOFDeployFromLegacyInit() { 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 @@ void shouldThrowAnExceptionWhenCodeContractTooLarge() { 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 @@ void shouldNotThrowAnExceptionWhenCodeContractTooLarge() { 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 @@ void shouldNotThrowAnExceptionWhenCodeSizeRuleNotAdded() { @Override protected ContractCreationProcessor getAbstractMessageProcessor() { return new ContractCreationProcessor( - gasCalculator, evm, true, Collections.emptyList(), 1, Collections.emptyList()); + evm, true, Collections.emptyList(), 1, Collections.emptyList()); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java index 4fc4d6bf6c7..fcf26c3c569 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/EvmToyCommand.java @@ -194,8 +194,7 @@ public void run() { .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 messageFrameStack = initialMessageFrame.getMessageFrameStack(); while (!messageFrameStack.isEmpty()) { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java index c0db4bfbf62..bd043f933b5 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java @@ -16,14 +16,14 @@ 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 @@ @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 @@ void setUp() { @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 @@ void shouldCallTraceAccountCreationResultIfIsExtendedTracing() { @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);