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 }