diff --git a/core/vm/contracts.go b/core/vm/contracts.go index ee1308fa7087..a21327e7da84 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls12381" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/libevm" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) @@ -163,12 +164,29 @@ func ActivePrecompiles(rules params.Rules) []common.Address { } } +type statefulPrecompileIntf interface { + RunExtra( + chainConifg *params.ChainConfig, + blockNumber *big.Int, blockTime uint64, + predicateResults libevm.PredicateResults, + _ libevm.StateDB, _ *params.Rules, caller, self common.Address, input []byte, suppliedGas uint64, readOnly bool) ([]byte, uint64, error) +} + // RunPrecompiledContract runs and evaluates the output of a precompiled contract. // It returns // - the returned bytes, // - the _remaining_ gas, // - any error that occurred func (args *evmCallArgs) RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if p, ok := p.(statefulPrecompileIntf); ok { + return p.RunExtra( + args.evm.chainConfig, + args.evm.Context.BlockNumber, + args.evm.Context.Time, + args.evm.Context.PredicateResults, + args.evm.StateDB, &args.evm.chainRules, args.caller.Address(), args.addr, input, + suppliedGas, args.evm.interpreter.readOnly) + } gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas diff --git a/core/vm/evm.go b/core/vm/evm.go index 1e6b24debb1a..29342c342560 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -79,6 +79,8 @@ type BlockContext struct { BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price) BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price) Random *common.Hash // Provides information for PREVRANDAO + + PredicateResults libevm.PredicateResults } // TxContext provides the EVM with information about a transaction. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1968289f4eaa..91fb8df1f674 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -55,7 +55,10 @@ type EVMInterpreter struct { func NewEVMInterpreter(evm *EVM) *EVMInterpreter { // If jump table was not initialised we set the default one. var table *JumpTable + customTable := evm.chainRules.Hooks().JumpTable() switch { + case customTable != nil: + table = customTable.(*JumpTable) case evm.chainRules.IsCancun: table = &cancunInstructionSet case evm.chainRules.IsShanghai: diff --git a/core/vm/jump_table_ext.go b/core/vm/jump_table_ext.go new file mode 100644 index 000000000000..55192582bdca --- /dev/null +++ b/core/vm/jump_table_ext.go @@ -0,0 +1,39 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package vm + +var ( + SubnetEVMInstructionSet = newSubnetEVMInstructionSet() + SubnetEVMDurangoInstructionSet = newSubnetEVMDurangoInstructionSet() + SubnetEVMCancunInstructionSet = newSubnetEVMCancunInstructionSet() +) + +func newSubnetEVMCancunInstructionSet() JumpTable { + instructionSet := newSubnetEVMDurangoInstructionSet() + enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) + enable7516(&instructionSet) // EIP-7516 (BLOBBASEFEE opcode) + enable1153(&instructionSet) // EIP-1153 "Transient Storage" + enable5656(&instructionSet) // EIP-5656 (MCOPY opcode) + enable6780(&instructionSet) // EIP-6780 SELFDESTRUCT only in same transaction + return validate(instructionSet) +} + +// newDurangoInstructionSet returns the frontier, homestead, byzantium, +// constantinople, istanbul, petersburg, subnet-evm, durango instructions. +func newSubnetEVMDurangoInstructionSet() JumpTable { + instructionSet := newSubnetEVMInstructionSet() + enable3855(&instructionSet) // PUSH0 instruction + enable3860(&instructionSet) // Limit and meter initcode + + return validate(instructionSet) +} + +// newSubnetEVMInstructionSet returns the frontier, homestead, byzantium, +// constantinople, istanbul, petersburg, subnet-evm instructions. +func newSubnetEVMInstructionSet() JumpTable { + instructionSet := newIstanbulInstructionSet() + enable2929(&instructionSet) + enable3198(&instructionSet) // Base fee opcode https://eips.ethereum.org/EIPS/eip-3198 + return validate(instructionSet) +} diff --git a/params/hooks.libevm.go b/params/hooks.libevm.go index 2b0b74fe86d0..1a27223ea19e 100644 --- a/params/hooks.libevm.go +++ b/params/hooks.libevm.go @@ -33,6 +33,8 @@ type RulesHooks interface { // [PrecompiledContract] is non-nil. If it returns `false` then the default // precompile behaviour is honoured. PrecompileOverride(common.Address) (_ libevm.PrecompiledContract, override bool) + + JumpTable() interface{} } // RulesAllowlistHooks are a subset of [RulesHooks] that gate actions, signalled @@ -99,3 +101,7 @@ func (NOOPHooks) CanCreateContract(*libevm.AddressContext, libevm.StateReader) e func (NOOPHooks) PrecompileOverride(common.Address) (libevm.PrecompiledContract, bool) { return nil, false } + +func (NOOPHooks) JumpTable() interface{} { + return nil +}