-
Notifications
You must be signed in to change notification settings - Fork 2.2k
funding: add fundmax flag to OpenChannelRequest
#6903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0c8aa81
e82410d
0e5b3e7
5d88693
b9bded3
d7f578b
8c1cf21
ff45fc7
94900ac
e352899
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -266,6 +266,15 @@ type InitFundingMsg struct { | |
| // peer. | ||
| MaxLocalCsv uint16 | ||
|
|
||
| // FundUpToMaxAmt is the maximum amount to try to commit to. If set, the | ||
| // MinFundAmt field denotes the acceptable minimum amount to commit to, | ||
| // while trying to commit as many coins as possible up to this value. | ||
| FundUpToMaxAmt btcutil.Amount | ||
|
|
||
| // MinFundAmt must be set iff FundUpToMaxAmt is set. It denotes the | ||
ellemouton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // minimum amount to commit to. | ||
| MinFundAmt btcutil.Amount | ||
|
|
||
| // ChanFunder is an optional channel funder that allows the caller to | ||
| // control exactly how the channel funding is carried out. If not | ||
| // specified, then the default chanfunding.WalletAssembler will be | ||
|
|
@@ -4079,23 +4088,26 @@ func (f *Manager) handleInitFundingMsg(msg *InitFundingMsg) { | |
| } | ||
|
||
|
|
||
| req := &lnwallet.InitFundingReserveMsg{ | ||
| ChainHash: &msg.ChainHash, | ||
| PendingChanID: chanID, | ||
| NodeID: peerKey, | ||
| NodeAddr: msg.Peer.Address(), | ||
| SubtractFees: msg.SubtractFees, | ||
| LocalFundingAmt: localAmt, | ||
| RemoteFundingAmt: 0, | ||
| CommitFeePerKw: commitFeePerKw, | ||
| FundingFeePerKw: msg.FundingFeePerKw, | ||
| PushMSat: msg.PushAmt, | ||
| Flags: channelFlags, | ||
| MinConfs: msg.MinConfs, | ||
| CommitType: commitType, | ||
| ChanFunder: msg.ChanFunder, | ||
| ZeroConf: zeroConf, | ||
| OptionScidAlias: scid, | ||
| ScidAliasFeature: scidFeatureVal, | ||
| ChainHash: &msg.ChainHash, | ||
| PendingChanID: chanID, | ||
| NodeID: peerKey, | ||
| NodeAddr: msg.Peer.Address(), | ||
| SubtractFees: msg.SubtractFees, | ||
| LocalFundingAmt: localAmt, | ||
| RemoteFundingAmt: 0, | ||
| FundUpToMaxAmt: msg.FundUpToMaxAmt, | ||
| MinFundAmt: msg.MinFundAmt, | ||
| RemoteChanReserve: chanReserve, | ||
| CommitFeePerKw: commitFeePerKw, | ||
| FundingFeePerKw: msg.FundingFeePerKw, | ||
| PushMSat: msg.PushAmt, | ||
| Flags: channelFlags, | ||
| MinConfs: msg.MinConfs, | ||
| CommitType: commitType, | ||
| ChanFunder: msg.ChanFunder, | ||
| ZeroConf: zeroConf, | ||
| OptionScidAlias: scid, | ||
| ScidAliasFeature: scidFeatureVal, | ||
| } | ||
|
|
||
| reservation, err := f.cfg.Wallet.InitChannelReservation(req) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -710,7 +710,7 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt, | |
| *wire.OutPoint, *wire.MsgTx) { | ||
|
|
||
| publ := fundChannel( | ||
| t, alice, bob, localFundingAmt, pushAmt, false, numConfs, | ||
| t, alice, bob, localFundingAmt, pushAmt, false, 0, 0, numConfs, | ||
| updateChan, announceChan, nil, | ||
| ) | ||
| fundingOutPoint := &wire.OutPoint{ | ||
|
|
@@ -723,7 +723,8 @@ func openChannel(t *testing.T, alice, bob *testNode, localFundingAmt, | |
| // fundChannel takes the funding process to the point where the funding | ||
| // transaction is confirmed on-chain. Returns the funding tx. | ||
| func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt, | ||
| pushAmt btcutil.Amount, subtractFees bool, numConfs uint32, | ||
| pushAmt btcutil.Amount, subtractFees bool, fundUpToMaxAmt, | ||
| minFundAmt btcutil.Amount, numConfs uint32, //nolint:unparam | ||
|
||
| updateChan chan *lnrpc.OpenStatusUpdate, announceChan bool, | ||
| chanType *lnwire.ChannelType) *wire.MsgTx { | ||
|
|
||
|
|
@@ -734,6 +735,8 @@ func fundChannel(t *testing.T, alice, bob *testNode, localFundingAmt, | |
| TargetPubkey: bob.privKey.PubKey(), | ||
| ChainHash: *fundingNetParams.GenesisHash, | ||
| SubtractFees: subtractFees, | ||
| FundUpToMaxAmt: fundUpToMaxAmt, | ||
| MinFundAmt: minFundAmt, | ||
| LocalFundingAmt: localFundingAmt, | ||
| PushAmt: lnwire.NewMSatFromSatoshis(pushAmt), | ||
| FundingFeePerKw: 1000, | ||
|
|
@@ -3730,7 +3733,7 @@ func TestFundingManagerFundAll(t *testing.T) { | |
| // Initiate a fund channel, and inspect the funding tx. | ||
| pushAmt := btcutil.Amount(0) | ||
| fundingTx := fundChannel( | ||
| t, alice, bob, test.spendAmt, pushAmt, true, 1, | ||
| t, alice, bob, test.spendAmt, pushAmt, true, 0, 0, 1, | ||
| updateChan, true, nil, | ||
| ) | ||
|
|
||
|
|
@@ -3761,6 +3764,157 @@ func TestFundingManagerFundAll(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| // TestFundingManagerFundMax tests that we can initiate a funding request to use | ||
| // the maximum allowed funds remaining in the wallet. | ||
| func TestFundingManagerFundMax(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
| // Helper function to create a test utxos | ||
| constructTestUtxos := func(values ...btcutil.Amount) []*lnwallet.Utxo { | ||
| var utxos []*lnwallet.Utxo | ||
| for _, value := range values { | ||
| utxos = append(utxos, &lnwallet.Utxo{ | ||
| AddressType: lnwallet.WitnessPubKey, | ||
| Value: value, | ||
| PkScript: mock.CoinPkScript, | ||
| OutPoint: wire.OutPoint{ | ||
| Hash: chainhash.Hash{}, | ||
| Index: 0, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| return utxos | ||
| } | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| coins []*lnwallet.Utxo | ||
| fundUpToMaxAmt btcutil.Amount | ||
| minFundAmt btcutil.Amount | ||
| pushAmt btcutil.Amount | ||
| change bool | ||
| }{ | ||
| { | ||
| // We will spend all the funds in the wallet, and expect | ||
| // no change output due to the dust limit. | ||
| coins: constructTestUtxos( | ||
| MaxBtcFundingAmount + 1, | ||
ellemouton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount, | ||
| minFundAmt: MinChanFundingSize, | ||
| pushAmt: 0, | ||
| change: false, | ||
| }, | ||
| { | ||
| // We spend less than the funds in the wallet, so a | ||
| // change output should be created. | ||
| coins: constructTestUtxos( | ||
| 2 * MaxBtcFundingAmount, | ||
| ), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount, | ||
| minFundAmt: MinChanFundingSize, | ||
| pushAmt: 0, | ||
| change: true, | ||
| }, | ||
| { | ||
| // We spend less than the funds in the wallet when | ||
| // setting a smaller channel size, so a change output | ||
| // should be created. | ||
| coins: constructTestUtxos( | ||
| MaxBtcFundingAmount, | ||
| ), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount / 2, | ||
| minFundAmt: MinChanFundingSize, | ||
| pushAmt: 0, | ||
| change: true, | ||
| }, | ||
| { | ||
| // We are using the entirety of two inputs for the | ||
| // funding of a channel, hence expect no change output. | ||
| coins: constructTestUtxos( | ||
| MaxBtcFundingAmount/2, MaxBtcFundingAmount/2, | ||
| ), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount, | ||
| minFundAmt: MinChanFundingSize, | ||
| pushAmt: 0, | ||
| change: false, | ||
| }, | ||
| { | ||
| // We are using a fraction of two inputs for the funding | ||
| // of our channel, hence expect a change output. | ||
| coins: constructTestUtxos( | ||
| MaxBtcFundingAmount/2, MaxBtcFundingAmount/2, | ||
| ), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount / 2, | ||
| minFundAmt: MinChanFundingSize, | ||
| pushAmt: 0, | ||
| change: true, | ||
| }, | ||
| { | ||
| // We are funding a channel with half of the balance in | ||
Crypt-iQ marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // our wallet hence expect a change output. Furthermore | ||
| // we push half of the funding amount to the remote end | ||
| // which we expect to succeed. | ||
| coins: constructTestUtxos(MaxBtcFundingAmount), | ||
| fundUpToMaxAmt: MaxBtcFundingAmount / 2, | ||
| minFundAmt: MinChanFundingSize / 4, | ||
| pushAmt: MaxBtcFundingAmount / 4, | ||
| change: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, test := range tests { | ||
ellemouton marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| test := test | ||
hieblmi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| t.Run(test.name, func(t *testing.T) { | ||
| t.Parallel() | ||
| // We set up our mock wallet to control a list of UTXOs | ||
| // that sum to more than the max channel size. | ||
| addFunds := func(fundingCfg *Config) { | ||
| wc := fundingCfg.Wallet.WalletController | ||
| mockWc, ok := wc.(*mock.WalletController) | ||
| if ok { | ||
| mockWc.Utxos = test.coins | ||
| } | ||
| } | ||
| alice, bob := setupFundingManagers(t, addFunds) | ||
| defer tearDownFundingManagers(t, alice, bob) | ||
|
|
||
| // We will consume the channel updates as we go, so no | ||
| // buffering is needed. | ||
| updateChan := make(chan *lnrpc.OpenStatusUpdate) | ||
|
|
||
| // Initiate a fund channel, and inspect the funding tx. | ||
| pushAmt := test.pushAmt | ||
| fundingTx := fundChannel( | ||
| t, alice, bob, 0, pushAmt, false, | ||
| test.fundUpToMaxAmt, test.minFundAmt, 1, | ||
| updateChan, true, nil, | ||
| ) | ||
|
|
||
| // Check whether the expected change output is present. | ||
| if test.change { | ||
| require.EqualValues(t, 2, len(fundingTx.TxOut)) | ||
| } | ||
|
|
||
| if !test.change { | ||
| require.EqualValues(t, 1, len(fundingTx.TxOut)) | ||
| } | ||
|
|
||
| // Inputs should be all funds in the wallet. | ||
| require.Equal(t, len(test.coins), len(fundingTx.TxIn)) | ||
|
|
||
| for i, txIn := range fundingTx.TxIn { | ||
| require.Equal( | ||
| t, test.coins[i].OutPoint, | ||
| txIn.PreviousOutPoint, | ||
| ) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // TestGetUpfrontShutdown tests different combinations of inputs for getting a | ||
| // shutdown script. It varies whether the peer has the feature set, whether | ||
| // the user has provided a script and our local configuration to test that | ||
|
|
@@ -4212,8 +4366,8 @@ func TestFundingManagerZeroConf(t *testing.T) { | |
|
|
||
| // Call fundChannel with the zero-conf ChannelType. | ||
| fundingTx := fundChannel( | ||
| t, alice, bob, fundingAmt, pushAmt, false, 1, updateChan, true, | ||
| &channelType, | ||
| t, alice, bob, fundingAmt, pushAmt, false, 0, 0, 1, updateChan, | ||
| true, &channelType, | ||
| ) | ||
| fundingOp := &wire.OutPoint{ | ||
| Hash: fundingTx.TxHash(), | ||
|
|
@@ -4309,3 +4463,35 @@ func TestFundingManagerZeroConf(t *testing.T) { | |
| // have been deleted from the database, as the channel is announced. | ||
| assertNoFwdingPolicy(t, alice, bob, fundingOp) | ||
| } | ||
|
|
||
| // TestCommitmentTypeFundmaxSanityCheck was introduced as a way of reminding | ||
| // developers of new channel commitment types to also consider the channel | ||
| // opening behavior with a specified fundmax flag. To give a hypothetical | ||
| // example, if ANCHOR types had been introduced after the fundmax flag had been | ||
| // activated, the developer would have had to code for the anchor reserve in the | ||
| // funding manager in the context of public and private channels. Otherwise | ||
| // inconsistent bahvior would have resulted when specifying fundmax for | ||
| // different types of channel openings. | ||
| // To ensure consistency this test compares a map of locally defined channel | ||
| // commitment types to the list of channel types that are defined in the proto | ||
| // files. It fails if the proto files contain additional commitment types. Once | ||
| // the developer considered the new channel type behavior it can be added in | ||
| // this test to the map `allCommitmentTypes`. | ||
| func TestCommitmentTypeFundmaxSanityCheck(t *testing.T) { | ||
|
||
| t.Parallel() | ||
| allCommitmentTypes := map[string]int{ | ||
| "UNKNOWN_COMMITMENT_TYPE": 0, | ||
| "LEGACY": 1, | ||
| "STATIC_REMOTE_KEY": 2, | ||
| "ANCHORS": 3, | ||
| "SCRIPT_ENFORCED_LEASE": 4, | ||
| } | ||
|
|
||
| for commitmentType := range lnrpc.CommitmentType_value { | ||
| if _, ok := allCommitmentTypes[commitmentType]; !ok { | ||
| t.Fatalf("Commitment type %s hasn't been considered "+ | ||
| "in the context of the --fundmax flag for "+ | ||
| "channel openings.", commitmentType) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.