From b967ab57744e151d40a2cd0da3d968c94a954f1b Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Thu, 14 Jan 2021 17:19:50 -0500 Subject: [PATCH 1/6] implement getKeysPaged RPC and storage functions --- dot/rpc/modules/api.go | 1 + dot/rpc/modules/state.go | 29 +++++++++++++++++++++++++---- dot/state/storage.go | 16 ++++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/dot/rpc/modules/api.go b/dot/rpc/modules/api.go index dd100f85da..b2c5e0efb0 100644 --- a/dot/rpc/modules/api.go +++ b/dot/rpc/modules/api.go @@ -19,6 +19,7 @@ type StorageAPI interface { RegisterStorageChangeChannel(sub state.StorageSubscription) (byte, error) UnregisterStorageChangeChannel(id byte) GetStateRootFromBlock(bhash *common.Hash) (*common.Hash, error) + Keys(root *common.Hash) ([]string, error) } // BlockAPI is the interface for the block state diff --git a/dot/rpc/modules/state.go b/dot/rpc/modules/state.go index 4a10e143e6..879e3ed910 100644 --- a/dot/rpc/modules/state.go +++ b/dot/rpc/modules/state.go @@ -18,7 +18,9 @@ package modules import ( "encoding/hex" + "fmt" "net/http" + "strings" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/runtime" @@ -41,7 +43,9 @@ type StateChildStorageRequest struct { // StateStorageKeyRequest holds json fields type StateStorageKeyRequest struct { - Key []byte `json:"key"` + Prefix string `json:"prefix"` + Qty uint32 `json:"qty"` + AfterKey string `afterKey` Block *common.Hash `json:"block"` } @@ -117,7 +121,7 @@ type StateStorageResponse string type StatePairResponse []interface{} // StateStorageKeysResponse field for storage keys -type StateStorageKeysResponse [][]byte +type StateStorageKeysResponse []string // StateMetadataResponse holds the metadata //TODO: Determine actual type @@ -234,9 +238,26 @@ func (sm *StateModule) GetChildStorageSize(r *http.Request, req *StateChildStora } // GetKeys isn't implemented properly yet. -func (sm *StateModule) GetKeys(r *http.Request, req *StateStorageKeyRequest, res *StateStorageKeysResponse) error { +func (sm *StateModule) GetKeysPaged(r *http.Request, req *StateStorageKeyRequest, res *StateStorageKeysResponse) error { // TODO implement change storage trie so that block hash parameter works (See issue #834) - return nil + // todo ed, test lookup by block hash + // todo ed add unit tests + keys, err := sm.storageAPI.Keys(req.Block) + resCount := uint32(0) + for _, k := range keys { + fKey := fmt.Sprintf("0x%x", k) + if strings.HasPrefix(fKey, req.Prefix) && + strings.Compare(fKey, req.AfterKey) == 1 { + // sm.storageAPI.Keys sorts keys in lexicographical order, so we know that keys where strings.Compare = 1 + // are after the requested after key. + *res = append(*res, fKey) + resCount++ + } + if resCount >= req.Qty { + break + } + } + return err } // GetMetadata calls runtime Metadata_metadata function diff --git a/dot/state/storage.go b/dot/state/storage.go index 35a8fd391b..30b23e921f 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -20,6 +20,7 @@ import ( "encoding/binary" "errors" "fmt" + "sort" "sync" "github.com/ChainSafe/gossamer/dot/types" @@ -314,6 +315,21 @@ func (s *StorageState) Entries(hash *common.Hash) (map[string][]byte, error) { return s.tries[*hash].Entries(), nil } +func (s *StorageState) Keys(hash *common.Hash) ([]string, error) { + entries, err := s.Entries(hash) + if err != nil { + return nil, err + } + keys := make([]string, 0, len(entries)) + + for k := range entries { + keys = append(keys, k) + } + sort.Strings(keys) + + return keys, nil +} + // GetStorageChild return GetChild from the trie func (s *StorageState) GetStorageChild(hash *common.Hash, keyToChild []byte) (*trie.Trie, error) { if hash == nil { diff --git a/go.mod b/go.mod index d00590a6ad..3ea998f57f 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/ChainSafe/gossamer require ( - github.com/ChainSafe/chaindb v0.1.5-0.20210113205339-507b3a78c512 + github.com/ChainSafe/chaindb v0.1.5-0.20210113220219-4e61b23c66d7 github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d github.com/ChainSafe/log15 v1.0.0 github.com/OneOfOne/xxhash v1.2.5 diff --git a/go.sum b/go.sum index c0f94fc637..45a2980a4c 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ChainSafe/chaindb v0.1.5-0.20210113205339-507b3a78c512 h1:Qos8z4ReLzdaAoQTWm3rC3gapGHfPd8UlVPwpURl+xo= -github.com/ChainSafe/chaindb v0.1.5-0.20210113205339-507b3a78c512/go.mod h1:WBsCSLGM7+DvSYU6cFVUltahwU7Sw4cN3e8kiLdNFJM= +github.com/ChainSafe/chaindb v0.1.5-0.20210113220219-4e61b23c66d7 h1:xgn/gSkFpSfLBqWyU20t3WTUG+nJyN3vuCc+CcTlbAA= +github.com/ChainSafe/chaindb v0.1.5-0.20210113220219-4e61b23c66d7/go.mod h1:WBsCSLGM7+DvSYU6cFVUltahwU7Sw4cN3e8kiLdNFJM= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/ChainSafe/log15 v1.0.0 h1:vRDVtWtVwIH5uSCBvgTTZh6FA58UBJ6+QiiypaZfBf8= From bdb88c8e121b63c7ef2de8e928edcf6f97029824 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Fri, 15 Jan 2021 15:36:44 -0500 Subject: [PATCH 2/6] add tests for state_getKeysPaged --- dot/rpc/modules/state.go | 17 +++----- dot/rpc/modules/state_test.go | 81 ++++++++++++++++++++++++++++++----- dot/rpc/websocket_test.go | 3 ++ dot/state/storage.go | 1 + 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/dot/rpc/modules/state.go b/dot/rpc/modules/state.go index 879e3ed910..ec7c5d816e 100644 --- a/dot/rpc/modules/state.go +++ b/dot/rpc/modules/state.go @@ -44,9 +44,9 @@ type StateChildStorageRequest struct { // StateStorageKeyRequest holds json fields type StateStorageKeyRequest struct { Prefix string `json:"prefix"` - Qty uint32 `json:"qty"` - AfterKey string `afterKey` - Block *common.Hash `json:"block"` + Qty uint32 `json:"qty"` + AfterKey string `json:"afterKey"` + Block *common.Hash `json:"block"` } // StateRuntimeMetadataQuery is a hash value @@ -237,11 +237,8 @@ func (sm *StateModule) GetChildStorageSize(r *http.Request, req *StateChildStora return nil } -// GetKeys isn't implemented properly yet. +// GetKeysPaged Returns the keys with prefix with pagination support. func (sm *StateModule) GetKeysPaged(r *http.Request, req *StateStorageKeyRequest, res *StateStorageKeysResponse) error { - // TODO implement change storage trie so that block hash parameter works (See issue #834) - // todo ed, test lookup by block hash - // todo ed add unit tests keys, err := sm.storageAPI.Keys(req.Block) resCount := uint32(0) for _, k := range keys { @@ -250,12 +247,12 @@ func (sm *StateModule) GetKeysPaged(r *http.Request, req *StateStorageKeyRequest strings.Compare(fKey, req.AfterKey) == 1 { // sm.storageAPI.Keys sorts keys in lexicographical order, so we know that keys where strings.Compare = 1 // are after the requested after key. + if resCount >= req.Qty { + break + } *res = append(*res, fKey) resCount++ } - if resCount >= req.Qty { - break - } } return err } diff --git a/dot/rpc/modules/state_test.go b/dot/rpc/modules/state_test.go index 9d64b790a2..08fb9a7599 100644 --- a/dot/rpc/modules/state_test.go +++ b/dot/rpc/modules/state_test.go @@ -57,7 +57,7 @@ func TestStateModule_GetRuntimeVersion(t *testing.T) { }, } - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -98,7 +98,7 @@ func TestStateModule_GetRuntimeVersion(t *testing.T) { } func TestStateModule_GetPairs(t *testing.T) { - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -166,7 +166,7 @@ func TestStateModule_GetPairs(t *testing.T) { } func TestStateModule_GetStorage(t *testing.T) { - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -216,7 +216,7 @@ func TestStateModule_GetStorage(t *testing.T) { } func TestStateModule_GetStorageHash(t *testing.T) { - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -268,7 +268,7 @@ func TestStateModule_GetStorageHash(t *testing.T) { } func TestStateModule_GetStorageSize(t *testing.T) { - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -313,7 +313,7 @@ func TestStateModule_GetStorageSize(t *testing.T) { } func TestStateModule_GetMetadata(t *testing.T) { - sm, hash := setupStateModule(t) + sm, hash, _ := setupStateModule(t) randomHash, err := common.HexToHash(RandomHash) require.NoError(t, err) @@ -353,7 +353,68 @@ func TestStateModule_GetMetadata(t *testing.T) { } } -func setupStateModule(t *testing.T) (*StateModule, *common.Hash) { +func TestStateModule_GetKeysPaged(t *testing.T) { + sm, _, stateRootHash := setupStateModule(t) + + testCases := []struct { + name string + params StateStorageKeyRequest + expected []string + }{ + {name: "allKeysNilBlockHash", + params: StateStorageKeyRequest{ + Qty: 10, + Block: nil, + }, expected: []string{"0x3a6b657931", "0x3a6b657932"}}, + {name: "allKeysTestBlockHash", + params: StateStorageKeyRequest{ + Qty: 10, + Block: stateRootHash, + }, expected: []string{"0x3a6b657931", "0x3a6b657932"}}, + {name: "prefixMatchAll", + params: StateStorageKeyRequest{ + Prefix: "0x3a6b6579", + Qty: 10, + }, expected: []string{"0x3a6b657931", "0x3a6b657932"}}, + {name: "prefixMatchOne", + params: StateStorageKeyRequest{ + Prefix: "0x3a6b657931", + Qty: 10, + }, expected: []string{"0x3a6b657931"}}, + {name: "prefixMatchNone", + params: StateStorageKeyRequest{ + Prefix: "0x00", + Qty: 10, + }, expected: nil}, + {name: "qtyOne", + params: StateStorageKeyRequest{ + Qty: 1, + }, expected: []string{"0x3a6b657931"}}, + {name: "afterKey", + params: StateStorageKeyRequest{ + Qty: 10, + AfterKey: "0x3a6b657931", + }, expected: []string{"0x3a6b657932"}}, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + var res StateStorageKeysResponse + + err := sm.GetKeysPaged(nil, &test.params, &res) + require.NoError(t, err) + + if test.expected == nil { + require.Empty(t, res) + return + } + + require.Equal(t, StateStorageKeysResponse(test.expected), res) + }) + } +} + +func setupStateModule(t *testing.T) (*StateModule, *common.Hash, *common.Hash) { // setup service net := newNetworkService(t) chain := newTestStateService(t) @@ -361,10 +422,10 @@ func setupStateModule(t *testing.T) (*StateModule, *common.Hash) { ts, err := chain.Storage.TrieState(nil) require.NoError(t, err) - err = ts.Set([]byte(`:key1`), []byte(`value1`)) - require.NoError(t, err) err = ts.Set([]byte(`:key2`), []byte(`value2`)) require.NoError(t, err) + err = ts.Set([]byte(`:key1`), []byte(`value1`)) + require.NoError(t, err) sr1, err := ts.Root() require.NoError(t, err) @@ -383,5 +444,5 @@ func setupStateModule(t *testing.T) (*StateModule, *common.Hash) { hash, _ := chain.Block.GetBlockHash(big.NewInt(2)) core := newCoreService(t, chain) - return NewStateModule(net, chain.Storage, core), hash + return NewStateModule(net, chain.Storage, core), hash, &sr1 } diff --git a/dot/rpc/websocket_test.go b/dot/rpc/websocket_test.go index dc613f3a4a..99a91bf5f5 100644 --- a/dot/rpc/websocket_test.go +++ b/dot/rpc/websocket_test.go @@ -140,3 +140,6 @@ func (m *MockStorageAPI) UnregisterStorageChangeChannel(id byte) { func (m *MockStorageAPI) GetStateRootFromBlock(bhash *common.Hash) (*common.Hash, error) { return nil, nil } +func (m *MockStorageAPI) Keys(root *common.Hash) ([]string, error) { + return nil, nil +} diff --git a/dot/state/storage.go b/dot/state/storage.go index 30b23e921f..0a0398a766 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -315,6 +315,7 @@ func (s *StorageState) Entries(hash *common.Hash) (map[string][]byte, error) { return s.tries[*hash].Entries(), nil } +// Keys returns all keys for given hash (or best block state root if hash is nil) in lexicographic order func (s *StorageState) Keys(hash *common.Hash) ([]string, error) { entries, err := s.Entries(hash) if err != nil { From c8be7fbcb86b881d3e70d574dc32607f26389720 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Mon, 18 Jan 2021 17:33:33 -0500 Subject: [PATCH 3/6] use GetKeysWithPrefix for RPC call --- dot/rpc/modules/api.go | 2 +- dot/rpc/modules/state.go | 12 +++++++++--- dot/rpc/websocket_test.go | 2 +- dot/state/storage.go | 22 +++++++++------------- lib/trie/trie.go | 10 +++++++--- lib/trie/trie_test.go | 8 ++++++++ 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/dot/rpc/modules/api.go b/dot/rpc/modules/api.go index e88b6611d6..9df87a4afa 100644 --- a/dot/rpc/modules/api.go +++ b/dot/rpc/modules/api.go @@ -19,7 +19,7 @@ type StorageAPI interface { RegisterStorageChangeChannel(sub state.StorageSubscription) (byte, error) UnregisterStorageChangeChannel(id byte) GetStateRootFromBlock(bhash *common.Hash) (*common.Hash, error) - Keys(root *common.Hash) ([]string, error) + GetKeysWithPrefix(root *common.Hash, prefix []byte) ([][]byte, error) } // BlockAPI is the interface for the block state diff --git a/dot/rpc/modules/state.go b/dot/rpc/modules/state.go index ec7c5d816e..fcc5e9741a 100644 --- a/dot/rpc/modules/state.go +++ b/dot/rpc/modules/state.go @@ -239,12 +239,18 @@ func (sm *StateModule) GetChildStorageSize(r *http.Request, req *StateChildStora // GetKeysPaged Returns the keys with prefix with pagination support. func (sm *StateModule) GetKeysPaged(r *http.Request, req *StateStorageKeyRequest, res *StateStorageKeysResponse) error { - keys, err := sm.storageAPI.Keys(req.Block) + if len(req.Prefix) == 0 { + req.Prefix = "0x" + } + hPrefix, err := common.HexToBytes(req.Prefix) + if err != nil { + return err + } + keys, err := sm.storageAPI.GetKeysWithPrefix(req.Block, hPrefix) resCount := uint32(0) for _, k := range keys { fKey := fmt.Sprintf("0x%x", k) - if strings.HasPrefix(fKey, req.Prefix) && - strings.Compare(fKey, req.AfterKey) == 1 { + if strings.Compare(fKey, req.AfterKey) == 1 { // sm.storageAPI.Keys sorts keys in lexicographical order, so we know that keys where strings.Compare = 1 // are after the requested after key. if resCount >= req.Qty { diff --git a/dot/rpc/websocket_test.go b/dot/rpc/websocket_test.go index 99a91bf5f5..abfd9f6f60 100644 --- a/dot/rpc/websocket_test.go +++ b/dot/rpc/websocket_test.go @@ -140,6 +140,6 @@ func (m *MockStorageAPI) UnregisterStorageChangeChannel(id byte) { func (m *MockStorageAPI) GetStateRootFromBlock(bhash *common.Hash) (*common.Hash, error) { return nil, nil } -func (m *MockStorageAPI) Keys(root *common.Hash) ([]string, error) { +func (m *MockStorageAPI) GetKeysWithPrefix(root *common.Hash, prefix []byte) ([][]byte, error) { return nil, nil } diff --git a/dot/state/storage.go b/dot/state/storage.go index 678c1cacbc..386c1707ac 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -20,7 +20,6 @@ import ( "encoding/binary" "errors" "fmt" - "sort" "sync" "github.com/ChainSafe/chaindb" @@ -315,20 +314,17 @@ func (s *StorageState) Entries(hash *common.Hash) (map[string][]byte, error) { return s.tries[*hash].Entries(), nil } -// Keys returns all keys for given hash (or best block state root if hash is nil) in lexicographic order -func (s *StorageState) Keys(hash *common.Hash) ([]string, error) { - entries, err := s.Entries(hash) - if err != nil { - return nil, err - } - keys := make([]string, 0, len(entries)) - - for k := range entries { - keys = append(keys, k) +// GetKeysWithPrefix returns all that match the given prefix for the given hash (or best block state root if hash is nil) in lexicographic order +func (s *StorageState) GetKeysWithPrefix(hash *common.Hash, prefix []byte) ([][]byte, error) { + if hash == nil { + sr, err := s.blockState.BestBlockStateRoot() + if err != nil { + return nil, err + } + hash = &sr } - sort.Strings(keys) - return keys, nil + return s.tries[*hash].GetKeysWithPrefix(prefix), nil } // GetStorageChild return GetChild from the trie diff --git a/lib/trie/trie.go b/lib/trie/trie.go index 2791d68f53..f4aa95f477 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -379,10 +379,14 @@ func (t *Trie) Load(data map[string]string) error { // GetKeysWithPrefix returns all keys in the trie that have the given prefix func (t *Trie) GetKeysWithPrefix(prefix []byte) [][]byte { - p := keyToNibbles(prefix) - if p[len(p)-1] == 0 { - p = p[:len(p)-1] + p := []byte{} + if len(prefix) != 0 { + p = keyToNibbles(prefix) + if p[len(p)-1] == 0 { + p = p[:len(p)-1] + } } + return t.getKeysWithPrefix(t.root, []byte{}, p, [][]byte{}) } diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index dae45b9681..d56fd075ff 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -553,6 +553,8 @@ func TestGetKeysWithPrefix(t *testing.T) { {key: []byte{0x07, 0x3a}, value: []byte("ramen"), op: PUT}, {key: []byte{0x07, 0x3b}, value: []byte("noodles"), op: PUT}, {key: []byte{0xf2}, value: []byte("pho"), op: PUT}, + {key: []byte(":key1"), value: []byte("value1"), op: PUT}, + {key: []byte(":key2"), value: []byte("value2"), op: PUT}, } for _, test := range tests { @@ -576,6 +578,12 @@ func TestGetKeysWithPrefix(t *testing.T) { if !reflect.DeepEqual(keys, expected) { t.Fatalf("Fail: got %v expected %v", keys, expected) } + + expected = [][]byte{} + keys = trie.GetKeysWithPrefix([]byte(":key1")) + if !reflect.DeepEqual(keys, expected) { + t.Fatalf("Fail: got %v expected %v", keys, expected) + } } func TestNextKey(t *testing.T) { From e0676c763aba976072a55924b4bdb1a7015b0016 Mon Sep 17 00:00:00 2001 From: noot Date: Tue, 19 Jan 2021 10:25:43 -0500 Subject: [PATCH 4/6] fix GetKeysWithPrefix --- lib/trie/trie.go | 6 ++++++ lib/trie/trie_test.go | 19 +++++-------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/trie/trie.go b/lib/trie/trie.go index f4aa95f477..e2b7a85d95 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -401,6 +401,12 @@ func (t *Trie) getKeysWithPrefix(parent node, prefix, key []byte, keys [][]byte) return keys } + if len(key) <= len(p.key) { + // no prefixed keys to be found here, return + return keys + } + + key = key[len(p.key):] keys = t.getKeysWithPrefix(p.children[key[0]], append(append(prefix, p.key...), key[0]), key[1:], keys) case *leaf: keys = append(keys, nibblesToKeyLE(append(prefix, p.key...))) diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index d56fd075ff..22fdc25662 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -24,7 +24,6 @@ import ( "math/rand" "os" "path/filepath" - "reflect" "strconv" "strings" "testing" @@ -563,27 +562,19 @@ func TestGetKeysWithPrefix(t *testing.T) { expected := [][]byte{{0x01, 0x35}, {0x01, 0x35, 0x79}} keys := trie.GetKeysWithPrefix([]byte{0x01}) - if !reflect.DeepEqual(keys, expected) { - t.Fatalf("Fail: got %v expected %v", keys, expected) - } + require.Equal(t, expected, keys) expected = [][]byte{{0x01, 0x35}, {0x01, 0x35, 0x79}, {0x07, 0x3a}, {0x07, 0x3b}} keys = trie.GetKeysWithPrefix([]byte{0x0}) - if !reflect.DeepEqual(keys, expected) { - t.Fatalf("Fail: got %v expected %v", keys, expected) - } + require.Equal(t, expected, keys) expected = [][]byte{{0x07, 0x3a}, {0x07, 0x3b}} keys = trie.GetKeysWithPrefix([]byte{0x07, 0x30}) - if !reflect.DeepEqual(keys, expected) { - t.Fatalf("Fail: got %v expected %v", keys, expected) - } + require.Equal(t, expected, keys) - expected = [][]byte{} + expected = [][]byte{[]byte(":key1")} keys = trie.GetKeysWithPrefix([]byte(":key1")) - if !reflect.DeepEqual(keys, expected) { - t.Fatalf("Fail: got %v expected %v", keys, expected) - } + require.Equal(t, expected, keys) } func TestNextKey(t *testing.T) { From 068c0757ae07bd47308fd3bae4e56915920074f5 Mon Sep 17 00:00:00 2001 From: noot Date: Tue, 19 Jan 2021 10:45:48 -0500 Subject: [PATCH 5/6] add go.sum --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index c4a6b8a5c1..b189587aa9 100644 --- a/go.sum +++ b/go.sum @@ -11,10 +11,6 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ChainSafe/chaindb v0.1.4 h1:cXaBIm21aGRijBDPSxkdeXIiuiuNQ4Yc5uV63HrjTg0= -github.com/ChainSafe/chaindb v0.1.4/go.mod h1:FQQJbGzWe+rOa0aW/wSMz1qfIScauntW0HiynEIezuk= -github.com/ChainSafe/chaindb v0.1.5-0.20210113205339-507b3a78c512 h1:Qos8z4ReLzdaAoQTWm3rC3gapGHfPd8UlVPwpURl+xo= -github.com/ChainSafe/chaindb v0.1.5-0.20210113205339-507b3a78c512/go.mod h1:WBsCSLGM7+DvSYU6cFVUltahwU7Sw4cN3e8kiLdNFJM= github.com/ChainSafe/chaindb v0.1.5-0.20210113220219-4e61b23c66d7 h1:xgn/gSkFpSfLBqWyU20t3WTUG+nJyN3vuCc+CcTlbAA= github.com/ChainSafe/chaindb v0.1.5-0.20210113220219-4e61b23c66d7/go.mod h1:WBsCSLGM7+DvSYU6cFVUltahwU7Sw4cN3e8kiLdNFJM= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= From ce61809e902822d16665ffec33e5524cb01c7a6c Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Wed, 20 Jan 2021 14:12:42 -0500 Subject: [PATCH 6/6] add check if trie is nil --- dot/state/storage.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dot/state/storage.go b/dot/state/storage.go index f1517df2d7..c588b28d1f 100644 --- a/dot/state/storage.go +++ b/dot/state/storage.go @@ -330,8 +330,11 @@ func (s *StorageState) GetKeysWithPrefix(hash *common.Hash, prefix []byte) ([][] } hash = &sr } - - return s.tries[*hash].GetKeysWithPrefix(prefix), nil + t := s.tries[*hash] + if t == nil { + return nil, fmt.Errorf("unable to retrieve trie with hash %x", *hash) + } + return t.GetKeysWithPrefix(prefix), nil } // GetStorageChild return GetChild from the trie