From abd62c321076e4b94438896bf1353affe4b641a7 Mon Sep 17 00:00:00 2001 From: Loredana Date: Wed, 16 Feb 2022 15:45:04 +0200 Subject: [PATCH] base precompile changes --- core/evm.go | 10 +++++++++ core/state_processor.go | 5 +++-- core/vm/contracts.go | 50 ++++++++++++++++++++--------------------- core/vm/evm.go | 40 ++++++++++++++++++++++++--------- eth/api_backend.go | 4 +++- 5 files changed, 71 insertions(+), 38 deletions(-) diff --git a/core/evm.go b/core/evm.go index 536ac673e6a6..5b44a2163447 100644 --- a/core/evm.go +++ b/core/evm.go @@ -35,6 +35,16 @@ type ChainContext interface { GetHeader(common.Hash, uint64) *types.Header } +type ChainContextExtended interface { + // Engine retrieves the chain's consensus engine. + Engine() consensus.Engine + + // GetHeader returns the hash corresponding to their hash. + GetHeader(common.Hash, uint64) *types.Header + GetBlock(common.Hash, uint64) *types.Block + GetBlockByNumber(uint64) *types.Block +} + // NewEVMBlockContext creates a new context for use in the EVM. func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext { var ( diff --git a/core/state_processor.go b/core/state_processor.go index d4c77ae41042..501a34e6cdef 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -92,10 +92,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, nil } -func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContextExtended, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) + evm.Chain = bc // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) @@ -141,7 +142,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainCon // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { +func ApplyTransaction(config *params.ChainConfig, bc ChainContextExtended, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee) if err != nil { return nil, err diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 9210f5486c57..4e0db1fca735 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -38,8 +38,8 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(input []byte) ([]byte, error) // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -147,13 +147,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(evm *EVM, caller ContractRef, p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } suppliedGas -= gasCost - output, err := p.Run(input) + output, err := p.Run(evm, caller, input) return output, suppliedGas, err } @@ -164,7 +164,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(input []byte) ([]byte, error) { +func (c *ecrecover) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -205,7 +205,7 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas } -func (c *sha256hash) Run(input []byte) ([]byte, error) { +func (c *sha256hash) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -220,7 +220,7 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas } -func (c *ripemd160hash) Run(input []byte) ([]byte, error) { +func (c *ripemd160hash) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -236,7 +236,7 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas } -func (c *dataCopy) Run(in []byte) ([]byte, error) { +func (c *dataCopy) Run(evm *EVM, caller ContractRef, in []byte) ([]byte, error) { return in, nil } @@ -362,7 +362,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(input []byte) ([]byte, error) { +func (c *bigModExp) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -435,7 +435,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256AddIstanbul) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256Add(input) } @@ -448,7 +448,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256AddByzantium) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256Add(input) } @@ -473,7 +473,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulIstanbul) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256ScalarMul(input) } @@ -486,7 +486,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256ScalarMulByzantium) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256ScalarMul(input) } @@ -541,7 +541,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) { +func (c *bn256PairingIstanbul) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256Pairing(input) } @@ -554,7 +554,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) { +func (c *bn256PairingByzantium) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { return runBn256Pairing(input) } @@ -580,7 +580,7 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(input []byte) ([]byte, error) { +func (c *blake2F) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -634,7 +634,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Add) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G1Add precompile. // > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each). // > Output is an encoding of addition operation result - single G1 point (`128` bytes). @@ -672,7 +672,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Mul) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G1Mul precompile. // > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G1 point (`128` bytes). @@ -722,7 +722,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000 } -func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G1MultiExp) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G1MultiExp precompile. // G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes). // Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes). @@ -765,7 +765,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Add) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G2Add precompile. // > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each). // > Output is an encoding of addition operation result - single G2 point (`256` bytes). @@ -803,7 +803,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Mul) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G2MUL precompile logic. // > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiplication operation result - single G2 point (`256` bytes). @@ -853,7 +853,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000 } -func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { +func (c *bls12381G2MultiExp) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 G2MultiExp precompile logic // > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes). // > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes). @@ -896,7 +896,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 { return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas } -func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { +func (c *bls12381Pairing) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 Pairing precompile logic. // > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure: // > - `128` bytes of G1 point encoding @@ -975,7 +975,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG1) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. @@ -1010,7 +1010,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG2) Run(evm *EVM, caller ContractRef, input []byte) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. diff --git a/core/vm/evm.go b/core/vm/evm.go index dd55618bf812..6f21d0e44820 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -41,19 +42,23 @@ type ( GetHashFunc func(uint64) common.Hash ) -func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { +func getPrecompiles(chainRules params.Rules) map[common.Address]PrecompiledContract { var precompiles map[common.Address]PrecompiledContract switch { - case evm.chainRules.IsBerlin: + case chainRules.IsBerlin: precompiles = PrecompiledContractsBerlin - case evm.chainRules.IsIstanbul: + case chainRules.IsIstanbul: precompiles = PrecompiledContractsIstanbul - case evm.chainRules.IsByzantium: + case chainRules.IsByzantium: precompiles = PrecompiledContractsByzantium default: precompiles = PrecompiledContractsHomestead } - p, ok := precompiles[addr] + return precompiles +} + +func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { + p, ok := evm.Precompiles[addr] return p, ok } @@ -86,6 +91,13 @@ type TxContext struct { GasPrice *big.Int // Provides information for GASPRICE } +type ChainContext interface { + // GetHeader returns the hash corresponding to their hash. + GetHeader(common.Hash, uint64) *types.Header + GetBlock(common.Hash, uint64) *types.Block + GetBlockByNumber(uint64) *types.Block +} + // EVM is the Ethereum Virtual Machine base object and provides // the necessary tools to run a contract on the given state with // the provided context. It should be noted that any error @@ -96,6 +108,8 @@ type TxContext struct { // // The EVM should never be reused and is not thread safe. type EVM struct { + Precompiles map[common.Address]PrecompiledContract + Chain ChainContext // Context provides auxiliary blockchain related information Context BlockContext TxContext @@ -125,8 +139,14 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { +func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config, args ...map[common.Address]PrecompiledContract) *EVM { + chainRules := chainConfig.Rules(blockCtx.BlockNumber) + precompiles := args[0] + if precompiles == nil { + precompiles = getPrecompiles(chainRules) + } evm := &EVM{ + Precompiles: precompiles, Context: blockCtx, TxContext: txCtx, StateDB: statedb, @@ -212,7 +232,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm, caller, p, input, gas) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -275,7 +295,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 { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm, caller, p, input, gas) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -316,7 +336,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 { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm, caller, p, input, gas) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -365,7 +385,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = RunPrecompiledContract(evm, caller, p, input, gas) } else { // At this point, we use a copy of address. If we don't, the go compiler will // leak the 'contract' to the outer scope, and make allocation for 'contract' diff --git a/eth/api_backend.go b/eth/api_backend.go index 6577ac1e1af4..3873080331fd 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -208,7 +208,9 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *sta } txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) - return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), vmError, nil + evm := vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig) + evm.Chain = b.eth.BlockChain() + return evm, vmError, nil } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {