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

Limit number of HTLCs in custom channel #1132

Merged
merged 6 commits into from
Nov 20, 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
4 changes: 2 additions & 2 deletions docs/examples/basic-price-oracle/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ require (
github.com/kkdai/bstream v1.0.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf // indirect
github.com/lightninglabs/lndclient v0.18.4-3 // indirect
github.com/lightninglabs/lndclient v0.18.4-5 // indirect
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.3-beta.rc3.0.20241025090009-615f3d633e61 // indirect
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2 // 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
8 changes: 4 additions & 4 deletions docs/examples/basic-price-oracle/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQ
github.com/lightninglabs/lightning-node-connect v0.2.5-alpha h1:ZRVChwczFXK0CEbxOCWwUA6TIZvrkE0APd1T3WjFAwg=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4=
github.com/lightninglabs/lndclient v0.18.4-3 h1:Xk3ZuCQE4ZlF70jaToryL2MvRcryiE0zTfUjJbmzUBY=
github.com/lightninglabs/lndclient v0.18.4-3/go.mod h1:/HLqmZGL9MtP8F1g+laq+L9VrsugBN5tsTct3C5wWCg=
github.com/lightninglabs/lndclient v0.18.4-5 h1:KokX5ZlFuZEmtD7sHWg1cXzee0ZsnBWuSKV9/RcTEv4=
github.com/lightninglabs/lndclient v0.18.4-5/go.mod h1:tafbfrisn1Iwt3em3nYWdE06C8jpoZtpNyiSB485OCg=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
Expand All @@ -428,8 +428,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.3-beta.rc3.0.20241025090009-615f3d633e61 h1:EcBM2tz+iyspYRFaDVjUe5a2bkuBWFxOWD2mzdCraUc=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241025090009-615f3d633e61/go.mod h1:q2DlXwj6ev8TMbo+CvfJ3BIrqw42HFM/fSBoyCFrjdc=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2 h1:zGnSH1gTpPA637465d5tp7VkdWw5sVyWZxxmfZ0rKo4=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2/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
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ require (
github.com/lib/pq v1.10.9
github.com/lightninglabs/aperture v0.3.2-beta.0.20241015115230-d59b5514c19a
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2
github.com/lightninglabs/lndclient v0.18.4-3
github.com/lightninglabs/lndclient v0.18.4-5
github.com/lightninglabs/neutrino/cache v1.1.2
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241025090009-615f3d633e61
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2
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
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,8 @@ github.com/lightninglabs/lightning-node-connect v0.2.5-alpha h1:ZRVChwczFXK0CEbx
github.com/lightninglabs/lightning-node-connect v0.2.5-alpha/go.mod h1:A9Pof9fETkH+F67BnOmrBDThPKstqp73wlImWOZvTXQ=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY=
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4=
github.com/lightninglabs/lndclient v0.18.4-3 h1:Xk3ZuCQE4ZlF70jaToryL2MvRcryiE0zTfUjJbmzUBY=
github.com/lightninglabs/lndclient v0.18.4-3/go.mod h1:/HLqmZGL9MtP8F1g+laq+L9VrsugBN5tsTct3C5wWCg=
github.com/lightninglabs/lndclient v0.18.4-5 h1:KokX5ZlFuZEmtD7sHWg1cXzee0ZsnBWuSKV9/RcTEv4=
github.com/lightninglabs/lndclient v0.18.4-5/go.mod h1:tafbfrisn1Iwt3em3nYWdE06C8jpoZtpNyiSB485OCg=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
Expand All @@ -496,8 +496,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.3-beta.rc3.0.20241025090009-615f3d633e61 h1:EcBM2tz+iyspYRFaDVjUe5a2bkuBWFxOWD2mzdCraUc=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241025090009-615f3d633e61/go.mod h1:q2DlXwj6ev8TMbo+CvfJ3BIrqw42HFM/fSBoyCFrjdc=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2 h1:zGnSH1gTpPA637465d5tp7VkdWw5sVyWZxxmfZ0rKo4=
github.com/lightningnetwork/lnd v0.18.3-beta.rc3.0.20241120143113-9246d5c51cd2/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
29 changes: 26 additions & 3 deletions psbt_channel_funder.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,8 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
// We'll map our high level params into a request for a: private,
// taproot channel, that uses the PSBT funding flow.
taprootCommitType := lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
openChanStream, errChan, err := l.lnd.Client.OpenChannelStream(
ctx, route.NewVertex(&req.PeerPub), req.ChanAmt, req.PushAmt,
true, lndclient.WithCommitmentType(&taprootCommitType),
channelOpenOptions := []lndclient.OpenChannelOption{
lndclient.WithCommitmentType(&taprootCommitType),
lndclient.WithFundingShim(&lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{
PsbtShim: &lnrpc.PsbtShim{
Expand All @@ -110,6 +109,20 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
},
}),
lndclient.WithRemoteReserve(CustomChannelRemoteReserve),
}

// Limit the number of HTLCs that can be added to the channel by the
// remote party.
if req.RemoteMaxHtlc > 0 {
channelOpenOptions = append(
channelOpenOptions,
lndclient.WithRemoteMaxHtlc(req.RemoteMaxHtlc),
)
}

openChanStream, errChan, err := l.lnd.Client.OpenChannelStream(
ctx, route.NewVertex(&req.PeerPub), req.ChanAmt, req.PushAmt,
true, channelOpenOptions...,
)
if err != nil {
return nil, fmt.Errorf("unable to open channel with "+
Expand Down Expand Up @@ -143,6 +156,16 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
}
}

// ChannelAcceptor is used to accept and potentially influence parameters of
// incoming channels.
func (l *LndPbstChannelFunder) ChannelAcceptor(ctx context.Context,
acceptor lndclient.AcceptorFunction) (chan error, error) {

return l.lnd.Client.ChannelAcceptor(
ctx, tapchannel.DefaultTimeout/2, acceptor,
)
}

// A compile-time check to ensure that LndPbstChannelFunder fully implements
// the tapchannel.PsbtChannelFunder interface.
var _ tapchannel.PsbtChannelFunder = (*LndPbstChannelFunder)(nil)
4 changes: 2 additions & 2 deletions sample-tapd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@
; universe.multiverse-caches.syncer-cache-pre-alloc-size=100000

; The size of the root node page cache for all requests that aren't served by
; the syncer cache. (default: 10240)
; universe.multiverse-caches.root-node-page-cache-size=10240
; the syncer cache. (default: 327680)
; universe.multiverse-caches.root-node-page-cache-size=327680


[address]
Expand Down
7 changes: 4 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -760,8 +760,8 @@ func (s *Server) FetchLeavesFromView(
// NOTE: This method is part of the lnwallet.AuxLeafStore interface.
// nolint:lll
func (s *Server) FetchLeavesFromCommit(chanState lnwl.AuxChanState,
com channeldb.ChannelCommitment,
keys lnwl.CommitmentKeyRing) lfn.Result[lnwl.CommitDiffAuxResult] {
com channeldb.ChannelCommitment, keys lnwl.CommitmentKeyRing,
whoseCommit lntypes.ChannelParty) lfn.Result[lnwl.CommitDiffAuxResult] {

srvrLog.Debugf("FetchLeavesFromCommit called, ourBalance=%v, "+
"theirBalance=%v, numHtlcs=%d", com.LocalBalance,
Expand Down Expand Up @@ -1159,7 +1159,8 @@ func (s *Server) ExtraBudgetForInputs(
//
// NOTE: This method is part of the sweep.AuxSweeper interface.
func (s *Server) NotifyBroadcast(req *sweep.BumpRequest,
tx *wire.MsgTx, fee btcutil.Amount) error {
tx *wire.MsgTx, fee btcutil.Amount,
outpointToTxIndex map[wire.OutPoint]int) error {

srvrLog.Tracef("NotifyBroadcast called, req=%v, tx=%v, fee=%v",
spew.Sdump(req), spew.Sdump(tx), fee)
Expand Down
1 change: 1 addition & 0 deletions tapcfg/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
DefaultCourierAddr: proofCourierAddr,
AssetSyncer: addrBook,
FeatureBits: lndFeatureBitsVerifier,
ErrChan: mainErrChan,
},
)
auxTrafficShaper := tapchannel.NewAuxTrafficShaper(
Expand Down
132 changes: 128 additions & 4 deletions tapchannel/aux_funding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/taproot-assets/address"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
Expand Down Expand Up @@ -52,6 +53,28 @@ const (
// ackTimeout is the amount of time we'll wait to receive the protocol
// level ACK from the remote party before timing out.
ackTimeout = time.Second * 30

// maxNumAssetIDs is the maximum number of fungible asset pieces (asset
// IDs) that can be committed to a single channel. The number needs to
Roasbeef marked this conversation as resolved.
Show resolved Hide resolved
// be limited to prevent the number of required HTLC signatures to be
// too large for a single CommitSig wire message to carry them. This
// value is tightly coupled with the number of HTLCs that can be added
// to a channel at the same time (maxNumHTLCs). The values were
// determined with the TestMaxCommitSigMsgSize test in
// aux_leaf_signer_test.go then a set was chosen that would allow for
// a decent number of HTLCs (and also a number that is divisible by two
// because each side will only be allowed to add half of the total).
maxNumAssetIDs = 3
ffranr marked this conversation as resolved.
Show resolved Hide resolved

// maxNumHTLCs is the maximum number of HTLCs there can be in an asset
// channel to avoid the number of signatures exceeding the maximum
// message size of a CommitSig message. See maxNumAssetIDs for more
// information.
maxNumHTLCs = 166

// maxNumHTLCsPerParty is the maximum number of HTLCs that can be added
// by a single party to a channel.
maxNumHTLCsPerParty = maxNumHTLCs / 2
Roasbeef marked this conversation as resolved.
Show resolved Hide resolved
)

// ErrorReporter is used to report an error back to the caller and/or peer that
Expand Down Expand Up @@ -94,6 +117,11 @@ type OpenChanReq struct {
// PushAmt is the amount of BTC to push to the remote peer.
PushAmt btcutil.Amount

// RemoteMaxHtlc is the maximum number of HTLCs we allow the remote to
// add to the channel. If this is zero, then the default value defined
// by lnd (and dependent on the channel capacity) will be used.
RemoteMaxHtlc uint32

// PeerPub is the identity public key of the remote peer we wish to
// open the channel with.
PeerPub btcec.PublicKey
Expand Down Expand Up @@ -133,6 +161,11 @@ type PsbtChannelFunder interface {
// process. Afterward, the funding transaction should be signed and
// broadcast.
OpenChannel(context.Context, OpenChanReq) (AssetChanIntent, error)

// ChannelAcceptor is used to accept and potentially influence
// parameters of incoming channels.
ChannelAcceptor(ctx context.Context,
acceptor lndclient.AcceptorFunction) (chan error, error)
}

// TxPublisher is an interface used to publish transactions.
Expand Down Expand Up @@ -217,6 +250,9 @@ type FundingControllerCfg struct {
// FeatureBits is used to verify that the peer has the required feature
// to fund asset channels.
FeatureBits FeatureBitVerifer

// ErrChan is used to report errors back to the main server.
ErrChan chan<- error
}

// bindFundingReq is a request to bind a pending channel ID to a complete aux
Expand Down Expand Up @@ -293,6 +329,36 @@ func (f *FundingController) Start() error {
f.Wg.Add(1)
go f.chanFunder()

f.Wg.Add(1)
go func() {
defer f.Wg.Done()

ctx, cancel := f.WithCtxQuitNoTimeout()
defer cancel()

errChan, err := f.cfg.ChannelFunder.ChannelAcceptor(
ctx, f.channelAcceptor,
)
if err != nil {
err = fmt.Errorf("unable to start channel acceptor: %w",
err)
f.cfg.ErrChan <- err
return
}

// We'll accept channels for as long as the funding controller
// is running or until we receive an error.
select {
case err := <-errChan:
err = fmt.Errorf("channel acceptor error: %w", err)
f.cfg.ErrChan <- err

case <-f.Quit:
log.Infof("Stopping channel acceptor, funding " +
"controller shutting down")
}
}()

return nil
}

Expand Down Expand Up @@ -1003,10 +1069,11 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
// Now that we have the initial PSBT template, we can start the funding
// flow with lnd.
fundingReq := OpenChanReq{
ChanAmt: 100_000,
PushAmt: fundingState.pushAmt,
PeerPub: fundingState.peerPub,
TempPID: fundingState.pid,
ChanAmt: 100_000,
PushAmt: fundingState.pushAmt,
PeerPub: fundingState.peerPub,
TempPID: fundingState.pid,
RemoteMaxHtlc: maxNumHTLCsPerParty,
}
assetChanIntent, err := f.cfg.ChannelFunder.OpenChannel(ctx, fundingReq)
if err != nil {
Expand Down Expand Up @@ -1430,6 +1497,26 @@ func (f *FundingController) processFundingReq(fundingFlows fundingFlowIndex,
}
}()

// We need to limit the number of different fungible assets (asset IDs)
// we allow to be commited to a single channel. This is to make sure we
// have a decent number of HTLCs available. See Godoc of maxNumAssetIDs
// for more information.
//
// TODO(guggero): This following code is obviously wrong and needs to be
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this TODO still applicable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we need to actually count the number of different asset IDs (tranches) that are used for funding a channel, once we allow grouped assets to be used. So this will change in 0.6.

// changed when we support committing fungible assets into a channel. To
// avoid this TODO from being overlooked, we add a dummy implementation
// with a condition that currently will never be true (since there's
// only a single vPacket being selected currently anyway).
guggero marked this conversation as resolved.
Show resolved Hide resolved
assetIDSet := lfn.NewSet[asset.ID]()
for _, out := range fundingVpkt.VPacket.Outputs {
assetIDSet.Add(out.Asset.ID())
}
if assetIDSet.Size() > maxNumAssetIDs {
return fmt.Errorf("too many different asset IDs in channel "+
"funding, got %d, max is %d", len(assetIDSet.ToSlice()),
maxNumAssetIDs)
}

// Now that we know the final funding asset root along with the splits,
// we can derive the tapscript root that'll be used alongside the
// internal key (which we'll only learn from lnd later as we finalize
Expand Down Expand Up @@ -1677,6 +1764,43 @@ func (f *FundingController) chanFunder() {
}
}

// channelAcceptor is a callback that's called by the lnd client when a new
// channel is proposed. This function is responsible for deciding whether to
// accept the channel based on the channel parameters, and to also set some
// channel parameters for our own side.
func (f *FundingController) channelAcceptor(_ context.Context,
req *lndclient.AcceptorRequest) (*lndclient.AcceptorResponse, error) {

// Avoid nil pointer dereference.
if req.CommitmentType == nil {
return nil, fmt.Errorf("commitment type is required")
}

// Ignore any non-asset channels, just accept them.
if *req.CommitmentType != lnwallet.CommitmentTypeSimpleTaprootOverlay {
return &lndclient.AcceptorResponse{
Accept: true,
}, nil
}

// Reject custom channels that don't observe the max HTLC limit.
if req.MaxAcceptedHtlcs > maxNumHTLCsPerParty {
return &lndclient.AcceptorResponse{
Accept: false,
Error: fmt.Sprintf("max accepted HTLCs must be at "+
"most %d, got %d", maxNumHTLCsPerParty,
req.MaxAcceptedHtlcs),
}, nil
}

// Everything looks good, we can now set our own max HTLC limit we'll
// observe for this channel.
return &lndclient.AcceptorResponse{
Accept: true,
MaxHtlcCount: maxNumHTLCsPerParty,
}, nil
}

// validateProofs validates the inclusion/exclusion/split proofs and the
// transfer witness of the given proofs.
func (f *FundingController) validateProofs(proofs []*proof.Proof) error {
Expand Down
Loading
Loading