diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index db48851ef50c..3287a7c9c328 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -30,6 +30,13 @@ jobs:
EXCLUDE_REGEX: 'ava-labs/libevm/(accounts/usbwallet/trezor)$'
runs-on: ubuntu-latest
steps:
+ - name: Install solc
+ run: |
+ sudo add-apt-repository ppa:ethereum/ethereum
+ sudo apt update
+ sudo apt list -a solc
+ sudo apt install solc=1:0.8.28-0ubuntu1~noble
+
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
diff --git a/accounts/abi/selector.libevm.go b/accounts/abi/selector.libevm.go
new file mode 100644
index 000000000000..e7b0ddfd03b6
--- /dev/null
+++ b/accounts/abi/selector.libevm.go
@@ -0,0 +1,75 @@
+// Copyright 2024 the libevm authors.
+//
+// The libevm additions to go-ethereum are free software: you can redistribute
+// them and/or modify them under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The libevm additions are distributed in the hope that they will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see
+// .
+
+package abi
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// SelectorByteLen is the number of bytes in an ABI function selector.
+const SelectorByteLen = 4
+
+// A Selector is an ABI function selector. It is a uint32 instead of a [4]byte
+// to allow for simpler hex literals.
+type Selector uint32
+
+// String returns a hex encoding of `s`.
+func (s Selector) String() string {
+ b := make([]byte, 4)
+ binary.BigEndian.PutUint32(b, uint32(s))
+ return fmt.Sprintf("%#x", b)
+}
+
+// ExtractSelector returns the first 4 bytes of the slice as a Selector. It
+// assumes that its input is of sufficient length.
+func ExtractSelector(data []byte) Selector {
+ return Selector(binary.BigEndian.Uint32(data[:4]))
+}
+
+// Selector returns the Method's ID as a Selector.
+func (m Method) Selector() Selector {
+ return ExtractSelector(m.ID)
+}
+
+// MethodsBySelector maps 4-byte ABI selectors to the corresponding method
+// representation. The key MUST be equivalent to the value's [Method.Selector].
+type MethodsBySelector map[Selector]Method
+
+// MethodsBySelector returns the [Method]s keyed by their Selectors.
+func (a *ABI) MethodsBySelector() MethodsBySelector {
+ ms := make(MethodsBySelector)
+ for _, m := range a.Methods {
+ ms[m.Selector()] = m
+ }
+ return ms
+}
+
+// FindSelector extracts the Selector from `data` and, if it exists in `m`,
+// returns it. The returned boolean functions as for regular map lookups. Unlike
+// [ExtractSelector], FindSelector confirms that `data` has at least 4 bytes,
+// treating invalid inputs as not found.
+func (m MethodsBySelector) FindSelector(data []byte) (Selector, bool) {
+ if len(data) < SelectorByteLen {
+ return 0, false
+ }
+ sel := ExtractSelector(data)
+ if _, ok := m[sel]; !ok {
+ return 0, false
+ }
+ return sel, true
+}
diff --git a/core/vm/contracts.libevm.go b/core/vm/contracts.libevm.go
index 66e3c91783a0..183c86ca2ce1 100644
--- a/core/vm/contracts.libevm.go
+++ b/core/vm/contracts.libevm.go
@@ -57,10 +57,10 @@ type evmCallArgs struct {
type CallType OpCode
const (
- Call = CallType(CALL)
- CallCode = CallType(CALLCODE)
- DelegateCall = CallType(DELEGATECALL)
- StaticCall = CallType(STATICCALL)
+ Call CallType = CallType(CALL)
+ CallCode CallType = CallType(CALLCODE)
+ DelegateCall CallType = CallType(DELEGATECALL)
+ StaticCall CallType = CallType(STATICCALL)
)
func (t CallType) isValid() bool {
@@ -88,6 +88,32 @@ func (t CallType) OpCode() OpCode {
return INVALID
}
+// StateMutability describes the available state access.
+type StateMutability uint
+
+const (
+ // Pure is a Solidity concept disallowing all access, read or write, to
+ // state.
+ Pure StateMutability = iota + 1
+ // ReadOnlyState is equivalent to Solidity's "view".
+ ReadOnlyState
+ // MutableState can be both read from and written to.
+ MutableState
+)
+
+// String returns a human-readable representation of the StateMutability.
+func (m StateMutability) String() string {
+ switch m {
+ case MutableState:
+ return "mutable"
+ case ReadOnlyState:
+ return "read-only"
+ case Pure:
+ return "no state access"
+ }
+ return fmt.Sprintf("unknown %T(%[1]d)", m)
+}
+
// run runs the [PrecompiledContract], differentiating between stateful and
// regular types, updating `args.gasRemaining` in the stateful case.
func (args *evmCallArgs) run(p PrecompiledContract, input []byte) (ret []byte, err error) {
@@ -96,7 +122,7 @@ func (args *evmCallArgs) run(p PrecompiledContract, input []byte) (ret []byte, e
return p.Run(input)
case statefulPrecompile:
env := args.env()
- ret, err := p(env, input)
+ ret, err := p(env, common.CopyBytes(input))
args.gasRemaining = env.Gas()
return ret, err
}
@@ -141,14 +167,28 @@ func (p statefulPrecompile) Run([]byte) ([]byte, error) {
type PrecompileEnvironment interface {
ChainConfig() *params.ChainConfig
Rules() params.Rules
- // StateDB will be non-nil i.f.f !ReadOnly().
+ // StateDB will be non-nil i.f.f StateMutability() returns [MutableState].
StateDB() StateDB
- // ReadOnlyState will always be non-nil.
+ // ReadOnlyState will be non-nil i.f.f. StateMutability() does not return
+ // [Pure].
ReadOnlyState() libevm.StateReader
+ // StateMutability can infer [MutableState] vs [ReadOnlyState] based on EVM
+ // context, but [Pure] is a Solidity concept that is enforced by user code.
+ StateMutability() StateMutability
+ // AsReadOnly returns a copy of the current environment for which
+ // StateMutability() is at most [ReadOnlyState]; i.e. if mutability is
+ // already limited to [Pure], AsReadOnly() will not expand access. It can be
+ // used as a guard against accidental writes when a read-only function is
+ // invoked with EVM call() instead of staticcall().
+ AsReadOnly() PrecompileEnvironment
+ // AsPure returns a copy of the current environment that has no access to
+ // state; i.e. StateMutability() returns [Pure]. All calls to both StateDB()
+ // and ReadOnlyState() will return nil.
+ AsPure() PrecompileEnvironment
+
IncomingCallType() CallType
Addresses() *libevm.AddressContext
- ReadOnly() bool
// Equivalent to respective methods on [Contract].
Gas() uint64
UseGas(uint64) (hasEnoughGas bool)
@@ -210,3 +250,21 @@ var (
(*EVM)(nil).StaticCall,
}
)
+
+// A RevertError is an error that couples [ErrExecutionReverted] with the EVM
+// return buffer. Although not used in vanilla geth, it can be returned by a
+// libevm `precompilegen` method implementation to circumvent regular argument
+// packing.
+type RevertError []byte
+
+// Error is equivalent to the respective method on [ErrExecutionReverted].
+func (e RevertError) Error() string { return ErrExecutionReverted.Error() }
+
+// Bytes returns the return buffer with which an EVM context reverted.
+func (e RevertError) Bytes() []byte { return []byte(e) }
+
+// Is returns true if `err` is directly == to `e` or if `err` is
+// [ErrExecutionReverted].
+func (e RevertError) Is(err error) bool {
+ return error(e) == err || err == ErrExecutionReverted
+}
diff --git a/core/vm/contracts.libevm_test.go b/core/vm/contracts.libevm_test.go
index 1bb98fac2fa0..a547c149f030 100644
--- a/core/vm/contracts.libevm_test.go
+++ b/core/vm/contracts.libevm_test.go
@@ -108,7 +108,7 @@ type statefulPrecompileOutput struct {
Addresses *libevm.AddressContext
StateValue common.Hash
ValueReceived *uint256.Int
- ReadOnly bool
+ Mutability vm.StateMutability
BlockNumber, Difficulty *big.Int
BlockTime uint64
Input []byte
@@ -149,9 +149,6 @@ func TestNewStatefulPrecompile(t *testing.T) {
gasCost := rng.Uint64n(gasLimit)
run := func(env vm.PrecompileEnvironment, input []byte, suppliedGas uint64) ([]byte, uint64, error) {
- if got, want := env.StateDB() != nil, !env.ReadOnly(); got != want {
- return nil, 0, fmt.Errorf("PrecompileEnvironment().StateDB() must be non-nil i.f.f. not read-only; got non-nil? %t; want %t", got, want)
- }
hdr, err := env.BlockHeader()
if err != nil {
return nil, 0, err
@@ -162,7 +159,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Addresses: env.Addresses(),
StateValue: env.ReadOnlyState().GetState(precompile, slot),
ValueReceived: env.Value(),
- ReadOnly: env.ReadOnly(),
+ Mutability: env.StateMutability(),
BlockNumber: env.BlockNumber(),
BlockTime: env.BlockTime(),
Difficulty: hdr.Difficulty,
@@ -216,8 +213,8 @@ func TestNewStatefulPrecompile(t *testing.T) {
wantTransferValue *uint256.Int
// Note that this only covers evm.readOnly being true because of the
// precompile's call. See TestInheritReadOnly for alternate case.
- wantReadOnly bool
- wantCallType vm.CallType
+ wantMutability vm.StateMutability
+ wantCallType vm.CallType
}{
{
name: "EVM.Call()",
@@ -229,7 +226,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Caller: caller,
Self: precompile,
},
- wantReadOnly: false,
+ wantMutability: vm.MutableState,
wantTransferValue: transferValue,
wantCallType: vm.Call,
},
@@ -243,7 +240,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Caller: caller,
Self: caller,
},
- wantReadOnly: false,
+ wantMutability: vm.MutableState,
wantTransferValue: transferValue,
wantCallType: vm.CallCode,
},
@@ -257,7 +254,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Caller: eoa, // inherited from caller
Self: caller,
},
- wantReadOnly: false,
+ wantMutability: vm.MutableState,
wantTransferValue: uint256.NewInt(0),
wantCallType: vm.DelegateCall,
},
@@ -271,7 +268,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Caller: caller,
Self: precompile,
},
- wantReadOnly: true,
+ wantMutability: vm.ReadOnlyState,
wantTransferValue: uint256.NewInt(0),
wantCallType: vm.StaticCall,
},
@@ -284,7 +281,7 @@ func TestNewStatefulPrecompile(t *testing.T) {
Addresses: tt.wantAddresses,
StateValue: stateValue,
ValueReceived: tt.wantTransferValue,
- ReadOnly: tt.wantReadOnly,
+ Mutability: tt.wantMutability,
BlockNumber: header.Number,
BlockTime: header.Time,
Difficulty: header.Difficulty,
@@ -334,7 +331,7 @@ func TestInheritReadOnly(t *testing.T) {
PrecompileOverrides: map[common.Address]libevm.PrecompiledContract{
precompile: vm.NewStatefulPrecompile(
func(env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
- if env.ReadOnly() {
+ if env.StateMutability() != vm.MutableState {
return []byte{ifReadOnly}, nil
}
return []byte{ifNotReadOnly}, nil
@@ -560,9 +557,9 @@ func TestPrecompileMakeCall(t *testing.T) {
}),
dest: vm.NewStatefulPrecompile(func(env vm.PrecompileEnvironment, input []byte) (ret []byte, err error) {
out := &statefulPrecompileOutput{
- Addresses: env.Addresses(),
- ReadOnly: env.ReadOnly(),
- Input: input, // expected to be callData
+ Addresses: env.Addresses(),
+ Mutability: env.StateMutability(),
+ Input: input, // expected to be callData
}
return out.Bytes(), nil
}),
@@ -591,7 +588,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: sut,
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -603,7 +601,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // overridden by CallOption
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -614,7 +613,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // SUT runs as its own caller because of CALLCODE
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -626,7 +626,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // CallOption is a NOOP
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -637,7 +638,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // as with CALLCODE
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -649,7 +651,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // CallOption is a NOOP
Self: dest,
},
- Input: precompileCallData,
+ Input: precompileCallData,
+ Mutability: vm.MutableState,
},
},
{
@@ -665,7 +668,7 @@ func TestPrecompileMakeCall(t *testing.T) {
// (non-static) CALL, the read-only state is inherited. Yes,
// this is _another_ way to get a read-only state, different to
// the other tests.
- ReadOnly: true,
+ Mutability: vm.ReadOnlyState,
},
},
{
@@ -677,8 +680,8 @@ func TestPrecompileMakeCall(t *testing.T) {
Caller: caller, // overridden by CallOption
Self: dest,
},
- Input: precompileCallData,
- ReadOnly: true,
+ Input: precompileCallData,
+ Mutability: vm.ReadOnlyState,
},
},
}
@@ -764,3 +767,76 @@ func ExamplePrecompileEnvironment() {
// variable to include it in this example function.
_ = actualCaller
}
+
+func TestStateMutability(t *testing.T) {
+ rng := ethtest.NewPseudoRand(0)
+ precompileAddr := rng.Address()
+ chainID := rng.BigUint64()
+
+ const precompileReturn = "precompile executed"
+ precompile := vm.NewStatefulPrecompile(func(env vm.PrecompileEnvironment, input []byte) (ret []byte, err error) {
+ tests := []struct {
+ name string
+ env vm.PrecompileEnvironment
+ want vm.StateMutability
+ }{
+ {
+ name: "incoming argument",
+ env: env,
+ want: vm.MutableState,
+ },
+ {
+ name: "AsReadOnly()",
+ env: env.AsReadOnly(),
+ want: vm.ReadOnlyState,
+ },
+ {
+ name: "AsPure()",
+ env: env.AsPure(),
+ want: vm.Pure,
+ },
+ {
+ name: "AsPure().AsReadOnly() is still pure",
+ env: env.AsPure().AsReadOnly(),
+ want: vm.Pure,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ env := tt.env // deliberately shadow the incoming arg
+ t.Run("mutability_and_access", func(t *testing.T) {
+ assert.Equal(t, tt.want, env.StateMutability(), "env.StateMutability()")
+ assert.Equal(t, env.StateDB() != nil, tt.want == vm.MutableState, "env.StateDB() != nil i.f.f. MutableState")
+ assert.Equal(t, env.ReadOnlyState() != nil, tt.want != vm.Pure, "env.ReadOnlyState() != nil i.f.f !Pure")
+ })
+
+ t.Run("environment_unmodified", func(t *testing.T) {
+ // Each of these demonstrate that the underlying
+ // copy of the environment propagates everything but
+ // mutability.
+ assert.Equal(t, chainID, env.ChainConfig().ChainID, "Chain ID preserved")
+ assert.Equalf(t, precompileAddr, env.Addresses().Self, "%T preserved", env.Addresses())
+ assert.Equalf(t, vm.Call, env.IncomingCallType(), "%T preserved", env.IncomingCallType())
+ })
+ })
+ }
+
+ return []byte(precompileReturn), nil
+ })
+
+ hooks := &hookstest.Stub{
+ PrecompileOverrides: map[common.Address]libevm.PrecompiledContract{
+ precompileAddr: precompile,
+ },
+ }
+ hooks.Register(t)
+
+ _, evm := ethtest.NewZeroEVM(t, ethtest.WithChainConfig(¶ms.ChainConfig{
+ ChainID: chainID,
+ }))
+ got, _, err := evm.Call(vm.AccountRef{}, precompileAddr, nil, 0, uint256.NewInt(0))
+ if got, want := string(got), precompileReturn; err != nil || got != want {
+ t.Errorf("%T.Call([precompile]) got {%q, %v}; want {%q, nil}", evm, got, err, want)
+ }
+}
diff --git a/core/vm/environment.libevm.go b/core/vm/environment.libevm.go
index f2b61169d26e..79fe4d09f0cb 100644
--- a/core/vm/environment.libevm.go
+++ b/core/vm/environment.libevm.go
@@ -17,6 +17,7 @@
package vm
import (
+ "errors"
"fmt"
"math/big"
@@ -33,21 +34,27 @@ import (
var _ PrecompileEnvironment = (*environment)(nil)
type environment struct {
- evm *EVM
- self *Contract
- callType CallType
+ evm *EVM
+ self *Contract
+ callType CallType
+ view, pure bool
+}
+
+func (e *environment) copy() *environment {
+ // This deliberately does not use field names so that a change in the fields
+ // will break this code and force it to be reviewed.
+ return &environment{e.evm, e.self, e.callType, e.view, e.pure}
}
func (e *environment) Gas() uint64 { return e.self.Gas }
func (e *environment) UseGas(gas uint64) bool { return e.self.UseGas(gas) }
func (e *environment) Value() *uint256.Int { return new(uint256.Int).Set(e.self.Value()) }
-func (e *environment) ChainConfig() *params.ChainConfig { return e.evm.chainConfig }
-func (e *environment) Rules() params.Rules { return e.evm.chainRules }
-func (e *environment) ReadOnlyState() libevm.StateReader { return e.evm.StateDB }
-func (e *environment) IncomingCallType() CallType { return e.callType }
-func (e *environment) BlockNumber() *big.Int { return new(big.Int).Set(e.evm.Context.BlockNumber) }
-func (e *environment) BlockTime() uint64 { return e.evm.Context.Time }
+func (e *environment) ChainConfig() *params.ChainConfig { return e.evm.chainConfig }
+func (e *environment) Rules() params.Rules { return e.evm.chainRules }
+func (e *environment) IncomingCallType() CallType { return e.callType }
+func (e *environment) BlockNumber() *big.Int { return new(big.Int).Set(e.evm.Context.BlockNumber) }
+func (e *environment) BlockTime() uint64 { return e.evm.Context.Time }
func (e *environment) refundGas(add uint64) error {
gas, overflow := math.SafeAdd(e.self.Gas, add)
@@ -58,37 +65,61 @@ func (e *environment) refundGas(add uint64) error {
return nil
}
-func (e *environment) ReadOnly() bool {
+func (e *environment) AsReadOnly() PrecompileEnvironment {
+ cp := e.copy()
+ cp.view = true
+ return cp
+}
+
+func (e *environment) AsPure() PrecompileEnvironment {
+ cp := e.copy()
+ cp.pure = true
+ return cp
+}
+
+func (e *environment) StateMutability() StateMutability {
// A switch statement provides clearer code coverage for difficult-to-test
// cases.
switch {
+ // cases MUST be ordered from most to least restrictive
+ case e.pure:
+ return Pure
case e.callType == StaticCall:
// evm.interpreter.readOnly is only set to true via a call to
// EVMInterpreter.Run() so, if a precompile is called directly with
// StaticCall(), then readOnly might not be set yet.
- return true
+ return ReadOnlyState
case e.evm.interpreter.readOnly:
- return true
+ return ReadOnlyState
+ case e.view:
+ return ReadOnlyState
default:
- return false
+ return MutableState
}
}
-func (e *environment) Addresses() *libevm.AddressContext {
- return &libevm.AddressContext{
- Origin: e.evm.Origin,
- Caller: e.self.CallerAddress,
- Self: e.self.Address(),
+func (e *environment) ReadOnlyState() libevm.StateReader {
+ if e.pure {
+ return nil
}
+ return e.evm.StateDB
}
func (e *environment) StateDB() StateDB {
- if e.ReadOnly() {
+ if e.StateMutability() != MutableState {
return nil
}
return e.evm.StateDB
}
+func (e *environment) Addresses() *libevm.AddressContext {
+ return &libevm.AddressContext{
+ Origin: e.evm.Origin,
+ Caller: e.self.CallerAddress,
+ Self: e.self.Address(),
+ }
+}
+
func (e *environment) BlockHeader() (types.Header, error) {
hdr := e.evm.Context.Header
if hdr == nil {
@@ -105,7 +136,13 @@ func (e *environment) Call(addr common.Address, input []byte, gas uint64, value
return e.callContract(Call, addr, input, gas, value, opts...)
}
+var errPureFunctionMakeCall = errors.New("contract call from pure function")
+
func (e *environment) callContract(typ CallType, addr common.Address, input []byte, gas uint64, value *uint256.Int, opts ...CallOption) (retData []byte, retErr error) {
+ if e.StateMutability() == Pure {
+ return nil, errPureFunctionMakeCall
+ }
+
// Depth and read-only setting are handled by [EVMInterpreter.Run], which
// isn't used for precompiles, so we need to do it ourselves to maintain the
// expected invariants.
@@ -114,7 +151,7 @@ func (e *environment) callContract(typ CallType, addr common.Address, input []by
in.evm.depth++
defer func() { in.evm.depth-- }()
- if e.ReadOnly() && !in.readOnly { // i.e. the precompile was StaticCall()ed
+ if e.StateMutability() != MutableState && !in.readOnly { // i.e. the precompile was StaticCall()ed
in.readOnly = true
defer func() { in.readOnly = false }()
}
diff --git a/libevm/ethtest/rand.go b/libevm/ethtest/rand.go
index 832d783e7185..af39a29dc8c6 100644
--- a/libevm/ethtest/rand.go
+++ b/libevm/ethtest/rand.go
@@ -17,13 +17,16 @@
package ethtest
import (
+ "crypto/ecdsa"
"math/big"
+ "testing"
"github.com/holiman/uint256"
"golang.org/x/exp/rand"
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/core/types"
+ "github.com/ava-labs/libevm/crypto"
)
// PseudoRand extends [rand.Rand] (*not* crypto/rand).
@@ -90,6 +93,16 @@ func (r *PseudoRand) Uint256() *uint256.Int {
return new(uint256.Int).SetBytes(r.Bytes(32))
}
+// UnsafePrivateKey returns a private key on the secp256k1 curve.
+func (r *PseudoRand) UnsafePrivateKey(tb testing.TB) *ecdsa.PrivateKey {
+ tb.Helper()
+ key, err := ecdsa.GenerateKey(crypto.S256(), r.Rand)
+ if err != nil {
+ tb.Fatalf("ecdsa.GenerateKey(crypto.S256(), %T) error %v", r.Rand, err)
+ }
+ return key
+}
+
// Bloom returns a pseudorandom Bloom.
func (r *PseudoRand) Bloom() (b types.Bloom) {
r.Read(b[:])
diff --git a/libevm/hookstest/stub.go b/libevm/hookstest/stub.go
index 1e37aa3f940d..40cd5c185740 100644
--- a/libevm/hookstest/stub.go
+++ b/libevm/hookstest/stub.go
@@ -19,6 +19,7 @@
package hookstest
import (
+ "encoding/json"
"math/big"
"testing"
@@ -126,3 +127,11 @@ var _ interface {
params.ChainConfigHooks
params.RulesHooks
} = Stub{}
+
+// MarshalJSON implements [json.Marshaler], always returning the empty JSON
+// object.
+func (*Stub) MarshalJSON() ([]byte, error) {
+ return []byte(`{}`), nil
+}
+
+var _ json.Marshaler = (*Stub)(nil)
diff --git a/libevm/precompilegen/main.go b/libevm/precompilegen/main.go
new file mode 100644
index 000000000000..5210f39b84aa
--- /dev/null
+++ b/libevm/precompilegen/main.go
@@ -0,0 +1,172 @@
+// Copyright 2024 the libevm authors.
+//
+// The libevm additions to go-ethereum are free software: you can redistribute
+// them and/or modify them under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The libevm additions are distributed in the hope that they will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see
+// .
+
+// The precompilegen binary generates code for creating EVM precompiles
+// conforming to arbitrary Solidity interfaces.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io"
+ "os"
+ "sort"
+ "strings"
+ "text/template"
+
+ "github.com/ava-labs/libevm/accounts/abi"
+
+ _ "embed"
+)
+
+type config struct {
+ in, out string
+ pkg string
+}
+
+func main() {
+ var c config
+ flag.StringVar(&c.in, "in", "", `Input ABI file or empty for stdin.`)
+ flag.StringVar(&c.out, "out", "", `Output Go file or empty for stdout.`)
+ flag.StringVar(&c.pkg, "package", "", "Generated package name.")
+ flag.Parse()
+
+ in := os.Stdin
+ if c.in != "" {
+ in = mustOpen(c.in, os.O_RDONLY, 0)
+ }
+ out := os.Stdout
+ if c.out != "" {
+ out = mustOpen(c.out, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ }
+
+ if err := c.generate(in, out); err != nil {
+ exit(err)
+ }
+ fmt.Fprintln(os.Stderr, "Generated precompile")
+}
+
+func mustOpen(name string, flag int, perm os.FileMode) *os.File {
+ f, err := os.OpenFile(name, flag, perm) //nolint:gosec // User-provided file path is necessary behaviour, isolated to development environment.
+ if err != nil {
+ exit(err)
+ }
+ return f
+}
+
+func exit(a ...any) {
+ fmt.Fprintln(os.Stderr, a...)
+ os.Exit(1)
+}
+
+var (
+ //go:embed precompile.go.tmpl
+ rawTemplate string
+ funcs = template.FuncMap{
+ "methods": methods,
+ "signature": signature,
+ "hex": hex,
+ "type": goType,
+ "args": args,
+ "interfaceID": interfaceID,
+ }
+ tmpl = template.Must(template.New("contract").Funcs(funcs).Parse(rawTemplate))
+)
+
+func (c *config) generate(abiJSON io.Reader, out io.WriteCloser) error {
+ var jsonCopy bytes.Buffer
+ parsed, err := abi.JSON(io.TeeReader(abiJSON, &jsonCopy))
+ if err != nil {
+ return fmt.Errorf("parse ABI: %v", err)
+ }
+
+ var buf bytes.Buffer
+ data := struct {
+ ABI abi.ABI
+ JSON string
+ Package string
+ }{parsed, jsonCopy.String(), c.pkg}
+ if err := tmpl.Execute(&buf, data); err != nil {
+ return fmt.Errorf("execute template: %v", err)
+ }
+
+ src, err := format.Source(buf.Bytes())
+ if err != nil {
+ return fmt.Errorf("format source: %v", err)
+ }
+ if _, err := out.Write(src); err != nil {
+ return fmt.Errorf("write output: %v", err)
+ }
+ return out.Close()
+}
+
+func methods(a abi.ABI) []abi.Method {
+ methods := make([]abi.Method, 0, len(a.Methods))
+ for _, m := range a.Methods {
+ methods = append(methods, m)
+ }
+ sort.Slice(methods, func(i, j int) bool {
+ return methods[i].Name < methods[j].Name
+ })
+ return methods
+}
+
+func signature(m abi.Method) string {
+ in := append([]string{"vm.PrecompileEnvironment"}, asGoArgs(m.Inputs)...)
+ out := append(asGoArgs(m.Outputs), "error")
+ return fmt.Sprintf("%s(%s) (%s)", m.Name, strings.Join(in, ","), strings.Join(out, ","))
+}
+
+// interfaceID returns the EIP-165 interface ID of the methods.
+func interfaceID(a abi.ABI) abi.Selector {
+ var id abi.Selector
+ for _, m := range a.Methods {
+ id ^= m.Selector()
+ }
+ return id
+}
+
+func asGoArgs(args abi.Arguments) []string {
+ goArgs := make([]string, len(args))
+ for i, a := range args {
+ goArgs[i] = a.Type.GetType().String()
+ }
+ return goArgs
+}
+
+func hex(x any) string {
+ return fmt.Sprintf("%#x", x)
+}
+
+func goType(a abi.Argument) string {
+ return a.Type.GetType().String()
+}
+
+func args(prefix string, n int, withEnv, withErr bool) string {
+ a := make([]string, n)
+ for i := 0; i < n; i++ {
+ a[i] = fmt.Sprintf("%s%d", prefix, i)
+ }
+ if withEnv {
+ a = append([]string{"env"}, a...)
+ }
+ if withErr {
+ a = append(a, "err")
+ }
+ return strings.Join(a, ", ")
+}
diff --git a/libevm/precompilegen/precompile.go.tmpl b/libevm/precompilegen/precompile.go.tmpl
new file mode 100644
index 000000000000..8633a673a6e0
--- /dev/null
+++ b/libevm/precompilegen/precompile.go.tmpl
@@ -0,0 +1,137 @@
+// Package {{.Package}} is a generated package for creating EVM precompiles
+// conforming to the EIP-165 interface ID {{interfaceID .ABI}}.
+package {{.Package}}
+
+// Code generated by precompilegen. DO NOT EDIT.
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ava-labs/libevm/accounts/abi"
+ "github.com/ava-labs/libevm/common"
+ "github.com/ava-labs/libevm/core/vm"
+)
+
+// A Contract is an implementation of a precompiled contract conforming to the
+// EIP-165 interface ID {{interfaceID .ABI}}.
+type Contract interface {
+ // Fallback implements a fallback function, called if the method selector
+ // fails to match any other method.
+ Fallback(vm.PrecompileEnvironment, []byte) ([]byte, error)
+{{range methods .ABI}}
+ // {{.Name}} implements the function with selector {{hex .ID}}:
+ // {{.String}}
+ {{signature .}}
+{{end}}
+}
+
+type methodDispatcher = func(Contract, vm.PrecompileEnvironment, []byte) ([]byte, error)
+
+var (
+ // Avoid unused-import errors.
+ _ *big.Int = nil
+ _ *common.Address = nil
+
+ methods abi.MethodsBySelector
+ dispatchers map[abi.Selector]methodDispatcher
+)
+
+const abiJSON = `{{.JSON}}`
+
+func init() {
+ parsed, err := abi.JSON(strings.NewReader(abiJSON))
+ if err != nil {
+ panic(err.Error())
+ }
+ methods = parsed.MethodsBySelector()
+
+ var d dispatch
+ dispatchers = map[abi.Selector]methodDispatcher{
+ {{range methods .ABI}}{{hex .ID}}: d.{{.Name}},
+ {{end}}
+ }
+}
+
+// New returns a precompiled contract backed by the provided implementation.
+func New(impl Contract) vm.PrecompiledContract {
+ return vm.NewStatefulPrecompile(precompile{impl}.run)
+}
+
+type precompile struct {
+ impl Contract
+}
+
+const revertBufferWhenNonPayableReceivesValue = "non-payable"
+
+func (p precompile) run(env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ selector, ok := methods.FindSelector(input)
+ if !ok {
+ return p.impl.Fallback(env, input)
+ }
+
+ payable := false
+ switch m := methods[selector]; m.StateMutability {
+ case "payable":
+ payable = true
+ case "nonpayable":
+ case "pure":
+ env = env.AsPure()
+ case "view":
+ env = env.AsReadOnly()
+ default:
+ // If this happens then `precompilegen` needs to be extended because the
+ // Solidity ABI spec changed.
+ data := fmt.Sprintf("unsupported state mutability %q on method %s", m.StateMutability, m.Sig)
+ return []byte(data), vm.ErrExecutionReverted
+ }
+ if !payable && !env.Value().IsZero() {
+ return []byte(revertBufferWhenNonPayableReceivesValue), vm.ErrExecutionReverted
+ }
+
+ ret, err := dispatchers[selector](p.impl, env, input)
+ switch err := err.(type) {
+ case nil:
+ return ret, nil
+ case vm.RevertError:
+ return err.Bytes(), vm.ErrExecutionReverted
+ default:
+ return nil, err
+ }
+}
+
+// dispatch is the type on which all method dispatchers are defined, stopping
+// them from being exported as top-level identifiers that clutter package
+// documentation.
+type dispatch struct{}
+
+{{range methods .ABI}}
+func (dispatch) {{.Name}}(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ {{if or (gt (len .Inputs) 0) (gt (len .Outputs) 0) -}}
+ method := methods[{{hex .ID}}]
+ {{- end}}
+
+ {{if gt (len .Inputs) 0 -}}
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ {{- range $i, $in := .Inputs}}
+ i{{$i}} := inputs[{{$i}}].({{type $in}})
+ {{- end}}
+ {{- end}}
+
+ {
+ {{args "o" (len .Outputs) false true}} := impl.{{.Name}}({{args "i" (len .Inputs) true false}})
+ if err != nil {
+ return nil, err
+ }
+ {{if gt (len .Outputs) 0}}
+ return method.Outputs.Pack({{args "o" (len .Outputs) false false}})
+ {{- else -}}
+ return nil, nil
+ {{- end}}
+ }
+}
+{{end}}
\ No newline at end of file
diff --git a/libevm/precompilegen/testprecompile/.gitignore b/libevm/precompilegen/testprecompile/.gitignore
new file mode 100644
index 000000000000..ba75a4ee7f65
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/.gitignore
@@ -0,0 +1,3 @@
+*.abi
+*.bin
+
diff --git a/libevm/precompilegen/testprecompile/IPrecompile.sol b/libevm/precompilegen/testprecompile/IPrecompile.sol
new file mode 100644
index 000000000000..65de9086f700
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/IPrecompile.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: LGPL-3.0
+pragma solidity 0.8.28;
+
+/// @dev Interface of precompiled contract for implementation via `precompilegen`.
+interface IPrecompile {
+ function Echo(string memory) external view returns (string memory);
+
+ function Echo(uint256) external view returns (uint256);
+
+ function HashPacked(uint256, bytes2, address) external view returns (bytes32);
+
+ struct Wrapper {
+ int256 val;
+ }
+
+ function Extract(Wrapper memory) external view returns (int256);
+
+ function Self() external view returns (address);
+
+ function RevertWith(bytes memory) external;
+
+ function View() external view returns (bool canReadState, bool canWriteState);
+
+ function Pure() external pure returns (bool canReadState, bool canWriteState);
+
+ function NeitherViewNorPure() external returns (bool canReadState, bool canWriteState);
+
+ function Payable() external payable returns (uint256 value);
+
+ function NonPayable() external;
+}
diff --git a/libevm/precompilegen/testprecompile/TestSuite.sol b/libevm/precompilegen/testprecompile/TestSuite.sol
new file mode 100644
index 000000000000..53a05f9de954
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/TestSuite.sol
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: LGPL-3.0
+pragma solidity 0.8.28;
+
+import {IPrecompile} from "./IPrecompile.sol";
+
+/// @dev Testing contract to exercise the Go implementaiton of `IPrecompile`.
+contract TestSuite {
+ IPrecompile immutable precompile;
+
+ /// @dev Expected revert buffer when paying a non-payable function.
+ string private _expectedNonPayableErrorMsg;
+
+ constructor(IPrecompile _precompile, string memory nonPayableErrorMsg) payable {
+ precompile = _precompile;
+ _expectedNonPayableErrorMsg = nonPayableErrorMsg;
+ }
+
+ /// @dev Emitted by each function to prove that it was successfully called.
+ event Called(string func);
+
+ function Echo(string memory x) external {
+ assert(keccak256(abi.encodePacked(precompile.Echo(x))) == keccak256(abi.encodePacked(x)));
+ emit Called("Echo(string)");
+ }
+
+ function Echo(uint256 x) external {
+ assert(precompile.Echo(x) == x);
+ emit Called("Echo(uint256)");
+ }
+
+ function Extract(IPrecompile.Wrapper memory x) external {
+ assert(x.val == precompile.Extract(x));
+ emit Called("Extract(...)");
+ }
+
+ function HashPacked(uint256 x, bytes2 y, address z) external {
+ assert(precompile.HashPacked(x, y, z) == keccak256(abi.encodePacked(x, y, z)));
+ emit Called("HashPacked(...)");
+ }
+
+ function Self() external {
+ assert(precompile.Self() == address(precompile));
+ emit Called("Self()");
+ }
+
+ function RevertWith(bytes memory err) external {
+ (bool ok, bytes memory ret) =
+ address(precompile).call(abi.encodeWithSelector(IPrecompile.RevertWith.selector, err));
+ assert(!ok);
+ assert(keccak256(ret) == keccak256(err));
+
+ emit Called("RevertWith(...)");
+ }
+
+ function EchoingFallback(bytes memory input) external {
+ bytes memory data = abi.encodeWithSelector( /*non-existent selector*/ 0, input);
+ (bool ok, bytes memory ret) = address(precompile).staticcall(data);
+ assert(ok);
+ // Note equality with `data`, not `input` as the fallback echoes its
+ // entire calldata, which includes the non-matching selector.
+ assert(keccak256(ret) == keccak256(data));
+
+ emit Called("EchoingFallback(...)");
+ }
+
+ function assertReadOnly(bytes4 selector, bool expectCanReadState, bool expectCanWriteState) internal {
+ // We use a low-level call() here to ensure that the Solidity compiler
+ // doesn't issue a staticcall() to view/pure functions as this would
+ // hide our forcing of a read-only state.
+ (bool ok, bytes memory ret) = address(precompile).call(abi.encodeWithSelector(selector));
+ assert(ok);
+ (bool canReadState, bool canWriteState) = abi.decode(ret, (bool, bool));
+ assert(canReadState == expectCanReadState);
+ assert(canWriteState == expectCanWriteState);
+ }
+
+ function View() external {
+ assertReadOnly(IPrecompile.View.selector, true, false);
+ emit Called("View()");
+ }
+
+ function Pure() external {
+ assertReadOnly(IPrecompile.Pure.selector, false, false);
+ emit Called("Pure()");
+ }
+
+ function NeitherViewNorPure() external {
+ assertReadOnly(IPrecompile.NeitherViewNorPure.selector, true, true);
+ emit Called("NeitherViewNorPure()");
+ }
+
+ function Transfer() external {
+ uint256 value = precompile.Payable{value: 42}();
+ assert(value == 42);
+
+ bytes4 nonPayable = IPrecompile.NonPayable.selector;
+ callNonPayable(nonPayable, 0, "");
+
+ bytes memory err = abi.encodePacked(_expectedNonPayableErrorMsg);
+ callNonPayable(nonPayable, 1, err);
+ callNonPayable(IPrecompile.View.selector, 1, err);
+ callNonPayable(IPrecompile.Pure.selector, 1, err);
+
+ emit Called("Transfer()");
+ }
+
+ function callNonPayable(bytes4 selector, uint256 value, bytes memory expectRevertWith) internal {
+ // We can't use just call `precompile.NonPayable()` directly because
+ // (a) it's a precompile and (b) it doesn't return values, which means
+ // that Solidity will perform an EXTCODESIZE check first and revert.
+ bytes memory data = abi.encodeWithSelector(selector);
+ (bool ok, bytes memory ret) = address(precompile).call{value: value}(data);
+
+ if (expectRevertWith.length == 0) {
+ assert(ok);
+ } else {
+ assert(!ok);
+ assert(keccak256(ret) == keccak256(expectRevertWith));
+ }
+ }
+}
diff --git a/libevm/precompilegen/testprecompile/generated.go b/libevm/precompilegen/testprecompile/generated.go
new file mode 100644
index 000000000000..e00f83efa138
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/generated.go
@@ -0,0 +1,331 @@
+// Package testprecompile is a generated package for creating EVM precompiles
+// conforming to the EIP-165 interface ID 0xcacc24d1.
+package testprecompile
+
+// Code generated by precompilegen. DO NOT EDIT.
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ava-labs/libevm/accounts/abi"
+ "github.com/ava-labs/libevm/common"
+ "github.com/ava-labs/libevm/core/vm"
+)
+
+// A Contract is an implementation of a precompiled contract conforming to the
+// EIP-165 interface ID 0xcacc24d1.
+type Contract interface {
+ // Fallback implements a fallback function, called if the method selector
+ // fails to match any other method.
+ Fallback(vm.PrecompileEnvironment, []byte) ([]byte, error)
+
+ // Echo implements the function with selector 0x34d6d9be:
+ // function Echo(uint256 ) view returns(uint256)
+ Echo(vm.PrecompileEnvironment, *big.Int) (*big.Int, error)
+
+ // Echo0 implements the function with selector 0xdb84d7c0:
+ // function Echo(string ) view returns(string)
+ Echo0(vm.PrecompileEnvironment, string) (string, error)
+
+ // Extract implements the function with selector 0xad8108a4:
+ // function Extract((int256) ) view returns(int256)
+ Extract(vm.PrecompileEnvironment, struct {
+ Val *big.Int "json:\"val\""
+ }) (*big.Int, error)
+
+ // HashPacked implements the function with selector 0xd7cc1f37:
+ // function HashPacked(uint256 , bytes2 , address ) view returns(bytes32)
+ HashPacked(vm.PrecompileEnvironment, *big.Int, [2]uint8, common.Address) ([32]uint8, error)
+
+ // NeitherViewNorPure implements the function with selector 0xa7263000:
+ // function NeitherViewNorPure() returns(bool canReadState, bool canWriteState)
+ NeitherViewNorPure(vm.PrecompileEnvironment) (bool, bool, error)
+
+ // NonPayable implements the function with selector 0x6fb1b0e9:
+ // function NonPayable() returns()
+ NonPayable(vm.PrecompileEnvironment) error
+
+ // Payable implements the function with selector 0x1b7fb4b0:
+ // function Payable() payable returns(uint256 value)
+ Payable(vm.PrecompileEnvironment) (*big.Int, error)
+
+ // Pure implements the function with selector 0xf5ad2fb8:
+ // function Pure() pure returns(bool canReadState, bool canWriteState)
+ Pure(vm.PrecompileEnvironment) (bool, bool, error)
+
+ // RevertWith implements the function with selector 0xa93cbd97:
+ // function RevertWith(bytes ) returns()
+ RevertWith(vm.PrecompileEnvironment, []uint8) error
+
+ // Self implements the function with selector 0xc62c692f:
+ // function Self() view returns(address)
+ Self(vm.PrecompileEnvironment) (common.Address, error)
+
+ // View implements the function with selector 0x1686f265:
+ // function View() view returns(bool canReadState, bool canWriteState)
+ View(vm.PrecompileEnvironment) (bool, bool, error)
+}
+
+type methodDispatcher = func(Contract, vm.PrecompileEnvironment, []byte) ([]byte, error)
+
+var (
+ // Avoid unused-import errors.
+ _ *big.Int = nil
+ _ *common.Address = nil
+
+ methods abi.MethodsBySelector
+ dispatchers map[abi.Selector]methodDispatcher
+)
+
+const abiJSON = `[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"Echo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"Echo","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"int256","name":"val","type":"int256"}],"internalType":"struct IPrecompile.Wrapper","name":"","type":"tuple"}],"name":"Extract","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes2","name":"","type":"bytes2"},{"internalType":"address","name":"","type":"address"}],"name":"HashPacked","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NeitherViewNorPure","outputs":[{"internalType":"bool","name":"canReadState","type":"bool"},{"internalType":"bool","name":"canWriteState","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"NonPayable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"Payable","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"Pure","outputs":[{"internalType":"bool","name":"canReadState","type":"bool"},{"internalType":"bool","name":"canWriteState","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"RevertWith","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"Self","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"View","outputs":[{"internalType":"bool","name":"canReadState","type":"bool"},{"internalType":"bool","name":"canWriteState","type":"bool"}],"stateMutability":"view","type":"function"}]`
+
+func init() {
+ parsed, err := abi.JSON(strings.NewReader(abiJSON))
+ if err != nil {
+ panic(err.Error())
+ }
+ methods = parsed.MethodsBySelector()
+
+ var d dispatch
+ dispatchers = map[abi.Selector]methodDispatcher{
+ 0x34d6d9be: d.Echo,
+ 0xdb84d7c0: d.Echo0,
+ 0xad8108a4: d.Extract,
+ 0xd7cc1f37: d.HashPacked,
+ 0xa7263000: d.NeitherViewNorPure,
+ 0x6fb1b0e9: d.NonPayable,
+ 0x1b7fb4b0: d.Payable,
+ 0xf5ad2fb8: d.Pure,
+ 0xa93cbd97: d.RevertWith,
+ 0xc62c692f: d.Self,
+ 0x1686f265: d.View,
+ }
+}
+
+// New returns a precompiled contract backed by the provided implementation.
+func New(impl Contract) vm.PrecompiledContract {
+ return vm.NewStatefulPrecompile(precompile{impl}.run)
+}
+
+type precompile struct {
+ impl Contract
+}
+
+const revertBufferWhenNonPayableReceivesValue = "non-payable"
+
+func (p precompile) run(env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ selector, ok := methods.FindSelector(input)
+ if !ok {
+ return p.impl.Fallback(env, input)
+ }
+
+ payable := false
+ switch m := methods[selector]; m.StateMutability {
+ case "payable":
+ payable = true
+ case "nonpayable":
+ case "pure":
+ env = env.AsPure()
+ case "view":
+ env = env.AsReadOnly()
+ default:
+ // If this happens then `precompilegen` needs to be extended because the
+ // Solidity ABI spec changed.
+ data := fmt.Sprintf("unsupported state mutability %q on method %s", m.StateMutability, m.Sig)
+ return []byte(data), vm.ErrExecutionReverted
+ }
+ if !payable && !env.Value().IsZero() {
+ return []byte(revertBufferWhenNonPayableReceivesValue), vm.ErrExecutionReverted
+ }
+
+ ret, err := dispatchers[selector](p.impl, env, input)
+ switch err := err.(type) {
+ case nil:
+ return ret, nil
+ case vm.RevertError:
+ return err.Bytes(), vm.ErrExecutionReverted
+ default:
+ return nil, err
+ }
+}
+
+// dispatch is the type on which all method dispatchers are defined, stopping
+// them from being exported as top-level identifiers that clutter package
+// documentation.
+type dispatch struct{}
+
+func (dispatch) Echo(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0x34d6d9be]
+
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ i0 := inputs[0].(*big.Int)
+
+ {
+ o0, err := impl.Echo(env, i0)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) Echo0(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xdb84d7c0]
+
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ i0 := inputs[0].(string)
+
+ {
+ o0, err := impl.Echo0(env, i0)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) Extract(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xad8108a4]
+
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ i0 := inputs[0].(struct {
+ Val *big.Int "json:\"val\""
+ })
+
+ {
+ o0, err := impl.Extract(env, i0)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) HashPacked(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xd7cc1f37]
+
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ i0 := inputs[0].(*big.Int)
+ i1 := inputs[1].([2]uint8)
+ i2 := inputs[2].(common.Address)
+
+ {
+ o0, err := impl.HashPacked(env, i0, i1, i2)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) NeitherViewNorPure(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xa7263000]
+
+ {
+ o0, o1, err := impl.NeitherViewNorPure(env)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0, o1)
+ }
+}
+
+func (dispatch) NonPayable(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+
+ {
+ err := impl.NonPayable(env)
+ if err != nil {
+ return nil, err
+ }
+ return nil, nil
+ }
+}
+
+func (dispatch) Payable(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0x1b7fb4b0]
+
+ {
+ o0, err := impl.Payable(env)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) Pure(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xf5ad2fb8]
+
+ {
+ o0, o1, err := impl.Pure(env)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0, o1)
+ }
+}
+
+func (dispatch) RevertWith(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xa93cbd97]
+
+ inputs, err := method.Inputs.Unpack(input[abi.SelectorByteLen:])
+ if err != nil {
+ return nil, err
+ }
+ i0 := inputs[0].([]uint8)
+
+ {
+ err := impl.RevertWith(env, i0)
+ if err != nil {
+ return nil, err
+ }
+ return nil, nil
+ }
+}
+
+func (dispatch) Self(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0xc62c692f]
+
+ {
+ o0, err := impl.Self(env)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0)
+ }
+}
+
+func (dispatch) View(impl Contract, env vm.PrecompileEnvironment, input []byte) ([]byte, error) {
+ method := methods[0x1686f265]
+
+ {
+ o0, o1, err := impl.View(env)
+ if err != nil {
+ return nil, err
+ }
+
+ return method.Outputs.Pack(o0, o1)
+ }
+}
diff --git a/libevm/precompilegen/testprecompile/generated_test.go b/libevm/precompilegen/testprecompile/generated_test.go
new file mode 100644
index 000000000000..42d400a8bc83
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/generated_test.go
@@ -0,0 +1,267 @@
+// Copyright 2024 the libevm authors.
+//
+// The libevm additions to go-ethereum are free software: you can redistribute
+// them and/or modify them under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The libevm additions are distributed in the hope that they will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see
+// .
+
+package testprecompile
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/holiman/uint256"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/ava-labs/libevm/accounts/abi/bind"
+ "github.com/ava-labs/libevm/common"
+ "github.com/ava-labs/libevm/core/types"
+ "github.com/ava-labs/libevm/core/vm"
+ "github.com/ava-labs/libevm/crypto"
+ "github.com/ava-labs/libevm/eth/ethconfig"
+ "github.com/ava-labs/libevm/ethclient/simulated"
+ "github.com/ava-labs/libevm/libevm"
+ "github.com/ava-labs/libevm/libevm/ethtest"
+ "github.com/ava-labs/libevm/libevm/hookstest"
+ "github.com/ava-labs/libevm/node"
+ "github.com/ava-labs/libevm/params"
+)
+
+// Note that the .abi and .bin files are .gitignored as only the generated Go
+// files are necessary.
+//go:generate solc -o ./ --overwrite --abi --bin IPrecompile.sol TestSuite.sol
+//go:generate go run ../ -in IPrecompile.abi -out ./generated.go -package testprecompile
+//go:generate go run ../../../cmd/abigen --abi TestSuite.abi --bin TestSuite.bin --pkg testprecompile --out ./suite.abigen_test.go --type TestSuite
+
+func successfulTxReceipt(ctx context.Context, tb testing.TB, client bind.DeployBackend, tx *types.Transaction) *types.Receipt {
+ tb.Helper()
+ r, err := bind.WaitMined(ctx, client, tx)
+ require.NoErrorf(tb, err, "bind.WaitMined(tx %#x)", tx.Hash())
+ require.Equalf(tb, uint64(1), r.Status, "%T.Status", r)
+ return r
+}
+
+func TestGeneratedPrecompile(t *testing.T) {
+ ctx := context.Background()
+ rng := ethtest.NewPseudoRand(424242)
+ precompile := rng.Address()
+
+ hooks := &hookstest.Stub{
+ PrecompileOverrides: map[common.Address]libevm.PrecompiledContract{
+ precompile: New(contract{}),
+ },
+ }
+ extras := hookstest.Register(t, params.Extras[*hookstest.Stub, *hookstest.Stub]{
+ NewRules: func(_ *params.ChainConfig, r *params.Rules, _ *hookstest.Stub, blockNum *big.Int, isMerge bool, timestamp uint64) *hookstest.Stub {
+ r.IsCancun = true // enable PUSH0
+ return hooks
+ },
+ })
+
+ key := rng.UnsafePrivateKey(t)
+ eoa := crypto.PubkeyToAddress(key.PublicKey)
+
+ sim := simulated.NewBackend(
+ types.GenesisAlloc{
+ eoa: types.Account{
+ Balance: new(uint256.Int).Not(uint256.NewInt(0)).ToBig(),
+ },
+ },
+ func(nodeConf *node.Config, ethConf *ethconfig.Config) {
+ ethConf.Genesis.GasLimit = 30e6
+ extras.ChainConfig.Set(ethConf.Genesis.Config, hooks)
+ },
+ )
+ defer sim.Close()
+
+ txOpts, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
+ require.NoError(t, err, "bind.NewKeyedTransactorWithChainID(..., 1337)")
+ txOpts.GasLimit = 30e6
+ txOpts.Value = big.NewInt(1e9)
+
+ client := sim.Client()
+ _, tx, test, err := DeployTestSuite(txOpts, client, precompile, revertBufferWhenNonPayableReceivesValue)
+ require.NoError(t, err, "DeployTestSuite(...)")
+ sim.Commit()
+ successfulTxReceipt(ctx, t, client, tx)
+
+ txOpts.Value = nil
+ suite := &TestSuiteSession{
+ Contract: test,
+ TransactOpts: *txOpts,
+ }
+
+ tests := []struct {
+ transact func() (*types.Transaction, error)
+ wantCalledEvent string
+ }{
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Echo(rng.BigUint64())
+ },
+ wantCalledEvent: "Echo(uint256)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Echo0("hello world")
+ },
+ wantCalledEvent: "Echo(string)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Extract(IPrecompileWrapper{
+ Val: rng.BigUint64(),
+ })
+ },
+ wantCalledEvent: "Extract(...)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.HashPacked(rng.BigUint64(), [2]byte{42, 42}, rng.Address())
+ },
+ wantCalledEvent: "HashPacked(...)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Self()
+ },
+ wantCalledEvent: "Self()",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.RevertWith(rng.Bytes(8))
+ },
+ wantCalledEvent: "RevertWith(...)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.EchoingFallback(rng.Bytes(8))
+ },
+ wantCalledEvent: "EchoingFallback(...)",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.View()
+ },
+ wantCalledEvent: "View()",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Pure()
+ },
+ wantCalledEvent: "Pure()",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.NeitherViewNorPure()
+ },
+ wantCalledEvent: "NeitherViewNorPure()",
+ },
+ {
+ transact: func() (*types.Transaction, error) {
+ return suite.Transfer()
+ },
+ wantCalledEvent: "Transfer()",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.wantCalledEvent, func(t *testing.T) {
+ tx, err := tt.transact()
+ require.NoError(t, err, "send tx")
+ sim.Commit()
+
+ rcpt := successfulTxReceipt(ctx, t, client, tx)
+ require.Equalf(t, uint64(1), rcpt.Status, "%T.Status (i.e. transaction executed without error)", rcpt)
+
+ require.Lenf(t, rcpt.Logs, 1, "%T.Logs", rcpt)
+ called, err := test.ParseCalled(*rcpt.Logs[0])
+ require.NoErrorf(t, err, "%T.ParseCalled(...)", test)
+ assert.Equal(t, tt.wantCalledEvent, called.Arg0, "function name emitted with `Called` event")
+ })
+ }
+}
+
+type contract struct{}
+
+var _ Contract = contract{}
+
+func (contract) Fallback(env vm.PrecompileEnvironment, callData []byte) ([]byte, error) {
+ // Note the test-suite assumption of the fallback's behaviour:
+ var _ = (*TestSuite).EchoingFallback
+ return callData, nil
+}
+
+func (contract) Echo(env vm.PrecompileEnvironment, x *big.Int) (*big.Int, error) {
+ return x, nil
+}
+
+func (contract) Echo0(env vm.PrecompileEnvironment, x string) (string, error) {
+ return x, nil
+}
+
+func (contract) Extract(env vm.PrecompileEnvironment, x struct {
+ Val *big.Int "json:\"val\""
+}) (*big.Int, error) {
+ return x.Val, nil
+}
+
+func (contract) HashPacked(env vm.PrecompileEnvironment, x *big.Int, y [2]byte, z common.Address) (hash [32]byte, _ error) {
+ copy(
+ hash[:],
+ crypto.Keccak256(
+ uint256.MustFromBig(x).PaddedBytes(32),
+ y[:],
+ z.Bytes(),
+ ),
+ )
+ return hash, nil
+}
+
+func (contract) RevertWith(env vm.PrecompileEnvironment, x []byte) error {
+ return vm.RevertError(x)
+}
+
+func (contract) Self(env vm.PrecompileEnvironment) (common.Address, error) {
+ return env.Addresses().Self, nil
+}
+
+func canReadState(env vm.PrecompileEnvironment) bool {
+ return env.ReadOnlyState() != nil
+}
+
+func canWriteState(env vm.PrecompileEnvironment) bool {
+ return env.StateDB() != nil
+}
+
+func (contract) View(env vm.PrecompileEnvironment) (bool, bool, error) {
+ return canReadState(env), canWriteState(env), nil
+}
+
+func (contract) Pure(env vm.PrecompileEnvironment) (bool, bool, error) {
+ return canReadState(env), canWriteState(env), nil
+}
+
+func (contract) NeitherViewNorPure(env vm.PrecompileEnvironment) (bool, bool, error) {
+ return canReadState(env), canWriteState(env), nil
+}
+
+func (contract) Payable(env vm.PrecompileEnvironment) (*big.Int, error) {
+ return env.Value().ToBig(), nil
+}
+
+func (contract) NonPayable(env vm.PrecompileEnvironment) error {
+ return nil
+}
diff --git a/libevm/precompilegen/testprecompile/suite.abigen_test.go b/libevm/precompilegen/testprecompile/suite.abigen_test.go
new file mode 100644
index 000000000000..480cfc591f0e
--- /dev/null
+++ b/libevm/precompilegen/testprecompile/suite.abigen_test.go
@@ -0,0 +1,573 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package testprecompile
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ava-labs/libevm"
+ "github.com/ava-labs/libevm/accounts/abi"
+ "github.com/ava-labs/libevm/accounts/abi/bind"
+ "github.com/ava-labs/libevm/common"
+ "github.com/ava-labs/libevm/core/types"
+ "github.com/ava-labs/libevm/event"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+// IPrecompileWrapper is an auto generated low-level Go binding around an user-defined struct.
+type IPrecompileWrapper struct {
+ Val *big.Int
+}
+
+// TestSuiteMetaData contains all meta data concerning the TestSuite contract.
+var TestSuiteMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIPrecompile\",\"name\":\"_precompile\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"nonPayableErrorMsg\",\"type\":\"string\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"func\",\"type\":\"string\"}],\"name\":\"Called\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"Echo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"x\",\"type\":\"string\"}],\"name\":\"Echo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"input\",\"type\":\"bytes\"}],\"name\":\"EchoingFallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"int256\",\"name\":\"val\",\"type\":\"int256\"}],\"internalType\":\"structIPrecompile.Wrapper\",\"name\":\"x\",\"type\":\"tuple\"}],\"name\":\"Extract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"x\",\"type\":\"uint256\"},{\"internalType\":\"bytes2\",\"name\":\"y\",\"type\":\"bytes2\"},{\"internalType\":\"address\",\"name\":\"z\",\"type\":\"address\"}],\"name\":\"HashPacked\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NeitherViewNorPure\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Pure\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"RevertWith\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Self\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Transfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"View\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60a060405260405161236f38038061236f83398181016040528101906100259190610227565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050805f90816100679190610491565b505050610560565b5f604051905090565b5f5ffd5b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100a982610080565b9050919050565b5f6100ba8261009f565b9050919050565b6100ca816100b0565b81146100d4575f5ffd5b50565b5f815190506100e5816100c1565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610139826100f3565b810181811067ffffffffffffffff8211171561015857610157610103565b5b80604052505050565b5f61016a61006f565b90506101768282610130565b919050565b5f67ffffffffffffffff82111561019557610194610103565b5b61019e826100f3565b9050602081019050919050565b8281835e5f83830152505050565b5f6101cb6101c68461017b565b610161565b9050828152602081018484840111156101e7576101e66100ef565b5b6101f28482856101ab565b509392505050565b5f82601f83011261020e5761020d6100eb565b5b815161021e8482602086016101b9565b91505092915050565b5f5f6040838503121561023d5761023c610078565b5b5f61024a858286016100d7565b925050602083015167ffffffffffffffff81111561026b5761026a61007c565b5b610277858286016101fa565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806102cf57607f821691505b6020821081036102e2576102e161028b565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026103447fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610309565b61034e8683610309565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f61039261038d61038884610366565b61036f565b610366565b9050919050565b5f819050919050565b6103ab83610378565b6103bf6103b782610399565b848454610315565b825550505050565b5f5f905090565b6103d66103c7565b6103e18184846103a2565b505050565b5b81811015610404576103f95f826103ce565b6001810190506103e7565b5050565b601f8211156104495761041a816102e8565b610423846102fa565b81016020851015610432578190505b61044661043e856102fa565b8301826103e6565b50505b505050565b5f82821c905092915050565b5f6104695f198460080261044e565b1980831691505092915050565b5f610481838361045a565b9150826002028217905092915050565b61049a82610281565b67ffffffffffffffff8111156104b3576104b2610103565b5b6104bd82546102b8565b6104c8828285610408565b5f60209050601f8311600181146104f9575f84156104e7578287015190505b6104f18582610476565b865550610558565b601f198416610507866102e8565b5f5b8281101561052e57848901518255600182019150602085019450602081019050610509565b8683101561054b5784890151610547601f89168261045a565b8355505b6001600288020188555050505b505050505050565b608051611db16105be5f395f81816101d2015281816102b101528181610454015281816105b8015281816106f2015281816107e0015281816108170152818161092a01528181610a3501528181610b870152610d340152611db15ff3fe608060405234801561000f575f5ffd5b50600436106100a7575f3560e01c8063ad8108a41161006f578063ad8108a414610101578063b4a818081461011d578063c62c692f14610139578063d7cc1f3714610143578063db84d7c01461015f578063f5ad2fb81461017b576100a7565b80631686f265146100ab57806334d6d9be146100b5578063406dade3146100d1578063a7263000146100db578063a93cbd97146100e5575b5f5ffd5b6100b3610185565b005b6100cf60048036038101906100ca9190610e51565b6101cf565b005b6100d96102ae565b005b6100e3610406565b005b6100ff60048036038101906100fa9190610fb8565b610450565b005b61011b6004803603810190610116919061106f565b6105b6565b005b61013760048036038101906101329190610fb8565b610698565b005b6101416107de565b005b61015d60048036038101906101589190611149565b6108fd565b005b61017960048036038101906101749190611237565b610a0c565b005b610183610b3a565b005b610198631686f26560e01b60015f610b83565b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516101c5906112d8565b60405180910390a1565b807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166334d6d9be836040518263ffffffff1660e01b81526004016102299190611305565b602060405180830381865afa158015610244573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102689190611332565b146102765761027561135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516102a3906113d4565b60405180910390a150565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631b7fb4b0602a6040518263ffffffff1660e01b815260040160206040518083038185885af115801561031b573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906103409190611332565b9050602a81146103535761035261135d565b5b5f636fb1b0e960e01b9050610377815f60405180602001604052805f815250610cc9565b5f5f60405160200161038991906114eb565b60405160208183030381529060405290506103a682600183610cc9565b6103b9631686f26560e01b600183610cc9565b6103cc63f5ad2fb860e01b600183610cc9565b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516103f99061154b565b60405180910390a1505050565b61041963a726300060e01b600180610b83565b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a604051610446906115b3565b60405180910390a1565b5f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a93cbd9760e01b846040516024016104a29190611631565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161050c919061168b565b5f604051808303815f865af19150503d805f8114610545576040519150601f19603f3d011682016040523d82523d5f602084013e61054a565b606091505b5091509150811561055e5761055d61135d565b5b828051906020012081805190602001201461057c5761057b61135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516105a9906116eb565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ad8108a4826040518263ffffffff1660e01b815260040161060f9190611732565b602060405180830381865afa15801561062a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061064e919061175f565b815f0151146106605761065f61135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a60405161068d906117d4565b60405180910390a150565b5f5f826040516024016106ab9190611631565b6040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1683604051610735919061168b565b5f60405180830381855afa9150503d805f811461076d576040519150601f19603f3d011682016040523d82523d5f602084013e610772565b606091505b5091509150816107855761078461135d565b5b82805190602001208180519060200120146107a3576107a261135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516107d09061183c565b60405180910390a150505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c62c692f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561087e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108a2919061186e565b73ffffffffffffffffffffffffffffffffffffffff16146108c6576108c561135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516108f3906118e3565b60405180910390a1565b82828260405160200161091293929190611986565b604051602081830303815290604052805190602001207f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d7cc1f378585856040518463ffffffff1660e01b8152600401610985939291906119e0565b602060405180830381865afa1580156109a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109c49190611a48565b146109d2576109d161135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a6040516109ff90611abd565b60405180910390a1505050565b80604051602001610a1d9190611b15565b604051602081830303815290604052805190602001207f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663db84d7c0836040518263ffffffff1660e01b8152600401610a8c9190611b63565b5f60405180830381865afa158015610aa6573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610ace9190611bf1565b604051602001610ade9190611b15565b6040516020818303038152906040528051906020012014610b0257610b0161135d565b5b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a604051610b2f90611c82565b60405180910390a150565b610b4c63f5ad2fb860e01b5f5f610b83565b7f3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a604051610b7990611cea565b60405180910390a1565b5f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1685604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c2d919061168b565b5f604051808303815f865af19150503d805f8114610c66576040519150601f19603f3d011682016040523d82523d5f602084013e610c6b565b606091505b509150915081610c7e57610c7d61135d565b5b5f5f82806020019051810190610c949190611d3d565b9150915085151582151514610cac57610cab61135d565b5b84151581151514610cc057610cbf61135d565b5b50505050505050565b5f83604051602401604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168584604051610d78919061168b565b5f6040518083038185875af1925050503d805f8114610db2576040519150601f19603f3d011682016040523d82523d5f602084013e610db7565b606091505b50915091505f845103610dd75781610dd257610dd161135d565b5b610e05565b8115610de657610de561135d565b5b8380519060200120818051906020012014610e0457610e0361135d565b5b5b505050505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b610e3081610e1e565b8114610e3a575f5ffd5b50565b5f81359050610e4b81610e27565b92915050565b5f60208284031215610e6657610e65610e16565b5b5f610e7384828501610e3d565b91505092915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610eca82610e84565b810181811067ffffffffffffffff82111715610ee957610ee8610e94565b5b80604052505050565b5f610efb610e0d565b9050610f078282610ec1565b919050565b5f67ffffffffffffffff821115610f2657610f25610e94565b5b610f2f82610e84565b9050602081019050919050565b828183375f83830152505050565b5f610f5c610f5784610f0c565b610ef2565b905082815260208101848484011115610f7857610f77610e80565b5b610f83848285610f3c565b509392505050565b5f82601f830112610f9f57610f9e610e7c565b5b8135610faf848260208601610f4a565b91505092915050565b5f60208284031215610fcd57610fcc610e16565b5b5f82013567ffffffffffffffff811115610fea57610fe9610e1a565b5b610ff684828501610f8b565b91505092915050565b5f5ffd5b5f819050919050565b61101581611003565b811461101f575f5ffd5b50565b5f813590506110308161100c565b92915050565b5f6020828403121561104b5761104a610fff565b5b6110556020610ef2565b90505f61106484828501611022565b5f8301525092915050565b5f6020828403121561108457611083610e16565b5b5f61109184828501611036565b91505092915050565b5f7fffff00000000000000000000000000000000000000000000000000000000000082169050919050565b6110ce8161109a565b81146110d8575f5ffd5b50565b5f813590506110e9816110c5565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611118826110ef565b9050919050565b6111288161110e565b8114611132575f5ffd5b50565b5f813590506111438161111f565b92915050565b5f5f5f606084860312156111605761115f610e16565b5b5f61116d86828701610e3d565b935050602061117e868287016110db565b925050604061118f86828701611135565b9150509250925092565b5f67ffffffffffffffff8211156111b3576111b2610e94565b5b6111bc82610e84565b9050602081019050919050565b5f6111db6111d684611199565b610ef2565b9050828152602081018484840111156111f7576111f6610e80565b5b611202848285610f3c565b509392505050565b5f82601f83011261121e5761121d610e7c565b5b813561122e8482602086016111c9565b91505092915050565b5f6020828403121561124c5761124b610e16565b5b5f82013567ffffffffffffffff81111561126957611268610e1a565b5b6112758482850161120a565b91505092915050565b5f82825260208201905092915050565b7f56696577282900000000000000000000000000000000000000000000000000005f82015250565b5f6112c260068361127e565b91506112cd8261128e565b602082019050919050565b5f6020820190508181035f8301526112ef816112b6565b9050919050565b6112ff81610e1e565b82525050565b5f6020820190506113185f8301846112f6565b92915050565b5f8151905061132c81610e27565b92915050565b5f6020828403121561134757611346610e16565b5b5f6113548482850161131e565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b7f4563686f2875696e7432353629000000000000000000000000000000000000005f82015250565b5f6113be600d8361127e565b91506113c98261138a565b602082019050919050565b5f6020820190508181035f8301526113eb816113b2565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061143657607f821691505b602082108103611449576114486113f2565b5b50919050565b5f81905092915050565b5f819050815f5260205f209050919050565b5f81546114778161141f565b611481818661144f565b9450600182165f811461149b57600181146114b0576114e2565b60ff19831686528115158202860193506114e2565b6114b985611459565b5f5b838110156114da578154818901526001820191506020810190506114bb565b838801955050505b50505092915050565b5f6114f6828461146b565b915081905092915050565b7f5472616e736665722829000000000000000000000000000000000000000000005f82015250565b5f611535600a8361127e565b915061154082611501565b602082019050919050565b5f6020820190508181035f83015261156281611529565b9050919050565b7f4e656974686572566965774e6f725075726528290000000000000000000000005f82015250565b5f61159d60148361127e565b91506115a882611569565b602082019050919050565b5f6020820190508181035f8301526115ca81611591565b9050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f611603826115d1565b61160d81856115db565b935061161d8185602086016115eb565b61162681610e84565b840191505092915050565b5f6020820190508181035f83015261164981846115f9565b905092915050565b5f81905092915050565b5f611665826115d1565b61166f8185611651565b935061167f8185602086016115eb565b80840191505092915050565b5f611696828461165b565b915081905092915050565b7f52657665727457697468282e2e2e2900000000000000000000000000000000005f82015250565b5f6116d5600f8361127e565b91506116e0826116a1565b602082019050919050565b5f6020820190508181035f830152611702816116c9565b9050919050565b61171281611003565b82525050565b602082015f82015161172c5f850182611709565b50505050565b5f6020820190506117455f830184611718565b92915050565b5f815190506117598161100c565b92915050565b5f6020828403121561177457611773610e16565b5b5f6117818482850161174b565b91505092915050565b7f45787472616374282e2e2e2900000000000000000000000000000000000000005f82015250565b5f6117be600c8361127e565b91506117c98261178a565b602082019050919050565b5f6020820190508181035f8301526117eb816117b2565b9050919050565b7f4563686f696e6746616c6c6261636b282e2e2e290000000000000000000000005f82015250565b5f61182660148361127e565b9150611831826117f2565b602082019050919050565b5f6020820190508181035f8301526118538161181a565b9050919050565b5f815190506118688161111f565b92915050565b5f6020828403121561188357611882610e16565b5b5f6118908482850161185a565b91505092915050565b7f53656c66282900000000000000000000000000000000000000000000000000005f82015250565b5f6118cd60068361127e565b91506118d882611899565b602082019050919050565b5f6020820190508181035f8301526118fa816118c1565b9050919050565b5f819050919050565b61191b61191682610e1e565b611901565b82525050565b5f819050919050565b61193b6119368261109a565b611921565b82525050565b5f8160601b9050919050565b5f61195782611941565b9050919050565b5f6119688261194d565b9050919050565b61198061197b8261110e565b61195e565b82525050565b5f611991828661190a565b6020820191506119a1828561192a565b6002820191506119b1828461196f565b601482019150819050949350505050565b6119cb8161109a565b82525050565b6119da8161110e565b82525050565b5f6060820190506119f35f8301866112f6565b611a0060208301856119c2565b611a0d60408301846119d1565b949350505050565b5f819050919050565b611a2781611a15565b8114611a31575f5ffd5b50565b5f81519050611a4281611a1e565b92915050565b5f60208284031215611a5d57611a5c610e16565b5b5f611a6a84828501611a34565b91505092915050565b7f486173685061636b6564282e2e2e2900000000000000000000000000000000005f82015250565b5f611aa7600f8361127e565b9150611ab282611a73565b602082019050919050565b5f6020820190508181035f830152611ad481611a9b565b9050919050565b5f81519050919050565b5f611aef82611adb565b611af9818561144f565b9350611b098185602086016115eb565b80840191505092915050565b5f611b208284611ae5565b915081905092915050565b5f611b3582611adb565b611b3f818561127e565b9350611b4f8185602086016115eb565b611b5881610e84565b840191505092915050565b5f6020820190508181035f830152611b7b8184611b2b565b905092915050565b5f611b95611b9084611199565b610ef2565b905082815260208101848484011115611bb157611bb0610e80565b5b611bbc8482856115eb565b509392505050565b5f82601f830112611bd857611bd7610e7c565b5b8151611be8848260208601611b83565b91505092915050565b5f60208284031215611c0657611c05610e16565b5b5f82015167ffffffffffffffff811115611c2357611c22610e1a565b5b611c2f84828501611bc4565b91505092915050565b7f4563686f28737472696e672900000000000000000000000000000000000000005f82015250565b5f611c6c600c8361127e565b9150611c7782611c38565b602082019050919050565b5f6020820190508181035f830152611c9981611c60565b9050919050565b7f50757265282900000000000000000000000000000000000000000000000000005f82015250565b5f611cd460068361127e565b9150611cdf82611ca0565b602082019050919050565b5f6020820190508181035f830152611d0181611cc8565b9050919050565b5f8115159050919050565b611d1c81611d08565b8114611d26575f5ffd5b50565b5f81519050611d3781611d13565b92915050565b5f5f60408385031215611d5357611d52610e16565b5b5f611d6085828601611d29565b9250506020611d7185828601611d29565b915050925092905056fea2646970667358221220f0b141f0869405a047b6257eeea3f5957b650b4c10613fbb449d8778f8d6986764736f6c634300081c0033",
+}
+
+// TestSuiteABI is the input ABI used to generate the binding from.
+// Deprecated: Use TestSuiteMetaData.ABI instead.
+var TestSuiteABI = TestSuiteMetaData.ABI
+
+// TestSuiteBin is the compiled bytecode used for deploying new contracts.
+// Deprecated: Use TestSuiteMetaData.Bin instead.
+var TestSuiteBin = TestSuiteMetaData.Bin
+
+// DeployTestSuite deploys a new Ethereum contract, binding an instance of TestSuite to it.
+func DeployTestSuite(auth *bind.TransactOpts, backend bind.ContractBackend, _precompile common.Address, nonPayableErrorMsg string) (common.Address, *types.Transaction, *TestSuite, error) {
+ parsed, err := TestSuiteMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TestSuiteBin), backend, _precompile, nonPayableErrorMsg)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &TestSuite{TestSuiteCaller: TestSuiteCaller{contract: contract}, TestSuiteTransactor: TestSuiteTransactor{contract: contract}, TestSuiteFilterer: TestSuiteFilterer{contract: contract}}, nil
+}
+
+// TestSuite is an auto generated Go binding around an Ethereum contract.
+type TestSuite struct {
+ TestSuiteCaller // Read-only binding to the contract
+ TestSuiteTransactor // Write-only binding to the contract
+ TestSuiteFilterer // Log filterer for contract events
+}
+
+// TestSuiteCaller is an auto generated read-only Go binding around an Ethereum contract.
+type TestSuiteCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// TestSuiteTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type TestSuiteTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// TestSuiteFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
+type TestSuiteFilterer struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// TestSuiteSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type TestSuiteSession struct {
+ Contract *TestSuite // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// TestSuiteCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type TestSuiteCallerSession struct {
+ Contract *TestSuiteCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// TestSuiteTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type TestSuiteTransactorSession struct {
+ Contract *TestSuiteTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// TestSuiteRaw is an auto generated low-level Go binding around an Ethereum contract.
+type TestSuiteRaw struct {
+ Contract *TestSuite // Generic contract binding to access the raw methods on
+}
+
+// TestSuiteCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type TestSuiteCallerRaw struct {
+ Contract *TestSuiteCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// TestSuiteTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type TestSuiteTransactorRaw struct {
+ Contract *TestSuiteTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewTestSuite creates a new instance of TestSuite, bound to a specific deployed contract.
+func NewTestSuite(address common.Address, backend bind.ContractBackend) (*TestSuite, error) {
+ contract, err := bindTestSuite(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &TestSuite{TestSuiteCaller: TestSuiteCaller{contract: contract}, TestSuiteTransactor: TestSuiteTransactor{contract: contract}, TestSuiteFilterer: TestSuiteFilterer{contract: contract}}, nil
+}
+
+// NewTestSuiteCaller creates a new read-only instance of TestSuite, bound to a specific deployed contract.
+func NewTestSuiteCaller(address common.Address, caller bind.ContractCaller) (*TestSuiteCaller, error) {
+ contract, err := bindTestSuite(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TestSuiteCaller{contract: contract}, nil
+}
+
+// NewTestSuiteTransactor creates a new write-only instance of TestSuite, bound to a specific deployed contract.
+func NewTestSuiteTransactor(address common.Address, transactor bind.ContractTransactor) (*TestSuiteTransactor, error) {
+ contract, err := bindTestSuite(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TestSuiteTransactor{contract: contract}, nil
+}
+
+// NewTestSuiteFilterer creates a new log filterer instance of TestSuite, bound to a specific deployed contract.
+func NewTestSuiteFilterer(address common.Address, filterer bind.ContractFilterer) (*TestSuiteFilterer, error) {
+ contract, err := bindTestSuite(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &TestSuiteFilterer{contract: contract}, nil
+}
+
+// bindTestSuite binds a generic wrapper to an already deployed contract.
+func bindTestSuite(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := TestSuiteMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_TestSuite *TestSuiteRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TestSuite.Contract.TestSuiteCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_TestSuite *TestSuiteRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.Contract.TestSuiteTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_TestSuite *TestSuiteRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TestSuite.Contract.TestSuiteTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_TestSuite *TestSuiteCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TestSuite.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_TestSuite *TestSuiteTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_TestSuite *TestSuiteTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TestSuite.Contract.contract.Transact(opts, method, params...)
+}
+
+// Echo is a paid mutator transaction binding the contract method 0x34d6d9be.
+//
+// Solidity: function Echo(uint256 x) returns()
+func (_TestSuite *TestSuiteTransactor) Echo(opts *bind.TransactOpts, x *big.Int) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Echo", x)
+}
+
+// Echo is a paid mutator transaction binding the contract method 0x34d6d9be.
+//
+// Solidity: function Echo(uint256 x) returns()
+func (_TestSuite *TestSuiteSession) Echo(x *big.Int) (*types.Transaction, error) {
+ return _TestSuite.Contract.Echo(&_TestSuite.TransactOpts, x)
+}
+
+// Echo is a paid mutator transaction binding the contract method 0x34d6d9be.
+//
+// Solidity: function Echo(uint256 x) returns()
+func (_TestSuite *TestSuiteTransactorSession) Echo(x *big.Int) (*types.Transaction, error) {
+ return _TestSuite.Contract.Echo(&_TestSuite.TransactOpts, x)
+}
+
+// Echo0 is a paid mutator transaction binding the contract method 0xdb84d7c0.
+//
+// Solidity: function Echo(string x) returns()
+func (_TestSuite *TestSuiteTransactor) Echo0(opts *bind.TransactOpts, x string) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Echo0", x)
+}
+
+// Echo0 is a paid mutator transaction binding the contract method 0xdb84d7c0.
+//
+// Solidity: function Echo(string x) returns()
+func (_TestSuite *TestSuiteSession) Echo0(x string) (*types.Transaction, error) {
+ return _TestSuite.Contract.Echo0(&_TestSuite.TransactOpts, x)
+}
+
+// Echo0 is a paid mutator transaction binding the contract method 0xdb84d7c0.
+//
+// Solidity: function Echo(string x) returns()
+func (_TestSuite *TestSuiteTransactorSession) Echo0(x string) (*types.Transaction, error) {
+ return _TestSuite.Contract.Echo0(&_TestSuite.TransactOpts, x)
+}
+
+// EchoingFallback is a paid mutator transaction binding the contract method 0xb4a81808.
+//
+// Solidity: function EchoingFallback(bytes input) returns()
+func (_TestSuite *TestSuiteTransactor) EchoingFallback(opts *bind.TransactOpts, input []byte) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "EchoingFallback", input)
+}
+
+// EchoingFallback is a paid mutator transaction binding the contract method 0xb4a81808.
+//
+// Solidity: function EchoingFallback(bytes input) returns()
+func (_TestSuite *TestSuiteSession) EchoingFallback(input []byte) (*types.Transaction, error) {
+ return _TestSuite.Contract.EchoingFallback(&_TestSuite.TransactOpts, input)
+}
+
+// EchoingFallback is a paid mutator transaction binding the contract method 0xb4a81808.
+//
+// Solidity: function EchoingFallback(bytes input) returns()
+func (_TestSuite *TestSuiteTransactorSession) EchoingFallback(input []byte) (*types.Transaction, error) {
+ return _TestSuite.Contract.EchoingFallback(&_TestSuite.TransactOpts, input)
+}
+
+// Extract is a paid mutator transaction binding the contract method 0xad8108a4.
+//
+// Solidity: function Extract((int256) x) returns()
+func (_TestSuite *TestSuiteTransactor) Extract(opts *bind.TransactOpts, x IPrecompileWrapper) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Extract", x)
+}
+
+// Extract is a paid mutator transaction binding the contract method 0xad8108a4.
+//
+// Solidity: function Extract((int256) x) returns()
+func (_TestSuite *TestSuiteSession) Extract(x IPrecompileWrapper) (*types.Transaction, error) {
+ return _TestSuite.Contract.Extract(&_TestSuite.TransactOpts, x)
+}
+
+// Extract is a paid mutator transaction binding the contract method 0xad8108a4.
+//
+// Solidity: function Extract((int256) x) returns()
+func (_TestSuite *TestSuiteTransactorSession) Extract(x IPrecompileWrapper) (*types.Transaction, error) {
+ return _TestSuite.Contract.Extract(&_TestSuite.TransactOpts, x)
+}
+
+// HashPacked is a paid mutator transaction binding the contract method 0xd7cc1f37.
+//
+// Solidity: function HashPacked(uint256 x, bytes2 y, address z) returns()
+func (_TestSuite *TestSuiteTransactor) HashPacked(opts *bind.TransactOpts, x *big.Int, y [2]byte, z common.Address) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "HashPacked", x, y, z)
+}
+
+// HashPacked is a paid mutator transaction binding the contract method 0xd7cc1f37.
+//
+// Solidity: function HashPacked(uint256 x, bytes2 y, address z) returns()
+func (_TestSuite *TestSuiteSession) HashPacked(x *big.Int, y [2]byte, z common.Address) (*types.Transaction, error) {
+ return _TestSuite.Contract.HashPacked(&_TestSuite.TransactOpts, x, y, z)
+}
+
+// HashPacked is a paid mutator transaction binding the contract method 0xd7cc1f37.
+//
+// Solidity: function HashPacked(uint256 x, bytes2 y, address z) returns()
+func (_TestSuite *TestSuiteTransactorSession) HashPacked(x *big.Int, y [2]byte, z common.Address) (*types.Transaction, error) {
+ return _TestSuite.Contract.HashPacked(&_TestSuite.TransactOpts, x, y, z)
+}
+
+// NeitherViewNorPure is a paid mutator transaction binding the contract method 0xa7263000.
+//
+// Solidity: function NeitherViewNorPure() returns()
+func (_TestSuite *TestSuiteTransactor) NeitherViewNorPure(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "NeitherViewNorPure")
+}
+
+// NeitherViewNorPure is a paid mutator transaction binding the contract method 0xa7263000.
+//
+// Solidity: function NeitherViewNorPure() returns()
+func (_TestSuite *TestSuiteSession) NeitherViewNorPure() (*types.Transaction, error) {
+ return _TestSuite.Contract.NeitherViewNorPure(&_TestSuite.TransactOpts)
+}
+
+// NeitherViewNorPure is a paid mutator transaction binding the contract method 0xa7263000.
+//
+// Solidity: function NeitherViewNorPure() returns()
+func (_TestSuite *TestSuiteTransactorSession) NeitherViewNorPure() (*types.Transaction, error) {
+ return _TestSuite.Contract.NeitherViewNorPure(&_TestSuite.TransactOpts)
+}
+
+// Pure is a paid mutator transaction binding the contract method 0xf5ad2fb8.
+//
+// Solidity: function Pure() returns()
+func (_TestSuite *TestSuiteTransactor) Pure(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Pure")
+}
+
+// Pure is a paid mutator transaction binding the contract method 0xf5ad2fb8.
+//
+// Solidity: function Pure() returns()
+func (_TestSuite *TestSuiteSession) Pure() (*types.Transaction, error) {
+ return _TestSuite.Contract.Pure(&_TestSuite.TransactOpts)
+}
+
+// Pure is a paid mutator transaction binding the contract method 0xf5ad2fb8.
+//
+// Solidity: function Pure() returns()
+func (_TestSuite *TestSuiteTransactorSession) Pure() (*types.Transaction, error) {
+ return _TestSuite.Contract.Pure(&_TestSuite.TransactOpts)
+}
+
+// RevertWith is a paid mutator transaction binding the contract method 0xa93cbd97.
+//
+// Solidity: function RevertWith(bytes err) returns()
+func (_TestSuite *TestSuiteTransactor) RevertWith(opts *bind.TransactOpts, err []byte) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "RevertWith", err)
+}
+
+// RevertWith is a paid mutator transaction binding the contract method 0xa93cbd97.
+//
+// Solidity: function RevertWith(bytes err) returns()
+func (_TestSuite *TestSuiteSession) RevertWith(err []byte) (*types.Transaction, error) {
+ return _TestSuite.Contract.RevertWith(&_TestSuite.TransactOpts, err)
+}
+
+// RevertWith is a paid mutator transaction binding the contract method 0xa93cbd97.
+//
+// Solidity: function RevertWith(bytes err) returns()
+func (_TestSuite *TestSuiteTransactorSession) RevertWith(err []byte) (*types.Transaction, error) {
+ return _TestSuite.Contract.RevertWith(&_TestSuite.TransactOpts, err)
+}
+
+// Self is a paid mutator transaction binding the contract method 0xc62c692f.
+//
+// Solidity: function Self() returns()
+func (_TestSuite *TestSuiteTransactor) Self(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Self")
+}
+
+// Self is a paid mutator transaction binding the contract method 0xc62c692f.
+//
+// Solidity: function Self() returns()
+func (_TestSuite *TestSuiteSession) Self() (*types.Transaction, error) {
+ return _TestSuite.Contract.Self(&_TestSuite.TransactOpts)
+}
+
+// Self is a paid mutator transaction binding the contract method 0xc62c692f.
+//
+// Solidity: function Self() returns()
+func (_TestSuite *TestSuiteTransactorSession) Self() (*types.Transaction, error) {
+ return _TestSuite.Contract.Self(&_TestSuite.TransactOpts)
+}
+
+// Transfer is a paid mutator transaction binding the contract method 0x406dade3.
+//
+// Solidity: function Transfer() returns()
+func (_TestSuite *TestSuiteTransactor) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "Transfer")
+}
+
+// Transfer is a paid mutator transaction binding the contract method 0x406dade3.
+//
+// Solidity: function Transfer() returns()
+func (_TestSuite *TestSuiteSession) Transfer() (*types.Transaction, error) {
+ return _TestSuite.Contract.Transfer(&_TestSuite.TransactOpts)
+}
+
+// Transfer is a paid mutator transaction binding the contract method 0x406dade3.
+//
+// Solidity: function Transfer() returns()
+func (_TestSuite *TestSuiteTransactorSession) Transfer() (*types.Transaction, error) {
+ return _TestSuite.Contract.Transfer(&_TestSuite.TransactOpts)
+}
+
+// View is a paid mutator transaction binding the contract method 0x1686f265.
+//
+// Solidity: function View() returns()
+func (_TestSuite *TestSuiteTransactor) View(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TestSuite.contract.Transact(opts, "View")
+}
+
+// View is a paid mutator transaction binding the contract method 0x1686f265.
+//
+// Solidity: function View() returns()
+func (_TestSuite *TestSuiteSession) View() (*types.Transaction, error) {
+ return _TestSuite.Contract.View(&_TestSuite.TransactOpts)
+}
+
+// View is a paid mutator transaction binding the contract method 0x1686f265.
+//
+// Solidity: function View() returns()
+func (_TestSuite *TestSuiteTransactorSession) View() (*types.Transaction, error) {
+ return _TestSuite.Contract.View(&_TestSuite.TransactOpts)
+}
+
+// TestSuiteCalledIterator is returned from FilterCalled and is used to iterate over the raw logs and unpacked data for Called events raised by the TestSuite contract.
+type TestSuiteCalledIterator struct {
+ Event *TestSuiteCalled // Event containing the contract specifics and raw log
+
+ contract *bind.BoundContract // Generic contract to use for unpacking event data
+ event string // Event name to use for unpacking event data
+
+ logs chan types.Log // Log channel receiving the found contract events
+ sub ethereum.Subscription // Subscription for errors, completion and termination
+ done bool // Whether the subscription completed delivering logs
+ fail error // Occurred error to stop iteration
+}
+
+// Next advances the iterator to the subsequent event, returning whether there
+// are any more events found. In case of a retrieval or parsing error, false is
+// returned and Error() can be queried for the exact failure.
+func (it *TestSuiteCalledIterator) Next() bool {
+ // If the iterator failed, stop iterating
+ if it.fail != nil {
+ return false
+ }
+ // If the iterator completed, deliver directly whatever's available
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TestSuiteCalled)
+ if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
+ it.fail = err
+ return false
+ }
+ it.Event.Raw = log
+ return true
+
+ default:
+ return false
+ }
+ }
+ // Iterator still in progress, wait for either a data or an error event
+ select {
+ case log := <-it.logs:
+ it.Event = new(TestSuiteCalled)
+ if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
+ it.fail = err
+ return false
+ }
+ it.Event.Raw = log
+ return true
+
+ case err := <-it.sub.Err():
+ it.done = true
+ it.fail = err
+ return it.Next()
+ }
+}
+
+// Error returns any retrieval or parsing error occurred during filtering.
+func (it *TestSuiteCalledIterator) Error() error {
+ return it.fail
+}
+
+// Close terminates the iteration process, releasing any pending underlying
+// resources.
+func (it *TestSuiteCalledIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+// TestSuiteCalled represents a Called event raised by the TestSuite contract.
+type TestSuiteCalled struct {
+ Arg0 string
+ Raw types.Log // Blockchain specific contextual infos
+}
+
+// FilterCalled is a free log retrieval operation binding the contract event 0x3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a.
+//
+// Solidity: event Called(string func)
+func (_TestSuite *TestSuiteFilterer) FilterCalled(opts *bind.FilterOpts) (*TestSuiteCalledIterator, error) {
+
+ logs, sub, err := _TestSuite.contract.FilterLogs(opts, "Called")
+ if err != nil {
+ return nil, err
+ }
+ return &TestSuiteCalledIterator{contract: _TestSuite.contract, event: "Called", logs: logs, sub: sub}, nil
+}
+
+// WatchCalled is a free log subscription operation binding the contract event 0x3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a.
+//
+// Solidity: event Called(string func)
+func (_TestSuite *TestSuiteFilterer) WatchCalled(opts *bind.WatchOpts, sink chan<- *TestSuiteCalled) (event.Subscription, error) {
+
+ logs, sub, err := _TestSuite.contract.WatchLogs(opts, "Called")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+ // New log arrived, parse the event and forward to the user
+ event := new(TestSuiteCalled)
+ if err := _TestSuite.contract.UnpackLog(event, "Called", log); err != nil {
+ return err
+ }
+ event.Raw = log
+
+ select {
+ case sink <- event:
+ case err := <-sub.Err():
+ return err
+ case <-quit:
+ return nil
+ }
+ case err := <-sub.Err():
+ return err
+ case <-quit:
+ return nil
+ }
+ }
+ }), nil
+}
+
+// ParseCalled is a log parse operation binding the contract event 0x3fd5724095fcb65d3b7e6d79ac130db7e9dbf891d59bb0da292d471bc40d564a.
+//
+// Solidity: event Called(string func)
+func (_TestSuite *TestSuiteFilterer) ParseCalled(log types.Log) (*TestSuiteCalled, error) {
+ event := new(TestSuiteCalled)
+ if err := _TestSuite.contract.UnpackLog(event, "Called", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}