Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions vms/saevm/sae/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ go_test(
"@com_github_ava_labs_libevm//crypto",
"@com_github_ava_labs_libevm//eth/tracers/logger",
"@com_github_ava_labs_libevm//ethclient",
"@com_github_ava_labs_libevm//ethclient/gethclient",
"@com_github_ava_labs_libevm//ethdb",
"@com_github_ava_labs_libevm//libevm",
"@com_github_ava_labs_libevm//libevm/ethapi",
Expand Down Expand Up @@ -209,6 +210,7 @@ go_test(
"@com_github_ava_labs_libevm//crypto",
"@com_github_ava_labs_libevm//eth/tracers/logger",
"@com_github_ava_labs_libevm//ethclient",
"@com_github_ava_labs_libevm//ethclient/gethclient",
"@com_github_ava_labs_libevm//ethdb",
"@com_github_ava_labs_libevm//libevm",
"@com_github_ava_labs_libevm//libevm/ethapi",
Expand Down
13 changes: 11 additions & 2 deletions vms/saevm/sae/rpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,27 @@ func (b *backend) server(filter *filters.FilterAPI) (*rpc.Server, error) {
{"eth", ethapi.NewEthereumAPI(b)},
// Standard Ethereum node APIs:
// - eth_blockNumber
// - eth_call
// - eth_chainId
// - eth_estimateGas
// - eth_getBalance
// - eth_getBlockByHash
// - eth_getBlockByNumber
// - eth_getBlockReceipts
// - eth_getCode
// - eth_getProof
// - eth_getStorageAt
// - eth_getUncleByBlockHashAndIndex
// - eth_getUncleByBlockNumberAndIndex
// - eth_getUncleCountByBlockHash
// - eth_getUncleCountByBlockNumber
//
// geth-specific APIs:
// Geth-specific APIs:
// - eth_createAccessList
// - eth_getHeaderByHash
// - eth_getHeaderByNumber
//
// Undocumented APIs:
// - eth_getBlockReceipts
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This RPC is actually already supported/tested, but it wasn't included in the list. When going through the list to add the ones for this PR, I thought I'd include it.

{"eth", &blockChainAPI{ethapi.NewBlockChainAPI(b), b}},
// Standard Ethereum node APIs:
// - eth_getBlockTransactionCountByHash
Expand Down
86 changes: 76 additions & 10 deletions vms/saevm/sae/rpc_stateful_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"github.com/ava-labs/libevm/core/vm"
"github.com/ava-labs/libevm/crypto"
"github.com/ava-labs/libevm/eth/tracers/logger"
"github.com/ava-labs/libevm/ethclient/gethclient"
"github.com/ava-labs/libevm/params"
"github.com/ava-labs/libevm/rpc"
"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -199,7 +200,7 @@
sut.testRPC(ctx, t, tests...)
}

func TestEthCall(t *testing.T) {
func TestStatefulRPCs(t *testing.T) {
opt, vmTime := withVMTime(t, time.Unix(saeparams.TauSeconds, 0))
ctx, sut := newSUT(t, 1, opt)

Expand Down Expand Up @@ -236,6 +237,26 @@
_, ok := sut.rawVM.consensusCritical.Load(b.Hash())
require.Falsef(t, ok, "%T[%#x] still in VM memory", b, b.Hash())

// Storage key for balances[recv] at mapping slot 0:
// keccak256(abi.encode(address, uint256(0)))
storageKey := crypto.Keccak256Hash(
common.LeftPadBytes(recv.Bytes(), 32),
common.Hash{}.Bytes(),
Comment on lines +204 to +205
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit/question: should we actually use abi.encode from abi package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how much of an improvement that would be -- I think manually encoding is fine. There's a lot of ABI setup required, and the goal is test the RPCs. If you feel strongly I can change it.

)
storageKeyHex := storageKey.Hex()

callMsg := ethereum.CallMsg{
From: sut.wallet.Addresses()[0],
To: &escrowAddr,
Data: escrow.CallDataForBalance(recv),
}

gc := gethclient.New(sut.rpcClient)

wantBig := big.NewInt(val)
wantBytes := uint256.NewInt(val).PaddedBytes(32)
wantCode := escrow.ByteCode()

tests := []struct {
name string
num rpc.BlockNumber
Expand All @@ -251,15 +272,60 @@
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
msg := ethereum.CallMsg{
To: &escrowAddr,
Data: escrow.CallDataForBalance(recv),
}

got, err := sut.CallContract(ctx, msg, big.NewInt(int64(tt.num)))
t.Logf("%T.CallContract(%+v, %d)", sut.Client, msg, tt.num) // avoids having to repeat in failure messages
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name hierarchy now provides this information

require.NoError(t, err)
assert.Equal(t, uint256.NewInt(val).PaddedBytes(32), got)
blockNum := big.NewInt(int64(tt.num))

t.Run("eth_call", func(t *testing.T) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got, err := sut.CallContract(ctx, callMsg, blockNum)
require.NoError(t, err, "CallContract()")
assert.Equal(t, wantBytes, got, "CallContract() result")

Check warning on line 280 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Equal`" continues on failure; consider require for fail-fast
})

t.Run("eth_getBalance", func(t *testing.T) {
got, err := sut.BalanceAt(ctx, escrowAddr, blockNum)
require.NoError(t, err, "BalanceAt()")
require.Zero(t, wantBig.Cmp(got), "BalanceAt(): want %d, got %s", val, got)
Comment thread
JonathanOppenheimer marked this conversation as resolved.
Outdated
})

t.Run("eth_getCode", func(t *testing.T) {
got, err := sut.CodeAt(ctx, escrowAddr, blockNum)
require.NoError(t, err, "CodeAt()")
assert.Equal(t, wantCode, got, "CodeAt() result")

Check warning on line 292 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Equal`" continues on failure; consider require for fail-fast
})

t.Run("eth_getStorageAt", func(t *testing.T) {
got, err := sut.StorageAt(ctx, escrowAddr, storageKey, blockNum)
require.NoError(t, err, "StorageAt()")
assert.Equal(t, wantBytes, got, "StorageAt() result")

Check warning on line 298 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Equal`" continues on failure; consider require for fail-fast
})

t.Run("eth_getProof", func(t *testing.T) {
got, err := gc.GetProof(ctx, escrowAddr, []string{storageKeyHex}, blockNum)
require.NoError(t, err, "GetProof()")
require.NotNil(t, got, "GetProof() result")

assert.NotEmpty(t, got.AccountProof, "GetProof() accountProof")

Check warning on line 306 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.NotEmpty`" continues on failure; consider require for fail-fast
require.Zero(t, wantBig.Cmp(got.Balance), "GetProof() balance: want %d, got %s", val, got.Balance)
Comment thread
JonathanOppenheimer marked this conversation as resolved.
Outdated
Comment thread
JonathanOppenheimer marked this conversation as resolved.
Outdated

require.Len(t, got.StorageProof, 1, "GetProof() storageProof length")
assert.NotEmpty(t, got.StorageProof[0].Proof, "GetProof() storageProof[0].Proof")

Check warning on line 310 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.NotEmpty`" continues on failure; consider require for fail-fast
require.Zero(t, wantBig.Cmp(got.StorageProof[0].Value), "GetProof() storageProof[0].Value: want %d, got %s", val, got.StorageProof[0].Value)
Comment thread
JonathanOppenheimer marked this conversation as resolved.
Outdated
})
})
}

// eth_estimateGas and eth_createAccessList don't accept a block number
// parameter via ethclient/gethclient, so they always run against latest.
t.Run("eth_estimateGas", func(t *testing.T) {
got, err := sut.EstimateGas(ctx, callMsg)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two tests are inherently different, given that they don't need to run in the table. I would put them in a separate test, and just create a new callMsg

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I can do so, but there is just a lot of shared setup for these, which is why I put them in here... I can see how I can split them out.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can actually do a nice helper function for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dif is bigger because we can use the helper function in other places, but I think this is a big improvement.

require.NoError(t, err, "EstimateGas()")
assert.Positive(t, got, "EstimateGas() result")

Check warning on line 321 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Positive`" continues on failure; consider require for fail-fast
})

t.Run("eth_createAccessList", func(t *testing.T) {
al, gas, errMsg, err := gc.CreateAccessList(ctx, callMsg)
require.NoError(t, err, "CreateAccessList()")
assert.Empty(t, errMsg, "CreateAccessList() error message")

Check warning on line 327 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Empty`" continues on failure; consider require for fail-fast
assert.NotEmpty(t, al, "CreateAccessList() access list")

Check warning on line 328 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.NotEmpty`" continues on failure; consider require for fail-fast
assert.Positive(t, gas, "CreateAccessList() gasUsed")

Check warning on line 329 in vms/saevm/sae/rpc_stateful_test.go

View workflow job for this annotation

GitHub Actions / Lint

`assert.Positive`" continues on failure; consider require for fail-fast
})
}
Loading