From 1a80a1e5406bc27f8bb0974645b0c0b0bd0233bb Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Tue, 16 Apr 2019 12:32:51 +0200 Subject: [PATCH] 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. --- contractcourt/channel_arbitrator.go | 53 ++++++++++++++++++++++++++--- server.go | 1 - witness_beacon.go | 22 ------------ 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index 7aeb2e35..bb16a3af 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -620,7 +620,10 @@ func (c *ChannelArbitrator) stateStep(triggerHeight uint32, // chain, we'll check to see if we need to make any on-chain // claims on behalf of the channel contract that we're // arbitrating for. - chainActions := c.checkChainActions(triggerHeight, trigger) + chainActions, err := c.checkChainActions(triggerHeight, trigger) + if err != nil { + return StateError, closeTx, err + } // If there are no actions to be made, then we'll remain in the // default state. If this isn't a self initiated event (we're @@ -1082,7 +1085,7 @@ func (c *ChannelArbitrator) shouldGoOnChain(htlcExpiry, broadcastDelta, // been sufficiently confirmed, the HTLC's should be canceled backwards. For // redeemed HTLC's, we should send the pre-image back to the incoming link. func (c *ChannelArbitrator) checkChainActions(height uint32, - trigger transitionTrigger) ChainActionMap { + trigger transitionTrigger) (ChainActionMap, error) { // TODO(roasbeef): would need to lock channel? channel totem? // * race condition if adding and we broadcast, etc @@ -1122,7 +1125,12 @@ func (c *ChannelArbitrator) checkChainActions(height uint32, // know the pre-image and it's close to timing out. We need to // ensure that we claim the funds that our rightfully ours // on-chain. - if _, ok := c.cfg.PreimageDB.LookupPreimage(htlc.RHash); !ok { + preimageAvailable, err := c.isPreimageAvailable(htlc.RHash) + if err != nil { + return nil, err + } + + if !preimageAvailable { continue } @@ -1151,7 +1159,7 @@ func (c *ChannelArbitrator) checkChainActions(height uint32, if !haveChainActions && trigger == chainTrigger { log.Tracef("ChannelArbitrator(%v): no actions to take at "+ "height=%v", c.cfg.ChanPoint, height) - return actionMap + return actionMap, nil } // Now that we know we'll need to go on-chain, we'll examine all of our @@ -1223,7 +1231,42 @@ func (c *ChannelArbitrator) checkChainActions(height uint32, ) } - return actionMap + return actionMap, nil +} + +// isPreimageAvailable returns whether the hash preimage is available in either +// the preimage cache or the invoice database. +func (c *ChannelArbitrator) isPreimageAvailable(hash lntypes.Hash) (bool, + error) { + + // Start by checking the preimage cache for preimages of + // forwarded HTLCs. + _, preimageAvailable := c.cfg.PreimageDB.LookupPreimage( + hash, + ) + if preimageAvailable { + return true, nil + } + + // Then check if we have an invoice that can be settled by this HTLC. + // + // TODO(joostjager): Check that there are still more blocks remaining + // than the invoice cltv delta. We don't want to go to chain only to + // have the incoming contest resolver decide that we don't want to + // settle this invoice. + invoice, _, err := c.cfg.Registry.LookupInvoice(hash) + switch err { + case nil: + case channeldb.ErrInvoiceNotFound, channeldb.ErrNoInvoicesCreated: + return false, nil + default: + return false, err + } + + preimageAvailable = invoice.Terms.PaymentPreimage != + channeldb.UnknownPreimage + + return preimageAvailable, nil } // prepContractResolutions is called either int he case that we decide we need diff --git a/server.go b/server.go index c71910e1..29a6b541 100644 --- a/server.go +++ b/server.go @@ -374,7 +374,6 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, } s.witnessBeacon = &preimageBeacon{ - invoices: s.invoices, wCache: chanDB.NewWitnessCache(), subscribers: make(map[uint64]*preimageSubscriber), } diff --git a/witness_beacon.go b/witness_beacon.go index 2971d93d..1593bee7 100644 --- a/witness_beacon.go +++ b/witness_beacon.go @@ -5,7 +5,6 @@ import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/contractcourt" - "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lntypes" ) @@ -23,8 +22,6 @@ type preimageSubscriber struct { type preimageBeacon struct { sync.RWMutex - invoices *invoices.InvoiceRegistry - wCache *channeldb.WitnessCache clientCounter uint64 @@ -71,25 +68,6 @@ func (p *preimageBeacon) LookupPreimage( p.RLock() defer p.RUnlock() - // First, we'll check the invoice registry to see if we already know of - // the preimage as it's on that we created ourselves. - invoice, _, err := p.invoices.LookupInvoice(payHash) - switch { - case err == channeldb.ErrInvoiceNotFound: - // If we get this error, then it simply means that this invoice - // wasn't found, so we don't treat it as a critical error. - case err != nil: - return lntypes.Preimage{}, false - } - - // If we've found the invoice, then we can return the preimage - // directly. - if err != channeldb.ErrInvoiceNotFound && - invoice.Terms.PaymentPreimage != channeldb.UnknownPreimage { - - return invoice.Terms.PaymentPreimage, true - } - // Otherwise, we'll perform a final check using the witness cache. preimage, err := p.wCache.LookupSha256Witness(payHash) if err != nil {