From 62797443a4ebcd971153d2993c169b26e7710e30 Mon Sep 17 00:00:00 2001 From: dboehm-avalabs Date: Thu, 26 Oct 2023 19:43:28 -0400 Subject: [PATCH] make TC a ptr --- x/merkledb/db.go | 4 ++-- x/merkledb/db_test.go | 2 +- x/merkledb/helpers_test.go | 2 +- x/merkledb/history.go | 4 ++-- x/merkledb/intermediate_node_db.go | 4 ++-- x/merkledb/key.go | 24 +++++++++---------- x/merkledb/key_test.go | 37 +++++++++++++++++++----------- x/merkledb/node.go | 4 ++-- x/merkledb/proof.go | 8 +++---- x/merkledb/trie_test.go | 2 +- x/merkledb/trieview.go | 2 +- x/merkledb/value_node_db.go | 4 ++-- 12 files changed, 54 insertions(+), 43 deletions(-) diff --git a/x/merkledb/db.go b/x/merkledb/db.go index b5fb7648f32a..cc5a3f061433 100644 --- a/x/merkledb/db.go +++ b/x/merkledb/db.go @@ -139,7 +139,7 @@ type MerkleDB interface { type Config struct { // TokenConfig determines the branching factor and other aspects of the tokens that make up a key - TokenConfig TokenConfiguration + TokenConfig *TokenConfiguration // RootGenConcurrency is the number of goroutines to use when // generating a new state root. @@ -204,7 +204,7 @@ type merkleDB struct { // [calculateNodeIDsHelper] at any given time. calculateNodeIDsSema *semaphore.Weighted - tokenConfig TokenConfiguration + tokenConfig *TokenConfiguration } // New returns a new merkle database. diff --git a/x/merkledb/db_test.go b/x/merkledb/db_test.go index 1e0dc6cbf061..19388091eeb4 100644 --- a/x/merkledb/db_test.go +++ b/x/merkledb/db_test.go @@ -851,7 +851,7 @@ const ( opMax // boundary value, not an actual op ) -func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest, tc TokenConfiguration) { +func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest, tc *TokenConfiguration) { db, err := getBasicDBWithBranchFactor(tc) require.NoError(err) diff --git a/x/merkledb/helpers_test.go b/x/merkledb/helpers_test.go index 0fbeaa049241..36544ae4be74 100644 --- a/x/merkledb/helpers_test.go +++ b/x/merkledb/helpers_test.go @@ -25,7 +25,7 @@ func getBasicDB() (*merkleDB, error) { ) } -func getBasicDBWithBranchFactor(bf TokenConfiguration) (*merkleDB, error) { +func getBasicDBWithBranchFactor(bf *TokenConfiguration) (*merkleDB, error) { config := newDefaultConfig() config.TokenConfig = bf return newDatabase( diff --git a/x/merkledb/history.go b/x/merkledb/history.go index 790097d11480..f17a4c4f4541 100644 --- a/x/merkledb/history.go +++ b/x/merkledb/history.go @@ -33,7 +33,7 @@ type trieHistory struct { // Each change is tagged with this monotonic increasing number. nextInsertNumber uint64 - tc TokenConfiguration + tc *TokenConfiguration } // Tracks the beginning and ending state of a value. @@ -65,7 +65,7 @@ func newChangeSummary(estimatedSize int) *changeSummary { } } -func newTrieHistory(maxHistoryLookback int, tc TokenConfiguration) *trieHistory { +func newTrieHistory(maxHistoryLookback int, tc *TokenConfiguration) *trieHistory { return &trieHistory{ maxHistoryLen: maxHistoryLookback, history: buffer.NewUnboundedDeque[*changeSummaryAndInsertNumber](maxHistoryLookback), diff --git a/x/merkledb/intermediate_node_db.go b/x/merkledb/intermediate_node_db.go index 2bd927e511dc..fa1a8646315d 100644 --- a/x/merkledb/intermediate_node_db.go +++ b/x/merkledb/intermediate_node_db.go @@ -31,7 +31,7 @@ type intermediateNodeDB struct { // the number of bytes to evict during an eviction batch evictionBatchSize int metrics merkleMetrics - tc TokenConfiguration + tc *TokenConfiguration } func newIntermediateNodeDB( @@ -40,7 +40,7 @@ func newIntermediateNodeDB( metrics merkleMetrics, size int, evictionBatchSize int, - tc TokenConfiguration, + tc *TokenConfiguration, ) *intermediateNodeDB { result := &intermediateNodeDB{ metrics: metrics, diff --git a/x/merkledb/key.go b/x/merkledb/key.go index 47b88f15e4c7..8dc2f9159aab 100644 --- a/x/merkledb/key.go +++ b/x/merkledb/key.go @@ -15,23 +15,23 @@ import ( var ( ErrInvalidTokenConfig = errors.New("token configuration must match one of the predefined configurations ") - BranchFactor2TokenConfig = TokenConfiguration{ + BranchFactor2TokenConfig = &TokenConfiguration{ branchFactor: 2, bitsPerToken: 1, } - BranchFactor4TokenConfig = TokenConfiguration{ + BranchFactor4TokenConfig = &TokenConfiguration{ branchFactor: 4, bitsPerToken: 2, } - BranchFactor16TokenConfig = TokenConfiguration{ + BranchFactor16TokenConfig = &TokenConfiguration{ branchFactor: 16, bitsPerToken: 4, } - BranchFactor256TokenConfig = TokenConfiguration{ + BranchFactor256TokenConfig = &TokenConfiguration{ branchFactor: 256, bitsPerToken: 8, } - validTokenConfigurations = []TokenConfiguration{ + validTokenConfigurations = []*TokenConfiguration{ BranchFactor2TokenConfig, BranchFactor4TokenConfig, BranchFactor16TokenConfig, @@ -44,11 +44,11 @@ type TokenConfiguration struct { bitsPerToken int } -func (t TokenConfiguration) ToKey(val byte) Key { +func (t *TokenConfiguration) ToKey(val byte) Key { return Key{value: string([]byte{val << dualBitIndex(t.bitsPerToken)}), length: t.bitsPerToken} } -func (t TokenConfiguration) Valid() error { +func (t *TokenConfiguration) Valid() error { for _, validConfig := range validTokenConfigurations { if validConfig == t { return nil @@ -58,7 +58,7 @@ func (t TokenConfiguration) Valid() error { } // Token returns the token at the specified index, -func (t TokenConfiguration) Token(k Key, bitIndex int) byte { +func (t *TokenConfiguration) Token(k Key, bitIndex int) byte { storageByte := k.value[bitIndex/8] // Shift the byte right to get the token to the rightmost position. storageByte >>= dualBitIndex((bitIndex + t.bitsPerToken) % 8) @@ -66,7 +66,7 @@ func (t TokenConfiguration) Token(k Key, bitIndex int) byte { return storageByte & (0xFF >> dualBitIndex(t.bitsPerToken)) } -func (t TokenConfiguration) getLengthOfCommonPrefix(first, second Key, secondOffset int) int { +func (t *TokenConfiguration) getLengthOfCommonPrefix(first, second Key, secondOffset int) int { commonIndex := 0 for first.length > commonIndex && second.length > commonIndex+secondOffset && t.Token(first, commonIndex) == t.Token(second, commonIndex+secondOffset) { @@ -77,7 +77,7 @@ func (t TokenConfiguration) getLengthOfCommonPrefix(first, second Key, secondOff // iteratedHasPrefix checks if the provided prefix path is a prefix of the current path after having skipped [skipTokens] tokens first // this has better performance than constructing the actual path via Skip() then calling HasPrefix because it avoids the []byte allocation -func (t TokenConfiguration) hasPrefix(k Key, prefix Key, bitsToSkip int) bool { +func (t *TokenConfiguration) hasPrefix(k Key, prefix Key, bitsToSkip int) bool { if k.length-bitsToSkip < prefix.length { return false } @@ -89,11 +89,11 @@ func (t TokenConfiguration) hasPrefix(k Key, prefix Key, bitsToSkip int) bool { return true } -func (t TokenConfiguration) BranchFactor() int { +func (t *TokenConfiguration) BranchFactor() int { return t.branchFactor } -func (t TokenConfiguration) BitsPerToken() int { +func (t *TokenConfiguration) BitsPerToken() int { return t.bitsPerToken } diff --git a/x/merkledb/key_test.go b/x/merkledb/key_test.go index 146cfd498e6d..545c3e575223 100644 --- a/x/merkledb/key_test.go +++ b/x/merkledb/key_test.go @@ -10,6 +10,17 @@ import ( "github.com/stretchr/testify/require" ) +func TestTokenConfigValid(t *testing.T) { + require := require.New(t) + for _, tc := range validTokenConfigurations { + require.NoError(tc.Valid()) + } + require.Error((&TokenConfiguration{}).Valid()) + + var nilTC *TokenConfiguration + require.Error(nilTC.Valid()) +} + func TestHasPartialByte(t *testing.T) { for _, branchFactor := range validTokenConfigurations { t.Run(fmt.Sprint(branchFactor), func(t *testing.T) { @@ -48,8 +59,8 @@ func TestHasPartialByte(t *testing.T) { func Test_Key_Has_Prefix(t *testing.T) { type test struct { name string - keyA func(bf TokenConfiguration) Key - keyB func(bf TokenConfiguration) Key + keyA func(bf *TokenConfiguration) Key + keyB func(bf *TokenConfiguration) Key isStrictPrefix bool isPrefix bool } @@ -59,15 +70,15 @@ func Test_Key_Has_Prefix(t *testing.T) { tests := []test{ { name: "equal keys", - keyA: func(bf TokenConfiguration) Key { return ToKey([]byte(key)) }, - keyB: func(bf TokenConfiguration) Key { return ToKey([]byte(key)) }, + keyA: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)) }, + keyB: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)) }, isPrefix: true, isStrictPrefix: false, }, { name: "one key has one fewer token", - keyA: func(bf TokenConfiguration) Key { return ToKey([]byte(key)) }, - keyB: func(bf TokenConfiguration) Key { + keyA: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)) }, + keyB: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)).Take(len(key)*8 - bf.bitsPerToken) }, isPrefix: true, @@ -75,10 +86,10 @@ func Test_Key_Has_Prefix(t *testing.T) { }, { name: "equal keys, both have one fewer token", - keyA: func(bf TokenConfiguration) Key { + keyA: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)).Take(len(key)*8 - bf.bitsPerToken) }, - keyB: func(bf TokenConfiguration) Key { + keyB: func(bf *TokenConfiguration) Key { return ToKey([]byte(key)).Take(len(key)*8 - bf.bitsPerToken) }, isPrefix: true, @@ -86,17 +97,17 @@ func Test_Key_Has_Prefix(t *testing.T) { }, { name: "different keys", - keyA: func(bf TokenConfiguration) Key { return ToKey([]byte{0xF7}) }, - keyB: func(bf TokenConfiguration) Key { return ToKey([]byte{0xF0}) }, + keyA: func(bf *TokenConfiguration) Key { return ToKey([]byte{0xF7}) }, + keyB: func(bf *TokenConfiguration) Key { return ToKey([]byte{0xF0}) }, isPrefix: false, isStrictPrefix: false, }, { name: "same bytes, different lengths", - keyA: func(bf TokenConfiguration) Key { + keyA: func(bf *TokenConfiguration) Key { return ToKey([]byte{0x10, 0x00}).Take(bf.bitsPerToken) }, - keyB: func(bf TokenConfiguration) Key { + keyB: func(bf *TokenConfiguration) Key { return ToKey([]byte{0x10, 0x00}).Take(bf.bitsPerToken * 2) }, isPrefix: false, @@ -177,7 +188,7 @@ func Test_Key_Token(t *testing.T) { type test struct { name string inputBytes []byte - branchFactor TokenConfiguration + branchFactor *TokenConfiguration assertTokens func(*require.Assertions, Key) } diff --git a/x/merkledb/node.go b/x/merkledb/node.go index 2898ebdc85ae..263fab52984e 100644 --- a/x/merkledb/node.go +++ b/x/merkledb/node.go @@ -112,7 +112,7 @@ func (n *node) setValueDigest() { // Adds [child] as a child of [n]. // Assumes [child]'s key is valid as a child of [n]. // That is, [n.key] is a prefix of [child.key]. -func (n *node) addChild(tc TokenConfiguration, childNode *node) { +func (n *node) addChild(tc *TokenConfiguration, childNode *node) { n.setChildEntry( tc.Token(childNode.key, n.key.length), child{ @@ -130,7 +130,7 @@ func (n *node) setChildEntry(index byte, childEntry child) { } // Removes [child] from [n]'s children. -func (n *node) removeChild(tc TokenConfiguration, child *node) { +func (n *node) removeChild(tc *TokenConfiguration, child *node) { n.onNodeChanged() delete(n.children, tc.Token(child.key, n.key.length)) } diff --git a/x/merkledb/proof.go b/x/merkledb/proof.go index 4b38578fdf30..c8a062953fb4 100644 --- a/x/merkledb/proof.go +++ b/x/merkledb/proof.go @@ -138,7 +138,7 @@ type Proof struct { // Returns nil if the trie given in [proof] has root [expectedRootID]. // That is, this is a valid proof that [proof.Key] exists/doesn't exist // in the trie with root [expectedRootID]. -func (proof *Proof) Verify(ctx context.Context, tc TokenConfiguration, expectedRootID ids.ID) error { +func (proof *Proof) Verify(ctx context.Context, tc *TokenConfiguration, expectedRootID ids.ID) error { // Make sure the proof is well-formed. if len(proof.Path) == 0 { return ErrNoProof @@ -282,7 +282,7 @@ type RangeProof struct { // If [end] is Nothing, all keys are considered < [end]. func (proof *RangeProof) Verify( ctx context.Context, - tc TokenConfiguration, + tc *TokenConfiguration, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedRootID ids.ID, @@ -734,7 +734,7 @@ func verifyKeyValues(kvs []KeyValue, start maybe.Maybe[[]byte], end maybe.Maybe[ // - Each key in [proof] is a strict prefix of [keyBytes], except possibly the last. // - If the last element in [proof] is [Key], this is an inclusion proof. // Otherwise, this is an exclusion proof and [keyBytes] must not be in [proof]. -func verifyProofPath(tc TokenConfiguration, proof []ProofNode, key maybe.Maybe[Key]) error { +func verifyProofPath(tc *TokenConfiguration, proof []ProofNode, key maybe.Maybe[Key]) error { if len(proof) == 0 { return nil } @@ -871,7 +871,7 @@ func addPathInfo( } // getStandaloneTrieView returns a new view that has nothing in it besides the changes due to [ops] -func getStandaloneTrieView(ctx context.Context, ops []database.BatchOp, tc TokenConfiguration) (*trieView, error) { +func getStandaloneTrieView(ctx context.Context, ops []database.BatchOp, tc *TokenConfiguration) (*trieView, error) { db, err := newDatabase( ctx, memdb.New(), diff --git a/x/merkledb/trie_test.go b/x/merkledb/trie_test.go index 1417ec823de6..b52af59e3218 100644 --- a/x/merkledb/trie_test.go +++ b/x/merkledb/trie_test.go @@ -1213,7 +1213,7 @@ func Test_Trie_ConcurrentNewViewAndCommit(t *testing.T) { // Returns the path of the only child of this node. // Assumes this node has exactly one child. -func getSingleChildKey(tc TokenConfiguration, n *node) Key { +func getSingleChildKey(tc *TokenConfiguration, n *node) Key { for index, entry := range n.children { return n.key.DoubleExtend(tc.ToKey(index), entry.compressedKey) } diff --git a/x/merkledb/trieview.go b/x/merkledb/trieview.go index 8d8ac1646599..235494e3277c 100644 --- a/x/merkledb/trieview.go +++ b/x/merkledb/trieview.go @@ -99,7 +99,7 @@ type trieView struct { // The root of the trie represented by this view. root *node - tokenConfig TokenConfiguration + tokenConfig *TokenConfiguration } // NewView returns a new view on top of this Trie where the passed changes diff --git a/x/merkledb/value_node_db.go b/x/merkledb/value_node_db.go index a0c60a4e213a..838398051b96 100644 --- a/x/merkledb/value_node_db.go +++ b/x/merkledb/value_node_db.go @@ -28,7 +28,7 @@ type valueNodeDB struct { metrics merkleMetrics closed utils.Atomic[bool] - tokenConfig TokenConfiguration + tokenConfig *TokenConfiguration } func newValueNodeDB( @@ -36,7 +36,7 @@ func newValueNodeDB( bufferPool *sync.Pool, metrics merkleMetrics, cacheSize int, - tokenConfig TokenConfiguration, + tokenConfig *TokenConfiguration, ) *valueNodeDB { return &valueNodeDB{ metrics: metrics,