make getPrecompile configurable

This commit is contained in:
ramtinms 2024-01-17 14:35:20 -08:00
parent e5d5e09faa
commit 6f86fdaf87
8 changed files with 120 additions and 97 deletions

View file

@ -154,6 +154,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
Difficulty: pre.Env.Difficulty, Difficulty: pre.Env.Difficulty,
GasLimit: pre.Env.GasLimit, GasLimit: pre.Env.GasLimit,
GetHash: getHash, GetHash: getHash,
GetPrecompile: core.GetPrecompile,
} }
// If currentBaseFee is defined, add it to the vmContext. // If currentBaseFee is defined, add it to the vmContext.
if pre.Env.BaseFee != nil { if pre.Env.BaseFee != nil {

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
) )
// ChainContext supports retrieving headers and consensus parameters from the // ChainContext supports retrieving headers and consensus parameters from the
@ -64,6 +65,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
CanTransfer: CanTransfer, CanTransfer: CanTransfer,
Transfer: Transfer, Transfer: Transfer,
GetHash: GetHashFn(header, chain), GetHash: GetHashFn(header, chain),
GetPrecompile: GetPrecompile,
Coinbase: beneficiary, Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number), BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time, Time: header.Time,
@ -127,6 +129,24 @@ func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash
} }
} }
func GetPrecompile(rules params.Rules, addr common.Address) (vm.PrecompiledContract, bool) {
var precompiles map[common.Address]vm.PrecompiledContract
switch {
case rules.IsCancun:
precompiles = vm.PrecompiledContractsCancun
case rules.IsBerlin:
precompiles = vm.PrecompiledContractsBerlin
case rules.IsIstanbul:
precompiles = vm.PrecompiledContractsIstanbul
case rules.IsByzantium:
precompiles = vm.PrecompiledContractsByzantium
default:
precompiles = vm.PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}
// CanTransfer checks whether there are enough funds in the address' account to make a transfer. // CanTransfer checks whether there are enough funds in the address' account to make a transfer.
// This does not take the necessary gas in to account to make the transfer valid. // This does not take the necessary gas in to account to make the transfer valid.
func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool { func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {

View file

@ -35,26 +35,11 @@ type (
// GetHashFunc returns the n'th block hash in the blockchain // GetHashFunc returns the n'th block hash in the blockchain
// and is used by the BLOCKHASH EVM op code. // and is used by the BLOCKHASH EVM op code.
GetHashFunc func(uint64) common.Hash GetHashFunc func(uint64) common.Hash
// GetPrecompileFunc returns a precompile contract if available for the given
// address, it returns false if no precompile is deployed at that address
GetPrecompileFunc func(rules params.Rules, addr common.Address) (PrecompiledContract, bool)
) )
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsCancun:
precompiles = PrecompiledContractsCancun
case evm.chainRules.IsBerlin:
precompiles = PrecompiledContractsBerlin
case evm.chainRules.IsIstanbul:
precompiles = PrecompiledContractsIstanbul
case evm.chainRules.IsByzantium:
precompiles = PrecompiledContractsByzantium
default:
precompiles = PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}
// BlockContext provides the EVM with auxiliary information. Once provided // BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified. // it shouldn't be modified.
type BlockContext struct { type BlockContext struct {
@ -65,6 +50,8 @@ type BlockContext struct {
Transfer TransferFunc Transfer TransferFunc
// GetHash returns the hash corresponding to n // GetHash returns the hash corresponding to n
GetHash GetHashFunc GetHash GetHashFunc
// GetPrecompileFunc gets a precompile by address if available
GetPrecompile GetPrecompileFunc
// Block information // Block information
Coinbase common.Address // Provides information for COINBASE Coinbase common.Address // Provides information for COINBASE
@ -172,6 +159,14 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter return evm.interpreter
} }
func (evm *EVM) GetPrecompile(addr common.Address) (PrecompiledContract, bool) {
if evm.Context.GetPrecompile != nil {
p, isPrecompile := evm.Context.GetPrecompile(evm.chainRules, addr)
return p, isPrecompile
}
return nil, false
}
// Call executes the contract associated with the addr with the given input as // Call executes the contract associated with the addr with the given input as
// parameters. It also handles any necessary value transfer required and takes // parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an // the necessary steps to create accounts and reverses the state in case of an
@ -186,7 +181,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return nil, gas, ErrInsufficientBalance return nil, gas, ErrInsufficientBalance
} }
snapshot := evm.StateDB.Snapshot() snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr) p, isPrecompile := evm.GetPrecompile(addr)
debug := evm.Config.Tracer != nil debug := evm.Config.Tracer != nil
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
@ -286,7 +281,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
} }
// It is allowed to call precompiles, even via delegatecall // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
addrCopy := addr addrCopy := addr
@ -331,7 +326,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
} }
// It is allowed to call precompiles, even via delegatecall // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
addrCopy := addr addrCopy := addr
@ -380,7 +375,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}(gas) }(gas)
} }
if p, isPrecompile := evm.precompile(addr); isPrecompile { if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas) ret, gas, err = RunPrecompiledContract(p, input, gas)
} else { } else {
// At this point, we use a copy of address. If we don't, the go compiler will // At this point, we use a copy of address. If we don't, the go compiler will

View file

@ -32,6 +32,7 @@ func NewEnv(cfg *Config) *vm.EVM {
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetHash: cfg.GetHashFn, GetHash: cfg.GetHashFn,
GetPrecompile: core.GetPrecompile,
Coinbase: cfg.Coinbase, Coinbase: cfg.Coinbase,
BlockNumber: cfg.BlockNumber, BlockNumber: cfg.BlockNumber,
Time: cfg.Time, Time: cfg.Time,

View file

@ -126,6 +126,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
context = vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time), Time: uint64(test.Context.Time),
@ -225,6 +226,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
context := vm.BlockContext{ context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time), Time: uint64(test.Context.Time),
@ -269,6 +271,7 @@ func TestInternals(t *testing.T) {
context = vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000), BlockNumber: new(big.Int).SetUint64(8000000),
Time: 5, Time: 5,

View file

@ -89,6 +89,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
context := vm.BlockContext{ context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time), Time: uint64(test.Context.Time),

View file

@ -96,6 +96,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
context = vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner, Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time), Time: uint64(test.Context.Time),

View file

@ -54,6 +54,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
context := vm.BlockContext{ context := vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: common.Address{}, Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(uint64(5)), BlockNumber: new(big.Int).SetUint64(uint64(5)),
Time: 5, Time: 5,