@@ -2685,3 +2685,74 @@ def test_multifunding_all_amount(node_factory, bitcoind):
26852685
26862686 inv2 = l3 .rpc .invoice (100000 , 'i2' , 'i2' )['bolt11' ]
26872687 l1 .rpc .pay (inv2 )
2688+
2689+
2690+ @pytest .mark .parametrize ("dopay" , [True , False ]) # Whether to send a payment or not
2691+ def test_zeroconf_forget (node_factory , bitcoind , dopay : bool ):
2692+ """Reprotest for #8147: We should not forget a channel on which we received a zeroconf payment.
2693+
2694+ The channel forgetting code actually uses the fact that we ever
2695+ had a non-zero amount in this channel.
2696+
2697+ """
2698+ blocks = 50
2699+ plugin_path = Path (__file__ ).parent / "plugins" / "zeroconf-selective.py"
2700+ l1 , l2 = node_factory .get_nodes (
2701+ 2 ,
2702+ opts = [
2703+ {},
2704+ {
2705+ "plugin" : str (plugin_path ),
2706+ "zeroconf-allow" : "0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518" ,
2707+ "zeroconf-mindepth" : "0" ,
2708+ "dev-max-funding-unconfirmed-blocks" : blocks ,
2709+ },
2710+ ],
2711+ )
2712+
2713+ # Make it such that l1 cannot broadcast transactions
2714+ def censoring_sendrawtx (tx ):
2715+ return {"id" : tx ["id" ], "result" : {}}
2716+
2717+ l1 .daemon .rpcproxy .mock_rpc ("sendrawtransaction" , censoring_sendrawtx )
2718+
2719+ l1 .connect (l2 )
2720+ l1 .fundwallet (10 ** 7 )
2721+ l1 .rpc .fundchannel (l2 .info ["id" ], 10 ** 6 , mindepth = 0 )
2722+ sync_blockheight (bitcoind , [l1 , l2 ])
2723+ wait_for (lambda : l2 .rpc .listincoming ()["incoming" ] != [])
2724+
2725+ # If we are told to pay while still not confirmed we perform one
2726+ # payment. This causes us to have a non-zero stake in the channel,
2727+ # thus we should not forget the channel. If we don't then our
2728+ # stake will remain 0msat, hence we can forget the channel without
2729+ # risking any of our funds.
2730+ if dopay :
2731+ inv = l2 .rpc .invoice (1 , "payme" , "my stake in the unconfirmed channel" )
2732+ l1 .rpc .pay (inv ["bolt11" ])
2733+ wait_for (lambda : only_one (l2 .rpc .listpeerchannels ()['channels' ])['to_us_msat' ] == 1 )
2734+
2735+ # Now stop, in order to cause catchup and re-evaluate whether to forget the channel
2736+ l2 .stop ()
2737+
2738+ # Now we generate enough blocks to cause l2 to forget the channel.
2739+ bitcoind .generate_block (blocks ) # > blocks
2740+ l2 .start ()
2741+
2742+ sync_blockheight (bitcoind , [l1 , l2 ])
2743+
2744+ # It will have completed processing of last block before being able to process this one:
2745+ # This ensures l2 will have forgotten channel if it was going to.
2746+ bitcoind .generate_block (1 )
2747+ sync_blockheight (bitcoind , [l1 , l2 ])
2748+
2749+ have_forgotten = l2 .daemon .is_in_log (
2750+ r"Forgetting channel: It has been [0-9]+ blocks without the funding transaction"
2751+ )
2752+
2753+ if dopay :
2754+ assert not have_forgotten
2755+ assert len (l2 .rpc .listpeerchannels ()["channels" ]) == 1
2756+ else :
2757+ assert have_forgotten
2758+ assert l2 .rpc .listpeerchannels () == {"channels" : []}
0 commit comments