github.com/decred/dcrlnd@v0.7.6/witness_beacon.go (about) 1 package dcrlnd 2 3 import ( 4 "sync" 5 6 "github.com/decred/dcrlnd/channeldb" 7 "github.com/decred/dcrlnd/contractcourt" 8 "github.com/decred/dcrlnd/lntypes" 9 ) 10 11 // preimageSubscriber reprints an active subscription to be notified once the 12 // daemon discovers new preimages, either on chain or off-chain. 13 type preimageSubscriber struct { 14 updateChan chan lntypes.Preimage 15 16 quit chan struct{} 17 } 18 19 // preimageBeacon is an implementation of the contractcourt.WitnessBeacon 20 // interface, and the lnwallet.PreimageCache interface. This implementation is 21 // concerned with a single witness type: sha256 hahsh preimages. 22 type preimageBeacon struct { 23 sync.RWMutex 24 25 wCache *channeldb.WitnessCache 26 27 clientCounter uint64 28 subscribers map[uint64]*preimageSubscriber 29 } 30 31 // SubscribeUpdates returns a channel that will be sent upon *each* time a new 32 // preimage is discovered. 33 func (p *preimageBeacon) SubscribeUpdates() *contractcourt.WitnessSubscription { 34 p.Lock() 35 defer p.Unlock() 36 37 clientID := p.clientCounter 38 client := &preimageSubscriber{ 39 updateChan: make(chan lntypes.Preimage, 10), 40 quit: make(chan struct{}), 41 } 42 43 p.subscribers[p.clientCounter] = client 44 45 p.clientCounter++ 46 47 srvrLog.Debugf("Creating new witness beacon subscriber, id=%v", 48 p.clientCounter) 49 50 return &contractcourt.WitnessSubscription{ 51 WitnessUpdates: client.updateChan, 52 CancelSubscription: func() { 53 p.Lock() 54 defer p.Unlock() 55 56 delete(p.subscribers, clientID) 57 58 close(client.quit) 59 }, 60 } 61 } 62 63 // LookupPreImage attempts to lookup a preimage in the global cache. True is 64 // returned for the second argument if the preimage is found. 65 func (p *preimageBeacon) LookupPreimage( 66 payHash lntypes.Hash) (lntypes.Preimage, bool) { 67 68 p.RLock() 69 defer p.RUnlock() 70 71 // Otherwise, we'll perform a final check using the witness cache. 72 preimage, err := p.wCache.LookupSha256Witness(payHash) 73 if err != nil { 74 ltndLog.Errorf("Unable to lookup witness: %v", err) 75 return lntypes.Preimage{}, false 76 } 77 78 return preimage, true 79 } 80 81 // AddPreimages adds a batch of newly discovered preimages to the global cache, 82 // and also signals any subscribers of the newly discovered witness. 83 func (p *preimageBeacon) AddPreimages(preimages ...lntypes.Preimage) error { 84 // Exit early if no preimages are presented. 85 if len(preimages) == 0 { 86 return nil 87 } 88 89 // Copy the preimages to ensure the backing area can't be modified by 90 // the caller when delivering notifications. 91 preimageCopies := make([]lntypes.Preimage, 0, len(preimages)) 92 for _, preimage := range preimages { 93 srvrLog.Infof("Adding preimage=%v to witness cache", preimage) 94 preimageCopies = append(preimageCopies, preimage) 95 } 96 97 // First, we'll add the witness to the decaying witness cache. 98 err := p.wCache.AddSha256Witnesses(preimages...) 99 if err != nil { 100 return err 101 } 102 103 p.Lock() 104 defer p.Unlock() 105 106 // With the preimage added to our state, we'll now send a new 107 // notification to all subscribers. 108 for _, client := range p.subscribers { 109 go func(c *preimageSubscriber) { 110 for _, preimage := range preimageCopies { 111 select { 112 case c.updateChan <- preimage: 113 case <-c.quit: 114 return 115 } 116 } 117 }(client) 118 } 119 120 return nil 121 } 122 123 var _ contractcourt.WitnessBeacon = (*preimageBeacon)(nil)