github.com/decred/dcrlnd@v0.7.6/chainntnfs/chainscannotify/csnotify_dev.go (about)

     1  //go:build dev
     2  // +build dev
     3  
     4  package csnotify
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/decred/dcrd/chaincfg/chainhash"
    11  	"github.com/decred/dcrlnd/chainntnfs"
    12  )
    13  
    14  // TODO(decred): Determine if the generateBlocks is needed.
    15  //
    16  // UnsafeStart starts the notifier with a specified best height and optional
    17  // best hash. Its bestBlock and txNotifier are initialized with bestHeight and
    18  // optionally bestHash. The parameter generateBlocks is necessary for the
    19  // dcrd notifier to ensure we drain all notifications up to syncHeight,
    20  // since if they are generated ahead of UnsafeStart the chainConn may start up
    21  // with an outdated best block and miss sending ntfns. Used for testing.
    22  func (n *ChainscanNotifier) UnsafeStart(bestHeight int64, bestHash *chainhash.Hash,
    23  	syncHeight int64, generateBlocks func() error) error {
    24  
    25  	n.txNotifier = chainntnfs.NewTxNotifier(
    26  		uint32(bestHeight), chainntnfs.ReorgSafetyLimit,
    27  		n.confirmHintCache, n.spendHintCache, n.chainParams,
    28  	)
    29  
    30  	runAndLogOnError(n.ctx, n.chainConn.c.Run, "chainConn")
    31  	runAndLogOnError(n.ctx, n.tipWatcher.Run, "tipWatcher")
    32  	runAndLogOnError(n.ctx, n.historical.Run, "historical")
    33  
    34  	n.chainEvents = n.tipWatcher.ChainEvents(n.ctx)
    35  
    36  	n.wg.Add(1)
    37  	go n.handleChainEvents()
    38  
    39  	if generateBlocks != nil {
    40  		// Ensure no block notifications are pending when we start the
    41  		// notification dispatcher goroutine.
    42  
    43  		// First generate the blocks, then drain the notifications
    44  		// for the generated blocks.
    45  		if err := generateBlocks(); err != nil {
    46  			return err
    47  		}
    48  
    49  		timeout := time.After(60 * time.Second)
    50  	loop:
    51  		for {
    52  			select {
    53  			case ntfn := <-n.chainUpdates:
    54  				if int64(ntfn.height) >= syncHeight {
    55  					break loop
    56  				}
    57  			case <-timeout:
    58  				return fmt.Errorf("unable to catch up to height %d",
    59  					syncHeight)
    60  			}
    61  		}
    62  	}
    63  
    64  	// Run notificationDispatcher after setting the notifier's best block
    65  	// to avoid a race condition.
    66  	n.bestBlock = chainntnfs.BlockEpoch{
    67  		Height: int32(bestHeight), Hash: bestHash,
    68  	}
    69  	if bestHash == nil {
    70  		hash, err := n.chainConn.GetBlockHash(int64(bestHeight))
    71  		if err != nil {
    72  			return err
    73  		}
    74  		n.bestBlock.Hash = hash
    75  	}
    76  
    77  	n.wg.Add(1)
    78  	go n.notificationDispatcher()
    79  
    80  	return nil
    81  }