@@ -6586,3 +6586,111 @@ def test_injectpaymentonion_failures(node_factory, executor):
65866586 # PAY_INJECTPAYMENTONION_FAILED
65876587 assert err .value .error ['code' ] == 218
65886588 assert 'onionreply' in err .value .error ['data' ]
6589+
6590+
6591+ def test_parallel_channels_reserve (node_factory , bitcoind ):
6592+ """Tests wether we are able to pay through parallel channels concurrently.
6593+ To do that we need to enable strict-forwarding."""
6594+
6595+ def direction (node1 , node2 ):
6596+ return 0 if node1 .info ["id" ] < node2 .info ["id" ] else 1
6597+
6598+ def get_local_channel_by_id (node , chanid ):
6599+ peerchannels = node .rpc .listpeerchannels ()["channels" ]
6600+ if not peerchannels :
6601+ return None
6602+ for c in peerchannels :
6603+ if c ["channel_id" ] == chanid :
6604+ return c
6605+ return None
6606+
6607+ opts = {
6608+ "fee-base" : 0 ,
6609+ "fee-per-satoshi" : 0 ,
6610+ "cltv-delta" : 6 ,
6611+ "dev-strict-forwarding" : None ,
6612+ }
6613+ l1 , l2 , l3 = node_factory .get_nodes (3 , opts = opts )
6614+
6615+ l1 .fundwallet (10 ** 7 )
6616+ l2 .fundwallet (10 ** 7 )
6617+
6618+ scids = []
6619+
6620+ l1 .rpc .connect (l2 .info ["id" ], "localhost" , l2 .port )
6621+ l2 .rpc .connect (l3 .info ["id" ], "localhost" , l3 .port )
6622+
6623+ c12 = l1 .rpc .fundchannel (l2 .info ["id" ], 3000_000 , minconf = 0 )["channel_id" ]
6624+
6625+ c23 = []
6626+ c23 .append (l2 .rpc .fundchannel (l3 .info ["id" ], 1000_000 , minconf = 0 )["channel_id" ])
6627+ c23 .append (l2 .rpc .fundchannel (l3 .info ["id" ], 2000_000 , minconf = 0 )["channel_id" ])
6628+
6629+ bitcoind .generate_block (6 )
6630+ sync_blockheight (bitcoind , [l1 , l2 , l3 ])
6631+
6632+ scids .append (get_local_channel_by_id (l1 , c12 )["short_channel_id" ])
6633+ scids .append (get_local_channel_by_id (l2 , c23 [0 ])["short_channel_id" ])
6634+ scids .append (get_local_channel_by_id (l2 , c23 [1 ])["short_channel_id" ])
6635+
6636+ for l in [l1 , l2 , l3 ]:
6637+ for c in scids :
6638+ l .wait_channel_active (c )
6639+
6640+ # we should be able to send these two parts:
6641+ nparts = 2
6642+ route_amounts = ["750000sat" , "1750000sat" ]
6643+ total_msat = sum ([Millisatoshi (a ) for a in route_amounts [:nparts ]])
6644+
6645+ # Test succeeds if we are able to pay this invoice
6646+ inv = l3 .rpc .call (
6647+ "invoice" ,
6648+ {"amount_msat" : total_msat , "label" : "inv" , "description" : "inv" , "cltv" : 10 },
6649+ )
6650+
6651+ # Share data by every route we will construct: l1->l2->l3
6652+ route = [
6653+ {
6654+ "id" : l2 .info ["id" ],
6655+ "direction" : direction (l1 , l2 ),
6656+ "delay" : 16 ,
6657+ "style" : "tlv" ,
6658+ },
6659+ {
6660+ "id" : l3 .info ["id" ],
6661+ "direction" : direction (l2 , l3 ),
6662+ "delay" : 10 ,
6663+ "style" : "tlv" ,
6664+ },
6665+ ]
6666+
6667+ # Send every part with sendpay
6668+ for part in range (nparts ):
6669+ this_part_msat = Millisatoshi (route_amounts [part ])
6670+ chan1 = get_local_channel_by_id (l1 , c12 )
6671+ chan2 = get_local_channel_by_id (l2 , c23 [part ])
6672+
6673+ route [0 ]["channel" ] = chan1 ["short_channel_id" ]
6674+ route [1 ]["channel" ] = chan2 ["short_channel_id" ]
6675+ route [0 ]["amount_msat" ] = route [1 ]["amount_msat" ] = this_part_msat
6676+
6677+ assert chan1 ["spendable_msat" ] >= this_part_msat
6678+ assert chan2 ["spendable_msat" ] >= this_part_msat
6679+
6680+ l1 .rpc .call (
6681+ "sendpay" ,
6682+ {
6683+ "route" : route ,
6684+ "payment_hash" : inv ["payment_hash" ],
6685+ "payment_secret" : inv ["payment_secret" ],
6686+ "amount_msat" : total_msat ,
6687+ "groupid" : 1 ,
6688+ "partid" : part + 1 ,
6689+ },
6690+ )
6691+ l1 .wait_for_htlcs ()
6692+
6693+ # Are we happy?
6694+ receipt = only_one (l3 .rpc .listinvoices ("inv" )["invoices" ])
6695+ assert receipt ["status" ] == "paid"
6696+ assert receipt ["amount_received_msat" ] == total_msat
0 commit comments