From 588a8ec8c612bf9f5fb1ed74300cdb4666fec4c7 Mon Sep 17 00:00:00 2001 From: Dan Forbes Date: Wed, 15 Sep 2021 15:06:02 -0700 Subject: [PATCH 1/6] WIP --- dot/rpc/modules/api.go | 1 + dot/rpc/modules/api_mocks.go | 1 + dot/rpc/modules/mocks/storage_api.go | 23 ++++++++++++ dot/rpc/modules/state.go | 17 ++++++++- dot/rpc/modules/state_test.go | 55 ++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/dot/rpc/modules/api.go b/dot/rpc/modules/api.go index c9d4da2e2c..55d6d46539 100644 --- a/dot/rpc/modules/api.go +++ b/dot/rpc/modules/api.go @@ -18,6 +18,7 @@ import ( type StorageAPI interface { GetStorage(root *common.Hash, key []byte) ([]byte, error) GetStorageByBlockHash(bhash common.Hash, key []byte) ([]byte, error) + GetStorageFromChild(root *common.Hash, keyToChild, key []byte) ([]byte, error) Entries(root *common.Hash) (map[string][]byte, error) GetStateRootFromBlock(bhash *common.Hash) (*common.Hash, error) GetKeysWithPrefix(root *common.Hash, prefix []byte) ([][]byte, error) diff --git a/dot/rpc/modules/api_mocks.go b/dot/rpc/modules/api_mocks.go index fa1d6c732a..59c80616bb 100644 --- a/dot/rpc/modules/api_mocks.go +++ b/dot/rpc/modules/api_mocks.go @@ -11,6 +11,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/mocks/storage_api.go b/dot/rpc/modules/mocks/storage_api.go index db3bb22a4e..52317031e5 100644 --- a/dot/rpc/modules/mocks/storage_api.go +++ b/dot/rpc/modules/mocks/storage_api.go @@ -129,6 +129,29 @@ func (_m *MockStorageAPI) GetStorageByBlockHash(bhash common.Hash, key []byte) ( return r0, r1 } +// GetStorageFromChild provides a mock function with given fields: root, keyToChild, key +func (_m *MockStorageAPI) GetStorageFromChild(root *common.Hash, keyToChild []byte, key []byte) ([]byte, error) { + ret := _m.Called(root, keyToChild, key) + + var r0 []byte + if rf, ok := ret.Get(0).(func(*common.Hash, []byte, []byte) []byte); ok { + r0 = rf(root, keyToChild, key) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*common.Hash, []byte, []byte) error); ok { + r1 = rf(root, keyToChild, key) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RegisterStorageObserver provides a mock function with given fields: observer func (_m *MockStorageAPI) RegisterStorageObserver(observer state.Observer) { _m.Called(observer) diff --git a/dot/rpc/modules/state.go b/dot/rpc/modules/state.go index f301b4e8ac..9587354a0b 100644 --- a/dot/rpc/modules/state.go +++ b/dot/rpc/modules/state.go @@ -221,9 +221,22 @@ func (sm *StateModule) GetChildKeys(r *http.Request, req *StateChildStorageReque return nil } -// GetChildStorage isn't implemented properly yet. +// GetChildStorage returns a child storage entry. func (sm *StateModule) GetChildStorage(r *http.Request, req *StateChildStorageRequest, res *StateStorageDataResponse) error { - // TODO implement change storage trie so that block hash parameter works (See issue #834) + var ( + item []byte + err error + ) + + item, err = sm.storageAPI.GetStorageFromChild(req.Block, req.ChildStorageKey, req.Key) + if err != nil { + return err + } + + if len(item) > 0 { + *res = StateStorageDataResponse(common.BytesToHex(item)) + } + return nil } diff --git a/dot/rpc/modules/state_test.go b/dot/rpc/modules/state_test.go index 19a844d80e..794c0d8c74 100644 --- a/dot/rpc/modules/state_test.go +++ b/dot/rpc/modules/state_test.go @@ -222,6 +222,60 @@ func TestStateModule_GetStorage(t *testing.T) { } } +func TestStateModule_GetChildStorage(t *testing.T) { + sm, hash, _ := setupStateModule(t) + randomHash, err := common.HexToHash(RandomHash) + require.NoError(t, err) + + testCases := []struct { + params []string + expected []byte + errMsg string + }{ + {params: []string{":child1", ""}, expected: nil}, + {params: []string{":child1", ":key1"}, expected: []byte("value1")}, + {params: []string{":child1", ":key1", hash.String()}, expected: []byte("value1")}, + {params: []string{":child1", ":key1", randomHash.String()}, errMsg: "Key not found"}, + } + + for _, test := range testCases { + t.Run(fmt.Sprintf("%s", test.params), func(t *testing.T) { + var res StateStorageDataResponse + var req StateChildStorageRequest + + 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.Block = &common.Hash{} + *req.Block, err = common.HexToHash(test.params[2]) + require.NoError(t, err) + } + + err = sm.GetChildStorage(nil, &req, &res) + // Handle error cases. + if test.errMsg != "" { + require.Error(t, err) + require.Contains(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 TestStateModule_GetStorageHash(t *testing.T) { sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) @@ -486,6 +540,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) From 142ed59e0ce2b8c8987725fe4a87e2c281e57bb6 Mon Sep 17 00:00:00 2001 From: Dan Forbes Date: Fri, 1 Oct 2021 14:52:35 -0700 Subject: [PATCH 2/6] WIP --- dot/rpc/modules/childstate.go | 44 +++++++++++++++++++++++ dot/rpc/modules/childstate_test.go | 56 ++++++++++++++++++++++++++++++ dot/rpc/modules/state.go | 31 ----------------- dot/rpc/modules/state_test.go | 1 + 4 files changed, 101 insertions(+), 31 deletions(-) diff --git a/dot/rpc/modules/childstate.go b/dot/rpc/modules/childstate.go index 361afe1fea..f60c2b5249 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"` + Block *common.Hash `json:"block"` +} + // GetStorageHash the request to get the entry child storage hash type GetStorageHash struct { KeyChild []byte @@ -106,3 +113,40 @@ func (cs *ChildStateModule) GetStorageHash(_ *http.Request, req *GetStorageHash, return nil } + +// GetStorage returns a child storage entry. +func (cs *ChildStateModule) GetStorage(r *http.Request, req *ChildStateStorageRequest, res *StateStorageResponse) error { + var ( + item []byte + err error + ) + + item, err = cs.storageAPI.GetStorageFromChild(req.Block, req.ChildStorageKey, req.Key) + if err != nil { + return err + } + + if len(item) > 0 { + *res = StateStorageResponse(common.BytesToHex(item)) + } + + return nil +} + +// GetChildKeys isn't implemented properly yet. +func (cs *ChildStateModule) GetChildKeys(_ *http.Request, _ *ChildStateStorageRequest, _ *StateKeysResponse) error { + // TODO implement change storage trie so that block hash parameter works (See issue #834) + return nil +} + +// GetChildStorageHash isn't implemented properly yet. +func (cs *ChildStateModule) GetChildStorageHash(_ *http.Request, _ *ChildStateStorageRequest, _ *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 (cs *ChildStateModule) GetChildStorageSize(_ *http.Request, _ *ChildStateStorageRequest, _ *StateChildStorageSizeResponse) error { + // TODO implement change storage trie so that block hash parameter works (See issue #834) + return nil +} diff --git a/dot/rpc/modules/childstate_test.go b/dot/rpc/modules/childstate_test.go index c46081698f..20dd09c4bb 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" @@ -130,6 +131,61 @@ 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")}, + // ??? trie with given root does not exist: 0xa5eb26ce5a6131f0737afbafa33ac3b9677a4fdb014d584862fe5da9d7d4539b + // {params: []string{":child_storage_key", ":child_first", blockHash.String()}, expected: []byte(":child_first_value")}, + {params: []string{":child_storage_key", ":child_first", randomHash.String()}, errMsg: "trie with given root does not exist"}, + } + + 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.Block = &common.Hash{} + *req.Block, 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.Contains(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 5bbbc40e1a..1489b8ff9c 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) From 0b3f0b2ea7a956d63203659b82cbddecf281bd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20J=C3=BAnior?= Date: Mon, 4 Oct 2021 20:26:54 -0400 Subject: [PATCH 3/6] chore: remove unused comment --- dot/rpc/modules/childstate_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/dot/rpc/modules/childstate_test.go b/dot/rpc/modules/childstate_test.go index ef00eaadef..4db3406654 100644 --- a/dot/rpc/modules/childstate_test.go +++ b/dot/rpc/modules/childstate_test.go @@ -143,7 +143,6 @@ func TestGetChildStorage(t *testing.T) { }{ {params: []string{":child_storage_key", ""}, expected: nil}, {params: []string{":child_storage_key", ":child_first"}, expected: []byte(":child_first_value")}, - // ??? trie with given root does not exist: 0xa5eb26ce5a6131f0737afbafa33ac3b9677a4fdb014d584862fe5da9d7d4539b {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"}, } From dbc663f3ff901ef61b681e8a1d62500390ab849f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20J=C3=BAnior?= Date: Mon, 4 Oct 2021 20:31:25 -0400 Subject: [PATCH 4/6] chore: remove unused rpc from state --- dot/rpc/modules/childstate.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/dot/rpc/modules/childstate.go b/dot/rpc/modules/childstate.go index 2873bea9e1..8be6d30f4f 100644 --- a/dot/rpc/modules/childstate.go +++ b/dot/rpc/modules/childstate.go @@ -144,21 +144,3 @@ func (cs *ChildStateModule) GetStorage(r *http.Request, req *ChildStateStorageRe return nil } - -// GetChildKeys isn't implemented properly yet. -func (cs *ChildStateModule) GetChildKeys(_ *http.Request, _ *ChildStateStorageRequest, _ *StateKeysResponse) error { - // TODO implement change storage trie so that block hash parameter works (See issue #834) - return nil -} - -// GetChildStorageHash isn't implemented properly yet. -func (cs *ChildStateModule) GetChildStorageHash(_ *http.Request, _ *ChildStateStorageRequest, _ *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 (cs *ChildStateModule) GetChildStorageSize(_ *http.Request, _ *ChildStateStorageRequest, _ *StateChildStorageSizeResponse) error { - // TODO implement change storage trie so that block hash parameter works (See issue #834) - return nil -} From 7c77f7990139411a585d85e54842beb7bf329e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20J=C3=BAnior?= Date: Tue, 5 Oct 2021 08:27:43 -0400 Subject: [PATCH 5/6] chore: ignore unused param --- dot/rpc/modules/childstate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dot/rpc/modules/childstate.go b/dot/rpc/modules/childstate.go index 8be6d30f4f..db288f6387 100644 --- a/dot/rpc/modules/childstate.go +++ b/dot/rpc/modules/childstate.go @@ -115,7 +115,7 @@ func (cs *ChildStateModule) GetStorageHash(_ *http.Request, req *GetStorageHash, } // GetStorage returns a child storage entry. -func (cs *ChildStateModule) GetStorage(r *http.Request, req *ChildStateStorageRequest, res *StateStorageResponse) error { +func (cs *ChildStateModule) GetStorage(_ *http.Request, req *ChildStateStorageRequest, res *StateStorageResponse) error { var ( item []byte err error From f8f7642f3d99612ed5026062ea7493c85438ac73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20J=C3=BAnior?= Date: Tue, 5 Oct 2021 22:22:29 -0400 Subject: [PATCH 6/6] chore: fix rpc tests --- tests/rpc/rpc_05-state_test.go | 24 ------------------------ 1 file changed, 24 deletions(-) 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",