Skip to content

Commit

Permalink
Merge pull request lightninglabs#1132 from lightninglabs/limit-asset-…
Browse files Browse the repository at this point in the history
…id-htlc

Limit number of HTLCs in custom channel
  • Loading branch information
guggero authored Nov 20, 2024
2 parents 77e8b28 + 9a7a4c1 commit e3a0aa1
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 24 deletions.
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
// 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

// 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
)

// 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
// 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).
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

0 comments on commit e3a0aa1

Please sign in to comment.