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