From 3d949f2eba8a4e9c65362d65dfebd5c37a99fe2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Junior?= Date: Fri, 8 Oct 2021 10:10:42 -0400 Subject: [PATCH] feat(rpc): Implement `childstate_getChildStorage` RPC call (#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 --- dot/rpc/modules/api_mocks.go | 1 + dot/rpc/modules/childstate.go | 38 +++++++++++++++++++++ dot/rpc/modules/childstate_test.go | 55 ++++++++++++++++++++++++++++++ dot/rpc/modules/state.go | 31 ----------------- dot/rpc/modules/state_test.go | 1 + tests/rpc/rpc_05-state_test.go | 24 ------------- 6 files changed, 95 insertions(+), 55 deletions(-) diff --git a/dot/rpc/modules/api_mocks.go b/dot/rpc/modules/api_mocks.go index 3d3765b7a4..46885f58f7 100644 --- a/dot/rpc/modules/api_mocks.go +++ b/dot/rpc/modules/api_mocks.go @@ -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) diff --git a/dot/rpc/modules/childstate.go b/dot/rpc/modules/childstate.go index cc454f4977..c821724de9 100644 --- a/dot/rpc/modules/childstate.go +++ b/dot/rpc/modules/childstate.go @@ -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 @@ -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 +} diff --git a/dot/rpc/modules/childstate_test.go b/dot/rpc/modules/childstate_test.go index 535d4134a9..62fa15d6df 100644 --- a/dot/rpc/modules/childstate_test.go +++ b/dot/rpc/modules/childstate_test.go @@ -17,6 +17,7 @@ package modules import ( + "encoding/hex" "fmt" "math/big" "testing" @@ -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() diff --git a/dot/rpc/modules/state.go b/dot/rpc/modules/state.go index cb9c8dcba8..6944b8396f 100644 --- a/dot/rpc/modules/state.go +++ b/dot/rpc/modules/state.go @@ -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"` @@ -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 == "" { diff --git a/dot/rpc/modules/state_test.go b/dot/rpc/modules/state_test.go index f79079053f..4f7ec7c30b 100644 --- a/dot/rpc/modules/state_test.go +++ b/dot/rpc/modules/state_test.go @@ -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) diff --git a/tests/rpc/rpc_05-state_test.go b/tests/rpc/rpc_05-state_test.go index fc8e147796..c7177c2b5f 100644 --- a/tests/rpc/rpc_05-state_test.go +++ b/tests/rpc/rpc_05-state_test.go @@ -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",