From d50e36fbf9a4cf6ccb1932739e352c69c64f76d4 Mon Sep 17 00:00:00 2001 From: noot Date: Tue, 9 Mar 2021 21:30:52 -0500 Subject: [PATCH 1/9] working on trie.NextKey --- lib/runtime/wasmer/imports.go | 6 -- lib/trie/trie.go | 175 +++++++++++++++++++++++----------- 2 files changed, 119 insertions(+), 62 deletions(-) diff --git a/lib/runtime/wasmer/imports.go b/lib/runtime/wasmer/imports.go index ed14af9334..7284c26eb6 100644 --- a/lib/runtime/wasmer/imports.go +++ b/lib/runtime/wasmer/imports.go @@ -1632,12 +1632,6 @@ func ext_storage_clear_prefix_version_1(context unsafe.Pointer, prefixSpan C.int if err != nil { logger.Error("[ext_storage_clear_prefix_version_1]", "error", err) } - - // sanity check - next := storage.NextKey(prefix) - if len(next) >= len(prefix) && bytes.Equal(prefix, next[:len(prefix)]) { - panic("did not clear prefix") - } } //export ext_storage_exists_version_1 diff --git a/lib/trie/trie.go b/lib/trie/trie.go index a5f59e1608..1ef2e18c05 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -152,7 +152,7 @@ func (t *Trie) entries(current node, prefix []byte, kv map[string][]byte) map[st func (t *Trie) NextKey(key []byte) []byte { k := keyToNibbles(key) - next := t.nextKey([]node{}, t.root, nil, k) + next := t.nextKey(t.root, nil, k) if next == nil { return nil } @@ -160,90 +160,153 @@ func (t *Trie) NextKey(key []byte) []byte { return nibblesToKeyLE(next) } -func (t *Trie) nextKey(ancestors []node, current node, prefix, target []byte) []byte { - switch c := current.(type) { +func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { + switch c := curr.(type) { case *branch: - fullKey := append(prefix, c.key...) - - if bytes.Equal(target, fullKey) { - for i, child := range c.children { - if child == nil { - continue - } + var cmp int + if len(key) < len(c.key) { + cmp = -1 + } else { + cmp = bytes.Compare(c.key, key[:len(c.key)]) // if cmp == 1, then p.key is lexigraphically greater than the key arg + } - // descend and return first key - return returnFirstKey(append(fullKey, byte(i)), child) + // length of key arg is less than branch key, return key of first child (or key of this branch, if not empty value) + if cmp > -1 && len(key) <= len(c.key) { + if c.value != nil && bytes.Compare(c.key, key) > 0 { + return append(prefix, c.key...) } - } - if len(target) >= len(fullKey) && bytes.Equal(target[:len(fullKey)], fullKey) { for i, child := range c.children { - if child == nil || byte(i) != target[len(fullKey)] { + if child == nil { continue } - return t.nextKey(append([]node{c}, ancestors...), child, append(fullKey, byte(i)), target) + next := t.nextKey(child, append(prefix, append(c.key, byte(i))...), []byte{}) + if len(next) != 0 { + return next + } } } - case *leaf: - fullKey := append(prefix, c.key...) - if bytes.Equal(target, fullKey) { - // ancestors are all branches, find one with another child w/ index greater than ours - for _, anc := range ancestors { - // index of the current node in its parent branch - myIdx := prefix[len(prefix)-1] - - br, ok := anc.(*branch) - if !ok { - return nil + if cmp > -1 && len(key) > len(c.key) { + idx := key[len(c.key)] + for i, child := range c.children[idx:] { + if child == nil { + continue } - prefix = prefix[:len(prefix)-len(br.key)-1] - - if br.childrenBitmap()>>(myIdx+1) == 0 { + if _, ok := child.(*leaf); ok && i == 0 { continue } - // descend into ancestor's other children - for i, child := range br.children[myIdx+1:] { - idx := byte(i) + myIdx + 1 - - if child == nil { - continue - } - - return returnFirstKey(append(prefix, append(br.key, idx)...), child) + next := t.nextKey(child, append(prefix, append(c.key, byte(i)+byte(idx))...), key[len(c.key)+1:]) + if len(next) != 0 { + return next } } } - } - return nil -} + // // found the value at this node + // if bytes.Equal(p.key, key) || len(key) == 0 { + // return &leaf{key: p.key, value: p.value, dirty: false} + // } -// returnFirstKey descends into a node and returns the first key with an associated value -func returnFirstKey(prefix []byte, n node) []byte { - switch c := n.(type) { - case *branch: - if c.value != nil { - return append(prefix, c.key...) - } - - for i, child := range c.children { - if child == nil { - continue - } + // // did not find value + // if bytes.Equal(p.key[:length], key) && len(key) < len(p.key) { + // return nil + // } - return returnFirstKey(append(prefix, append(c.key, byte(i))...), child) - } + //value = t.retrieve(c.children[key[length]], key[length+1:]) case *leaf: return append(prefix, c.key...) + case nil: + return nil } + return nil + + // switch c := current.(type) { + // case *branch: + // fullKey := append(prefix, c.key...) + + // if bytes.Equal(target, fullKey) { + // for i, child := range c.children { + // if child == nil { + // continue + // } + + // // descend and return first key + // return returnFirstKey(append(fullKey, byte(i)), child) + // } + // } + + // if len(target) >= len(fullKey) && bytes.Equal(target[:len(fullKey)], fullKey) { + // for i, child := range c.children { + // if child == nil || byte(i) != target[len(fullKey)] { + // continue + // } + + // return t.nextKey(append([]node{c}, ancestors...), child, append(fullKey, byte(i)), target) + // } + // } + // case *leaf: + // fullKey := append(prefix, c.key...) + + // if bytes.Equal(target, fullKey) { + // // ancestors are all branches, find one with another child w/ index greater than ours + // for _, anc := range ancestors { + // // index of the current node in its parent branch + // myIdx := prefix[len(prefix)-1] + + // br, ok := anc.(*branch) + // if !ok { + // return nil + // } + + // prefix = prefix[:len(prefix)-len(br.key)-1] + + // if br.childrenBitmap()>>(myIdx+1) == 0 { + // continue + // } + + // // descend into ancestor's other children + // for i, child := range br.children[myIdx+1:] { + // idx := byte(i) + myIdx + 1 + + // if child == nil { + // continue + // } + + // return returnFirstKey(append(prefix, append(br.key, idx)...), child) + // } + // } + // } + // } return nil } +// // returnFirstKey descends into a node and returns the first key with an associated value +// func returnFirstKey(prefix []byte, n node) []byte { +// switch c := n.(type) { +// case *branch: +// if c.value != nil { +// return append(prefix, c.key...) +// } + +// for i, child := range c.children { +// if child == nil { +// continue +// } + +// return returnFirstKey(append(prefix, append(c.key, byte(i))...), child) +// } +// case *leaf: +// return append(prefix, c.key...) +// } + +// return nil +// } + // Put inserts a key with value into the trie func (t *Trie) Put(key, value []byte) { t.tryPut(key, value) From 23594569e6fc1f7135a949389f5e6eee4d2673b1 Mon Sep 17 00:00:00 2001 From: noot Date: Wed, 10 Mar 2021 16:16:55 -0500 Subject: [PATCH 2/9] test seemingly functional NextKey --- lib/runtime/storage/trie.go | 32 +++---- lib/runtime/storage/trie_test.go | 4 +- lib/runtime/wasmer/exports_test.go | 4 - lib/trie/trie.go | 136 ++++++----------------------- lib/trie/trie_test.go | 57 +++++++++++- 5 files changed, 102 insertions(+), 131 deletions(-) diff --git a/lib/runtime/storage/trie.go b/lib/runtime/storage/trie.go index 59d164f7fb..a8bd3cdeb6 100644 --- a/lib/runtime/storage/trie.go +++ b/lib/runtime/storage/trie.go @@ -17,7 +17,7 @@ package storage import ( - "bytes" + //"bytes" "encoding/binary" "sync" @@ -101,26 +101,26 @@ func (s *TrieState) Delete(key []byte) { func (s *TrieState) NextKey(key []byte) []byte { s.lock.RLock() defer s.lock.RUnlock() - keys := s.t.GetKeysWithPrefix([]byte{}) + // keys := s.t.GetKeysWithPrefix([]byte{}) - for i, k := range keys { - if i == len(keys)-1 { - return nil - } + // for i, k := range keys { + // if i == len(keys)-1 { + // return nil + // } - if bytes.Equal(key, k) { - return keys[i+1] - } + // if bytes.Equal(key, k) { + // return keys[i+1] + // } - // `keys` is already is lexigraphical order, so if k is greater than `key`, it's next - if bytes.Compare(k, key) == 1 { - return k - } - } + // // `keys` is already is lexigraphical order, so if k is greater than `key`, it's next + // if bytes.Compare(k, key) == 1 { + // return k + // } + // } // TODO: fix this!! - //return s.t.NextKey(key) - return nil + return s.t.NextKey(key) + //return nil } // ClearPrefix deletes all key-value pairs from the trie where the key starts with the given prefix diff --git a/lib/runtime/storage/trie_test.go b/lib/runtime/storage/trie_test.go index eac7a9f926..8d9a8da5e5 100644 --- a/lib/runtime/storage/trie_test.go +++ b/lib/runtime/storage/trie_test.go @@ -21,6 +21,7 @@ import ( "sort" "testing" + "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/trie" "github.com/stretchr/testify/require" ) @@ -151,6 +152,7 @@ func TestTrieState_NextKey(t *testing.T) { ts.Set([]byte(tc), []byte(tc)) } + t.Log(ts.t) sort.Slice(testCases, func(i, j int) bool { return bytes.Compare([]byte(testCases[i]), []byte(testCases[j])) == -1 }) @@ -160,7 +162,7 @@ func TestTrieState_NextKey(t *testing.T) { if i == len(testCases)-1 { require.Nil(t, next) } else { - require.Equal(t, []byte(testCases[i+1]), next) + require.Equal(t, []byte(testCases[i+1]), next, common.BytesToHex([]byte(tc))) } } } diff --git a/lib/runtime/wasmer/exports_test.go b/lib/runtime/wasmer/exports_test.go index c78c0e4e8c..fcdcb20746 100644 --- a/lib/runtime/wasmer/exports_test.go +++ b/lib/runtime/wasmer/exports_test.go @@ -643,10 +643,6 @@ func TestInstance_ExecuteBlock_KusamaRuntime_KusamaBlock901442(t *testing.T) { } func TestInstance_ExecuteBlock_KusamaRuntime_KusamaBlock1377831(t *testing.T) { - if testing.Short() { - t.Skip("this test takes around 3min to run at the moment") - } - ksmTrie := newTrieFromPairs(t, "../test_data/block1377830_kusama.out") expectedRoot := common.MustHexToHash("0xe4de6fecda9e9e35f937d159665cf984bc1a68048b6c78912de0aeb6bd7f7e99") require.Equal(t, expectedRoot, ksmTrie.MustHash()) diff --git a/lib/trie/trie.go b/lib/trie/trie.go index 1ef2e18c05..71aca16643 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -163,17 +163,18 @@ func (t *Trie) NextKey(key []byte) []byte { func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { switch c := curr.(type) { case *branch: + fullKey := append(prefix, c.key...) var cmp int - if len(key) < len(c.key) { - cmp = -1 + if len(key) < len(fullKey) { + cmp = 1 // the key is lexigraphically less than the current node key. return first key available } else { - cmp = bytes.Compare(c.key, key[:len(c.key)]) // if cmp == 1, then p.key is lexigraphically greater than the key arg + cmp = bytes.Compare(fullKey, key[:len(fullKey)]) // if cmp == 1, then node key is lexigraphically greater than the key arg } - // length of key arg is less than branch key, return key of first child (or key of this branch, if not empty value) - if cmp > -1 && len(key) <= len(c.key) { - if c.value != nil && bytes.Compare(c.key, key) > 0 { - return append(prefix, c.key...) + // length of key arg is less than branch key, return key of first child (or key of this branch, if it's a branch w/ value) + if (cmp > -1 && len(key) == len(fullKey)) || cmp == 1 { + if c.value != nil && bytes.Compare(fullKey, key) > 0 { + return fullKey } for i, child := range c.children { @@ -181,132 +182,49 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { continue } - next := t.nextKey(child, append(prefix, append(c.key, byte(i))...), []byte{}) + next := t.nextKey(child, append(fullKey, byte(i)), key) if len(next) != 0 { return next } } } - if cmp > -1 && len(key) > len(c.key) { - idx := key[len(c.key)] + // node key isn't greater than the arg key, continue to iterate + if cmp > -1 && len(key) > len(fullKey) { + idx := key[len(fullKey)] for i, child := range c.children[idx:] { if child == nil { continue } - if _, ok := child.(*leaf); ok && i == 0 { - continue - } + // if _, ok := child.(*leaf); ok && i == 0 && !bytes.Equal(fullKey, key[:len(fullKey)]) { + // continue + // } - next := t.nextKey(child, append(prefix, append(c.key, byte(i)+byte(idx))...), key[len(c.key)+1:]) + next := t.nextKey(child, append(fullKey, byte(i)+byte(idx)), key) if len(next) != 0 { return next } } } - - // // found the value at this node - // if bytes.Equal(p.key, key) || len(key) == 0 { - // return &leaf{key: p.key, value: p.value, dirty: false} - // } - - // // did not find value - // if bytes.Equal(p.key[:length], key) && len(key) < len(p.key) { - // return nil - // } - - //value = t.retrieve(c.children[key[length]], key[length+1:]) case *leaf: - return append(prefix, c.key...) + fullKey := append(prefix, c.key...) + var cmp int + if len(key) < len(fullKey) { + cmp = 1 // the key is lexigraphically less than the current node key. return first key available + } else { + cmp = bytes.Compare(fullKey, key[:len(fullKey)]) // if cmp == 1, then node key is lexigraphically greater than the key arg + } + + if cmp == 1 { + return append(prefix, c.key...) + } case nil: return nil } return nil - - // switch c := current.(type) { - // case *branch: - // fullKey := append(prefix, c.key...) - - // if bytes.Equal(target, fullKey) { - // for i, child := range c.children { - // if child == nil { - // continue - // } - - // // descend and return first key - // return returnFirstKey(append(fullKey, byte(i)), child) - // } - // } - - // if len(target) >= len(fullKey) && bytes.Equal(target[:len(fullKey)], fullKey) { - // for i, child := range c.children { - // if child == nil || byte(i) != target[len(fullKey)] { - // continue - // } - - // return t.nextKey(append([]node{c}, ancestors...), child, append(fullKey, byte(i)), target) - // } - // } - // case *leaf: - // fullKey := append(prefix, c.key...) - - // if bytes.Equal(target, fullKey) { - // // ancestors are all branches, find one with another child w/ index greater than ours - // for _, anc := range ancestors { - // // index of the current node in its parent branch - // myIdx := prefix[len(prefix)-1] - - // br, ok := anc.(*branch) - // if !ok { - // return nil - // } - - // prefix = prefix[:len(prefix)-len(br.key)-1] - - // if br.childrenBitmap()>>(myIdx+1) == 0 { - // continue - // } - - // // descend into ancestor's other children - // for i, child := range br.children[myIdx+1:] { - // idx := byte(i) + myIdx + 1 - - // if child == nil { - // continue - // } - - // return returnFirstKey(append(prefix, append(br.key, idx)...), child) - // } - // } - // } - // } - - return nil } -// // returnFirstKey descends into a node and returns the first key with an associated value -// func returnFirstKey(prefix []byte, n node) []byte { -// switch c := n.(type) { -// case *branch: -// if c.value != nil { -// return append(prefix, c.key...) -// } - -// for i, child := range c.children { -// if child == nil { -// continue -// } - -// return returnFirstKey(append(prefix, append(c.key, byte(i))...), child) -// } -// case *leaf: -// return append(prefix, c.key...) -// } - -// return nil -// } - // Put inserts a key with value into the trie func (t *Trie) Put(key, value []byte) { t.tryPut(key, value) diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index fe0401e07c..955beff0c5 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -634,6 +634,7 @@ func TestNextKey_MoreAncestors(t *testing.T) { {key: []byte{0x01, 0x35, 0x79}, value: []byte("gnocchi"), op: PUT}, {key: []byte{0x01, 0x35, 0x79, 0xab}, value: []byte("spaghetti"), op: PUT}, {key: []byte{0x01, 0x35, 0x79, 0xab, 0x9}, value: []byte("gnocchi"), op: PUT}, + {key: []byte{0x01, 0x35, 0x79, 0xab, 0xf}, value: []byte("gnocchi"), op: PUT}, {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}, @@ -673,13 +674,67 @@ func TestNextKey_MoreAncestors(t *testing.T) { }, { tests[6].key, + tests[7].key, + }, + { + tests[7].key, nil, }, + { + []byte{}, + tests[0].key, + }, + { + []byte{0}, + tests[0].key, + }, + { + []byte{0x01}, + tests[0].key, + }, + { + []byte{0x02}, + tests[5].key, + }, + { + []byte{0x05, 0x12, 0x34}, + tests[5].key, + }, + { + []byte{0xf}, + tests[7].key, + }, } for _, tc := range testCases { next := trie.NextKey(tc.input) - require.Equal(t, tc.expected, next) + require.Equal(t, tc.expected, next, common.BytesToHex(tc.input)) + } +} + +func TestNextKey_Again(t *testing.T) { + trie := NewEmptyTrie() + + var testCases = []string{ + "asdf", + "bnm", + "ghjk", + "qwerty", + "uiopl", + "zxcv", + } + + for _, tc := range testCases { + trie.Put([]byte(tc), []byte(tc)) + } + + for i, tc := range testCases { + next := trie.NextKey([]byte(tc)) + if i == len(testCases)-1 { + require.Nil(t, next) + } else { + require.Equal(t, []byte(testCases[i+1]), next, common.BytesToHex([]byte(tc))) + } } } From e666fa76c67bd409d57e1f207725436482f9f0b4 Mon Sep 17 00:00:00 2001 From: noot Date: Wed, 10 Mar 2021 16:18:45 -0500 Subject: [PATCH 3/9] lint --- lib/trie/trie.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/trie/trie.go b/lib/trie/trie.go index 71aca16643..eed3e2d28a 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -201,7 +201,7 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { // continue // } - next := t.nextKey(child, append(fullKey, byte(i)+byte(idx)), key) + next := t.nextKey(child, append(fullKey, byte(i)+idx), key) if len(next) != 0 { return next } From ae8c764930e7ede2c8df6a2bd47c8f9737ce2a77 Mon Sep 17 00:00:00 2001 From: noot Date: Wed, 10 Mar 2021 16:25:52 -0500 Subject: [PATCH 4/9] cleanup --- lib/runtime/storage/trie.go | 19 ------------------- lib/trie/trie.go | 4 ---- 2 files changed, 23 deletions(-) diff --git a/lib/runtime/storage/trie.go b/lib/runtime/storage/trie.go index a8bd3cdeb6..37621f82f5 100644 --- a/lib/runtime/storage/trie.go +++ b/lib/runtime/storage/trie.go @@ -101,26 +101,7 @@ func (s *TrieState) Delete(key []byte) { func (s *TrieState) NextKey(key []byte) []byte { s.lock.RLock() defer s.lock.RUnlock() - // keys := s.t.GetKeysWithPrefix([]byte{}) - - // for i, k := range keys { - // if i == len(keys)-1 { - // return nil - // } - - // if bytes.Equal(key, k) { - // return keys[i+1] - // } - - // // `keys` is already is lexigraphical order, so if k is greater than `key`, it's next - // if bytes.Compare(k, key) == 1 { - // return k - // } - // } - - // TODO: fix this!! return s.t.NextKey(key) - //return nil } // ClearPrefix deletes all key-value pairs from the trie where the key starts with the given prefix diff --git a/lib/trie/trie.go b/lib/trie/trie.go index eed3e2d28a..05aec1d375 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -197,10 +197,6 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { continue } - // if _, ok := child.(*leaf); ok && i == 0 && !bytes.Equal(fullKey, key[:len(fullKey)]) { - // continue - // } - next := t.nextKey(child, append(fullKey, byte(i)+idx), key) if len(next) != 0 { return next From 765d9b01f890c0f25b6d5edbc2d7767cf8d94bd6 Mon Sep 17 00:00:00 2001 From: noot Date: Wed, 10 Mar 2021 16:49:20 -0500 Subject: [PATCH 5/9] simplify a bit --- lib/trie/trie.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/trie/trie.go b/lib/trie/trie.go index 05aec1d375..d63ba07ae3 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -172,7 +172,7 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { } // length of key arg is less than branch key, return key of first child (or key of this branch, if it's a branch w/ value) - if (cmp > -1 && len(key) == len(fullKey)) || cmp == 1 { + if (cmp == 0 && len(key) == len(fullKey)) || cmp == 1 { if c.value != nil && bytes.Compare(fullKey, key) > 0 { return fullKey } @@ -190,7 +190,7 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { } // node key isn't greater than the arg key, continue to iterate - if cmp > -1 && len(key) > len(fullKey) { + if cmp < 1 && len(key) > len(fullKey) { idx := key[len(fullKey)] for i, child := range c.children[idx:] { if child == nil { From c19b72117e7256f47af3ece9e598406be7d8a397 Mon Sep 17 00:00:00 2001 From: Arijit Das Date: Thu, 11 Mar 2021 19:41:39 +0530 Subject: [PATCH 6/9] Add randomized test for next trie value. --- lib/trie/trie_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index 955beff0c5..02f32c2291 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -24,6 +24,7 @@ import ( "math/rand" "os" "path/filepath" + "sort" "strconv" "strings" "testing" @@ -994,3 +995,44 @@ func TestSnapshot(t *testing.T) { require.Equal(t, expectedTrie.MustHash(), newTrie.MustHash()) require.NotEqual(t, parentSnapshot.MustHash(), newTrie.MustHash()) } + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func RandStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} + +func TestNextKey_Random(t *testing.T) { + for i := 0; i < 100; i++ { + trie := NewEmptyTrie() + + // Generate random test cases. + testCases := make([]string, 1000+rand.Intn(10000)) + for ii := 0; ii < len(testCases); ii++ { + testCases[ii] = RandStringBytes(1 + rand.Intn(20)) + } + + sort.Slice(testCases, func(i, j int) bool { + return strings.Compare(testCases[i], testCases[j]) < 0 + }) + + for _, tc := range testCases { + trie.Put([]byte(tc), []byte(tc)) + } + + fmt.Println("Iteration: ", i) + + for idx, tc := range testCases { + next := trie.NextKey([]byte(tc)) + if idx == len(testCases)-1 { + require.Nil(t, next) + } else { + require.Equal(t, []byte(testCases[idx+1]), next, common.BytesToHex([]byte(tc))) + } + } + } +} From 2f1057386d857dc32eb90c7ac20b81e8684aa4e1 Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 11 Mar 2021 10:54:50 -0500 Subject: [PATCH 7/9] fix test and update comments --- lib/runtime/storage/trie.go | 1 - lib/trie/trie.go | 12 ++++++++---- lib/trie/trie_test.go | 24 +++++++++++++++++++----- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/runtime/storage/trie.go b/lib/runtime/storage/trie.go index 37621f82f5..ded5568283 100644 --- a/lib/runtime/storage/trie.go +++ b/lib/runtime/storage/trie.go @@ -17,7 +17,6 @@ package storage import ( - //"bytes" "encoding/binary" "sync" diff --git a/lib/trie/trie.go b/lib/trie/trie.go index d63ba07ae3..169d9cad65 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -166,9 +166,11 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { fullKey := append(prefix, c.key...) var cmp int if len(key) < len(fullKey) { - cmp = 1 // the key is lexigraphically less than the current node key. return first key available + // the key is lexicographically less than the current node key. return first key available + cmp = 1 } else { - cmp = bytes.Compare(fullKey, key[:len(fullKey)]) // if cmp == 1, then node key is lexigraphically greater than the key arg + // if cmp == 1, then node key is lexicographically greater than the key arg + cmp = bytes.Compare(fullKey, key[:len(fullKey)]) } // length of key arg is less than branch key, return key of first child (or key of this branch, if it's a branch w/ value) @@ -207,9 +209,11 @@ func (t *Trie) nextKey(curr node, prefix, key []byte) []byte { fullKey := append(prefix, c.key...) var cmp int if len(key) < len(fullKey) { - cmp = 1 // the key is lexigraphically less than the current node key. return first key available + // the key is lexicographically less than the current node key. return first key available + cmp = 1 } else { - cmp = bytes.Compare(fullKey, key[:len(fullKey)]) // if cmp == 1, then node key is lexigraphically greater than the key arg + // if cmp == 1, then node key is lexicographically greater than the key arg + cmp = bytes.Compare(fullKey, key[:len(fullKey)]) } if cmp == 1 { diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index 02f32c2291..8a543fdb4e 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -1011,13 +1011,27 @@ func TestNextKey_Random(t *testing.T) { trie := NewEmptyTrie() // Generate random test cases. - testCases := make([]string, 1000+rand.Intn(10000)) - for ii := 0; ii < len(testCases); ii++ { - testCases[ii] = RandStringBytes(1 + rand.Intn(20)) + testCaseMap := make(map[string]struct{}) // ensure no duplicate keys + size := 1000 + rand.Intn(10000) + + for ii := 0; ii < size; ii++ { + str := RandStringBytes(1 + rand.Intn(20)) + if len(str) == 0 { + continue + } + testCaseMap[str] = struct{}{} + } + + testCases := make([][]byte, len(testCaseMap)) + j := 0 + + for k := range testCaseMap { + testCases[j] = []byte(k) + j++ } sort.Slice(testCases, func(i, j int) bool { - return strings.Compare(testCases[i], testCases[j]) < 0 + return bytes.Compare(testCases[i], testCases[j]) < 0 }) for _, tc := range testCases { @@ -1031,7 +1045,7 @@ func TestNextKey_Random(t *testing.T) { if idx == len(testCases)-1 { require.Nil(t, next) } else { - require.Equal(t, []byte(testCases[idx+1]), next, common.BytesToHex([]byte(tc))) + require.Equal(t, []byte(testCases[idx+1]), next, common.BytesToHex([]byte(tc)), trie) } } } From a6ad558ac457a5e662c1628f57a4d1edcd50fd65 Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 11 Mar 2021 10:57:53 -0500 Subject: [PATCH 8/9] lint --- lib/trie/trie_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index 8a543fdb4e..4b9a609ffa 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -1041,11 +1041,11 @@ func TestNextKey_Random(t *testing.T) { fmt.Println("Iteration: ", i) for idx, tc := range testCases { - next := trie.NextKey([]byte(tc)) + next := trie.NextKey(tc) if idx == len(testCases)-1 { require.Nil(t, next) } else { - require.Equal(t, []byte(testCases[idx+1]), next, common.BytesToHex([]byte(tc)), trie) + require.Equal(t, testCases[idx+1], next, common.BytesToHex(tc)) } } } From 464426d79d50242266ba72404f6f909b2209427e Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 11 Mar 2021 10:58:38 -0500 Subject: [PATCH 9/9] lint --- lib/trie/trie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index 4b9a609ffa..2edbde6259 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -1035,7 +1035,7 @@ func TestNextKey_Random(t *testing.T) { }) for _, tc := range testCases { - trie.Put([]byte(tc), []byte(tc)) + trie.Put(tc, tc) } fmt.Println("Iteration: ", i)