Skip to content

Commit

Permalink
Merge pull request #1236 from lightninglabs/bandwidth-manager-switch
Browse files Browse the repository at this point in the history
[custom channels]: Fix bandwidth manager and other bugs
  • Loading branch information
guggero authored Dec 9, 2024
2 parents 4a15eb2 + 2ed2772 commit fde6732
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 88 deletions.
2 changes: 1 addition & 1 deletion docs/examples/basic-price-oracle/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ require (
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd // indirect
github.com/lightninglabs/neutrino/cache v1.1.2 // indirect
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb // indirect
github.com/lightningnetwork/lnd v0.18.4-beta.rc1 // indirect
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5 // indirect
github.com/lightningnetwork/lnd/clock v1.1.1 // indirect
github.com/lightningnetwork/lnd/fn v1.2.3 // indirect
github.com/lightningnetwork/lnd/healthcheck v1.2.5 // indirect
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/basic-price-oracle/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display h1:Y2WiPkBS
github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1 h1:z6hFKvtbfo8udPrIb81GbSoKlUWd06d4LRxTkD19IMQ=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1/go.mod h1:nPRQzLla5uHPQFyyZn8r9Vgddkd23PBUDa9rggEPOfY=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5 h1:YJ/DPJd3YyPWmvv5b74KdpCFi3uBMdmDei54AageGpc=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5/go.mod h1:nPRQzLla5uHPQFyyZn8r9Vgddkd23PBUDa9rggEPOfY=
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ=
github.com/lightningnetwork/lnd/fn v1.2.3 h1:Q1OrgNSgQynVheBNa16CsKVov1JI5N2AR6G07x9Mles=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2
github.com/lightninglabs/lndclient v0.18.4-7
github.com/lightninglabs/neutrino/cache v1.1.2
github.com/lightningnetwork/lnd v0.18.4-beta.rc1
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5
github.com/lightningnetwork/lnd/cert v1.2.2
github.com/lightningnetwork/lnd/clock v1.1.1
github.com/lightningnetwork/lnd/fn v1.2.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display h1:Y2WiPkBS
github.com/lightninglabs/protobuf-go-hex-display v1.33.0-hex-display/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1 h1:z6hFKvtbfo8udPrIb81GbSoKlUWd06d4LRxTkD19IMQ=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1/go.mod h1:nPRQzLla5uHPQFyyZn8r9Vgddkd23PBUDa9rggEPOfY=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5 h1:YJ/DPJd3YyPWmvv5b74KdpCFi3uBMdmDei54AageGpc=
github.com/lightningnetwork/lnd v0.18.4-beta.rc1.0.20241205204908-f312064bfbd5/go.mod h1:nPRQzLla5uHPQFyyZn8r9Vgddkd23PBUDa9rggEPOfY=
github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI=
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
Expand Down
52 changes: 9 additions & 43 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -6819,13 +6819,9 @@ func marshallRfqEvent(eventInterface fn.Event) (*rfqrpc.RfqEvent, error) {
}, nil

case *rfq.PeerAcceptedSellQuoteEvent:
rpcAcceptedQuote, err := taprpc.MarshalAcceptedSellQuoteEvent(
rpcAcceptedQuote := taprpc.MarshalAcceptedSellQuoteEvent(
event,
)
if err != nil {
return nil, fmt.Errorf("error marshalling accepted "+
"sell quote event: %w", err)
}

eventRpc := &rfqrpc.RfqEvent_PeerAcceptedSellQuote{
PeerAcceptedSellQuote: &rfqrpc.PeerAcceptedSellQuoteEvent{
Expand Down Expand Up @@ -7036,9 +7032,9 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest,
// Continue below.

case req.RfqId != nil:
// Check if the provided rfq ID matches the expected length.
// Check if the provided RFQ ID matches the expected length.
if len(req.RfqId) != 32 {
return fmt.Errorf("rfq must be 32 bytes in length")
return fmt.Errorf("RFQ ID must be 32 bytes in length")
}

// Now let's try to perform an internal lookup to see if there's
Expand All @@ -7061,36 +7057,12 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest,
"accepted quote")
}

invoice, err := zpay32.Decode(
pReq.PaymentRequest, r.cfg.Lnd.ChainParams,
)
if err != nil {
return fmt.Errorf("error decoding payment request: %w",
err)
}

rate := quote.AssetRate.Rate

// Calculate the equivalent asset units for the given invoice
// amount based on the asset-to-BTC conversion rate.
numAssetUnits := rfqmath.MilliSatoshiToUnits(
*invoice.MilliSat, rate,
)

sellOrder := &rfqrpc.PeerAcceptedSellQuote{
Peer: quote.Peer.String(),
Id: quote.ID[:],
Scid: uint64(quote.ID.Scid()),
BidAssetRate: &rfqrpc.FixedPoint{
Coefficient: rate.Coefficient.String(),
Scale: uint32(rate.Scale),
},
AssetAmount: numAssetUnits.ToUint64(),
Expiry: uint64(quote.AssetRate.Expiry.Unix()),
}
sellOrder := taprpc.MarshalAcceptedSellQuote(*quote)

// Send out the information about the quote on the stream.
err = stream.Send(&tchrpc.SendPaymentResponse{
err := stream.Send(&tchrpc.SendPaymentResponse{
Result: &tchrpc.SendPaymentResponse_AcceptedSellOrder{
AcceptedSellOrder: sellOrder,
},
Expand All @@ -7101,8 +7073,8 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest,
}

rpcsLog.Infof("Using quote for %v asset units at %v asset/BTC "+
"from peer %x with SCID %d", numAssetUnits,
rate.String(), quote.Peer, quote.ID.Scid())
"from peer %x with SCID %d", sellOrder.AssetAmount,
quote.AssetRate.String(), quote.Peer, quote.ID.Scid())

htlc := rfqmsg.NewHtlc(nil, fn.Some(quote.ID))

Expand Down Expand Up @@ -7243,15 +7215,9 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest,
err)
}

// Calculate the equivalent asset units for the given invoice
// amount based on the asset-to-BTC conversion rate.
numAssetUnits := rfqmath.MilliSatoshiToUnits(
*invoice.MilliSat, *assetRate,
)

rpcsLog.Infof("Got quote for %v asset units at %v asset/BTC "+
"from peer %x with SCID %d", numAssetUnits, assetRate,
peerPubKey, acceptedQuote.Scid)
"from peer %x with SCID %d", acceptedQuote.AssetAmount,
assetRate, peerPubKey, acceptedQuote.Scid)

var rfqID rfqmsg.ID
copy(rfqID[:], acceptedQuote.Id)
Expand Down
6 changes: 3 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
lfn "github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
Expand All @@ -37,7 +38,6 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/lightningnetwork/lnd/msgmux"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/sweep"
"github.com/lightningnetwork/lnd/tlv"
"google.golang.org/grpc"
Expand Down Expand Up @@ -696,14 +696,14 @@ func (s *Server) Stop() error {

// A compile-time check to ensure that Server fully implements the
// lnwallet.AuxLeafStore, lnd.AuxDataParser, lnwallet.AuxSigner,
// msgmux.Endpoint, funding.AuxFundingController, routing.TlvTrafficShaper
// msgmux.Endpoint, funding.AuxFundingController, htlcswitch.AuxTrafficShaper
// and chancloser.AuxChanCloser interfaces.
var _ lnwl.AuxLeafStore = (*Server)(nil)
var _ lnd.AuxDataParser = (*Server)(nil)
var _ lnwl.AuxSigner = (*Server)(nil)
var _ msgmux.Endpoint = (*Server)(nil)
var _ funding.AuxFundingController = (*Server)(nil)
var _ routing.TlvTrafficShaper = (*Server)(nil)
var _ htlcswitch.AuxTrafficShaper = (*Server)(nil)
var _ chancloser.AuxChanCloser = (*Server)(nil)
var _ lnwl.AuxContractResolver = (*Server)(nil)
var _ sweep.AuxSweeper = (*Server)(nil)
Expand Down
30 changes: 21 additions & 9 deletions tapchannel/aux_traffic_shaper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"github.com/lightninglabs/taproot-assets/rfqmsg"
cmsg "github.com/lightninglabs/taproot-assets/tapchannelmsg"
lfn "github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/tlv"
)

Expand Down Expand Up @@ -84,8 +84,8 @@ func (s *AuxTrafficShaper) Stop() error {
}

// A compile-time check to ensure that AuxTrafficShaper fully implements the
// routing.TlvTrafficShaper interface.
var _ routing.TlvTrafficShaper = (*AuxTrafficShaper)(nil)
// htlcswitch.AuxTrafficShaper interface.
var _ htlcswitch.AuxTrafficShaper = (*AuxTrafficShaper)(nil)

// ShouldHandleTraffic is called in order to check if the channel identified by
// the provided channel ID is handled by the traffic shaper implementation. If
Expand Down Expand Up @@ -187,8 +187,8 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
if htlcAssetAmount != 0 && htlcAssetAmount <= localBalance {
// Check if the current link bandwidth can afford sending out
// the htlc amount without dipping into the channel reserve. If
// it goes below the reserve, we report zero bandwdith as we
// cannot push the htlc amount.
// it goes below the reserve, we report zero bandwidth as we
// cannot push the HTLC amount.
if linkBandwidth < htlcAmt {
return 0, nil
}
Expand All @@ -213,9 +213,21 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
// up the accepted quote and determine the outgoing bandwidth in
// satoshis based on the local asset balance.
rfqID := htlc.RfqID.ValOpt().UnsafeFromSome()
acceptedQuotes := s.cfg.RfqManager.PeerAcceptedSellQuotes()
quote, ok := acceptedQuotes[rfqID.Scid()]
if !ok {
acceptedSellQuotes := s.cfg.RfqManager.PeerAcceptedSellQuotes()
acceptedBuyQuotes := s.cfg.RfqManager.LocalAcceptedBuyQuotes()

sellQuote, isSellQuote := acceptedSellQuotes[rfqID.Scid()]
buyQuote, isBuyQuote := acceptedBuyQuotes[rfqID.Scid()]

var rate rfqmsg.AssetRate
switch {
case isSellQuote:
rate = sellQuote.AssetRate

case isBuyQuote:
rate = buyQuote.AssetRate

default:
return 0, fmt.Errorf("no accepted quote found for RFQ ID "+
"%x (SCID %d)", rfqID[:], rfqID.Scid())
}
Expand All @@ -224,7 +236,7 @@ func (s *AuxTrafficShaper) PaymentBandwidth(htlcBlob,
// expressed in milli-satoshis.
localBalanceFp := rfqmath.NewBigIntFixedPoint(localBalance, 0)
availableBalanceMsat := rfqmath.UnitsToMilliSatoshi(
localBalanceFp, quote.AssetRate.Rate,
localBalanceFp, rate.Rate,
)

// At this point we have acquired what we need to express the asset
Expand Down
43 changes: 35 additions & 8 deletions tapchannel/commitment.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,20 +363,47 @@ func processAddEntry(htlc *DecodedDescriptor, ourBalance, theirBalance uint64,
// non-dust satoshi balance. It also checks and returns whether we need a local
// and/or remote anchor output.
func SanityCheckAmounts(ourBalance, theirBalance btcutil.Amount,
ourAssetBalance, theirAssetBalance uint64, view *DecodedView,
chanType channeldb.ChannelType, whoseCommit lntypes.ChannelParty,
dustLimit btcutil.Amount) (bool, bool, error) {
ourAssetBalance, theirAssetBalance uint64, assetView,
nonAssetView *DecodedView, chanType channeldb.ChannelType,
whoseCommit lntypes.ChannelParty, dustLimit btcutil.Amount) (bool, bool,
error) {

log.Tracef("Sanity checking amounts, whoseCommit=%v, ourBalance=%d, "+
"theirBalance=%d, ourAssetBalance=%d, theirAssetBalance=%d",
whoseCommit, ourBalance, theirBalance, ourAssetBalance,
theirAssetBalance)

var (
numHTLCs int64
feePerKw = view.FeePerKw
numHTLCs uint64
feePerKw = assetView.FeePerKw
)
for _, entry := range view.OurUpdates {

// We need to count any non-dust BTC-only HTLCs too for determining
// whether we need a commitment anchor output. The assetView and
// nonAssetView are non-overlapping, so we can just sum the number of
// non-dust HTLCs in both.
for _, entry := range nonAssetView.OurUpdates {
if !lnwallet.HtlcIsDust(
chanType, false, whoseCommit, feePerKw,
entry.Amount.ToSatoshis(), dustLimit,
) {

numHTLCs++
}
}
for _, entry := range nonAssetView.TheirUpdates {
if !lnwallet.HtlcIsDust(
chanType, true, whoseCommit, feePerKw,
entry.Amount.ToSatoshis(), dustLimit,
) {

numHTLCs++
}
}

// And finally we check the asset HTLCs. Here we also enforce that an
// HTLC that's carrying an asset must be above dust.
for _, entry := range assetView.OurUpdates {
isDust := lnwallet.HtlcIsDust(
chanType, false, whoseCommit, feePerKw,
entry.Amount.ToSatoshis(), dustLimit,
Expand All @@ -391,7 +418,7 @@ func SanityCheckAmounts(ourBalance, theirBalance btcutil.Amount,

numHTLCs++
}
for _, entry := range view.TheirUpdates {
for _, entry := range assetView.TheirUpdates {
isDust := lnwallet.HtlcIsDust(
chanType, true, whoseCommit, feePerKw,
entry.Amount.ToSatoshis(), dustLimit,
Expand Down Expand Up @@ -488,7 +515,7 @@ func GenerateCommitmentAllocations(prevState *cmsg.Commitment,
// corresponding non-dust BTC output.
wantLocalAnchor, wantRemoteAnchor, err := SanityCheckAmounts(
ourBalance.ToSatoshis(), theirBalance.ToSatoshis(),
ourAssetBalance, theirAssetBalance, filteredView,
ourAssetBalance, theirAssetBalance, filteredView, nonAssetView,
chanState.ChanType, whoseCommit, dustLimit,
)
if err != nil {
Expand Down
46 changes: 27 additions & 19 deletions taprpc/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/lightninglabs/taproot-assets/commitment"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/rfq"
"github.com/lightninglabs/taproot-assets/rfqmath"
"github.com/lightninglabs/taproot-assets/rfqmsg"
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
"github.com/lightningnetwork/lnd/keychain"
)
Expand Down Expand Up @@ -522,25 +524,37 @@ func MarshalAsset(ctx context.Context, a *asset.Asset,
}

// MarshalAcceptedSellQuoteEvent marshals a peer accepted sell quote event to
// its rpc representation.
// its RPC representation.
func MarshalAcceptedSellQuoteEvent(
event *rfq.PeerAcceptedSellQuoteEvent) (*rfqrpc.PeerAcceptedSellQuote,
error) {
event *rfq.PeerAcceptedSellQuoteEvent) *rfqrpc.PeerAcceptedSellQuote {

return MarshalAcceptedSellQuote(event.SellAccept)
}

// MarshalAcceptedSellQuote marshals a peer accepted sell quote to its RPC
// representation.
func MarshalAcceptedSellQuote(
accept rfqmsg.SellAccept) *rfqrpc.PeerAcceptedSellQuote {

rpcAssetRate := &rfqrpc.FixedPoint{
Coefficient: event.AssetRate.Rate.Coefficient.String(),
Scale: uint32(event.AssetRate.Rate.Scale),
Coefficient: accept.AssetRate.Rate.Coefficient.String(),
Scale: uint32(accept.AssetRate.Rate.Scale),
}

// TODO(ffranr): Add SellRequest payment max amount to
// PeerAcceptedSellQuote.
// Calculate the equivalent asset units for the given total BTC amount
// based on the asset-to-BTC conversion rate.
numAssetUnits := rfqmath.MilliSatoshiToUnits(
accept.Request.PaymentMaxAmt, accept.AssetRate.Rate,
)

return &rfqrpc.PeerAcceptedSellQuote{
Peer: event.Peer.String(),
Id: event.ID[:],
Scid: uint64(event.ShortChannelId()),
Peer: accept.Peer.String(),
Id: accept.ID[:],
Scid: uint64(accept.ShortChannelId()),
BidAssetRate: rpcAssetRate,
Expiry: uint64(event.AssetRate.Expiry.Unix()),
}, nil
Expiry: uint64(accept.AssetRate.Expiry.Unix()),
AssetAmount: numAssetUnits.ScaleTo(0).ToUint64(),
}
}

// MarshalAcceptedBuyQuoteEvent marshals a peer accepted buy quote event to
Expand Down Expand Up @@ -636,14 +650,8 @@ func NewAddAssetSellOrderResponse(

switch e := event.(type) {
case *rfq.PeerAcceptedSellQuoteEvent:
rpcAcceptedQuote, err := MarshalAcceptedSellQuoteEvent(e)
if err != nil {
return nil, fmt.Errorf("unable to marshal accepted "+
"sell quote event to RPC: %w", err)
}

resp.Response = &rfqrpc.AddAssetSellOrderResponse_AcceptedQuote{
AcceptedQuote: rpcAcceptedQuote,
AcceptedQuote: MarshalAcceptedSellQuoteEvent(e),
}
return resp, nil

Expand Down

0 comments on commit fde6732

Please sign in to comment.