@@ -5996,3 +5996,148 @@ def test_enableoffer(node_factory):
59965996 # Can't enable unknown.
59975997 with pytest .raises (RpcError , match = "Unknown offer" ):
59985998 l1 .rpc .enableoffer (offer_id = offer1 ['offer_id' ])
5999+
6000+
6001+ def get_local_channel_by_id (node , chanid ):
6002+ peerchannels = node .rpc .listpeerchannels ()["channels" ]
6003+ if not peerchannels :
6004+ return None
6005+ for c in peerchannels :
6006+ if c ["channel_id" ] == chanid :
6007+ return c
6008+ return None
6009+
6010+
6011+ def start_channels (connections ):
6012+ """Similar to join_nodes but with arbitrary connections."""
6013+ nodes = list ()
6014+ for src , dst , fundamount in connections :
6015+ nodes .append (src )
6016+ nodes .append (dst )
6017+ src .rpc .connect (dst .info ["id" ], "localhost" , dst .port )
6018+
6019+ bitcoind = nodes [0 ].bitcoin
6020+ # If we got here, we want to fund channels
6021+ for src , dst , fundamount in connections :
6022+ addr = src .rpc .newaddr ()["bech32" ]
6023+ bitcoind .rpc .sendtoaddress (addr , (fundamount + 1000000 ) / 10 ** 8 )
6024+
6025+ bitcoind .generate_block (1 )
6026+ sync_blockheight (bitcoind , nodes )
6027+ txids = []
6028+ chan_ids = []
6029+ for src , dst , fundamount in connections :
6030+ reply = src .rpc .fundchannel (
6031+ dst .info ["id" ], fundamount , announce = True , minconf = 0
6032+ )
6033+ txids .append (reply ["txid" ])
6034+ chan_ids .append (reply ["channel_id" ])
6035+
6036+ # Confirm all channels and wait for them to become usable
6037+ bitcoind .generate_block (1 , wait_for_mempool = txids )
6038+ scids = []
6039+ for con , mychan_id in zip (connections , chan_ids ):
6040+ src = con [0 ]
6041+ wait_for (
6042+ lambda : get_local_channel_by_id (src , mychan_id )["state" ]
6043+ == "CHANNELD_NORMAL"
6044+ )
6045+ scids .append (get_local_channel_by_id (src , mychan_id )["short_channel_id" ])
6046+
6047+ # Make sure they have all seen block so they don't complain about
6048+ # the coming gossip messages
6049+ sync_blockheight (bitcoind , nodes )
6050+ bitcoind .generate_block (5 )
6051+
6052+ # Make sure everyone sees all channels, all other nodes
6053+ for n in nodes :
6054+ for scid in scids :
6055+ n .wait_channel_active (scid )
6056+
6057+ # Make sure we have all node announcements, too
6058+ for n in nodes :
6059+ for n2 in nodes :
6060+ wait_for (
6061+ lambda : "alias" in only_one (n .rpc .listnodes (n2 .info ["id" ])["nodes" ])
6062+ )
6063+ return chan_ids
6064+
6065+
6066+ def test_parallel_channels_reserve (node_factory ):
6067+ """Tests wether we are able to pay through parallel channels concurrently."""
6068+ def direction (node1 , node2 ):
6069+ return 0 if node1 .info ["id" ] < node2 .info ["id" ] else 1
6070+
6071+ opts = {"disable-mpp" : None , "fee-base" : 0 , "fee-per-satoshi" : 0 , "cltv-delta" : 6 }
6072+ l1 , l2 , l3 = node_factory .get_nodes (3 , opts = opts )
6073+
6074+ chan_ids = start_channels (
6075+ [
6076+ (l1 , l2 , 100_000 ),
6077+ (l2 , l3 , 100_000 ),
6078+ (l1 , l2 , 200_000 ),
6079+ (l2 , l3 , 200_000 ),
6080+ (l1 , l2 , 300_000 ),
6081+ (l2 , l3 , 300_000 ),
6082+ (l1 , l2 , 400_000 ),
6083+ (l2 , l3 , 400_000 ),
6084+ ]
6085+ )
6086+
6087+ # we should be able to send these four parts:
6088+ nparts = 4
6089+ route_amounts = ["75000sat" , "175000sat" , "275000sat" , "375000sat" ]
6090+ total_msat = sum ([Millisatoshi (a ) for a in route_amounts [:nparts ]])
6091+
6092+ # Test succeeds if we are able to pay this invoice
6093+ inv = l3 .rpc .call (
6094+ "invoice" ,
6095+ {"amount_msat" : total_msat , "label" : "inv" , "description" : "inv" , "cltv" : 10 },
6096+ )
6097+
6098+ # Share data by every route we will construct: l1->l2->l3
6099+ route = [
6100+ {
6101+ "id" : l2 .info ["id" ],
6102+ "direction" : direction (l1 , l2 ),
6103+ "delay" : 16 ,
6104+ "style" : "tlv" ,
6105+ },
6106+ {
6107+ "id" : l3 .info ["id" ],
6108+ "direction" : direction (l2 , l3 ),
6109+ "delay" : 10 ,
6110+ "style" : "tlv" ,
6111+ },
6112+ ]
6113+
6114+ # Send every part with sendpay
6115+ for part in range (nparts ):
6116+ this_part_msat = Millisatoshi (route_amounts [part ])
6117+ chan1 = get_local_channel_by_id (l1 , chan_ids [part * 2 ])
6118+ chan2 = get_local_channel_by_id (l2 , chan_ids [part * 2 + 1 ])
6119+
6120+ route [0 ]["channel" ] = chan1 ["short_channel_id" ]
6121+ route [1 ]["channel" ] = chan2 ["short_channel_id" ]
6122+ route [0 ]["amount_msat" ] = route [1 ]["amount_msat" ] = this_part_msat
6123+
6124+ assert chan1 ["spendable_msat" ] >= this_part_msat
6125+ assert chan2 ["spendable_msat" ] >= this_part_msat
6126+
6127+ l1 .rpc .call (
6128+ "sendpay" ,
6129+ {
6130+ "route" : route ,
6131+ "payment_hash" : inv ["payment_hash" ],
6132+ "payment_secret" : inv ["payment_secret" ],
6133+ "amount_msat" : total_msat ,
6134+ "groupid" : 1 ,
6135+ "partid" : part + 1 ,
6136+ },
6137+ )
6138+ l1 .wait_for_htlcs ()
6139+
6140+ # Are we happy?
6141+ receipt = only_one (l3 .rpc .listinvoices ("inv" )["invoices" ])
6142+ assert receipt ["status" ] == "paid"
6143+ assert receipt ["amount_received_msat" ] == total_msat
0 commit comments