Skip to content

Commit

Permalink
added batch call for StoragesAt as well as tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mralj committed Oct 4, 2024
1 parent c4b24af commit bea23a3
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 15 deletions.
2 changes: 1 addition & 1 deletion core/vm/contracts_rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (c *L1SLoad) Run(input []byte) ([]byte, error) {
ctx = context.Background()
}

res, err := c.L1RpcClient.StorageAt(ctx, contractAddress, contractStorageKeys[0], c.GetLatestL1BlockNumber())
res, err := c.L1RpcClient.StoragesAt(ctx, contractAddress, contractStorageKeys, c.GetLatestL1BlockNumber())
if err != nil {
return nil, err
}
Expand Down
22 changes: 11 additions & 11 deletions core/vm/contracts_rollup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ import (

type MockL1RPCClient struct{}

func (m MockL1RPCClient) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
return common.Hex2Bytes("abab"), nil
func (m MockL1RPCClient) StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) {
// testcase is in format "abab", this makes output lenght 2 bytes
const mockedRespValueSize = 2
mockResp := make([]byte, mockedRespValueSize*len(keys))
for i := range keys {
copy(mockResp[mockedRespValueSize*i:], common.Hex2Bytes("abab"))
}

return mockResp, nil
}

func TestPrecompiledL1SLOAD(t *testing.T) {
Expand All @@ -20,13 +27,6 @@ func TestPrecompiledL1SLOAD(t *testing.T) {
allPrecompiles[rollupL1SloadAddress] = &L1SLoad{}
allPrecompiles.activateL1SLoad(mockL1RPCClient, func() *big.Int { return big1 })

l1SLoadTestcase := precompiledTest{
Name: "L1SLOAD",
Input: "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e864",
Expected: "abab",
Gas: 4000,
NoBenchmark: true,
}

testPrecompiled(rollupL1SloadAddress.Hex(), l1SLoadTestcase, t)
testJson("l1sload", rollupL1SloadAddress.Hex(), t)
testJsonFail("l1sload", rollupL1SloadAddress.Hex(), t)
}
2 changes: 1 addition & 1 deletion core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type Config struct {

// [rollup-geth]
type L1RpcClient interface {
StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)
StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error)
}

// ScopeContext contains the things that are per-call, such as stack and memory,
Expand Down
16 changes: 16 additions & 0 deletions core/vm/testdata/precompiles/fail-l1sload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{
"Name": "L1SLOAD FAIL: input contains only address",
"Input": "a83114A443dA1CecEFC50368531cACE9F37fCCcb",
"ExpectedError": "L1SLOAD input too short",
"Gas": 4000,
"NoBenchmark": true
},
{
"Name": "L1SLOAD FAIL: input key not 32 bytes",
"Input": "a83114A443dA1CecEFC50368531cACE9F37fCCcb112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7122",
"ExpectedError": "L1SLOAD input is malformed",
"Gas": 4000,
"NoBenchmark": true
}
]
24 changes: 24 additions & 0 deletions core/vm/testdata/precompiles/l1sload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"Name": "L1SLOAD: 1 key",
"Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e864",
"Expected": "abab",
"Gas": 4000,
"NoBenchmark": true
},
{
"Name": "L1SLOAD: 2 keys",
"Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e8640112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a",
"Expected": "abababab",
"Gas": 6000,
"NoBenchmark": true
},

{
"Name": "L1SLOAD: 5 keys",
"Input": "C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc22d2c7bb6fc06067df8b0223aec460d1ebb51febb9012bc2554141a4dca08e8640112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a112d016b65e9c617ad9ab60604f772a3620177bada4cdc773d9b6a982d3c2a7a",
"Expected": "abababababababababab",
"Gas": 12000,
"NoBenchmark": true
}
]
38 changes: 38 additions & 0 deletions ethclient/ethclient_rollup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ethclient

import (
"context"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc"
)

// StoragesAt returns the values of keys in the contract storage of the given account.
// The block number can be nil, in which case the value is taken from the latest known block.
func (ec *Client) StoragesAt(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) ([]byte, error) {
results := make([]hexutil.Bytes, len(keys))
reqs := make([]rpc.BatchElem, len(keys))

for i := range reqs {
reqs[i] = rpc.BatchElem{
Method: "eth_getStorageAt",
Args: []interface{}{account, keys[i], toBlockNumArg(blockNumber)},
Result: &results[i],
}
}
if err := ec.c.BatchCallContext(ctx, reqs); err != nil {
return nil, err
}

output := make([]byte, common.HashLength*len(keys))
for i := range reqs {
if reqs[i].Error != nil {
return nil, reqs[i].Error
}
copy(output[i*common.HashLength:], results[i])
}

return output, nil
}
3 changes: 1 addition & 2 deletions params/protocol_params_rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ const (
L1SLoadBaseGas uint64 = 2000 // Base price for L1Sload
L1SLoadPerLoadGas uint64 = 2000 // Per-load price for loading one storage slot
L1SLoadMaxNumStorageSlots = 5 // Max number of storage slots requested in L1Sload precompile
L1SLoadRPCTimeoutInSec = 3
)

var L1SLoadRPCTimeoutInSec = MainnetChainConfig.Clique.Period // After how many ms will RPC call timeout

0 comments on commit bea23a3

Please sign in to comment.