github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/trie/iterator.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package trie 18 19 import ( 20 "bytes" 21 "container/heap" 22 "errors" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/ethdb" 26 ) 27 28 // Iterator is a key-value trie iterator that traverses a Trie. 29 type Iterator struct { 30 nodeIt NodeIterator 31 32 Key []byte // Current data key on which the iterator is positioned on 33 Value []byte // Current data value on which the iterator is positioned on 34 Err error 35 } 36 37 // NewIterator creates a new key-value iterator from a node iterator. 38 // Note that the value returned by the iterator is raw. If the content is encoded 39 // (e.g. storage value is RLP-encoded), it's caller's duty to decode it. 40 func NewIterator(it NodeIterator) *Iterator { 41 return &Iterator{ 42 nodeIt: it, 43 } 44 } 45 46 // Next moves the iterator forward one key-value entry. 47 func (it *Iterator) Next() bool { 48 for it.nodeIt.Next(true) { 49 if it.nodeIt.Leaf() { 50 it.Key = it.nodeIt.LeafKey() 51 it.Value = it.nodeIt.LeafBlob() 52 return true 53 } 54 } 55 it.Key = nil 56 it.Value = nil 57 it.Err = it.nodeIt.Error() 58 return false 59 } 60 61 // Prove generates the Merkle proof for the leaf node the iterator is currently 62 // positioned on. 63 func (it *Iterator) Prove() [][]byte { 64 return it.nodeIt.LeafProof() 65 } 66 67 // NodeIterator is an iterator to traverse the trie pre-order. 68 type NodeIterator interface { 69 // Next moves the iterator to the next node. If the parameter is false, any child 70 // nodes will be skipped. 71 Next(bool) bool 72 73 // Error returns the error status of the iterator. 74 Error() error 75 76 // Hash returns the hash of the current node. 77 Hash() common.Hash 78 79 // Parent returns the hash of the parent of the current node. The hash may be the one 80 // grandparent if the immediate parent is an internal node with no hash. 81 Parent() common.Hash 82 83 // Path returns the hex-encoded path to the current node. 84 // Callers must not retain references to the return value after calling Next. 85 // For leaf nodes, the last element of the path is the 'terminator symbol' 0x10. 86 Path() []byte 87 88 // NodeBlob returns the rlp-encoded value of the current iterated node. 89 // If the node is an embedded node in its parent, nil is returned then. 90 NodeBlob() []byte 91 92 // Leaf returns true iff the current node is a leaf node. 93 Leaf() bool 94 95 // LeafKey returns the key of the leaf. The method panics if the iterator is not 96 // positioned at a leaf. Callers must not retain references to the value after 97 // calling Next. 98 LeafKey() []byte 99 100 // LeafBlob returns the content of the leaf. The method panics if the iterator 101 // is not positioned at a leaf. Callers must not retain references to the value 102 // after calling Next. 103 LeafBlob() []byte 104 105 // LeafProof returns the Merkle proof of the leaf. The method panics if the 106 // iterator is not positioned at a leaf. Callers must not retain references 107 // to the value after calling Next. 108 LeafProof() [][]byte 109 110 // AddResolver sets an intermediate database to use for looking up trie nodes 111 // before reaching into the real persistent layer. 112 // 113 // This is not required for normal operation, rather is an optimization for 114 // cases where trie nodes can be recovered from some external mechanism without 115 // reading from disk. In those cases, this resolver allows short circuiting 116 // accesses and returning them from memory. 117 // 118 // Before adding a similar mechanism to any other place in Geth, consider 119 // making trie.Database an interface and wrapping at that level. It's a huge 120 // refactor, but it could be worth it if another occurrence arises. 121 AddResolver(ethdb.KeyValueReader) 122 } 123 124 // nodeIteratorState represents the iteration state at one particular node of the 125 // trie, which can be resumed at a later invocation. 126 type nodeIteratorState struct { 127 hash common.Hash // Hash of the node being iterated (nil if not standalone) 128 node node // Trie node being iterated 129 parent common.Hash // Hash of the first full ancestor node (nil if current is the root) 130 index int // Child to be processed next 131 pathlen int // Length of the path to this node 132 } 133 134 type nodeIterator struct { 135 trie *Trie // Trie being iterated 136 stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state 137 path []byte // Path to the current node 138 err error // Failure set in case of an internal error in the iterator 139 140 resolver ethdb.KeyValueReader // Optional intermediate resolver above the disk layer 141 } 142 143 // errIteratorEnd is stored in nodeIterator.err when iteration is done. 144 var errIteratorEnd = errors.New("end of iteration") 145 146 // seekError is stored in nodeIterator.err if the initial seek has failed. 147 type seekError struct { 148 key []byte 149 err error 150 } 151 152 func (e seekError) Error() string { 153 return "seek error: " + e.err.Error() 154 } 155 156 func newNodeIterator(trie *Trie, start []byte) NodeIterator { 157 if trie.Hash() == emptyRoot { 158 return &nodeIterator{ 159 trie: trie, 160 err: errIteratorEnd, 161 } 162 } 163 it := &nodeIterator{trie: trie} 164 it.err = it.seek(start) 165 return it 166 } 167 168 func (it *nodeIterator) AddResolver(resolver ethdb.KeyValueReader) { 169 it.resolver = resolver 170 } 171 172 func (it *nodeIterator) Hash() common.Hash { 173 if len(it.stack) == 0 { 174 return common.Hash{} 175 } 176 return it.stack[len(it.stack)-1].hash 177 } 178 179 func (it *nodeIterator) Parent() common.Hash { 180 if len(it.stack) == 0 { 181 return common.Hash{} 182 } 183 return it.stack[len(it.stack)-1].parent 184 } 185 186 func (it *nodeIterator) Leaf() bool { 187 return hasTerm(it.path) 188 } 189 190 func (it *nodeIterator) LeafKey() []byte { 191 if len(it.stack) > 0 { 192 if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { 193 return hexToKeybytes(it.path) 194 } 195 } 196 panic("not at leaf") 197 } 198 199 func (it *nodeIterator) LeafBlob() []byte { 200 if len(it.stack) > 0 { 201 if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { 202 return node 203 } 204 } 205 panic("not at leaf") 206 } 207 208 func (it *nodeIterator) LeafProof() [][]byte { 209 if len(it.stack) > 0 { 210 if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { 211 hasher := newHasher(false) 212 defer returnHasherToPool(hasher) 213 proofs := make([][]byte, 0, len(it.stack)) 214 215 for i, item := range it.stack[:len(it.stack)-1] { 216 // Gather nodes that end up as hash nodes (or the root) 217 node, hashed := hasher.proofHash(item.node) 218 if _, ok := hashed.(hashNode); ok || i == 0 { 219 proofs = append(proofs, nodeToBytes(node)) 220 } 221 } 222 return proofs 223 } 224 } 225 panic("not at leaf") 226 } 227 228 func (it *nodeIterator) Path() []byte { 229 return it.path 230 } 231 232 func (it *nodeIterator) NodeBlob() []byte { 233 if it.Hash() == (common.Hash{}) { 234 return nil // skip the non-standalone node 235 } 236 blob, err := it.resolveBlob(it.Hash().Bytes(), it.Path()) 237 if err != nil { 238 it.err = err 239 return nil 240 } 241 return blob 242 } 243 244 func (it *nodeIterator) Error() error { 245 if it.err == errIteratorEnd { 246 return nil 247 } 248 if seek, ok := it.err.(seekError); ok { 249 return seek.err 250 } 251 return it.err 252 } 253 254 // Next moves the iterator to the next node, returning whether there are any 255 // further nodes. In case of an internal error this method returns false and 256 // sets the Error field to the encountered failure. If `descend` is false, 257 // skips iterating over any subnodes of the current node. 258 func (it *nodeIterator) Next(descend bool) bool { 259 if it.err == errIteratorEnd { 260 return false 261 } 262 if seek, ok := it.err.(seekError); ok { 263 if it.err = it.seek(seek.key); it.err != nil { 264 return false 265 } 266 } 267 // Otherwise step forward with the iterator and report any errors. 268 state, parentIndex, path, err := it.peek(descend) 269 it.err = err 270 if it.err != nil { 271 return false 272 } 273 it.push(state, parentIndex, path) 274 return true 275 } 276 277 func (it *nodeIterator) seek(prefix []byte) error { 278 // The path we're looking for is the hex encoded key without terminator. 279 key := keybytesToHex(prefix) 280 key = key[:len(key)-1] 281 // Move forward until we're just before the closest match to key. 282 for { 283 state, parentIndex, path, err := it.peekSeek(key) 284 if err == errIteratorEnd { 285 return errIteratorEnd 286 } else if err != nil { 287 return seekError{prefix, err} 288 } else if bytes.Compare(path, key) >= 0 { 289 return nil 290 } 291 it.push(state, parentIndex, path) 292 } 293 } 294 295 // init initializes the iterator. 296 func (it *nodeIterator) init() (*nodeIteratorState, error) { 297 root := it.trie.Hash() 298 state := &nodeIteratorState{node: it.trie.root, index: -1} 299 if root != emptyRoot { 300 state.hash = root 301 } 302 return state, state.resolve(it, nil) 303 } 304 305 // peek creates the next state of the iterator. 306 func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, error) { 307 // Initialize the iterator if we've just started. 308 if len(it.stack) == 0 { 309 state, err := it.init() 310 return state, nil, nil, err 311 } 312 if !descend { 313 // If we're skipping children, pop the current node first 314 it.pop() 315 } 316 317 // Continue iteration to the next child 318 for len(it.stack) > 0 { 319 parent := it.stack[len(it.stack)-1] 320 ancestor := parent.hash 321 if (ancestor == common.Hash{}) { 322 ancestor = parent.parent 323 } 324 state, path, ok := it.nextChild(parent, ancestor) 325 if ok { 326 if err := state.resolve(it, path); err != nil { 327 return parent, &parent.index, path, err 328 } 329 return state, &parent.index, path, nil 330 } 331 // No more child nodes, move back up. 332 it.pop() 333 } 334 return nil, nil, nil, errIteratorEnd 335 } 336 337 // peekSeek is like peek, but it also tries to skip resolving hashes by skipping 338 // over the siblings that do not lead towards the desired seek position. 339 func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []byte, error) { 340 // Initialize the iterator if we've just started. 341 if len(it.stack) == 0 { 342 state, err := it.init() 343 return state, nil, nil, err 344 } 345 if !bytes.HasPrefix(seekKey, it.path) { 346 // If we're skipping children, pop the current node first 347 it.pop() 348 } 349 350 // Continue iteration to the next child 351 for len(it.stack) > 0 { 352 parent := it.stack[len(it.stack)-1] 353 ancestor := parent.hash 354 if (ancestor == common.Hash{}) { 355 ancestor = parent.parent 356 } 357 state, path, ok := it.nextChildAt(parent, ancestor, seekKey) 358 if ok { 359 if err := state.resolve(it, path); err != nil { 360 return parent, &parent.index, path, err 361 } 362 return state, &parent.index, path, nil 363 } 364 // No more child nodes, move back up. 365 it.pop() 366 } 367 return nil, nil, nil, errIteratorEnd 368 } 369 370 func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) { 371 if it.resolver != nil { 372 if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 { 373 if resolved, err := decodeNode(hash, blob); err == nil { 374 return resolved, nil 375 } 376 } 377 } 378 resolved, err := it.trie.resolveHash(hash, path) 379 return resolved, err 380 } 381 382 func (it *nodeIterator) resolveBlob(hash hashNode, path []byte) ([]byte, error) { 383 if it.resolver != nil { 384 if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 { 385 return blob, nil 386 } 387 } 388 return it.trie.resolveBlob(hash, path) 389 } 390 391 func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error { 392 if hash, ok := st.node.(hashNode); ok { 393 resolved, err := it.resolveHash(hash, path) 394 if err != nil { 395 return err 396 } 397 st.node = resolved 398 st.hash = common.BytesToHash(hash) 399 } 400 return nil 401 } 402 403 func findChild(n *fullNode, index int, path []byte, ancestor common.Hash) (node, *nodeIteratorState, []byte, int) { 404 var ( 405 child node 406 state *nodeIteratorState 407 childPath []byte 408 ) 409 for ; index < len(n.Children); index++ { 410 if n.Children[index] != nil { 411 child = n.Children[index] 412 hash, _ := child.cache() 413 state = &nodeIteratorState{ 414 hash: common.BytesToHash(hash), 415 node: child, 416 parent: ancestor, 417 index: -1, 418 pathlen: len(path), 419 } 420 childPath = append(childPath, path...) 421 childPath = append(childPath, byte(index)) 422 return child, state, childPath, index 423 } 424 } 425 return nil, nil, nil, 0 426 } 427 428 func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) { 429 switch node := parent.node.(type) { 430 case *fullNode: 431 // Full node, move to the first non-nil child. 432 if child, state, path, index := findChild(node, parent.index+1, it.path, ancestor); child != nil { 433 parent.index = index - 1 434 return state, path, true 435 } 436 case *shortNode: 437 // Short node, return the pointer singleton child 438 if parent.index < 0 { 439 hash, _ := node.Val.cache() 440 state := &nodeIteratorState{ 441 hash: common.BytesToHash(hash), 442 node: node.Val, 443 parent: ancestor, 444 index: -1, 445 pathlen: len(it.path), 446 } 447 path := append(it.path, node.Key...) 448 return state, path, true 449 } 450 } 451 return parent, it.path, false 452 } 453 454 // nextChildAt is similar to nextChild, except that it targets a child as close to the 455 // target key as possible, thus skipping siblings. 456 func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.Hash, key []byte) (*nodeIteratorState, []byte, bool) { 457 switch n := parent.node.(type) { 458 case *fullNode: 459 // Full node, move to the first non-nil child before the desired key position 460 child, state, path, index := findChild(n, parent.index+1, it.path, ancestor) 461 if child == nil { 462 // No more children in this fullnode 463 return parent, it.path, false 464 } 465 // If the child we found is already past the seek position, just return it. 466 if bytes.Compare(path, key) >= 0 { 467 parent.index = index - 1 468 return state, path, true 469 } 470 // The child is before the seek position. Try advancing 471 for { 472 nextChild, nextState, nextPath, nextIndex := findChild(n, index+1, it.path, ancestor) 473 // If we run out of children, or skipped past the target, return the 474 // previous one 475 if nextChild == nil || bytes.Compare(nextPath, key) >= 0 { 476 parent.index = index - 1 477 return state, path, true 478 } 479 // We found a better child closer to the target 480 state, path, index = nextState, nextPath, nextIndex 481 } 482 case *shortNode: 483 // Short node, return the pointer singleton child 484 if parent.index < 0 { 485 hash, _ := n.Val.cache() 486 state := &nodeIteratorState{ 487 hash: common.BytesToHash(hash), 488 node: n.Val, 489 parent: ancestor, 490 index: -1, 491 pathlen: len(it.path), 492 } 493 path := append(it.path, n.Key...) 494 return state, path, true 495 } 496 } 497 return parent, it.path, false 498 } 499 500 func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []byte) { 501 it.path = path 502 it.stack = append(it.stack, state) 503 if parentIndex != nil { 504 *parentIndex++ 505 } 506 } 507 508 func (it *nodeIterator) pop() { 509 last := it.stack[len(it.stack)-1] 510 it.path = it.path[:last.pathlen] 511 it.stack[len(it.stack)-1] = nil 512 it.stack = it.stack[:len(it.stack)-1] 513 } 514 515 func compareNodes(a, b NodeIterator) int { 516 if cmp := bytes.Compare(a.Path(), b.Path()); cmp != 0 { 517 return cmp 518 } 519 if a.Leaf() && !b.Leaf() { 520 return -1 521 } else if b.Leaf() && !a.Leaf() { 522 return 1 523 } 524 if cmp := bytes.Compare(a.Hash().Bytes(), b.Hash().Bytes()); cmp != 0 { 525 return cmp 526 } 527 if a.Leaf() && b.Leaf() { 528 return bytes.Compare(a.LeafBlob(), b.LeafBlob()) 529 } 530 return 0 531 } 532 533 type differenceIterator struct { 534 a, b NodeIterator // Nodes returned are those in b - a. 535 eof bool // Indicates a has run out of elements 536 count int // Number of nodes scanned on either trie 537 } 538 539 // NewDifferenceIterator constructs a NodeIterator that iterates over elements in b that 540 // are not in a. Returns the iterator, and a pointer to an integer recording the number 541 // of nodes seen. 542 func NewDifferenceIterator(a, b NodeIterator) (NodeIterator, *int) { 543 a.Next(true) 544 it := &differenceIterator{ 545 a: a, 546 b: b, 547 } 548 return it, &it.count 549 } 550 551 func (it *differenceIterator) Hash() common.Hash { 552 return it.b.Hash() 553 } 554 555 func (it *differenceIterator) Parent() common.Hash { 556 return it.b.Parent() 557 } 558 559 func (it *differenceIterator) Leaf() bool { 560 return it.b.Leaf() 561 } 562 563 func (it *differenceIterator) LeafKey() []byte { 564 return it.b.LeafKey() 565 } 566 567 func (it *differenceIterator) LeafBlob() []byte { 568 return it.b.LeafBlob() 569 } 570 571 func (it *differenceIterator) LeafProof() [][]byte { 572 return it.b.LeafProof() 573 } 574 575 func (it *differenceIterator) Path() []byte { 576 return it.b.Path() 577 } 578 579 func (it *differenceIterator) NodeBlob() []byte { 580 return it.b.NodeBlob() 581 } 582 583 func (it *differenceIterator) AddResolver(resolver ethdb.KeyValueReader) { 584 panic("not implemented") 585 } 586 587 func (it *differenceIterator) Next(bool) bool { 588 // Invariants: 589 // - We always advance at least one element in b. 590 // - At the start of this function, a's path is lexically greater than b's. 591 if !it.b.Next(true) { 592 return false 593 } 594 it.count++ 595 596 if it.eof { 597 // a has reached eof, so we just return all elements from b 598 return true 599 } 600 601 for { 602 switch compareNodes(it.a, it.b) { 603 case -1: 604 // b jumped past a; advance a 605 if !it.a.Next(true) { 606 it.eof = true 607 return true 608 } 609 it.count++ 610 case 1: 611 // b is before a 612 return true 613 case 0: 614 // a and b are identical; skip this whole subtree if the nodes have hashes 615 hasHash := it.a.Hash() == common.Hash{} 616 if !it.b.Next(hasHash) { 617 return false 618 } 619 it.count++ 620 if !it.a.Next(hasHash) { 621 it.eof = true 622 return true 623 } 624 it.count++ 625 } 626 } 627 } 628 629 func (it *differenceIterator) Error() error { 630 if err := it.a.Error(); err != nil { 631 return err 632 } 633 return it.b.Error() 634 } 635 636 type nodeIteratorHeap []NodeIterator 637 638 func (h nodeIteratorHeap) Len() int { return len(h) } 639 func (h nodeIteratorHeap) Less(i, j int) bool { return compareNodes(h[i], h[j]) < 0 } 640 func (h nodeIteratorHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 641 func (h *nodeIteratorHeap) Push(x interface{}) { *h = append(*h, x.(NodeIterator)) } 642 func (h *nodeIteratorHeap) Pop() interface{} { 643 n := len(*h) 644 x := (*h)[n-1] 645 *h = (*h)[0 : n-1] 646 return x 647 } 648 649 type unionIterator struct { 650 items *nodeIteratorHeap // Nodes returned are the union of the ones in these iterators 651 count int // Number of nodes scanned across all tries 652 } 653 654 // NewUnionIterator constructs a NodeIterator that iterates over elements in the union 655 // of the provided NodeIterators. Returns the iterator, and a pointer to an integer 656 // recording the number of nodes visited. 657 func NewUnionIterator(iters []NodeIterator) (NodeIterator, *int) { 658 h := make(nodeIteratorHeap, len(iters)) 659 copy(h, iters) 660 heap.Init(&h) 661 662 ui := &unionIterator{items: &h} 663 return ui, &ui.count 664 } 665 666 func (it *unionIterator) Hash() common.Hash { 667 return (*it.items)[0].Hash() 668 } 669 670 func (it *unionIterator) Parent() common.Hash { 671 return (*it.items)[0].Parent() 672 } 673 674 func (it *unionIterator) Leaf() bool { 675 return (*it.items)[0].Leaf() 676 } 677 678 func (it *unionIterator) LeafKey() []byte { 679 return (*it.items)[0].LeafKey() 680 } 681 682 func (it *unionIterator) LeafBlob() []byte { 683 return (*it.items)[0].LeafBlob() 684 } 685 686 func (it *unionIterator) LeafProof() [][]byte { 687 return (*it.items)[0].LeafProof() 688 } 689 690 func (it *unionIterator) Path() []byte { 691 return (*it.items)[0].Path() 692 } 693 694 func (it *unionIterator) NodeBlob() []byte { 695 return (*it.items)[0].NodeBlob() 696 } 697 698 func (it *unionIterator) AddResolver(resolver ethdb.KeyValueReader) { 699 panic("not implemented") 700 } 701 702 // Next returns the next node in the union of tries being iterated over. 703 // 704 // It does this by maintaining a heap of iterators, sorted by the iteration 705 // order of their next elements, with one entry for each source trie. Each 706 // time Next() is called, it takes the least element from the heap to return, 707 // advancing any other iterators that also point to that same element. These 708 // iterators are called with descend=false, since we know that any nodes under 709 // these nodes will also be duplicates, found in the currently selected iterator. 710 // Whenever an iterator is advanced, it is pushed back into the heap if it still 711 // has elements remaining. 712 // 713 // In the case that descend=false - eg, we're asked to ignore all subnodes of the 714 // current node - we also advance any iterators in the heap that have the current 715 // path as a prefix. 716 func (it *unionIterator) Next(descend bool) bool { 717 if len(*it.items) == 0 { 718 return false 719 } 720 721 // Get the next key from the union 722 least := heap.Pop(it.items).(NodeIterator) 723 724 // Skip over other nodes as long as they're identical, or, if we're not descending, as 725 // long as they have the same prefix as the current node. 726 for len(*it.items) > 0 && ((!descend && bytes.HasPrefix((*it.items)[0].Path(), least.Path())) || compareNodes(least, (*it.items)[0]) == 0) { 727 skipped := heap.Pop(it.items).(NodeIterator) 728 // Skip the whole subtree if the nodes have hashes; otherwise just skip this node 729 if skipped.Next(skipped.Hash() == common.Hash{}) { 730 it.count++ 731 // If there are more elements, push the iterator back on the heap 732 heap.Push(it.items, skipped) 733 } 734 } 735 if least.Next(descend) { 736 it.count++ 737 heap.Push(it.items, least) 738 } 739 return len(*it.items) > 0 740 } 741 742 func (it *unionIterator) Error() error { 743 for i := 0; i < len(*it.items); i++ { 744 if err := (*it.items)[i].Error(); err != nil { 745 return err 746 } 747 } 748 return nil 749 }