diff --git a/lib/trie/trie.go b/lib/trie/trie.go index cf76ee49ba..735d32c248 100644 --- a/lib/trie/trie.go +++ b/lib/trie/trie.go @@ -68,27 +68,41 @@ func (t *Trie) Snapshot() (newTrie *Trie) { } } +// handleTrackedDeltas sets the pending deleted Merkle values in +// the trie deleted merkle values set if and only if success is true. +func (t *Trie) handleTrackedDeltas(success bool, pendingDeletedMerkleValues map[string]struct{}) { + if !success { + return + } + + for merkleValue := range pendingDeletedMerkleValues { + t.deletedMerkleValues[merkleValue] = struct{}{} + } +} + func (t *Trie) prepLeafForMutation(currentLeaf *Node, - copySettings node.CopySettings) (newLeaf *Node) { + copySettings node.CopySettings, + pendingDeletedMerkleValues map[string]struct{}) (newLeaf *Node) { if currentLeaf.Generation == t.generation { // no need to deep copy and update generation // of current leaf. newLeaf = currentLeaf } else { - newLeaf = updateGeneration(currentLeaf, t.generation, t.deletedMerkleValues, copySettings) + newLeaf = updateGeneration(currentLeaf, t.generation, pendingDeletedMerkleValues, copySettings) } newLeaf.SetDirty() return newLeaf } func (t *Trie) prepBranchForMutation(currentBranch *Node, - copySettings node.CopySettings) (newBranch *Node) { + copySettings node.CopySettings, + pendingDeletedMerkleValues map[string]struct{}) (newBranch *Node) { if currentBranch.Generation == t.generation { // no need to deep copy and update generation // of current branch. newBranch = currentBranch } else { - newBranch = updateGeneration(currentBranch, t.generation, t.deletedMerkleValues, copySettings) + newBranch = updateGeneration(currentBranch, t.generation, pendingDeletedMerkleValues, copySettings) } newBranch.SetDirty() return newBranch @@ -322,14 +336,24 @@ func findNextKeyChild(children []*Node, startIndex byte, // Put inserts a value into the trie at the // key specified in little Endian format. func (t *Trie) Put(keyLE, value []byte) { + pendingDeletedMerkleValues := make(map[string]struct{}) + defer func() { + const success = true + t.handleTrackedDeltas(success, pendingDeletedMerkleValues) + }() + t.insertKeyLE(keyLE, value, pendingDeletedMerkleValues) +} + +func (t *Trie) insertKeyLE(keyLE, value []byte, deletedMerkleValues map[string]struct{}) { nibblesKey := codec.KeyLEToNibbles(keyLE) - t.root, _, _ = t.insert(t.root, nibblesKey, value) + t.root, _, _ = t.insert(t.root, nibblesKey, value, deletedMerkleValues) } // insert inserts a value in the trie at the key specified. // It may create one or more new nodes or update an existing node. -func (t *Trie) insert(parent *Node, key, value []byte) ( - newParent *Node, mutated bool, nodesCreated uint32) { +func (t *Trie) insert(parent *Node, key, value []byte, + deletedMerkleValues map[string]struct{}) (newParent *Node, + mutated bool, nodesCreated uint32) { if parent == nil { mutated = true nodesCreated = 1 @@ -344,12 +368,13 @@ func (t *Trie) insert(parent *Node, key, value []byte) ( // TODO ensure all values have dirty set to true if parent.Kind() == node.Branch { - return t.insertInBranch(parent, key, value) + return t.insertInBranch(parent, key, value, deletedMerkleValues) } - return t.insertInLeaf(parent, key, value) + return t.insertInLeaf(parent, key, value, deletedMerkleValues) } -func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte) ( +func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte, + deletedMerkleValues map[string]struct{}) ( newParent *Node, mutated bool, nodesCreated uint32) { if bytes.Equal(parentLeaf.Key, key) { nodesCreated = 0 @@ -360,7 +385,7 @@ func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte) ( copySettings := node.DefaultCopySettings copySettings.CopyValue = false - parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings) + parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings, deletedMerkleValues) parentLeaf.SubValue = value mutated = true return parentLeaf, mutated, nodesCreated @@ -388,7 +413,7 @@ func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte) ( childIndex := parentLeafKey[commonPrefixLength] newParentLeafKey := parentLeaf.Key[commonPrefixLength+1:] if !bytes.Equal(parentLeaf.Key, newParentLeafKey) { - parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings) + parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings, deletedMerkleValues) parentLeaf.Key = newParentLeafKey } newBranchParent.Children[childIndex] = parentLeaf @@ -408,7 +433,7 @@ func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte) ( childIndex := parentLeafKey[commonPrefixLength] newParentLeafKey := parentLeaf.Key[commonPrefixLength+1:] if !bytes.Equal(parentLeaf.Key, newParentLeafKey) { - parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings) + parentLeaf = t.prepLeafForMutation(parentLeaf, copySettings, deletedMerkleValues) parentLeaf.Key = newParentLeafKey } newBranchParent.Children[childIndex] = parentLeaf @@ -428,7 +453,8 @@ func (t *Trie) insertInLeaf(parentLeaf *Node, key, value []byte) ( return newBranchParent, mutated, nodesCreated } -func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( +func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte, + deletedMerkleValues map[string]struct{}) ( newParent *Node, mutated bool, nodesCreated uint32) { copySettings := node.DefaultCopySettings @@ -437,7 +463,7 @@ func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( mutated = false return parentBranch, mutated, 0 } - parentBranch = t.prepBranchForMutation(parentBranch, copySettings) + parentBranch = t.prepBranchForMutation(parentBranch, copySettings, deletedMerkleValues) parentBranch.SubValue = value mutated = true return parentBranch, mutated, 0 @@ -458,19 +484,19 @@ func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( Dirty: true, } nodesCreated = 1 - parentBranch = t.prepBranchForMutation(parentBranch, copySettings) + parentBranch = t.prepBranchForMutation(parentBranch, copySettings, deletedMerkleValues) parentBranch.Children[childIndex] = child parentBranch.Descendants += nodesCreated mutated = true return parentBranch, mutated, nodesCreated } - child, mutated, nodesCreated = t.insert(child, remainingKey, value) + child, mutated, nodesCreated = t.insert(child, remainingKey, value, deletedMerkleValues) if !mutated { return parentBranch, mutated, 0 } - parentBranch = t.prepBranchForMutation(parentBranch, copySettings) + parentBranch = t.prepBranchForMutation(parentBranch, copySettings, deletedMerkleValues) parentBranch.Children[childIndex] = child parentBranch.Descendants += nodesCreated return parentBranch, mutated, nodesCreated @@ -492,7 +518,7 @@ func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( remainingOldParentKey := parentBranch.Key[commonPrefixLength+1:] // Note: parentBranch.Key != remainingOldParentKey - parentBranch = t.prepBranchForMutation(parentBranch, copySettings) + parentBranch = t.prepBranchForMutation(parentBranch, copySettings, deletedMerkleValues) parentBranch.Key = remainingOldParentKey newParentBranch.Children[oldParentIndex] = parentBranch newParentBranch.Descendants += 1 + parentBranch.Descendants @@ -503,7 +529,8 @@ func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( childIndex := key[commonPrefixLength] remainingKey := key[commonPrefixLength+1:] var additionalNodesCreated uint32 - newParentBranch.Children[childIndex], _, additionalNodesCreated = t.insert(nil, remainingKey, value) + newParentBranch.Children[childIndex], _, additionalNodesCreated = t.insert( + nil, remainingKey, value, deletedMerkleValues) nodesCreated += additionalNodesCreated newParentBranch.Descendants += additionalNodesCreated } @@ -516,6 +543,12 @@ func (t *Trie) insertInBranch(parentBranch *Node, key, value []byte) ( // are hexadecimal encoded. func LoadFromMap(data map[string]string) (trie Trie, err error) { trie = *NewEmptyTrie() + + pendingDeletedMerkleValues := make(map[string]struct{}) + defer func() { + trie.handleTrackedDeltas(err == nil, pendingDeletedMerkleValues) + }() + for key, value := range data { keyLEBytes, err := common.HexToBytes(key) if err != nil { @@ -527,7 +560,7 @@ func LoadFromMap(data map[string]string) (trie Trie, err error) { return Trie{}, fmt.Errorf("cannot convert value hex to bytes: %w", err) } - trie.Put(keyLEBytes, valueBytes) + trie.insertKeyLE(keyLEBytes, valueBytes, pendingDeletedMerkleValues) } return trie, nil @@ -682,6 +715,12 @@ func retrieveFromBranch(branch *Node, key []byte) (value []byte) { // keys and a boolean indicating if all keys with the prefix were deleted // within the limit. func (t *Trie) ClearPrefixLimit(prefixLE []byte, limit uint32) (deleted uint32, allDeleted bool) { + pendingDeletedMerkleValues := make(map[string]struct{}) + defer func() { + const success = true + t.handleTrackedDeltas(success, pendingDeletedMerkleValues) + }() + if limit == 0 { return 0, false } @@ -689,14 +728,16 @@ func (t *Trie) ClearPrefixLimit(prefixLE []byte, limit uint32) (deleted uint32, prefix := codec.KeyLEToNibbles(prefixLE) prefix = bytes.TrimSuffix(prefix, []byte{0}) - t.root, deleted, _, allDeleted = t.clearPrefixLimitAtNode(t.root, prefix, limit) + t.root, deleted, _, allDeleted = t.clearPrefixLimitAtNode( + t.root, prefix, limit, pendingDeletedMerkleValues) return deleted, allDeleted } // clearPrefixLimitAtNode deletes the keys having the prefix until the value deletion limit is reached. // It returns the updated node newParent, the number of deleted values valuesDeleted and the // allDeleted boolean indicating if there is no key left with the prefix. -func (t *Trie) clearPrefixLimitAtNode(parent *Node, prefix []byte, limit uint32) ( +func (t *Trie) clearPrefixLimitAtNode(parent *Node, prefix []byte, + limit uint32, deletedMerkleValues map[string]struct{}) ( newParent *Node, valuesDeleted, nodesRemoved uint32, allDeleted bool) { if parent == nil { return nil, 0, 0, true @@ -713,15 +754,17 @@ func (t *Trie) clearPrefixLimitAtNode(parent *Node, prefix []byte, limit uint32) return parent, 0, 0, allDeleted } - return t.clearPrefixLimitBranch(parent, prefix, limit) + return t.clearPrefixLimitBranch(parent, prefix, limit, deletedMerkleValues) } -func (t *Trie) clearPrefixLimitBranch(branch *Node, prefix []byte, limit uint32) ( +func (t *Trie) clearPrefixLimitBranch(branch *Node, prefix []byte, limit uint32, + deletedMerkleValues map[string]struct{}) ( newParent *Node, valuesDeleted, nodesRemoved uint32, allDeleted bool) { newParent = branch if bytes.HasPrefix(branch.Key, prefix) { - newParent, valuesDeleted, nodesRemoved = t.deleteNodesLimit(branch, limit) + newParent, valuesDeleted, nodesRemoved = t.deleteNodesLimit( + branch, limit, deletedMerkleValues) allDeleted = newParent == nil return newParent, valuesDeleted, nodesRemoved, allDeleted } @@ -729,7 +772,7 @@ func (t *Trie) clearPrefixLimitBranch(branch *Node, prefix []byte, limit uint32) if len(prefix) == len(branch.Key)+1 && bytes.HasPrefix(branch.Key, prefix[:len(prefix)-1]) { // Prefix is one the children of the branch - return t.clearPrefixLimitChild(branch, prefix, limit) + return t.clearPrefixLimitChild(branch, prefix, limit, deletedMerkleValues) } noPrefixForNode := len(prefix) <= len(branch.Key) || @@ -744,13 +787,14 @@ func (t *Trie) clearPrefixLimitBranch(branch *Node, prefix []byte, limit uint32) childPrefix := prefix[len(branch.Key)+1:] child := branch.Children[childIndex] - child, valuesDeleted, nodesRemoved, allDeleted = t.clearPrefixLimitAtNode(child, childPrefix, limit) + child, valuesDeleted, nodesRemoved, allDeleted = t.clearPrefixLimitAtNode( + child, childPrefix, limit, deletedMerkleValues) if valuesDeleted == 0 { return branch, valuesDeleted, nodesRemoved, allDeleted } copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) branch.Children[childIndex] = child branch.Descendants -= nodesRemoved newParent, branchChildMerged := handleDeletion(branch, prefix) @@ -761,7 +805,8 @@ func (t *Trie) clearPrefixLimitBranch(branch *Node, prefix []byte, limit uint32) return newParent, valuesDeleted, nodesRemoved, allDeleted } -func (t *Trie) clearPrefixLimitChild(branch *Node, prefix []byte, limit uint32) ( +func (t *Trie) clearPrefixLimitChild(branch *Node, prefix []byte, limit uint32, + deletedMerkleValues map[string]struct{}) ( newParent *Node, valuesDeleted, nodesRemoved uint32, allDeleted bool) { newParent = branch @@ -775,14 +820,15 @@ func (t *Trie) clearPrefixLimitChild(branch *Node, prefix []byte, limit uint32) return newParent, valuesDeleted, nodesRemoved, allDeleted } - child, valuesDeleted, nodesRemoved = t.deleteNodesLimit(child, limit) + child, valuesDeleted, nodesRemoved = t.deleteNodesLimit( + child, limit, deletedMerkleValues) if valuesDeleted == 0 { allDeleted = branch.Children[childIndex] == nil return branch, valuesDeleted, nodesRemoved, allDeleted } copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) branch.Children[childIndex] = child branch.Descendants -= nodesRemoved @@ -795,7 +841,8 @@ func (t *Trie) clearPrefixLimitChild(branch *Node, prefix []byte, limit uint32) return newParent, valuesDeleted, nodesRemoved, allDeleted } -func (t *Trie) deleteNodesLimit(parent *Node, limit uint32) ( +func (t *Trie) deleteNodesLimit(parent *Node, limit uint32, + deletedMerkleValues map[string]struct{}) ( newParent *Node, valuesDeleted, nodesRemoved uint32) { if limit == 0 { valuesDeleted, nodesRemoved = 0, 0 @@ -824,9 +871,10 @@ func (t *Trie) deleteNodesLimit(parent *Node, limit uint32) ( } copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) - branch.Children[i], newDeleted, newNodesRemoved = t.deleteNodesLimit(child, limit) + branch.Children[i], newDeleted, newNodesRemoved = t.deleteNodesLimit( + child, limit, deletedMerkleValues) // Note: newDeleted can never be zero here since the limit isn't zero // and the child is not nil. Therefore it is safe to prepare the branch // for mutation right before this call. @@ -866,6 +914,12 @@ func (t *Trie) deleteNodesLimit(parent *Node, limit uint32) ( // ClearPrefix deletes all nodes in the trie for which the key contains the // prefix given in little Endian format. func (t *Trie) ClearPrefix(prefixLE []byte) { + pendingDeletedMerkleValues := make(map[string]struct{}) + defer func() { + const success = true + t.handleTrackedDeltas(success, pendingDeletedMerkleValues) + }() + if len(prefixLE) == 0 { t.root = nil return @@ -874,10 +928,11 @@ func (t *Trie) ClearPrefix(prefixLE []byte) { prefix := codec.KeyLEToNibbles(prefixLE) prefix = bytes.TrimSuffix(prefix, []byte{0}) - t.root, _ = t.clearPrefixAtNode(t.root, prefix) + t.root, _ = t.clearPrefixAtNode(t.root, prefix, pendingDeletedMerkleValues) } -func (t *Trie) clearPrefixAtNode(parent *Node, prefix []byte) ( +func (t *Trie) clearPrefixAtNode(parent *Node, prefix []byte, + deletedMerkleValues map[string]struct{}) ( newParent *Node, nodesRemoved uint32) { if parent == nil { const nodesRemoved = 0 @@ -908,7 +963,7 @@ func (t *Trie) clearPrefixAtNode(parent *Node, prefix []byte) ( nodesRemoved = 1 + child.Descendants copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) branch.Children[childIndex] = nil branch.Descendants -= nodesRemoved var branchChildMerged bool @@ -930,13 +985,13 @@ func (t *Trie) clearPrefixAtNode(parent *Node, prefix []byte) ( childPrefix := prefix[len(branch.Key)+1:] child := branch.Children[childIndex] - child, nodesRemoved = t.clearPrefixAtNode(child, childPrefix) + child, nodesRemoved = t.clearPrefixAtNode(child, childPrefix, deletedMerkleValues) if nodesRemoved == 0 { return parent, nodesRemoved } copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) branch.Descendants -= nodesRemoved branch.Children[childIndex] = child newParent, branchChildMerged := handleDeletion(branch, prefix) @@ -951,11 +1006,18 @@ func (t *Trie) clearPrefixAtNode(parent *Node, prefix []byte) ( // matching the key given in little Endian format. // If no node is found at this key, nothing is deleted. func (t *Trie) Delete(keyLE []byte) { + pendingDeletedMerkleValues := make(map[string]struct{}) + defer func() { + const success = true + t.handleTrackedDeltas(success, pendingDeletedMerkleValues) + }() + key := codec.KeyLEToNibbles(keyLE) - t.root, _, _ = t.deleteAtNode(t.root, key) + t.root, _, _ = t.deleteAtNode(t.root, key, pendingDeletedMerkleValues) } -func (t *Trie) deleteAtNode(parent *Node, key []byte) ( +func (t *Trie) deleteAtNode(parent *Node, key []byte, + deletedMerkleValues map[string]struct{}) ( newParent *Node, deleted bool, nodesRemoved uint32) { if parent == nil { const nodesRemoved = 0 @@ -970,7 +1032,7 @@ func (t *Trie) deleteAtNode(parent *Node, key []byte) ( const nodesRemoved = 0 return parent, false, nodesRemoved } - return t.deleteBranch(parent, key) + return t.deleteBranch(parent, key, deletedMerkleValues) } func deleteLeaf(parent *Node, key []byte) (newParent *Node) { @@ -980,12 +1042,13 @@ func deleteLeaf(parent *Node, key []byte) (newParent *Node) { return parent } -func (t *Trie) deleteBranch(branch *Node, key []byte) ( +func (t *Trie) deleteBranch(branch *Node, key []byte, + deletedMerkleValues map[string]struct{}) ( newParent *Node, deleted bool, nodesRemoved uint32) { if len(key) == 0 || bytes.Equal(branch.Key, key) { copySettings := node.DefaultCopySettings copySettings.CopyValue = false - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) // we need to set to nil if the branch has the same generation // as the current trie. branch.SubValue = nil @@ -1007,14 +1070,14 @@ func (t *Trie) deleteBranch(branch *Node, key []byte) ( childKey := key[commonPrefixLength+1:] child := branch.Children[childIndex] - newChild, deleted, nodesRemoved := t.deleteAtNode(child, childKey) + newChild, deleted, nodesRemoved := t.deleteAtNode(child, childKey, deletedMerkleValues) if !deleted { const nodesRemoved = 0 return branch, false, nodesRemoved } copySettings := node.DefaultCopySettings - branch = t.prepBranchForMutation(branch, copySettings) + branch = t.prepBranchForMutation(branch, copySettings, deletedMerkleValues) branch.Descendants -= nodesRemoved branch.Children[childIndex] = newChild diff --git a/lib/trie/trie_test.go b/lib/trie/trie_test.go index 4b8aa7b1fc..0e9ef8d8ad 100644 --- a/lib/trie/trie_test.go +++ b/lib/trie/trie_test.go @@ -90,7 +90,7 @@ func Test_Trie_Snapshot(t *testing.T) { newTrie := trie.Snapshot() - assert.Equal(t, expectedTrie, newTrie) + assert.Equal(t, expectedTrie.childTries, newTrie.childTries) } func Test_Trie_updateGeneration(t *testing.T) { @@ -1058,13 +1058,14 @@ func Test_Trie_insert(t *testing.T) { t.Parallel() testCases := map[string]struct { - trie Trie - parent *Node - key []byte - value []byte - newNode *Node - mutated bool - nodesCreated uint32 + trie Trie + parent *Node + key []byte + value []byte + deletedMerkleValues map[string]struct{} + newNode *Node + mutated bool + nodesCreated uint32 }{ "nil parent": { trie: Trie{ @@ -1267,7 +1268,9 @@ func Test_Trie_insert(t *testing.T) { trie := testCase.trie expectedTrie := *trie.DeepCopy() - newNode, mutated, nodesCreated := trie.insert(testCase.parent, testCase.key, testCase.value) + newNode, mutated, nodesCreated := trie.insert( + testCase.parent, testCase.key, testCase.value, + testCase.deletedMerkleValues) assert.Equal(t, testCase.newNode, newNode) assert.Equal(t, testCase.mutated, mutated) @@ -1281,12 +1284,13 @@ func Test_Trie_insertInBranch(t *testing.T) { t.Parallel() testCases := map[string]struct { - parent *Node - key []byte - value []byte - newNode *Node - mutated bool - nodesCreated uint32 + parent *Node + key []byte + value []byte + deletedMerkleValues map[string]struct{} + newNode *Node + mutated bool + nodesCreated uint32 }{ "insert existing value to branch": { parent: &Node{ @@ -1558,7 +1562,9 @@ func Test_Trie_insertInBranch(t *testing.T) { trie := new(Trie) - newNode, mutated, nodesCreated := trie.insertInBranch(testCase.parent, testCase.key, testCase.value) + newNode, mutated, nodesCreated := trie.insertInBranch( + testCase.parent, testCase.key, testCase.value, + testCase.deletedMerkleValues) assert.Equal(t, testCase.newNode, newNode) assert.Equal(t, testCase.mutated, mutated) @@ -1604,7 +1610,26 @@ func Test_LoadFromMap(t *testing.T) { errWrapped: hex.ErrLength, errMessage: "cannot convert value hex to bytes: encoding/hex: odd length hex string: 0xa", }, - "load into empty trie": { + "load large key value": { + data: map[string]string{ + "0x01": "0x1234567812345678123456781234567812345678123456781234567812345678", // 32 bytes + }, + expectedTrie: Trie{ + root: &Node{ + Key: []byte{00, 01}, + SubValue: []byte{ + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, + }, + Dirty: true, + }, + childTries: map[common.Hash]*Trie{}, + deletedMerkleValues: map[string]struct{}{}, + }, + }, + "load key values": { data: map[string]string{ "0x01": "0x06", "0x0120": "0x07", @@ -2141,14 +2166,15 @@ func Test_Trie_clearPrefixLimitAtNode(t *testing.T) { t.Parallel() testCases := map[string]struct { - trie Trie - parent *Node - prefix []byte - limit uint32 - newParent *Node - valuesDeleted uint32 - nodesRemoved uint32 - allDeleted bool + trie Trie + parent *Node + prefix []byte + limit uint32 + deletedMerkleValues map[string]struct{} + newParent *Node + valuesDeleted uint32 + nodesRemoved uint32 + allDeleted bool }{ "limit is zero": { allDeleted: true, @@ -2666,7 +2692,8 @@ func Test_Trie_clearPrefixLimitAtNode(t *testing.T) { expectedTrie := *trie.DeepCopy() newParent, valuesDeleted, nodesRemoved, allDeleted := - trie.clearPrefixLimitAtNode(testCase.parent, testCase.prefix, testCase.limit) + trie.clearPrefixLimitAtNode(testCase.parent, testCase.prefix, + testCase.limit, testCase.deletedMerkleValues) assert.Equal(t, testCase.newParent, newParent) assert.Equal(t, testCase.valuesDeleted, valuesDeleted) @@ -2681,12 +2708,13 @@ func Test_Trie_deleteNodesLimit(t *testing.T) { t.Parallel() testCases := map[string]struct { - trie Trie - parent *Node - limit uint32 - newNode *Node - valuesDeleted uint32 - nodesRemoved uint32 + trie Trie + parent *Node + limit uint32 + deletedMerkleValues map[string]struct{} + newNode *Node + valuesDeleted uint32 + nodesRemoved uint32 }{ "zero limit": { trie: Trie{ @@ -2838,7 +2866,8 @@ func Test_Trie_deleteNodesLimit(t *testing.T) { expectedTrie := *trie.DeepCopy() newNode, valuesDeleted, nodesRemoved := - trie.deleteNodesLimit(testCase.parent, testCase.limit) + trie.deleteNodesLimit(testCase.parent, + testCase.limit, testCase.deletedMerkleValues) assert.Equal(t, testCase.newNode, newNode) assert.Equal(t, testCase.valuesDeleted, valuesDeleted) @@ -2928,11 +2957,12 @@ func Test_Trie_clearPrefixAtNode(t *testing.T) { t.Parallel() testCases := map[string]struct { - trie Trie - parent *Node - prefix []byte - newParent *Node - nodesRemoved uint32 + trie Trie + parent *Node + prefix []byte + deletedMerkleValues map[string]struct{} + newParent *Node + nodesRemoved uint32 }{ "delete one of two children of branch": { trie: Trie{ @@ -3209,8 +3239,8 @@ func Test_Trie_clearPrefixAtNode(t *testing.T) { trie := testCase.trie expectedTrie := *trie.DeepCopy() - newParent, nodesRemoved := - trie.clearPrefixAtNode(testCase.parent, testCase.prefix) + newParent, nodesRemoved := trie.clearPrefixAtNode( + testCase.parent, testCase.prefix, testCase.deletedMerkleValues) assert.Equal(t, testCase.newParent, newParent) assert.Equal(t, testCase.nodesRemoved, nodesRemoved) @@ -3314,12 +3344,13 @@ func Test_Trie_deleteAtNode(t *testing.T) { t.Parallel() testCases := map[string]struct { - trie Trie - parent *Node - key []byte - newParent *Node - updated bool - nodesRemoved uint32 + trie Trie + parent *Node + key []byte + deletedMerkleValues map[string]struct{} + newParent *Node + updated bool + nodesRemoved uint32 }{ "nil parent": { key: []byte{1}, @@ -3610,7 +3641,8 @@ func Test_Trie_deleteAtNode(t *testing.T) { } expectedTrie := *testCase.trie.DeepCopy() - newParent, updated, nodesRemoved := testCase.trie.deleteAtNode(testCase.parent, testCase.key) + newParent, updated, nodesRemoved := testCase.trie.deleteAtNode( + testCase.parent, testCase.key, testCase.deletedMerkleValues) assert.Equal(t, testCase.newParent, newParent) assert.Equal(t, testCase.updated, updated)