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 4 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
56 changes: 56 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 @@ -106,3 +113,52 @@ 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
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
}

// 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
}
56 changes: 56 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 @@ -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
Copy link
Contributor

@danforbes danforbes Oct 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should be removed as it was only included for development purposes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed!

{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