You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

137 lines
3.5 KiB

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
}