peer: set and use aux htlc validator
When instantiating the lightning channel we now pass in the created HTLC validator. This validator simply performs a bandwidth check and errors out if that is insufficient.
This commit is contained in:
1 file changed
+110
@@ -52,6 +52,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/pool"
|
||||
"github.com/lightningnetwork/lnd/protofsm"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/subscribe"
|
||||
"github.com/lightningnetwork/lnd/ticker"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
@@ -1146,6 +1147,16 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) (
|
||||
},
|
||||
)
|
||||
|
||||
p.cfg.AuxTrafficShaper.WhenSome(
|
||||
func(ts htlcswitch.AuxTrafficShaper) {
|
||||
val := p.createHtlcValidator(dbChan, ts)
|
||||
chanOpts = append(
|
||||
chanOpts,
|
||||
lnwallet.WithAuxHtlcValidator(val),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
lnChan, err := lnwallet.NewLightningChannel(
|
||||
p.cfg.Signer, dbChan, p.cfg.SigPool, chanOpts...,
|
||||
)
|
||||
@@ -5259,6 +5270,15 @@ func (p *Brontide) addActiveChannel(c *lnpeer.NewChannel) error {
|
||||
chanOpts = append(chanOpts, lnwallet.WithAuxResolver(s))
|
||||
})
|
||||
|
||||
p.cfg.AuxTrafficShaper.WhenSome(
|
||||
func(ts htlcswitch.AuxTrafficShaper) {
|
||||
val := p.createHtlcValidator(c.OpenChannel, ts)
|
||||
chanOpts = append(
|
||||
chanOpts, lnwallet.WithAuxHtlcValidator(val),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
// If not already active, we'll add this channel to the set of active
|
||||
// channels, so we can look it up later easily according to its channel
|
||||
// ID.
|
||||
@@ -5465,6 +5485,96 @@ func (p *Brontide) scaleTimeout(timeout time.Duration) time.Duration {
|
||||
return timeout
|
||||
}
|
||||
|
||||
// auxHtlcValidator implements lnwallet.AuxHtlcValidator by checking HTLC
|
||||
// bandwidth against the traffic shaper.
|
||||
type auxHtlcValidator struct {
|
||||
peer *Brontide
|
||||
dbChan *channeldb.OpenChannel
|
||||
ts htlcswitch.AuxTrafficShaper
|
||||
}
|
||||
|
||||
// ValidateHtlc performs final aux balance validation before an HTLC is added
|
||||
// to the channel state. It calls into the traffic shaper's PaymentBandwidth
|
||||
// method to check external balance against the most up-to-date channel state,
|
||||
// preventing race conditions where multiple HTLCs could be approved based on
|
||||
// stale bandwidth.
|
||||
func (v *auxHtlcValidator) ValidateHtlc(amount,
|
||||
linkBandwidth lnwire.MilliSatoshi,
|
||||
customRecords lnwire.CustomRecords,
|
||||
view lnwallet.AuxHtlcView) error {
|
||||
|
||||
// Get the short channel ID for logging.
|
||||
scid := v.dbChan.ShortChannelID
|
||||
|
||||
// Extract the HTLC custom records to pass to the traffic shaper.
|
||||
var htlcBlob fn.Option[tlv.Blob]
|
||||
if len(customRecords) > 0 {
|
||||
blob, err := customRecords.Serialize()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serialize "+
|
||||
"custom records: %w", err)
|
||||
}
|
||||
htlcBlob = fn.Some(blob)
|
||||
}
|
||||
|
||||
// Get the funding and commitment blobs for this channel.
|
||||
fundingBlob := v.dbChan.CustomBlob
|
||||
commitmentBlob := v.dbChan.LocalCommitment.CustomBlob
|
||||
|
||||
// Check if this channel should be handled by the traffic shaper. If
|
||||
// not, we skip the aux validation entirely and allow the HTLC to
|
||||
// proceed through normal validation.
|
||||
shouldHandle, err := v.ts.ShouldHandleTraffic(
|
||||
scid, fundingBlob, htlcBlob,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("traffic shaper failed to decide "+
|
||||
"whether to handle traffic: %w", err)
|
||||
}
|
||||
if !shouldHandle {
|
||||
return nil
|
||||
}
|
||||
|
||||
peer := route.NewVertex(v.peer.IdentityKey())
|
||||
|
||||
// Call the traffic shaper's PaymentBandwidth method with the current
|
||||
// state. This performs the same bandwidth checks as during
|
||||
// pathfinding/forwarding, but against the absolute latest channel
|
||||
// state.
|
||||
//
|
||||
// The linkBandwidth is provided by the channel and represents the
|
||||
// current available balance, which is used by the traffic shaper to
|
||||
// ensure we don't dip below channel reserves.
|
||||
bandwidth, err := v.ts.PaymentBandwidth(
|
||||
fundingBlob, htlcBlob, commitmentBlob,
|
||||
linkBandwidth, amount, view, peer,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("traffic shaper bandwidth check "+
|
||||
"failed: %w", err)
|
||||
}
|
||||
|
||||
if amount > bandwidth {
|
||||
return fmt.Errorf("insufficient aux bandwidth: "+
|
||||
"need %v, have %v (scid=%v)", amount,
|
||||
bandwidth, scid)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createHtlcValidator creates an HTLC validator that performs final aux balance
|
||||
// validation before HTLCs are added to the channel state.
|
||||
func (p *Brontide) createHtlcValidator(dbChan *channeldb.OpenChannel,
|
||||
ts htlcswitch.AuxTrafficShaper) lnwallet.AuxHtlcValidator {
|
||||
|
||||
return &auxHtlcValidator{
|
||||
peer: p,
|
||||
dbChan: dbChan,
|
||||
ts: ts,
|
||||
}
|
||||
}
|
||||
|
||||
// CoopCloseUpdates is a struct used to communicate updates for an active close
|
||||
// to the caller.
|
||||
type CoopCloseUpdates struct {
|
||||
|
||||
Reference in new issue
Block a user