@@ -20,6 +20,7 @@ import (
2020 "github.com/btcsuite/btcd/chaincfg/chainhash"
2121 "github.com/btcsuite/btcd/wire"
2222 "github.com/davecgh/go-spew/spew"
23+ "github.com/lightninglabs/lndclient"
2324 "github.com/lightninglabs/taproot-assets/address"
2425 "github.com/lightninglabs/taproot-assets/asset"
2526 "github.com/lightninglabs/taproot-assets/commitment"
@@ -52,6 +53,28 @@ const (
5253 // ackTimeout is the amount of time we'll wait to receive the protocol
5354 // level ACK from the remote party before timing out.
5455 ackTimeout = time .Second * 30
56+
57+ // maxNumAssetIDs is the maximum number of fungible asset pieces (asset
58+ // IDs) that can be committed to a single channel. The number needs to
59+ // be limited to prevent the number of required HTLC signatures to be
60+ // too large for a single CommitSig wire message to carry them. This
61+ // value is tightly coupled with the number of HTLCs that can be added
62+ // to a channel at the same time (maxNumHTLCs). The values were
63+ // determined with the TestMaxCommitSigMsgSize test in
64+ // aux_leaf_signer_test.go then a set was chosen that would allow for
65+ // a decent number of HTLCs (and also a number that is divisible by two
66+ // because each side will only be allowed to add half of the total).
67+ maxNumAssetIDs = 3
68+
69+ // maxNumHTLCs is the maximum number of HTLCs there can be in an asset
70+ // channel to avoid the number of signatures exceeding the maximum
71+ // message size of a CommitSig message. See maxNumAssetIDs for more
72+ // information.
73+ maxNumHTLCs = 166
74+
75+ // maxNumHTLCsPerParty is the maximum number of HTLCs that can be added
76+ // by a single party to a channel.
77+ maxNumHTLCsPerParty = maxNumHTLCs / 2
5578)
5679
5780// ErrorReporter is used to report an error back to the caller and/or peer that
@@ -138,6 +161,11 @@ type PsbtChannelFunder interface {
138161 // process. Afterward, the funding transaction should be signed and
139162 // broadcast.
140163 OpenChannel (context.Context , OpenChanReq ) (AssetChanIntent , error )
164+
165+ // ChannelAcceptor is used to accept and potentially influence
166+ // parameters of incoming channels.
167+ ChannelAcceptor (ctx context.Context ,
168+ acceptor lndclient.AcceptorFunction ) (chan error , error )
141169}
142170
143171// TxPublisher is an interface used to publish transactions.
@@ -222,6 +250,9 @@ type FundingControllerCfg struct {
222250 // FeatureBits is used to verify that the peer has the required feature
223251 // to fund asset channels.
224252 FeatureBits FeatureBitVerifer
253+
254+ // ErrChan is used to report errors back to the main server.
255+ ErrChan chan <- error
225256}
226257
227258// bindFundingReq is a request to bind a pending channel ID to a complete aux
@@ -298,6 +329,36 @@ func (f *FundingController) Start() error {
298329 f .Wg .Add (1 )
299330 go f .chanFunder ()
300331
332+ f .Wg .Add (1 )
333+ go func () {
334+ defer f .Wg .Done ()
335+
336+ ctx , cancel := f .WithCtxQuitNoTimeout ()
337+ defer cancel ()
338+
339+ errChan , err := f .cfg .ChannelFunder .ChannelAcceptor (
340+ ctx , f .channelAcceptor ,
341+ )
342+ if err != nil {
343+ err = fmt .Errorf ("unable to start channel acceptor: %w" ,
344+ err )
345+ f .cfg .ErrChan <- err
346+ return
347+ }
348+
349+ // We'll accept channels for as long as the funding controller
350+ // is running or until we receive an error.
351+ select {
352+ case err := <- errChan :
353+ err = fmt .Errorf ("channel acceptor error: %w" , err )
354+ f .cfg .ErrChan <- err
355+
356+ case <- f .Quit :
357+ log .Infof ("Stopping channel acceptor, funding " +
358+ "controller shutting down" )
359+ }
360+ }()
361+
301362 return nil
302363}
303364
@@ -1008,10 +1069,11 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
10081069 // Now that we have the initial PSBT template, we can start the funding
10091070 // flow with lnd.
10101071 fundingReq := OpenChanReq {
1011- ChanAmt : 100_000 ,
1012- PushAmt : fundingState .pushAmt ,
1013- PeerPub : fundingState .peerPub ,
1014- TempPID : fundingState .pid ,
1072+ ChanAmt : 100_000 ,
1073+ PushAmt : fundingState .pushAmt ,
1074+ PeerPub : fundingState .peerPub ,
1075+ TempPID : fundingState .pid ,
1076+ RemoteMaxHtlc : maxNumHTLCsPerParty ,
10151077 }
10161078 assetChanIntent , err := f .cfg .ChannelFunder .OpenChannel (ctx , fundingReq )
10171079 if err != nil {
@@ -1670,6 +1732,42 @@ func (f *FundingController) chanFunder() {
16701732 }
16711733}
16721734
1735+ // channelAcceptor is a callback that's called by the lnd client when a new
1736+ // channel is proposed. This function is responsible for deciding whether to
1737+ // accept the channel based on the channel parameters, and to also set some
1738+ // channel parameters for our own side.
1739+ func (f * FundingController ) channelAcceptor (_ context.Context ,
1740+ req * lndclient.AcceptorRequest ) (* lndclient.AcceptorResponse , error ) {
1741+
1742+ // Avoid nil pointer dereference.
1743+ if req .CommitmentType == nil {
1744+ return nil , fmt .Errorf ("commitment type is required" )
1745+ }
1746+
1747+ // Ignore any non-asset channels, just accept them.
1748+ if * req .CommitmentType != lnwallet .CommitmentTypeSimpleTaprootOverlay {
1749+ return & lndclient.AcceptorResponse {
1750+ Accept : true ,
1751+ }, nil
1752+ }
1753+
1754+ // Reject custom channels that don't observe the max HTLC limit.
1755+ if req .MaxAcceptedHtlcs != maxNumHTLCsPerParty {
1756+ return & lndclient.AcceptorResponse {
1757+ Accept : false ,
1758+ Error : fmt .Sprintf ("max accepted HTLCs must be 123, " +
1759+ "got %d" , req .MaxAcceptedHtlcs ),
1760+ }, nil
1761+ }
1762+
1763+ // Everything looks good, we can now set our own max HTLC limit we'll
1764+ // observe for this channel.
1765+ return & lndclient.AcceptorResponse {
1766+ Accept : true ,
1767+ MaxHtlcCount : maxNumHTLCsPerParty ,
1768+ }, nil
1769+ }
1770+
16731771// validateProofs validates the inclusion/exclusion/split proofs and the
16741772// transfer witness of the given proofs.
16751773func (f * FundingController ) validateProofs (proofs []* proof.Proof ) error {
0 commit comments