mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-26 01:33:02 +01:00
multi: fix up custom records
This commit is contained in:
parent
a7fa041a0b
commit
8a4531fc96
@ -2550,6 +2550,8 @@ type HTLC struct {
|
||||
// HTLC. It is stored in the ExtraData field, which is used to store
|
||||
// a TLV stream of additional information associated with the HTLC.
|
||||
BlindingPoint lnwire.BlindingPointRecord
|
||||
|
||||
CustomRecords lnwire.CustomRecords
|
||||
}
|
||||
|
||||
// serializeExtraData encodes a TLV stream of extra data to be stored with a
|
||||
@ -2568,6 +2570,11 @@ func (h *HTLC) serializeExtraData() error {
|
||||
records = append(records, &b)
|
||||
})
|
||||
|
||||
records, err := h.CustomRecords.ExtendRecordProducers(records)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return h.ExtraData.PackRecords(records...)
|
||||
}
|
||||
|
||||
@ -2589,8 +2596,19 @@ func (h *HTLC) deserializeExtraData() error {
|
||||
|
||||
if val, ok := tlvMap[h.BlindingPoint.TlvType()]; ok && val == nil {
|
||||
h.BlindingPoint = tlv.SomeRecordT(blindingPoint)
|
||||
|
||||
// Remove the entry from the TLV map. Anything left in the map
|
||||
// will be included in the custom records field.
|
||||
delete(tlvMap, h.BlindingPoint.TlvType())
|
||||
}
|
||||
|
||||
// Set the custom records field to the remaining TLV records.
|
||||
customRecords, err := lnwire.NewCustomRecordsFromTlvTypeMap(tlvMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.CustomRecords = customRecords
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -2728,6 +2746,7 @@ func (h *HTLC) Copy() HTLC {
|
||||
copy(clone.Signature[:], h.Signature)
|
||||
copy(clone.RHash[:], h.RHash[:])
|
||||
copy(clone.ExtraData, h.ExtraData)
|
||||
clone.CustomRecords = h.CustomRecords.Copy()
|
||||
|
||||
return clone
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
@ -489,8 +490,6 @@ func (s *InterceptableSwitch) interceptForward(packet *htlcPacket,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
packet.wireRecords = record.CustomSet(htlc.CustomRecords)
|
||||
|
||||
intercepted := &interceptedForward{
|
||||
htlc: htlc,
|
||||
packet: packet,
|
||||
@ -633,7 +632,7 @@ func (f *interceptedForward) Packet() InterceptedPacket {
|
||||
CustomRecords: f.packet.customRecords,
|
||||
OnionBlob: f.htlc.OnionBlob,
|
||||
AutoFailHeight: f.autoFailHeight,
|
||||
CustomPeerRecords: f.packet.wireRecords,
|
||||
WireCustomRecords: record.CustomSet(f.htlc.CustomRecords),
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,6 +684,8 @@ func (f *interceptedForward) ResumeModified(
|
||||
}
|
||||
}
|
||||
|
||||
log.Tracef("Forwarding packet %v", spew.Sdump(f.packet))
|
||||
|
||||
// Forward to the switch. A link quit channel isn't needed, because we
|
||||
// are on a different thread now.
|
||||
return f.htlcSwitch.ForwardPackets(nil, f.packet)
|
||||
|
@ -368,9 +368,9 @@ type InterceptedPacket struct {
|
||||
// OnionBlob is the onion packet for the next hop
|
||||
OnionBlob [lnwire.OnionPacketSize]byte
|
||||
|
||||
// CustomPeerRecords are user-defined records that were defined by the
|
||||
// WireCustomRecords are user-defined records that were defined by the
|
||||
// peer that forwarded this htlc to us.
|
||||
CustomPeerRecords record.CustomSet
|
||||
WireCustomRecords record.CustomSet
|
||||
|
||||
// AutoFailHeight is the block height at which this intercept will be
|
||||
// failed back automatically.
|
||||
|
@ -3376,7 +3376,29 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
|
||||
Amount: fwdInfo.AmountToForward,
|
||||
PaymentHash: pd.RHash,
|
||||
BlindingPoint: fwdInfo.NextBlinding,
|
||||
CustomRecords: pd.WireRecords,
|
||||
}
|
||||
|
||||
err = fn.MapOptionZ(
|
||||
pd.CustomRecords,
|
||||
func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(
|
||||
b,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addMsg.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
l.fail(LinkFailureError{
|
||||
code: ErrInternalError,
|
||||
}, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, we'll encode the onion packet for
|
||||
@ -3423,7 +3445,26 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
|
||||
Amount: fwdInfo.AmountToForward,
|
||||
PaymentHash: pd.RHash,
|
||||
BlindingPoint: fwdInfo.NextBlinding,
|
||||
CustomRecords: pd.WireRecords,
|
||||
}
|
||||
|
||||
err = fn.MapOptionZ(
|
||||
pd.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addMsg.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
l.fail(LinkFailureError{
|
||||
code: ErrInternalError,
|
||||
}, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finally, we'll encode the onion packet for the
|
||||
|
@ -98,10 +98,6 @@ type htlcPacket struct {
|
||||
// were included in the payload.
|
||||
customRecords record.CustomSet
|
||||
|
||||
// wireRecords are user-defined records in the custom type range that
|
||||
// were included in the peer's wire message.
|
||||
wireRecords record.CustomSet
|
||||
|
||||
// originalOutgoingChanID is used when sending back failure messages.
|
||||
// It is only used for forwarded Adds on option_scid_alias channels.
|
||||
// This is to avoid possible confusion if a payer uses the public SCID
|
||||
|
@ -2484,11 +2484,13 @@ func (s *Switch) getLinkByMapping(pkt *htlcPacket) (ChannelLink, error) {
|
||||
chanID := pkt.outgoingChanID
|
||||
aliasID := s.cfg.IsAlias(chanID)
|
||||
|
||||
_, haveAliasMapping := s.aliasToReal[chanID]
|
||||
|
||||
// Set the originalOutgoingChanID so the proper channel_update can be
|
||||
// sent back if the option-scid-alias feature bit was negotiated.
|
||||
pkt.originalOutgoingChanID = chanID
|
||||
|
||||
if aliasID {
|
||||
if aliasID || haveAliasMapping {
|
||||
// Since outgoingChanID is an alias, we'll fetch the link via
|
||||
// baseIndex.
|
||||
baseScid, ok := s.baseIndex[chanID]
|
||||
|
@ -93,7 +93,7 @@ func (r *forwardInterceptor) onIntercept(
|
||||
CustomRecords: htlc.CustomRecords,
|
||||
OnionBlob: htlc.OnionBlob[:],
|
||||
AutoFailHeight: htlc.AutoFailHeight,
|
||||
WireCustomRecords: htlc.CustomPeerRecords,
|
||||
WireCustomRecords: htlc.WireCustomRecords,
|
||||
}
|
||||
|
||||
return r.stream.Send(interceptionRequest)
|
||||
|
@ -335,7 +335,7 @@ type PaymentDescriptor struct {
|
||||
// NOTE: Populated only on add payment descriptor entry types.
|
||||
OnionBlob []byte
|
||||
|
||||
// CustomRecrods also stores the set of optional custom records that
|
||||
// CustomRecords also stores the set of optional custom records that
|
||||
// may have been attached to a sent HTLC.
|
||||
CustomRecords fn.Option[tlv.Blob]
|
||||
|
||||
@ -383,10 +383,6 @@ type PaymentDescriptor struct {
|
||||
// blinded route (ie, not the introduction node) from update_add_htlc's
|
||||
// TLVs.
|
||||
BlindingPoint lnwire.BlindingPointRecord
|
||||
|
||||
// WireRecords contains the TLV records blob that was included in
|
||||
// the original wire message that added this HTLC.
|
||||
WireRecords lnwire.CustomRecords
|
||||
}
|
||||
|
||||
// AddHeight returns a pointer to the height at which the HTLC was added to the
|
||||
@ -454,6 +450,17 @@ func PayDescsFromRemoteLogUpdates(chanID lnwire.ShortChannelID, height uint64,
|
||||
pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob))
|
||||
copy(pd.OnionBlob[:], wireMsg.OnionBlob[:])
|
||||
|
||||
if len(wireMsg.CustomRecords) > 0 {
|
||||
b, err := wireMsg.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error "+
|
||||
"serializing custom records: "+
|
||||
"%w", err)
|
||||
}
|
||||
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
case *lnwire.UpdateFulfillHTLC:
|
||||
pd = PaymentDescriptor{
|
||||
RPreimage: wireMsg.PaymentPreimage,
|
||||
@ -745,7 +752,9 @@ func (c *commitment) populateHtlcIndexes(chanType channeldb.ChannelType,
|
||||
|
||||
// toDiskCommit converts the target commitment into a format suitable to be
|
||||
// written to disk after an accepted state transition.
|
||||
func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
|
||||
func (c *commitment) toDiskCommit(ourCommit bool) (*channeldb.ChannelCommitment,
|
||||
error) {
|
||||
|
||||
numHtlcs := len(c.outgoingHTLCs) + len(c.incomingHTLCs)
|
||||
|
||||
commit := &channeldb.ChannelCommitment{
|
||||
@ -782,11 +791,23 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
|
||||
}
|
||||
copy(h.OnionBlob[:], htlc.OnionBlob)
|
||||
|
||||
// If the HTLC had custom records, then we'll copy that over so
|
||||
// If the HTLC had custom records, then we'll copy that over, so
|
||||
// we restore with the same information.
|
||||
htlc.CustomRecords.WhenSome(func(b tlv.Blob) {
|
||||
copy(h.ExtraData[:], b[:])
|
||||
})
|
||||
err := fn.MapOptionZ(
|
||||
htlc.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ourCommit && htlc.sig != nil {
|
||||
h.Signature = htlc.sig.Serialize()
|
||||
@ -813,11 +834,23 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
|
||||
}
|
||||
copy(h.OnionBlob[:], htlc.OnionBlob)
|
||||
|
||||
// If the HTLC had custom records, then we'll copy that over so
|
||||
// If the HTLC had custom records, then we'll copy that over, so
|
||||
// we restore with the same information.
|
||||
htlc.CustomRecords.WhenSome(func(b tlv.Blob) {
|
||||
copy(h.ExtraData[:], b[:])
|
||||
})
|
||||
err := fn.MapOptionZ(
|
||||
htlc.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ourCommit && htlc.sig != nil {
|
||||
h.Signature = htlc.sig.Serialize()
|
||||
@ -826,7 +859,7 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
|
||||
commit.Htlcs = append(commit.Htlcs, h)
|
||||
}
|
||||
|
||||
return commit
|
||||
return commit, nil
|
||||
}
|
||||
|
||||
// diskHtlcToPayDesc converts an HTLC previously written to disk within a
|
||||
@ -920,8 +953,12 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
|
||||
|
||||
// Ensure that we'll restore any custom records which were stored as
|
||||
// extra data on disk.
|
||||
if len(htlc.ExtraData) != 0 {
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](htlc.ExtraData)
|
||||
if len(htlc.CustomRecords) != 0 {
|
||||
b, err := htlc.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return pd, err
|
||||
}
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
return pd, nil
|
||||
@ -1678,6 +1715,16 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
|
||||
pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob))
|
||||
copy(pd.OnionBlob[:], wireMsg.OnionBlob[:])
|
||||
|
||||
if len(wireMsg.CustomRecords) > 0 {
|
||||
b, err := wireMsg.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error serializing "+
|
||||
"custom records: %w", err)
|
||||
}
|
||||
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
isDustRemote := HtlcIsDust(
|
||||
lc.channelState.ChanType, false, false, feeRate,
|
||||
wireMsg.Amount.ToSatoshis(), remoteDustLimit,
|
||||
@ -1883,6 +1930,16 @@ func (lc *LightningChannel) remoteLogUpdateToPayDesc(logUpdate *channeldb.LogUpd
|
||||
pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob))
|
||||
copy(pd.OnionBlob, wireMsg.OnionBlob[:])
|
||||
|
||||
if len(wireMsg.CustomRecords) > 0 {
|
||||
b, err := wireMsg.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error serializing "+
|
||||
"custom records: %w", err)
|
||||
}
|
||||
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
// We don't need to generate an htlc script yet. This will be
|
||||
// done once we sign our remote commitment.
|
||||
|
||||
@ -3620,9 +3677,14 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
|
||||
var err error
|
||||
cancelChan := make(chan struct{})
|
||||
|
||||
diskCommit, err := remoteCommitView.toDiskCommit(true)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("unable to convert "+
|
||||
"commitment: %w", err)
|
||||
}
|
||||
|
||||
auxLeaves, err := AuxLeavesFromCommit(
|
||||
chanState, *remoteCommitView.toDiskCommit(false), leafStore,
|
||||
*keyRing,
|
||||
chanState, *diskCommit, leafStore, *keyRing,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("unable to fetch aux leaves: "+
|
||||
@ -3866,6 +3928,26 @@ func (lc *LightningChannel) createCommitDiff(newCommit *commitment,
|
||||
BlindingPoint: pd.BlindingPoint,
|
||||
}
|
||||
copy(htlc.OnionBlob[:], pd.OnionBlob)
|
||||
|
||||
// Copy over any custom records as extra data that we
|
||||
// may not explicitly know about.
|
||||
err := fn.MapOptionZ(
|
||||
pd.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlc.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error mapping custom "+
|
||||
"records: %w", err)
|
||||
}
|
||||
|
||||
logUpdate.UpdateMsg = htlc
|
||||
|
||||
// Gather any references for circuits opened by this Add
|
||||
@ -3875,14 +3957,6 @@ func (lc *LightningChannel) createCommitDiff(newCommit *commitment,
|
||||
*pd.OpenCircuitKey)
|
||||
}
|
||||
|
||||
// Copy over any custom records as extra data that we
|
||||
// may not explicitly know about.
|
||||
pd.CustomRecords.WhenSome(func(b tlv.Blob) {
|
||||
// TODO(roasbeef): needs to merge w/ existing
|
||||
// TLVs
|
||||
copy(htlc.ExtraData[:], b[:])
|
||||
})
|
||||
|
||||
logUpdates = append(logUpdates, logUpdate)
|
||||
|
||||
// Short circuit here since an add should not have any
|
||||
@ -3941,7 +4015,11 @@ func (lc *LightningChannel) createCommitDiff(newCommit *commitment,
|
||||
// With the set of log updates mapped into wire messages, we'll now
|
||||
// convert the in-memory commit into a format suitable for writing to
|
||||
// disk.
|
||||
diskCommit := newCommit.toDiskCommit(false)
|
||||
diskCommit, err := newCommit.toDiskCommit(false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting commitment to disk "+
|
||||
"commit: %w", err)
|
||||
}
|
||||
|
||||
auxSigBlob, err := packSigs(auxSigs, lc.auxSigner)
|
||||
if err != nil {
|
||||
@ -3968,7 +4046,9 @@ 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 {
|
||||
func (lc *LightningChannel) getUnsignedAckedUpdates() ([]channeldb.LogUpdate,
|
||||
error) {
|
||||
|
||||
// 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)
|
||||
@ -4018,6 +4098,26 @@ func (lc *LightningChannel) getUnsignedAckedUpdates() []channeldb.LogUpdate {
|
||||
BlindingPoint: pd.BlindingPoint,
|
||||
}
|
||||
copy(htlc.OnionBlob[:], pd.OnionBlob)
|
||||
|
||||
// Copy over any custom records as extra data that we
|
||||
// may not explicitly know about.
|
||||
err := fn.MapOptionZ(
|
||||
pd.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlc.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error mapping custom "+
|
||||
"records: %w", err)
|
||||
}
|
||||
|
||||
logUpdate.UpdateMsg = htlc
|
||||
|
||||
case Settle:
|
||||
@ -4054,7 +4154,7 @@ func (lc *LightningChannel) getUnsignedAckedUpdates() []channeldb.LogUpdate {
|
||||
|
||||
logUpdates = append(logUpdates, logUpdate)
|
||||
}
|
||||
return logUpdates
|
||||
return logUpdates, nil
|
||||
}
|
||||
|
||||
// CalcFeeBuffer calculates a FeeBuffer in accordance with the recommended
|
||||
@ -5157,8 +5257,14 @@ func genHtlcSigValidationJobs(chanState *channeldb.OpenChannel,
|
||||
verifyJobs := make([]VerifyJob, 0, numHtlcs)
|
||||
auxVerifyJobs := make([]AuxVerifyJob, 0, numHtlcs)
|
||||
|
||||
diskCommit, err := localCommitmentView.toDiskCommit(true)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to convert commitment: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
auxLeaves, err := AuxLeavesFromCommit(
|
||||
chanState, *localCommitmentView.toDiskCommit(true), leafStore,
|
||||
chanState, *diskCommit, leafStore,
|
||||
*keyRing,
|
||||
)
|
||||
if err != nil {
|
||||
@ -5938,12 +6044,18 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck,
|
||||
// Additionally, generate a channel delta for this state transition for
|
||||
// persistent storage.
|
||||
chainTail := lc.localCommitChain.tail()
|
||||
newCommitment := chainTail.toDiskCommit(true)
|
||||
newCommitment, err := chainTail.toDiskCommit(true)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Get the unsigned acked remotes updates that are currently in memory.
|
||||
// We need them after a restart to sync our remote commitment with what
|
||||
// is committed locally.
|
||||
unsignedAckedUpdates := lc.getUnsignedAckedUpdates()
|
||||
unsignedAckedUpdates, err := lc.getUnsignedAckedUpdates()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
finalHtlcs, err := lc.channelState.UpdateCommitment(
|
||||
newCommitment, unsignedAckedUpdates,
|
||||
@ -6132,6 +6244,26 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
|
||||
BlindingPoint: pd.BlindingPoint,
|
||||
}
|
||||
copy(htlc.OnionBlob[:], pd.OnionBlob)
|
||||
|
||||
// Copy over any custom records as extra data that we
|
||||
// may not explicitly know about.
|
||||
err := fn.MapOptionZ(
|
||||
pd.CustomRecords, func(b tlv.Blob) error {
|
||||
r, err := lnwire.ParseCustomRecords(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlc.CustomRecords = r
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("error "+
|
||||
"mapping custom records: %w", err)
|
||||
}
|
||||
|
||||
logUpdate.UpdateMsg = htlc
|
||||
addUpdates = append(addUpdates, logUpdate)
|
||||
|
||||
@ -6333,7 +6465,11 @@ func (lc *LightningChannel) addHTLC(htlc *lnwire.UpdateAddHTLC,
|
||||
lc.Lock()
|
||||
defer lc.Unlock()
|
||||
|
||||
pd := lc.htlcAddDescriptor(htlc, openKey)
|
||||
pd, err := lc.htlcAddDescriptor(htlc, openKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err := lc.validateAddHtlc(pd, buffer); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -6437,12 +6573,16 @@ func (lc *LightningChannel) MayAddOutgoingHtlc(amt lnwire.MilliSatoshi) error {
|
||||
// to the commitment so that we validate commitment slots rather than
|
||||
// available balance, since our actual htlc amount is unknown at this
|
||||
// stage.
|
||||
pd := lc.htlcAddDescriptor(
|
||||
pd, err := lc.htlcAddDescriptor(
|
||||
&lnwire.UpdateAddHTLC{
|
||||
Amount: mockHtlcAmt,
|
||||
},
|
||||
&models.CircuitKey{},
|
||||
)
|
||||
if err != nil {
|
||||
lc.log.Errorf("Error adding htlc descriptor: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Enforce the FeeBuffer because we are evaluating whether we can add
|
||||
// another htlc to the channel state.
|
||||
@ -6457,7 +6597,7 @@ 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, error) {
|
||||
|
||||
pd := &PaymentDescriptor{
|
||||
EntryType: Add,
|
||||
@ -6473,11 +6613,17 @@ func (lc *LightningChannel) htlcAddDescriptor(htlc *lnwire.UpdateAddHTLC,
|
||||
|
||||
// Copy over any extra data included to ensure we can forward and
|
||||
// process this HTLC properly.
|
||||
if len(htlc.ExtraData) != 0 {
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](htlc.ExtraData[:])
|
||||
if len(htlc.CustomRecords) > 0 {
|
||||
b, err := htlc.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error serializing custom "+
|
||||
"records: %w", err)
|
||||
}
|
||||
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
return pd
|
||||
return pd, nil
|
||||
}
|
||||
|
||||
// validateAddHtlc validates the addition of an outgoing htlc to our local and
|
||||
@ -6535,13 +6681,16 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err
|
||||
HtlcIndex: lc.remoteUpdateLog.htlcCounter,
|
||||
OnionBlob: htlc.OnionBlob[:],
|
||||
BlindingPoint: htlc.BlindingPoint,
|
||||
WireRecords: htlc.CustomRecords,
|
||||
}
|
||||
|
||||
// Copy over any extra data included to ensure we can forward and
|
||||
// process this HTLC properly.
|
||||
if htlc.ExtraData != nil {
|
||||
pd.CustomRecords = fn.Some(tlv.Blob(htlc.ExtraData[:]))
|
||||
if len(htlc.CustomRecords) > 0 {
|
||||
b, err := htlc.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error serializing custom "+
|
||||
"records: %w", err)
|
||||
}
|
||||
|
||||
pd.CustomRecords = fn.Some[tlv.Blob](b)
|
||||
}
|
||||
|
||||
localACKedIndex := lc.remoteCommitChain.tail().ourMessageIndex
|
||||
|
@ -1,6 +1,7 @@
|
||||
package lnwire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
@ -13,13 +14,33 @@ const (
|
||||
MinCustomRecordsTlvType = 65536
|
||||
)
|
||||
|
||||
// ParseCustomRecords decodes a set of custom records from a byte slice.
|
||||
func ParseCustomRecords(b tlv.Blob) (CustomRecords, error) {
|
||||
stream, err := tlv.NewStream()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating stream: %w", err)
|
||||
}
|
||||
|
||||
typeMap, err := stream.DecodeWithParsedTypes(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding HTLC record: %w", err)
|
||||
}
|
||||
|
||||
customRecords := make(CustomRecords, len(typeMap))
|
||||
for k, v := range typeMap {
|
||||
customRecords[uint64(k)] = v
|
||||
}
|
||||
|
||||
return customRecords, nil
|
||||
}
|
||||
|
||||
// CustomRecords stores a set of custom key/value pairs. Map keys are TLV types
|
||||
// which must be greater than or equal to MinCustomRecordsTlvType.
|
||||
type CustomRecords map[uint64][]byte
|
||||
|
||||
// NewCustomRecordsFromTlvTypeMap creates a new CustomRecords instance from a
|
||||
// tlv.TypeMap.
|
||||
func NewCustomRecordsFromTlvTypeMap(tlvMap tlv.TypeMap) (*CustomRecords,
|
||||
func NewCustomRecordsFromTlvTypeMap(tlvMap tlv.TypeMap) (CustomRecords,
|
||||
error) {
|
||||
|
||||
customRecords := make(CustomRecords, len(tlvMap))
|
||||
@ -34,16 +55,16 @@ func NewCustomRecordsFromTlvTypeMap(tlvMap tlv.TypeMap) (*CustomRecords,
|
||||
"validation error: %v", err)
|
||||
}
|
||||
|
||||
return &customRecords, nil
|
||||
return customRecords, nil
|
||||
}
|
||||
|
||||
// Validate checks that all custom records are in the custom type range.
|
||||
func (c *CustomRecords) Validate() error {
|
||||
func (c CustomRecords) Validate() error {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for key := range *c {
|
||||
for key := range c {
|
||||
if key < MinCustomRecordsTlvType {
|
||||
return fmt.Errorf("custom records entry with TLV "+
|
||||
"type below min: %d", MinCustomRecordsTlvType)
|
||||
@ -53,15 +74,23 @@ func (c *CustomRecords) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CustomRecords) Copy() CustomRecords {
|
||||
customRecords := make(CustomRecords, len(c))
|
||||
for k, v := range c {
|
||||
customRecords[k] = v
|
||||
}
|
||||
return customRecords
|
||||
}
|
||||
|
||||
// ExtendRecordProducers extends the given records slice with the custom
|
||||
// records. The resultant records slice will be sorted if the given records
|
||||
// slice contains TLV types greater than or equal to MinCustomRecordsTlvType.
|
||||
func (c *CustomRecords) ExtendRecordProducers(
|
||||
records []tlv.RecordProducer) ([]tlv.RecordProducer, error) {
|
||||
func (c CustomRecords) ExtendRecordProducers(
|
||||
producers []tlv.RecordProducer) ([]tlv.RecordProducer, error) {
|
||||
|
||||
// If the custom records are nil or empty, there is nothing to do.
|
||||
if c == nil || len(*c) == 0 {
|
||||
return records, nil
|
||||
if c == nil || len(c) == 0 {
|
||||
return producers, nil
|
||||
}
|
||||
|
||||
// Validate the custom records.
|
||||
@ -78,11 +107,11 @@ func (c *CustomRecords) ExtendRecordProducers(
|
||||
// Ensure that the existing records slice TLV types are not also present
|
||||
// in the custom records. If they are, the resultant extended records
|
||||
// slice would erroneously contain duplicate TLV types.
|
||||
for _, recordProducer := range records {
|
||||
record := recordProducer.Record()
|
||||
for _, rp := range producers {
|
||||
record := rp.Record()
|
||||
recordTlvType := uint64(record.Type())
|
||||
|
||||
_, foundDuplicateTlvType := (*c)[recordTlvType]
|
||||
_, foundDuplicateTlvType := c[recordTlvType]
|
||||
if foundDuplicateTlvType {
|
||||
return nil, fmt.Errorf("custom records contains a TLV "+
|
||||
"type that is already present in the "+
|
||||
@ -97,23 +126,36 @@ func (c *CustomRecords) ExtendRecordProducers(
|
||||
|
||||
// Convert the custom records map to a TLV record producer slice and
|
||||
// append them to the exiting records slice.
|
||||
crRecords := tlv.MapToRecords(*c)
|
||||
crRecords := tlv.MapToRecords(c)
|
||||
for _, record := range crRecords {
|
||||
r := recordProducer{record}
|
||||
records = append(records, &r)
|
||||
producers = append(producers, &r)
|
||||
}
|
||||
|
||||
// If the records slice which was given as an argument included TLV
|
||||
// values greater than or equal to the minimum custom records TLV type
|
||||
// we will sort the extended records slice to ensure that it is ordered
|
||||
// correctly.
|
||||
if maxRecordTlvType >= MinCustomRecordsTlvType {
|
||||
sort.Slice(records, func(i, j int) bool {
|
||||
recordI := records[i].Record()
|
||||
recordJ := records[j].Record()
|
||||
return recordI.Type() < recordJ.Type()
|
||||
})
|
||||
sort.Slice(producers, func(i, j int) bool {
|
||||
recordI := producers[i].Record()
|
||||
recordJ := producers[j].Record()
|
||||
return recordI.Type() < recordJ.Type()
|
||||
})
|
||||
|
||||
return producers, nil
|
||||
}
|
||||
|
||||
func (c CustomRecords) Serialize() ([]byte, error) {
|
||||
records := tlv.MapToRecords(c)
|
||||
stream, err := tlv.NewStream(records...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating stream: %w", err)
|
||||
}
|
||||
|
||||
return records, nil
|
||||
var b bytes.Buffer
|
||||
if err := stream.Encode(&b); err != nil {
|
||||
return nil, fmt.Errorf("error encoding custom records: %w", err)
|
||||
}
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
@ -71,7 +71,8 @@ func (e *ExtraOpaqueData) PackRecords(recordProducers ...tlv.RecordProducer) err
|
||||
return err
|
||||
}
|
||||
|
||||
*e = append(extraBytesWriter.Bytes(), *e...)
|
||||
// *e = append(extraBytesWriter.Bytes(), *e...)
|
||||
*e = ExtraOpaqueData(extraBytesWriter.Bytes())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ func (c *UpdateAddHTLC) Decode(r io.Reader, pver uint32) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.CustomRecords = *customRecords
|
||||
c.CustomRecords = customRecords
|
||||
|
||||
// Set extra data to nil if we didn't parse anything out of it so that
|
||||
// we can use assert.Equal in tests.
|
||||
|
@ -610,22 +610,15 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
|
||||
|
||||
if source == self {
|
||||
|
||||
firstHopTLVs := tlv.MapToRecords(r.FirstHopCustomRecords)
|
||||
wireRecords := fn.Map(func(r tlv.Record) tlv.RecordProducer {
|
||||
return &r
|
||||
}, firstHopTLVs)
|
||||
|
||||
firstHopData := lnwire.ExtraOpaqueData{}
|
||||
|
||||
err := firstHopData.PackRecords(wireRecords...)
|
||||
customRecords := lnwire.CustomRecords(r.FirstHopCustomRecords)
|
||||
firstHopData, err := customRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
tlvOption := fn.Some[tlv.Blob](firstHopData)
|
||||
max, total, err := getOutgoingBalance(
|
||||
self, outgoingChanMap, g.bandwidthHints, g.graph,
|
||||
tlvOption,
|
||||
fn.Some[tlv.Blob](firstHopData),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/routing/shards"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
// ErrPaymentLifecycleExiting is used when waiting for htlc attempt result, but
|
||||
@ -680,28 +679,32 @@ func (p *paymentLifecycle) sendAttempt(
|
||||
}
|
||||
|
||||
// If we had any first hop TLVs, then we'll encode that here now.
|
||||
firstHopTLVs := tlv.MapToRecords(p.firstHopTLVs)
|
||||
wireRecords := fn.Map(func(r tlv.Record) tlv.RecordProducer {
|
||||
return &r
|
||||
}, firstHopTLVs)
|
||||
if err := htlcAdd.ExtraData.PackRecords(wireRecords...); err != nil {
|
||||
return nil, err
|
||||
htlcAdd.CustomRecords = lnwire.CustomRecords(p.firstHopTLVs)
|
||||
encodedRecords, err := htlcAdd.CustomRecords.Serialize()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to encode first hop TLVs: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
// If a hook exists that may affect our outgoing message, we call it now
|
||||
// and apply its side effects to the UpdateAddHTLC message.
|
||||
err := fn.MapOptionZ(
|
||||
err = fn.MapOptionZ(
|
||||
p.router.cfg.TrafficShaper,
|
||||
func(ts TlvTrafficShaper) error {
|
||||
newAmt, newData, err := ts.ProduceHtlcExtraData(
|
||||
rt.TotalAmount, htlcAdd.ExtraData,
|
||||
rt.TotalAmount, encodedRecords,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcAdd.ExtraData = newData
|
||||
htlcAdd.Amount = lnwire.MilliSatoshi(newAmt * 1000)
|
||||
customRecords, err := lnwire.ParseCustomRecords(newData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcAdd.CustomRecords = customRecords
|
||||
htlcAdd.Amount = lnwire.NewMSatFromSatoshis(newAmt)
|
||||
|
||||
return nil
|
||||
},
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
)
|
||||
|
||||
// preimageSubscriber reprints an active subscription to be notified once the
|
||||
@ -101,10 +102,11 @@ func (p *preimageBeacon) SubscribeUpdates(
|
||||
ChanID: chanID,
|
||||
HtlcID: htlc.HtlcIndex,
|
||||
},
|
||||
OutgoingChanID: payload.FwdInfo.NextHop,
|
||||
OutgoingExpiry: payload.FwdInfo.OutgoingCTLV,
|
||||
OutgoingAmount: payload.FwdInfo.AmountToForward,
|
||||
CustomRecords: payload.CustomRecords(),
|
||||
OutgoingChanID: payload.FwdInfo.NextHop,
|
||||
OutgoingExpiry: payload.FwdInfo.OutgoingCTLV,
|
||||
OutgoingAmount: payload.FwdInfo.AmountToForward,
|
||||
CustomRecords: payload.CustomRecords(),
|
||||
WireCustomRecords: record.CustomSet(htlc.CustomRecords),
|
||||
}
|
||||
copy(packet.OnionBlob[:], nextHopOnionBlob)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user