2019-01-24 14:28:25 +01:00
|
|
|
package lnd
|
2018-01-17 05:02:25 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
2022-02-04 14:32:15 +01:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2022-11-18 12:15:22 +01:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb/models"
|
2018-01-17 05:02:25 +01:00
|
|
|
"github.com/lightningnetwork/lnd/contractcourt"
|
2022-02-04 14:32:15 +01:00
|
|
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
|
|
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
2019-01-15 11:31:22 +01:00
|
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
2022-02-04 14:32:15 +01:00
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2018-01-17 05:02:25 +01:00
|
|
|
)
|
|
|
|
|
2018-02-07 04:11:11 +01:00
|
|
|
// preimageSubscriber reprints an active subscription to be notified once the
|
2018-01-17 05:02:25 +01:00
|
|
|
// daemon discovers new preimages, either on chain or off-chain.
|
2018-02-07 04:11:11 +01:00
|
|
|
type preimageSubscriber struct {
|
2019-02-20 02:06:00 +01:00
|
|
|
updateChan chan lntypes.Preimage
|
2018-01-17 05:02:25 +01:00
|
|
|
|
|
|
|
quit chan struct{}
|
|
|
|
}
|
|
|
|
|
2022-04-13 11:16:34 +02:00
|
|
|
type witnessCache interface {
|
|
|
|
// LookupSha256Witness attempts to lookup the preimage for a sha256
|
|
|
|
// hash. If the witness isn't found, ErrNoWitnesses will be returned.
|
|
|
|
LookupSha256Witness(hash lntypes.Hash) (lntypes.Preimage, error)
|
|
|
|
|
|
|
|
// AddSha256Witnesses adds a batch of new sha256 preimages into the
|
|
|
|
// witness cache. This is an alias for AddWitnesses that uses
|
|
|
|
// Sha256HashWitness as the preimages' witness type.
|
|
|
|
AddSha256Witnesses(preimages ...lntypes.Preimage) error
|
|
|
|
}
|
|
|
|
|
2018-01-17 05:02:25 +01:00
|
|
|
// 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
|
|
|
|
|
2022-04-13 11:16:34 +02:00
|
|
|
wCache witnessCache
|
2018-01-17 05:02:25 +01:00
|
|
|
|
|
|
|
clientCounter uint64
|
2018-02-07 04:11:11 +01:00
|
|
|
subscribers map[uint64]*preimageSubscriber
|
2022-02-04 14:32:15 +01:00
|
|
|
|
|
|
|
interceptor func(htlcswitch.InterceptedForward) error
|
2018-01-17 05:02:25 +01:00
|
|
|
}
|
|
|
|
|
2022-02-04 14:32:15 +01:00
|
|
|
func newPreimageBeacon(wCache witnessCache,
|
|
|
|
interceptor func(htlcswitch.InterceptedForward) error) *preimageBeacon {
|
|
|
|
|
2022-04-13 10:19:25 +02:00
|
|
|
return &preimageBeacon{
|
|
|
|
wCache: wCache,
|
2022-02-04 14:32:15 +01:00
|
|
|
interceptor: interceptor,
|
2022-04-13 10:19:25 +02:00
|
|
|
subscribers: make(map[uint64]*preimageSubscriber),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-07 04:11:11 +01:00
|
|
|
// SubscribeUpdates returns a channel that will be sent upon *each* time a new
|
2018-01-17 05:02:25 +01:00
|
|
|
// preimage is discovered.
|
2022-02-04 14:32:15 +01:00
|
|
|
func (p *preimageBeacon) SubscribeUpdates(
|
|
|
|
chanID lnwire.ShortChannelID, htlc *channeldb.HTLC,
|
|
|
|
payload *hop.Payload,
|
|
|
|
nextHopOnionBlob []byte) (*contractcourt.WitnessSubscription, error) {
|
|
|
|
|
2018-01-17 05:02:25 +01:00
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
|
|
|
clientID := p.clientCounter
|
2018-02-07 04:11:11 +01:00
|
|
|
client := &preimageSubscriber{
|
2019-02-20 02:06:00 +01:00
|
|
|
updateChan: make(chan lntypes.Preimage, 10),
|
2018-01-17 05:02:25 +01:00
|
|
|
quit: make(chan struct{}),
|
|
|
|
}
|
|
|
|
|
|
|
|
p.subscribers[p.clientCounter] = client
|
|
|
|
|
|
|
|
p.clientCounter++
|
|
|
|
|
|
|
|
srvrLog.Debugf("Creating new witness beacon subscriber, id=%v",
|
|
|
|
p.clientCounter)
|
|
|
|
|
2022-02-04 14:32:15 +01:00
|
|
|
sub := &contractcourt.WitnessSubscription{
|
2018-01-17 05:02:25 +01:00
|
|
|
WitnessUpdates: client.updateChan,
|
2018-02-07 04:11:11 +01:00
|
|
|
CancelSubscription: func() {
|
2018-01-17 05:02:25 +01:00
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
|
|
|
delete(p.subscribers, clientID)
|
|
|
|
|
|
|
|
close(client.quit)
|
|
|
|
},
|
|
|
|
}
|
2022-02-04 14:32:15 +01:00
|
|
|
|
|
|
|
// Notify the htlc interceptor. There may be a client connected
|
|
|
|
// and willing to supply a preimage.
|
|
|
|
packet := &htlcswitch.InterceptedPacket{
|
|
|
|
Hash: htlc.RHash,
|
|
|
|
IncomingExpiry: htlc.RefundTimeout,
|
|
|
|
IncomingAmount: htlc.Amt,
|
2022-11-18 12:15:22 +01:00
|
|
|
IncomingCircuit: models.CircuitKey{
|
2022-02-04 14:32:15 +01:00
|
|
|
ChanID: chanID,
|
|
|
|
HtlcID: htlc.HtlcIndex,
|
|
|
|
},
|
|
|
|
OutgoingChanID: payload.FwdInfo.NextHop,
|
|
|
|
OutgoingExpiry: payload.FwdInfo.OutgoingCTLV,
|
|
|
|
OutgoingAmount: payload.FwdInfo.AmountToForward,
|
|
|
|
CustomRecords: payload.CustomRecords(),
|
|
|
|
}
|
|
|
|
copy(packet.OnionBlob[:], nextHopOnionBlob)
|
|
|
|
|
|
|
|
fwd := newInterceptedForward(packet, p)
|
|
|
|
|
|
|
|
err := p.interceptor(fwd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return sub, nil
|
2018-01-17 05:02:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// LookupPreImage attempts to lookup a preimage in the global cache. True is
|
|
|
|
// returned for the second argument if the preimage is found.
|
2019-02-20 02:06:00 +01:00
|
|
|
func (p *preimageBeacon) LookupPreimage(
|
|
|
|
payHash lntypes.Hash) (lntypes.Preimage, bool) {
|
|
|
|
|
2018-01-17 05:02:25 +01:00
|
|
|
p.RLock()
|
|
|
|
defer p.RUnlock()
|
|
|
|
|
|
|
|
// Otherwise, we'll perform a final check using the witness cache.
|
2019-02-20 02:06:42 +01:00
|
|
|
preimage, err := p.wCache.LookupSha256Witness(payHash)
|
2018-01-17 05:02:25 +01:00
|
|
|
if err != nil {
|
2019-02-20 02:06:00 +01:00
|
|
|
ltndLog.Errorf("Unable to lookup witness: %v", err)
|
|
|
|
return lntypes.Preimage{}, false
|
|
|
|
}
|
|
|
|
|
2018-01-17 05:02:25 +01:00
|
|
|
return preimage, true
|
|
|
|
}
|
|
|
|
|
2019-02-20 02:05:04 +01:00
|
|
|
// AddPreimages adds a batch of newly discovered preimages to the global cache,
|
|
|
|
// and also signals any subscribers of the newly discovered witness.
|
2019-02-20 02:06:00 +01:00
|
|
|
func (p *preimageBeacon) AddPreimages(preimages ...lntypes.Preimage) error {
|
2019-02-20 02:05:04 +01:00
|
|
|
// Exit early if no preimages are presented.
|
|
|
|
if len(preimages) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2018-01-17 05:02:25 +01:00
|
|
|
|
2019-02-20 02:05:04 +01:00
|
|
|
// Copy the preimages to ensure the backing area can't be modified by
|
|
|
|
// the caller when delivering notifications.
|
2019-02-20 02:06:00 +01:00
|
|
|
preimageCopies := make([]lntypes.Preimage, 0, len(preimages))
|
2019-02-20 02:05:04 +01:00
|
|
|
for _, preimage := range preimages {
|
2019-02-20 02:06:00 +01:00
|
|
|
srvrLog.Infof("Adding preimage=%v to witness cache", preimage)
|
2019-02-20 02:05:04 +01:00
|
|
|
preimageCopies = append(preimageCopies, preimage)
|
|
|
|
}
|
2018-01-17 05:02:25 +01:00
|
|
|
|
|
|
|
// First, we'll add the witness to the decaying witness cache.
|
2019-02-20 02:06:00 +01:00
|
|
|
err := p.wCache.AddSha256Witnesses(preimages...)
|
2018-01-17 05:02:25 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-20 02:05:04 +01:00
|
|
|
p.Lock()
|
|
|
|
defer p.Unlock()
|
|
|
|
|
2018-01-17 05:02:25 +01:00
|
|
|
// With the preimage added to our state, we'll now send a new
|
|
|
|
// notification to all subscribers.
|
|
|
|
for _, client := range p.subscribers {
|
2018-02-07 04:11:11 +01:00
|
|
|
go func(c *preimageSubscriber) {
|
2019-02-20 02:05:04 +01:00
|
|
|
for _, preimage := range preimageCopies {
|
|
|
|
select {
|
|
|
|
case c.updateChan <- preimage:
|
|
|
|
case <-c.quit:
|
|
|
|
return
|
|
|
|
}
|
2018-01-17 05:02:25 +01:00
|
|
|
}
|
|
|
|
}(client)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ contractcourt.WitnessBeacon = (*preimageBeacon)(nil)
|