|
|
- package merkle
-
- import (
- "bytes"
- "crypto/sha256"
-
- "github.com/tendermint/tendermint/binary"
- . "github.com/tendermint/tendermint/common"
- )
-
- type IAVLProof struct {
- LeafNode IAVLProofLeafNode
- InnerNodes []IAVLProofInnerNode
- RootHash []byte
- }
-
- func (proof *IAVLProof) Verify(keyBytes, valueBytes, rootHash []byte) bool {
- if !bytes.Equal(keyBytes, proof.LeafNode.KeyBytes) {
- return false
- }
- if !bytes.Equal(valueBytes, proof.LeafNode.ValueBytes) {
- return false
- }
- if !bytes.Equal(rootHash, proof.RootHash) {
- return false
- }
- hash := proof.LeafNode.Hash()
- // fmt.Printf("leaf hash: %X\n", hash)
- for _, branch := range proof.InnerNodes {
- hash = branch.Hash(hash)
- // fmt.Printf("branch hash: %X\n", hash)
- }
- // fmt.Printf("root: %X, computed: %X\n", proof.RootHash, hash)
- return bytes.Equal(proof.RootHash, hash)
- }
-
- type IAVLProofInnerNode struct {
- Height int8
- Size int
- Left []byte
- Right []byte
- }
-
- func (branch IAVLProofInnerNode) Hash(childHash []byte) []byte {
- hasher := sha256.New()
- buf := new(bytes.Buffer)
- n, err := int64(0), error(nil)
- binary.WriteInt8(branch.Height, buf, &n, &err)
- binary.WriteVarint(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 IAVLProofInnerNode: %v", err))
- }
- // fmt.Printf("InnerNode hash bytes: %X\n", buf.Bytes())
- hasher.Write(buf.Bytes())
- return hasher.Sum(nil)
- }
-
- type IAVLProofLeafNode struct {
- KeyBytes []byte
- ValueBytes []byte
- }
-
- func (leaf IAVLProofLeafNode) Hash() []byte {
- hasher := sha256.New()
- buf := new(bytes.Buffer)
- n, err := int64(0), error(nil)
- binary.WriteInt8(0, buf, &n, &err)
- binary.WriteVarint(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 IAVLProofLeafNode: %v", err))
- }
- // fmt.Printf("LeafNode 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 := IAVLProofLeafNode{
- KeyBytes: keyBuf.Bytes(),
- ValueBytes: valueBuf.Bytes(),
- }
- proof.LeafNode = leaf
- return true
- } else {
- return false
- }
- } else {
- if t.keyCodec.Compare(key, node.key) < 0 {
- exists := node.getLeftNode(t).constructProof(t, key, proof)
- if !exists {
- return false
- }
- branch := IAVLProofInnerNode{
- Height: node.height,
- Size: node.size,
- Left: nil,
- Right: node.getRightNode(t).hash,
- }
- proof.InnerNodes = append(proof.InnerNodes, branch)
- return true
- } else {
- exists := node.getRightNode(t).constructProof(t, key, proof)
- if !exists {
- return false
- }
- branch := IAVLProofInnerNode{
- Height: node.height,
- Size: node.size,
- Left: node.getLeftNode(t).hash,
- Right: nil,
- }
- proof.InnerNodes = append(proof.InnerNodes, branch)
- return true
- }
- }
- }
-
- // 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{
- RootHash: t.root.hash,
- }
- t.root.constructProof(t, key, proof)
- return proof
- }
|