Skip to content

Commit

Permalink
feat(trie): Add trie v1 new headers support
Browse files Browse the repository at this point in the history
  • Loading branch information
dimartiro committed Jun 1, 2023
1 parent 483b23f commit 3838b8f
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 116 deletions.
17 changes: 7 additions & 10 deletions internal/trie/node/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@ import (
var (
// ErrDecodeStorageValue is defined since no sentinel error is defined
// in the scale package.
// TODO remove once the following issue is done:
// https://github.com/ChainSafe/gossamer/issues/2631 .
ErrDecodeStorageValue = errors.New("cannot decode storage value")
ErrReadChildrenBitmap = errors.New("cannot read children bitmap")
// ErrDecodeChildHash is defined since no sentinel error is defined
// in the scale package.
// TODO remove once the following issue is done:
// https://github.com/ChainSafe/gossamer/issues/2631 .
ErrDecodeChildHash = errors.New("cannot decode child hash")
)

Expand All @@ -39,21 +35,22 @@ func Decode(reader io.Reader) (n *Node, err error) {
}

switch variant {
case leafVariant.bits:
case emptyVariant:
return nil, nil //nolint:nilnil
case leafVariant:
n, err = decodeLeaf(reader, partialKeyLength)
if err != nil {
return nil, fmt.Errorf("cannot decode leaf: %w", err)
}
return n, nil
case branchVariant.bits, branchWithValueVariant.bits:
case branchVariant, branchWithValueVariant:
n, err = decodeBranch(reader, variant, partialKeyLength)
if err != nil {
return nil, fmt.Errorf("cannot decode branch: %w", err)
}
return n, nil
default:
// this is a programming error, an unknown node variant
// should be caught by decodeHeader.
// this is a programming error, an unknown node variant should be caught by decodeHeader.
panic(fmt.Sprintf("not implemented for node variant %08b", variant))
}
}
Expand All @@ -63,7 +60,7 @@ func Decode(reader io.Reader) (n *Node, err error) {
// reconstructing the child nodes from the encoding. This function instead stubs where the
// children are known to be with an empty leaf. The children nodes hashes are then used to
// find other storage values using the persistent database.
func decodeBranch(reader io.Reader, variant byte, partialKeyLength uint16) (
func decodeBranch(reader io.Reader, variant variant, partialKeyLength uint16) (
node *Node, err error) {
node = &Node{
Children: make([]*Node, ChildrenCapacity),
Expand All @@ -82,7 +79,7 @@ func decodeBranch(reader io.Reader, variant byte, partialKeyLength uint16) (

sd := scale.NewDecoder(reader)

if variant == branchWithValueVariant.bits {
if variant == branchWithValueVariant {
err := sd.Decode(&node.StorageValue)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrDecodeStorageValue, err)
Expand Down
72 changes: 34 additions & 38 deletions internal/trie/node/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ func Test_Decode(t *testing.T) {
errMessage: "decoding header: reading header byte: EOF",
},
"unknown_node_variant": {
reader: bytes.NewReader([]byte{0}),
reader: bytes.NewReader([]byte{0b0000_1000}),
errWrapped: ErrVariantUnknown,
errMessage: "decoding header: decoding header byte: node variant is unknown: for header byte 00000000",
errMessage: "decoding header: decoding header byte: node variant is unknown: for header byte 00001000",
},
"empty_node": {
reader: bytes.NewReader([]byte{emptyVariant.bits}),
n: nil,
},
"leaf_decoding_error": {
reader: bytes.NewReader([]byte{
Expand All @@ -64,15 +68,11 @@ func Test_Decode(t *testing.T) {
"reading from reader: EOF",
},
"leaf_success": {
reader: bytes.NewReader(
append(
[]byte{
leafVariant.bits | 1, // key length 1
9, // key data
},
scaleEncodeBytes(t, 1, 2, 3)...,
),
),
reader: bytes.NewReader(concatByteSlices([][]byte{
{leafVariant.bits | 1}, // partial key length 1
{9}, // key data
scaleEncodeBytes(t, 1, 2, 3),
})),
n: &Node{
PartialKey: []byte{9},
StorageValue: []byte{1, 2, 3},
Expand All @@ -88,13 +88,11 @@ func Test_Decode(t *testing.T) {
"reading from reader: EOF",
},
"branch_success": {
reader: bytes.NewReader(
[]byte{
branchVariant.bits | 1, // key length 1
9, // key data
0, 0, // no children bitmap
},
),
reader: bytes.NewReader(concatByteSlices([][]byte{
{branchVariant.bits | 1}, // partial key length 1
{9}, // key data
{0b0000_0000, 0b0000_0000}, // no children bitmap
})),
n: &Node{
PartialKey: []byte{9},
Children: make([]*Node, ChildrenCapacity),
Expand Down Expand Up @@ -130,7 +128,7 @@ func Test_decodeBranch(t *testing.T) {

testCases := map[string]struct {
reader io.Reader
variant byte
nodeVariant variant
partialKeyLength uint16
branch *Node
errWrapped error
Expand All @@ -140,7 +138,7 @@ func Test_decodeBranch(t *testing.T) {
reader: bytes.NewBuffer([]byte{
// missing key data byte
}),
variant: branchVariant.bits,
nodeVariant: branchVariant,
partialKeyLength: 1,
errWrapped: io.EOF,
errMessage: "cannot decode key: reading from reader: EOF",
Expand All @@ -150,7 +148,7 @@ func Test_decodeBranch(t *testing.T) {
9, // key data
// missing children bitmap 2 bytes
}),
variant: branchVariant.bits,
nodeVariant: branchVariant,
partialKeyLength: 1,
errWrapped: ErrReadChildrenBitmap,
errMessage: "cannot read children bitmap: EOF",
Expand All @@ -161,7 +159,7 @@ func Test_decodeBranch(t *testing.T) {
0, 4, // children bitmap
// missing children scale encoded data
}),
variant: branchVariant.bits,
nodeVariant: branchVariant,
partialKeyLength: 1,
errWrapped: ErrDecodeChildHash,
errMessage: "cannot decode child hash: at index 10: reading byte: EOF",
Expand All @@ -174,7 +172,7 @@ func Test_decodeBranch(t *testing.T) {
scaleEncodedChildHash,
}),
),
variant: branchVariant.bits,
nodeVariant: branchVariant,
partialKeyLength: 1,
branch: &Node{
PartialKey: []byte{9},
Expand All @@ -196,7 +194,7 @@ func Test_decodeBranch(t *testing.T) {
// missing encoded branch storage value
}),
),
variant: branchWithValueVariant.bits,
nodeVariant: branchWithValueVariant,
partialKeyLength: 1,
errWrapped: ErrDecodeStorageValue,
errMessage: "cannot decode storage value: reading byte: EOF",
Expand All @@ -208,7 +206,7 @@ func Test_decodeBranch(t *testing.T) {
scaleEncodeBytes(t, 7, 8, 9), // branch storage value
scaleEncodedChildHash,
})),
variant: branchWithValueVariant.bits,
nodeVariant: branchWithValueVariant,
partialKeyLength: 1,
branch: &Node{
PartialKey: []byte{9},
Expand All @@ -230,7 +228,7 @@ func Test_decodeBranch(t *testing.T) {
scaleEncodeBytes(t, 1), // branch storage value
{0}, // garbage inlined node
})),
variant: branchWithValueVariant.bits,
nodeVariant: branchWithValueVariant,
partialKeyLength: 1,
errWrapped: io.EOF,
errMessage: "decoding inlined child at index 0: " +
Expand Down Expand Up @@ -260,7 +258,7 @@ func Test_decodeBranch(t *testing.T) {
})),
})),
})),
variant: branchVariant.bits,
nodeVariant: branchVariant,
partialKeyLength: 1,
branch: &Node{
PartialKey: []byte{1},
Expand All @@ -286,7 +284,7 @@ func Test_decodeBranch(t *testing.T) {
t.Parallel()

branch, err := decodeBranch(testCase.reader,
testCase.variant, testCase.partialKeyLength)
testCase.nodeVariant, testCase.partialKeyLength)

assert.ErrorIs(t, err, testCase.errWrapped)
if err != nil {
Expand Down Expand Up @@ -318,10 +316,10 @@ func Test_decodeLeaf(t *testing.T) {
errMessage: "cannot decode key: reading from reader: EOF",
},
"value_decoding_error": {
reader: bytes.NewBuffer([]byte{
9, // key data
255, 255, // bad storage value data
}),
reader: bytes.NewBuffer(concatByteSlices([][]byte{
{9}, // key data
{255, 255}, // bad storage value data
})),
variant: leafVariant.bits,
partialKeyLength: 1,
errWrapped: ErrDecodeStorageValue,
Expand Down Expand Up @@ -350,12 +348,10 @@ func Test_decodeLeaf(t *testing.T) {
},
},
"success": {
reader: bytes.NewBuffer(
concatByteSlices([][]byte{
{9}, // key data
scaleEncodeBytes(t, 1, 2, 3, 4, 5), // storage value data
}),
),
reader: bytes.NewBuffer(concatByteSlices([][]byte{
{9}, // key data
scaleEncodeBytes(t, 1, 2, 3, 4, 5), // storage value data
})),
variant: leafVariant.bits,
partialKeyLength: 1,
leaf: &Node{
Expand Down
5 changes: 5 additions & 0 deletions internal/trie/node/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ func (n *Node) Encode(buffer Buffer) (err error) {
return fmt.Errorf("cannot encode header: %w", err)
}

if n == nil {
// only encode the empty variant byte header
return nil
}

keyLE := codec.NibblesToKeyLE(n.PartialKey)
_, err = buffer.Write(keyLE)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/trie/node/encode_decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ func Test_Branch_Encode_Decode(t *testing.T) {
err := testCase.branchToEncode.Encode(buffer)
require.NoError(t, err)

variant, partialKeyLength, err := decodeHeader(buffer)
nodeVariant, partialKeyLength, err := decodeHeader(buffer)
require.NoError(t, err)

resultBranch, err := decodeBranch(buffer, variant, partialKeyLength)
resultBranch, err := decodeBranch(buffer, nodeVariant, partialKeyLength)
require.NoError(t, err)

assert.Equal(t, testCase.branchDecoded, resultBranch)
Expand Down
9 changes: 9 additions & 0 deletions internal/trie/node/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ func Test_Node_Encode(t *testing.T) {
wrappedErr error
errMessage string
}{
"nil_node": {
node: nil,
writes: []writeCall{
{
written: []byte{emptyVariant.bits},
},
},
expectedEncoding: []byte{emptyVariant.bits},
},
"leaf_header_encoding_error": {
node: &Node{
PartialKey: make([]byte, 1),
Expand Down
Loading

0 comments on commit 3838b8f

Please sign in to comment.