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

fix(dot/rpc/modules): rpc.state.queryStorage fixed #2565

Merged
merged 40 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1bf8834
setup files for testing with rt 0.9.19
edwardmack May 17, 2022
a9fd5ca
add to tests
edwardmack May 17, 2022
0f1745a
implement rpc_state_queryStorage
edwardmack May 19, 2022
996cd0a
WIP creating TestStateModuleQueryStorage
edwardmack May 19, 2022
10ad1ee
remove unused functions, lint
edwardmack May 19, 2022
89e6751
change tests mocks
edwardmack May 20, 2022
db547bc
implement unit tests
edwardmack May 20, 2022
4a4bb34
fix failing tests
edwardmack May 25, 2022
821d00d
fix integration tests
edwardmack May 25, 2022
a3a47ee
revert config.toml to use original genesis-spec.json
edwardmack May 25, 2022
ee1988c
fix lint issues
edwardmack May 25, 2022
ea34a13
regen mockery files
edwardmack May 26, 2022
bd5156a
regerate mockery files
edwardmack May 26, 2022
2fdf270
edit config.toml, remove comments
edwardmack Jun 6, 2022
3298176
create file for mockgen
edwardmack Jun 8, 2022
3bf9b5a
address PR comments
edwardmack Jun 9, 2022
64cd32f
add to unit tests
edwardmack Jun 13, 2022
140c534
add tests to mocha tests
edwardmack Jun 14, 2022
76751ee
update api state mocha tests
edwardmack Jun 14, 2022
e4e1da5
add copyright notice
edwardmack Jun 14, 2022
68a873e
revert dev config.toml
edwardmack Jun 14, 2022
aaf8358
WIP, testing queryStorage javascript call
edwardmack Jun 15, 2022
9efac9c
update polkadot api version
edwardmack Jun 15, 2022
24d3732
revert dev config.toml
edwardmack Jun 15, 2022
6fc80ea
fix QueryStorage integration test
edwardmack Jun 15, 2022
334e25a
address PR comments
edwardmack Jun 17, 2022
77e2f6c
Merge branch 'development' into ed/rpc_state_queryStorage
edwardmack Jun 17, 2022
2c3678e
address lint issue
edwardmack Jun 20, 2022
2ca4586
remove test genesis spec file
edwardmack Jun 29, 2022
9ebcc8b
Merge branch 'development' into ed/rpc_state_queryStorage
edwardmack Jul 1, 2022
b41a0a0
fix merge conflicts
edwardmack Jul 1, 2022
f5f51d8
Merge branch 'development' into ed/rpc_state_queryStorage
edwardmack Jul 7, 2022
bcd11fd
use stringPtr for assignment, re-run mockery generation
edwardmack Jul 8, 2022
7f0344d
use regexp to test for errors
edwardmack Jul 14, 2022
4f79e2e
address PR comments for state_test
edwardmack Jul 14, 2022
fad98c8
address comments regarding test-polkadot.js
edwardmack Jul 14, 2022
d028e39
address PR comments
edwardmack Jul 14, 2022
f10020f
add copyright notice
edwardmack Jul 14, 2022
aaf8fa4
add check for hex string
edwardmack Jul 19, 2022
dd41f16
remove firstPass variable
edwardmack Jul 19, 2022
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
55 changes: 0 additions & 55 deletions dot/core/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,61 +560,6 @@ func (s *Service) GetMetadata(bhash *common.Hash) ([]byte, error) {
return rt.Metadata()
}

// QueryStorage returns the key-value data by block based on `keys` params
// on every block starting `from` until `to` block, if `to` is not nil
func (s *Service) QueryStorage(from, to common.Hash, keys ...string) (map[common.Hash]QueryKeyValueChanges, error) {
if to.IsEmpty() {
to = s.blockState.BestBlockHash()
}

blocksToQuery, err := s.blockState.SubChain(from, to)
if err != nil {
return nil, err
}

queries := make(map[common.Hash]QueryKeyValueChanges)

for _, hash := range blocksToQuery {
changes, err := s.tryQueryStorage(hash, keys...)
if err != nil {
return nil, err
}

queries[hash] = changes
}

return queries, nil
}

// tryQueryStorage will try to get all the `keys` inside the block's current state
func (s *Service) tryQueryStorage(block common.Hash, keys ...string) (QueryKeyValueChanges, error) {
stateRootHash, err := s.storageState.GetStateRootFromBlock(&block)
if err != nil {
return nil, err
}

changes := make(QueryKeyValueChanges)
for _, k := range keys {
keyBytes, err := common.HexToBytes(k)
if err != nil {
return nil, err
}

storedData, err := s.storageState.GetStorage(stateRootHash, keyBytes)
if err != nil {
return nil, err
}

if storedData == nil {
continue
}

changes[k] = common.BytesToHex(storedData)
}

return changes, nil
}

// GetReadProofAt will return an array with the proofs for the keys passed as params
// based on the block hash passed as param as well, if block hash is nil then the current state will take place
func (s *Service) GetReadProofAt(block common.Hash, keys [][]byte) (
Expand Down
204 changes: 0 additions & 204 deletions dot/core/service_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ import (

//go:generate mockgen -destination=mock_telemetry_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/dot/telemetry Client

const testSlotNumber = 21

func balanceKey(t *testing.T, pub []byte) (bKey []byte) {
t.Helper()

Expand All @@ -53,35 +51,6 @@ func balanceKey(t *testing.T, pub []byte) (bKey []byte) {
return
}

func newTestDigest(t *testing.T, slotNumber uint64) scale.VaryingDataTypeSlice {
t.Helper()
testBabeDigest := types.NewBabeDigest()
err := testBabeDigest.Set(types.BabeSecondaryPlainPreDigest{
AuthorityIndex: 17,
SlotNumber: slotNumber,
})
require.NoError(t, err)
data, err := scale.Marshal(testBabeDigest)
require.NoError(t, err)
vdts := types.NewDigest()
err = vdts.Add(
types.PreRuntimeDigest{
ConsensusEngineID: types.BabeEngineID,
Data: data,
},
types.ConsensusDigest{
ConsensusEngineID: types.BabeEngineID,
Data: data,
},
types.SealDigest{
ConsensusEngineID: types.BabeEngineID,
Data: data,
},
)
require.NoError(t, err)
return vdts
}

func generateTestValidRemarkTxns(t *testing.T, pubKey []byte, accInfo types.AccountInfo) ([]byte, runtime.Instance) {
t.Helper()
projectRootPath := filepath.Join(utils.GetProjectRootPathTest(t), "chain/gssmr/genesis.json")
Expand Down Expand Up @@ -759,176 +728,3 @@ func TestService_HandleRuntimeChangesAfterCodeSubstitutes(t *testing.T) {
rt.GetCodeHash(),
"expected different code hash after runtime update")
}

func TestTryQueryStore_WhenThereIsDataToRetrieve(t *testing.T) {
s := NewTestService(t, nil)
storageStateTrie, err := rtstorage.NewTrieState(trie.NewTrie(nil))

testKey, testValue := []byte("to"), []byte("0x1723712318238AB12312")
storageStateTrie.Set(testKey, testValue)
require.NoError(t, err)

digest := newTestDigest(t, testSlotNumber)
header, err := types.NewHeader(s.blockState.GenesisHash(), storageStateTrie.MustRoot(), common.Hash{}, 1, digest)

require.NoError(t, err)

err = s.storageState.StoreTrie(storageStateTrie, header)
require.NoError(t, err)

testBlock := &types.Block{
Header: *header,
Body: *types.NewBody([]types.Extrinsic{}),
}

err = s.blockState.AddBlock(testBlock)
require.NoError(t, err)

blockhash := testBlock.Header.Hash()
hexKey := common.BytesToHex(testKey)
keys := []string{hexKey}

changes, err := s.tryQueryStorage(blockhash, keys...)
require.NoError(t, err)

require.Equal(t, changes[hexKey], common.BytesToHex(testValue))
}

func TestTryQueryStore_WhenDoesNotHaveDataToRetrieve(t *testing.T) {
s := NewTestService(t, nil)
storageStateTrie, err := rtstorage.NewTrieState(trie.NewTrie(nil))
require.NoError(t, err)

digest := newTestDigest(t, testSlotNumber)
header, err := types.NewHeader(s.blockState.GenesisHash(), storageStateTrie.MustRoot(), common.Hash{}, 1, digest)
require.NoError(t, err)

err = s.storageState.StoreTrie(storageStateTrie, header)
require.NoError(t, err)

testBlock := &types.Block{
Header: *header,
Body: *types.NewBody([]types.Extrinsic{}),
}

err = s.blockState.AddBlock(testBlock)
require.NoError(t, err)

testKey := []byte("to")
blockhash := testBlock.Header.Hash()
hexKey := common.BytesToHex(testKey)
keys := []string{hexKey}

changes, err := s.tryQueryStorage(blockhash, keys...)
require.NoError(t, err)

require.Empty(t, changes)
}

func TestTryQueryState_WhenDoesNotHaveStateRoot(t *testing.T) {
s := NewTestService(t, nil)

digest := newTestDigest(t, testSlotNumber)
header, err := types.NewHeader(
s.blockState.GenesisHash(),
common.Hash{}, common.Hash{}, 1, digest)
require.NoError(t, err)

testBlock := &types.Block{
Header: *header,
Body: *types.NewBody([]types.Extrinsic{}),
}

err = s.blockState.AddBlock(testBlock)
require.NoError(t, err)

testKey := []byte("to")
blockhash := testBlock.Header.Hash()
hexKey := common.BytesToHex(testKey)
keys := []string{hexKey}

changes, err := s.tryQueryStorage(blockhash, keys...)
require.Error(t, err)
require.Nil(t, changes)
}

func TestQueryStorate_WhenBlocksHasData(t *testing.T) {
keys := []string{
common.BytesToHex([]byte("transfer.to")),
common.BytesToHex([]byte("transfer.from")),
common.BytesToHex([]byte("transfer.value")),
}

s := NewTestService(t, nil)

firstKey, firstValue := []byte("transfer.to"), []byte("some-address-herer")
firstBlock := createNewBlockAndStoreDataAtBlock(
t, s, firstKey, firstValue, s.blockState.GenesisHash(), 1,
)

secondKey, secondValue := []byte("transfer.from"), []byte("another-address-here")
secondBlock := createNewBlockAndStoreDataAtBlock(
t, s, secondKey, secondValue, firstBlock.Header.Hash(), 2,
)

thirdKey, thirdValue := []byte("transfer.value"), []byte("value-gigamegablaster")
thirdBlock := createNewBlockAndStoreDataAtBlock(
t, s, thirdKey, thirdValue, secondBlock.Header.Hash(), 3,
)

from := firstBlock.Header.Hash()
data, err := s.QueryStorage(from, common.Hash{}, keys...)
require.NoError(t, err)
require.Len(t, data, 3)

require.Equal(t, data[firstBlock.Header.Hash()], QueryKeyValueChanges(
map[string]string{
common.BytesToHex(firstKey): common.BytesToHex(firstValue),
},
))

from = secondBlock.Header.Hash()
to := thirdBlock.Header.Hash()

data, err = s.QueryStorage(from, to, keys...)
require.NoError(t, err)
require.Len(t, data, 2)

require.Equal(t, data[secondBlock.Header.Hash()], QueryKeyValueChanges(
map[string]string{
common.BytesToHex(secondKey): common.BytesToHex(secondValue),
},
))
require.Equal(t, data[thirdBlock.Header.Hash()], QueryKeyValueChanges(
map[string]string{
common.BytesToHex(thirdKey): common.BytesToHex(thirdValue),
},
))
}

func createNewBlockAndStoreDataAtBlock(t *testing.T, s *Service,
key, value []byte, parentHash common.Hash,
number uint) *types.Block {
t.Helper()

storageStateTrie, err := rtstorage.NewTrieState(trie.NewTrie(nil))
storageStateTrie.Set(key, value)
require.NoError(t, err)

digest := newTestDigest(t, 421)
header, err := types.NewHeader(parentHash, storageStateTrie.MustRoot(), common.Hash{}, number, digest)
require.NoError(t, err)

err = s.storageState.StoreTrie(storageStateTrie, header)
require.NoError(t, err)

testBlock := &types.Block{
Header: *header,
Body: *types.NewBody([]types.Extrinsic{}),
}

err = s.blockState.AddBlock(testBlock)
require.NoError(t, err)

return testBlock
}
96 changes: 0 additions & 96 deletions dot/core/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1229,102 +1229,6 @@ func TestServiceGetMetadata(t *testing.T) {
})
}

func TestService_tryQueryStorage(t *testing.T) {
t.Parallel()
execTest := func(t *testing.T, s *Service, block common.Hash, keys []string, exp QueryKeyValueChanges, expErr error) {
res, err := s.tryQueryStorage(block, keys...)
assert.ErrorIs(t, err, expErr)
if expErr != nil {
assert.EqualError(t, err, expErr.Error())
}
assert.Equal(t, exp, res)
}

t.Run("get state root error", func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
mockStorageState := NewMockStorageState(ctrl)
mockStorageState.EXPECT().GetStateRootFromBlock(&common.Hash{}).Return(nil, errDummyErr)
service := &Service{
storageState: mockStorageState,
}
execTest(t, service, common.Hash{}, nil, nil, errDummyErr)
})

t.Run("get storage error", func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
mockStorageState := NewMockStorageState(ctrl)
mockStorageState.EXPECT().GetStateRootFromBlock(&common.Hash{}).Return(&common.Hash{}, nil)
mockStorageState.EXPECT().GetStorage(&common.Hash{}, common.MustHexToBytes("0x01")).Return(nil, errDummyErr)
service := &Service{
storageState: mockStorageState,
}
execTest(t, service, common.Hash{}, []string{"0x01"}, nil, errDummyErr)
})

t.Run("happy path", func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
mockStorageState := NewMockStorageState(ctrl)
mockStorageState.EXPECT().GetStateRootFromBlock(&common.Hash{}).Return(&common.Hash{}, nil)
mockStorageState.EXPECT().GetStorage(&common.Hash{}, common.MustHexToBytes("0x01")).
Return([]byte{1, 2, 3}, nil)
expChanges := make(QueryKeyValueChanges)
expChanges["0x01"] = common.BytesToHex([]byte{1, 2, 3})
service := &Service{
storageState: mockStorageState,
}
execTest(t, service, common.Hash{}, []string{"0x01"}, expChanges, nil)
})
}

func TestService_QueryStorage(t *testing.T) {
t.Parallel()
execTest := func(t *testing.T, s *Service, from common.Hash, to common.Hash,
keys []string, exp map[common.Hash]QueryKeyValueChanges, expErr error) {
res, err := s.QueryStorage(from, to, keys...)
assert.ErrorIs(t, err, expErr)
if expErr != nil {
assert.EqualError(t, err, expErr.Error())
}
assert.Equal(t, exp, res)
}

t.Run("subchain error", func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
mockBlockState := NewMockBlockState(ctrl)
mockBlockState.EXPECT().BestBlockHash().Return(common.Hash{2})
mockBlockState.EXPECT().SubChain(common.Hash{1}, common.Hash{2}).Return(nil, errDummyErr)
service := &Service{
blockState: mockBlockState,
}
execTest(t, service, common.Hash{1}, common.Hash{}, nil, nil, errDummyErr)
})

t.Run("happy path", func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
mockBlockState := NewMockBlockState(ctrl)
mockBlockState.EXPECT().BestBlockHash().Return(common.Hash{2})
mockBlockState.EXPECT().SubChain(common.Hash{1}, common.Hash{2}).Return([]common.Hash{{0x01}}, nil)
mockStorageState := NewMockStorageState(ctrl)
mockStorageState.EXPECT().GetStateRootFromBlock(&common.Hash{0x01}).Return(&common.Hash{}, nil)
mockStorageState.EXPECT().GetStorage(&common.Hash{}, common.MustHexToBytes("0x01")).
Return([]byte{1, 2, 3}, nil)
expChanges := make(QueryKeyValueChanges)
expChanges["0x01"] = common.BytesToHex([]byte{1, 2, 3})
expQueries := make(map[common.Hash]QueryKeyValueChanges)
expQueries[common.Hash{0x01}] = expChanges
service := &Service{
blockState: mockBlockState,
storageState: mockStorageState,
}
execTest(t, service, common.Hash{1}, common.Hash{}, []string{"0x01"}, expQueries, nil)
})
}

func TestService_GetReadProofAt(t *testing.T) {
t.Parallel()
execTest := func(t *testing.T, s *Service, block common.Hash, keys [][]byte,
Expand Down
3 changes: 2 additions & 1 deletion dot/rpc/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ func (h *HTTPServer) RegisterModules(mods []string) {
case "grandpa":
srvc = modules.NewGrandpaModule(h.serverConfig.BlockAPI, h.serverConfig.BlockFinalityAPI)
case "state":
srvc = modules.NewStateModule(h.serverConfig.NetworkAPI, h.serverConfig.StorageAPI, h.serverConfig.CoreAPI)
srvc = modules.NewStateModule(h.serverConfig.NetworkAPI, h.serverConfig.StorageAPI,
h.serverConfig.CoreAPI, h.serverConfig.BlockAPI)
case "rpc":
srvc = modules.NewRPCModule(h.serverConfig.RPCAPI)
case "dev":
Expand Down
Loading