Add ChanEdgePolicyFromWire to construct ChannelEdgePolicy from channel update messages, centralizing v1/v2 field mapping. Update call sites to use the helper: - discovery/gossiper: handleChanUpdate - graph/builder: ApplyChannelUpdate - routing/router_test: ApplyChannelUpdate test helper This consolidates update-to-policy conversion logic across versions.
194 lines
6.9 KiB
Go
194 lines
6.9 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/lightningnetwork/lnd/fn/v2"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
)
|
|
|
|
// ChannelEdgePolicy represents a *directed* edge within the channel graph. For
|
|
// each channel in the database, there are two distinct edges: one for each
|
|
// possible direction of travel along the channel. The edges themselves hold
|
|
// information concerning fees, and minimum time-lock information which is
|
|
// utilized during path finding.
|
|
type ChannelEdgePolicy struct {
|
|
// Version is the gossip version of the channel update that produced
|
|
// this policy.
|
|
Version lnwire.GossipVersion
|
|
|
|
// SigBytes is the raw bytes of the signature of the channel edge
|
|
// policy. We'll only parse these if the caller needs to access the
|
|
// signature for validation purposes.
|
|
SigBytes []byte
|
|
|
|
// ChannelID is the unique channel ID for the channel. The first 3
|
|
// bytes are the block height, the next 3 the index within the block,
|
|
// and the last 2 bytes are the output index for the channel.
|
|
ChannelID uint64
|
|
|
|
// LastUpdate is the last time an authenticated edge for this channel
|
|
// was received.
|
|
LastUpdate time.Time
|
|
|
|
// LastBlockHeight is the block height that timestamps the last update
|
|
// for v2 channel updates.
|
|
LastBlockHeight uint32
|
|
|
|
// SecondPeer indicates whether this policy was announced by the second
|
|
// peer in the channel for v2 channel updates.
|
|
SecondPeer bool
|
|
|
|
// MessageFlags is a bitfield which indicates the presence of optional
|
|
// fields (like max_htlc) in the policy.
|
|
MessageFlags lnwire.ChanUpdateMsgFlags
|
|
|
|
// ChannelFlags is a bitfield which signals the capabilities of the
|
|
// channel as well as the directed edge this update applies to.
|
|
ChannelFlags lnwire.ChanUpdateChanFlags
|
|
|
|
// DisableFlags is a v2-specific bitfield which signals whether the
|
|
// channel is disabled for incoming or outgoing traffic.
|
|
DisableFlags lnwire.ChanUpdateDisableFlags
|
|
|
|
// TimeLockDelta is the number of blocks this node will subtract from
|
|
// the expiry of an incoming HTLC. This value expresses the time buffer
|
|
// the node would like to HTLC exchanges.
|
|
TimeLockDelta uint16
|
|
|
|
// MinHTLC is the smallest value HTLC this node will forward, expressed
|
|
// in millisatoshi.
|
|
MinHTLC lnwire.MilliSatoshi
|
|
|
|
// MaxHTLC is the largest value HTLC this node will forward, expressed
|
|
// in millisatoshi.
|
|
MaxHTLC lnwire.MilliSatoshi
|
|
|
|
// FeeBaseMSat is the base HTLC fee that will be charged for forwarding
|
|
// ANY HTLC, expressed in mSAT's.
|
|
FeeBaseMSat lnwire.MilliSatoshi
|
|
|
|
// FeeProportionalMillionths is the rate that the node will charge for
|
|
// HTLCs for each millionth of a satoshi forwarded.
|
|
FeeProportionalMillionths lnwire.MilliSatoshi
|
|
|
|
// ToNode is the public key of the node that this directed edge leads
|
|
// to. Using this pub key, the channel graph can further be traversed.
|
|
ToNode [33]byte
|
|
|
|
// InboundFee is the fee that must be paid for incoming HTLCs.
|
|
//
|
|
// NOTE: for our kvdb implementation of the graph store, inbound fees
|
|
// are still only persisted as part of extra opaque data and so this
|
|
// field is not explicitly stored but is rather populated from the
|
|
// ExtraOpaqueData field on deserialization. For our SQL implementation,
|
|
// this field will be explicitly persisted in the database.
|
|
InboundFee fn.Option[lnwire.Fee]
|
|
|
|
// ExtraOpaqueData is the set of data that was appended to this
|
|
// message, some of which we may not actually know how to iterate or
|
|
// parse. By holding onto this data, we ensure that we're able to
|
|
// properly validate the set of signatures that cover these new fields,
|
|
// and ensure we're able to make upgrades to the network in a forwards
|
|
// compatible manner.
|
|
ExtraOpaqueData lnwire.ExtraOpaqueData
|
|
|
|
// ExtraSignedFields are the extra signed fields found in v2 channel
|
|
// updates.
|
|
ExtraSignedFields map[uint64][]byte
|
|
}
|
|
|
|
// ChanEdgePolicyFromWire constructs a ChannelEdgePolicy from a channel update
|
|
// message.
|
|
func ChanEdgePolicyFromWire(scid uint64,
|
|
update lnwire.ChannelUpdate) (*ChannelEdgePolicy, error) {
|
|
|
|
switch upd := update.(type) {
|
|
case *lnwire.ChannelUpdate1:
|
|
//nolint:ll
|
|
return &ChannelEdgePolicy{
|
|
Version: lnwire.GossipVersion1,
|
|
SigBytes: upd.Signature.ToSignatureBytes(),
|
|
ChannelID: scid,
|
|
LastUpdate: time.Unix(int64(upd.Timestamp), 0),
|
|
MessageFlags: upd.MessageFlags,
|
|
ChannelFlags: upd.ChannelFlags,
|
|
TimeLockDelta: upd.TimeLockDelta,
|
|
MinHTLC: upd.HtlcMinimumMsat,
|
|
MaxHTLC: upd.HtlcMaximumMsat,
|
|
FeeBaseMSat: lnwire.MilliSatoshi(upd.BaseFee),
|
|
FeeProportionalMillionths: lnwire.MilliSatoshi(upd.FeeRate),
|
|
InboundFee: upd.InboundFee.ValOpt(),
|
|
ExtraOpaqueData: upd.ExtraOpaqueData,
|
|
}, nil
|
|
|
|
case *lnwire.ChannelUpdate2:
|
|
return &ChannelEdgePolicy{
|
|
Version: lnwire.GossipVersion2,
|
|
SigBytes: upd.Signature.Val.ToSignatureBytes(),
|
|
ChannelID: scid,
|
|
LastBlockHeight: upd.BlockHeight.Val,
|
|
SecondPeer: upd.SecondPeer.IsSome(),
|
|
DisableFlags: upd.DisabledFlags.Val,
|
|
TimeLockDelta: upd.CLTVExpiryDelta.Val,
|
|
MinHTLC: upd.HTLCMinimumMsat.Val,
|
|
MaxHTLC: upd.HTLCMaximumMsat.Val,
|
|
FeeBaseMSat: lnwire.MilliSatoshi(
|
|
upd.FeeBaseMsat.Val,
|
|
),
|
|
FeeProportionalMillionths: lnwire.MilliSatoshi(
|
|
upd.FeeProportionalMillionths.Val,
|
|
),
|
|
InboundFee: upd.InboundFee.ValOpt(),
|
|
ExtraSignedFields: upd.ExtraSignedFields,
|
|
}, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("unknown channel update version: %v",
|
|
update.MsgType())
|
|
}
|
|
|
|
// IsNode1 returns true if this policy was announced by the channel's node_1.
|
|
func (c *ChannelEdgePolicy) IsNode1() bool {
|
|
if c.Version == lnwire.GossipVersion1 {
|
|
return c.ChannelFlags&lnwire.ChanUpdateDirection == 0
|
|
}
|
|
|
|
return !c.SecondPeer
|
|
}
|
|
|
|
// IsDisabled determines whether the edge has the disabled bit set.
|
|
//
|
|
// NOTE: for v2 channel updates, we return true here only if both the incoming
|
|
// and outgoing disabled bits are set.
|
|
func (c *ChannelEdgePolicy) IsDisabled() bool {
|
|
if c.Version == lnwire.GossipVersion1 {
|
|
return c.ChannelFlags.IsDisabled()
|
|
}
|
|
|
|
return !c.DisableFlags.IsEnabled()
|
|
}
|
|
|
|
// ComputeFee computes the fee to forward an HTLC of `amt` milli-satoshis over
|
|
// the passed active payment channel. This value is currently computed as
|
|
// specified in BOLT07, but will likely change in the near future.
|
|
func (c *ChannelEdgePolicy) ComputeFee(
|
|
amt lnwire.MilliSatoshi) lnwire.MilliSatoshi {
|
|
|
|
return c.FeeBaseMSat + (amt*c.FeeProportionalMillionths)/feeRateParts
|
|
}
|
|
|
|
// String returns a human-readable version of the channel edge policy.
|
|
func (c *ChannelEdgePolicy) String() string {
|
|
if c.Version == lnwire.GossipVersion1 {
|
|
return fmt.Sprintf("ChannelID=%v, MessageFlags=%v, "+
|
|
"ChannelFlags=%v, LastUpdate=%v", c.ChannelID,
|
|
c.MessageFlags, c.ChannelFlags, c.LastUpdate)
|
|
}
|
|
|
|
return fmt.Sprintf("ChannelID=%v, Node1=%v, DisableFlags=%v, "+
|
|
"BlockHeight=%v", c.ChannelID, !c.SecondPeer,
|
|
c.DisableFlags, c.LastBlockHeight)
|
|
}
|