Skip to content

Commit

Permalink
feat(rpc): Implement childstate_getChildStorage RPC call (ChainSafe…
Browse files Browse the repository at this point in the history
…#1832)

* WIP

* WIP

* chore: remove unused comment

* chore: remove unused rpc from state

* chore: ignore unused param

* chore: fix rpc tests

Co-authored-by: Dan Forbes <dan@danforbes.dev>
  • Loading branch information
2 people authored and timwu20 committed Dec 6, 2021
1 parent 541f580 commit 4977d06
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 55 deletions.
1 change: 1 addition & 0 deletions dot/rpc/modules/api_mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
func NewMockStorageAPI() *modulesmocks.MockStorageAPI {
m := new(modulesmocks.MockStorageAPI)
m.On("GetStorage", mock.AnythingOfType("*common.Hash"), mock.AnythingOfType("[]uint8")).Return(nil, nil)
m.On("GetStorageFromChild", mock.AnythingOfType("*common.Hash"), mock.AnythingOfType("[]uint8"), mock.AnythingOfType("[]uint8")).Return(nil, nil)
m.On("Entries", mock.AnythingOfType("*common.Hash")).Return(nil, nil)
m.On("GetStorageByBlockHash", mock.AnythingOfType("common.Hash"), mock.AnythingOfType("[]uint8")).Return(nil, nil)
m.On("RegisterStorageObserver", mock.Anything)
Expand Down
38 changes: 38 additions & 0 deletions dot/rpc/modules/childstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ type GetKeysRequest struct {
Hash *common.Hash
}

// ChildStateStorageRequest holds json fields
type ChildStateStorageRequest struct {
ChildStorageKey []byte `json:"childStorageKey"`
Key []byte `json:"key"`
Hash *common.Hash `json:"block"`
}

// GetStorageHash the request to get the entry child storage hash
type GetStorageHash struct {
KeyChild []byte
Expand Down Expand Up @@ -140,3 +147,34 @@ func (cs *ChildStateModule) GetStorageHash(_ *http.Request, req *GetStorageHash,

return nil
}

// GetStorage returns a child storage entry.
func (cs *ChildStateModule) GetStorage(_ *http.Request, req *ChildStateStorageRequest, res *StateStorageResponse) error {
var (
item []byte
err error
hash common.Hash
)

if req.Hash == nil {
hash = cs.blockAPI.BestBlockHash()
} else {
hash = *req.Hash
}

stateRoot, err := cs.storageAPI.GetStateRootFromBlock(&hash)
if err != nil {
return err
}

item, err = cs.storageAPI.GetStorageFromChild(stateRoot, req.ChildStorageKey, req.Key)
if err != nil {
return err
}

if len(item) > 0 {
*res = StateStorageResponse(common.BytesToHex(item))
}

return nil
}
55 changes: 55 additions & 0 deletions dot/rpc/modules/childstate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package modules

import (
"encoding/hex"
"fmt"
"math/big"
"testing"
Expand Down Expand Up @@ -194,6 +195,60 @@ func TestGetStorageHash(t *testing.T) {
}
}

func TestGetChildStorage(t *testing.T) {
mod, blockHash := setupChildStateStorage(t)
randomHash, err := common.HexToHash(RandomHash)
require.NoError(t, err)

testCases := []struct {
params []string
expected []byte
errMsg string
}{
{params: []string{":child_storage_key", ""}, expected: nil},
{params: []string{":child_storage_key", ":child_first"}, expected: []byte(":child_first_value")},
{params: []string{":child_storage_key", ":child_first", blockHash.String()}, expected: []byte(":child_first_value")},
{params: []string{":child_storage_key", ":child_first", randomHash.String()}, errMsg: "Key not found"},
}

for _, test := range testCases {
t.Run(fmt.Sprintf("%s", test.params), func(t *testing.T) {
var res StateStorageResponse
var req ChildStateStorageRequest

if test.params[0] != "" {
req.ChildStorageKey = []byte(test.params[0])
}

if test.params[1] != "" {
req.Key = []byte(test.params[1])
}

if len(test.params) > 2 && test.params[2] != "" {
req.Hash = &common.Hash{}
*req.Hash, err = common.HexToHash(test.params[2])
require.NoError(t, err)
}

err = mod.GetStorage(nil, &req, &res)
// Handle error cases.
if test.errMsg != "" {
require.Error(t, err)
require.Equal(t, err.Error(), test.errMsg)
return
}

// Verify expected values.
require.NoError(t, err)
if test.expected != nil {
// Convert human-readable result value to hex.
expectedVal := "0x" + hex.EncodeToString(test.expected)
require.Equal(t, StateStorageResponse(expectedVal), res)
}
})
}
}

func setupChildStateStorage(t *testing.T) (*ChildStateModule, common.Hash) {
t.Helper()

Expand Down
31 changes: 0 additions & 31 deletions dot/rpc/modules/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ type StateCallRequest struct {
Block *common.Hash `json:"block"`
}

// StateChildStorageRequest holds json fields
type StateChildStorageRequest struct {
ChildStorageKey []byte `json:"childStorageKey"`
Key []byte `json:"key"`
Block *common.Hash `json:"block"`
}

// StateStorageKeyRequest holds json fields
type StateStorageKeyRequest struct {
Prefix string `json:"prefix"`
Expand Down Expand Up @@ -227,30 +220,6 @@ func (sm *StateModule) Call(_ *http.Request, _ *StateCallRequest, _ *StateCallRe
return nil
}

// GetChildKeys isn't implemented properly yet.
func (*StateModule) GetChildKeys(_ *http.Request, _ *StateChildStorageRequest, _ *StateKeysResponse) error {
// TODO implement change storage trie so that block hash parameter works (See issue #834)
return nil
}

// GetChildStorage isn't implemented properly yet.
func (*StateModule) GetChildStorage(_ *http.Request, _ *StateChildStorageRequest, _ *StateStorageDataResponse) error {
// TODO implement change storage trie so that block hash parameter works (See issue #834)
return nil
}

// GetChildStorageHash isn't implemented properly yet.
func (*StateModule) GetChildStorageHash(_ *http.Request, _ *StateChildStorageRequest, _ *StateChildStorageResponse) error {
// TODO implement change storage trie so that block hash parameter works (See issue #834)
return nil
}

// GetChildStorageSize isn't implemented properly yet.
func (*StateModule) GetChildStorageSize(_ *http.Request, _ *StateChildStorageRequest, _ *StateChildStorageSizeResponse) error {
// TODO implement change storage trie so that block hash parameter works (See issue #834)
return nil
}

// GetKeysPaged Returns the keys with prefix with pagination support.
func (sm *StateModule) GetKeysPaged(_ *http.Request, req *StateStorageKeyRequest, res *StateStorageKeysResponse) error {
if req.Prefix == "" {
Expand Down
1 change: 1 addition & 0 deletions dot/rpc/modules/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ func setupStateModule(t *testing.T) (*StateModule, *common.Hash, *common.Hash) {

ts.Set([]byte(`:key2`), []byte(`value2`))
ts.Set([]byte(`:key1`), []byte(`value1`))
ts.SetChildStorage([]byte(`:child1`), []byte(`:key1`), []byte(`:childValue1`))

sr1, err := ts.Root()
require.NoError(t, err)
Expand Down
24 changes: 0 additions & 24 deletions tests/rpc/rpc_05-state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,30 +61,6 @@ func TestStateRPCResponseValidation(t *testing.T) {
method: "state_getKeysPaged",
skip: true,
},
{
description: "Test state_getChildKeys",
method: "state_getChildKeys",
params: `["","","0x579deccea7183c2afedbdaea59ad23e970458186afc4d57d5577842d4a219925"]`,
expected: modules.StateKeysResponse{},
},
{
description: "Test state_getChildStorage",
method: "state_getChildStorage",
params: `["","","0x579deccea7183c2afedbdaea59ad23e970458186afc4d57d5577842d4a219925"]`,
expected: modules.StateStorageDataResponse(""),
},
{
description: "Test state_getChildStorageHash",
method: "state_getChildStorageHash",
params: `["","","0x579deccea7183c2afedbdaea59ad23e970458186afc4d57d5577842d4a219925"]`,
expected: modules.StateChildStorageResponse(""),
},
{
description: "Test state_getChildStorageSize",
method: "state_getChildStorageSize",
params: `["","","0x579deccea7183c2afedbdaea59ad23e970458186afc4d57d5577842d4a219925"]`,
expected: modules.StateChildStorageSizeResponse(0),
},
{
description: "Test state_queryStorage",
method: "state_queryStorage",
Expand Down

0 comments on commit 4977d06

Please sign in to comment.