diff --git a/internal/trie/node/branch_encode.go b/internal/trie/node/branch_encode.go index 78d55502431..9ed2bed8d23 100644 --- a/internal/trie/node/branch_encode.go +++ b/internal/trie/node/branch_encode.go @@ -133,7 +133,7 @@ func encodeChild(child *Node, buffer io.Writer) (err error) { // and then SCALE encodes it. This is used to encode children // nodes of branches. func scaleEncodeHash(node *Node) (encoding []byte, err error) { - _, merkleValue, err := node.EncodeAndHash() + merkleValue, err := node.CalculateMerkleValue() if err != nil { return nil, fmt.Errorf("encoding and hashing %s: %w", node.Kind(), err) } diff --git a/lib/trie/trie.go b/lib/trie/trie.go index c3fd7f320fc..c42afefd2af 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -13,7 +13,7 @@ import ( ) // EmptyHash is the empty trie hash. -var EmptyHash, _ = NewEmptyTrie().Hash() +var EmptyHash = common.MustBlake2bHash([]byte{0}) // Trie is a base 16 modified Merkle Patricia trie. type Trie struct { @@ -170,18 +170,6 @@ func (t *Trie) RootNode() *Node { return t.root.Copy(copySettings) } -// encodeRoot writes the encoding of the root node to the buffer. -func encodeRoot(root *Node, buffer node.Buffer) (err error) { - if root == nil { - _, err = buffer.Write([]byte{0}) - if err != nil { - return fmt.Errorf("cannot write nil root node to buffer: %w", err) - } - return nil - } - return root.Encode(buffer) -} - // MustHash returns the hashed root of the trie. // It panics if it fails to hash the root node. func (t *Trie) MustHash() common.Hash { @@ -195,13 +183,17 @@ func (t *Trie) MustHash() common.Hash { // Hash returns the hashed root of the trie. func (t *Trie) Hash() (rootHash common.Hash, err error) { - buffer := bytes.NewBuffer(nil) - err = encodeRoot(t.root, buffer) - if err != nil { - return [32]byte{}, err + if t.root == nil { + return EmptyHash, nil } - return common.Blake2bHash(buffer.Bytes()) // TODO optimisation: use hashers sync pools + merkleValue, err := t.root.CalculateRootMerkleValue() + if err != nil { + // no need to wrap the error really + return rootHash, err + } + copy(rootHash[:], merkleValue) + return rootHash, nil } // Entries returns all the key-value pairs in the trie as a map of keys to values diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index d799fa9f663..597b6497d61 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -11,11 +11,22 @@ import ( "github.com/ChainSafe/gossamer/internal/trie/node" "github.com/ChainSafe/gossamer/lib/common" - gomock "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func Test_EmptyHash(t *testing.T) { + t.Parallel() + + expected := common.Hash{ + 0x3, 0x17, 0xa, 0x2e, 0x75, 0x97, 0xb7, 0xb7, + 0xe3, 0xd8, 0x4c, 0x5, 0x39, 0x1d, 0x13, 0x9a, + 0x62, 0xb1, 0x57, 0xe7, 0x87, 0x86, 0xd8, 0xc0, + 0x82, 0xf2, 0x9d, 0xcf, 0x4c, 0x11, 0x13, 0x14, + } + assert.Equal(t, expected, EmptyHash) +} + func Test_NewEmptyTrie(t *testing.T) { expectedTrie := &Trie{ childTries: make(map[common.Hash]*Trie), @@ -292,97 +303,6 @@ func Test_Trie_RootNode(t *testing.T) { //go:generate mockgen -destination=buffer_mock_test.go -package $GOPACKAGE github.com/ChainSafe/gossamer/internal/trie/node Buffer -func Test_encodeRoot(t *testing.T) { - t.Parallel() - - testCases := map[string]struct { - root *Node - writeCalls []writeCall - errWrapped error - errMessage string - expectedRoot *Node - }{ - "nil root and no error": { - writeCalls: []writeCall{ - {written: []byte{0}}, - }, - }, - "nil root and write error": { - writeCalls: []writeCall{ - { - written: []byte{0}, - err: errTest, - }, - }, - errWrapped: errTest, - errMessage: "cannot write nil root node to buffer: test error", - }, - "root encoding error": { - root: &Node{ - Key: []byte{1, 2}, - SubValue: []byte{1}, - }, - writeCalls: []writeCall{ - { - written: []byte{66}, - err: errTest, - }, - }, - errWrapped: errTest, - errMessage: "cannot encode header: test error", - expectedRoot: &Node{ - Key: []byte{1, 2}, - SubValue: []byte{1}, - }, - }, - "root encoding success": { - root: &Node{ - Key: []byte{1, 2}, - SubValue: []byte{1}, - }, - writeCalls: []writeCall{ - {written: []byte{66}}, - {written: []byte{18}}, - {written: []byte{4, 1}}, - }, - expectedRoot: &Node{ - Key: []byte{1, 2}, - SubValue: []byte{1}, - }, - }, - } - - for name, testCase := range testCases { - testCase := testCase - t.Run(name, func(t *testing.T) { - t.Parallel() - ctrl := gomock.NewController(t) - - buffer := NewMockBuffer(ctrl) - - var previousCall *gomock.Call - for _, write := range testCase.writeCalls { - call := buffer.EXPECT(). - Write(write.written). - Return(write.n, write.err) - - if previousCall != nil { - call.After(previousCall) - } - previousCall = call - } - - err := encodeRoot(testCase.root, buffer) - - assert.ErrorIs(t, err, testCase.errWrapped) - if testCase.errWrapped != nil { - assert.EqualError(t, err, testCase.errMessage) - } - assert.Equal(t, testCase.expectedRoot, testCase.root) - }) - } -} - func Test_Trie_MustHash(t *testing.T) { t.Parallel() @@ -435,6 +355,12 @@ func Test_Trie_Hash(t *testing.T) { root: &Node{ Key: []byte{1, 2, 3}, SubValue: []byte{1}, + MerkleValue: []byte{ + 0xa8, 0x13, 0x7c, 0xee, 0xb4, 0xad, 0xea, 0xac, + 0x9e, 0x5b, 0x37, 0xe2, 0x8e, 0x7d, 0x64, 0x78, + 0xac, 0xba, 0xb0, 0x6e, 0x90, 0x76, 0xe4, 0x67, + 0xa1, 0xd8, 0xa2, 0x29, 0x4e, 0x4a, 0xd9, 0xa3, + }, }, }, }, @@ -456,8 +382,14 @@ func Test_Trie_Hash(t *testing.T) { 0xf0, 0xe, 0xd3, 0x39, 0x48, 0x21, 0xe3, 0xdd}, expectedTrie: Trie{ root: &Node{ - Key: []byte{1, 2, 3}, - SubValue: []byte("branch"), + Key: []byte{1, 2, 3}, + SubValue: []byte("branch"), + MerkleValue: []byte{ + 0xaa, 0x7e, 0x57, 0x48, 0xb0, 0x27, 0x4d, 0x18, + 0xf5, 0x1c, 0xfd, 0x36, 0x4c, 0x4b, 0x56, 0x4a, + 0xf5, 0x37, 0x9d, 0xd7, 0xcb, 0xf5, 0x80, 0x15, + 0xf0, 0x0e, 0xd3, 0x39, 0x48, 0x21, 0xe3, 0xdd, + }, Descendants: 1, Children: padRightChildren([]*Node{ {