@@ -831,3 +831,53 @@ def test_xpay_twohop_bug(node_factory, bitcoind):
831831 # This doesn't!
832832 l1 .rpc .xpay (inv )
833833 l1 .daemon .wait_for_log (f'Adding HTLC 1 amount=15002msat cltv={ 110 + 1 + 100 + 200 + 400 } ' )
834+
835+
836+ def test_attempt_notifications (node_factory ):
837+ plugin_path = os .path .join (os .getcwd (), 'tests/plugins/custom_notifications.py' )
838+ l1 , l2 , l3 = node_factory .line_graph (3 , wait_for_announce = True ,
839+ opts = [{"plugin" : plugin_path }, {}, {}])
840+
841+ scid12 = only_one (l1 .rpc .listpeerchannels (l2 .info ['id' ])['channels' ])['short_channel_id' ]
842+ scid12_dir = only_one (l1 .rpc .listpeerchannels (l2 .info ['id' ])['channels' ])['direction' ]
843+ scid23 = only_one (l2 .rpc .listpeerchannels (l3 .info ['id' ])['channels' ])['short_channel_id' ]
844+ scid23_dir = only_one (l2 .rpc .listpeerchannels (l3 .info ['id' ])['channels' ])['direction' ]
845+ inv1 = l3 .rpc .invoice (5000000 , 'test_attempt_notifications1' , 'test_attempt_notifications1' )
846+ l1 .rpc .xpay (inv1 ['bolt11' ])
847+
848+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_start: " )
849+ regex = r".*Got xpay_attempt_start: \{'payment_hash': '" + inv1 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1, 'total_payment_msat': 5000000, 'attempt_msat': 5000000, 'hops': \[\{'next_node': '" + l2 .info ['id' ] + r"', 'short_channel_id': '" + scid12 + r"', 'direction': " + str (scid12_dir ) + r", 'channel_in_msat': 5000051, 'channel_out_msat': 5000051\}, \{'next_node': '" + l3 .info ['id' ] + r"', 'short_channel_id': '" + scid23 + r"', 'direction': " + str (scid23_dir ) + r", 'channel_in_msat': 5000051, 'channel_out_msat': 5000000\}\]\}"
850+ assert re .match (regex , line )
851+
852+ # Note, duration always has 9 decimals, EXCEPT that the python code interprets it, so if the last digit is a 0 it will only print 8.
853+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_end: " )
854+ regex = r".*Got xpay_attempt_end: \{'status': 'success', 'duration': [0-9]*\.[0-9]*, 'payment_hash': '" + inv1 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1\}"
855+ assert re .match (regex , line )
856+
857+ inv2 = l3 .rpc .invoice (10000000 , 'test_attempt_notifications2' , 'test_attempt_notifications2' )
858+ l3 .rpc .delinvoice ('test_attempt_notifications2' , "unpaid" )
859+
860+ # Final node failure
861+ with pytest .raises (RpcError , match = r"Destination said it doesn't know invoice: incorrect_or_unknown_payment_details" ):
862+ l1 .rpc .xpay (inv2 ['bolt11' ])
863+
864+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_start: " )
865+ regex = r".*Got xpay_attempt_start: \{'payment_hash': '" + inv2 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1, 'total_payment_msat': 10000000, 'attempt_msat': 10000000, 'hops': \[\{'next_node': '" + l2 .info ['id' ] + r"', 'short_channel_id': '" + scid12 + r"', 'direction': " + str (scid12_dir ) + r", 'channel_in_msat': 10000101, 'channel_out_msat': 10000101\}, \{'next_node': '" + l3 .info ['id' ] + r"', 'short_channel_id': '" + scid23 + r"', 'direction': " + str (scid23_dir ) + r", 'channel_in_msat': 10000101, 'channel_out_msat': 10000000\}\]\}"
866+ assert re .match (regex , line )
867+
868+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_end: " )
869+ regex = r".*Got xpay_attempt_end: \{'status': 'failure', 'payment_hash': '" + inv2 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1, 'failed_msg': '400f00000000009896800000006c', 'duration': [0-9]*\.[0-9]*, 'failed_node_id': '" + l3 .info ['id' ] + r"', 'error_code': 16399, 'error_message': 'incorrect_or_unknown_payment_details'\}"
870+ assert re .match (regex , line )
871+
872+ # Intermediary node failure
873+ l3 .stop ()
874+ with pytest .raises (RpcError , match = r"Failed after 1 attempts" ):
875+ l1 .rpc .xpay (inv2 ['bolt11' ])
876+
877+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_start: " )
878+ regex = r".*Got xpay_attempt_start: \{'payment_hash': '" + inv2 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1, 'total_payment_msat': 10000000, 'attempt_msat': 10000000, 'hops': \[\{'next_node': '" + l2 .info ['id' ] + r"', 'short_channel_id': '" + scid12 + r"', 'direction': " + str (scid12_dir ) + r", 'channel_in_msat': 10000101, 'channel_out_msat': 10000101\}, \{'next_node': '" + l3 .info ['id' ] + r"', 'short_channel_id': '" + scid23 + r"', 'direction': " + str (scid23_dir ) + r", 'channel_in_msat': 10000101, 'channel_out_msat': 10000000\}\]\}"
879+ assert re .match (regex , line )
880+
881+ line = l1 .daemon .wait_for_log ("plugin-custom_notifications.py: Got xpay_attempt_end: " )
882+ regex = r".*Got xpay_attempt_end: \{'status': 'failure', 'payment_hash': '" + inv2 ['payment_hash' ] + r"', 'groupid': [0-9]*, 'partid': 1, 'failed_msg': '1007[a-f0-9]*', 'duration': [0-9]*\.[0-9]{9}, 'failed_node_id': '" + l2 .info ['id' ] + r"', 'failed_short_channel_id': '" + scid23 + r"', 'failed_direction': " + str (scid23_dir ) + r", 'error_code': 4103, 'error_message': 'temporary_channel_failure'\}"
883+ assert re .match (regex , line )
0 commit comments