Skip to content

Commit d2da7fb

Browse files
authored
chore(trie): proof code refactoring and fixes (#2604)
- New package `lib/trie/proof` containing: - `lib/trie/proof.go` (refactored) - `internal/trie/record` files (then removed) - `lib/trie/database.go` (moved since it had nothing to do with database) - Proof `Verify` function: - ⚠️ returns an error when root is not found in proof encoded nodes - ⚠️ fix `buildTrie` to detect root node for roots with encoding smaller than 32 bytes - ⚠️ Removes child with no matching hash from proof trie - ⚠️ Only decode root node, and then lazy decode nodes. **This is to allow for 'values' (not node encodings) to be together node encodings with v1 generated proofs**. - Only verify for a single key and value instead of pairs (no usage at all) - Produce ordered (from root to leaf) proof encoded nodes - Returns only an error and no boolean (was unneeded before) - Proof `Generate` function: - ⚠️ returns an error when one key is not found in trie when generating proof - Remove `internal/trie/recorder` code (now unneeded) - Generate encoded nodes ordered from root to leaf (to reduce verify hash computations) - Do not add inlined nodes - Add full coverage unit tests and remove older tests - Minor changes - Better error wrapping - Database arguments uses a smaller locally defined `Database` interface in `proof` and `trie` packages - rename `proofEncodedNodes` to `encodedProofNodes` - rename `decProofs` to `encodedProofNodes`
1 parent a0a1804 commit d2da7fb

20 files changed

+1839
-629
lines changed

dot/state/storage.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/ChainSafe/gossamer/lib/common"
1515
rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage"
1616
"github.com/ChainSafe/gossamer/lib/trie"
17+
"github.com/ChainSafe/gossamer/lib/trie/proof"
1718
)
1819

1920
// storagePrefix storage key prefix.
@@ -301,6 +302,7 @@ func (s *StorageState) LoadCodeHash(hash *common.Hash) (common.Hash, error) {
301302
}
302303

303304
// GenerateTrieProof returns the proofs related to the keys on the state root trie
304-
func (s *StorageState) GenerateTrieProof(stateRoot common.Hash, keys [][]byte) ([][]byte, error) {
305-
return trie.GenerateProof(stateRoot[:], keys, s.db)
305+
func (s *StorageState) GenerateTrieProof(stateRoot common.Hash, keys [][]byte) (
306+
encodedProofNodes [][]byte, err error) {
307+
return proof.Generate(stateRoot[:], keys, s.db)
306308
}

internal/trie/node/children.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,13 @@ func (n *Node) NumChildren() (count int) {
3030
}
3131
return count
3232
}
33+
34+
// HasChild returns true if the node has at least one child.
35+
func (n *Node) HasChild() (has bool) {
36+
for _, child := range n.Children {
37+
if child != nil {
38+
return true
39+
}
40+
}
41+
return false
42+
}

internal/trie/node/children_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,42 @@ func Test_Node_NumChildren(t *testing.T) {
118118
})
119119
}
120120
}
121+
122+
func Test_Node_HasChild(t *testing.T) {
123+
t.Parallel()
124+
125+
testCases := map[string]struct {
126+
node Node
127+
has bool
128+
}{
129+
"no child": {},
130+
"one child at index 0": {
131+
node: Node{
132+
Children: []*Node{
133+
{},
134+
},
135+
},
136+
has: true,
137+
},
138+
"one child at index 1": {
139+
node: Node{
140+
Children: []*Node{
141+
nil,
142+
{},
143+
},
144+
},
145+
has: true,
146+
},
147+
}
148+
149+
for name, testCase := range testCases {
150+
testCase := testCase
151+
t.Run(name, func(t *testing.T) {
152+
t.Parallel()
153+
154+
has := testCase.node.HasChild()
155+
156+
assert.Equal(t, testCase.has, has)
157+
})
158+
}
159+
}

internal/trie/record/node.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

internal/trie/record/recorder.go

Lines changed: 0 additions & 27 deletions
This file was deleted.

internal/trie/record/recorder_test.go

Lines changed: 0 additions & 122 deletions
This file was deleted.

lib/runtime/wasmer/imports.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ import (
121121
rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage"
122122
"github.com/ChainSafe/gossamer/lib/transaction"
123123
"github.com/ChainSafe/gossamer/lib/trie"
124+
"github.com/ChainSafe/gossamer/lib/trie/proof"
124125
"github.com/ChainSafe/gossamer/pkg/scale"
125126

126127
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
@@ -886,8 +887,8 @@ func ext_trie_blake2_256_verify_proof_version_1(context unsafe.Pointer, rootSpan
886887
instanceContext := wasm.IntoInstanceContext(context)
887888

888889
toDecProofs := asMemorySlice(instanceContext, proofSpan)
889-
var decProofs [][]byte
890-
err := scale.Unmarshal(toDecProofs, &decProofs)
890+
var encodedProofNodes [][]byte
891+
err := scale.Unmarshal(toDecProofs, &encodedProofNodes)
891892
if err != nil {
892893
logger.Errorf("[ext_trie_blake2_256_verify_proof_version_1]: %s", err)
893894
return C.int32_t(0)
@@ -899,18 +900,13 @@ func ext_trie_blake2_256_verify_proof_version_1(context unsafe.Pointer, rootSpan
899900
mem := instanceContext.Memory().Data()
900901
trieRoot := mem[rootSpan : rootSpan+32]
901902

902-
exists, err := trie.VerifyProof(decProofs, trieRoot, []trie.Pair{{Key: key, Value: value}})
903+
err = proof.Verify(encodedProofNodes, trieRoot, key, value)
903904
if err != nil {
904905
logger.Errorf("[ext_trie_blake2_256_verify_proof_version_1]: %s", err)
905906
return C.int32_t(0)
906907
}
907908

908-
var result C.int32_t = 0
909-
if exists {
910-
result = 1
911-
}
912-
913-
return result
909+
return C.int32_t(1)
914910
}
915911

916912
//export ext_misc_print_hex_version_1

lib/runtime/wasmer/imports_test.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/ChainSafe/gossamer/lib/runtime"
2323
"github.com/ChainSafe/gossamer/lib/runtime/storage"
2424
"github.com/ChainSafe/gossamer/lib/trie"
25+
"github.com/ChainSafe/gossamer/lib/trie/proof"
2526
"github.com/ChainSafe/gossamer/pkg/scale"
2627
"github.com/stretchr/testify/assert"
2728
"github.com/stretchr/testify/require"
@@ -1801,7 +1802,7 @@ func Test_ext_trie_blake2_256_verify_proof_version_1(t *testing.T) {
18011802
root := hash.ToBytes()
18021803
otherRoot := otherHash.ToBytes()
18031804

1804-
proof, err := trie.GenerateProof(root, keys, memdb)
1805+
allProofs, err := proof.Generate(root, keys, memdb)
18051806
require.NoError(t, err)
18061807

18071808
testcases := map[string]struct {
@@ -1810,17 +1811,17 @@ func Test_ext_trie_blake2_256_verify_proof_version_1(t *testing.T) {
18101811
expect bool
18111812
}{
18121813
"Proof should be true": {
1813-
root: root, key: []byte("do"), proof: proof, value: []byte("verb"), expect: true},
1814+
root: root, key: []byte("do"), proof: allProofs, value: []byte("verb"), expect: true},
18141815
"Root empty, proof should be false": {
1815-
root: []byte{}, key: []byte("do"), proof: proof, value: []byte("verb"), expect: false},
1816+
root: []byte{}, key: []byte("do"), proof: allProofs, value: []byte("verb"), expect: false},
18161817
"Other root, proof should be false": {
1817-
root: otherRoot, key: []byte("do"), proof: proof, value: []byte("verb"), expect: false},
1818+
root: otherRoot, key: []byte("do"), proof: allProofs, value: []byte("verb"), expect: false},
18181819
"Value empty, proof should be true": {
1819-
root: root, key: []byte("do"), proof: proof, value: nil, expect: true},
1820+
root: root, key: []byte("do"), proof: allProofs, value: nil, expect: true},
18201821
"Unknow key, proof should be false": {
1821-
root: root, key: []byte("unknow"), proof: proof, value: nil, expect: false},
1822+
root: root, key: []byte("unknow"), proof: allProofs, value: nil, expect: false},
18221823
"Key and value unknow, proof should be false": {
1823-
root: root, key: []byte("unknow"), proof: proof, value: []byte("unknow"), expect: false},
1824+
root: root, key: []byte("unknow"), proof: allProofs, value: []byte("unknow"), expect: false},
18241825
"Empty proof, should be false": {
18251826
root: root, key: []byte("do"), proof: [][]byte{}, value: nil, expect: false},
18261827
}

0 commit comments

Comments
 (0)