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

@ -146,14 +146,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
)
gaspool.AddGas(pre.Env.GasLimit)
vmContext := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: pre.Env.Coinbase,
BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
Time: pre.Env.Timestamp,
Difficulty: pre.Env.Difficulty,
GasLimit: pre.Env.GasLimit,
GetHash: getHash,
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: pre.Env.Coinbase,
BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
Time: pre.Env.Timestamp,
Difficulty: pre.Env.Difficulty,
GasLimit: pre.Env.GasLimit,
GetHash: getHash,
GetPrecompile: core.GetPrecompile,
}
// If currentBaseFee is defined, add it to the vmContext.
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/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
)
// ChainContext supports retrieving headers and consensus parameters from the
@ -61,17 +62,18 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
random = &header.MixDigest
}
return vm.BlockContext{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time,
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
BlobBaseFee: blobBaseFee,
GasLimit: header.GasLimit,
Random: random,
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
GetPrecompile: GetPrecompile,
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time,
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
BlobBaseFee: blobBaseFee,
GasLimit: header.GasLimit,
Random: random,
}
}
@ -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.
// 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 {

View file

@ -35,26 +35,11 @@ type (
// GetHashFunc returns the n'th block hash in the blockchain
// and is used by the BLOCKHASH EVM op code.
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
// it shouldn't be modified.
type BlockContext struct {
@ -65,6 +50,8 @@ type BlockContext struct {
Transfer TransferFunc
// GetHash returns the hash corresponding to n
GetHash GetHashFunc
// GetPrecompileFunc gets a precompile by address if available
GetPrecompile GetPrecompileFunc
// Block information
Coinbase common.Address // Provides information for COINBASE
@ -172,6 +159,14 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
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
// 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
@ -186,7 +181,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return nil, gas, ErrInsufficientBalance
}
snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr)
p, isPrecompile := evm.GetPrecompile(addr)
debug := evm.Config.Tracer != nil
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
if p, isPrecompile := evm.precompile(addr); isPrecompile {
if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas)
} else {
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
if p, isPrecompile := evm.precompile(addr); isPrecompile {
if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas)
} else {
addrCopy := addr
@ -380,7 +375,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}(gas)
}
if p, isPrecompile := evm.precompile(addr); isPrecompile {
if p, isPrecompile := evm.GetPrecompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas)
} else {
// At this point, we use a copy of address. If we don't, the go compiler will

View file

@ -29,17 +29,18 @@ func NewEnv(cfg *Config) *vm.EVM {
BlobFeeCap: cfg.BlobFeeCap,
}
blockContext := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetHash: cfg.GetHashFn,
Coinbase: cfg.Coinbase,
BlockNumber: cfg.BlockNumber,
Time: cfg.Time,
Difficulty: cfg.Difficulty,
GasLimit: cfg.GasLimit,
BaseFee: cfg.BaseFee,
BlobBaseFee: cfg.BlobBaseFee,
Random: cfg.Random,
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetHash: cfg.GetHashFn,
GetPrecompile: core.GetPrecompile,
Coinbase: cfg.Coinbase,
BlockNumber: cfg.BlockNumber,
Time: cfg.Time,
Difficulty: cfg.Difficulty,
GasLimit: cfg.GasLimit,
BaseFee: cfg.BaseFee,
BlobBaseFee: cfg.BlobBaseFee,
Random: cfg.Random,
}
return vm.NewEVM(blockContext, txContext, cfg.State, cfg.ChainConfig, cfg.EVMConfig)

View file

@ -124,14 +124,15 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
context = vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
}
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
)
@ -223,13 +224,14 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
GasPrice: tx.GasPrice(),
}
context := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
}
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil {
@ -267,13 +269,14 @@ func TestInternals(t *testing.T) {
GasPrice: big.NewInt(1),
}
context = vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000),
Time: 5,
Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000),
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(8000000),
Time: 5,
Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000),
}
)
mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer {

View file

@ -87,13 +87,14 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
}
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
context := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
}
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
defer triedb.Close()

View file

@ -94,14 +94,15 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
var (
signer = types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
context = vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: test.Context.Miner,
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
Time: uint64(test.Context.Time),
Difficulty: (*big.Int)(test.Context.Difficulty),
GasLimit: uint64(test.Context.GasLimit),
BaseFee: test.Genesis.BaseFee,
}
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme)
)

View file

@ -52,14 +52,15 @@ func BenchmarkTransactionTrace(b *testing.B) {
GasPrice: tx.GasPrice(),
}
context := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(uint64(5)),
Time: 5,
Difficulty: big.NewInt(0xffffffff),
GasLimit: gas,
BaseFee: big.NewInt(8),
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetPrecompile: core.GetPrecompile,
Coinbase: common.Address{},
BlockNumber: new(big.Int).SetUint64(uint64(5)),
Time: 5,
Difficulty: big.NewInt(0xffffffff),
GasLimit: gas,
BaseFee: big.NewInt(8),
}
alloc := core.GenesisAlloc{}
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns