Skip to content

Commit f6275f6

Browse files
committed
fix(trie): use cached Merkle values for root hash
1 parent 46e19da commit f6275f6

File tree

3 files changed

+37
-113
lines changed

3 files changed

+37
-113
lines changed

internal/trie/node/branch_encode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func encodeChild(child *Node, buffer io.Writer) (err error) {
133133
// and then SCALE encodes it. This is used to encode children
134134
// nodes of branches.
135135
func scaleEncodeHash(node *Node) (encoding []byte, err error) {
136-
_, merkleValue, err := node.EncodeAndHash()
136+
merkleValue, err := node.CalculateMerkleValue()
137137
if err != nil {
138138
return nil, fmt.Errorf("encoding and hashing %s: %w", node.Kind(), err)
139139
}

lib/trie/trie.go

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
// EmptyHash is the empty trie hash.
16-
var EmptyHash, _ = NewEmptyTrie().Hash()
16+
var EmptyHash = common.MustBlake2bHash([]byte{0})
1717

1818
// Trie is a base 16 modified Merkle Patricia trie.
1919
type Trie struct {
@@ -170,18 +170,6 @@ func (t *Trie) RootNode() *Node {
170170
return t.root.Copy(copySettings)
171171
}
172172

173-
// encodeRoot writes the encoding of the root node to the buffer.
174-
func encodeRoot(root *Node, buffer node.Buffer) (err error) {
175-
if root == nil {
176-
_, err = buffer.Write([]byte{0})
177-
if err != nil {
178-
return fmt.Errorf("cannot write nil root node to buffer: %w", err)
179-
}
180-
return nil
181-
}
182-
return root.Encode(buffer)
183-
}
184-
185173
// MustHash returns the hashed root of the trie.
186174
// It panics if it fails to hash the root node.
187175
func (t *Trie) MustHash() common.Hash {
@@ -195,13 +183,17 @@ func (t *Trie) MustHash() common.Hash {
195183

196184
// Hash returns the hashed root of the trie.
197185
func (t *Trie) Hash() (rootHash common.Hash, err error) {
198-
buffer := bytes.NewBuffer(nil)
199-
err = encodeRoot(t.root, buffer)
200-
if err != nil {
201-
return [32]byte{}, err
186+
if t.root == nil {
187+
return EmptyHash, nil
202188
}
203189

204-
return common.Blake2bHash(buffer.Bytes()) // TODO optimisation: use hashers sync pools
190+
merkleValue, err := t.root.CalculateRootMerkleValue()
191+
if err != nil {
192+
// no need to wrap the error really
193+
return rootHash, err
194+
}
195+
copy(rootHash[:], merkleValue)
196+
return rootHash, nil
205197
}
206198

207199
// Entries returns all the key-value pairs in the trie as a map of keys to values

lib/trie/trie_test.go

Lines changed: 26 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,22 @@ import (
1111

1212
"github.com/ChainSafe/gossamer/internal/trie/node"
1313
"github.com/ChainSafe/gossamer/lib/common"
14-
gomock "github.com/golang/mock/gomock"
1514
"github.com/stretchr/testify/assert"
1615
"github.com/stretchr/testify/require"
1716
)
1817

18+
func Test_EmptyHash(t *testing.T) {
19+
t.Parallel()
20+
21+
expected := common.Hash{
22+
0x3, 0x17, 0xa, 0x2e, 0x75, 0x97, 0xb7, 0xb7,
23+
0xe3, 0xd8, 0x4c, 0x5, 0x39, 0x1d, 0x13, 0x9a,
24+
0x62, 0xb1, 0x57, 0xe7, 0x87, 0x86, 0xd8, 0xc0,
25+
0x82, 0xf2, 0x9d, 0xcf, 0x4c, 0x11, 0x13, 0x14,
26+
}
27+
assert.Equal(t, expected, EmptyHash)
28+
}
29+
1930
func Test_NewEmptyTrie(t *testing.T) {
2031
expectedTrie := &Trie{
2132
childTries: make(map[common.Hash]*Trie),
@@ -292,97 +303,6 @@ func Test_Trie_RootNode(t *testing.T) {
292303

293304
//go:generate mockgen -destination=buffer_mock_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/internal/trie/node Buffer
294305

295-
func Test_encodeRoot(t *testing.T) {
296-
t.Parallel()
297-
298-
testCases := map[string]struct {
299-
root *Node
300-
writeCalls []writeCall
301-
errWrapped error
302-
errMessage string
303-
expectedRoot *Node
304-
}{
305-
"nil root and no error": {
306-
writeCalls: []writeCall{
307-
{written: []byte{0}},
308-
},
309-
},
310-
"nil root and write error": {
311-
writeCalls: []writeCall{
312-
{
313-
written: []byte{0},
314-
err: errTest,
315-
},
316-
},
317-
errWrapped: errTest,
318-
errMessage: "cannot write nil root node to buffer: test error",
319-
},
320-
"root encoding error": {
321-
root: &Node{
322-
Key: []byte{1, 2},
323-
SubValue: []byte{1},
324-
},
325-
writeCalls: []writeCall{
326-
{
327-
written: []byte{66},
328-
err: errTest,
329-
},
330-
},
331-
errWrapped: errTest,
332-
errMessage: "cannot encode header: test error",
333-
expectedRoot: &Node{
334-
Key: []byte{1, 2},
335-
SubValue: []byte{1},
336-
},
337-
},
338-
"root encoding success": {
339-
root: &Node{
340-
Key: []byte{1, 2},
341-
SubValue: []byte{1},
342-
},
343-
writeCalls: []writeCall{
344-
{written: []byte{66}},
345-
{written: []byte{18}},
346-
{written: []byte{4, 1}},
347-
},
348-
expectedRoot: &Node{
349-
Key: []byte{1, 2},
350-
SubValue: []byte{1},
351-
},
352-
},
353-
}
354-
355-
for name, testCase := range testCases {
356-
testCase := testCase
357-
t.Run(name, func(t *testing.T) {
358-
t.Parallel()
359-
ctrl := gomock.NewController(t)
360-
361-
buffer := NewMockBuffer(ctrl)
362-
363-
var previousCall *gomock.Call
364-
for _, write := range testCase.writeCalls {
365-
call := buffer.EXPECT().
366-
Write(write.written).
367-
Return(write.n, write.err)
368-
369-
if previousCall != nil {
370-
call.After(previousCall)
371-
}
372-
previousCall = call
373-
}
374-
375-
err := encodeRoot(testCase.root, buffer)
376-
377-
assert.ErrorIs(t, err, testCase.errWrapped)
378-
if testCase.errWrapped != nil {
379-
assert.EqualError(t, err, testCase.errMessage)
380-
}
381-
assert.Equal(t, testCase.expectedRoot, testCase.root)
382-
})
383-
}
384-
}
385-
386306
func Test_Trie_MustHash(t *testing.T) {
387307
t.Parallel()
388308

@@ -435,6 +355,12 @@ func Test_Trie_Hash(t *testing.T) {
435355
root: &Node{
436356
Key: []byte{1, 2, 3},
437357
SubValue: []byte{1},
358+
MerkleValue: []byte{
359+
0xa8, 0x13, 0x7c, 0xee, 0xb4, 0xad, 0xea, 0xac,
360+
0x9e, 0x5b, 0x37, 0xe2, 0x8e, 0x7d, 0x64, 0x78,
361+
0xac, 0xba, 0xb0, 0x6e, 0x90, 0x76, 0xe4, 0x67,
362+
0xa1, 0xd8, 0xa2, 0x29, 0x4e, 0x4a, 0xd9, 0xa3,
363+
},
438364
},
439365
},
440366
},
@@ -456,8 +382,14 @@ func Test_Trie_Hash(t *testing.T) {
456382
0xf0, 0xe, 0xd3, 0x39, 0x48, 0x21, 0xe3, 0xdd},
457383
expectedTrie: Trie{
458384
root: &Node{
459-
Key: []byte{1, 2, 3},
460-
SubValue: []byte("branch"),
385+
Key: []byte{1, 2, 3},
386+
SubValue: []byte("branch"),
387+
MerkleValue: []byte{
388+
0xaa, 0x7e, 0x57, 0x48, 0xb0, 0x27, 0x4d, 0x18,
389+
0xf5, 0x1c, 0xfd, 0x36, 0x4c, 0x4b, 0x56, 0x4a,
390+
0xf5, 0x37, 0x9d, 0xd7, 0xcb, 0xf5, 0x80, 0x15,
391+
0xf0, 0x0e, 0xd3, 0x39, 0x48, 0x21, 0xe3, 0xdd,
392+
},
461393
Descendants: 1,
462394
Children: padRightChildren([]*Node{
463395
{

0 commit comments

Comments
 (0)