Skip to content

Commit

Permalink
Merge pull request #21 from sei-protocol/precompile-readonly-flag
Browse files Browse the repository at this point in the history
Pass ReadOnly flag to precompiles
  • Loading branch information
codchen authored Apr 9, 2024
2 parents 6ab0d19 + 9205987 commit babe11a
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 38 deletions.
56 changes: 28 additions & 28 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ 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(evm *EVM, sender common.Address, input []byte, value *big.Int) ([]byte, error) // Run runs the precompiled contract
RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
Run(evm *EVM, sender common.Address, input []byte, value *big.Int, readOnly bool) ([]byte, error) // Run runs the precompiled contract
}

type DynamicGasPrecompiledContract interface {
RunAndCalculateGas(evm *EVM, sender common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) // Run runs the precompiled contract and calculate gas dynamically
RunAndCalculateGas(evm *EVM, sender common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) // Run runs the precompiled contract and calculate gas dynamically
}

// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
Expand Down Expand Up @@ -173,9 +173,9 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
// - the returned bytes,
// - the _remaining_ gas,
// - any error that occurred
func RunPrecompiledContract(p PrecompiledContract, evm *EVM, sender common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
func RunPrecompiledContract(p PrecompiledContract, evm *EVM, sender common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) {
if dp, ok := p.(DynamicGasPrecompiledContract); ok {
return dp.RunAndCalculateGas(evm, sender, callingContract, input, suppliedGas, value, logger)
return dp.RunAndCalculateGas(evm, sender, callingContract, input, suppliedGas, value, logger, readOnly)
}
gasCost := p.RequiredGas(input)
if suppliedGas < gasCost {
Expand All @@ -185,7 +185,7 @@ func RunPrecompiledContract(p PrecompiledContract, evm *EVM, sender common.Addre
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
}
suppliedGas -= gasCost
output, err := p.Run(evm, sender, input, value)
output, err := p.Run(evm, sender, input, value, readOnly)
return output, suppliedGas, err
}

Expand All @@ -196,7 +196,7 @@ func (c *Ecrecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas
}

func (c *Ecrecover) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Ecrecover) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
const ecRecoverInputLength = 128

input = common.RightPadBytes(input, ecRecoverInputLength)
Expand Down Expand Up @@ -237,7 +237,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(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Sha256hash) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
h := sha256.Sum256(input)
return h[:], nil
}
Expand All @@ -252,7 +252,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(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Ripemd160hash) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
ripemd := ripemd160.New()
ripemd.Write(input)
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
Expand All @@ -268,7 +268,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(_ *EVM, _ common.Address, in []byte, _ *big.Int) ([]byte, error) {
func (c *DataCopy) Run(_ *EVM, _ common.Address, in []byte, _ *big.Int, _ bool) ([]byte, error) {
return common.CopyBytes(in), nil
}

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

func (c *BigModExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *BigModExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -474,7 +474,7 @@ func (c *Bn256AddIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasIstanbul
}

func (c *Bn256AddIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bn256AddIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256Add(input)
}

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

func (c *bn256AddByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *bn256AddByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256Add(input)
}

Expand All @@ -512,7 +512,7 @@ func (c *Bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasIstanbul
}

func (c *Bn256ScalarMulIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bn256ScalarMulIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256ScalarMul(input)
}

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

func (c *bn256ScalarMulByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *bn256ScalarMulByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256ScalarMul(input)
}

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

func (c *Bn256PairingIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bn256PairingIstanbul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256Pairing(input)
}

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

func (c *bn256PairingByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *bn256PairingByzantium) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
return runBn256Pairing(input)
}

Expand All @@ -619,7 +619,7 @@ var (
ErrBlake2FInvalidFinalFlag = errors.New("invalid final flag")
)

func (c *Blake2F) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Blake2F) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -673,7 +673,7 @@ func (c *Bls12381G1Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G1AddGas
}

func (c *Bls12381G1Add) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G1Add) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -711,7 +711,7 @@ func (c *Bls12381G1Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G1MulGas
}

func (c *Bls12381G1Mul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G1Mul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -761,7 +761,7 @@ func (c *Bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
}

func (c *Bls12381G1MultiExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G1MultiExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -804,7 +804,7 @@ func (c *Bls12381G2Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G2AddGas
}

func (c *Bls12381G2Add) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G2Add) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -842,7 +842,7 @@ func (c *Bls12381G2Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G2MulGas
}

func (c *Bls12381G2Mul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G2Mul) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -892,7 +892,7 @@ func (c *Bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
}

func (c *Bls12381G2MultiExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381G2MultiExp) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -935,7 +935,7 @@ func (c *Bls12381Pairing) RequiredGas(input []byte) uint64 {
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
}

func (c *Bls12381Pairing) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381Pairing) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -1014,7 +1014,7 @@ func (c *Bls12381MapG1) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG1Gas
}

func (c *Bls12381MapG1) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381MapG1) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 @@ -1049,7 +1049,7 @@ func (c *Bls12381MapG2) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG2Gas
}

func (c *Bls12381MapG2) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (c *Bls12381MapG2) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ 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 Expand Up @@ -1104,7 +1104,7 @@ var (
)

// Run executes the point evaluation precompile.
func (b *KzgPointEvaluation) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int) ([]byte, error) {
func (b *KzgPointEvaluation) Run(_ *EVM, _ common.Address, input []byte, _ *big.Int, _ bool) ([]byte, error) {
if len(input) != blobVerifyInputLength {
return nil, errBlobVerifyInvalidInputLength
}
Expand Down
2 changes: 1 addition & 1 deletion core/vm/contracts_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func FuzzPrecompiledContracts(f *testing.F) {
return
}
inWant := string(input)
vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, input, gas, nil, nil)
vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, input, gas, nil, nil, false)
if inHave := string(input); inWant != inHave {
t.Errorf("Precompiled %v modified input data", a)
}
Expand Down
8 changes: 4 additions & 4 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,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 := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil); err != nil {
if res, _, err := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil, false); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.Expected {
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
Expand All @@ -121,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 := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil)
_, _, err := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil, false)
if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err)
}
Expand All @@ -138,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 := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil)
_, _, err := vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, in, gas, nil, nil, false)
if err.Error() != test.ExpectedError {
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
}
Expand Down Expand Up @@ -170,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 = vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, data, reqGas, nil, nil)
res, _, err = vm.RunPrecompiledContract(p, nil, common.Address{}, common.Address{}, data, reqGas, nil, nil, false)
}
bench.StopTimer()
elapsed := uint64(time.Since(start))
Expand Down
8 changes: 4 additions & 4 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)

if isPrecompile {
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, value, evm.Config.Tracer)
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, value, evm.Config.Tracer, 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.
Expand Down Expand Up @@ -281,7 +281,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,

// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, value, evm.Config.Tracer)
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, value, evm.Config.Tracer, false)
} else {
addrCopy := addr
// Initialise a new contract and set the code that is to be used by the EVM.
Expand Down Expand Up @@ -332,7 +332,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// NOTE: caller must, at all times be a contract. It should never happen
// that caller is something other than a Contract.
parent := caller.(*Contract)
ret, gas, err = RunPrecompiledContract(p, evm, parent.CallerAddress, caller.Address(), input, gas, nil, evm.Config.Tracer)
ret, gas, err = RunPrecompiledContract(p, evm, parent.CallerAddress, caller.Address(), input, gas, nil, evm.Config.Tracer, false)
} else {
addrCopy := addr
// Initialise a new contract and make initialise the delegate values
Expand Down Expand Up @@ -383,7 +383,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
evm.StateDB.AddBalance(addr, new(big.Int), tracing.BalanceChangeTouchAccount)

if p, isPrecompile := evm.precompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, nil, evm.Config.Tracer)
ret, gas, err = RunPrecompiledContract(p, evm, caller.Address(), caller.Address(), input, gas, nil, evm.Config.Tracer, 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'
Expand Down
2 changes: 1 addition & 1 deletion tests/fuzzers/bls12381/precompile_fuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func fuzz(id byte, data []byte) int {
}
cpy := make([]byte, len(data))
copy(cpy, data)
_, err := precompile.Run(nil, common.Address{}, cpy, nil)
_, err := precompile.Run(nil, common.Address{}, cpy, nil, false)
if !bytes.Equal(cpy, data) {
panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy))
}
Expand Down

0 comments on commit babe11a

Please sign in to comment.