mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
resolve tree reinit bug
This commit is contained in:
parent
7f8137df67
commit
6df30fb455
@ -262,6 +262,7 @@ func (t *VectorCommitmentTree) Insert(key, value []byte) error {
|
||||
return newBranch
|
||||
}
|
||||
}
|
||||
|
||||
// Key matches prefix, continue with final nibble
|
||||
finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits)
|
||||
n.Children[finalNibble] = insert(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits)
|
||||
|
||||
258
node/crypto/tree_compare.go
Normal file
258
node/crypto/tree_compare.go
Normal file
@ -0,0 +1,258 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CompareTreesAtHeight compares two vector commitment trees at each level
|
||||
func CompareTreesAtHeight(tree1, tree2 *VectorCommitmentTree) [][]ComparisonResult {
|
||||
if tree1 == nil || tree2 == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var results [][]ComparisonResult
|
||||
maxHeight := getMaxHeight(tree1.Root, tree2.Root)
|
||||
|
||||
// Compare level by level
|
||||
for height := 0; height <= maxHeight; height++ {
|
||||
levelResults := compareLevelCommits(tree1.Root, tree2.Root, height, 0)
|
||||
results = append(results, levelResults)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
type ComparisonResult struct {
|
||||
Path []int // Path taken to reach this node (nibble values)
|
||||
Height int // Current height in the tree
|
||||
Commit1 []byte // Commitment from first tree
|
||||
Commit2 []byte // Commitment from second tree
|
||||
Matches bool // Whether the commitments match
|
||||
}
|
||||
|
||||
func getMaxHeight(node1, node2 VectorCommitmentNode) int {
|
||||
height1 := getHeight(node1)
|
||||
height2 := getHeight(node2)
|
||||
if height1 > height2 {
|
||||
return height1
|
||||
}
|
||||
return height2
|
||||
}
|
||||
|
||||
func getHeight(node VectorCommitmentNode) int {
|
||||
if node == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch n := node.(type) {
|
||||
case *VectorCommitmentLeafNode:
|
||||
return 0
|
||||
case *VectorCommitmentBranchNode:
|
||||
maxChildHeight := 0
|
||||
for _, child := range n.Children {
|
||||
childHeight := getHeight(child)
|
||||
if childHeight > maxChildHeight {
|
||||
maxChildHeight = childHeight
|
||||
}
|
||||
}
|
||||
return maxChildHeight + 1 + len(n.Prefix)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func compareLevelCommits(node1, node2 VectorCommitmentNode, targetHeight, currentHeight int) []ComparisonResult {
|
||||
if node1 == nil && node2 == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we've reached the target height, compare the commits
|
||||
if currentHeight == targetHeight {
|
||||
var commit1, commit2 []byte
|
||||
if node1 != nil {
|
||||
commit1 = node1.Commit(false)
|
||||
}
|
||||
if node2 != nil {
|
||||
commit2 = node2.Commit(false)
|
||||
}
|
||||
|
||||
return []ComparisonResult{{
|
||||
Height: targetHeight,
|
||||
Commit1: commit1,
|
||||
Commit2: commit2,
|
||||
Matches: bytes.Equal(commit1, commit2),
|
||||
}}
|
||||
}
|
||||
|
||||
// If we haven't reached the target height, traverse deeper
|
||||
var results []ComparisonResult
|
||||
|
||||
// Handle branch nodes
|
||||
switch n1 := node1.(type) {
|
||||
case *VectorCommitmentBranchNode:
|
||||
n2, ok := node2.(*VectorCommitmentBranchNode)
|
||||
if !ok {
|
||||
// Trees have different structure at this point
|
||||
return results
|
||||
}
|
||||
|
||||
// Account for prefix lengths
|
||||
nextHeight := currentHeight
|
||||
if len(n1.Prefix) > 0 {
|
||||
nextHeight += len(n1.Prefix)
|
||||
}
|
||||
|
||||
// If we're still below target height after prefix, traverse children
|
||||
if nextHeight < targetHeight {
|
||||
for i := 0; i < BranchNodes; i++ {
|
||||
childResults := compareLevelCommits(n1.Children[i], n2.Children[i], targetHeight, nextHeight+1)
|
||||
results = append(results, childResults...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// TraverseAndCompare provides a channel-based iterator for comparing trees
|
||||
func TraverseAndCompare(tree1, tree2 *VectorCommitmentTree) chan ComparisonResult {
|
||||
resultChan := make(chan ComparisonResult)
|
||||
|
||||
go func() {
|
||||
defer close(resultChan)
|
||||
|
||||
if tree1 == nil || tree2 == nil {
|
||||
return
|
||||
}
|
||||
|
||||
maxHeight := getMaxHeight(tree1.Root, tree2.Root)
|
||||
|
||||
// Traverse each height
|
||||
for height := 0; height <= maxHeight; height++ {
|
||||
results := compareLevelCommits(tree1.Root, tree2.Root, height, 0)
|
||||
for _, result := range results {
|
||||
resultChan <- result
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return resultChan
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
// LeafDifference contains information about leaves that differ between trees
|
||||
type LeafDifference struct {
|
||||
Key []byte // The key of the leaf
|
||||
OnlyInTree1 bool // True if the leaf only exists in tree1
|
||||
OnlyInTree2 bool // True if the leaf only exists in tree2
|
||||
Value1 []byte // Value from tree1 (if present)
|
||||
Value2 []byte // Value from tree2 (if present)
|
||||
}
|
||||
|
||||
// CompareLeaves returns all leaves that differ between the two trees
|
||||
func CompareLeaves(tree1, tree2 *VectorCommitmentTree) []LeafDifference {
|
||||
// Get all leaves from both trees
|
||||
leaves1 := getAllLeaves(tree1.Root)
|
||||
leaves2 := getAllLeaves(tree2.Root)
|
||||
|
||||
differences := make([]LeafDifference, 0)
|
||||
|
||||
// Use maps for efficient lookup
|
||||
leafMap1 := make(map[string]*VectorCommitmentLeafNode)
|
||||
leafMap2 := make(map[string]*VectorCommitmentLeafNode)
|
||||
|
||||
// Build maps
|
||||
for _, leaf := range leaves1 {
|
||||
leafMap1[string(leaf.Key)] = leaf
|
||||
}
|
||||
for _, leaf := range leaves2 {
|
||||
leafMap2[string(leaf.Key)] = leaf
|
||||
}
|
||||
|
||||
// Find leaves only in tree1 or with different values
|
||||
for _, leaf1 := range leaves1 {
|
||||
key := string(leaf1.Key)
|
||||
if leaf2, exists := leafMap2[key]; exists {
|
||||
// Leaf exists in both trees, check if values match
|
||||
if !bytes.Equal(leaf1.Value, leaf2.Value) {
|
||||
differences = append(differences, LeafDifference{
|
||||
Key: leaf1.Key,
|
||||
Value1: leaf1.Value,
|
||||
Value2: leaf2.Value,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Leaf only exists in tree1
|
||||
differences = append(differences, LeafDifference{
|
||||
Key: leaf1.Key,
|
||||
OnlyInTree1: true,
|
||||
Value1: leaf1.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Find leaves only in tree2
|
||||
for _, leaf2 := range leaves2 {
|
||||
key := string(leaf2.Key)
|
||||
if _, exists := leafMap1[key]; !exists {
|
||||
differences = append(differences, LeafDifference{
|
||||
Key: leaf2.Key,
|
||||
OnlyInTree2: true,
|
||||
Value2: leaf2.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return differences
|
||||
}
|
||||
|
||||
// getAllLeaves returns all leaf nodes in the tree
|
||||
func getAllLeaves(node VectorCommitmentNode) []*VectorCommitmentLeafNode {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var leaves []*VectorCommitmentLeafNode
|
||||
|
||||
switch n := node.(type) {
|
||||
case *VectorCommitmentLeafNode:
|
||||
leaves = append(leaves, n)
|
||||
case *VectorCommitmentBranchNode:
|
||||
for _, child := range n.Children {
|
||||
if child != nil {
|
||||
childLeaves := getAllLeaves(child)
|
||||
leaves = append(leaves, childLeaves...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return leaves
|
||||
}
|
||||
|
||||
func ExampleComparison() {
|
||||
// Create and populate two trees
|
||||
tree1 := &VectorCommitmentTree{}
|
||||
tree2 := &VectorCommitmentTree{}
|
||||
|
||||
// Compare trees using channel-based iterator
|
||||
for result := range TraverseAndCompare(tree1, tree2) {
|
||||
if !result.Matches {
|
||||
fmt.Printf("Mismatch at height %d\n", result.Height)
|
||||
fmt.Printf("Tree1 commit: %x\n", result.Commit1)
|
||||
fmt.Printf("Tree2 commit: %x\n", result.Commit2)
|
||||
}
|
||||
}
|
||||
|
||||
// Compare leaves between trees
|
||||
differences := CompareLeaves(tree1, tree2)
|
||||
for _, diff := range differences {
|
||||
if diff.OnlyInTree1 {
|
||||
fmt.Printf("Key %x only exists in tree1 with value %x\n", diff.Key, diff.Value1)
|
||||
} else if diff.OnlyInTree2 {
|
||||
fmt.Printf("Key %x only exists in tree2 with value %x\n", diff.Key, diff.Value2)
|
||||
} else {
|
||||
fmt.Printf("Key %x has different values: tree1=%x, tree2=%x\n",
|
||||
diff.Key, diff.Value1, diff.Value2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,10 +45,12 @@ func (a *TokenApplication) handleDataAnnounceProverJoin(
|
||||
error,
|
||||
) {
|
||||
if currentFrameNumber < PROOF_FRAME_CUTOFF {
|
||||
a.Logger.Debug("join earlier than cutoff", zap.Uint64("current_frame", currentFrameNumber), zap.Uint64("cutoff", PROOF_FRAME_CUTOFF))
|
||||
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
|
||||
}
|
||||
|
||||
if err := t.Validate(); err != nil {
|
||||
a.Logger.Debug("invalid join", zap.Error(err))
|
||||
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
|
||||
}
|
||||
|
||||
@ -94,6 +96,7 @@ func (a *TokenApplication) handleDataAnnounceProverJoin(
|
||||
if t.Announce != nil {
|
||||
outputs, err = a.handleAnnounce(currentFrameNumber, lockMap, t.Announce)
|
||||
if err != nil {
|
||||
a.Logger.Debug("bad announce", zap.Error(err))
|
||||
return nil, errors.Wrap(ErrInvalidStateTransition, "handle join")
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +436,11 @@ func (e *TokenExecutionEngine) rebuildStateTree() {
|
||||
panic(err)
|
||||
}
|
||||
for iter.First(); iter.Valid(); iter.Next() {
|
||||
e.stateTree.Insert(iter.Key()[2:], iter.Value())
|
||||
key := make([]byte, len(iter.Key()[2:]))
|
||||
value := make([]byte, len(iter.Value()))
|
||||
copy(key, iter.Key()[2:])
|
||||
copy(value, iter.Value())
|
||||
e.stateTree.Insert(key, value)
|
||||
}
|
||||
iter.Close()
|
||||
|
||||
@ -445,7 +449,11 @@ func (e *TokenExecutionEngine) rebuildStateTree() {
|
||||
panic(err)
|
||||
}
|
||||
for iter.First(); iter.Valid(); iter.Next() {
|
||||
e.stateTree.Insert(iter.Key()[2:], iter.Value())
|
||||
key := make([]byte, len(iter.Key()[2:]))
|
||||
value := make([]byte, len(iter.Value()))
|
||||
copy(key, iter.Key()[2:])
|
||||
copy(value, iter.Value())
|
||||
e.stateTree.Insert(key, value)
|
||||
}
|
||||
iter.Close()
|
||||
e.logger.Info("saving rebuilt state tree")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user