lnd/witness_beacon.go
Joost Jager 1a80a1e540
witness_beacon: do not look up invoice preimages
This commit isolates preimages of forwarded htlcs from invoice
preimages. The reason to do this is to prevent the incoming contest
resolver from settling exit hop htlcs for which the invoice isn't marked
as settled.
2019-05-15 14:41:58 +02:00

124 lines
3.2 KiB
Go

package lnd
import (
"sync"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/lntypes"
)
// preimageSubscriber reprints an active subscription to be notified once the
// daemon discovers new preimages, either on chain or off-chain.
type preimageSubscriber struct {
updateChan chan lntypes.Preimage
quit chan struct{}
}
// preimageBeacon is an implementation of the contractcourt.WitnessBeacon
// interface, and the lnwallet.PreimageCache interface. This implementation is
// concerned with a single witness type: sha256 hahsh preimages.
type preimageBeacon struct {
sync.RWMutex
wCache *channeldb.WitnessCache
clientCounter uint64
subscribers map[uint64]*preimageSubscriber
}
// SubscribeUpdates returns a channel that will be sent upon *each* time a new
// preimage is discovered.
func (p *preimageBeacon) SubscribeUpdates() *contractcourt.WitnessSubscription {
p.Lock()
defer p.Unlock()
clientID := p.clientCounter
client := &preimageSubscriber{
updateChan: make(chan lntypes.Preimage, 10),
quit: make(chan struct{}),
}
p.subscribers[p.clientCounter] = client
p.clientCounter++
srvrLog.Debugf("Creating new witness beacon subscriber, id=%v",
p.clientCounter)
return &contractcourt.WitnessSubscription{
WitnessUpdates: client.updateChan,
CancelSubscription: func() {
p.Lock()
defer p.Unlock()
delete(p.subscribers, clientID)
close(client.quit)
},
}
}
// LookupPreImage attempts to lookup a preimage in the global cache. True is
// returned for the second argument if the preimage is found.
func (p *preimageBeacon) LookupPreimage(
payHash lntypes.Hash) (lntypes.Preimage, bool) {
p.RLock()
defer p.RUnlock()
// Otherwise, we'll perform a final check using the witness cache.
preimage, err := p.wCache.LookupSha256Witness(payHash)
if err != nil {
ltndLog.Errorf("Unable to lookup witness: %v", err)
return lntypes.Preimage{}, false
}
return preimage, true
}
// AddPreimages adds a batch of newly discovered preimages to the global cache,
// and also signals any subscribers of the newly discovered witness.
func (p *preimageBeacon) AddPreimages(preimages ...lntypes.Preimage) error {
// Exit early if no preimages are presented.
if len(preimages) == 0 {
return nil
}
// Copy the preimages to ensure the backing area can't be modified by
// the caller when delivering notifications.
preimageCopies := make([]lntypes.Preimage, 0, len(preimages))
for _, preimage := range preimages {
srvrLog.Infof("Adding preimage=%v to witness cache", preimage)
preimageCopies = append(preimageCopies, preimage)
}
// First, we'll add the witness to the decaying witness cache.
err := p.wCache.AddSha256Witnesses(preimages...)
if err != nil {
return err
}
p.Lock()
defer p.Unlock()
// With the preimage added to our state, we'll now send a new
// notification to all subscribers.
for _, client := range p.subscribers {
go func(c *preimageSubscriber) {
for _, preimage := range preimageCopies {
select {
case c.updateChan <- preimage:
case <-c.quit:
return
}
}
}(client)
}
return nil
}
var _ contractcourt.WitnessBeacon = (*preimageBeacon)(nil)