Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[custom channels]: Fix bandwidth manager and other bugs #1236

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
guggero marked this conversation as resolved.
Show resolved Hide resolved
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
Loading