resolve state tree issue, ensure message validation is consistent with mint

This commit is contained in:
Cassandra Heart 2025-01-28 08:35:48 -06:00
parent a0107caabc
commit 5ed5f4ca6a
No known key found for this signature in database
GPG Key ID: 6352152859385958
6 changed files with 109 additions and 55 deletions

View File

@ -74,6 +74,7 @@ func (e *DataClockConsensusEngine) syncWithMesh() error {
func (e *DataClockConsensusEngine) prove(
previousFrame *protobufs.ClockFrame,
) (*protobufs.ClockFrame, error) {
time.Sleep(40 * time.Second)
if e.lastProven >= previousFrame.FrameNumber && e.lastProven != 0 {
return previousFrame, nil
}

View File

@ -117,7 +117,7 @@ func (e *DataClockConsensusEngine) validateTxMessage(peerID peer.ID, message *pb
if err != nil {
panic(err)
}
if frameNumber+2 < head.FrameNumber {
if frameNumber+1 < head.FrameNumber {
return p2p.ValidationResultIgnore
}
}

View File

@ -23,7 +23,7 @@ const (
)
type VectorCommitmentNode interface {
Commit() []byte
Commit(recalculate bool) []byte
}
type VectorCommitmentLeafNode struct {
@ -38,8 +38,8 @@ type VectorCommitmentBranchNode struct {
Commitment []byte
}
func (n *VectorCommitmentLeafNode) Commit() []byte {
if n.Commitment == nil {
func (n *VectorCommitmentLeafNode) Commit(recalculate bool) []byte {
if n.Commitment == nil || recalculate {
h := sha512.New()
h.Write([]byte{0})
h.Write(n.Key)
@ -49,12 +49,12 @@ func (n *VectorCommitmentLeafNode) Commit() []byte {
return n.Commitment
}
func (n *VectorCommitmentBranchNode) Commit() []byte {
if n.Commitment == nil {
func (n *VectorCommitmentBranchNode) Commit(recalculate bool) []byte {
if n.Commitment == nil || recalculate {
data := []byte{}
for _, child := range n.Children {
if child != nil {
out := child.Commit()
out := child.Commit(recalculate)
switch c := child.(type) {
case *VectorCommitmentBranchNode:
h := sha512.New()
@ -84,7 +84,7 @@ func (n *VectorCommitmentBranchNode) Verify(index int, proof []byte) bool {
if n.Commitment == nil {
for _, child := range n.Children {
if child != nil {
out := child.Commit()
out := child.Commit(false)
switch c := child.(type) {
case *VectorCommitmentBranchNode:
h := sha512.New()
@ -108,7 +108,7 @@ func (n *VectorCommitmentBranchNode) Verify(index int, proof []byte) bool {
} else {
child := n.Children[index]
if child != nil {
out := child.Commit()
out := child.Commit(false)
switch c := child.(type) {
case *VectorCommitmentBranchNode:
h := sha512.New()
@ -134,7 +134,7 @@ func (n *VectorCommitmentBranchNode) Prove(index int) []byte {
data := []byte{}
for _, child := range n.Children {
if child != nil {
out := child.Commit()
out := child.Commit(false)
switch c := child.(type) {
case *VectorCommitmentBranchNode:
h := sha512.New()
@ -416,13 +416,14 @@ func (t *VectorCommitmentTree) Delete(key []byte) error {
return errors.New("empty key not allowed")
}
var delete func(node VectorCommitmentNode, depth int) VectorCommitmentNode
delete = func(node VectorCommitmentNode, depth int) VectorCommitmentNode {
var remove func(node VectorCommitmentNode, depth int) VectorCommitmentNode
remove = func(node VectorCommitmentNode, depth int) VectorCommitmentNode {
if node == nil {
return nil
}
switch n := node.(type) {
case *VectorCommitmentLeafNode:
if bytes.Equal(n.Key, key) {
return nil
@ -430,63 +431,66 @@ func (t *VectorCommitmentTree) Delete(key []byte) error {
return n
case *VectorCommitmentBranchNode:
// Check prefix match
for i, expectedNibble := range n.Prefix {
currentNibble := getNextNibble(key, depth+i*BranchBits)
if currentNibble != expectedNibble {
return n // Key doesn't match prefix, nothing to delete
return n
}
}
// Delete at final position after prefix
finalNibble := getNextNibble(key, depth+len(n.Prefix)*BranchBits)
n.Children[finalNibble] = delete(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits)
n.Children[finalNibble] =
remove(n.Children[finalNibble], depth+len(n.Prefix)*BranchBits+BranchBits)
n.Commitment = nil
// Count remaining children
childCount := 0
var lastChild VectorCommitmentNode
var lastIndex int
var lastChildIndex int
for i, child := range n.Children {
if child != nil {
childCount++
lastChild = child
lastIndex = i
lastChildIndex = i
}
}
if childCount == 0 {
switch childCount {
case 0:
return nil
} else if childCount == 1 {
// If the only child is a leaf, keep structure if its path matches
if leaf, ok := lastChild.(*VectorCommitmentLeafNode); ok {
if lastIndex == getLastNibble(leaf.Key, len(n.Prefix)) {
return n
}
return leaf
}
// If it's a branch, merge the prefixes
if branch, ok := lastChild.(*VectorCommitmentBranchNode); ok {
branch.Prefix = append(n.Prefix, branch.Prefix...)
return branch
}
}
return n
}
case 1:
if childBranch, ok := lastChild.(*VectorCommitmentBranchNode); ok {
// Merge:
// n.Prefix + [lastChildIndex] + childBranch.Prefix
mergedPrefix := make([]int, 0, len(n.Prefix)+1+len(childBranch.Prefix))
mergedPrefix = append(mergedPrefix, n.Prefix...)
mergedPrefix = append(mergedPrefix, lastChildIndex)
mergedPrefix = append(mergedPrefix, childBranch.Prefix...)
return nil
childBranch.Prefix = mergedPrefix
childBranch.Commitment = nil
return childBranch
}
return lastChild
default:
return n
}
default:
return node
}
}
t.Root = delete(t.Root, 0)
t.Root = remove(t.Root, 0)
return nil
}
// Commit returns the root of the tree
func (t *VectorCommitmentTree) Commit() []byte {
func (t *VectorCommitmentTree) Commit(recalculate bool) []byte {
if t.Root == nil {
return make([]byte, 64)
}
return t.Root.Commit()
return t.Root.Commit(recalculate)
}
func debugNode(node VectorCommitmentNode, depth int, prefix string) {

View File

@ -36,7 +36,7 @@ func BenchmarkVectorCommitmentTreeCommit(b *testing.B) {
if err != nil {
b.Errorf("Failed to insert item %d: %v", i, err)
}
tree.Commit()
tree.Commit(false)
}
}
@ -221,7 +221,7 @@ func TestVectorCommitmentTrees(t *testing.T) {
// Root should change after insert
tree.Insert([]byte("key1"), []byte("value1"))
firstRoot := tree.Root.Commit()
firstRoot := tree.Root.Commit(false)
if bytes.Equal(firstRoot, bytes.Repeat([]byte{0x00}, 64)) {
t.Error("Root hash should change after insert")
@ -229,7 +229,7 @@ func TestVectorCommitmentTrees(t *testing.T) {
// Root should change after update
tree.Insert([]byte("key1"), []byte("value2"))
secondRoot := tree.Root.Commit()
secondRoot := tree.Root.Commit(false)
if bytes.Equal(secondRoot, firstRoot) {
t.Error("Root hash should change after update")
@ -248,14 +248,27 @@ func TestVectorCommitmentTrees(t *testing.T) {
addresses := [][]byte{}
for i := 0; i < 1000; i++ {
for i := 0; i < 10000; i++ {
d := make([]byte, 32)
rand.Read(d)
addresses = append(addresses, d)
}
// Insert 1000 items
for i := 0; i < 1000; i++ {
kept := [][]byte{}
for i := 0; i < 5000; i++ {
kept = append(kept, addresses[i])
}
newAdditions := [][]byte{}
for i := 0; i < 5000; i++ {
d := make([]byte, 32)
rand.Read(d)
newAdditions = append(newAdditions, d)
kept = append(kept, d)
}
// Insert 10000 items
for i := 0; i < 10000; i++ {
key := addresses[i]
value := addresses[i]
err := tree.Insert(key, value)
@ -264,8 +277,8 @@ func TestVectorCommitmentTrees(t *testing.T) {
}
}
// Insert 1000 items in reverse
for i := 999; i >= 0; i-- {
// Insert 10000 items in reverse
for i := 9999; i >= 0; i-- {
key := addresses[i]
value := addresses[i]
err := cmptree.Insert(key, value)
@ -275,7 +288,7 @@ func TestVectorCommitmentTrees(t *testing.T) {
}
// Verify all items
for i := 0; i < 1000; i++ {
for i := 0; i < 10000; i++ {
key := addresses[i]
expected := addresses[i]
value, err := tree.Get(key)
@ -294,8 +307,44 @@ func TestVectorCommitmentTrees(t *testing.T) {
}
}
tcommit := tree.Root.Commit()
cmptcommit := cmptree.Root.Commit()
// delete keys
for i := 5000; i < 10000; i++ {
key := addresses[i]
fmt.Printf("delete %x\n", key)
tree.Delete(key)
}
// add new
for i := 0; i < 5000; i++ {
tree.Insert(newAdditions[i], newAdditions[i])
}
cmptree = &VectorCommitmentTree{}
for i := 0; i < 10000; i++ {
cmptree.Insert(kept[i], kept[i])
}
// Verify all items
for i := 0; i < 10000; i++ {
key := kept[i]
expected := kept[i]
value, err := tree.Get(key)
if err != nil {
t.Errorf("Failed to get item %d: %v", i, err)
}
cmpvalue, err := cmptree.Get(key)
if err != nil {
t.Errorf("Failed to get item %d: %v", i, err)
}
if !bytes.Equal(value, expected) {
t.Errorf("Item %d: expected %x, got %x", i, string(expected), string(value))
}
if !bytes.Equal(expected, cmpvalue) {
t.Errorf("Item %d: expected %x, got %x", i, string(value), string(cmpvalue))
}
}
tcommit := tree.Root.Commit(false)
cmptcommit := cmptree.Root.Commit(false)
if !bytes.Equal(tcommit, cmptcommit) {
t.Errorf("tree mismatch, %x, %x", tcommit, cmptcommit)

View File

@ -209,7 +209,7 @@ func (a *TokenApplication) ApplyTransitions(
continue
} else if len(t.Mint.Proofs) >= 3 && currentFrameNumber > PROOF_FRAME_CUTOFF {
frameNumber := binary.BigEndian.Uint64(t.Mint.Proofs[2])
if frameNumber < currentFrameNumber-2 {
if frameNumber < currentFrameNumber-1 {
fails[i] = transition
continue
}

View File

@ -348,7 +348,7 @@ func NewTokenExecutionEngine(
e.provingKeyAddress = provingKeyAddress
frame, _, err := e.clockStore.GetLatestDataClockFrame(e.intrinsicFilter)
if err != nil || frame.FrameNumber < 184479 {
if err != nil || frame.FrameNumber < 186405 {
e.rebuildStateTree()
} else {
e.stateTree, err = e.clockStore.GetDataStateTree(e.intrinsicFilter)
@ -457,7 +457,7 @@ func (e *TokenExecutionEngine) rebuildStateTree() {
e.logger.Info("committing state tree")
root := e.stateTree.Commit()
root := e.stateTree.Commit(true)
e.logger.Info(
"committed state tree",
@ -1049,7 +1049,7 @@ func (e *TokenExecutionEngine) ProcessFrame(
e.logger.Info("committing state tree")
root := stateTree.Commit()
root := stateTree.Commit(false)
e.logger.Info(
"commited state tree",