Skip to content

Commit

Permalink
Add eth_call override (#240)
Browse files Browse the repository at this point in the history
* Add eth_call override

* Update Changelog
  • Loading branch information
ferranbt authored Mar 26, 2023
1 parent f090936 commit 15b1df4
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 0.1.4 (Unreleased)

- feat: Add override to `eth_call` request [[GH-240](https://github.com/umbracle/ethgo/issues/240)]
- fix: Recovery of typed transactions [[GH-238](https://github.com/umbracle/ethgo/issues/238)]
- fix: Parse `nonce` and `mixHash` on `Block` [[GH-228](https://github.com/umbracle/ethgo/issues/228)]
- feat: `abi` decodes function string in multilines [[GH-212](https://github.com/umbracle/ethgo/issues/212)]
Expand Down
9 changes: 7 additions & 2 deletions jsonrpc/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,14 @@ func (e *Eth) GasPrice() (uint64, error) {
}

// Call executes a new message call immediately without creating a transaction on the block chain.
func (e *Eth) Call(msg *ethgo.CallMsg, block ethgo.BlockNumber) (string, error) {
func (e *Eth) Call(msg *ethgo.CallMsg, block ethgo.BlockNumber, override ...*ethgo.StateOverride) (string, error) {
var cleanOverride *ethgo.StateOverride
if len(override) == 1 && override[0] != nil {
cleanOverride = override[0]
}

var out string
if err := e.c.Call("eth_call", &out, msg, block.String()); err != nil {
if err := e.c.Call("eth_call", &out, msg, block.String(), cleanOverride); err != nil {
return "", err
}
return out, nil
Expand Down
49 changes: 49 additions & 0 deletions jsonrpc/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/umbracle/ethgo"
"github.com/umbracle/ethgo/abi"
"github.com/umbracle/ethgo/testutil"
)

Expand Down Expand Up @@ -245,6 +246,54 @@ func TestEthChainID(t *testing.T) {
})
}

func TestEthCall(t *testing.T) {
s := testutil.NewTestServer(t)

c, _ := NewClient(s.HTTPAddr())
cc := &testutil.Contract{}

// add global variables
cc.AddCallback(func() string {
return "uint256 val = 1;"
})

// add setter method
cc.AddCallback(func() string {
return `function getValue() public returns (uint256) {
return val;
}`
})

_, addr, err := s.DeployContract(cc)
require.NoError(t, err)

input := abi.MustNewMethod("function getValue() public returns (uint256)").ID()

resp, err := c.Eth().Call(&ethgo.CallMsg{To: &addr, Data: input}, ethgo.Latest)
require.NoError(t, err)

require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resp)

nonce := uint64(1)

// override the state
override := &ethgo.StateOverride{
addr: ethgo.OverrideAccount{
Nonce: &nonce,
Balance: big.NewInt(1),
StateDiff: &map[ethgo.Hash]ethgo.Hash{
// storage slot 0 stores the 'val' uint256 value
{0x0}: {0x3},
},
},
}

resp, err = c.Eth().Call(&ethgo.CallMsg{To: &addr, Data: input}, ethgo.Latest, override)
require.NoError(t, err)

require.Equal(t, "0x0300000000000000000000000000000000000000000000000000000000000000", resp)
}

func TestEthGetNonce(t *testing.T) {
s := testutil.NewTestServer(t)

Expand Down
10 changes: 10 additions & 0 deletions structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,3 +392,13 @@ func completeHex(str string, num int) []byte {
}
return []byte("0x" + str)
}

type OverrideAccount struct {
Nonce *uint64
Code *[]byte
Balance *big.Int
State *map[Hash]Hash
StateDiff *map[Hash]Hash
}

type StateOverride map[Address]OverrideAccount
38 changes: 38 additions & 0 deletions structs_marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,41 @@ func (l *LogFilter) MarshalJSON() ([]byte, error) {
defaultArena.Put(a)
return res, nil
}

func (s StateOverride) MarshalJSON() ([]byte, error) {
a := defaultArena.Get()

o := a.NewObject()
for addr, obj := range s {
oo := a.NewObject()
if obj.Nonce != nil {
oo.Set("nonce", a.NewString(fmt.Sprintf("0x%x", *obj.Nonce)))
}
if obj.Balance != nil {
oo.Set("balance", a.NewString(fmt.Sprintf("0x%x", obj.Balance)))
}
if obj.Code != nil {
oo.Set("code", a.NewString("0x"+hex.EncodeToString(*obj.Code)))
}
if obj.State != nil {
ooo := a.NewObject()
for k, v := range *obj.State {
ooo.Set(k.String(), a.NewString(v.String()))
}
oo.Set("state", ooo)
}
if obj.StateDiff != nil {
ooo := a.NewObject()
for k, v := range *obj.StateDiff {
ooo.Set(k.String(), a.NewString(v.String()))
}
oo.Set("stateDiff", ooo)
}
o.Set(addr.String(), oo)
}

res := o.MarshalTo(nil)
defaultArena.Put(a)

return res, nil
}
27 changes: 27 additions & 0 deletions structs_marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package ethgo

import (
"encoding/json"
"math/big"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func generateHashPtr(input string) *Hash {
Expand Down Expand Up @@ -94,3 +96,28 @@ func TestLogFilter_MarshalJSON(t *testing.T) {
})
}
}

func TestMarshal_StateOverride(t *testing.T) {
nonce := uint64(1)
code := []byte{0x1}

o := StateOverride{
{0x0}: OverrideAccount{
Nonce: &nonce,
Balance: big.NewInt(1),
Code: &code,
State: &map[Hash]Hash{
{0x1}: {0x1},
},
StateDiff: &map[Hash]Hash{
{0x1}: {0x1},
},
},
}

res, err := o.MarshalJSON()
require.NoError(t, err)

expected := `{"0x0000000000000000000000000000000000000000":{"nonce":"0x1","balance":"0x1","code":"0x01","state":{"0x0100000000000000000000000000000000000000000000000000000000000000":"0x0100000000000000000000000000000000000000000000000000000000000000"},"stateDiff":{"0x0100000000000000000000000000000000000000000000000000000000000000":"0x0100000000000000000000000000000000000000000000000000000000000000"}}}`
require.Equal(t, expected, string(res))
}

0 comments on commit 15b1df4

Please sign in to comment.