diff --git a/channeldb/forwarding_package.go b/channeldb/forwarding_package.go index 4c447fc03..11c0099e7 100644 --- a/channeldb/forwarding_package.go +++ b/channeldb/forwarding_package.go @@ -286,6 +286,27 @@ func NewFwdPkg(source lnwire.ShortChannelID, height uint64, } } +// SourceRef is a convenience method that returns an AddRef to this forwarding +// package for the index in the argument. It is the caller's responsibility +// to ensure that the index is in bounds. +func (f *FwdPkg) SourceRef(i uint16) AddRef { + return AddRef{ + Height: f.Height, + Index: i, + } +} + +// DestRef is a convenience method that returns a SettleFailRef to this +// forwarding package for the index in the argument. It is the caller's +// responsibility to ensure that the index is in bounds. +func (f *FwdPkg) DestRef(i uint16) SettleFailRef { + return SettleFailRef{ + Source: f.Source, + Height: f.Height, + Index: i, + } +} + // ID returns an unique identifier for this package, used to ensure that sphinx // replay processing of this batch is idempotent. func (f *FwdPkg) ID() []byte { diff --git a/htlcswitch/link.go b/htlcswitch/link.go index a8e35afe6..83495f357 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -442,7 +442,8 @@ func (m *hookMap) invoke() { // hodlHtlc contains htlc data that is required for resolution. type hodlHtlc struct { - pd *lnwallet.PaymentDescriptor + add lnwire.UpdateAddHTLC + sourceRef channeldb.AddRef obfuscator hop.ErrorEncrypter } @@ -992,15 +993,7 @@ func (l *channelLink) resolveFwdPkg(fwdPkg *channeldb.FwdPkg) error { // If the package is fully acked but not completed, it must still have // settles and fails to propagate. if !fwdPkg.SettleFailFilter.IsFull() { - settleFails, err := lnwallet.PayDescsFromRemoteLogUpdates( - fwdPkg.Source, fwdPkg.Height, fwdPkg.SettleFails, - ) - if err != nil { - l.log.Errorf("unable to process remote log updates: %v", - err) - return err - } - l.processRemoteSettleFails(fwdPkg, settleFails) + l.processRemoteSettleFails(fwdPkg) } // Finally, replay *ALL ADDS* in this forwarding package. The @@ -1008,15 +1001,7 @@ func (l *channelLink) resolveFwdPkg(fwdPkg *channeldb.FwdPkg) error { // shove the entire, original set of adds down the pipeline so that the // batch of adds presented to the sphinx router does not ever change. if !fwdPkg.AckFilter.IsFull() { - adds, err := lnwallet.PayDescsFromRemoteLogUpdates( - fwdPkg.Source, fwdPkg.Height, fwdPkg.Adds, - ) - if err != nil { - l.log.Errorf("unable to process remote log updates: %v", - err) - return err - } - l.processRemoteAdds(fwdPkg, adds) + l.processRemoteAdds(fwdPkg) // If the link failed during processing the adds, we must // return to ensure we won't attempted to update the state @@ -1520,7 +1505,9 @@ func (l *channelLink) processHtlcResolution(resolution invoices.HtlcResolution, l.log.Debugf("received settle resolution for %v "+ "with outcome: %v", circuitKey, res.Outcome) - return l.settleHTLC(res.Preimage, htlc.pd) + return l.settleHTLC( + res.Preimage, htlc.add.ID, htlc.sourceRef, + ) // For htlc failures, we get the relevant failure message based // on the failure resolution and then fail the htlc. @@ -1530,10 +1517,11 @@ func (l *channelLink) processHtlcResolution(resolution invoices.HtlcResolution, // Get the lnwire failure message based on the resolution // result. - failure := getResolutionFailure(res, htlc.pd.Amount) + failure := getResolutionFailure(res, htlc.add.Amount) l.sendHTLCError( - htlc.pd, failure, htlc.obfuscator, true, + htlc.add, htlc.sourceRef, failure, htlc.obfuscator, + true, ) return nil @@ -2333,8 +2321,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { // We now process the message and advance our remote commit // chain. - fwdPkg, adds, settleFails, remoteHTLCs, err := l.channel. - ReceiveRevocation(msg) + fwdPkg, remoteHTLCs, err := l.channel.ReceiveRevocation(msg) if err != nil { // TODO(halseth): force close? l.failf( @@ -2384,8 +2371,8 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { } } - l.processRemoteSettleFails(fwdPkg, settleFails) - l.processRemoteAdds(fwdPkg, adds) + l.processRemoteSettleFails(fwdPkg) + l.processRemoteAdds(fwdPkg) // If the link failed during processing the adds, we must // return to ensure we won't attempted to update the state @@ -3291,17 +3278,17 @@ func (l *channelLink) updateChannelFee(feePerKw chainfee.SatPerKWeight) error { // the context of the provided forwarding package. Any settles or fails that // have already been acknowledged in the forwarding package will not be sent to // the switch. -func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, - settleFails []*lnwallet.PaymentDescriptor) { - - if len(settleFails) == 0 { +func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg) { + if len(fwdPkg.SettleFails) == 0 { return } l.log.Debugf("settle-fail-filter: %v", fwdPkg.SettleFailFilter) var switchPackets []*htlcPacket - for i, pd := range settleFails { + for i, update := range fwdPkg.SettleFails { + destRef := fwdPkg.DestRef(uint16(i)) + // Skip any settles or fails that have already been // acknowledged by the incoming link that originated the // forwarded Add. @@ -3312,12 +3299,11 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, // TODO(roasbeef): rework log entries to a shared // interface. - switch pd.EntryType { - + switch msg := update.UpdateMsg.(type) { // A settle for an HTLC we previously forwarded HTLC has been // received. So we'll forward the HTLC to the switch which will // handle propagating the settle to the prior hop. - case lnwallet.Settle: + case *lnwire.UpdateFulfillHTLC: // If hodl.SettleIncoming is requested, we will not // forward the SETTLE to the switch and will not signal // a free slot on the commitment transaction. @@ -3328,11 +3314,9 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, settlePacket := &htlcPacket{ outgoingChanID: l.ShortChanID(), - outgoingHTLCID: pd.ParentIndex, - destRef: pd.DestRef, - htlc: &lnwire.UpdateFulfillHTLC{ - PaymentPreimage: pd.RPreimage, - }, + outgoingHTLCID: msg.ID, + destRef: &destRef, + htlc: msg, } // Add the packet to the batch to be forwarded, and @@ -3344,7 +3328,7 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, // been received. As a result a new slot will be freed up in // our commitment state, so we'll forward this to the switch so // the backwards undo can continue. - case lnwallet.Fail: + case *lnwire.UpdateFailHTLC: // If hodl.SettleIncoming is requested, we will not // forward the FAIL to the switch and will not signal a // free slot on the commitment transaction. @@ -3359,16 +3343,12 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, // set on the packet. failPacket := &htlcPacket{ outgoingChanID: l.ShortChanID(), - outgoingHTLCID: pd.ParentIndex, - destRef: pd.DestRef, - htlc: &lnwire.UpdateFailHTLC{ - Reason: lnwire.OpaqueReason( - pd.FailReason, - ), - }, + outgoingHTLCID: msg.ID, + destRef: &destRef, + htlc: msg, } - l.log.Debugf("Failed to send %s", pd.Amount) + l.log.Debugf("Failed to send HTLC with ID=%d", msg.ID) // If the failure message lacks an HMAC (but includes // the 4 bytes for encoding the message and padding @@ -3378,7 +3358,7 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, // to an actual error, by encrypting it as if we were // the originating hop. convertedErrorSize := lnwire.FailureMessageLength + 4 - if len(pd.FailReason) == convertedErrorSize { + if len(msg.Reason) == convertedErrorSize { failPacket.convertedError = true } @@ -3401,32 +3381,29 @@ func (l *channelLink) processRemoteSettleFails(fwdPkg *channeldb.FwdPkg, // indicating whether this is the first time these Adds are being processed, or // whether we are reprocessing as a result of a failure or restart. Adds that // have already been acknowledged in the forwarding package will be ignored. -func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, - lockedInHtlcs []*lnwallet.PaymentDescriptor) { - +// +//nolint:funlen +func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { l.log.Tracef("processing %d remote adds for height %d", - len(lockedInHtlcs), fwdPkg.Height) + len(fwdPkg.Adds), fwdPkg.Height) decodeReqs := make( - []hop.DecodeHopIteratorRequest, 0, len(lockedInHtlcs), + []hop.DecodeHopIteratorRequest, 0, len(fwdPkg.Adds), ) - for _, pd := range lockedInHtlcs { - switch pd.EntryType { - - // TODO(conner): remove type switch? - case lnwallet.Add: + for _, update := range fwdPkg.Adds { + if msg, ok := update.UpdateMsg.(*lnwire.UpdateAddHTLC); ok { // Before adding the new htlc to the state machine, // parse the onion object in order to obtain the // routing information with DecodeHopIterator function // which process the Sphinx packet. - onionReader := bytes.NewReader(pd.OnionBlob) + onionReader := bytes.NewReader(msg.OnionBlob[:]) req := hop.DecodeHopIteratorRequest{ OnionReader: onionReader, - RHash: pd.RHash[:], - IncomingCltv: pd.Timeout, - IncomingAmount: pd.Amount, - BlindingPoint: pd.BlindingPoint, + RHash: msg.PaymentHash[:], + IncomingCltv: msg.Expiry, + IncomingAmount: msg.Amount, + BlindingPoint: msg.BlindingPoint, } decodeReqs = append(decodeReqs, req) @@ -3448,9 +3425,13 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, var switchPackets []*htlcPacket - for i, pd := range lockedInHtlcs { + for i, update := range fwdPkg.Adds { idx := uint16(i) + //nolint:forcetypeassert + add := *update.UpdateMsg.(*lnwire.UpdateAddHTLC) + sourceRef := fwdPkg.SourceRef(idx) + if fwdPkg.State == channeldb.FwdStateProcessed && fwdPkg.AckFilter.Contains(idx) { @@ -3468,11 +3449,6 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // or are able to settle it (and it adheres to our fee related // constraints). - // Fetch the onion blob that was included within this processed - // payment descriptor. - var onionBlob [lnwire.OnionPacketSize]byte - copy(onionBlob[:], pd.OnionBlob) - // Before adding the new htlc to the state machine, parse the // onion object in order to obtain the routing information with // DecodeHopIterator function which process the Sphinx packet. @@ -3481,8 +3457,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // If we're unable to process the onion blob then we // should send the malformed htlc error to payment // sender. - l.sendMalformedHTLCError(pd.HtlcIndex, failureCode, - onionBlob[:], pd.SourceRef) + l.sendMalformedHTLCError( + add.ID, failureCode, add.OnionBlob, &sourceRef, + ) l.log.Errorf("unable to decode onion hop "+ "iterator: %v", failureCode) @@ -3526,8 +3503,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // We can't process this htlc, send back // malformed. l.sendMalformedHTLCError( - pd.HtlcIndex, failureCode, - onionBlob[:], pd.SourceRef, + add.ID, failureCode, add.OnionBlob, + &sourceRef, ) continue @@ -3540,8 +3517,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // payloads. Deferring this non-trival effort till a // later date failure := lnwire.NewInvalidOnionPayload(failedType, 0) + l.sendHTLCError( - pd, NewLinkError(failure), obfuscator, false, + add, sourceRef, NewLinkError(failure), + obfuscator, false, ) l.log.Errorf("unable to decode forwarding "+ @@ -3561,8 +3540,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // should send the malformed htlc error to payment // sender. l.sendMalformedHTLCError( - pd.HtlcIndex, failureCode, onionBlob[:], - pd.SourceRef, + add.ID, failureCode, add.OnionBlob, + &sourceRef, ) l.log.Errorf("unable to decode onion "+ @@ -3581,10 +3560,12 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, l.cfg.DisallowRouteBlinding { failure := lnwire.NewInvalidBlinding( - onionBlob[:], + fn.Some(add.OnionBlob), ) + l.sendHTLCError( - pd, NewLinkError(failure), obfuscator, false, + add, sourceRef, NewLinkError(failure), + obfuscator, false, ) l.log.Error("rejected htlc that uses use as an " + @@ -3597,7 +3578,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, switch fwdInfo.NextHop { case hop.Exit: err := l.processExitHop( - pd, obfuscator, fwdInfo, heightNow, pld, + add, sourceRef, obfuscator, fwdInfo, + heightNow, pld, ) if err != nil { l.failf(LinkFailureError{ @@ -3631,18 +3613,20 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, } // Otherwise, it was already processed, we can - // collect it and continue. - addMsg := &lnwire.UpdateAddHTLC{ + // can collect it and continue. + outgoingAdd := &lnwire.UpdateAddHTLC{ Expiry: fwdInfo.OutgoingCTLV, Amount: fwdInfo.AmountToForward, - PaymentHash: pd.RHash, + PaymentHash: add.PaymentHash, BlindingPoint: fwdInfo.NextBlinding, } // Finally, we'll encode the onion packet for // the _next_ hop using the hop iterator // decoded for the current hop. - buf := bytes.NewBuffer(addMsg.OnionBlob[0:0]) + buf := bytes.NewBuffer( + outgoingAdd.OnionBlob[0:0], + ) // We know this cannot fail, as this ADD // was marked forwarded in a previous @@ -3654,18 +3638,18 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, //nolint:lll updatePacket := &htlcPacket{ incomingChanID: l.ShortChanID(), - incomingHTLCID: pd.HtlcIndex, + incomingHTLCID: add.ID, outgoingChanID: fwdInfo.NextHop, - sourceRef: pd.SourceRef, - incomingAmount: pd.Amount, - amount: addMsg.Amount, - htlc: addMsg, + sourceRef: &sourceRef, + incomingAmount: add.Amount, + amount: outgoingAdd.Amount, + htlc: outgoingAdd, obfuscator: obfuscator, - incomingTimeout: pd.Timeout, + incomingTimeout: add.Expiry, outgoingTimeout: fwdInfo.OutgoingCTLV, inOnionCustomRecords: pld.CustomRecords(), inboundFee: inboundFee, - inWireCustomRecords: pd.CustomRecords.Copy(), + inWireCustomRecords: add.CustomRecords.Copy(), } switchPackets = append( switchPackets, updatePacket, @@ -3683,7 +3667,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, addMsg := &lnwire.UpdateAddHTLC{ Expiry: fwdInfo.OutgoingCTLV, Amount: fwdInfo.AmountToForward, - PaymentHash: pd.RHash, + PaymentHash: add.PaymentHash, BlindingPoint: fwdInfo.NextBlinding, } @@ -3705,7 +3689,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, ) l.sendHTLCError( - pd, NewLinkError(failure), obfuscator, false, + add, sourceRef, NewLinkError(failure), + obfuscator, false, ) continue } @@ -3724,18 +3709,18 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, //nolint:lll updatePacket := &htlcPacket{ incomingChanID: l.ShortChanID(), - incomingHTLCID: pd.HtlcIndex, + incomingHTLCID: add.ID, outgoingChanID: fwdInfo.NextHop, - sourceRef: pd.SourceRef, - incomingAmount: pd.Amount, + sourceRef: &sourceRef, + incomingAmount: add.Amount, amount: addMsg.Amount, htlc: addMsg, obfuscator: obfuscator, - incomingTimeout: pd.Timeout, + incomingTimeout: add.Expiry, outgoingTimeout: fwdInfo.OutgoingCTLV, inOnionCustomRecords: pld.CustomRecords(), inboundFee: inboundFee, - inWireCustomRecords: pd.CustomRecords.Copy(), + inWireCustomRecords: add.CustomRecords.Copy(), } fwdPkg.FwdFilter.Set(idx) @@ -3775,9 +3760,10 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // processExitHop handles an htlc for which this link is the exit hop. It // returns a boolean indicating whether the commitment tx needs an update. -func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, - obfuscator hop.ErrorEncrypter, fwdInfo hop.ForwardingInfo, - heightNow uint32, payload invoices.Payload) error { +func (l *channelLink) processExitHop(add lnwire.UpdateAddHTLC, + sourceRef channeldb.AddRef, obfuscator hop.ErrorEncrypter, + fwdInfo hop.ForwardingInfo, heightNow uint32, + payload invoices.Payload) error { // If hodl.ExitSettle is requested, we will not validate the final hop's // ADD, nor will we settle the corresponding invoice or respond with the @@ -3791,30 +3777,31 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, // As we're the exit hop, we'll double check the hop-payload included in // the HTLC to ensure that it was crafted correctly by the sender and // is compatible with the HTLC we were extended. - if pd.Amount < fwdInfo.AmountToForward { + if add.Amount < fwdInfo.AmountToForward { l.log.Errorf("onion payload of incoming htlc(%x) has "+ - "incompatible value: expected <=%v, got %v", pd.RHash, - pd.Amount, fwdInfo.AmountToForward) + "incompatible value: expected <=%v, got %v", + add.PaymentHash, add.Amount, fwdInfo.AmountToForward) failure := NewLinkError( - lnwire.NewFinalIncorrectHtlcAmount(pd.Amount), + lnwire.NewFinalIncorrectHtlcAmount(add.Amount), ) - l.sendHTLCError(pd, failure, obfuscator, true) + l.sendHTLCError(add, sourceRef, failure, obfuscator, true) return nil } // We'll also ensure that our time-lock value has been computed // correctly. - if pd.Timeout < fwdInfo.OutgoingCTLV { + if add.Expiry < fwdInfo.OutgoingCTLV { l.log.Errorf("onion payload of incoming htlc(%x) has "+ "incompatible time-lock: expected <=%v, got %v", - pd.RHash[:], pd.Timeout, fwdInfo.OutgoingCTLV) + add.PaymentHash, add.Expiry, fwdInfo.OutgoingCTLV) failure := NewLinkError( - lnwire.NewFinalIncorrectCltvExpiry(pd.Timeout), + lnwire.NewFinalIncorrectCltvExpiry(add.Expiry), ) - l.sendHTLCError(pd, failure, obfuscator, true) + + l.sendHTLCError(add, sourceRef, failure, obfuscator, true) return nil } @@ -3822,15 +3809,15 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, // Notify the invoiceRegistry of the exit hop htlc. If we crash right // after this, this code will be re-executed after restart. We will // receive back a resolution event. - invoiceHash := lntypes.Hash(pd.RHash) + invoiceHash := lntypes.Hash(add.PaymentHash) circuitKey := models.CircuitKey{ ChanID: l.ShortChanID(), - HtlcID: pd.HtlcIndex, + HtlcID: add.ID, } event, err := l.cfg.Registry.NotifyExitHopHtlc( - invoiceHash, pd.Amount, pd.Timeout, int32(heightNow), + invoiceHash, add.Amount, add.Expiry, int32(heightNow), circuitKey, l.hodlQueue.ChanIn(), payload, ) if err != nil { @@ -3839,7 +3826,8 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, // Create a hodlHtlc struct and decide either resolved now or later. htlc := hodlHtlc{ - pd: pd, + add: add, + sourceRef: sourceRef, obfuscator: obfuscator, } @@ -3856,14 +3844,14 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, // settleHTLC settles the HTLC on the channel. func (l *channelLink) settleHTLC(preimage lntypes.Preimage, - pd *lnwallet.PaymentDescriptor) error { + htlcIndex uint64, sourceRef channeldb.AddRef) error { hash := preimage.Hash() l.log.Infof("settling htlc %v as exit hop", hash) err := l.channel.SettleHTLC( - preimage, pd.HtlcIndex, pd.SourceRef, nil, nil, + preimage, htlcIndex, &sourceRef, nil, nil, ) if err != nil { return fmt.Errorf("unable to settle htlc: %w", err) @@ -3881,7 +3869,7 @@ func (l *channelLink) settleHTLC(preimage lntypes.Preimage, // remote peer. l.cfg.Peer.SendMessage(false, &lnwire.UpdateFulfillHTLC{ ChanID: l.ChanID(), - ID: pd.HtlcIndex, + ID: htlcIndex, PaymentPreimage: preimage, }) @@ -3890,7 +3878,7 @@ func (l *channelLink) settleHTLC(preimage lntypes.Preimage, HtlcKey{ IncomingCircuit: models.CircuitKey{ ChanID: l.ShortChanID(), - HtlcID: pd.HtlcIndex, + HtlcID: htlcIndex, }, }, preimage, @@ -3925,8 +3913,9 @@ func (l *channelLink) forwardBatch(replay bool, packets ...*htlcPacket) { // sendHTLCError functions cancels HTLC and send cancel message back to the // peer from which HTLC was received. -func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor, - failure *LinkError, e hop.ErrorEncrypter, isReceive bool) { +func (l *channelLink) sendHTLCError(add lnwire.UpdateAddHTLC, + sourceRef channeldb.AddRef, failure *LinkError, + e hop.ErrorEncrypter, isReceive bool) { reason, err := e.EncryptFirstHop(failure.WireMessage()) if err != nil { @@ -3934,7 +3923,7 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor, return } - err = l.channel.FailHTLC(pd.HtlcIndex, reason, pd.SourceRef, nil, nil) + err = l.channel.FailHTLC(add.ID, reason, &sourceRef, nil, nil) if err != nil { l.log.Errorf("unable cancel htlc: %v", err) return @@ -3943,7 +3932,7 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor, // Send the appropriate failure message depending on whether we're // in a blinded route or not. if err := l.sendIncomingHTLCFailureMsg( - pd.HtlcIndex, e, reason, + add.ID, e, reason, ); err != nil { l.log.Errorf("unable to send HTLC failure: %v", err) return @@ -3963,12 +3952,12 @@ func (l *channelLink) sendHTLCError(pd *lnwallet.PaymentDescriptor, HtlcKey{ IncomingCircuit: models.CircuitKey{ ChanID: l.ShortChanID(), - HtlcID: pd.HtlcIndex, + HtlcID: add.ID, }, }, HtlcInfo{ - IncomingTimeLock: pd.Timeout, - IncomingAmt: pd.Amount, + IncomingTimeLock: add.Expiry, + IncomingAmt: add.Amount, }, eventType, failure, @@ -4027,7 +4016,9 @@ func (l *channelLink) sendIncomingHTLCFailureMsg(htlcIndex uint64, // The specification does not require that we set the onion // blob. - failureMsg := lnwire.NewInvalidBlinding(nil) + failureMsg := lnwire.NewInvalidBlinding( + fn.None[[lnwire.OnionPacketSize]byte](), + ) reason, err := e.EncryptFirstHop(failureMsg) if err != nil { return err @@ -4065,9 +4056,10 @@ func (l *channelLink) sendIncomingHTLCFailureMsg(htlcIndex uint64, // sendMalformedHTLCError helper function which sends the malformed HTLC update // to the payment sender. func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64, - code lnwire.FailCode, onionBlob []byte, sourceRef *channeldb.AddRef) { + code lnwire.FailCode, onionBlob [lnwire.OnionPacketSize]byte, + sourceRef *channeldb.AddRef) { - shaOnionBlob := sha256.Sum256(onionBlob) + shaOnionBlob := sha256.Sum256(onionBlob[:]) err := l.channel.MalformedFailHTLC(htlcIndex, code, shaOnionBlob, sourceRef) if err != nil { l.log.Errorf("unable cancel htlc: %v", err) diff --git a/htlcswitch/link_isolated_test.go b/htlcswitch/link_isolated_test.go index 89d0ef319..5d769d920 100644 --- a/htlcswitch/link_isolated_test.go +++ b/htlcswitch/link_isolated_test.go @@ -129,7 +129,7 @@ func (l *linkTestContext) receiveRevAndAckAliceToBob() { l.t.Fatalf("expected RevokeAndAck, got %T", msg) } - _, _, _, _, err := l.bobChannel.ReceiveRevocation(rev) + _, _, err := l.bobChannel.ReceiveRevocation(rev) if err != nil { l.t.Fatalf("bob failed receiving revocation: %v", err) } diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 60010d6ff..53a084209 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -2335,7 +2335,7 @@ func handleStateUpdate(link *channelLink, if !ok { return fmt.Errorf("expected RevokeAndAck got %T", msg) } - _, _, _, _, err = remoteChannel.ReceiveRevocation(revoke) + _, _, err = remoteChannel.ReceiveRevocation(revoke) if err != nil { return fmt.Errorf("unable to receive "+ "revocation: %v", err) @@ -2389,7 +2389,7 @@ func updateState(batchTick chan time.Time, link *channelLink, return fmt.Errorf("expected RevokeAndAck got %T", msg) } - _, _, _, _, err = remoteChannel.ReceiveRevocation(revoke) + _, _, err = remoteChannel.ReceiveRevocation(revoke) if err != nil { return fmt.Errorf("unable to receive "+ "revocation: %v", err) @@ -3643,7 +3643,7 @@ func TestChannelLinkTrimCircuitsRemoteCommit(t *testing.T) { rev, _, _, err := harness.bobChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke current commitment") - _, _, _, _, err = alice.channel.ReceiveRevocation(rev) + _, _, err = alice.channel.ReceiveRevocation(rev) require.NoError(t, err, "unable to receive revocation") // Restart Alice's link, which simulates a disconnection with the remote diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go index a839ec3bf..01596ade0 100644 --- a/htlcswitch/switch.go +++ b/htlcswitch/switch.go @@ -1911,18 +1911,8 @@ func (s *Switch) loadChannelFwdPkgs(source lnwire.ShortChannelID) ([]*channeldb. // NOTE: This should mimic the behavior processRemoteSettleFails. func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) { for _, fwdPkg := range fwdPkgs { - settleFails, err := lnwallet.PayDescsFromRemoteLogUpdates( - fwdPkg.Source, fwdPkg.Height, fwdPkg.SettleFails, - ) - if err != nil { - log.Errorf("Unable to process remote log updates: %v", - err) - continue - } - - switchPackets := make([]*htlcPacket, 0, len(settleFails)) - for i, pd := range settleFails { - + switchPackets := make([]*htlcPacket, 0, len(fwdPkg.SettleFails)) + for i, update := range fwdPkg.SettleFails { // Skip any settles or fails that have already been // acknowledged by the incoming link that originated the // forwarded Add. @@ -1930,20 +1920,18 @@ func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) { continue } - switch pd.EntryType { - + switch msg := update.UpdateMsg.(type) { // A settle for an HTLC we previously forwarded HTLC has // been received. So we'll forward the HTLC to the // switch which will handle propagating the settle to // the prior hop. - case lnwallet.Settle: + case *lnwire.UpdateFulfillHTLC: + destRef := fwdPkg.DestRef(uint16(i)) settlePacket := &htlcPacket{ outgoingChanID: fwdPkg.Source, - outgoingHTLCID: pd.ParentIndex, - destRef: pd.DestRef, - htlc: &lnwire.UpdateFulfillHTLC{ - PaymentPreimage: pd.RPreimage, - }, + outgoingHTLCID: msg.ID, + destRef: &destRef, + htlc: msg, } // Add the packet to the batch to be forwarded, and @@ -1955,7 +1943,7 @@ func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) { // received. As a result a new slot will be freed up in our // commitment state, so we'll forward this to the switch so the // backwards undo can continue. - case lnwallet.Fail: + case *lnwire.UpdateFailHTLC: // Fetch the reason the HTLC was canceled so // we can continue to propagate it. This // failure originated from another node, so @@ -1964,11 +1952,13 @@ func (s *Switch) reforwardSettleFails(fwdPkgs []*channeldb.FwdPkg) { // additional circuit information for us. failPacket := &htlcPacket{ outgoingChanID: fwdPkg.Source, - outgoingHTLCID: pd.ParentIndex, - destRef: pd.DestRef, - htlc: &lnwire.UpdateFailHTLC{ - Reason: lnwire.OpaqueReason(pd.FailReason), + outgoingHTLCID: msg.ID, + destRef: &channeldb.SettleFailRef{ + Source: fwdPkg.Source, + Height: fwdPkg.Height, + Index: uint16(i), }, + htlc: msg, } // Add the packet to the batch to be forwarded, and diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 49d8df566..32492171f 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -168,100 +168,6 @@ func (e *ErrCommitSyncLocalDataLoss) Error() string { // payments requested by the wallet/daemon. type PaymentHash [32]byte -// PayDescsFromRemoteLogUpdates converts a slice of LogUpdates received from the -// remote peer into PaymentDescriptors to inform a link's forwarding decisions. -// -// NOTE: The provided `logUpdates` MUST correspond exactly to either the Adds -// or SettleFails in this channel's forwarding package at `height`. -func PayDescsFromRemoteLogUpdates(chanID lnwire.ShortChannelID, height uint64, - logUpdates []channeldb.LogUpdate) ([]*PaymentDescriptor, error) { - - // Allocate enough space to hold all of the payment descriptors we will - // reconstruct, and also the list of pointers that will be returned to - // the caller. - payDescs := make([]PaymentDescriptor, 0, len(logUpdates)) - payDescPtrs := make([]*PaymentDescriptor, 0, len(logUpdates)) - - // Iterate over the log updates we loaded from disk, and reconstruct the - // payment descriptor corresponding to one of the four types of htlcs we - // can receive from the remote peer. We only repopulate the information - // necessary to process the packets and, if necessary, forward them to - // the switch. - // - // For each log update, we include either an AddRef or a SettleFailRef - // so that they can be ACK'd and garbage collected. - for i, logUpdate := range logUpdates { - var pd PaymentDescriptor - switch wireMsg := logUpdate.UpdateMsg.(type) { - - case *lnwire.UpdateAddHTLC: - pd = PaymentDescriptor{ - RHash: wireMsg.PaymentHash, - Timeout: wireMsg.Expiry, - Amount: wireMsg.Amount, - EntryType: Add, - HtlcIndex: wireMsg.ID, - LogIndex: logUpdate.LogIndex, - SourceRef: &channeldb.AddRef{ - Height: height, - Index: uint16(i), - }, - BlindingPoint: wireMsg.BlindingPoint, - CustomRecords: wireMsg.CustomRecords.Copy(), - } - pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob)) - copy(pd.OnionBlob[:], wireMsg.OnionBlob[:]) - - case *lnwire.UpdateFulfillHTLC: - pd = PaymentDescriptor{ - RPreimage: wireMsg.PaymentPreimage, - ParentIndex: wireMsg.ID, - EntryType: Settle, - DestRef: &channeldb.SettleFailRef{ - Source: chanID, - Height: height, - Index: uint16(i), - }, - } - - case *lnwire.UpdateFailHTLC: - pd = PaymentDescriptor{ - ParentIndex: wireMsg.ID, - EntryType: Fail, - FailReason: wireMsg.Reason[:], - DestRef: &channeldb.SettleFailRef{ - Source: chanID, - Height: height, - Index: uint16(i), - }, - } - - case *lnwire.UpdateFailMalformedHTLC: - pd = PaymentDescriptor{ - ParentIndex: wireMsg.ID, - EntryType: MalformedFail, - FailCode: wireMsg.FailureCode, - ShaOnionBlob: wireMsg.ShaOnionBlob, - DestRef: &channeldb.SettleFailRef{ - Source: chanID, - Height: height, - Index: uint16(i), - }, - } - - // NOTE: UpdateFee is not expected since they are not forwarded. - case *lnwire.UpdateFee: - return nil, fmt.Errorf("unexpected update fee") - - } - - payDescs = append(payDescs, pd) - payDescPtrs = append(payDescPtrs, &payDescs[i]) - } - - return payDescPtrs, nil -} - // commitment represents a commitment to a new state within an active channel. // New commitments can be initiated by either side. Commitments are ordered // into a commitment chain, with one existing for both parties. Each side can @@ -328,11 +234,11 @@ type commitment struct { // outgoingHTLCs is a slice of all the outgoing HTLC's (from our PoV) // on this commitment transaction. - outgoingHTLCs []PaymentDescriptor + outgoingHTLCs []paymentDescriptor // incomingHTLCs is a slice of all the incoming HTLC's (from our PoV) // on this commitment transaction. - incomingHTLCs []PaymentDescriptor + incomingHTLCs []paymentDescriptor // customBlob stores opaque bytes that may be used by custom channels // to store extra data for a given commitment state. @@ -348,8 +254,8 @@ type commitment struct { // this map in order to locate the details needed to validate an HTLC // signature while iterating of the outputs in the local commitment // view. - outgoingHTLCIndex map[int32]*PaymentDescriptor - incomingHTLCIndex map[int32]*PaymentDescriptor + outgoingHTLCIndex map[int32]*paymentDescriptor + incomingHTLCIndex map[int32]*paymentDescriptor } // locateOutputIndex is a small helper function to locate the output index of a @@ -357,7 +263,7 @@ type commitment struct { // passed in is to be retained for each output within the commitment // transition. This ensures that we don't assign multiple HTLCs to the same // index within the commitment transaction. -func locateOutputIndex(p *PaymentDescriptor, tx *wire.MsgTx, +func locateOutputIndex(p *paymentDescriptor, tx *wire.MsgTx, whoseCommit lntypes.ChannelParty, dups map[PaymentHash][]int32, cltvs []uint32) (int32, error) { @@ -397,7 +303,7 @@ func locateOutputIndex(p *PaymentDescriptor, tx *wire.MsgTx, // populateHtlcIndexes modifies the set of HTLCs locked-into the target view // to have full indexing information populated. This information is required as // we need to keep track of the indexes of each HTLC in order to properly write -// the current state to disk, and also to locate the PaymentDescriptor +// the current state to disk, and also to locate the paymentDescriptor // corresponding to HTLC outputs in the commitment transaction. func (c *commitment) populateHtlcIndexes(chanType channeldb.ChannelType, cltvs []uint32) error { @@ -407,12 +313,12 @@ func (c *commitment) populateHtlcIndexes(chanType channeldb.ChannelType, // must keep this index so we can validate the HTLC signatures sent to // us. dups := make(map[PaymentHash][]int32) - c.outgoingHTLCIndex = make(map[int32]*PaymentDescriptor) - c.incomingHTLCIndex = make(map[int32]*PaymentDescriptor) + c.outgoingHTLCIndex = make(map[int32]*paymentDescriptor) + c.incomingHTLCIndex = make(map[int32]*paymentDescriptor) // populateIndex is a helper function that populates the necessary // indexes within the commitment view for a particular HTLC. - populateIndex := func(htlc *PaymentDescriptor, incoming bool) error { + populateIndex := func(htlc *paymentDescriptor, incoming bool) error { isDust := HtlcIsDust( chanType, incoming, c.whoseCommit, c.feePerKw, htlc.Amount.ToSatoshis(), c.dustLimit, @@ -528,10 +434,10 @@ func (c *commitment) toDiskCommit( HtlcIndex: htlc.HtlcIndex, LogIndex: htlc.LogIndex, Incoming: false, + OnionBlob: htlc.OnionBlob, BlindingPoint: htlc.BlindingPoint, CustomRecords: htlc.CustomRecords.Copy(), } - copy(h.OnionBlob[:], htlc.OnionBlob) if whoseCommit.IsLocal() && htlc.sig != nil { h.Signature = htlc.sig.Serialize() @@ -554,11 +460,10 @@ func (c *commitment) toDiskCommit( HtlcIndex: htlc.HtlcIndex, LogIndex: htlc.LogIndex, Incoming: true, + OnionBlob: htlc.OnionBlob, BlindingPoint: htlc.BlindingPoint, CustomRecords: htlc.CustomRecords.Copy(), } - copy(h.OnionBlob[:], htlc.OnionBlob) - if whoseCommit.IsLocal() && htlc.sig != nil { h.Signature = htlc.sig.Serialize() } @@ -577,15 +482,15 @@ func (c *commitment) toDiskCommit( func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, htlc *channeldb.HTLC, commitKeys lntypes.Dual[*CommitmentKeyRing], whoseCommit lntypes.ChannelParty, - auxLeaf input.AuxTapLeaf) (PaymentDescriptor, error) { + auxLeaf input.AuxTapLeaf) (paymentDescriptor, error) { - // The proper pkScripts for this PaymentDescriptor must be + // The proper pkScripts for this paymentDescriptor must be // generated so we can easily locate them within the commitment // transaction in the future. var ( ourP2WSH, theirP2WSH []byte ourWitnessScript, theirWitnessScript []byte - pd PaymentDescriptor + pd paymentDescriptor chanType = lc.channelState.ChanType ) @@ -645,14 +550,15 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, // With the scripts reconstructed (depending on if this is our commit // vs theirs or a pending commit for the remote party), we can now // re-create the original payment descriptor. - return PaymentDescriptor{ + return paymentDescriptor{ + ChanID: lc.ChannelID(), RHash: htlc.RHash, Timeout: htlc.RefundTimeout, Amount: htlc.Amt, EntryType: Add, HtlcIndex: htlc.HtlcIndex, LogIndex: htlc.LogIndex, - OnionBlob: htlc.OnionBlob[:], + OnionBlob: htlc.OnionBlob, localOutputIndex: localOutputIndex, remoteOutputIndex: remoteOutputIndex, ourPkScript: ourP2WSH, @@ -671,16 +577,16 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight, func (lc *LightningChannel) extractPayDescs(feeRate chainfee.SatPerKWeight, htlcs []channeldb.HTLC, commitKeys lntypes.Dual[*CommitmentKeyRing], whoseCommit lntypes.ChannelParty, - auxLeaves fn.Option[CommitAuxLeaves]) ([]PaymentDescriptor, - []PaymentDescriptor, error) { + auxLeaves fn.Option[CommitAuxLeaves]) ([]paymentDescriptor, + []paymentDescriptor, error) { var ( - incomingHtlcs []PaymentDescriptor - outgoingHtlcs []PaymentDescriptor + incomingHtlcs []paymentDescriptor + outgoingHtlcs []paymentDescriptor ) // For each included HTLC within this commitment state, we'll convert - // the disk format into our in memory PaymentDescriptor format, + // the disk format into our in memory paymentDescriptor format, // partitioning based on if we offered or received the HTLC. for _, htlc := range htlcs { // TODO(roasbeef): set isForwarded to false for all? need to @@ -762,7 +668,7 @@ func (lc *LightningChannel) diskCommitToMemCommit( } // With the key rings re-created, we'll now convert all the on-disk - // HTLC"s into PaymentDescriptor's so we can re-insert them into our + // HTLC"s into paymentDescriptor's so we can re-insert them into our // update log. incomingHtlcs, outgoingHtlcs, err := lc.extractPayDescs( chainfee.SatPerKWeight(diskCommit.FeePerKw), @@ -1118,7 +1024,7 @@ func (lc *LightningChannel) ResetState() { lc.Unlock() } -// logUpdateToPayDesc converts a LogUpdate into a matching PaymentDescriptor +// logUpdateToPayDesc converts a LogUpdate into a matching paymentDescriptor // entry that can be re-inserted into the update log. This method is used when // we extended a state to the remote party, but the connection was obstructed // before we could finish the commitment dance. In this case, we need to @@ -1128,25 +1034,26 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, remoteUpdateLog *updateLog, commitHeight uint64, feeRate chainfee.SatPerKWeight, remoteCommitKeys *CommitmentKeyRing, remoteDustLimit btcutil.Amount, - auxLeaves fn.Option[CommitAuxLeaves]) (*PaymentDescriptor, error) { + auxLeaves fn.Option[CommitAuxLeaves]) (*paymentDescriptor, error) { // Depending on the type of update message we'll map that to a distinct - // PaymentDescriptor instance. - var pd *PaymentDescriptor + // paymentDescriptor instance. + var pd *paymentDescriptor switch wireMsg := logUpdate.UpdateMsg.(type) { - // For offered HTLC's, we'll map that to a PaymentDescriptor with the + // For offered HTLC's, we'll map that to a paymentDescriptor with the // type Add, ensuring we restore the necessary fields. From the PoV of // the commitment chain, this HTLC was included in the remote chain, // but not the local chain. case *lnwire.UpdateAddHTLC: // First, we'll map all the relevant fields in the // UpdateAddHTLC message to their corresponding fields in the - // PaymentDescriptor struct. We also set addCommitHeightRemote + // paymentDescriptor struct. We also set addCommitHeightRemote // as we've included this HTLC in our local commitment chain // for the remote party. - pd = &PaymentDescriptor{ + pd = &paymentDescriptor{ + ChanID: wireMsg.ChanID, RHash: wireMsg.PaymentHash, Timeout: wireMsg.Expiry, Amount: wireMsg.Amount, @@ -1154,11 +1061,10 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, HtlcIndex: wireMsg.ID, LogIndex: logUpdate.LogIndex, addCommitHeightRemote: commitHeight, + OnionBlob: wireMsg.OnionBlob, BlindingPoint: wireMsg.BlindingPoint, CustomRecords: wireMsg.CustomRecords.Copy(), } - pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob)) - copy(pd.OnionBlob[:], wireMsg.OnionBlob[:]) isDustRemote := HtlcIsDust( lc.channelState.ChanType, false, lntypes.Remote, @@ -1187,11 +1093,12 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, // For HTLC's we're offered we'll fetch the original offered HTLC // from the remote party's update log so we can retrieve the same - // PaymentDescriptor that SettleHTLC would produce. + // paymentDescriptor that SettleHTLC would produce. case *lnwire.UpdateFulfillHTLC: ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) - pd = &PaymentDescriptor{ + pd = &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, RPreimage: wireMsg.PaymentPreimage, @@ -1208,7 +1115,8 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, case *lnwire.UpdateFailHTLC: ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) - pd = &PaymentDescriptor{ + pd = &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1224,7 +1132,8 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) // TODO(roasbeef): err if nil? - pd = &PaymentDescriptor{ + pd = &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1242,7 +1151,8 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, // height to the same value, as we consider the fee update locked in by // adding and removing it at the same height. case *lnwire.UpdateFee: - pd = &PaymentDescriptor{ + pd = &paymentDescriptor{ + ChanID: wireMsg.ChanID, LogIndex: logUpdate.LogIndex, Amount: lnwire.NewMSatFromSatoshis( btcutil.Amount(wireMsg.FeePerKw), @@ -1256,29 +1166,30 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate, return pd, nil } -// localLogUpdateToPayDesc converts a LogUpdate into a matching PaymentDescriptor -// entry that can be re-inserted into the local update log. This method is used -// when we sent an update+sig, receive a revocation, but drop right before the -// counterparty can sign for the update we just sent. In this case, we need to -// re-insert the original entries back into the update log so we'll be expecting -// the peer to sign them. The height of the remote commitment is expected to be -// provided and we restore all log update entries with this height, even though -// the real height may be lower. In the way these fields are used elsewhere, this -// doesn't change anything. +// localLogUpdateToPayDesc converts a LogUpdate into a matching +// paymentDescriptor entry that can be re-inserted into the local update log. +// This method is used when we sent an update+sig, receive a revocation, but +// drop right before the counterparty can sign for the update we just sent. In +// this case, we need to re-insert the original entries back into the update +// log so we'll be expecting the peer to sign them. The height of the remote +// commitment is expected to be provided and we restore all log update entries +// with this height, even though the real height may be lower. In the way these +// fields are used elsewhere, this doesn't change anything. func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpdate, - remoteUpdateLog *updateLog, commitHeight uint64) (*PaymentDescriptor, + remoteUpdateLog *updateLog, commitHeight uint64) (*paymentDescriptor, error) { // Since Add updates aren't saved to disk under this key, the update will // never be an Add. switch wireMsg := logUpdate.UpdateMsg.(type) { // For HTLCs that we settled, we'll fetch the original offered HTLC from - // the remote update log so we can retrieve the same PaymentDescriptor that - // ReceiveHTLCSettle would produce. + // the remote update log so we can retrieve the same paymentDescriptor + // that ReceiveHTLCSettle would produce. case *lnwire.UpdateFulfillHTLC: ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, RPreimage: wireMsg.PaymentPreimage, @@ -1294,7 +1205,8 @@ func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpda case *lnwire.UpdateFailHTLC: ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1309,7 +1221,8 @@ func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpda case *lnwire.UpdateFailMalformedHTLC: ogHTLC := remoteUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1321,7 +1234,8 @@ func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpda }, nil case *lnwire.UpdateFee: - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, LogIndex: logUpdate.LogIndex, Amount: lnwire.NewMSatFromSatoshis( btcutil.Amount(wireMsg.FeePerKw), @@ -1337,7 +1251,7 @@ func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpda } // remoteLogUpdateToPayDesc converts a LogUpdate into a matching -// PaymentDescriptor entry that can be re-inserted into the update log. This +// paymentDescriptor entry that can be re-inserted into the update log. This // method is used when we revoked a local commitment, but the connection was // obstructed before we could sign a remote commitment that contains these // updates. In this case, we need to re-insert the original entries back into @@ -1347,12 +1261,13 @@ func (lc *LightningChannel) localLogUpdateToPayDesc(logUpdate *channeldb.LogUpda // may be lower. In the way these fields are used elsewhere, this doesn't change // anything. func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpdate, - localUpdateLog *updateLog, commitHeight uint64) (*PaymentDescriptor, + localUpdateLog *updateLog, commitHeight uint64) (*paymentDescriptor, error) { switch wireMsg := logUpdate.UpdateMsg.(type) { case *lnwire.UpdateAddHTLC: - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: wireMsg.ChanID, RHash: wireMsg.PaymentHash, Timeout: wireMsg.Expiry, Amount: wireMsg.Amount, @@ -1360,11 +1275,10 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd HtlcIndex: wireMsg.ID, LogIndex: logUpdate.LogIndex, addCommitHeightLocal: commitHeight, + OnionBlob: wireMsg.OnionBlob, BlindingPoint: wireMsg.BlindingPoint, CustomRecords: wireMsg.CustomRecords.Copy(), } - pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob)) - copy(pd.OnionBlob, wireMsg.OnionBlob[:]) // We don't need to generate an htlc script yet. This will be // done once we sign our remote commitment. @@ -1373,11 +1287,12 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd // For HTLCs that the remote party settled, we'll fetch the original // offered HTLC from the local update log so we can retrieve the same - // PaymentDescriptor that ReceiveHTLCSettle would produce. + // paymentDescriptor that ReceiveHTLCSettle would produce. case *lnwire.UpdateFulfillHTLC: ogHTLC := localUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, RPreimage: wireMsg.PaymentPreimage, @@ -1393,7 +1308,8 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd case *lnwire.UpdateFailHTLC: ogHTLC := localUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1408,7 +1324,8 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd case *lnwire.UpdateFailMalformedHTLC: ogHTLC := localUpdateLog.lookupHtlc(wireMsg.ID) - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, Amount: ogHTLC.Amount, RHash: ogHTLC.RHash, ParentIndex: ogHTLC.HtlcIndex, @@ -1426,7 +1343,8 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd // height to the same value, as we consider the fee update locked in by // adding and removing it at the same height. case *lnwire.UpdateFee: - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: wireMsg.ChanID, LogIndex: logUpdate.LogIndex, Amount: lnwire.NewMSatFromSatoshis( btcutil.Amount(wireMsg.FeePerKw), @@ -2618,10 +2536,10 @@ type HtlcView struct { NextHeight uint64 // OurUpdates are our outgoing HTLCs. - OurUpdates []*PaymentDescriptor + OurUpdates []*paymentDescriptor // TheirUpdates are their incoming HTLCs. - TheirUpdates []*PaymentDescriptor + TheirUpdates []*paymentDescriptor // FeePerKw is the fee rate in sat/kw of the commitment transaction. FeePerKw chainfee.SatPerKWeight @@ -2633,7 +2551,7 @@ type HtlcView struct { func (lc *LightningChannel) fetchHTLCView(theirLogIndex, ourLogIndex uint64) *HtlcView { - var ourHTLCs []*PaymentDescriptor + var ourHTLCs []*paymentDescriptor for e := lc.updateLogs.Local.Front(); e != nil; e = e.Next() { htlc := e.Value @@ -2645,7 +2563,7 @@ func (lc *LightningChannel) fetchHTLCView(theirLogIndex, } } - var theirHTLCs []*PaymentDescriptor + var theirHTLCs []*paymentDescriptor for e := lc.updateLogs.Remote.Front(); e != nil; e = e.Next() { htlc := e.Value @@ -2783,13 +2701,13 @@ func (lc *LightningChannel) fetchCommitmentView( // commitment are mutated, we'll manually copy over each HTLC to its // respective slice. c.outgoingHTLCs = make( - []PaymentDescriptor, len(filteredHTLCView.OurUpdates), + []paymentDescriptor, len(filteredHTLCView.OurUpdates), ) for i, htlc := range filteredHTLCView.OurUpdates { c.outgoingHTLCs[i] = *htlc } c.incomingHTLCs = make( - []PaymentDescriptor, len(filteredHTLCView.TheirUpdates), + []paymentDescriptor, len(filteredHTLCView.TheirUpdates), ) for i, htlc := range filteredHTLCView.TheirUpdates { c.incomingHTLCs[i] = *htlc @@ -2964,9 +2882,9 @@ func (lc *LightningChannel) evaluateHTLCView(view *HtlcView, ourBalance, // fetchParent is a helper that looks up update log parent entries in the // appropriate log. -func (lc *LightningChannel) fetchParent(entry *PaymentDescriptor, +func (lc *LightningChannel) fetchParent(entry *paymentDescriptor, whoseCommitChain, whoseUpdateLog lntypes.ChannelParty, -) (*PaymentDescriptor, error) { +) (*paymentDescriptor, error) { var ( updateLog *updateLog @@ -3019,7 +2937,7 @@ func (lc *LightningChannel) fetchParent(entry *PaymentDescriptor, // If the HTLC hasn't yet been committed in either chain, then the height it // was committed is updated. Keeping track of this inclusion height allows us to // later compact the log once the change is fully committed in both chains. -func processAddEntry(htlc *PaymentDescriptor, ourBalance, +func processAddEntry(htlc *paymentDescriptor, ourBalance, theirBalance *lnwire.MilliSatoshi, nextHeight uint64, whoseCommitChain lntypes.ChannelParty, isIncoming, mutateState bool) { @@ -3057,7 +2975,7 @@ func processAddEntry(htlc *PaymentDescriptor, ourBalance, // processRemoveEntry processes a log entry which settles or times out a // previously added HTLC. If the removal entry has already been processed, it // is skipped. -func processRemoveEntry(htlc *PaymentDescriptor, ourBalance, +func processRemoveEntry(htlc *paymentDescriptor, ourBalance, theirBalance *lnwire.MilliSatoshi, nextHeight uint64, whoseCommitChain lntypes.ChannelParty, isIncoming, mutateState bool) { @@ -3106,7 +3024,7 @@ func processRemoveEntry(htlc *PaymentDescriptor, ourBalance, // processFeeUpdate processes a log update that updates the current commitment // fee. -func processFeeUpdate(feeUpdate *PaymentDescriptor, nextHeight uint64, +func processFeeUpdate(feeUpdate *paymentDescriptor, nextHeight uint64, whoseCommitChain lntypes.ChannelParty, mutateState bool, view *HtlcView) { @@ -3356,12 +3274,6 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing, func (lc *LightningChannel) createCommitDiff(newCommit *commitment, commitSig lnwire.Sig, htlcSigs []lnwire.Sig) *channeldb.CommitDiff { - // First, we need to convert the funding outpoint into the ID that's - // used on the wire to identify this channel. We'll use this shortly - // when recording the exact CommitSig message that we'll be sending - // out. - chanID := lnwire.NewChanIDFromOutPoint(lc.channelState.FundingOutpoint) - var ( logUpdates []channeldb.LogUpdate ackAddRefs []channeldb.AddRef @@ -3386,91 +3298,42 @@ func (lc *LightningChannel) createCommitDiff(newCommit *commitment, continue } - // Knowing that this update is a part of this new commitment, - // we'll create a log update and not its index in the log so - // we can later restore it properly if a restart occurs. - logUpdate := channeldb.LogUpdate{ - LogIndex: pd.LogIndex, - } - - // We'll map the type of the PaymentDescriptor to one of the + // We'll map the type of the paymentDescriptor to one of the // four messages that it corresponds to. With this set of // messages obtained, we can simply read from disk and re-send // them in the case of a needed channel sync. switch pd.EntryType { case Add: - htlc := &lnwire.UpdateAddHTLC{ - ChanID: chanID, - ID: pd.HtlcIndex, - Amount: pd.Amount, - Expiry: pd.Timeout, - PaymentHash: pd.RHash, - BlindingPoint: pd.BlindingPoint, - CustomRecords: pd.CustomRecords.Copy(), - } - copy(htlc.OnionBlob[:], pd.OnionBlob) - logUpdate.UpdateMsg = htlc - // Gather any references for circuits opened by this Add // HTLC. if pd.OpenCircuitKey != nil { - openCircuitKeys = append(openCircuitKeys, - *pd.OpenCircuitKey) + openCircuitKeys = append( + openCircuitKeys, *pd.OpenCircuitKey, + ) } - logUpdates = append(logUpdates, logUpdate) - - // Short circuit here since an add should not have any - // of the references gathered in the case of settles, - // fails or malformed fails. - continue - - case Settle: - logUpdate.UpdateMsg = &lnwire.UpdateFulfillHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - PaymentPreimage: pd.RPreimage, + case Settle, Fail, MalformedFail: + // Gather the fwd pkg references from any settle or fail + // packets, if they exist. + if pd.SourceRef != nil { + ackAddRefs = append(ackAddRefs, *pd.SourceRef) } - - case Fail: - logUpdate.UpdateMsg = &lnwire.UpdateFailHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - Reason: pd.FailReason, + if pd.DestRef != nil { + settleFailRefs = append( + settleFailRefs, *pd.DestRef, + ) } - - case MalformedFail: - logUpdate.UpdateMsg = &lnwire.UpdateFailMalformedHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - ShaOnionBlob: pd.ShaOnionBlob, - FailureCode: pd.FailCode, + if pd.ClosedCircuitKey != nil { + closedCircuitKeys = append( + closedCircuitKeys, *pd.ClosedCircuitKey, + ) } case FeeUpdate: - // The Amount field holds the feerate denominated in - // msat. Since feerates are only denominated in sat/kw, - // we can convert it without loss of precision. - logUpdate.UpdateMsg = &lnwire.UpdateFee{ - ChanID: chanID, - FeePerKw: uint32(pd.Amount.ToSatoshis()), - } + // Nothing special to do. } - // Gather the fwd pkg references from any settle or fail - // packets, if they exist. - if pd.SourceRef != nil { - ackAddRefs = append(ackAddRefs, *pd.SourceRef) - } - if pd.DestRef != nil { - settleFailRefs = append(settleFailRefs, *pd.DestRef) - } - if pd.ClosedCircuitKey != nil { - closedCircuitKeys = append(closedCircuitKeys, - *pd.ClosedCircuitKey) - } - - logUpdates = append(logUpdates, logUpdate) + logUpdates = append(logUpdates, pd.toLogUpdate()) } // With the set of log updates mapped into wire messages, we'll now @@ -3498,10 +3361,6 @@ func (lc *LightningChannel) createCommitDiff(newCommit *commitment, // getUnsignedAckedUpdates returns all remote log updates that we haven't // signed for yet ourselves. func (lc *LightningChannel) getUnsignedAckedUpdates() []channeldb.LogUpdate { - // First, we need to convert the funding outpoint into the ID that's - // used on the wire to identify this channel. - chanID := lnwire.NewChanIDFromOutPoint(lc.channelState.FundingOutpoint) - // Fetch the last remote update that we have signed for. lastRemoteCommitted := lc.commitChains.Remote.tail().messageIndices.Remote @@ -3532,60 +3391,9 @@ func (lc *LightningChannel) getUnsignedAckedUpdates() []channeldb.LogUpdate { continue } - logUpdate := channeldb.LogUpdate{ - LogIndex: pd.LogIndex, - } - - // We'll map the type of the PaymentDescriptor to one of the - // four messages that it corresponds to. - switch pd.EntryType { - case Add: - htlc := &lnwire.UpdateAddHTLC{ - ChanID: chanID, - ID: pd.HtlcIndex, - Amount: pd.Amount, - Expiry: pd.Timeout, - PaymentHash: pd.RHash, - BlindingPoint: pd.BlindingPoint, - CustomRecords: pd.CustomRecords.Copy(), - } - copy(htlc.OnionBlob[:], pd.OnionBlob) - logUpdate.UpdateMsg = htlc - - case Settle: - logUpdate.UpdateMsg = &lnwire.UpdateFulfillHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - PaymentPreimage: pd.RPreimage, - } - - case Fail: - logUpdate.UpdateMsg = &lnwire.UpdateFailHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - Reason: pd.FailReason, - } - - case MalformedFail: - logUpdate.UpdateMsg = &lnwire.UpdateFailMalformedHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - ShaOnionBlob: pd.ShaOnionBlob, - FailureCode: pd.FailCode, - } - - case FeeUpdate: - // The Amount field holds the feerate denominated in - // msat. Since feerates are only denominated in sat/kw, - // we can convert it without loss of precision. - logUpdate.UpdateMsg = &lnwire.UpdateFee{ - ChanID: chanID, - FeePerKw: uint32(pd.Amount.ToSatoshis()), - } - } - - logUpdates = append(logUpdates, logUpdate) + logUpdates = append(logUpdates, pd.toLogUpdate()) } + return logUpdates } @@ -3727,11 +3535,11 @@ func (lc *LightningChannel) applyCommitFee( // commitment transaction in terms of the ChannelConstraints that we and our // remote peer agreed upon during the funding workflow. The // predict[Our|Their]Add should parameters should be set to a valid -// PaymentDescriptor if we are validating in the state when adding a new HTLC, +// paymentDescriptor if we are validating in the state when adding a new HTLC, // or nil otherwise. func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, ourLogCounter uint64, whoseCommitChain lntypes.ChannelParty, - buffer BufferType, predictOurAdd, predictTheirAdd *PaymentDescriptor, + buffer BufferType, predictOurAdd, predictTheirAdd *paymentDescriptor, ) error { // First fetch the initial balance before applying any updates. @@ -3858,7 +3666,7 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, // validateUpdates take a set of updates, and validates them against // the passed channel constraints. - validateUpdates := func(updates []*PaymentDescriptor, + validateUpdates := func(updates []*paymentDescriptor, constraints *channeldb.ChannelConfig) error { // We keep track of the number of HTLCs in flight for the @@ -5470,15 +5278,10 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, // The returned values correspond to: // 1. The forwarding package corresponding to the remote commitment height // that was revoked. -// 2. The PaymentDescriptor of any Add HTLCs that were locked in by this -// revocation. -// 3. The PaymentDescriptor of any Settle/Fail HTLCs that were locked in by -// this revocation. -// 4. The set of HTLCs present on the current valid commitment transaction +// 2. The set of HTLCs present on the current valid commitment transaction // for the remote party. func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( - *channeldb.FwdPkg, []*PaymentDescriptor, []*PaymentDescriptor, - []channeldb.HTLC, error) { + *channeldb.FwdPkg, []channeldb.HTLC, error) { lc.Lock() defer lc.Unlock() @@ -5487,10 +5290,10 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( store := lc.channelState.RevocationStore revocation, err := chainhash.NewHash(revMsg.Revocation[:]) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } if err := store.AddNextEntry(revocation); err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } // Verify that if we use the commitment point computed based off of the @@ -5499,7 +5302,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( currentCommitPoint := lc.channelState.RemoteCurrentRevocation derivedCommitPoint := input.ComputeCommitmentPoint(revMsg.Revocation[:]) if !derivedCommitPoint.IsEqual(currentCommitPoint) { - return nil, nil, nil, nil, fmt.Errorf("revocation key mismatch") + return nil, nil, fmt.Errorf("revocation key mismatch") } // Now that we've verified that the prior commitment has been properly @@ -5521,7 +5324,6 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( localChainTail := lc.commitChains.Local.tail().height source := lc.ShortChanID() - chanID := lnwire.NewChanIDFromOutPoint(lc.channelState.FundingOutpoint) // Determine the set of htlcs that can be forwarded as a result of // having received the revocation. We will simultaneously construct the @@ -5529,10 +5331,8 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( // updates to disk and optimistically buffer the forwarding package in // memory. var ( - addsToForward []*PaymentDescriptor - addUpdates []channeldb.LogUpdate - settleFailsToForward []*PaymentDescriptor - settleFailUpdates []channeldb.LogUpdate + addUpdatesToForward []channeldb.LogUpdate + settleFailUpdatesToForward []channeldb.LogUpdate ) var addIndex, settleFailIndex uint16 @@ -5584,7 +5384,13 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( addIndex++ pd.isForwarded = true - addsToForward = append(addsToForward, pd) + + // At this point we put the update into our list of + // updates that we will eventually put into the + // FwdPkg at this height. + addUpdatesToForward = append( + addUpdatesToForward, pd.toLogUpdate(), + ) case pd.EntryType != Add && committedRmv && shouldFwdRmv: // Construct a reference specifying the location that @@ -5598,64 +5404,19 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( settleFailIndex++ pd.isForwarded = true - settleFailsToForward = append(settleFailsToForward, pd) + + // At this point we put the update into our list of + // updates that we will eventually put into the + // FwdPkg at this height. + settleFailUpdatesToForward = append( + settleFailUpdatesToForward, pd.toLogUpdate(), + ) default: + // The update was not "freshly locked in" so we will + // ignore it as we construct the forwarding package. continue } - - // If we've reached this point, this HTLC will be added to the - // forwarding package at the height of the remote commitment. - // All types of HTLCs will record their assigned log index. - logUpdate := channeldb.LogUpdate{ - LogIndex: pd.LogIndex, - } - - // Next, we'll map the type of the PaymentDescriptor to one of - // the four messages that it corresponds to and separate the - // updates into Adds and Settle/Fail/MalformedFail such that - // they can be written in the forwarding package. Adds are - // aggregated separately from the other types of HTLCs. - switch pd.EntryType { - case Add: - htlc := &lnwire.UpdateAddHTLC{ - ChanID: chanID, - ID: pd.HtlcIndex, - Amount: pd.Amount, - Expiry: pd.Timeout, - PaymentHash: pd.RHash, - BlindingPoint: pd.BlindingPoint, - CustomRecords: pd.CustomRecords.Copy(), - } - copy(htlc.OnionBlob[:], pd.OnionBlob) - logUpdate.UpdateMsg = htlc - addUpdates = append(addUpdates, logUpdate) - - case Settle: - logUpdate.UpdateMsg = &lnwire.UpdateFulfillHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - PaymentPreimage: pd.RPreimage, - } - settleFailUpdates = append(settleFailUpdates, logUpdate) - - case Fail: - logUpdate.UpdateMsg = &lnwire.UpdateFailHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - Reason: pd.FailReason, - } - settleFailUpdates = append(settleFailUpdates, logUpdate) - - case MalformedFail: - logUpdate.UpdateMsg = &lnwire.UpdateFailMalformedHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - ShaOnionBlob: pd.ShaOnionBlob, - FailureCode: pd.FailCode, - } - settleFailUpdates = append(settleFailUpdates, logUpdate) - } } // We use the remote commitment chain's tip as it will soon become the tail @@ -5664,14 +5425,15 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( localMessageIndex := lc.commitChains.Local.tail().messageIndices.Local localPeerUpdates := lc.unsignedLocalUpdates( - remoteMessageIndex, localMessageIndex, chanID, + remoteMessageIndex, localMessageIndex, ) // Now that we have gathered the set of HTLCs to forward, separated by // type, construct a forwarding package using the height that the remote // commitment chain will be extended after persisting the revocation. fwdPkg := channeldb.NewFwdPkg( - source, remoteChainTail, addUpdates, settleFailUpdates, + source, remoteChainTail, addUpdatesToForward, + settleFailUpdatesToForward, ) // We will soon be saving the current remote commitment to revocation @@ -5684,7 +5446,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( revocation, lc.channelState, lc.leafStore, ) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } // Now that we have a new verification nonce from them, we can refresh @@ -5692,7 +5454,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( if lc.channelState.ChanType.IsTaproot() { localNonce, err := revMsg.LocalNonce.UnwrapOrErrV(errNoNonce) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } session, err := lc.musigSessions.RemoteSession.Refresh( @@ -5701,7 +5463,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( }, ) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } lc.musigSessions.RemoteSession = session @@ -5717,7 +5479,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( ourOutputIndex, theirOutputIndex, ) if err != nil { - return nil, nil, nil, nil, err + return nil, nil, err } // Since they revoked the current lowest height in their commitment @@ -5734,7 +5496,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( remoteHTLCs := lc.channelState.RemoteCommitment.Htlcs - return fwdPkg, addsToForward, settleFailsToForward, remoteHTLCs, nil + return fwdPkg, remoteHTLCs, nil } // LoadFwdPkgs loads any pending log updates from disk and returns the payment @@ -5959,16 +5721,17 @@ func (lc *LightningChannel) MayAddOutgoingHtlc(amt lnwire.MilliSatoshi) error { // htlcAddDescriptor returns a payment descriptor for the htlc and open key // provided to add to our local update log. func (lc *LightningChannel) htlcAddDescriptor(htlc *lnwire.UpdateAddHTLC, - openKey *models.CircuitKey) *PaymentDescriptor { + openKey *models.CircuitKey) *paymentDescriptor { - return &PaymentDescriptor{ + return &paymentDescriptor{ + ChanID: htlc.ChanID, EntryType: Add, RHash: PaymentHash(htlc.PaymentHash), Timeout: htlc.Expiry, Amount: htlc.Amount, LogIndex: lc.updateLogs.Local.logIndex, HtlcIndex: lc.updateLogs.Local.htlcCounter, - OnionBlob: htlc.OnionBlob[:], + OnionBlob: htlc.OnionBlob, OpenCircuitKey: openKey, BlindingPoint: htlc.BlindingPoint, CustomRecords: htlc.CustomRecords.Copy(), @@ -5977,7 +5740,7 @@ func (lc *LightningChannel) htlcAddDescriptor(htlc *lnwire.UpdateAddHTLC, // validateAddHtlc validates the addition of an outgoing htlc to our local and // remote commitments. -func (lc *LightningChannel) validateAddHtlc(pd *PaymentDescriptor, +func (lc *LightningChannel) validateAddHtlc(pd *paymentDescriptor, buffer BufferType) error { // Make sure adding this HTLC won't violate any of the constraints we // must keep on the commitment transactions. @@ -6023,14 +5786,15 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, "ID %d", htlc.ID, lc.updateLogs.Remote.htlcCounter) } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: htlc.ChanID, EntryType: Add, RHash: PaymentHash(htlc.PaymentHash), Timeout: htlc.Expiry, Amount: htlc.Amount, LogIndex: lc.updateLogs.Remote.logIndex, HtlcIndex: lc.updateLogs.Remote.htlcCounter, - OnionBlob: htlc.OnionBlob[:], + OnionBlob: htlc.OnionBlob, BlindingPoint: htlc.BlindingPoint, CustomRecords: htlc.CustomRecords.Copy(), } @@ -6103,7 +5867,8 @@ func (lc *LightningChannel) SettleHTLC(preimage [32]byte, return ErrInvalidSettlePreimage{preimage[:], htlc.RHash[:]} } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), Amount: htlc.Amount, RPreimage: preimage, LogIndex: lc.updateLogs.Local.logIndex, @@ -6148,7 +5913,8 @@ func (lc *LightningChannel) ReceiveHTLCSettle(preimage [32]byte, htlcIndex uint6 return ErrInvalidSettlePreimage{preimage[:], htlc.RHash[:]} } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), Amount: htlc.Amount, RPreimage: preimage, ParentIndex: htlc.HtlcIndex, @@ -6209,7 +5975,8 @@ func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte, return ErrHtlcIndexAlreadyFailed(htlcIndex) } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), Amount: htlc.Amount, RHash: htlc.RHash, ParentIndex: htlcIndex, @@ -6259,7 +6026,8 @@ func (lc *LightningChannel) MalformedFailHTLC(htlcIndex uint64, return ErrHtlcIndexAlreadyFailed(htlcIndex) } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), Amount: htlc.Amount, RHash: htlc.RHash, ParentIndex: htlcIndex, @@ -6301,7 +6069,8 @@ func (lc *LightningChannel) ReceiveFailHTLC(htlcIndex uint64, reason []byte, return ErrHtlcIndexAlreadyFailed(htlcIndex) } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), Amount: htlc.Amount, RHash: htlc.RHash, ParentIndex: htlc.HtlcIndex, @@ -6327,6 +6096,12 @@ func (lc *LightningChannel) ChannelPoint() wire.OutPoint { return lc.channelState.FundingOutpoint } +// ChannelID returns the ChannelID of this LightningChannel. This is the same +// ChannelID that is used in update messages for this channel. +func (lc *LightningChannel) ChannelID() lnwire.ChannelID { + return lnwire.NewChanIDFromOutPoint(lc.ChannelPoint()) +} + // ShortChanID returns the short channel ID for the channel. The short channel // ID encodes the exact location in the main chain that the original // funding output can be found. @@ -8414,7 +8189,8 @@ func (lc *LightningChannel) UpdateFee(feePerKw chainfee.SatPerKWeight) error { return err } - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), LogIndex: lc.updateLogs.Local.logIndex, Amount: lnwire.NewMSatFromSatoshis(btcutil.Amount(feePerKw)), EntryType: FeeUpdate, @@ -8486,7 +8262,8 @@ func (lc *LightningChannel) ReceiveUpdateFee(feePerKw chainfee.SatPerKWeight) er } // TODO(roasbeef): or just modify to use the other balance? - pd := &PaymentDescriptor{ + pd := &paymentDescriptor{ + ChanID: lc.ChannelID(), LogIndex: lc.updateLogs.Remote.logIndex, Amount: lnwire.NewMSatFromSatoshis(btcutil.Amount(feePerKw)), EntryType: FeeUpdate, @@ -8958,7 +8735,7 @@ func (lc *LightningChannel) FwdMinHtlc() lnwire.MilliSatoshi { // NOTE: remoteMessageIndex is the height on the tip because this is called // before the tail is advanced to the tip during ReceiveRevocation. func (lc *LightningChannel) unsignedLocalUpdates(remoteMessageIndex, - localMessageIndex uint64, chanID lnwire.ChannelID) []channeldb.LogUpdate { + localMessageIndex uint64) []channeldb.LogUpdate { var localPeerUpdates []channeldb.LogUpdate for e := lc.updateLogs.Local.Front(); e != nil; e = e.Next() { @@ -8975,38 +8752,9 @@ func (lc *LightningChannel) unsignedLocalUpdates(remoteMessageIndex, // covered in the next commitment signature that the remote // sends. if pd.LogIndex < remoteMessageIndex && pd.LogIndex >= localMessageIndex { - logUpdate := channeldb.LogUpdate{ - LogIndex: pd.LogIndex, - } - - switch pd.EntryType { - case FeeUpdate: - logUpdate.UpdateMsg = &lnwire.UpdateFee{ - ChanID: chanID, - FeePerKw: uint32(pd.Amount.ToSatoshis()), - } - case Settle: - logUpdate.UpdateMsg = &lnwire.UpdateFulfillHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - PaymentPreimage: pd.RPreimage, - } - case Fail: - logUpdate.UpdateMsg = &lnwire.UpdateFailHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - Reason: pd.FailReason, - } - case MalformedFail: - logUpdate.UpdateMsg = &lnwire.UpdateFailMalformedHTLC{ - ChanID: chanID, - ID: pd.ParentIndex, - ShaOnionBlob: pd.ShaOnionBlob, - FailureCode: pd.FailCode, - } - } - - localPeerUpdates = append(localPeerUpdates, logUpdate) + localPeerUpdates = append( + localPeerUpdates, pd.toLogUpdate(), + ) } } diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 532d7b9a6..d97a92042 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -132,7 +132,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool, // Alice then processes this revocation, sending her own revocation for // her prior commitment transaction. Alice shouldn't have any HTLCs to // forward since she's sending an outgoing HTLC. - fwdPkg, _, _, _, err := aliceChannel.ReceiveRevocation(bobRevocation) + fwdPkg, _, err := aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to process bob's revocation") if len(fwdPkg.Adds) != 0 { t.Fatalf("alice forwards %v add htlcs, should forward none", @@ -157,7 +157,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool, // is fully locked in within both commitment transactions. Bob should // also be able to forward an HTLC now that the HTLC has been locked // into both commitment transactions. - fwdPkg, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + fwdPkg, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to process alice's revocation") if len(fwdPkg.Adds) != 1 { t.Fatalf("bob forwards %v add htlcs, should only forward one", @@ -249,7 +249,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool, aliceNewCommit, err = aliceChannel.SignNextCommitment() require.NoError(t, err, "alice unable to sign new commitment") - fwdPkg, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation2) + fwdPkg, _, err = bobChannel.ReceiveRevocation(aliceRevocation2) require.NoError(t, err, "bob unable to process alice's revocation") if len(fwdPkg.Adds) != 0 { t.Fatalf("bob forwards %v add htlcs, should forward none", @@ -286,7 +286,7 @@ func testAddSettleWorkflow(t *testing.T, tweakless bool, } } - fwdPkg, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation2) + fwdPkg, _, err = aliceChannel.ReceiveRevocation(bobRevocation2) require.NoError(t, err, "alice unable to process bob's revocation") if len(fwdPkg.Adds) != 0 { // Alice should now be able to forward the settlement HTLC to @@ -468,7 +468,7 @@ func TestChannelZeroAddLocalHeight(t *testing.T) { aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) // We now restore Alice's channel as this was the point at which @@ -643,7 +643,7 @@ func testCommitHTLCSigTieBreak(t *testing.T, restart bool) { bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke bob's commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive bob's revocation") // Now have Bob initiate the second half of the commitment dance. Here @@ -2554,7 +2554,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { // Alice receives the revocation of the old one, and can now assume // that Bob's received everything up to the signature she sent, // including the HTLC and fee update. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to process bob's revocation") // Alice receives new signature from Bob, and assumes this covers the @@ -2582,7 +2582,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { } // Bob receives revocation from Alice. - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to process alice's revocation") } @@ -2641,7 +2641,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { require.NoError(t, err, "unable to generate bob revocation") // Bob receives the revocation of the old commitment - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "alice unable to process bob's revocation") // Alice will sign next commitment. Since she sent the revocation, she @@ -2682,7 +2682,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { // Alice receives revocation from Bob, and can now be sure that Bob // received the two updates, and they are considered locked in. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "bob unable to process alice's revocation") // Alice will receive the signature from Bob, which will cover what was @@ -2710,7 +2710,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { } // Bob receives revocation from Alice. - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to process alice's revocation") } @@ -2819,7 +2819,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { // Alice receives the revocation of the old one, and can now assume that // Bob's received everything up to the signature she sent, including the // HTLC and fee update. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to process bob's revocation") // Alice receives new signature from Bob, and assumes this covers the @@ -2849,7 +2849,7 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { } // Bob receives revocation from Alice. - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to process alice's revocation") } @@ -3264,13 +3264,13 @@ func testChanSyncOweCommitment(t *testing.T, chanType channeldb.ChannelType) { require.NoError(t, err, "unable to revoke bob commitment") bobNewCommit, err := bobChannel.SignNextCommitment() require.NoError(t, err, "bob unable to sign commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(bobNewCommit.CommitSigs) require.NoError(t, err, "alice unable to rev bob's commitment") aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") // At this point, we'll now assert that their log states are what we @@ -3456,7 +3456,7 @@ func testChanSyncOweCommitmentPendingRemote(t *testing.T, t.Fatalf("unable to revoke commitment: %v", err) } - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevoke) + _, _, err = aliceChannel.ReceiveRevocation(bobRevoke) if err != nil { t.Fatalf("unable to revoke commitment: %v", err) } @@ -3492,7 +3492,7 @@ func testChanSyncOweCommitmentPendingRemote(t *testing.T, if err != nil { t.Fatal(err) } - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevoke) + _, _, err = bobChannel.ReceiveRevocation(aliceRevoke) if err != nil { t.Fatal(err) } @@ -3586,7 +3586,7 @@ func testChanSyncOweRevocation(t *testing.T, chanType channeldb.ChannelType) { bobNewCommit, err := bobChannel.SignNextCommitment() require.NoError(t, err, "bob unable to sign commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(bobNewCommit.CommitSigs) require.NoError(t, err, "alice unable to rev bob's commitment") @@ -3681,7 +3681,7 @@ func testChanSyncOweRevocation(t *testing.T, chanType channeldb.ChannelType) { // We'll continue by then allowing bob to process Alice's revocation // message. - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") // Finally, Alice will add an HTLC over her own such that we assert the @@ -3898,13 +3898,13 @@ func testChanSyncOweRevocationAndCommit(t *testing.T, // We'll now finish the state transition by having Alice process both // messages, and send her final revocation. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(bobNewCommit.CommitSigs) require.NoError(t, err, "alice unable to recv bob's commitment") aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") } @@ -3989,7 +3989,7 @@ func testChanSyncOweRevocationAndCommitForceTransition(t *testing.T, // local commit chain getting height > remote commit chain. aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") // Next, Alice will settle that incoming HTLC, then we'll start the @@ -4121,7 +4121,7 @@ func testChanSyncOweRevocationAndCommitForceTransition(t *testing.T, // Now, we'll continue the exchange, sending Bob's revocation and // signature message to Alice, ending with Alice sending her revocation // message to Bob. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(&CommitSigs{ CommitSig: bobSigMsg.CommitSig, @@ -4131,7 +4131,7 @@ func testChanSyncOweRevocationAndCommitForceTransition(t *testing.T, require.NoError(t, err, "alice unable to rev bob's commitment") aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") } @@ -4546,13 +4546,13 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) { require.NoError(t, err, "unable to revoke bob commitment") bobNewCommit, err := bobChannel.SignNextCommitment() require.NoError(t, err, "bob unable to sign commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(bobNewCommit.CommitSigs) require.NoError(t, err, "alice unable to rev bob's commitment") aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") // Both parties should now have the latest fee rate locked-in. @@ -4744,13 +4744,13 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) { require.NoError(t, err, "unable to revoke bob commitment") bobNewCommitSigs, err := bobChannel.SignNextCommitment() require.NoError(t, err, "bob unable to sign commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "alice unable to recv revocation") err = aliceChannel.ReceiveNewCommitment(bobNewCommitSigs.CommitSigs) require.NoError(t, err, "alice unable to rev bob's commitment") aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "alice unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to recv revocation") // Both parties should now have the latest fee rate locked-in. @@ -5459,7 +5459,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { } // Alice should detect that she doesn't need to forward any HTLC's. - fwdPkg, _, _, _, err := aliceChannel.ReceiveRevocation(bobRevocation) + fwdPkg, _, err := aliceChannel.ReceiveRevocation(bobRevocation) if err != nil { t.Fatal(err) } @@ -5490,7 +5490,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // Bob should now detect that he now has 2 incoming HTLC's that he can // forward along. - fwdPkg, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + fwdPkg, _, err = bobChannel.ReceiveRevocation(aliceRevocation) if err != nil { t.Fatal(err) } @@ -5535,7 +5535,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // At this point, Bob receives the revocation from Alice, which is now // his signal to examine all the HTLC's that have been locked in to // process. - fwdPkg, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + fwdPkg, _, err = bobChannel.ReceiveRevocation(aliceRevocation) if err != nil { t.Fatal(err) } @@ -5584,22 +5584,31 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // Alice should detect that she doesn't need to forward any Adds's, but // that the Fail has been locked in an can be forwarded. - _, adds, settleFails, _, err := aliceChannel.ReceiveRevocation(bobRevocation) + fwdPkg, _, err = aliceChannel.ReceiveRevocation(bobRevocation) if err != nil { t.Fatal(err) } + + adds := fwdPkg.Adds + settleFails := fwdPkg.SettleFails if len(adds) != 0 { t.Fatalf("alice shouldn't forward any HTLC's, instead wants to "+ - "forward %v htlcs", len(adds)) + "forward %v htlcs", len(fwdPkg.Adds)) } if len(settleFails) != 1 { t.Fatalf("alice should only forward %d HTLC's, instead wants to "+ - "forward %v htlcs", 1, len(settleFails)) + "forward %v htlcs", 1, len(fwdPkg.SettleFails)) } - if settleFails[0].ParentIndex != htlc.ID { + + fail, ok := settleFails[0].UpdateMsg.(*lnwire.UpdateFailHTLC) + if !ok { + t.Fatalf("expected UpdateFailHTLC, got %T", + settleFails[0].UpdateMsg) + } + if fail.ID != htlc.ID { t.Fatalf("alice should forward fail for htlcid=%d, instead "+ "forwarding id=%d", htlc.ID, - settleFails[0].ParentIndex) + fail.ID) } // We'll now restart both Alice and Bob. This emulates a reconnection @@ -5633,7 +5642,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // Alice should detect that she doesn't need to forward any HTLC's, as // the updates haven't been committed by Bob yet. - fwdPkg, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + fwdPkg, _, err = aliceChannel.ReceiveRevocation(bobRevocation) if err != nil { t.Fatal(err) } @@ -5664,7 +5673,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // Bob should detect that he has nothing to forward, as he hasn't // received any HTLCs. - fwdPkg, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + fwdPkg, _, err = bobChannel.ReceiveRevocation(aliceRevocation) if err != nil { t.Fatal(err) } @@ -5694,10 +5703,13 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { // When Alice receives the revocation, she should detect that she // can now forward the freshly locked-in Fail. - _, adds, settleFails, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + fwdPkg, _, err = aliceChannel.ReceiveRevocation(bobRevocation) if err != nil { t.Fatal(err) } + + adds = fwdPkg.Adds + settleFails = fwdPkg.SettleFails if len(adds) != 0 { t.Fatalf("alice shouldn't forward any HTLC's, instead wants to "+ "forward %v htlcs", len(adds)) @@ -5706,10 +5718,16 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { t.Fatalf("alice should only forward one HTLC, instead wants to "+ "forward %v htlcs", len(settleFails)) } - if settleFails[0].ParentIndex != htlc2.ID { + + fail, ok = settleFails[0].UpdateMsg.(*lnwire.UpdateFailHTLC) + if !ok { + t.Fatalf("expected UpdateFailHTLC, got %T", + settleFails[0].UpdateMsg) + } + if fail.ID != htlc2.ID { t.Fatalf("alice should forward fail for htlcid=%d, instead "+ "forwarding id=%d", htlc2.ID, - settleFails[0].ParentIndex) + fail.ID) } } @@ -6309,13 +6327,13 @@ func TestMaxAsynchronousHtlcs(t *testing.T) { bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke revocation") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive revocation") aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke revocation") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "unable to receive revocation") // Send the final Add which should succeed as in step 6. @@ -6878,8 +6896,8 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) { } } -// compareHtlcs compares two PaymentDescriptors. -func compareHtlcs(htlc1, htlc2 *PaymentDescriptor) error { +// compareHtlcs compares two paymentDescriptors. +func compareHtlcs(htlc1, htlc2 *paymentDescriptor) error { if htlc1.LogIndex != htlc2.LogIndex { return fmt.Errorf("htlc log index did not match") } @@ -6897,7 +6915,7 @@ func compareHtlcs(htlc1, htlc2 *PaymentDescriptor) error { } // compareIndexes is a helper method to compare two index maps. -func compareIndexes(a, b map[uint64]*fn.Node[*PaymentDescriptor]) error { +func compareIndexes(a, b map[uint64]*fn.Node[*paymentDescriptor]) error { for k1, e1 := range a { e2, ok := b[k1] if !ok { @@ -6997,7 +7015,7 @@ func TestChannelRestoreUpdateLogs(t *testing.T) { // sent. However her local commitment chain still won't include the // state with the HTLC, since she hasn't received a new commitment // signature from Bob yet. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive revocation") // Now make Alice send and sign an additional HTLC. We don't let Bob @@ -7173,7 +7191,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke commitment") - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "bob unable to process alice's revocation") // At this point Alice has advanced her local commitment chain to a @@ -7203,7 +7221,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { // the corresponding Fail from the local update log. bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err, "unable to revoke commitment") - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive revocation") assertInLogs(t, aliceChannel, 0, 0, 0, 0) @@ -7366,7 +7384,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { t.Fatalf("unable to create new channel: %v", err) } - var pd *PaymentDescriptor + var pd *paymentDescriptor if remoteLog { h := newChannel.updateLogs.Local.lookupHtlc(htlcIndex) if h != nil { @@ -7428,7 +7446,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { bobChannel = restoreAndAssertCommitHeights(t, bobChannel, true, 0, 1, 0) // Alice receives the revocation, ACKing her pending commitment. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive revocation") // However, the HTLC is still not locked into her local commitment, so @@ -7457,7 +7475,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { t, aliceChannel, false, 0, 1, 1, ) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "unable to receive revocation") // Alice ACKing Bob's pending commitment shouldn't change the heights @@ -7502,7 +7520,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { bobChannel = restoreAndAssertCommitHeights(t, bobChannel, true, 1, 2, 0) // Alice receives the revocation, ACKing her pending commitment for Bob. - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err, "unable to receive revocation") // Alice receiving Bob's revocation should bump both addCommitHeightRemote @@ -7540,7 +7558,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { // Bob receives the revocation, which should set both addCommitHeightRemote // fields to 2. - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err, "unable to receive revocation") bobChannel = restoreAndAssertCommitHeights(t, bobChannel, true, 0, 2, 2) @@ -7643,7 +7661,7 @@ func TestForceCloseBorkedState(t *testing.T) { // At this point, all channel mutating methods should now fail as they // shouldn't be able to proceed if the channel is borked. - _, _, _, _, err = aliceChannel.ReceiveRevocation(revokeMsg) + _, _, err = aliceChannel.ReceiveRevocation(revokeMsg) if err != channeldb.ErrChanBorked { t.Fatalf("advance commitment tail should have failed") } @@ -8134,8 +8152,8 @@ func TestFetchParent(t *testing.T) { name string whoseCommitChain lntypes.ChannelParty whoseUpdateLog lntypes.ChannelParty - localEntries []*PaymentDescriptor - remoteEntries []*PaymentDescriptor + localEntries []*paymentDescriptor + remoteEntries []*paymentDescriptor // parentIndex is the parent index of the entry that we will // lookup with fetch parent. @@ -8169,7 +8187,7 @@ func TestFetchParent(t *testing.T) { { name: "remote log + chain, remote add height 0", localEntries: nil, - remoteEntries: []*PaymentDescriptor{ + remoteEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8191,7 +8209,7 @@ func TestFetchParent(t *testing.T) { }, { name: "remote log, local chain, local add height 0", - remoteEntries: []*PaymentDescriptor{ + remoteEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8214,7 +8232,7 @@ func TestFetchParent(t *testing.T) { }, { name: "local log + chain, local add height 0", - localEntries: []*PaymentDescriptor{ + localEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8238,7 +8256,7 @@ func TestFetchParent(t *testing.T) { { name: "local log + remote chain, remote add height 0", - localEntries: []*PaymentDescriptor{ + localEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8262,7 +8280,7 @@ func TestFetchParent(t *testing.T) { { name: "remote log found", localEntries: nil, - remoteEntries: []*PaymentDescriptor{ + remoteEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8285,7 +8303,7 @@ func TestFetchParent(t *testing.T) { }, { name: "local log found", - localEntries: []*PaymentDescriptor{ + localEntries: []*paymentDescriptor{ // This entry will be added at log index =0. { HtlcIndex: 1, @@ -8331,7 +8349,7 @@ func TestFetchParent(t *testing.T) { } parent, err := lc.fetchParent( - &PaymentDescriptor{ + &paymentDescriptor{ ParentIndex: test.parentIndex, }, test.whoseCommitChain, @@ -8394,8 +8412,8 @@ func TestEvaluateView(t *testing.T) { tests := []struct { name string - ourHtlcs []*PaymentDescriptor - theirHtlcs []*PaymentDescriptor + ourHtlcs []*paymentDescriptor + theirHtlcs []*paymentDescriptor whoseCommitChain lntypes.ChannelParty mutateState bool @@ -8427,7 +8445,7 @@ func TestEvaluateView(t *testing.T) { name: "our fee update is applied", whoseCommitChain: lntypes.Local, mutateState: false, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { Amount: ourFeeUpdateAmt, EntryType: FeeUpdate, @@ -8444,8 +8462,8 @@ func TestEvaluateView(t *testing.T) { name: "their fee update is applied", whoseCommitChain: lntypes.Local, mutateState: false, - ourHtlcs: []*PaymentDescriptor{}, - theirHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{}, + theirHtlcs: []*paymentDescriptor{ { Amount: theirFeeUpdateAmt, EntryType: FeeUpdate, @@ -8462,14 +8480,14 @@ func TestEvaluateView(t *testing.T) { name: "htlcs adds without settles", whoseCommitChain: lntypes.Local, mutateState: false, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, EntryType: Add, }, }, - theirHtlcs: []*PaymentDescriptor{ + theirHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8496,7 +8514,7 @@ func TestEvaluateView(t *testing.T) { name: "our htlc settled, state mutated", whoseCommitChain: lntypes.Local, mutateState: true, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8504,7 +8522,7 @@ func TestEvaluateView(t *testing.T) { addCommitHeightLocal: addHeight, }, }, - theirHtlcs: []*PaymentDescriptor{ + theirHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8531,7 +8549,7 @@ func TestEvaluateView(t *testing.T) { name: "our htlc settled, state not mutated", whoseCommitChain: lntypes.Local, mutateState: false, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8539,7 +8557,7 @@ func TestEvaluateView(t *testing.T) { addCommitHeightLocal: addHeight, }, }, - theirHtlcs: []*PaymentDescriptor{ + theirHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8566,7 +8584,7 @@ func TestEvaluateView(t *testing.T) { name: "their htlc settled, state mutated", whoseCommitChain: lntypes.Local, mutateState: true, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8581,7 +8599,7 @@ func TestEvaluateView(t *testing.T) { ParentIndex: 1, }, }, - theirHtlcs: []*PaymentDescriptor{ + theirHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8610,7 +8628,7 @@ func TestEvaluateView(t *testing.T) { whoseCommitChain: lntypes.Local, mutateState: false, - ourHtlcs: []*PaymentDescriptor{ + ourHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8625,7 +8643,7 @@ func TestEvaluateView(t *testing.T) { ParentIndex: 0, }, }, - theirHtlcs: []*PaymentDescriptor{ + theirHtlcs: []*paymentDescriptor{ { HtlcIndex: 0, Amount: htlcAddAmount, @@ -8732,9 +8750,9 @@ func TestEvaluateView(t *testing.T) { // checkExpectedHtlcs checks that a set of htlcs that we have contains all the // htlcs we expect. -func checkExpectedHtlcs(t *testing.T, actual []*PaymentDescriptor, - expected map[uint64]bool, -) { +func checkExpectedHtlcs(t *testing.T, actual []*paymentDescriptor, + expected map[uint64]bool) { + if len(expected) != len(actual) { t.Fatalf("expected: %v htlcs, got: %v", len(expected), len(actual)) @@ -8924,7 +8942,7 @@ func TestProcessFeeUpdate(t *testing.T) { // Create a fee update with add and remove heights as // set in the test. heights := test.startHeights - update := &PaymentDescriptor{ + update := &paymentDescriptor{ Amount: ourFeeUpdateAmt, addCommitHeightRemote: heights.remoteAdd, addCommitHeightLocal: heights.localAdd, @@ -8951,7 +8969,7 @@ func TestProcessFeeUpdate(t *testing.T) { } } -func checkHeights(t *testing.T, update *PaymentDescriptor, expected heights) { +func checkHeights(t *testing.T, update *paymentDescriptor, expected heights) { updateHeights := heights{ localAdd: update.addCommitHeightLocal, localRemove: update.removeCommitHeightLocal, @@ -9320,7 +9338,7 @@ func TestProcessAddRemoveEntry(t *testing.T) { t.Parallel() heights := test.startHeights - update := &PaymentDescriptor{ + update := &paymentDescriptor{ Amount: updateAmount, addCommitHeightLocal: heights.localAdd, addCommitHeightRemote: heights.remoteAdd, @@ -9436,7 +9454,7 @@ func TestChannelUnsignedAckedFailure(t *testing.T) { // -----rev-----> aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) // Alice should sign the next commitment and go down before @@ -9461,7 +9479,7 @@ func TestChannelUnsignedAckedFailure(t *testing.T) { // <----rev------ bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = newAliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = newAliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) // Now Bob sends an HTLC to Alice. @@ -9547,7 +9565,7 @@ func TestChannelLocalUnsignedUpdatesFailure(t *testing.T) { // <----rev----- bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) // Restart Alice and assert that she can receive Bob's next commitment @@ -9631,7 +9649,7 @@ func TestChannelSignedAckRegression(t *testing.T) { // <----rev----- bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) // <----sig----- @@ -9658,7 +9676,7 @@ func TestChannelSignedAckRegression(t *testing.T) { // <----rev----- bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) // Restart Bob's channel state here. @@ -9671,7 +9689,7 @@ func TestChannelSignedAckRegression(t *testing.T) { // -----rev----> aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - fwdPkg, _, _, _, err := newBobChannel.ReceiveRevocation(aliceRevocation) + fwdPkg, _, err := newBobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) // Assert that the fwdpkg is not empty. @@ -9763,7 +9781,7 @@ func TestIsChannelClean(t *testing.T) { // <---rev--- bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) assertCleanOrDirty(false, aliceChannel, bobChannel, t) @@ -9777,7 +9795,7 @@ func TestIsChannelClean(t *testing.T) { // ---rev---> aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) assertCleanOrDirty(false, aliceChannel, bobChannel, t) @@ -9798,7 +9816,7 @@ func TestIsChannelClean(t *testing.T) { // ---rev---> aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) assertCleanOrDirty(false, aliceChannel, bobChannel, t) @@ -9812,7 +9830,7 @@ func TestIsChannelClean(t *testing.T) { // <---rev--- bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) assertCleanOrDirty(true, aliceChannel, bobChannel, t) @@ -9836,7 +9854,7 @@ func TestIsChannelClean(t *testing.T) { // <---rev--- bobRevocation, _, _, err = bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) assertCleanOrDirty(false, aliceChannel, bobChannel, t) @@ -9851,7 +9869,7 @@ func TestIsChannelClean(t *testing.T) { // ---rev---> aliceRevocation, _, _, err = aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) assertCleanOrDirty(true, aliceChannel, bobChannel, t) } @@ -9994,7 +10012,7 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) { // dust. bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) checkDust(aliceChannel, htlc2Amt, htlc2Amt) checkDust(bobChannel, htlc2Amt, htlc2Amt) @@ -10007,7 +10025,7 @@ func testGetDustSum(t *testing.T, chantype channeldb.ChannelType) { require.NoError(t, err) aliceRevocation, _, _, err := aliceChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) + _, _, err = bobChannel.ReceiveRevocation(aliceRevocation) require.NoError(t, err) checkDust(aliceChannel, htlc2Amt, htlc2Amt) checkDust(bobChannel, htlc2Amt, htlc2Amt) @@ -10513,7 +10531,7 @@ func testNewBreachRetribution(t *testing.T, chanType channeldb.ChannelType) { } // TestExtractPayDescs asserts that `extractPayDescs` can correctly turn a -// slice of htlcs into two slices of PaymentDescriptors. +// slice of htlcs into two slices of paymentDescriptors. func TestExtractPayDescs(t *testing.T) { t.Parallel() @@ -10550,24 +10568,24 @@ func TestExtractPayDescs(t *testing.T) { ) require.NoError(t, err) - // Assert the incoming PaymentDescriptors are matched. + // Assert the incoming paymentDescriptors are matched. for i, pd := range incomingPDs { htlc := incomings[i] assertPayDescMatchHTLC(t, pd, htlc) } - // Assert the outgoing PaymentDescriptors are matched. + // Assert the outgoing paymentDescriptors are matched. for i, pd := range outgoingPDs { htlc := outgoings[i] assertPayDescMatchHTLC(t, pd, htlc) } } -// assertPayDescMatchHTLC compares a PaymentDescriptor to a channeldb.HTLC and +// assertPayDescMatchHTLC compares a paymentDescriptor to a channeldb.HTLC and // asserts that the fields are matched. -func assertPayDescMatchHTLC(t *testing.T, pd PaymentDescriptor, - htlc channeldb.HTLC, -) { +func assertPayDescMatchHTLC(t *testing.T, pd paymentDescriptor, + htlc channeldb.HTLC) { + require := require.New(t) require.EqualValues(htlc.RHash, pd.RHash, "RHash") @@ -10967,7 +10985,7 @@ func TestAsynchronousSendingWithFeeBuffer(t *testing.T) { bobRevocation, _, _, err := bobChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) + _, _, err = aliceChannel.ReceiveRevocation(bobRevocation) require.NoError(t, err) // Before testing the behavior of the fee buffer, we are going to fail diff --git a/lnwallet/commitment.go b/lnwallet/commitment.go index 2ff23ab63..73565ea18 100644 --- a/lnwallet/commitment.go +++ b/lnwallet/commitment.go @@ -1229,10 +1229,10 @@ func genHtlcScript(chanType channeldb.ChannelType, isIncoming bool, // is incoming and if it's being applied to our commitment transaction or that // of the remote node's. Additionally, in order to be able to efficiently // locate the added HTLC on the commitment transaction from the -// PaymentDescriptor that generated it, the generated script is stored within +// paymentDescriptor that generated it, the generated script is stored within // the descriptor itself. func addHTLC(commitTx *wire.MsgTx, whoseCommit lntypes.ChannelParty, - isIncoming bool, paymentDesc *PaymentDescriptor, + isIncoming bool, paymentDesc *paymentDescriptor, keyRing *CommitmentKeyRing, chanType channeldb.ChannelType, auxLeaf input.AuxTapLeaf) error { @@ -1253,7 +1253,7 @@ func addHTLC(commitTx *wire.MsgTx, whoseCommit lntypes.ChannelParty, amountPending := int64(paymentDesc.Amount.ToSatoshis()) commitTx.AddTxOut(wire.NewTxOut(amountPending, pkScript)) - // Store the pkScript of this particular PaymentDescriptor so we can + // Store the pkScript of this particular paymentDescriptor so we can // quickly locate it within the commitment transaction later. if whoseCommit.IsLocal() { paymentDesc.ourPkScript = pkScript diff --git a/lnwallet/payment_descriptor.go b/lnwallet/payment_descriptor.go index 6fe74bb6f..5a51f29ce 100644 --- a/lnwallet/payment_descriptor.go +++ b/lnwallet/payment_descriptor.go @@ -62,14 +62,19 @@ func (u updateType) String() string { } } -// PaymentDescriptor represents a commitment state update which either adds, -// settles, or removes an HTLC. PaymentDescriptors encapsulate all necessary +// paymentDescriptor represents a commitment state update which either adds, +// settles, or removes an HTLC. paymentDescriptors encapsulate all necessary // metadata w.r.t to an HTLC, and additional data pairing a settle message to // the original added HTLC. // // TODO(roasbeef): LogEntry interface?? // - need to separate attrs for cancel/add/settle/feeupdate -type PaymentDescriptor struct { +type paymentDescriptor struct { + // ChanID is the ChannelID of the LightningChannel that this + // paymentDescriptor belongs to. We track this here so we can + // reconstruct the Messages that this paymentDescriptor is built from. + ChanID lnwire.ChannelID + // RHash is the payment hash for this HTLC. The HTLC can be settled iff // the preimage to this hash is presented. RHash PaymentHash @@ -165,7 +170,7 @@ type PaymentDescriptor struct { // removeCommitHeight[Remote|Local] encodes the height of the // commitment which removed the parent pointer of this - // PaymentDescriptor either due to a timeout or a settle. Once both + // paymentDescriptor either due to a timeout or a settle. Once both // these heights are below the tail of both chains, the log entries can // safely be removed. removeCommitHeightRemote uint64 @@ -175,7 +180,7 @@ type PaymentDescriptor struct { // routing. // // NOTE: Populated only on add payment descriptor entry types. - OnionBlob []byte + OnionBlob [lnwire.OnionPacketSize]byte // ShaOnionBlob is a sha of the onion blob. // @@ -194,7 +199,7 @@ type PaymentDescriptor struct { // [our|their|]PkScript are the raw public key scripts that encodes the // redemption rules for this particular HTLC. These fields will only be - // populated iff the EntryType of this PaymentDescriptor is Add. + // populated iff the EntryType of this paymentDescriptor is Add. // ourPkScript is the ourPkScript from the context of our local // commitment chain. theirPkScript is the latest pkScript from the // context of the remote commitment chain. @@ -207,7 +212,7 @@ type PaymentDescriptor struct { theirPkScript []byte theirWitnessScript []byte - // EntryType denotes the exact type of the PaymentDescriptor. In the + // EntryType denotes the exact type of the paymentDescriptor. In the // case of a Timeout, or Settle type, then the Parent field will point // into the log to the HTLC being modified. EntryType updateType @@ -226,3 +231,56 @@ type PaymentDescriptor struct { // may have been attached to a sent HTLC. CustomRecords lnwire.CustomRecords } + +// toLogUpdate recovers the underlying LogUpdate from the paymentDescriptor. +// This operation is lossy and will forget some extra information tracked by the +// paymentDescriptor but the function is total in that all paymentDescriptors +// can be converted back to LogUpdates. +func (pd *paymentDescriptor) toLogUpdate() channeldb.LogUpdate { + var msg lnwire.Message + switch pd.EntryType { + case Add: + msg = &lnwire.UpdateAddHTLC{ + ChanID: pd.ChanID, + ID: pd.HtlcIndex, + Amount: pd.Amount, + PaymentHash: pd.RHash, + Expiry: pd.Timeout, + OnionBlob: pd.OnionBlob, + BlindingPoint: pd.BlindingPoint, + CustomRecords: pd.CustomRecords.Copy(), + } + case Settle: + msg = &lnwire.UpdateFulfillHTLC{ + ChanID: pd.ChanID, + ID: pd.ParentIndex, + PaymentPreimage: pd.RPreimage, + } + case Fail: + msg = &lnwire.UpdateFailHTLC{ + ChanID: pd.ChanID, + ID: pd.ParentIndex, + Reason: pd.FailReason, + } + case MalformedFail: + msg = &lnwire.UpdateFailMalformedHTLC{ + ChanID: pd.ChanID, + ID: pd.ParentIndex, + ShaOnionBlob: pd.ShaOnionBlob, + FailureCode: pd.FailCode, + } + case FeeUpdate: + // The Amount field holds the feerate denominated in + // msat. Since feerates are only denominated in sat/kw, + // we can convert it without loss of precision. + msg = &lnwire.UpdateFee{ + ChanID: pd.ChanID, + FeePerKw: uint32(pd.Amount.ToSatoshis()), + } + } + + return channeldb.LogUpdate{ + LogIndex: pd.LogIndex, + UpdateMsg: msg, + } +} diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 5e0cac1f8..a9f71f24c 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -566,7 +566,7 @@ func ForceStateTransition(chanA, chanB *LightningChannel) error { return err } - _, _, _, _, err = chanA.ReceiveRevocation(bobRevocation) + _, _, err = chanA.ReceiveRevocation(bobRevocation) if err != nil { return err } @@ -579,7 +579,7 @@ func ForceStateTransition(chanA, chanB *LightningChannel) error { if err != nil { return err } - _, _, _, _, err = chanB.ReceiveRevocation(aliceRevocation) + _, _, err = chanB.ReceiveRevocation(aliceRevocation) if err != nil { return err } diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 439e7ce95..3588acfeb 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -366,7 +366,7 @@ func testVectors(t *testing.T, chanType channeldb.ChannelType, test testCase) { revMsg, _, _, err := remoteChannel.RevokeCurrentCommitment() require.NoError(t, err) - _, _, _, _, err = localChannel.ReceiveRevocation(revMsg) + _, _, err = localChannel.ReceiveRevocation(revMsg) require.NoError(t, err) remoteNewCommit, err := remoteChannel.SignNextCommitment() diff --git a/lnwallet/update_log.go b/lnwallet/update_log.go index 5b9d6c565..42e5373a2 100644 --- a/lnwallet/update_log.go +++ b/lnwallet/update_log.go @@ -29,16 +29,16 @@ type updateLog struct { // List is the updatelog itself, we embed this value so updateLog has // access to all the method of a list.List. - *fn.List[*PaymentDescriptor] + *fn.List[*paymentDescriptor] // updateIndex maps a `logIndex` to a particular update entry. It // deals with the four update types: // `Fail|MalformedFail|Settle|FeeUpdate` - updateIndex map[uint64]*fn.Node[*PaymentDescriptor] + updateIndex map[uint64]*fn.Node[*paymentDescriptor] // htlcIndex maps a `htlcCounter` to an offered HTLC entry, hence the // `Add` update. - htlcIndex map[uint64]*fn.Node[*PaymentDescriptor] + htlcIndex map[uint64]*fn.Node[*paymentDescriptor] // modifiedHtlcs is a set that keeps track of all the current modified // htlcs, hence update types `Fail|MalformedFail|Settle`. A modified @@ -50,9 +50,9 @@ type updateLog struct { // newUpdateLog creates a new updateLog instance. func newUpdateLog(logIndex, htlcCounter uint64) *updateLog { return &updateLog{ - List: fn.NewList[*PaymentDescriptor](), - updateIndex: make(map[uint64]*fn.Node[*PaymentDescriptor]), - htlcIndex: make(map[uint64]*fn.Node[*PaymentDescriptor]), + List: fn.NewList[*paymentDescriptor](), + updateIndex: make(map[uint64]*fn.Node[*paymentDescriptor]), + htlcIndex: make(map[uint64]*fn.Node[*paymentDescriptor]), logIndex: logIndex, htlcCounter: htlcCounter, modifiedHtlcs: fn.NewSet[uint64](), @@ -64,7 +64,7 @@ func newUpdateLog(logIndex, htlcCounter uint64) *updateLog { // state. This function differs from appendHtlc in that it won't increment // either of log's counters. If the HTLC is already present, then it is // ignored. -func (u *updateLog) restoreHtlc(pd *PaymentDescriptor) { +func (u *updateLog) restoreHtlc(pd *paymentDescriptor) { if _, ok := u.htlcIndex[pd.HtlcIndex]; ok { return } @@ -74,7 +74,7 @@ func (u *updateLog) restoreHtlc(pd *PaymentDescriptor) { // appendUpdate appends a new update to the tip of the updateLog. The entry is // also added to index accordingly. -func (u *updateLog) appendUpdate(pd *PaymentDescriptor) { +func (u *updateLog) appendUpdate(pd *paymentDescriptor) { u.updateIndex[u.logIndex] = u.PushBack(pd) u.logIndex++ } @@ -82,13 +82,13 @@ func (u *updateLog) appendUpdate(pd *PaymentDescriptor) { // restoreUpdate appends a new update to the tip of the updateLog. The entry is // also added to index accordingly. This function differs from appendUpdate in // that it won't increment the log index counter. -func (u *updateLog) restoreUpdate(pd *PaymentDescriptor) { +func (u *updateLog) restoreUpdate(pd *paymentDescriptor) { u.updateIndex[pd.LogIndex] = u.PushBack(pd) } // appendHtlc appends a new HTLC offer to the tip of the update log. The entry // is also added to the offer index accordingly. -func (u *updateLog) appendHtlc(pd *PaymentDescriptor) { +func (u *updateLog) appendHtlc(pd *paymentDescriptor) { u.htlcIndex[u.htlcCounter] = u.PushBack(pd) u.htlcCounter++ @@ -97,7 +97,7 @@ func (u *updateLog) appendHtlc(pd *PaymentDescriptor) { // lookupHtlc attempts to look up an offered HTLC according to its offer // index. If the entry isn't found, then a nil pointer is returned. -func (u *updateLog) lookupHtlc(i uint64) *PaymentDescriptor { +func (u *updateLog) lookupHtlc(i uint64) *paymentDescriptor { htlc, ok := u.htlcIndex[i] if !ok { return nil @@ -145,7 +145,7 @@ func compactLogs(ourLog, theirLog *updateLog, localChainTail, remoteChainTail uint64) { compactLog := func(logA, logB *updateLog) { - var nextA *fn.Node[*PaymentDescriptor] + var nextA *fn.Node[*paymentDescriptor] for e := logA.Front(); e != nil; e = nextA { // Assign next iteration element at top of loop because // we may remove the current element from the list, diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 66db6a9f5..f8a8bf069 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -10,6 +10,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/tlv" ) @@ -1271,14 +1272,19 @@ func (f *FailInvalidBlinding) Encode(w *bytes.Buffer, _ uint32) error { } // NewInvalidBlinding creates new instance of FailInvalidBlinding. -func NewInvalidBlinding(onion []byte) *FailInvalidBlinding { +func NewInvalidBlinding( + onion fn.Option[[OnionPacketSize]byte]) *FailInvalidBlinding { // The spec allows empty onion hashes for invalid blinding, so we only // include our onion hash if it's provided. - if onion == nil { + if onion.IsNone() { return &FailInvalidBlinding{} } - return &FailInvalidBlinding{OnionSHA256: sha256.Sum256(onion)} + shaSum := fn.MapOptionZ(onion, func(o [OnionPacketSize]byte) [32]byte { + return sha256.Sum256(o[:]) + }) + + return &FailInvalidBlinding{OnionSHA256: shaSum} } // DecodeFailure decodes, validates, and parses the lnwire onion failure, for diff --git a/lnwire/onion_error_test.go b/lnwire/onion_error_test.go index a06c572dc..bc14d5d42 100644 --- a/lnwire/onion_error_test.go +++ b/lnwire/onion_error_test.go @@ -9,11 +9,12 @@ import ( "testing" "github.com/davecgh/go-spew/spew" + "github.com/lightningnetwork/lnd/fn" "github.com/stretchr/testify/require" ) var ( - testOnionHash = []byte{} + testOnionHash = [OnionPacketSize]byte{} testAmount = MilliSatoshi(1) testCtlvExpiry = uint32(2) testFlags = uint16(2) @@ -43,9 +44,9 @@ var onionFailures = []FailureMessage{ &FailMPPTimeout{}, NewFailIncorrectDetails(99, 100), - NewInvalidOnionVersion(testOnionHash), - NewInvalidOnionHmac(testOnionHash), - NewInvalidOnionKey(testOnionHash), + NewInvalidOnionVersion(testOnionHash[:]), + NewInvalidOnionHmac(testOnionHash[:]), + NewInvalidOnionKey(testOnionHash[:]), NewTemporaryChannelFailure(&testChannelUpdate), NewTemporaryChannelFailure(nil), NewAmountBelowMinimum(testAmount, testChannelUpdate), @@ -56,7 +57,7 @@ var onionFailures = []FailureMessage{ NewFinalIncorrectCltvExpiry(testCtlvExpiry), NewFinalIncorrectHtlcAmount(testAmount), NewInvalidOnionPayload(testType, testOffset), - NewInvalidBlinding(testOnionHash), + NewInvalidBlinding(fn.Some(testOnionHash)), } // TestEncodeDecodeCode tests the ability of onion errors to be properly encoded