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)