-
Notifications
You must be signed in to change notification settings - Fork 146
chore(lib/trie): refactor encoding and hash related code in trie package #2077
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
ccf0218
export all trie node methods
qdm12 c94b882
Export `node` interface
qdm12 a10fd38
export `branch`
qdm12 b6fc29e
export `leaf` struct
qdm12 5bc7d18
Add exported comments
qdm12 59ab003
Refactor encoding and hash related code with tests
qdm12 d87deba
Address TODOs
qdm12 77e4203
Remove no longer needed mocks
qdm12 d5f06a4
Fix encode decode tests
qdm12 07c52c2
Remove old parallel related code
qdm12 4a7cb4c
Fix eventual bad type assertion
qdm12 0063885
Remove commented Decode method in node interface
qdm12 a3ee3a7
chore(lib/trie): `lib/trie/recorder` sub-package (#2082)
qdm12 e77adb2
Remove ReadNextByte and use sync.Pool
qdm12 8697d2d
Rename `ExtraPartialKeyLength` to `KeyLength`
qdm12 b03ecff
Remove unneded `NibblesToKey`
qdm12 207a5c3
Rename `Header()` to `encodeHeader()`
qdm12 37425a7
encode headers directly to buffer
qdm12 301188d
Merge packages in `lib/trie/node`
qdm12 d35fc0f
`lib/trie/node` -> `internal/trie/node`
qdm12 9df5d2c
Simplify and fix mock generations
qdm12 d65d600
Add licenses
qdm12 a443ac5
Use `Node` instead of `node.Node` in `lib/trie`
qdm12 d1e21cc
`lib/trie/recorder` -> `internal/trie/recorder`
qdm12 4721f25
`lib/trie/pools` -> `internal/trie/pools`
qdm12 8cd2ebb
`lib/trie/codec` -> `internal/trie/codec`
qdm12 1c53578
Node interface named returns
qdm12 79c2ecb
Use `bytes.NewReader` for readers
qdm12 5cce780
Add `GetValue` method to node interface
qdm12 5b800f1
Add `GetKey` method to node interface
qdm12 93ee8b6
`node.Decode` function
qdm12 c054516
Apply suggestions from @kishansagathiya's code review
qdm12 87f058d
Improve ScaleEncodeHash error wrapping
qdm12 9fd4036
Shorten children bitmap bitwise or
qdm12 2feebe7
Add comments for `Dirty` and `Generation`
qdm12 8c213df
Unexport `Generation` node field
qdm12 db578d4
Unexport `Dirty` field for node
qdm12 a4da41a
Unexport node's `Hash` as `hashDigest`
qdm12 89bf885
Trie string does not cache encoding in nodes
qdm12 23560c6
Unexport node's `Encoding` field
qdm12 1837d85
Fix `NewBranch` to `NewLeaf`
qdm12 3129e79
Add node type comments in tests
qdm12 7503f21
Use `node.Type` for Type constants
qdm12 e17c08e
`keyLenOffset` constant 0x3f
qdm12 865aae6
Fix comment (@noot suggestion)
qdm12 8c31788
Updated generation comment
qdm12 831213c
fix copy functions to copy nil slices correctly
qdm12 8a315af
Move leaf hash methods to hash.go
qdm12 9c73b48
fix naming in `decodeKey` function
qdm12 61baed1
95.7% test coverage for `internal/trie/node`
qdm12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // Copyright 2021 ChainSafe Systems (ON) | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| package codec | ||
|
|
||
| // NibblesToKeyLE converts a slice of nibbles with length k into a | ||
| // Little Endian byte slice. | ||
| // It assumes nibbles are already in Little Endian and does not rearrange nibbles. | ||
| // If the length of the input is odd, the result is | ||
| // [ 0000 in[0] | in[1] in[2] | ... | in[k-2] in[k-1] ] | ||
| // Otherwise, the result is | ||
| // [ in[0] in[1] | ... | in[k-2] in[k-1] ] | ||
| func NibblesToKeyLE(nibbles []byte) []byte { | ||
| if len(nibbles)%2 == 0 { | ||
| keyLE := make([]byte, len(nibbles)/2) | ||
| for i := 0; i < len(nibbles); i += 2 { | ||
| keyLE[i/2] = (nibbles[i] << 4 & 0xf0) | (nibbles[i+1] & 0xf) | ||
| } | ||
| return keyLE | ||
| } | ||
|
|
||
| keyLE := make([]byte, len(nibbles)/2+1) | ||
| keyLE[0] = nibbles[0] | ||
| for i := 2; i < len(nibbles); i += 2 { | ||
| keyLE[i/2] = (nibbles[i-1] << 4 & 0xf0) | (nibbles[i] & 0xf) | ||
| } | ||
|
|
||
| return keyLE | ||
| } | ||
|
|
||
| // KeyLEToNibbles converts a Little Endian byte slice into nibbles. | ||
| // It assumes bytes are already in Little Endian and does not rearrange nibbles. | ||
| func KeyLEToNibbles(in []byte) (nibbles []byte) { | ||
| if len(in) == 0 { | ||
| return []byte{} | ||
| } else if len(in) == 1 && in[0] == 0 { | ||
| return []byte{0, 0} | ||
| } | ||
|
|
||
| l := len(in) * 2 | ||
| nibbles = make([]byte, l) | ||
| for i, b := range in { | ||
| nibbles[2*i] = b / 16 | ||
| nibbles[2*i+1] = b % 16 | ||
| } | ||
|
|
||
| return nibbles | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| // Copyright 2021 ChainSafe Systems (ON) | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| package codec | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func Test_NibblesToKeyLE(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| testCases := map[string]struct { | ||
| nibbles []byte | ||
| keyLE []byte | ||
| }{ | ||
| "nil nibbles": { | ||
| keyLE: []byte{}, | ||
| }, | ||
| "empty nibbles": { | ||
| nibbles: []byte{}, | ||
| keyLE: []byte{}, | ||
| }, | ||
| "0xF 0xF": { | ||
| nibbles: []byte{0xF, 0xF}, | ||
| keyLE: []byte{0xFF}, | ||
| }, | ||
| "0x3 0xa 0x0 0x5": { | ||
| nibbles: []byte{0x3, 0xa, 0x0, 0x5}, | ||
| keyLE: []byte{0x3a, 0x05}, | ||
| }, | ||
| "0xa 0xa 0xf 0xf 0x0 0x1": { | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1}, | ||
| keyLE: []byte{0xaa, 0xff, 0x01}, | ||
| }, | ||
| "0xa 0xa 0xf 0xf 0x0 0x1 0xc 0x2": { | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1, 0xc, 0x2}, | ||
| keyLE: []byte{0xaa, 0xff, 0x01, 0xc2}, | ||
| }, | ||
| "0xa 0xa 0xf 0xf 0x0 0x1 0xc": { | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1, 0xc}, | ||
| keyLE: []byte{0xa, 0xaf, 0xf0, 0x1c}, | ||
| }, | ||
| } | ||
|
|
||
| for name, testCase := range testCases { | ||
| testCase := testCase | ||
| t.Run(name, func(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| keyLE := NibblesToKeyLE(testCase.nibbles) | ||
|
|
||
| assert.Equal(t, testCase.keyLE, keyLE) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func Test_KeyLEToNibbles(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| testCases := map[string]struct { | ||
| in []byte | ||
| nibbles []byte | ||
| }{ | ||
| "nil input": { | ||
| nibbles: []byte{}, | ||
| }, | ||
| "empty input": { | ||
| in: []byte{}, | ||
| nibbles: []byte{}, | ||
| }, | ||
| "0x0": { | ||
| in: []byte{0x0}, | ||
| nibbles: []byte{0, 0}}, | ||
| "0xFF": { | ||
| in: []byte{0xFF}, | ||
| nibbles: []byte{0xF, 0xF}}, | ||
| "0x3a 0x05": { | ||
| in: []byte{0x3a, 0x05}, | ||
| nibbles: []byte{0x3, 0xa, 0x0, 0x5}}, | ||
| "0xAA 0xFF 0x01": { | ||
| in: []byte{0xAA, 0xFF, 0x01}, | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1}}, | ||
| "0xAA 0xFF 0x01 0xc2": { | ||
| in: []byte{0xAA, 0xFF, 0x01, 0xc2}, | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1, 0xc, 0x2}}, | ||
| "0xAA 0xFF 0x01 0xc0": { | ||
| in: []byte{0xAA, 0xFF, 0x01, 0xc0}, | ||
| nibbles: []byte{0xa, 0xa, 0xf, 0xf, 0x0, 0x1, 0xc, 0x0}}, | ||
| } | ||
|
|
||
| for name, testCase := range testCases { | ||
| testCase := testCase | ||
| t.Run(name, func(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| nibbles := KeyLEToNibbles(testCase.in) | ||
|
|
||
| assert.Equal(t, testCase.nibbles, nibbles) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func Test_NibblesKeyLE(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| testCases := map[string]struct { | ||
| nibblesToEncode []byte | ||
| nibblesDecoded []byte | ||
| }{ | ||
| "empty input": { | ||
| nibblesToEncode: []byte{}, | ||
| nibblesDecoded: []byte{}, | ||
| }, | ||
| "one byte": { | ||
| nibblesToEncode: []byte{1}, | ||
| nibblesDecoded: []byte{0, 1}, | ||
| }, | ||
| "two bytes": { | ||
| nibblesToEncode: []byte{1, 2}, | ||
| nibblesDecoded: []byte{1, 2}, | ||
| }, | ||
| "three bytes": { | ||
| nibblesToEncode: []byte{1, 2, 3}, | ||
| nibblesDecoded: []byte{0, 1, 2, 3}, | ||
| }, | ||
| } | ||
|
|
||
| for name, testCase := range testCases { | ||
| testCase := testCase | ||
| t.Run(name, func(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| keyLE := NibblesToKeyLE(testCase.nibblesToEncode) | ||
| nibblesDecoded := KeyLEToNibbles(keyLE) | ||
|
|
||
| assert.Equal(t, testCase.nibblesDecoded, nibblesDecoded) | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Copyright 2021 ChainSafe Systems (ON) | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| package node | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sync" | ||
|
|
||
| "github.com/ChainSafe/gossamer/lib/common" | ||
| ) | ||
|
|
||
| var _ Node = (*Branch)(nil) | ||
|
|
||
| // Branch is a branch in the trie. | ||
| type Branch struct { | ||
| Key []byte // partial key | ||
| Children [16]Node | ||
| Value []byte | ||
| // dirty is true when the branch differs | ||
| // from the node stored in the database. | ||
| dirty bool | ||
| hashDigest []byte | ||
| encoding []byte | ||
| // generation is incremented on every trie Snapshot() call. | ||
| // Each node also contain a certain generation number, | ||
| // which is updated to match the trie generation once they are | ||
| // inserted, moved or iterated over. | ||
| generation uint64 | ||
| sync.RWMutex | ||
| } | ||
|
|
||
| // NewBranch creates a new branch using the arguments given. | ||
| func NewBranch(key, value []byte, dirty bool, generation uint64) *Branch { | ||
| return &Branch{ | ||
| Key: key, | ||
| Value: value, | ||
| dirty: dirty, | ||
| generation: generation, | ||
| } | ||
| } | ||
|
|
||
| func (b *Branch) String() string { | ||
| if len(b.Value) > 1024 { | ||
| return fmt.Sprintf("branch key=0x%x childrenBitmap=%b value (hashed)=0x%x dirty=%t", | ||
| b.Key, b.ChildrenBitmap(), common.MustBlake2bHash(b.Value), b.dirty) | ||
| } | ||
| return fmt.Sprintf("branch key=0x%x childrenBitmap=%b value=0x%x dirty=%t", | ||
| b.Key, b.ChildrenBitmap(), b.Value, b.dirty) | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.