From cbc11dac8f4ba9323df078a982a2624dafec1a47 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Tue, 6 Feb 2024 12:25:45 +0100 Subject: [PATCH] multi: add coin selection strategy to channel funding With this commit we prepare for the lnwallet channel funding logic to be aware of the config-level coin selection strategy by adding it to the wallet config. --- config_builder.go | 34 +++++++------- funding/manager_test.go | 18 ++++---- lnwallet/chanfunding/wallet_assembler.go | 5 +++ lnwallet/config.go | 5 +++ lnwallet/test/test_interface.go | 57 +++++++++++++----------- lnwallet/wallet.go | 5 ++- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/config_builder.go b/config_builder.go index f1858cfd2..3fcfbb376 100644 --- a/config_builder.go +++ b/config_builder.go @@ -686,14 +686,15 @@ func (d *DefaultWalletImpl) BuildChainControl( // Create, and start the lnwallet, which handles the core payment // channel logic, and exposes control via proxy state machines. lnWalletConfig := lnwallet.Config{ - Database: partialChainControl.Cfg.ChanStateDB, - Notifier: partialChainControl.ChainNotifier, - WalletController: walletController, - Signer: walletController, - FeeEstimator: partialChainControl.FeeEstimator, - SecretKeyRing: keyRing, - ChainIO: walletController, - NetParams: *walletConfig.NetParams, + Database: partialChainControl.Cfg.ChanStateDB, + Notifier: partialChainControl.ChainNotifier, + WalletController: walletController, + Signer: walletController, + FeeEstimator: partialChainControl.FeeEstimator, + SecretKeyRing: keyRing, + ChainIO: walletController, + NetParams: *walletConfig.NetParams, + CoinSelectionStrategy: walletConfig.CoinSelectionStrategy, } // The broadcast is already always active for neutrino nodes, so we @@ -800,14 +801,15 @@ func (d *RPCSignerWalletImpl) BuildChainControl( // Create, and start the lnwallet, which handles the core payment // channel logic, and exposes control via proxy state machines. lnWalletConfig := lnwallet.Config{ - Database: partialChainControl.Cfg.ChanStateDB, - Notifier: partialChainControl.ChainNotifier, - WalletController: rpcKeyRing, - Signer: rpcKeyRing, - FeeEstimator: partialChainControl.FeeEstimator, - SecretKeyRing: rpcKeyRing, - ChainIO: walletController, - NetParams: *walletConfig.NetParams, + Database: partialChainControl.Cfg.ChanStateDB, + Notifier: partialChainControl.ChainNotifier, + WalletController: rpcKeyRing, + Signer: rpcKeyRing, + FeeEstimator: partialChainControl.FeeEstimator, + SecretKeyRing: rpcKeyRing, + ChainIO: walletController, + NetParams: *walletConfig.NetParams, + CoinSelectionStrategy: walletConfig.CoinSelectionStrategy, } // We've created the wallet configuration now, so we can finish diff --git a/funding/manager_test.go b/funding/manager_test.go index 83ff6c12b..6e1f22216 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -20,6 +20,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/wallet" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainreg" acpt "github.com/lightningnetwork/lnd/chanacceptor" @@ -360,14 +361,15 @@ func createTestWallet(cdb *channeldb.ChannelStateDB, netParams *chaincfg.Params, estimator chainfee.Estimator) (*lnwallet.LightningWallet, error) { wallet, err := lnwallet.NewLightningWallet(lnwallet.Config{ - Database: cdb, - Notifier: notifier, - SecretKeyRing: keyRing, - WalletController: wc, - Signer: signer, - ChainIO: bio, - FeeEstimator: estimator, - NetParams: *netParams, + Database: cdb, + Notifier: notifier, + SecretKeyRing: keyRing, + WalletController: wc, + Signer: signer, + ChainIO: bio, + FeeEstimator: estimator, + NetParams: *netParams, + CoinSelectionStrategy: wallet.CoinSelectionLargest, }) if err != nil { return nil, err diff --git a/lnwallet/chanfunding/wallet_assembler.go b/lnwallet/chanfunding/wallet_assembler.go index 104a5c05f..c5be0e25c 100644 --- a/lnwallet/chanfunding/wallet_assembler.go +++ b/lnwallet/chanfunding/wallet_assembler.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/btcutil/txsort" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcwallet/wallet" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" ) @@ -207,6 +208,10 @@ type WalletConfig struct { // CoinSource is what the WalletAssembler uses to list/locate coins. CoinSource CoinSource + // CoinSelectionStrategy is the strategy that is used for selecting + // coins when funding a transaction. + CoinSelectionStrategy wallet.CoinSelectionStrategy + // CoinSelectionLocker allows the WalletAssembler to gain exclusive // access to the current set of coins returned by the CoinSource. CoinSelectLocker CoinSelectionLocker diff --git a/lnwallet/config.go b/lnwallet/config.go index e85761693..7eeacb6ea 100644 --- a/lnwallet/config.go +++ b/lnwallet/config.go @@ -2,6 +2,7 @@ package lnwallet import ( "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcwallet/wallet" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" @@ -57,4 +58,8 @@ type Config struct { // passively rebroadcast transactions in the background until they're // detected as being confirmed. Rebroadcaster Rebroadcaster + + // CoinSelectionStrategy is the strategy that is used for selecting + // coins when funding a transaction. + CoinSelectionStrategy wallet.CoinSelectionStrategy } diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index 19633f23c..e4e4fd24c 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -27,6 +27,7 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/chain" + "github.com/btcsuite/btcwallet/wallet" "github.com/btcsuite/btcwallet/walletdb" _ "github.com/btcsuite/btcwallet/walletdb/bdb" "github.com/davecgh/go-spew/spew" @@ -349,14 +350,15 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness, } cfg := lnwallet.Config{ - Database: fullDB.ChannelStateDB(), - Notifier: notifier, - SecretKeyRing: keyRing, - WalletController: wc, - Signer: signer, - ChainIO: bio, - FeeEstimator: chainfee.NewStaticEstimator(2500, 0), - NetParams: *netParams, + Database: fullDB.ChannelStateDB(), + Notifier: notifier, + SecretKeyRing: keyRing, + WalletController: wc, + Signer: signer, + ChainIO: bio, + FeeEstimator: chainfee.NewStaticEstimator(2500, 0), + NetParams: *netParams, + CoinSelectionStrategy: wallet.CoinSelectionLargest, } wallet, err := lnwallet.NewLightningWallet(cfg) @@ -2984,28 +2986,33 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness, // Simulating external funding negotiation, we'll now create the // funding transaction for both parties. Utilizing existing tools, // we'll create a new chanfunding.Assembler hacked by Alice's wallet. - aliceChanFunder := chanfunding.NewWalletAssembler(chanfunding.WalletConfig{ - CoinSource: lnwallet.NewCoinSource(alice), - CoinSelectLocker: alice, - CoinLocker: alice, - Signer: alice.Cfg.Signer, - DustLimit: 600, - }) + aliceChanFunder := chanfunding.NewWalletAssembler( + chanfunding.WalletConfig{ + CoinSource: lnwallet.NewCoinSource(alice), + CoinSelectLocker: alice, + CoinLocker: alice, + Signer: alice.Cfg.Signer, + DustLimit: 600, + CoinSelectionStrategy: wallet.CoinSelectionLargest, + }, + ) // With the chan funder created, we'll now provision a funding intent, // bind the keys we obtained above, and finally obtain our funding // transaction and outpoint. - fundingIntent, err := aliceChanFunder.ProvisionChannel(&chanfunding.Request{ - LocalAmt: btcutil.Amount(chanAmt), - MinConfs: 1, - FeeRate: 253, - ChangeAddr: func() (btcutil.Address, error) { - return alice.NewAddress( - lnwallet.WitnessPubKey, true, - lnwallet.DefaultAccountName, - ) + fundingIntent, err := aliceChanFunder.ProvisionChannel( + &chanfunding.Request{ + LocalAmt: btcutil.Amount(chanAmt), + MinConfs: 1, + FeeRate: 253, + ChangeAddr: func() (btcutil.Address, error) { + return alice.NewAddress( + lnwallet.WitnessPubKey, true, + lnwallet.DefaultAccountName, + ) + }, }, - }) + ) require.NoError(t, err, "unable to perform coin selection") // With our intent created, we'll instruct it to finalize the funding diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index 7b9009fb1..183f4c72e 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -852,7 +852,10 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg CoinSelectLocker: l, CoinLocker: l, Signer: l.Cfg.Signer, - DustLimit: DustLimitForSize(input.P2WSHSize), + DustLimit: DustLimitForSize( + input.P2WSHSize, + ), + CoinSelectionStrategy: l.Cfg.CoinSelectionStrategy, } req.ChanFunder = chanfunding.NewWalletAssembler(cfg) } else {