Skip to content

Commit 449d2fd

Browse files
committed
multi: add channel acceptor, enforce max HTLC limit
1 parent 7c5a3fe commit 449d2fd

File tree

5 files changed

+119
-15
lines changed

5 files changed

+119
-15
lines changed

go.mod

+2-7
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ require (
2626
github.com/lib/pq v1.10.9
2727
github.com/lightninglabs/aperture v0.3.2-beta.0.20240919071136-db27bb9a78bd
2828
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2
29-
github.com/lightninglabs/lndclient v1.0.1-0.20240920110952-ac3012686ab5
29+
github.com/lightninglabs/lndclient v1.0.1-0.20240920113744-6c0e26f97430
3030
github.com/lightninglabs/neutrino/cache v1.1.2
31-
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919095711-611852fd34b1
31+
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240920093603-53cea846b417
3232
github.com/lightningnetwork/lnd/cert v1.2.2
3333
github.com/lightningnetwork/lnd/clock v1.1.1
3434
github.com/lightningnetwork/lnd/fn v1.2.1
@@ -207,8 +207,3 @@ require (
207207
// We want to format raw bytes as hex instead of base64. The forked version
208208
// allows us to specify that as an option.
209209
replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display
210-
211-
// We need this replace until the final custom channel PR (part5) is merged and
212-
// the lnd-18-4 branch of `lndclient` points to that. Otherwise go mod tidy will
213-
// revert the version to what `lndclient` has in its go.mod file.
214-
replace github.com/lightningnetwork/lnd => github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919124701-168e301ccfdc

go.sum

+4-4
Original file line numberDiff line numberDiff line change
@@ -483,8 +483,8 @@ github.com/lightninglabs/lightning-node-connect v0.2.5-alpha h1:ZRVChwczFXK0CEbx
483483
github.com/lightninglabs/lightning-node-connect v0.2.5-alpha/go.mod h1:A9Pof9fETkH+F67BnOmrBDThPKstqp73wlImWOZvTXQ=
484484
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2 h1:Er1miPZD2XZwcfE4xoS5AILqP1mj7kqnhbBSxW9BDxY=
485485
github.com/lightninglabs/lightning-node-connect/hashmailrpc v1.0.2/go.mod h1:antQGRDRJiuyQF6l+k6NECCSImgCpwaZapATth2Chv4=
486-
github.com/lightninglabs/lndclient v1.0.1-0.20240920110952-ac3012686ab5 h1:ZKJtS00m+Wol/1ghFWkmcpYpQHrMl7k67cIYMzINRPo=
487-
github.com/lightninglabs/lndclient v1.0.1-0.20240920110952-ac3012686ab5/go.mod h1:WGJkH/qCE2pvkCW+P5Hvw4D48E7Ay4fUQ+QV3ZtMO7Q=
486+
github.com/lightninglabs/lndclient v1.0.1-0.20240920113744-6c0e26f97430 h1:WPdK83o1B/dj8mWAvMuBlY0/vsOwwvayAwtzeV0BjI8=
487+
github.com/lightninglabs/lndclient v1.0.1-0.20240920113744-6c0e26f97430/go.mod h1:fLzkN+f1Mt0h2QgRrUtFq25jNrHFLwSl4W2iG9yqT0I=
488488
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd h1:D8aRocHpoCv43hL8egXEMYyPmyOiefFHZ66338KQB2s=
489489
github.com/lightninglabs/neutrino v0.16.1-0.20240425105051-602843d34ffd/go.mod h1:x3OmY2wsA18+Kc3TSV2QpSUewOCiscw2mKpXgZv2kZk=
490490
github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
@@ -493,8 +493,8 @@ github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wl
493493
github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
494494
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb h1:yfM05S8DXKhuCBp5qSMZdtSwvJ+GFzl94KbXMNB1JDY=
495495
github.com/lightningnetwork/lightning-onion v1.2.1-0.20240712235311-98bd56499dfb/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
496-
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919124701-168e301ccfdc h1:PQhnYsHrozS/Wrf26WpjgjYqJkRSsFUmkt3z6F0tT2o=
497-
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919124701-168e301ccfdc/go.mod h1:Y4sP4cQS+V8IpDn6hD6zEyX3dkIwUqLkCPtHfXNaVY0=
496+
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240920093603-53cea846b417 h1:tPEhBe1gefwYvCHv1Ob7FrQKV+dHdYH467R7mHpIZcE=
497+
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240920093603-53cea846b417/go.mod h1:Y4sP4cQS+V8IpDn6hD6zEyX3dkIwUqLkCPtHfXNaVY0=
498498
github.com/lightningnetwork/lnd/cert v1.2.2 h1:71YK6hogeJtxSxw2teq3eGeuy4rHGKcFf0d0Uy4qBjI=
499499
github.com/lightningnetwork/lnd/cert v1.2.2/go.mod h1:jQmFn/Ez4zhDgq2hnYSw8r35bqGVxViXhX6Cd7HXM6U=
500500
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=

psbt_channel_funder.go

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ func (l *LndPbstChannelFunder) OpenChannel(ctx context.Context,
144144
}
145145
}
146146

147+
// ChannelAcceptor is used to accept and potentially influence parameters of
148+
// incoming channels.
149+
func (l *LndPbstChannelFunder) ChannelAcceptor(ctx context.Context,
150+
acceptor lndclient.AcceptorFunction) (chan error, error) {
151+
152+
return l.lnd.Client.ChannelAcceptor(
153+
ctx, tapchannel.DefaultTimeout/2, acceptor,
154+
)
155+
}
156+
147157
// A compile-time check to ensure that LndPbstChannelFunder fully implements
148158
// the tapchannel.PsbtChannelFunder interface.
149159
var _ tapchannel.PsbtChannelFunder = (*LndPbstChannelFunder)(nil)

tapcfg/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
451451
DefaultCourierAddr: proofCourierAddr,
452452
AssetSyncer: addrBook,
453453
FeatureBits: lndFeatureBitsVerifier,
454+
ErrChan: mainErrChan,
454455
},
455456
)
456457
auxTrafficShaper := tapchannel.NewAuxTrafficShaper(

tapchannel/aux_funding_controller.go

+102-4
Original file line numberDiff line numberDiff line change
@@ -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"
@@ -51,6 +52,28 @@ const (
5152
// ackTimeout is the amount of time we'll wait to receive the protocol
5253
// level ACK from the remote party before timing out.
5354
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
5477
)
5578

5679
// ErrorReporter is used to report an error back to the caller and/or peer that
@@ -137,6 +160,11 @@ type PsbtChannelFunder interface {
137160
// process. Afterward, the funding transaction should be signed and
138161
// broadcast.
139162
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)
140168
}
141169

142170
// TxPublisher is an interface used to publish transactions.
@@ -221,6 +249,9 @@ type FundingControllerCfg struct {
221249
// FeatureBits is used to verify that the peer has the required feature
222250
// to fund asset channels.
223251
FeatureBits FeatureBitVerifer
252+
253+
// ErrChan is used to report errors back to the main server.
254+
ErrChan chan<- error
224255
}
225256

226257
// bindFundingReq is a request to bind a pending channel ID to a complete aux
@@ -297,6 +328,36 @@ func (f *FundingController) Start() error {
297328
f.Wg.Add(1)
298329
go f.chanFunder()
299330

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+
300361
return nil
301362
}
302363

@@ -1007,10 +1068,11 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
10071068
// Now that we have the initial PSBT template, we can start the funding
10081069
// flow with lnd.
10091070
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,
10141076
}
10151077
assetChanIntent, err := f.cfg.ChannelFunder.OpenChannel(ctx, fundingReq)
10161078
if err != nil {
@@ -1669,6 +1731,42 @@ func (f *FundingController) chanFunder() {
16691731
}
16701732
}
16711733

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+
16721770
// validateProofs validates the inclusion/exclusion/split proofs and the
16731771
// transfer witness of the given proofs.
16741772
func (f *FundingController) validateProofs(proofs []*proof.Proof) error {

0 commit comments

Comments
 (0)