@@ -12,6 +12,7 @@ import (
1212 "github.com/lightningnetwork/lnd/lntest"
1313 "github.com/lightningnetwork/lnd/lntest/wait"
1414 "github.com/lightningnetwork/lnd/lntypes"
15+ "github.com/lightningnetwork/lnd/lnwallet/chainfee"
1516 "github.com/stretchr/testify/require"
1617)
1718
@@ -93,14 +94,17 @@ func coopCloseWithHTLCs(ht *lntest.HarnessTest) {
9394 // closure is set up. Let's settle the invoice.
9495 alice .RPC .SettleInvoice (preimage [:])
9596
96- // Pull the instant update off the wire to clear the path for the
97- // close pending update .
98- _ , err := closeClient .Recv ()
97+ // Pull the instant update off the wire and make sure the number of
98+ // pending HTLCs is as expected .
99+ update , err := closeClient .Recv ()
99100 require .NoError (ht , err )
101+ closeInstant := update .GetCloseInstant ()
102+ require .NotNil (ht , closeInstant )
103+ require .Equal (ht , closeInstant .NumPendingHtlcs , int32 (1 ))
100104
101105 // Wait for the next channel closure update. Now that we have settled
102106 // the only HTLC this should be imminent.
103- update , err : = closeClient .Recv ()
107+ update , err = closeClient .Recv ()
104108 require .NoError (ht , err )
105109
106110 // This next update should be a GetClosePending as it should be the
@@ -243,3 +247,76 @@ func coopCloseWithHTLCsWithRestart(ht *lntest.HarnessTest) {
243247 // Show that the address used is the one she requested.
244248 require .Equal (ht , outputDetail .Address , newAddr .Address )
245249}
250+
251+ // testCoopCloseExceedsMaxFee tests that we fail the coop close process if
252+ // the max fee rate exceeds the expected fee rate for the initial closing fee
253+ // proposal.
254+ func testCoopCloseExceedsMaxFee (ht * lntest.HarnessTest ) {
255+ const chanAmt = 1000000
256+
257+ // Create a channel Alice->Bob.
258+ chanPoints , nodes := ht .CreateSimpleNetwork (
259+ [][]string {nil , nil }, lntest.OpenChannelParams {
260+ Amt : chanAmt ,
261+ },
262+ )
263+
264+ alice , _ := nodes [0 ], nodes [1 ]
265+ chanPoint := chanPoints [0 ]
266+
267+ // Set the fee estimate for one block to 10 sat/vbyte.
268+ ht .SetFeeEstimateWithConf (chainfee .SatPerVByte (10 ).FeePerKWeight (), 1 )
269+
270+ // Have alice attempt to close the channel. We expect the initial fee
271+ // rate to exceed the max fee rate for the closing transaction so we
272+ // fail the closing process.
273+ req := & lnrpc.CloseChannelRequest {
274+ ChannelPoint : chanPoint ,
275+ MaxFeePerVbyte : 5 ,
276+ NoWait : true ,
277+ TargetConf : 1 ,
278+ }
279+ err := ht .CloseChannelAssertErr (alice , req )
280+ require .Contains (ht , err .Error (), "max_fee_per_vbyte (1250 sat/kw) is " +
281+ "less than the required fee rate (2500 sat/kw)" )
282+
283+ // Now close the channel with a appropriate max fee rate.
284+ closeClient := alice .RPC .CloseChannel (& lnrpc.CloseChannelRequest {
285+ ChannelPoint : chanPoint ,
286+ NoWait : true ,
287+ TargetConf : 1 ,
288+ MaxFeePerVbyte : 10 ,
289+ })
290+
291+ // Pull the instant update off the wire to clear the path for the
292+ // close pending update. Moreover confirm that there are no pending
293+ // HTLCs on the channel.
294+ update , err := closeClient .Recv ()
295+ require .NoError (ht , err )
296+ closeInstant := update .GetCloseInstant ()
297+ require .NotNil (ht , closeInstant )
298+ require .Equal (ht , closeInstant .NumPendingHtlcs , int32 (0 ))
299+
300+ // Wait for the channel to be closed.
301+ update , err = closeClient .Recv ()
302+ require .NoError (ht , err )
303+
304+ // This next update should be a GetClosePending as it should be the
305+ // negotiation of the coop close tx.
306+ closePending := update .GetClosePending ()
307+ require .NotNil (ht , closePending )
308+
309+ // Convert the txid we get from the PendingUpdate to a Hash so we can
310+ // wait for it to be mined.
311+ var closeTxid chainhash.Hash
312+ require .NoError (
313+ ht , closeTxid .SetBytes (closePending .Txid ),
314+ "invalid closing txid" ,
315+ )
316+
317+ // Wait for the close tx to be in the Mempool.
318+ ht .AssertTxInMempool (closeTxid )
319+
320+ // Wait for it to get mined and finish tearing down.
321+ ht .AssertStreamChannelCoopClosed (alice , chanPoint , false , closeClient )
322+ }
0 commit comments