@@ -198,8 +198,8 @@ func (s *Store) MainChainTip(dbtx walletdb.ReadTx) (chainhash.Hash, int32) {
198198// If the block is already inserted and part of the main chain, an errors.Exist
199199// error is returned.
200200//
201- // The main chain tip may not be extended unless compact filters have been saved
202- // for all existing main chain blocks .
201+ // The main chain may be extended without cfilters if this block is before the
202+ // wallet birthday. If the filter is nil it will not be saved to the database .
203203func (s * Store ) ExtendMainChain (ns walletdb.ReadWriteBucket , header * wire.BlockHeader , blockHash * chainhash.Hash , f * gcs2.FilterV2 ) error {
204204 height := int32 (header .Height )
205205 if height < 1 {
@@ -266,9 +266,12 @@ func (s *Store) ExtendMainChain(ns walletdb.ReadWriteBucket, header *wire.BlockH
266266 return err
267267 }
268268
269- // Save the compact filter.
270- bcf2Key := blockcf2 .Key (& header .MerkleRoot )
271- return putRawCFilter (ns , blockHash [:], valueRawCFilter2 (bcf2Key , f .Bytes ()))
269+ // Save the compact filter if we have it.
270+ if f != nil {
271+ bcf2Key := blockcf2 .Key (& header .MerkleRoot )
272+ return putRawCFilter (ns , blockHash [:], valueRawCFilter2 (bcf2Key , f .Bytes ()))
273+ }
274+ return nil
272275}
273276
274277// ProcessedTxsBlockMarker returns the hash of the block which records the last
@@ -402,19 +405,37 @@ func (s *Store) IsMissingMainChainCFilters(dbtx walletdb.ReadTx) bool {
402405 return len (v ) != 1 || v [0 ] == 0
403406}
404407
408+ // SetMissingMainChainCFilters sets whether we have all of the main chain
409+ // cfilters. Should be used to set missing to false if the wallet birthday is
410+ // moved back in time.
411+ func (s * Store ) SetMissingMainChainCFilters (dbtx walletdb.ReadWriteTx , have bool ) error {
412+ haveB := []byte {0 }
413+ if have {
414+ haveB = []byte {1 }
415+ }
416+ err := dbtx .ReadWriteBucket (wtxmgrBucketKey ).Put (rootHaveCFilters , haveB )
417+ if err != nil {
418+ return errors .E (errors .IO , err )
419+ }
420+ return nil
421+ }
422+
405423// MissingCFiltersHeight returns the first main chain block height
406424// with a missing cfilter. Errors with NotExist when all main chain
407425// blocks record cfilters.
408- func ( s * Store ) MissingCFiltersHeight (dbtx walletdb.ReadTx ) (int32 , error ) {
426+ func MissingCFiltersHeight (dbtx walletdb.ReadTx , fromHeight int32 ) (int32 , error ) {
409427 ns := dbtx .ReadBucket (wtxmgrBucketKey )
410428 c := ns .NestedReadBucket (bucketBlocks ).ReadCursor ()
411429 defer c .Close ()
412- for k , v := c .First ( ); k != nil ; k , v = c .Next () {
430+ for k , v := c .Seek ( keyBlockRecord ( fromHeight ) ); k != nil ; k , v = c .Next () {
413431 hash := extractRawBlockRecordHash (v )
414432 _ , _ , err := fetchRawCFilter2 (ns , hash )
415- if errors .Is (err , errors .NotExist ) {
416- height := int32 (byteOrder .Uint32 (k ))
417- return height , nil
433+ if err != nil {
434+ if errors .Is (err , errors .NotExist ) {
435+ height := int32 (byteOrder .Uint32 (k ))
436+ return height , nil
437+ }
438+ return 0 , errors .E (errors .IO , err )
418439 }
419440 }
420441 return 0 , errors .E (errors .NotExist )
@@ -442,42 +463,37 @@ func (s *Store) InsertMissingCFilters(dbtx walletdb.ReadWriteTx, blockHashes []*
442463 }
443464
444465 for i , blockHash := range blockHashes {
445- // Ensure that blockHashes are ordered and that all previous cfilters in the
446- // main chain are known.
466+ // Ensure that blockHashes are ordered.
467+ header := existsBlockHeader (ns , blockHash [:])
468+ if header == nil {
469+ return errors .E (errors .NotExist , errors .Errorf ("missing header for block %v" , blockHash ))
470+ }
447471 ok := i == 0 && * blockHash == s .chainParams .GenesisHash
448- var bcf2Key [gcs2 .KeySize ]byte
449472 if ! ok {
450- header := existsBlockHeader (ns , blockHash [:])
451- if header == nil {
452- return errors .E (errors .NotExist , errors .Errorf ("missing header for block %v" , blockHash ))
453- }
454473 parentHash := extractBlockHeaderParentHash (header )
455- merkleRoot := extractBlockHeaderMerkleRoot (header )
456- merkleRootHash , err := chainhash .NewHash (merkleRoot )
457- if err != nil {
458- return errors .E (errors .Invalid , errors .Errorf ("invalid stored header %v" , blockHash ))
459- }
460- bcf2Key = blockcf2 .Key (merkleRootHash )
461- if i == 0 {
462- _ , _ , err := fetchRawCFilter2 (ns , parentHash )
463- ok = err == nil
464- } else {
465- ok = bytes .Equal (parentHash , blockHashes [i - 1 ][:])
474+ if i != 0 {
475+ if ! bytes .Equal (parentHash , blockHashes [i - 1 ][:]) {
476+ return errors .E (errors .Invalid , "block hashes are not ordered" )
477+ }
466478 }
467479 }
468- if ! ok {
469- return errors .E (errors .Invalid , "block hashes are not ordered or previous cfilters are missing" )
470- }
471480
472481 // Record cfilter for this block
473- err := putRawCFilter (ns , blockHash [:], valueRawCFilter2 (bcf2Key , filters [i ].Bytes ()))
482+ merkleRoot := extractBlockHeaderMerkleRoot (header )
483+ merkleRootHash , err := chainhash .NewHash (merkleRoot )
484+ if err != nil {
485+ return errors .E (errors .Invalid , errors .Errorf ("invalid stored header %v" , blockHash ))
486+ }
487+ bcf2Key := blockcf2 .Key (merkleRootHash )
488+ err = putRawCFilter (ns , blockHash [:], valueRawCFilter2 (bcf2Key , filters [i ].Bytes ()))
474489 if err != nil {
475490 return err
476491 }
477492 }
478493
479494 // Mark all main chain cfilters as saved if the last block hash is the main
480- // chain tip.
495+ // chain tip. Even if this is not the head block, all cfilters may be saved
496+ // at this point. The caller may need to check and set rootHaveCFilters.
481497 tip , _ := s .MainChainTip (dbtx )
482498 if bytes .Equal (tip [:], blockHashes [len (blockHashes )- 1 ][:]) {
483499 err := ns .Put (rootHaveCFilters , []byte {1 })
0 commit comments