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