package merkle import ( "bytes" "crypto/sha256" "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" ) type IAVLProof struct { Root []byte Branches []IAVLProofBranch Leaf IAVLProofLeaf } func (proof *IAVLProof) Verify() bool { hash := proof.Leaf.Hash() // fmt.Printf("leaf hash: %X\n", hash) for i := len(proof.Branches) - 1; 0 <= i; i-- { hash = proof.Branches[i].Hash(hash) // fmt.Printf("branch hash: %X\n", hash) } // fmt.Printf("root: %X, computed: %X\n", proof.Root, hash) return bytes.Equal(proof.Root, hash) } type IAVLProofBranch struct { Height uint8 Size uint Left []byte Right []byte } func (branch IAVLProofBranch) Hash(childHash []byte) []byte { hasher := sha256.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) binary.WriteUint8(branch.Height, buf, &n, &err) binary.WriteUvarint(branch.Size, buf, &n, &err) if branch.Left == nil { binary.WriteByteSlice(childHash, buf, &n, &err) binary.WriteByteSlice(branch.Right, buf, &n, &err) } else { binary.WriteByteSlice(branch.Left, buf, &n, &err) binary.WriteByteSlice(childHash, buf, &n, &err) } if err != nil { panic(Fmt("Failed to hash IAVLProofBranch: %v", err)) } // fmt.Printf("Branch hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) return hasher.Sum(nil) } type IAVLProofLeaf struct { KeyBytes []byte ValueBytes []byte } func (leaf IAVLProofLeaf) Hash() []byte { hasher := sha256.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) binary.WriteUint8(0, buf, &n, &err) binary.WriteUvarint(1, buf, &n, &err) binary.WriteByteSlice(leaf.KeyBytes, buf, &n, &err) binary.WriteByteSlice(leaf.ValueBytes, buf, &n, &err) if err != nil { panic(Fmt("Failed to hash IAVLProofLeaf: %v", err)) } // fmt.Printf("Leaf hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) return hasher.Sum(nil) } func (node *IAVLNode) constructProof(t *IAVLTree, key interface{}, proof *IAVLProof) (exists bool) { if node.height == 0 { if t.keyCodec.Compare(node.key, key) == 0 { keyBuf, valueBuf := new(bytes.Buffer), new(bytes.Buffer) n, err := int64(0), error(nil) t.keyCodec.Encode(node.key, keyBuf, &n, &err) if err != nil { panic(Fmt("Failed to encode node.key: %v", err)) } t.valueCodec.Encode(node.value, valueBuf, &n, &err) if err != nil { panic(Fmt("Failed to encode node.value: %v", err)) } leaf := IAVLProofLeaf{ KeyBytes: keyBuf.Bytes(), ValueBytes: valueBuf.Bytes(), } proof.Leaf = leaf return true } else { return false } } else { if t.keyCodec.Compare(key, node.key) < 0 { branch := IAVLProofBranch{ Height: node.height, Size: node.size, Left: nil, Right: node.getRightNode(t).hash, } if node.getRightNode(t).hash == nil { // fmt.Println(node.getRightNode(t)) panic("WTF") } proof.Branches = append(proof.Branches, branch) return node.getLeftNode(t).constructProof(t, key, proof) } else { branch := IAVLProofBranch{ Height: node.height, Size: node.size, Left: node.getLeftNode(t).hash, Right: nil, } proof.Branches = append(proof.Branches, branch) return node.getRightNode(t).constructProof(t, key, proof) } } } // Returns nil if key is not in tree. func (t *IAVLTree) ConstructProof(key interface{}) *IAVLProof { if t.root == nil { return nil } t.root.hashWithCount(t) // Ensure that all hashes are calculated. proof := &IAVLProof{ Root: t.root.hash, } t.root.constructProof(t, key, proof) return proof }