Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 8 additions & 4 deletions rpc/contracts/direct_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ func NewDirectBackend(api jsonrpc.EthAPI) DirectBackend {
}

func (b DirectBackend) CodeAt(ctx context.Context, account common.Address, blockNum *uint256.Int) ([]byte, error) {
return b.api.GetCode(ctx, account, BlockNumArg(blockNum))
blockNrOrHash := BlockNumArg(blockNum)
return b.api.GetCode(ctx, account, &blockNrOrHash)
}

func (b DirectBackend) CallContract(ctx context.Context, callMsg bind.CallMsg, blockNum *uint256.Int) ([]byte, error) {
Expand All @@ -59,11 +60,13 @@ func (b DirectBackend) CallContract(ctx context.Context, callMsg bind.CallMsg, b
}

func (b DirectBackend) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
return b.api.GetCode(ctx, account, PendingBlockNumArg())
blockNrOrHash := PendingBlockNumArg()
return b.api.GetCode(ctx, account, &blockNrOrHash)
}

func (b DirectBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
count, err := b.api.GetTransactionCount(ctx, account, PendingBlockNumArg())
blockNrOrHash := PendingBlockNumArg()
count, err := b.api.GetTransactionCount(ctx, account, &blockNrOrHash)
if err != nil {
return 0, err
}
Expand All @@ -79,7 +82,8 @@ func (b DirectBackend) NonceAt(ctx context.Context, account common.Address, bloc
blockRef = rpc.BlockNumber(blockNumber.Int64()).AsBlockReference()
}

count, err := b.api.GetTransactionCount(ctx, account, rpc.BlockNumberOrHash(blockRef))
blockNrOrHash := rpc.BlockNumberOrHash(blockRef)
count, err := b.api.GetTransactionCount(ctx, account, &blockNrOrHash)
if err != nil {
return 0, err
}
Expand Down
2 changes: 1 addition & 1 deletion rpc/jsonrpc/corner_cases_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestNotFoundMustReturnError(t *testing.T) {
api := newEthApiForTest(newBaseApiForTest(m), m.DB, nil, nil)
ctx := context.Background()

a, err := api.GetBalance(ctx, common.Address{}, rpc.BlockNumberOrHashWithNumber(10_000))
a, err := api.GetBalance(ctx, common.Address{}, bnhPtr(rpc.BlockNumberOrHashWithNumber(10_000)))
assertions.Nil(a)
assertions.EqualError(err, "block not found: 10000")
}
15 changes: 10 additions & 5 deletions rpc/jsonrpc/eth_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func (api *APIImpl) stateReaderAt(ctx context.Context, blockNrOrHash rpc.BlockNu
}

// GetBalance implements eth_getBalance. Returns the balance of an account for a given address.
func (api *APIImpl) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
func (api *APIImpl) GetBalance(ctx context.Context, address common.Address, blockNrOrHashArg *rpc.BlockNumberOrHash) (*hexutil.Big, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
tx, reader, err := api.stateReaderAt(ctx, blockNrOrHash)
if err != nil {
return nil, err
Expand All @@ -93,7 +94,8 @@ func (api *APIImpl) GetBalance(ctx context.Context, address common.Address, bloc
}

// GetTransactionCount implements eth_getTransactionCount. Returns the number of transactions sent from an address (the nonce).
func (api *APIImpl) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
func (api *APIImpl) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHashArg *rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
if blockNrOrHash.BlockNumber != nil && *blockNrOrHash.BlockNumber == rpc.PendingBlockNumber {
reply, err := api.txPool.Nonce(ctx, &txpoolproto.NonceRequest{
Address: gointerfaces.ConvertAddressToH160(address),
Expand Down Expand Up @@ -122,7 +124,8 @@ func (api *APIImpl) GetTransactionCount(ctx context.Context, address common.Addr
}

// GetCode implements eth_getCode. Returns the byte code at a given address (if it's a smart contract).
func (api *APIImpl) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
func (api *APIImpl) GetCode(ctx context.Context, address common.Address, blockNrOrHashArg *rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
tx, reader, err := api.stateReaderAt(ctx, blockNrOrHash)
if err != nil {
return nil, err
Expand All @@ -143,7 +146,8 @@ func (api *APIImpl) GetCode(ctx context.Context, address common.Address, blockNr

// GetStorageValues implements eth_getStorageValues. Returns the values of multiple
// storage slots for multiple accounts in a single request.
func (api *APIImpl) GetStorageValues(ctx context.Context, requests map[common.Address][]common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address][]hexutil.Bytes, error) {
func (api *APIImpl) GetStorageValues(ctx context.Context, requests map[common.Address][]common.Hash, blockNrOrHashArg *rpc.BlockNumberOrHash) (map[common.Address][]hexutil.Bytes, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
var totalSlots int

for _, keys := range requests {
Expand Down Expand Up @@ -204,7 +208,8 @@ func (api *APIImpl) GetStorageValues(ctx context.Context, requests map[common.Ad
}

// GetStorageAt implements eth_getStorageAt. Returns the value from a storage position at a given address.
func (api *APIImpl) GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHash rpc.BlockNumberOrHash) (string, error) {
func (api *APIImpl) GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHashArg *rpc.BlockNumberOrHash) (string, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
var empty []byte
// Validation for index i.e. storage slot is non-standard: it can be interpreted as QUANTITY (stricter) or as DATA (like Hive tests do).
// Waiting for a spec, we choose the latter because it's more general, but we check that the length is not greater than 64 hex-digits.
Expand Down
12 changes: 6 additions & 6 deletions rpc/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ type EthAPI interface {

// Account related (see ./eth_accounts.go)
Accounts(ctx context.Context) ([]common.Address, error)
GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error)
GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error)
GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHash rpc.BlockNumberOrHash) (string, error)
GetStorageValues(ctx context.Context, requests map[common.Address][]common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (map[common.Address][]hexutil.Bytes, error)
GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error)
GetBalance(ctx context.Context, address common.Address, blockNrOrHash *rpc.BlockNumberOrHash) (*hexutil.Big, error)
GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash *rpc.BlockNumberOrHash) (*hexutil.Uint64, error)
GetStorageAt(ctx context.Context, address common.Address, index string, blockNrOrHash *rpc.BlockNumberOrHash) (string, error)
GetStorageValues(ctx context.Context, requests map[common.Address][]common.Hash, blockNrOrHash *rpc.BlockNumberOrHash) (map[common.Address][]hexutil.Bytes, error)
GetCode(ctx context.Context, address common.Address, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Bytes, error)

// System related (see ./eth_system.go)
BlockNumber(ctx context.Context) (hexutil.Uint64, error)
Expand All @@ -125,7 +125,7 @@ type EthAPI interface {
SendTransaction(_ context.Context, txObject any) (common.Hash, error)
Sign(ctx context.Context, _ common.Address, _ hexutil.Bytes) (hexutil.Bytes, error)
SignTransaction(_ context.Context, txObject any) (common.Hash, error)
GetProof(ctx context.Context, address common.Address, storageKeys []hexutil.Bytes, blockNr rpc.BlockNumberOrHash) (*accounts.AccProofResult, error)
GetProof(ctx context.Context, address common.Address, storageKeys []hexutil.Bytes, blockNr *rpc.BlockNumberOrHash) (*accounts.AccProofResult, error)
CreateAccessList(ctx context.Context, args ethapi.CallArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *ethapi2.StateOverrides, optimizeGas *bool) (*accessListResult, error)

// Mining related (see ./eth_mining.go)
Expand Down
84 changes: 69 additions & 15 deletions rpc/jsonrpc/eth_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func TestGetStorageAt_ByBlockNumber_WithRequireCanonicalDefault(t *testing.T) {
api := newEthApiForTest(newBaseApiForTest(m), m.DB, nil, nil)
addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")

result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithNumber(0))
result, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithNumber(0)))
if err != nil {
t.Errorf("calling GetStorageAt: %v", err)
}
Expand All @@ -127,7 +127,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault(t *testing.T) {
api := newEthApiForTest(newBaseApiForTest(m), m.DB, nil, nil)
addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")

result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), false))
result, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), false)))
if err != nil {
t.Errorf("calling GetStorageAt: %v", err)
}
Expand All @@ -141,7 +141,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue(t *testing.T) {
api := newEthApiForTest(newBaseApiForTest(m), m.DB, nil, nil)
addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")

result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), true))
result, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), true)))
if err != nil {
t.Errorf("calling GetStorageAt: %v", err)
}
Expand All @@ -164,7 +164,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_BlockNotFoundError
}
offChainBlock := offChain.Blocks[0]

if _, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(offChainBlock.Hash(), false)); err != nil {
if _, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(offChainBlock.Hash(), false))); err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("block not found: %s", offChainBlock.Hash().String()) {
t.Errorf("wrong error: %v", err)
}
Expand All @@ -185,7 +185,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_BlockNotFoundError(t
}
offChainBlock := offChain.Blocks[0]

if _, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(offChainBlock.Hash(), true)); err != nil {
if _, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(offChainBlock.Hash(), true))); err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("block not found: %s", offChainBlock.Hash().String()) {
t.Errorf("wrong error: %v", err)
}
Expand All @@ -202,7 +202,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalDefault_NonCanonicalBlock(

orphanedBlock := orphanedChain[0].Blocks[0]

result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(orphanedBlock.Hash(), false))
result, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(orphanedBlock.Hash(), false)))
if err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("hash %s is not currently canonical", orphanedBlock.Hash().String()[2:]) {
t.Errorf("wrong error: %v", err)
Expand All @@ -221,7 +221,7 @@ func TestGetStorageAt_ByBlockHash_WithRequireCanonicalTrue_NonCanonicalBlock(t *

orphanedBlock := orphanedChain[0].Blocks[0]

if _, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(orphanedBlock.Hash(), true)); err != nil {
if _, err := api.GetStorageAt(context.Background(), addr, "0x0", bnhPtr(rpc.BlockNumberOrHashWithHash(orphanedBlock.Hash(), true))); err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("hash %s is not currently canonical", orphanedBlock.Hash().String()[2:]) {
t.Errorf("wrong error: %v", err)
}
Expand Down Expand Up @@ -302,7 +302,7 @@ func TestGetStorageValues_HappyPath(t *testing.T) {

result, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: {slot0, slot1},
}, latest)
}, &latest)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -329,7 +329,7 @@ func TestGetStorageValues_MultipleAddresses(t *testing.T) {
addr2: {slot1, slot2},
addr3: {slot0, slot2},
}
result, err := api.GetStorageValues(context.Background(), request, latest)
result, err := api.GetStorageValues(context.Background(), request, &latest)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -356,7 +356,7 @@ func TestGetStorageValues_MissingSlotReturnsZero(t *testing.T) {

result, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: {common.HexToHash("0xff")},
}, latest)
}, &latest)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -371,7 +371,7 @@ func TestGetStorageValues_EmptyRequestReturnsError(t *testing.T) {

latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)

_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{}, latest)
_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{}, &latest)
if err == nil {
t.Fatal("expected error for empty request")
}
Expand All @@ -394,7 +394,7 @@ func TestGetStorageValues_ExceedingSlotLimitReturnsError(t *testing.T) {

_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: tooMany,
}, latest)
}, &latest)
if err == nil {
t.Fatal("expected error for exceeding slot limit")
}
Expand All @@ -411,7 +411,7 @@ func TestGetStorageValues_ByBlockHash_NonCanonicalBlock(t *testing.T) {

_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: {common.Hash{}},
}, blockNumberOrHash)
}, &blockNumberOrHash)
if err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("hash %s is not currently canonical", orphanedBlock.Hash().String()[2:]) {
t.Errorf("wrong error: %v", err)
Expand All @@ -432,7 +432,7 @@ func TestGetStorageValues_ByBlockHash_WithRequireCanonicalTrue_NonCanonicalBlock

_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: {common.Hash{}},
}, blockNumberOrHash)
}, &blockNumberOrHash)
if err != nil {
if fmt.Sprintf("%v", err) != fmt.Sprintf("hash %s is not currently canonical", orphanedBlock.Hash().String()[2:]) {
t.Errorf("wrong error: %v", err)
Expand All @@ -453,8 +453,62 @@ func TestGetStorageValues_PrunedBlockReturnsError(t *testing.T) {

_, err := api.GetStorageValues(context.Background(), map[common.Address][]common.Hash{
addr1: {common.Hash{}},
}, blockNumberOrHash)
}, &blockNumberOrHash)
if err != nil {
t.Logf("got expected prune error: %v", err)
}
}

// bnhPtr returns a pointer to a BlockNumberOrHash, for the state methods whose
// block parameter is now optional (*rpc.BlockNumberOrHash).
func bnhPtr(b rpc.BlockNumberOrHash) *rpc.BlockNumberOrHash { return &b }

// TestStateMethods_OmittedBlockDefaultsToLatest verifies that an omitted (nil)
// block selector is treated identically to an explicit "latest" selector for each
// state method (per execution-apis: the Block parameter is optional, default
// 'latest'). This exercises the orLatest(nil) path directly.
func TestStateMethods_OmittedBlockDefaultsToLatest(t *testing.T) {
a := assert.New(t)
m, _, _ := rpcdaemontest.CreateTestExecModule(t)
api := newEthApiForTest(newBaseApiForTest(m), m.DB, nil, nil)
ctx := context.Background()
addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)

balNil, err := api.GetBalance(ctx, addr, nil)
a.NoError(err)
balLatest, err := api.GetBalance(ctx, addr, &latest)
a.NoError(err)
a.Equal(balLatest, balNil)

codeNil, err := api.GetCode(ctx, addr, nil)
a.NoError(err)
codeLatest, err := api.GetCode(ctx, addr, &latest)
a.NoError(err)
a.Equal(codeLatest, codeNil)

nonceNil, err := api.GetTransactionCount(ctx, addr, nil)
a.NoError(err)
nonceLatest, err := api.GetTransactionCount(ctx, addr, &latest)
a.NoError(err)
a.Equal(nonceLatest, nonceNil)

storageNil, err := api.GetStorageAt(ctx, addr, "0x0", nil)
a.NoError(err)
storageLatest, err := api.GetStorageAt(ctx, addr, "0x0", &latest)
a.NoError(err)
a.Equal(storageLatest, storageNil)

proofNil, err := api.GetProof(ctx, addr, nil, nil)
a.NoError(err)
proofLatest, err := api.GetProof(ctx, addr, nil, &latest)
a.NoError(err)
a.Equal(proofLatest, proofNil)

req := map[common.Address][]common.Hash{addr: {{}}}
svNil, err := api.GetStorageValues(ctx, req, nil)
a.NoError(err)
svLatest, err := api.GetStorageValues(ctx, req, &latest)
a.NoError(err)
a.Equal(svLatest, svNil)
}
13 changes: 12 additions & 1 deletion rpc/jsonrpc/eth_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ import (

var latestNumOrHash = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)

// orLatest resolves an optional block selector, defaulting to the latest block
// when the caller omitted the parameter (nil). Used by the state-reading methods
// whose Block parameter is optional per execution-apis (default 'latest').
func orLatest(blockNrOrHash *rpc.BlockNumberOrHash) rpc.BlockNumberOrHash {
if blockNrOrHash != nil {
Comment on lines +59 to +63
return *blockNrOrHash
}
return latestNumOrHash
}

const (
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
// allowed to produce in order to speed up calculations.
Expand Down Expand Up @@ -398,7 +408,8 @@ type StorageKeysInfo struct {
}

// GetProof implements eth_getProof partially; Proofs are available only with the `latest` block tag.
func (api *APIImpl) GetProof(ctx context.Context, address common.Address, storageKeys []hexutil.Bytes, blockNrOrHash rpc.BlockNumberOrHash) (*accounts.AccProofResult, error) {
func (api *APIImpl) GetProof(ctx context.Context, address common.Address, storageKeys []hexutil.Bytes, blockNrOrHashArg *rpc.BlockNumberOrHash) (*accounts.AccProofResult, error) {
blockNrOrHash := orLatest(blockNrOrHashArg)
if len(storageKeys) > maxGetProofKeys {
return nil, &rpc.CustomError{
Message: fmt.Sprintf("too many storage keys requested (max %d, got %d)", maxGetProofKeys, len(storageKeys)),
Expand Down
2 changes: 1 addition & 1 deletion rpc/jsonrpc/eth_call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ func TestGetProof(t *testing.T) {
context.Background(),
tt.addr,
tt.storageKeys,
rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.blockNum)),
bnhPtr(rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(tt.blockNum))),
)
if tt.expectedErr != "" {
require.EqualError(t, err, tt.expectedErr)
Expand Down
Loading
Loading