diff --git a/core/state_transition.go b/core/state_transition.go index 1a6a66a2fc..089480d9b3 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -431,7 +431,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) + st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, st.evm.ActivePrecompiles(rules), msg.AccessList) var ( ret []byte diff --git a/core/vm/contract.go b/core/vm/contract.go index cfda75b27e..65fbf37a7c 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -60,8 +60,9 @@ type Contract struct { // is the execution frame represented by this object a contract deployment IsDeployment bool - Gas uint64 - value *uint256.Int + Gas uint64 + value *uint256.Int + isPrecompile bool } // NewContract returns a new contract environment for the execution of EVM. @@ -84,7 +85,34 @@ func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas return c } +// NewPrecompile returns a new instance of a precompiled contract environment for the execution of EVM. +func NewPrecompile(caller, object ContractRef, value *uint256.Int, gas uint64) *Contract { + c := &Contract{ + CallerAddress: caller.Address(), + caller: caller, + self: object, + isPrecompile: true, + } + + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas + // ensures a value is set + c.value = value + + return c +} + +// IsPrecompile returns true if the contract is a precompiled contract environment +func (c Contract) IsPrecompile() bool { + return c.isPrecompile +} + func (c *Contract) validJumpdest(dest *uint256.Int) bool { + if c.isPrecompile { + return false + } + udest, overflow := dest.Uint64WithOverflow() // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. // Don't bother checking for JUMPDEST in that case. @@ -101,6 +129,10 @@ func (c *Contract) validJumpdest(dest *uint256.Int) bool { // isCode returns true if the provided PC location is an actual opcode, as // opposed to a data-segment following a PUSHN operation. func (c *Contract) isCode(udest uint64) bool { + if c.isPrecompile { + return false + } + // Do we already have an analysis laying around? if c.analysis != nil { return c.analysis.codeSegment(udest) @@ -134,6 +166,9 @@ func (c *Contract) isCode(udest uint64) bool { // AsDelegate sets the contract to be a delegate call and returns the current // contract (for chaining calls) func (c *Contract) AsDelegate() *Contract { + if c.isPrecompile { + return c + } // NOTE: caller must, at all times be a contract. It should never happen // that caller is something other than a Contract. parent := c.caller.(*Contract) @@ -196,6 +231,9 @@ func (c *Contract) Value() *uint256.Int { // SetCallCode sets the code of the contract and address of the backing data // object func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { + if c.isPrecompile { + return + } c.Code = code c.CodeHash = hash c.CodeAddr = addr @@ -204,6 +242,9 @@ func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []by // SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. // In case hash is not provided, the jumpdest analysis will not be saved to the parent context func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { + if c.isPrecompile { + return + } c.Code = codeAndHash.code c.CodeHash = codeAndHash.hash c.CodeAddr = addr diff --git a/core/vm/contracts.go b/core/vm/contracts.go index dd71a9729f..55edd5515f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -17,6 +17,7 @@ package vm import ( + "bytes" "crypto/sha256" "encoding/binary" "errors" @@ -35,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" "golang.org/x/crypto/ripemd160" ) @@ -42,97 +44,96 @@ 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 + ContractRef + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum // contracts used in the Frontier and Homestead releases. var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &ecrecover{}, - common.BytesToAddress([]byte{0x2}): &sha256hash{}, - common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x4}): &dataCopy{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, } // PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum // contracts used in the Byzantium release. var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &ecrecover{}, - common.BytesToAddress([]byte{0x2}): &sha256hash{}, - common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, - common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{}, - common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{}, - common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, + bigModExp{}.Address(): &bigModExp{eip2565: false}, + bn256AddByzantium{}.Address(): &bn256AddByzantium{}, + bn256ScalarMulByzantium{}.Address(): &bn256ScalarMulByzantium{}, + bn256PairingByzantium{}.Address(): &bn256PairingByzantium{}, } -// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum -// contracts used in the Istanbul release. var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &ecrecover{}, - common.BytesToAddress([]byte{0x2}): &sha256hash{}, - common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false}, - common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{0x9}): &blake2F{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, + bigModExp{}.Address(): &bigModExp{eip2565: false}, + bn256AddIstanbul{}.Address(): &bn256AddIstanbul{}, + bn256ScalarMulIstanbul{}.Address(): &bn256ScalarMulIstanbul{}, + bn256PairingIstanbul{}.Address(): &bn256PairingIstanbul{}, + blake2F{}.Address(): &blake2F{}, } // PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum // contracts used in the Berlin release. var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &ecrecover{}, - common.BytesToAddress([]byte{0x2}): &sha256hash{}, - common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, - common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{0x9}): &blake2F{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, + bigModExp{}.Address(): &bigModExp{eip2565: true}, + bn256AddIstanbul{}.Address(): &bn256AddIstanbul{}, + bn256ScalarMulIstanbul{}.Address(): &bn256ScalarMulIstanbul{}, + bn256PairingIstanbul{}.Address(): &bn256PairingIstanbul{}, + blake2F{}.Address(): &blake2F{}, } // PrecompiledContractsCancun contains the default set of pre-compiled Ethereum // contracts used in the Cancun release. var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x1}): &ecrecover{}, - common.BytesToAddress([]byte{0x2}): &sha256hash{}, - common.BytesToAddress([]byte{0x3}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x4}): &dataCopy{}, - common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true}, - common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{0x9}): &blake2F{}, - common.BytesToAddress([]byte{0xa}): &kzgPointEvaluation{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, + bigModExp{}.Address(): &bigModExp{eip2565: true}, + bn256AddIstanbul{}.Address(): &bn256AddIstanbul{}, + bn256ScalarMulIstanbul{}.Address(): &bn256ScalarMulIstanbul{}, + bn256PairingIstanbul{}.Address(): &bn256PairingIstanbul{}, + blake2F{}.Address(): &blake2F{}, + kzgPointEvaluation{}.Address(): &kzgPointEvaluation{}, } // PrecompiledContractsPrague contains the set of pre-compiled Ethereum // contracts used in the Prague release. var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{ - common.BytesToAddress([]byte{0x01}): &ecrecover{}, - common.BytesToAddress([]byte{0x02}): &sha256hash{}, - common.BytesToAddress([]byte{0x03}): &ripemd160hash{}, - common.BytesToAddress([]byte{0x04}): &dataCopy{}, - common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, - common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, - common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, - common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, - common.BytesToAddress([]byte{0x09}): &blake2F{}, - common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{}, - common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{}, - common.BytesToAddress([]byte{0x0c}): &bls12381G1Mul{}, - common.BytesToAddress([]byte{0x0d}): &bls12381G1MultiExp{}, - common.BytesToAddress([]byte{0x0e}): &bls12381G2Add{}, - common.BytesToAddress([]byte{0x0f}): &bls12381G2Mul{}, - common.BytesToAddress([]byte{0x10}): &bls12381G2MultiExp{}, - common.BytesToAddress([]byte{0x11}): &bls12381Pairing{}, - common.BytesToAddress([]byte{0x12}): &bls12381MapG1{}, - common.BytesToAddress([]byte{0x13}): &bls12381MapG2{}, + ecrecover{}.Address(): &ecrecover{}, + sha256hash{}.Address(): &sha256hash{}, + ripemd160hash{}.Address(): &ripemd160hash{}, + dataCopy{}.Address(): &dataCopy{}, + bigModExp{}.Address(): &bigModExp{eip2565: true}, + bn256AddIstanbul{}.Address(): &bn256AddIstanbul{}, + bn256ScalarMulIstanbul{}.Address(): &bn256ScalarMulIstanbul{}, + bn256PairingIstanbul{}.Address(): &bn256PairingIstanbul{}, + blake2F{}.Address(): &blake2F{}, + kzgPointEvaluation{}.Address(): &kzgPointEvaluation{}, + bls12381G1Add{}.Address(): &bls12381G1Add{}, + bls12381G1Mul{}.Address(): &bls12381G1Mul{}, + bls12381G1MultiExp{}.Address(): &bls12381G1MultiExp{}, + bls12381G2Add{}.Address(): &bls12381G2Add{}, + bls12381G2Mul{}.Address(): &bls12381G2Mul{}, + bls12381G2MultiExp{}.Address(): &bls12381G2MultiExp{}, + bls12381Pairing{}.Address(): &bls12381Pairing{}, + bls12381MapG1{}.Address(): &bls12381MapG1{}, + bls12381MapG2{}.Address(): &bls12381MapG2{}, } var PrecompiledContractsBLS = PrecompiledContractsPrague @@ -169,8 +170,8 @@ func init() { } } -// ActivePrecompiles returns the precompiles enabled with the current configuration. -func ActivePrecompiles(rules params.Rules) []common.Address { +// DefaultActivePrecompiles returns the set of precompiles enabled with the default configuration. +func DefaultActivePrecompiles(rules params.Rules) []common.Address { switch { case rules.IsPrague: return PrecompiledAddressesPrague @@ -187,53 +188,167 @@ func ActivePrecompiles(rules params.Rules) []common.Address { } } +// DefaultPrecompiles define the mapping of address and precompiles from the default configuration +func DefaultPrecompiles(rules params.Rules) (precompiles map[common.Address]PrecompiledContract) { + switch { + case rules.IsPrague: + precompiles = PrecompiledContractsPrague + case rules.IsCancun: + precompiles = PrecompiledContractsCancun + case rules.IsBerlin: + precompiles = PrecompiledContractsBerlin + case rules.IsIstanbul: + precompiles = PrecompiledContractsIstanbul + case rules.IsByzantium: + precompiles = PrecompiledContractsByzantium + default: + precompiles = PrecompiledContractsHomestead + } + + return precompiles +} + +// ActivePrecompiles returns the precompiles enabled with the current configuration. +// +// NOTE: The rules argument is ignored as the active precompiles can be set via the WithPrecompiles +// method according to the chain rules from the current block context. +func (evm *EVM) ActivePrecompiles(rules params.Rules) []common.Address { + return evm.activePrecompiles +} + +// Precompile returns a precompiled contract for the given address. This +// function returns false if the address is not a registered precompile. +func (evm *EVM) Precompile(addr common.Address) (PrecompiledContract, bool) { + p, ok := evm.precompiles[addr] + return p, ok +} + +// WithPrecompiles sets the precompiled contracts and the slice of actives precompiles. +// IMPORTANT: This function does NOT validate the precompiles provided to the EVM. The caller should +// use the ValidatePrecompiles function for this purpose prior to calling WithPrecompiles. +func (evm *EVM) WithPrecompiles( + precompiles map[common.Address]PrecompiledContract, + activePrecompiles []common.Address, +) { + evm.precompiles = precompiles + evm.activePrecompiles = activePrecompiles +} + +// ValidatePrecompiles validates the precompile map against the active +// precompile slice. +// It returns an error if the precompiled contract map has a different length +// than the slice of active contract addresses. This function also checks for +// duplicates, invalid addresses and empty precompile contract instances. +func ValidatePrecompiles( + precompiles map[common.Address]PrecompiledContract, + activePrecompiles []common.Address, +) error { + if len(precompiles) != len(activePrecompiles) { + return fmt.Errorf("precompiles length mismatch (expected %d, got %d)", len(precompiles), len(activePrecompiles)) + } + + dupActivePrecompiles := make(map[common.Address]bool) + + for _, addr := range activePrecompiles { + if dupActivePrecompiles[addr] { + return fmt.Errorf("duplicate active precompile: %s", addr) + } + + precompile, ok := precompiles[addr] + if !ok { + return fmt.Errorf("active precompile address doesn't exist in precompiles map: %s", addr) + } + + if precompile == nil { + return fmt.Errorf("precompile contract cannot be nil: %s", addr) + } + + if bytes.Equal(addr.Bytes(), common.Address{}.Bytes()) { + return fmt.Errorf("precompile cannot be the zero address: %s", addr) + } + + dupActivePrecompiles[addr] = true + } + + return nil +} + // RunPrecompiledContract runs and evaluates the output of a precompiled contract. // It returns // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { +func (evm *EVM) RunPrecompiledContract( + p PrecompiledContract, + caller ContractRef, + input []byte, + suppliedGas uint64, + value *uint256.Int, + readOnly bool, +) (ret []byte, remainingGas uint64, err error) { + return runPrecompiledContract(evm, p, caller, input, suppliedGas, value, readOnly) +} + +func runPrecompiledContract( + evm *EVM, + p PrecompiledContract, + caller ContractRef, + input []byte, + suppliedGas uint64, + value *uint256.Int, + readOnly bool, +) (ret []byte, remainingGas uint64, err error) { + addrCopy := p.Address() + inputCopy := make([]byte, len(input)) + copy(inputCopy, input) + + contract := NewPrecompile(caller, AccountRef(addrCopy), value, suppliedGas) + contract.Input = inputCopy + gasCost := p.RequiredGas(input) - if suppliedGas < gasCost { - return nil, 0, ErrOutOfGas + if !contract.UseGas(gasCost, evm.Config.Tracer, tracing.GasChangeCallPrecompiledContract) { + return nil, contract.Gas, ErrOutOfGas } - if logger != nil && logger.OnGasChange != nil { - logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) - } - suppliedGas -= gasCost - output, err := p.Run(input) - return output, suppliedGas, err + + output, err := p.Run(evm, contract, readOnly) + return output, contract.Gas, err } // ecrecover implemented as a native contract. type ecrecover struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (ecrecover) Address() common.Address { + return common.BytesToAddress([]byte{1}) +} + func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(input []byte) ([]byte, error) { +func (c *ecrecover) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { const ecRecoverInputLength = 128 - input = common.RightPadBytes(input, ecRecoverInputLength) + contract.Input = common.RightPadBytes(contract.Input, ecRecoverInputLength) // "input" is (hash, v, r, s), each 32 bytes // but for ecrecover we want (r, s, v) - r := new(big.Int).SetBytes(input[64:96]) - s := new(big.Int).SetBytes(input[96:128]) - v := input[63] - 27 + r := new(big.Int).SetBytes(contract.Input[64:96]) + s := new(big.Int).SetBytes(contract.Input[96:128]) + v := contract.Input[63] - 27 // tighter sig s values input homestead only apply to tx sigs - if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + if !allZero(contract.Input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { return nil, nil } // We must make sure not to modify the 'input', so placing the 'v' along with // the signature needs to be done on a new allocation sig := make([]byte, 65) - copy(sig, input[64:128]) + copy(sig, contract.Input[64:128]) sig[64] = v // v needs to be at the end for libsecp256k1 - pubKey, err := crypto.Ecrecover(input[:32], sig) + pubKey, err := crypto.Ecrecover(contract.Input[:32], sig) // make sure the public key is a valid one if err != nil { return nil, nil @@ -246,6 +361,12 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) { // SHA256 implemented as a native contract. type sha256hash struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (sha256hash) Address() common.Address { + return common.BytesToAddress([]byte{2}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -253,14 +374,20 @@ 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) { - h := sha256.Sum256(input) +func (c *sha256hash) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + h := sha256.Sum256(contract.Input) return h[:], nil } // RIPEMD160 implemented as a native contract. type ripemd160hash struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (ripemd160hash) Address() common.Address { + return common.BytesToAddress([]byte{3}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -268,15 +395,22 @@ 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, contract *Contract, readonly bool) ([]byte, error) { ripemd := ripemd160.New() - ripemd.Write(input) + ripemd.Write(contract.Input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil } // data copy implemented as a native contract. type dataCopy struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (dataCopy) Address() common.Address { + return common.BytesToAddress([]byte{4}) +} + + // RequiredGas returns the gas required to execute the pre-compiled contract. // // This method does not require any overflow checking as the input size gas costs @@ -284,8 +418,8 @@ 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) { - return common.CopyBytes(in), nil +func (c *dataCopy) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return common.CopyBytes(contract.Input), nil } // bigModExp implements a native big integer exponential modular operation. @@ -335,6 +469,12 @@ func modexpMultComplexity(x *big.Int) *big.Int { return x } +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bigModExp) Address() common.Address { + return common.BytesToAddress([]byte{5}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bigModExp) RequiredGas(input []byte) uint64 { var ( @@ -406,16 +546,16 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { return gas.Uint64() } -func (c *bigModExp) Run(input []byte) ([]byte, error) { +func (c *bigModExp) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { var ( - baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() - expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() - modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() + baseLen = new(big.Int).SetBytes(getData(contract.Input, 0, 32)).Uint64() + expLen = new(big.Int).SetBytes(getData(contract.Input, 32, 32)).Uint64() + modLen = new(big.Int).SetBytes(getData(contract.Input, 64, 32)).Uint64() ) - if len(input) > 96 { - input = input[96:] + if len(contract.Input) > 96 { + contract.Input = contract.Input[96:] } else { - input = input[:0] + contract.Input = contract.Input[:0] } // Handle a special case when both the base and mod length is zero if baseLen == 0 && modLen == 0 { @@ -423,9 +563,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { } // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(getData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(getData(contract.Input, 0, baseLen)) + exp = new(big.Int).SetBytes(getData(contract.Input, baseLen, expLen)) + mod = new(big.Int).SetBytes(getData(contract.Input, baseLen+expLen, modLen)) v []byte ) switch { @@ -486,21 +626,33 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256AddGasIstanbul } -func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) { - return runBn256Add(input) +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256AddIstanbul) Address() common.Address { + return common.BytesToAddress([]byte{6}) +} + +func (c *bn256AddIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256Add(contract.Input) } // bn256AddByzantium implements a native elliptic curve point addition // conforming to Byzantium consensus rules. type bn256AddByzantium struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256AddByzantium) Address() common.Address { + return common.BytesToAddress([]byte{6}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 { return params.Bn256AddGasByzantium } -func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) { - return runBn256Add(input) +func (c *bn256AddByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256Add(contract.Input) } // runBn256ScalarMul implements the Bn256ScalarMul precompile, referenced by @@ -519,26 +671,38 @@ func runBn256ScalarMul(input []byte) ([]byte, error) { // multiplication conforming to Istanbul consensus rules. type bn256ScalarMulIstanbul struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256ScalarMulIstanbul) Address() common.Address { + return common.BytesToAddress([]byte{7}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasIstanbul } -func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) { - return runBn256ScalarMul(input) +func (c *bn256ScalarMulIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256ScalarMul(contract.Input) } // bn256ScalarMulByzantium implements a native elliptic curve scalar // multiplication conforming to Byzantium consensus rules. type bn256ScalarMulByzantium struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256ScalarMulByzantium) Address() common.Address { + return common.BytesToAddress([]byte{7}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 { return params.Bn256ScalarMulGasByzantium } -func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) { - return runBn256ScalarMul(input) +func (c *bn256ScalarMulByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256ScalarMul(contract.Input) } var ( @@ -587,30 +751,48 @@ func runBn256Pairing(input []byte) ([]byte, error) { // conforming to Istanbul consensus rules. type bn256PairingIstanbul struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256PairingIstanbul) Address() common.Address { + return common.BytesToAddress([]byte{8}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul } -func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) { - return runBn256Pairing(input) +func (c *bn256PairingIstanbul) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256Pairing(contract.Input) } // bn256PairingByzantium implements a pairing pre-compile for the bn256 curve // conforming to Byzantium consensus rules. type bn256PairingByzantium struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bn256PairingByzantium) Address() common.Address { + return common.BytesToAddress([]byte{8}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 { return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium } -func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) { - return runBn256Pairing(input) +func (c *bn256PairingByzantium) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + return runBn256Pairing(contract.Input) } type blake2F struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (blake2F) Address() common.Address { + return common.BytesToAddress([]byte{9}) +} + func (c *blake2F) RequiredGas(input []byte) uint64 { // If the input is malformed, we can't calculate the gas, return 0 and let the // actual call choke and fault. @@ -631,18 +813,18 @@ var ( errBlake2FInvalidFinalFlag = errors.New("invalid final flag") ) -func (c *blake2F) Run(input []byte) ([]byte, error) { +func (c *blake2F) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { // Make sure the input is valid (correct length and final flag) - if len(input) != blake2FInputLength { + if len(contract.Input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength } - if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes { + if contract.Input[212] != blake2FNonFinalBlockBytes && contract.Input[212] != blake2FFinalBlockBytes { return nil, errBlake2FInvalidFinalFlag } // Parse the input into the Blake2b call parameters var ( - rounds = binary.BigEndian.Uint32(input[0:4]) - final = input[212] == blake2FFinalBlockBytes + rounds = binary.BigEndian.Uint32(contract.Input[0:4]) + final = contract.Input[212] == blake2FFinalBlockBytes h [8]uint64 m [16]uint64 @@ -650,14 +832,14 @@ func (c *blake2F) Run(input []byte) ([]byte, error) { ) for i := 0; i < 8; i++ { offset := 4 + i*8 - h[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + h[i] = binary.LittleEndian.Uint64(contract.Input[offset : offset+8]) } for i := 0; i < 16; i++ { offset := 68 + i*8 - m[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + m[i] = binary.LittleEndian.Uint64(contract.Input[offset : offset+8]) } - t[0] = binary.LittleEndian.Uint64(input[196:204]) - t[1] = binary.LittleEndian.Uint64(input[204:212]) + t[0] = binary.LittleEndian.Uint64(contract.Input[196:204]) + t[1] = binary.LittleEndian.Uint64(contract.Input[204:212]) // Execute the compression function, extract and return the result blake2b.F(&h, m, t, final, rounds) @@ -680,27 +862,33 @@ var ( // bls12381G1Add implements EIP-2537 G1Add precompile. type bls12381G1Add struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G1Add) Address() common.Address { + return common.BytesToAddress([]byte{10}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1Add) RequiredGas(input []byte) uint64 { return params.Bls12381G1AddGas } -func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Add) Run(evm *EVM, contract *Contract, readonly bool) ([]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). - if len(input) != 256 { + if len(contract.Input) != 256 { return nil, errBLS12381InvalidInputLength } var err error var p0, p1 *bls12381.G1Affine // Decode G1 point p_0 - if p0, err = decodePointG1(input[:128]); err != nil { + if p0, err = decodePointG1(contract.Input[:128]); err != nil { return nil, err } // Decode G1 point p_1 - if p1, err = decodePointG1(input[128:]); err != nil { + if p1, err = decodePointG1(contract.Input[128:]); err != nil { return nil, err } @@ -716,23 +904,29 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) { // bls12381G1Mul implements EIP-2537 G1Mul precompile. type bls12381G1Mul struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G1Mul) Address() common.Address { + return common.BytesToAddress([]byte{11}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G1MulGas } -func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G1Mul) Run(evm *EVM, contract *Contract, readonly bool) ([]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). - if len(input) != 160 { + if len(contract.Input) != 160 { return nil, errBLS12381InvalidInputLength } var err error var p0 *bls12381.G1Affine // Decode G1 point - if p0, err = decodePointG1(input[:128]); err != nil { + if p0, err = decodePointG1(contract.Input[:128]); err != nil { return nil, err } // 'point is on curve' check already done, @@ -741,7 +935,7 @@ func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { return nil, errBLS12381G1PointSubgroup } // Decode scalar value - e := new(big.Int).SetBytes(input[128:]) + e := new(big.Int).SetBytes(contract.Input[128:]) // Compute r = e * p_0 r := new(bls12381.G1Affine) @@ -754,6 +948,12 @@ func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) { // bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile. type bls12381G1MultiExp struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G1MultiExp) Address() common.Address { + return common.BytesToAddress([]byte{12}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 { // Calculate G1 point, scalar value pair length @@ -773,12 +973,12 @@ 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, contract *Contract, readonly bool) ([]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). - k := len(input) / 160 - if len(input) == 0 || len(input)%160 != 0 { + k := len(contract.Input) / 160 + if len(contract.Input) == 0 || len(contract.Input)%160 != 0 { return nil, errBLS12381InvalidInputLength } points := make([]bls12381.G1Affine, k) @@ -789,7 +989,7 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { off := 160 * i t0, t1, t2 := off, off+128, off+160 // Decode G1 point - p, err := decodePointG1(input[t0:t1]) + p, err := decodePointG1(contract.Input[t0:t1]) if err != nil { return nil, err } @@ -800,7 +1000,7 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { } points[i] = *p // Decode scalar value - scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) + scalars[i] = *new(fr.Element).SetBytes(contract.Input[t1:t2]) } // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1) @@ -814,27 +1014,33 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) { // bls12381G2Add implements EIP-2537 G2Add precompile. type bls12381G2Add struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G2Add) Address() common.Address { + return common.BytesToAddress([]byte{13}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2Add) RequiredGas(input []byte) uint64 { return params.Bls12381G2AddGas } -func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Add) Run(evm *EVM, contract *Contract, readonly bool) ([]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). - if len(input) != 512 { + if len(contract.Input) != 512 { return nil, errBLS12381InvalidInputLength } var err error var p0, p1 *bls12381.G2Affine // Decode G2 point p_0 - if p0, err = decodePointG2(input[:256]); err != nil { + if p0, err = decodePointG2(contract.Input[:256]); err != nil { return nil, err } // Decode G2 point p_1 - if p1, err = decodePointG2(input[256:]); err != nil { + if p1, err = decodePointG2(contract.Input[256:]); err != nil { return nil, err } @@ -851,23 +1057,29 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) { // bls12381G2Mul implements EIP-2537 G2Mul precompile. type bls12381G2Mul struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G2Mul) Address() common.Address { + return common.BytesToAddress([]byte{14}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 { return params.Bls12381G2MulGas } -func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { +func (c *bls12381G2Mul) Run(evm *EVM, contract *Contract, readonly bool) ([]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). - if len(input) != 288 { + if len(contract.Input) != 288 { return nil, errBLS12381InvalidInputLength } var err error var p0 *bls12381.G2Affine // Decode G2 point - if p0, err = decodePointG2(input[:256]); err != nil { + if p0, err = decodePointG2(contract.Input[:256]); err != nil { return nil, err } // 'point is on curve' check already done, @@ -876,7 +1088,7 @@ func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { return nil, errBLS12381G2PointSubgroup } // Decode scalar value - e := new(big.Int).SetBytes(input[256:]) + e := new(big.Int).SetBytes(contract.Input[256:]) // Compute r = e * p_0 r := new(bls12381.G2Affine) @@ -889,6 +1101,12 @@ func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) { // bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile. type bls12381G2MultiExp struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381G2MultiExp) Address() common.Address { + return common.BytesToAddress([]byte{15}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 { // Calculate G2 point, scalar value pair length @@ -908,12 +1126,12 @@ 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, contract *Contract, readonly bool) ([]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). - k := len(input) / 288 - if len(input) == 0 || len(input)%288 != 0 { + k := len(contract.Input) / 288 + if len(contract.Input) == 0 || len(contract.Input)%288 != 0 { return nil, errBLS12381InvalidInputLength } points := make([]bls12381.G2Affine, k) @@ -924,7 +1142,7 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { off := 288 * i t0, t1, t2 := off, off+256, off+288 // Decode G2 point - p, err := decodePointG2(input[t0:t1]) + p, err := decodePointG2(contract.Input[t0:t1]) if err != nil { return nil, err } @@ -935,7 +1153,7 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { } points[i] = *p // Decode scalar value - scalars[i] = *new(fr.Element).SetBytes(input[t1:t2]) + scalars[i] = *new(fr.Element).SetBytes(contract.Input[t1:t2]) } // Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1) @@ -949,20 +1167,26 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) { // bls12381Pairing implements EIP-2537 Pairing precompile. type bls12381Pairing struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381Pairing) Address() common.Address { + return common.BytesToAddress([]byte{16}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. 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, contract *Contract, readonly bool) ([]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 // > - `256` bytes of G2 point encoding // > Output is a `32` bytes where last single byte is `0x01` if pairing result is equal to multiplicative identity in a pairing target field and `0x00` otherwise // > (which is equivalent of Big Endian encoding of Solidity values `uint256(1)` and `uin256(0)` respectively). - k := len(input) / 384 - if len(input) == 0 || len(input)%384 != 0 { + k := len(contract.Input) / 384 + if len(contract.Input) == 0 || len(contract.Input)%384 != 0 { return nil, errBLS12381InvalidInputLength } @@ -977,12 +1201,12 @@ func (c *bls12381Pairing) Run(input []byte) ([]byte, error) { t0, t1, t2 := off, off+128, off+384 // Decode G1 point - p1, err := decodePointG1(input[t0:t1]) + p1, err := decodePointG1(contract.Input[t0:t1]) if err != nil { return nil, err } // Decode G2 point - p2, err := decodePointG2(input[t1:t2]) + p2, err := decodePointG2(contract.Input[t1:t2]) if err != nil { return nil, err } @@ -1101,21 +1325,27 @@ func encodePointG2(p *bls12381.G2Affine) []byte { // bls12381MapG1 implements EIP-2537 MapG1 precompile. type bls12381MapG1 struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381MapG1) Address() common.Address { + return common.BytesToAddress([]byte{17}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381MapG1) RequiredGas(input []byte) uint64 { return params.Bls12381MapG1Gas } -func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG1) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_To_G1 precompile. // > Field-to-curve call expects an `64` bytes input that is interpreted as an element of the base field. // > Output of this call is `128` bytes and is G1 point following respective encoding rules. - if len(input) != 64 { + if len(contract.Input) != 64 { return nil, errBLS12381InvalidInputLength } // Decode input field element - fe, err := decodeBLS12381FieldElement(input) + fe, err := decodeBLS12381FieldElement(contract.Input) if err != nil { return nil, err } @@ -1130,25 +1360,31 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) { // bls12381MapG2 implements EIP-2537 MapG2 precompile. type bls12381MapG2 struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (bls12381MapG2) Address() common.Address { + return common.BytesToAddress([]byte{18}) +} + // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bls12381MapG2) RequiredGas(input []byte) uint64 { return params.Bls12381MapG2Gas } -func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { +func (c *bls12381MapG2) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { // Implements EIP-2537 Map_FP2_TO_G2 precompile logic. // > Field-to-curve call expects an `128` bytes input that is interpreted as an element of the quadratic extension field. // > Output of this call is `256` bytes and is G2 point following respective encoding rules. - if len(input) != 128 { + if len(contract.Input) != 128 { return nil, errBLS12381InvalidInputLength } // Decode input field element - c0, err := decodeBLS12381FieldElement(input[:64]) + c0, err := decodeBLS12381FieldElement(contract.Input[:64]) if err != nil { return nil, err } - c1, err := decodeBLS12381FieldElement(input[64:]) + c1, err := decodeBLS12381FieldElement(contract.Input[64:]) if err != nil { return nil, err } @@ -1163,6 +1399,12 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // kzgPointEvaluation implements the EIP-4844 point evaluation precompile. type kzgPointEvaluation struct{} +// Address defines the precompiled contract address. This MUST match the address +// set in the precompiled contract map. +func (kzgPointEvaluation) Address() common.Address { + return common.BytesToAddress([]byte{4}) +} + // RequiredGas estimates the gas required for running the point evaluation precompile. func (b *kzgPointEvaluation) RequiredGas(input []byte) uint64 { return params.BlobTxPointEvaluationPrecompileGas @@ -1181,33 +1423,33 @@ var ( ) // Run executes the point evaluation precompile. -func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) { - if len(input) != blobVerifyInputLength { +func (b *kzgPointEvaluation) Run(evm *EVM, contract *Contract, readonly bool) ([]byte, error) { + if len(contract.Input) != blobVerifyInputLength { return nil, errBlobVerifyInvalidInputLength } // versioned hash: first 32 bytes var versionedHash common.Hash - copy(versionedHash[:], input[:]) + copy(versionedHash[:], contract.Input[:]) var ( point kzg4844.Point claim kzg4844.Claim ) // Evaluation point: next 32 bytes - copy(point[:], input[32:]) + copy(point[:], contract.Input[32:]) // Expected output: next 32 bytes - copy(claim[:], input[64:]) + copy(claim[:], contract.Input[64:]) // input kzg point: next 48 bytes var commitment kzg4844.Commitment - copy(commitment[:], input[96:]) + copy(commitment[:], contract.Input[96:]) if kZGToVersionedHash(commitment) != versionedHash { return nil, errBlobVerifyMismatchedVersion } // Proof: next 48 bytes var proof kzg4844.Proof - copy(proof[:], input[144:]) + copy(proof[:], contract.Input[144:]) if err := kzg4844.VerifyProof(commitment, point, claim, proof); err != nil { return nil, fmt.Errorf("%w: %v", errBlobVerifyKZGProof, err) diff --git a/core/vm/contracts_fuzz_test.go b/core/vm/contracts_fuzz_test.go index 1e5cc80074..82b4192193 100644 --- a/core/vm/contracts_fuzz_test.go +++ b/core/vm/contracts_fuzz_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" ) func FuzzPrecompiledContracts(f *testing.F) { @@ -36,7 +37,7 @@ func FuzzPrecompiledContracts(f *testing.F) { return } inWant := string(input) - RunPrecompiledContract(p, input, gas, nil) + runPrecompiledContract(nil, p, AccountRef(common.Address{}), input, gas, new(uint256.Int), false) if inHave := string(input); inWant != inHave { t.Errorf("Precompiled %v modified input data", a) } diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index fff5c966f3..458ca969f3 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -23,6 +23,7 @@ import ( "os" "testing" "time" + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" ) @@ -98,7 +99,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil { + if res, _, err := runPrecompiledContract(nil, p, AccountRef(common.Address{}), in, gas, new(uint256.Int), false); err != nil { t.Error(err) } else if common.Bytes2Hex(res) != test.Expected { t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res)) @@ -120,7 +121,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { gas := p.RequiredGas(in) - 1 t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas, nil) + _, _, err := runPrecompiledContract(nil, p, AccountRef(common.Address{}), in, gas, new(uint256.Int), false) if err.Error() != "out of gas" { t.Errorf("Expected error [out of gas], got [%v]", err) } @@ -137,7 +138,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing in := common.Hex2Bytes(test.Input) gas := p.RequiredGas(in) t.Run(test.Name, func(t *testing.T) { - _, _, err := RunPrecompiledContract(p, in, gas, nil) + _, _, err := runPrecompiledContract(nil, p, AccountRef(common.Address{}), in, gas, new(uint256.Int), false) if err.Error() != test.ExpectedError { t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err) } @@ -169,7 +170,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { bench.ResetTimer() for i := 0; i < bench.N; i++ { copy(data, in) - res, _, err = RunPrecompiledContract(p, data, reqGas, nil) + res, _, err = runPrecompiledContract(nil, p, AccountRef(common.Address{}), in, reqGas, new(uint256.Int), false) } bench.StopTimer() elapsed := uint64(time.Since(start)) diff --git a/core/vm/evm.go b/core/vm/evm.go index 1944189b5d..e53134ffd3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -40,28 +40,6 @@ type ( GetHashFunc func(uint64) common.Hash ) -func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { - var precompiles map[common.Address]PrecompiledContract - switch { - case evm.chainRules.IsVerkle: - precompiles = PrecompiledContractsVerkle - case evm.chainRules.IsPrague: - precompiles = PrecompiledContractsPrague - 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 { @@ -129,6 +107,10 @@ type EVM struct { // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. callGasTemp uint64 + // precompiles defines the precompiled contracts used by the EVM + precompiles map[common.Address]PrecompiledContract + // activePrecompiles defines the precompiles that are currently active + activePrecompiles []common.Address } // NewEVM returns a new EVM. The returned EVM is not thread safe and should @@ -153,6 +135,9 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainConfig: chainConfig, chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } + // set the default precompiles + evm.activePrecompiles = DefaultActivePrecompiles(evm.chainRules) + evm.precompiles = DefaultPrecompiles(evm.chainRules) evm.interpreter = NewEVMInterpreter(evm) return evm } @@ -204,7 +189,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.Precompile(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP4762 { @@ -225,8 +210,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) + // It is allowed to call precompiles, even via call -- as opposed to callcode, staticcall and delegatecall it can also modify state if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + ret, gas, err = evm.RunPrecompiledContract(p, caller, input, gas, value, false) } 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. @@ -293,9 +279,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, } var snapshot = evm.StateDB.Snapshot() - // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + // It is allowed to call precompiles, even via callcode, but only for reading + if p, isPrecompile := evm.Precompile(addr); isPrecompile { + ret, gas, err = evm.RunPrecompiledContract(p, caller, input, gas, value, true) } else { addrCopy := addr // Initialise a new contract and set the code that is to be used by the EVM. @@ -345,8 +331,8 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var snapshot = evm.StateDB.Snapshot() // It is allowed to call precompiles, even via delegatecall - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + if p, isPrecompile := evm.Precompile(addr); isPrecompile { + ret, gas, err = evm.RunPrecompiledContract(p, caller, input, gas, nil, true) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -399,8 +385,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // future scenarios evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount) - if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + if p, isPrecompile := evm.Precompile(addr); isPrecompile { + ret, gas, err = evm.RunPrecompiledContract(p, caller, input, gas, new(uint256.Int), true) } 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/core/vm/operations_verkle.go b/core/vm/operations_verkle.go index 73eb05974d..a06701e2e1 100644 --- a/core/vm/operations_verkle.go +++ b/core/vm/operations_verkle.go @@ -49,7 +49,7 @@ func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { address := stack.peek().Bytes20() - if _, isPrecompile := evm.precompile(address); isPrecompile { + if _, isPrecompile := evm.Precompile(address); isPrecompile { return 0, nil } gas := evm.AccessEvents.VersionGas(address, false) @@ -62,7 +62,7 @@ func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { address := stack.peek().Bytes20() - if _, isPrecompile := evm.precompile(address); isPrecompile { + if _, isPrecompile := evm.Precompile(address); isPrecompile { return 0, nil } gas := evm.AccessEvents.CodeHashGas(address, false) @@ -78,7 +78,7 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc) gasFunc { if err != nil { return 0, err } - if _, isPrecompile := evm.precompile(contract.Address()); isPrecompile { + if _, isPrecompile := evm.Precompile(contract.Address()); isPrecompile { return gas, nil } witnessGas := evm.AccessEvents.MessageCallGas(contract.Address()) @@ -98,7 +98,7 @@ var ( func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { beneficiaryAddr := common.Address(stack.peek().Bytes20()) - if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile { + if _, isPrecompile := evm.Precompile(beneficiaryAddr); isPrecompile { return 0, nil } contractAddr := contract.Address() diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 1181e5fccd..a4847dd25d 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -142,7 +142,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.DefaultActivePrecompiles(rules), nil) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) @@ -178,7 +178,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil) + cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.DefaultActivePrecompiles(rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( sender, @@ -209,7 +209,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er // Execute the preparatory steps for state transition which includes: // - prepare accessList(post-berlin) // - reset transient storage(eip 1153) - statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil) + statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.DefaultActivePrecompiles(rules), nil) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 5290d4f709..bdbccb18e9 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -245,7 +245,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.dbValue = db.setupObject() // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.DefaultActivePrecompiles(rules) t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) t.ctx["gas"] = t.vm.ToValue(tx.Gas()) gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index 6cb0e433d2..83970939c2 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -89,7 +89,7 @@ func (t *fourByteTracer) store(id []byte, size int) { func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.DefaultActivePrecompiles(rules) } // OnEnter is called when EVM enters a new scope (via call, create or selfdestruct). diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index a47b79f8df..164743d872 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -207,7 +207,7 @@ func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction t.tracer.OnTxStart(env, tx, from) // Update list of precompiles based on current block rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time) - t.activePrecompiles = vm.ActivePrecompiles(rules) + t.activePrecompiles = vm.DefaultActivePrecompiles(rules) } func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) { diff --git a/go.mod b/go.mod index 763210decd..ae6b12c0b8 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,6 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 - github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 diff --git a/go.sum b/go.sum index 562362dee6..4dadd40a75 100644 --- a/go.sum +++ b/go.sum @@ -339,7 +339,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c3cb4adf9..d9da5476bb 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1521,7 +1521,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } isPostMerge := header.Difficulty.Sign() == 0 // Retrieve the precompiles since they don't need to be added to the access list - precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) + precompiles := vm.DefaultActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)) // Create an initial tracer prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go index 4df4db73d1..e8480692b8 100644 --- a/tests/fuzzers/bls12381/precompile_fuzzer.go +++ b/tests/fuzzers/bls12381/precompile_fuzzer.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" ) const ( @@ -82,7 +83,9 @@ func fuzz(id byte, data []byte) int { } cpy := make([]byte, len(data)) copy(cpy, data) - _, err := precompile.Run(cpy) + contract := vm.NewPrecompile(vm.AccountRef(common.Address{}), precompile, new(uint256.Int).SetUint64(0), gas) + contract.Input = cpy + _, err := precompile.Run(nil, contract, false) if !bytes.Equal(cpy, data) { panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy)) } diff --git a/tests/state_test.go b/tests/state_test.go index 76fec97de0..5bf0536947 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -319,7 +319,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.ResetTimer() for n := 0; n < b.N; n++ { snapshot := state.StateDB.Snapshot() - state.StateDB.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) + state.StateDB.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.DefaultActivePrecompiles(rules), msg.AccessList) b.StartTimer() start := time.Now()