github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/proof_range.go (about)

     1  package iavl
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/tmhash"
    12  )
    13  
    14  type RangeProof struct {
    15  	// You don't need the right path because
    16  	// it can be derived from what we have.
    17  	LeftPath   PathToLeaf      `json:"left_path"`
    18  	InnerNodes []PathToLeaf    `json:"inner_nodes"`
    19  	Leaves     []ProofLeafNode `json:"leaves"`
    20  
    21  	// memoize
    22  	rootHash     []byte // valid iff rootVerified is true
    23  	rootVerified bool
    24  	treeEnd      bool // valid iff rootVerified is true
    25  
    26  }
    27  
    28  // Keys returns all the keys in the RangeProof.  NOTE: The keys here may
    29  // include more keys than provided by tree.GetRangeWithProof or
    30  // MutableTree.GetVersionedRangeWithProof.  The keys returned there are only
    31  // in the provided [startKey,endKey){limit} range.  The keys returned here may
    32  // include extra keys, such as:
    33  // - the key before startKey if startKey is provided and doesn't exist;
    34  // - the key after a queried key with tree.GetWithProof, when the key is absent.
    35  func (proof *RangeProof) Keys() (keys [][]byte) {
    36  	if proof == nil {
    37  		return nil
    38  	}
    39  	for _, leaf := range proof.Leaves {
    40  		keys = append(keys, leaf.Key)
    41  	}
    42  	return keys
    43  }
    44  
    45  // String returns a string representation of the proof.
    46  func (proof *RangeProof) String() string {
    47  	if proof == nil {
    48  		return "<nil-RangeProof>"
    49  	}
    50  	return proof.StringIndented("")
    51  }
    52  
    53  func (proof *RangeProof) StringIndented(indent string) string {
    54  	istrs := make([]string, 0, len(proof.InnerNodes))
    55  	for _, ptl := range proof.InnerNodes {
    56  		istrs = append(istrs, ptl.stringIndented(indent+"    "))
    57  	}
    58  	lstrs := make([]string, 0, len(proof.Leaves))
    59  	for _, leaf := range proof.Leaves {
    60  		lstrs = append(lstrs, leaf.stringIndented(indent+"    "))
    61  	}
    62  	return fmt.Sprintf(`RangeProof{
    63  %s  LeftPath: %v
    64  %s  InnerNodes:
    65  %s    %v
    66  %s  Leaves:
    67  %s    %v
    68  %s  (rootVerified): %v
    69  %s  (rootHash): %X
    70  %s  (treeEnd): %v
    71  %s}`,
    72  		indent, proof.LeftPath.stringIndented(indent+"  "),
    73  		indent,
    74  		indent, strings.Join(istrs, "\n"+indent+"    "),
    75  		indent,
    76  		indent, strings.Join(lstrs, "\n"+indent+"    "),
    77  		indent, proof.rootVerified,
    78  		indent, proof.rootHash,
    79  		indent, proof.treeEnd,
    80  		indent)
    81  }
    82  
    83  // The index of the first leaf (of the whole tree).
    84  // Returns -1 if the proof is nil.
    85  func (proof *RangeProof) LeftIndex() int64 {
    86  	if proof == nil {
    87  		return -1
    88  	}
    89  	return proof.LeftPath.Index()
    90  }
    91  
    92  // Also see LeftIndex().
    93  // Verify that a key has some value.
    94  // Does not assume that the proof itself is valid, call Verify() first.
    95  func (proof *RangeProof) VerifyItem(key, value []byte) error {
    96  	if proof == nil {
    97  		return errors.Wrap(ErrInvalidProof, "proof is nil")
    98  	}
    99  	if !proof.rootVerified {
   100  		return errors.New("must call Verify(root) first")
   101  	}
   102  	leaves := proof.Leaves
   103  	i := sort.Search(len(leaves), func(i int) bool {
   104  		return bytes.Compare(key, leaves[i].Key) <= 0
   105  	})
   106  	if i >= len(leaves) || !bytes.Equal(leaves[i].Key, key) {
   107  		return errors.Wrap(ErrInvalidProof, "leaf key not found in proof")
   108  	}
   109  	valueHash := tmhash.Sum(value)
   110  	if !bytes.Equal(leaves[i].ValueHash, valueHash) {
   111  		return errors.Wrap(ErrInvalidProof, "leaf value hash not same")
   112  	}
   113  	return nil
   114  }
   115  
   116  // Verify that proof is valid absence proof for key.
   117  // Does not assume that the proof itself is valid.
   118  // For that, use Verify(root).
   119  func (proof *RangeProof) VerifyAbsence(key []byte) error {
   120  	if proof == nil {
   121  		return errors.Wrap(ErrInvalidProof, "proof is nil")
   122  	}
   123  	if !proof.rootVerified {
   124  		return errors.New("must call Verify(root) first")
   125  	}
   126  	cmp := bytes.Compare(key, proof.Leaves[0].Key)
   127  	if cmp < 0 {
   128  		if proof.LeftPath.isLeftmost() {
   129  			return nil
   130  		}
   131  		return errors.New("absence not proved by left path")
   132  
   133  	} else if cmp == 0 {
   134  		return errors.New("absence disproved via first item #0")
   135  	}
   136  	if len(proof.LeftPath) == 0 {
   137  		return nil // proof ok
   138  	}
   139  	if proof.LeftPath.isRightmost() {
   140  		return nil
   141  	}
   142  
   143  	// See if any of the leaves are greater than key.
   144  	for i := 1; i < len(proof.Leaves); i++ {
   145  		leaf := proof.Leaves[i]
   146  		cmp := bytes.Compare(key, leaf.Key)
   147  		switch {
   148  		case cmp < 0:
   149  			return nil // proof ok
   150  		case cmp == 0:
   151  			return errors.New(fmt.Sprintf("absence disproved via item #%v", i))
   152  		default:
   153  			// if i == len(proof.Leaves)-1 {
   154  			// If last item, check whether
   155  			// it's the last item in the tree.
   156  
   157  			// }
   158  			continue
   159  		}
   160  	}
   161  
   162  	// It's still a valid proof if our last leaf is the rightmost child.
   163  	if proof.treeEnd {
   164  		return nil // OK!
   165  	}
   166  
   167  	// It's not a valid absence proof.
   168  	if len(proof.Leaves) < 2 {
   169  		return errors.New("absence not proved by right leaf (need another leaf?)")
   170  	}
   171  	return errors.New("absence not proved by right leaf")
   172  
   173  }
   174  
   175  // Verify that proof is valid.
   176  func (proof *RangeProof) Verify(root []byte) error {
   177  	if proof == nil {
   178  		return errors.Wrap(ErrInvalidProof, "proof is nil")
   179  	}
   180  	err := proof.verify(root)
   181  	return err
   182  }
   183  
   184  func (proof *RangeProof) verify(root []byte) (err error) {
   185  	rootHash := proof.rootHash
   186  	if rootHash == nil {
   187  		derivedHash, err := proof.computeRootHash()
   188  		if err != nil {
   189  			return err
   190  		}
   191  		rootHash = derivedHash
   192  	}
   193  	if !bytes.Equal(rootHash, root) {
   194  		return errors.Wrap(ErrInvalidRoot, "root hash doesn't match")
   195  	}
   196  	proof.rootVerified = true
   197  	return nil
   198  }
   199  
   200  // ComputeRootHash computes the root hash with leaves.
   201  // Returns nil if error or proof is nil.
   202  // Does not verify the root hash.
   203  func (proof *RangeProof) ComputeRootHash() []byte {
   204  	if proof == nil {
   205  		return nil
   206  	}
   207  	rootHash, _ := proof.computeRootHash()
   208  	return rootHash
   209  }
   210  
   211  func (proof *RangeProof) computeRootHash() (rootHash []byte, err error) {
   212  	rootHash, treeEnd, err := proof._computeRootHash()
   213  	if err == nil {
   214  		proof.rootHash = rootHash // memoize
   215  		proof.treeEnd = treeEnd   // memoize
   216  	}
   217  	return rootHash, err
   218  }
   219  
   220  func (proof *RangeProof) _computeRootHash() (rootHash []byte, treeEnd bool, err error) {
   221  	if len(proof.Leaves) == 0 {
   222  		return nil, false, errors.Wrap(ErrInvalidProof, "no leaves")
   223  	}
   224  	if len(proof.InnerNodes)+1 != len(proof.Leaves) {
   225  		return nil, false, errors.Wrap(ErrInvalidProof, "InnerNodes vs Leaves length mismatch, leaves should be 1 more.")
   226  	}
   227  
   228  	// Start from the left path and prove each leaf.
   229  
   230  	// shared across recursive calls
   231  	var leaves = proof.Leaves
   232  	var innersq = proof.InnerNodes
   233  	var COMPUTEHASH func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error)
   234  
   235  	// rightmost: is the root a rightmost child of the tree?
   236  	// treeEnd: true iff the last leaf is the last item of the tree.
   237  	// Returns the (possibly intermediate, possibly root) hash.
   238  	COMPUTEHASH = func(path PathToLeaf, rightmost bool) (hash []byte, treeEnd bool, done bool, err error) {
   239  
   240  		// Pop next leaf.
   241  		nleaf, rleaves := leaves[0], leaves[1:]
   242  		leaves = rleaves
   243  
   244  		// Compute hash.
   245  		hash = (pathWithLeaf{
   246  			Path: path,
   247  			Leaf: nleaf,
   248  		}).computeRootHash()
   249  
   250  		// If we don't have any leaves left, we're done.
   251  		if len(leaves) == 0 {
   252  			rightmost = rightmost && path.isRightmost()
   253  			return hash, rightmost, true, nil
   254  		}
   255  
   256  		// Prove along path (until we run out of leaves).
   257  		for len(path) > 0 {
   258  
   259  			// Drop the leaf-most (last-most) inner nodes from path
   260  			// until we encounter one with a left hash.
   261  			// We assume that the left side is already verified.
   262  			// rpath: rest of path
   263  			// lpath: last path item
   264  			rpath, lpath := path[:len(path)-1], path[len(path)-1]
   265  			path = rpath
   266  			if len(lpath.Right) == 0 {
   267  				continue
   268  			}
   269  
   270  			// Pop next inners, a PathToLeaf (e.g. []ProofInnerNode).
   271  			inners, rinnersq := innersq[0], innersq[1:]
   272  			innersq = rinnersq
   273  
   274  			// Recursively verify inners against remaining leaves.
   275  			derivedRoot, treeEnd, done, err := COMPUTEHASH(inners, rightmost && rpath.isRightmost())
   276  			if err != nil {
   277  				return nil, treeEnd, false, errors.Wrap(err, "recursive COMPUTEHASH call")
   278  			}
   279  			if !bytes.Equal(derivedRoot, lpath.Right) {
   280  				return nil, treeEnd, false, errors.Wrapf(ErrInvalidRoot, "intermediate root hash %X doesn't match, got %X", lpath.Right, derivedRoot)
   281  			}
   282  			if done {
   283  				return hash, treeEnd, true, nil
   284  			}
   285  		}
   286  
   287  		// We're not done yet (leaves left over). No error, not done either.
   288  		// Technically if rightmost, we know there's an error "left over leaves
   289  		// -- malformed proof", but we return that at the top level, below.
   290  		return hash, false, false, nil
   291  	}
   292  
   293  	// Verify!
   294  	path := proof.LeftPath
   295  	rootHash, treeEnd, done, err := COMPUTEHASH(path, true)
   296  	if err != nil {
   297  		return nil, treeEnd, errors.Wrap(err, "root COMPUTEHASH call")
   298  	} else if !done {
   299  		return nil, treeEnd, errors.Wrap(ErrInvalidProof, "left over leaves -- malformed proof")
   300  	}
   301  
   302  	// Ok!
   303  	return rootHash, treeEnd, nil
   304  }
   305  
   306  // keyStart is inclusive and keyEnd is exclusive.
   307  // If keyStart or keyEnd don't exist, the leaf before keyStart
   308  // or after keyEnd will also be included, but not be included in values.
   309  // If keyEnd-1 exists, no later leaves will be included.
   310  // If keyStart >= keyEnd and both not nil, panics.
   311  // Limit is never exceeded.
   312  func (t *ImmutableTree) getRangeProof(keyStart, keyEnd []byte, limit int) (proof *RangeProof, keys, values [][]byte, err error) {
   313  	if keyStart != nil && keyEnd != nil && bytes.Compare(keyStart, keyEnd) >= 0 {
   314  		panic("if keyStart and keyEnd are present, need keyStart < keyEnd.")
   315  	}
   316  	if limit < 0 {
   317  		panic("limit must be greater or equal to 0 -- 0 means no limit")
   318  	}
   319  	if t.root == nil {
   320  		return nil, nil, nil, nil
   321  	}
   322  	t.root.hashWithCount() // Ensure that all hashes are calculated.
   323  
   324  	// Get the first key/value pair proof, which provides us with the left key.
   325  	path, left, err := t.root.PathToLeaf(t, keyStart)
   326  	if err != nil {
   327  		// Key doesn't exist, but instead we got the prev leaf (or the
   328  		// first or last leaf), which provides proof of absence).
   329  		err = nil
   330  	}
   331  	startOK := keyStart == nil || bytes.Compare(keyStart, left.key) <= 0
   332  	endOK := keyEnd == nil || bytes.Compare(left.key, keyEnd) < 0
   333  	// If left.key is in range, add it to key/values.
   334  	if startOK && endOK {
   335  		keys = append(keys, left.key) // == keyStart
   336  		values = append(values, left.value)
   337  	}
   338  	// Either way, add to proof leaves.
   339  	var leaves = []ProofLeafNode{
   340  		{
   341  			Key:       left.key,
   342  			ValueHash: tmhash.Sum(left.value),
   343  			Version:   left.version,
   344  		},
   345  	}
   346  
   347  	// 1: Special case if limit is 1.
   348  	// 2: Special case if keyEnd is left.key+1.
   349  	_stop := false
   350  	if limit == 1 {
   351  		_stop = true // case 1
   352  	} else if keyEnd != nil && bytes.Compare(cpIncr(left.key), keyEnd) >= 0 {
   353  		_stop = true // case 2
   354  	}
   355  	if _stop {
   356  		return &RangeProof{
   357  			LeftPath: path,
   358  			Leaves:   leaves,
   359  		}, keys, values, nil
   360  	}
   361  
   362  	// Get the key after left.key to iterate from.
   363  	afterLeft := cpIncr(left.key)
   364  
   365  	// Traverse starting from afterLeft, until keyEnd or the next leaf
   366  	// after keyEnd.
   367  	var allPathToLeafs = []PathToLeaf(nil)
   368  	var currentPathToLeaf = PathToLeaf(nil)
   369  	var leafCount = 1 // from left above.
   370  	var pathCount = 0
   371  
   372  	t.root.traverseInRange(t, afterLeft, nil, true, false, 0, false,
   373  		func(node *Node, depth uint8) (stop bool) {
   374  
   375  			// Track when we diverge from path, or when we've exhausted path,
   376  			// since the first allPathToLeafs shouldn't include it.
   377  			if pathCount != -1 {
   378  				if len(path) <= pathCount {
   379  					// We're done with path counting.
   380  					pathCount = -1
   381  				} else {
   382  					pn := path[pathCount]
   383  					if pn.Height != node.height ||
   384  						pn.Left != nil && !bytes.Equal(pn.Left, node.leftHash) ||
   385  						pn.Right != nil && !bytes.Equal(pn.Right, node.rightHash) {
   386  
   387  						// We've diverged, so start appending to allPathToLeaf.
   388  						pathCount = -1
   389  					} else {
   390  						pathCount++
   391  					}
   392  				}
   393  			}
   394  
   395  			if node.height == 0 { // Leaf node
   396  				// Append all paths that we tracked so far to get to this leaf node.
   397  				allPathToLeafs = append(allPathToLeafs, currentPathToLeaf)
   398  				// Start a new one to track as we traverse the tree.
   399  				currentPathToLeaf = PathToLeaf(nil)
   400  				// Append leaf to leaves.
   401  				leaves = append(leaves, ProofLeafNode{
   402  					Key:       node.key,
   403  					ValueHash: tmhash.Sum(node.value),
   404  					Version:   node.version,
   405  				})
   406  				leafCount++
   407  				// Maybe terminate because we found enough leaves.
   408  				if limit > 0 && limit <= leafCount {
   409  					return true
   410  				}
   411  				// Terminate if we've found keyEnd or after.
   412  				if keyEnd != nil && bytes.Compare(node.key, keyEnd) >= 0 {
   413  					return true
   414  				}
   415  				// Value is in range, append to keys and values.
   416  				keys = append(keys, node.key)
   417  				values = append(values, node.value)
   418  				// Terminate if we've found keyEnd-1 or after.
   419  				// We don't want to fetch any leaves for it.
   420  				if keyEnd != nil && bytes.Compare(cpIncr(node.key), keyEnd) >= 0 {
   421  					return true
   422  				}
   423  
   424  			} else if pathCount < 0 { // Inner node.
   425  				// Only store if the node is not stored in currentPathToLeaf already. We track if we are
   426  				// still going through PathToLeaf using pathCount. When pathCount goes to -1, we
   427  				// start storing the other paths we took to get to the leaf nodes. Also we skip
   428  				// storing the left node, since we are traversing the tree starting from the left
   429  				// and don't need to store unnecessary info as we only need to go down the right
   430  				// path.
   431  				currentPathToLeaf = append(currentPathToLeaf, ProofInnerNode{
   432  					Height:  node.height,
   433  					Size:    node.size,
   434  					Version: node.version,
   435  					Left:    nil,
   436  					Right:   node.rightHash,
   437  				})
   438  			}
   439  			return false
   440  		},
   441  	)
   442  
   443  	return &RangeProof{
   444  		LeftPath:   path,
   445  		InnerNodes: allPathToLeafs,
   446  		Leaves:     leaves,
   447  	}, keys, values, nil
   448  }
   449  
   450  //----------------------------------------
   451  
   452  // GetWithProof gets the value under the key if it exists, or returns nil.
   453  // A proof of existence or absence is returned alongside the value.
   454  func (t *ImmutableTree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error) {
   455  	proof, _, values, err := t.getRangeProof(key, cpIncr(key), 2)
   456  	if err != nil {
   457  		return nil, nil, errors.Wrap(err, "constructing range proof")
   458  	}
   459  	if len(values) > 0 && bytes.Equal(proof.Leaves[0].Key, key) {
   460  		return values[0], proof, nil
   461  	}
   462  	return nil, proof, nil
   463  }
   464  
   465  // GetRangeWithProof gets key/value pairs within the specified range and limit.
   466  func (t *ImmutableTree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error) {
   467  	proof, keys, values, err = t.getRangeProof(startKey, endKey, limit)
   468  	return
   469  }
   470  
   471  // GetVersionedWithProof gets the value under the key at the specified version
   472  // if it exists, or returns nil.
   473  func (tree *MutableTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error) {
   474  	if tree.versions.Get(version) {
   475  		t, err := tree.GetImmutable(version)
   476  		if err != nil {
   477  			return nil, nil, err
   478  		}
   479  
   480  		return t.GetWithProof(key)
   481  	}
   482  	return nil, nil, errors.Wrap(ErrVersionDoesNotExist, "")
   483  }
   484  
   485  // GetVersionedRangeWithProof gets key/value pairs within the specified range
   486  // and limit.
   487  func (tree *MutableTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) (
   488  	keys, values [][]byte, proof *RangeProof, err error) {
   489  
   490  	if tree.versions.Get(version) {
   491  		t, err := tree.GetImmutable(version)
   492  		if err != nil {
   493  			return nil, nil, nil, err
   494  		}
   495  		return t.GetRangeWithProof(startKey, endKey, limit)
   496  	}
   497  	return nil, nil, nil, errors.Wrap(ErrVersionDoesNotExist, "")
   498  }