Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rpc): Implement childstate_getChildStorage RPC call #1832

Merged
merged 16 commits into from
Oct 8, 2021
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
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