Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(precompile): Add EVM to Precompiles #16

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type PrecompiledContract interface {
// RequiredGas calculates the contract static gas use.
RequiredGas(input []byte) uint64
// Run runs the precompiled contract with the given context.
Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error)
Run(ctx context.Context, evm PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error)
}

// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
Expand Down Expand Up @@ -156,7 +156,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas
}

func (c *ecrecover) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *ecrecover) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
const ecRecoverInputLength = 128

input = common.RightPadBytes(input, ecRecoverInputLength)
Expand Down Expand Up @@ -201,7 +201,7 @@ func (c *sha256hash) RegistryKey() common.Address {
func (c *sha256hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
}
func (c *sha256hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *sha256hash) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
h := sha256.Sum256(input)
return h[:], nil
}
Expand All @@ -220,7 +220,7 @@ func (c *ripemd160hash) RegistryKey() common.Address {
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
}
func (c *ripemd160hash) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *ripemd160hash) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
ripemd := ripemd160.New()
ripemd.Write(input)
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
Expand All @@ -240,7 +240,7 @@ func (c *dataCopy) RegistryKey() common.Address {
func (c *dataCopy) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
}
func (c *dataCopy) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *dataCopy) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return input, nil
}

Expand Down Expand Up @@ -371,7 +371,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
return gas.Uint64()
}

func (c *bigModExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bigModExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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()
Expand Down Expand Up @@ -455,7 +455,7 @@ func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasIstanbul
}

func (c *bn256AddIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256AddIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Add(input)
}

Expand All @@ -472,7 +472,7 @@ func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasByzantium
}

func (c *bn256AddByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256AddByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Add(input)
}

Expand Down Expand Up @@ -501,7 +501,7 @@ func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasIstanbul
}

func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256ScalarMul(input)
}

Expand All @@ -518,7 +518,7 @@ func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasByzantium
}

func (c *bn256ScalarMulByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256ScalarMulByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256ScalarMul(input)
}

Expand Down Expand Up @@ -577,7 +577,7 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
}

func (c *bn256PairingIstanbul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256PairingIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Pairing(input)
}

Expand All @@ -594,7 +594,7 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium
}

func (c *bn256PairingByzantium) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bn256PairingByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Pairing(input)
}

Expand Down Expand Up @@ -624,7 +624,7 @@ var (
errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
)

func (c *blake2F) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *blake2F) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Make sure the input is valid (correct length and final flag)
if len(input) != blake2FInputLength {
return nil, errBlake2FInvalidInputLength
Expand Down Expand Up @@ -682,7 +682,7 @@ func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G1AddGas
}

func (c *bls12381G1Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G1Add) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -724,7 +724,7 @@ func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G1MulGas
}

func (c *bls12381G1Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G1Mul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -778,7 +778,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
}

func (c *bls12381G1MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G1MultiExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -825,7 +825,7 @@ func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G2AddGas
}

func (c *bls12381G2Add) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G2Add) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -867,7 +867,7 @@ func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G2MulGas
}

func (c *bls12381G2Mul) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G2Mul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -921,7 +921,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
}

func (c *bls12381G2MultiExp) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381G2MultiExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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).
Expand Down Expand Up @@ -968,7 +968,7 @@ func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
}

func (c *bls12381Pairing) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381Pairing) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, 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
Expand Down Expand Up @@ -1051,7 +1051,7 @@ func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG1Gas
}

func (c *bls12381MapG1) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381MapG1) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]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.
Expand Down Expand Up @@ -1090,7 +1090,7 @@ func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG2Gas
}

func (c *bls12381MapG2) Run(ctx context.Context, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
func (c *bls12381MapG2) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]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.
Expand Down
2 changes: 1 addition & 1 deletion core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin
return nil, 0, ErrOutOfGas
}
suppliedGas -= gasCost
output, err := p.Run(context.Background(), input, common.Address{}, new(big.Int), true)
output, err := p.Run(context.Background(), nil, input, common.Address{}, new(big.Int), true)
return output, suppliedGas, err
}

Expand Down
27 changes: 8 additions & 19 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,6 @@ type (
GetHashFunc func(uint64) common.Hash
)

// `PrecompileManager` allows the EVM to execute a precompiled contract.
type PrecompileManager interface {
// `Has` returns if a precompiled contract was found at `addr`.
Has(addr common.Address) bool

// `Get` returns the precompiled contract at `addr`. Returns nil if no
// contract is found at `addr`.
Get(addr common.Address) PrecompiledContract

// `Run` runs a precompiled contract and returns the remaining gas.
Run(sdb StateDB, p PrecompiledContract, input []byte, caller common.Address,
value *big.Int, suppliedGas uint64, readonly bool,
) (ret []byte, remainingGas uint64, err error)
}

// BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified.
type BlockContext struct {
Expand Down Expand Up @@ -171,6 +156,10 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}

func (evm *EVM) GetStateDB() StateDB {
return evm.StateDB
}

// 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
Expand Down Expand Up @@ -223,7 +212,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas

if isPrecompile {
ret, gas, err = evm.PrecompileManager.Run(
evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false,
evm, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false,
)
} else {
// Initialise a new contract and set the code that is to be used by the EVM.
Expand Down Expand Up @@ -288,7 +277,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// It is allowed to call precompiles, even via delegatecall
if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
ret, gas, err = evm.PrecompileManager.Run(
evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true,
evm, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, true,
)
} else {
addrCopy := addr
Expand Down Expand Up @@ -336,7 +325,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
parent := caller.(*Contract)
ret, gas, err = evm.PrecompileManager.Run(
evm.StateDB, evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false,
evm, evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false,
)
} else {
addrCopy := addr
Expand Down Expand Up @@ -387,7 +376,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte

if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
ret, gas, err = evm.PrecompileManager.Run(
evm.StateDB, evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true,
evm, evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true,
)
} else {
// At this point, we use a copy of address. If we don't, the go compiler will
Expand Down
28 changes: 28 additions & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/holiman/uint256"
)

// StateDB is an EVM database for full state querying.
Expand All @@ -38,3 +39,30 @@ type CallContext interface {
// Create creates a new contract
Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)
}

type (
// PrecompileManager allows the EVM to execute a precompiled contract.
PrecompileManager interface {
// `Has` returns if a precompiled contract was found at `addr`.
Has(addr common.Address) bool

// `Get` returns the precompiled contract at `addr`. Returns nil if no
// contract is found at `addr`.
Get(addr common.Address) PrecompiledContract

// `Run` runs a precompiled contract and returns the remaining gas.
Run(evm PrecompileEVM, p PrecompiledContract, input []byte, caller common.Address,
value *big.Int, suppliedGas uint64, readonly bool,
) (ret []byte, remainingGas uint64, err error)
}

// PrecompileEVM is the interface through which stateful precompiles can call back into the EVM.
PrecompileEVM interface {
GetStateDB() StateDB

Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
}
)
4 changes: 2 additions & 2 deletions core/vm/precompile_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (pm *precompileManager) Get(addr common.Address) PrecompiledContract {

// Run runs the given precompiled contract with the given input data and returns the remaining gas.
func (pm *precompileManager) Run(
_ StateDB, p PrecompiledContract, input []byte,
evm PrecompileEVM, p PrecompiledContract, input []byte,
caller common.Address, value *big.Int, suppliedGas uint64, readonly bool,
) (ret []byte, remainingGas uint64, err error) {
gasCost := p.RequiredGas(input)
Expand All @@ -65,7 +65,7 @@ func (pm *precompileManager) Run(
}

suppliedGas -= gasCost
output, err := p.Run(context.Background(), input, caller, value, readonly)
output, err := p.Run(context.Background(), evm, input, caller, value, readonly)

return output, suppliedGas, err
}
Expand Down