Skip to content

Commit 535cb48

Browse files
committed
Introduce multi-hop payment test
We establish a simple 5-node topology and try to send a payment from one end to the other.
1 parent 01bcb1c commit 535cb48

File tree

2 files changed

+130
-20
lines changed

2 files changed

+130
-20
lines changed

src/test/functional_tests.rs

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::builder::NodeBuilder;
22
use crate::io::test_utils::TestSyncStore;
33
use crate::test::utils::*;
4-
use crate::test::utils::{expect_event, random_config, setup_two_nodes};
4+
use crate::test::utils::{expect_channel_pending_event, expect_event, open_channel, random_config};
55
use crate::{Error, Event, Node, PaymentDirection, PaymentStatus};
66

77
use bitcoin::Amount;
@@ -63,24 +63,13 @@ fn do_channel_full_cycle<K: KVStore + Sync + Send>(
6363
.unwrap();
6464

6565
assert_eq!(node_a.list_peers().first().unwrap().node_id, node_b.node_id());
66-
expect_event!(node_a, ChannelPending);
66+
let funding_txo_a = expect_channel_pending_event!(node_a, node_b.node_id());
67+
let funding_txo_b = expect_channel_pending_event!(node_b, node_a.node_id());
68+
assert_eq!(funding_txo_a, funding_txo_b);
6769

68-
let funding_txo = match node_b.wait_next_event() {
69-
ref e @ Event::ChannelPending { funding_txo, .. } => {
70-
println!("{} got event {:?}", std::stringify!(node_b), e);
71-
assert_eq!(node_b.next_event().as_ref(), Some(e));
72-
node_b.event_handled();
73-
funding_txo
74-
}
75-
ref e => {
76-
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
77-
}
78-
};
79-
80-
wait_for_tx(&electrsd, funding_txo.txid);
70+
wait_for_tx(&electrsd, funding_txo_a.txid);
8171

8272
if !allow_0conf {
83-
println!("\n .. generating blocks ..");
8473
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
8574
}
8675

@@ -253,7 +242,7 @@ fn do_channel_full_cycle<K: KVStore + Sync + Send>(
253242
expect_event!(node_a, ChannelClosed);
254243
expect_event!(node_b, ChannelClosed);
255244

256-
wait_for_outpoint_spend(&electrsd, funding_txo);
245+
wait_for_outpoint_spend(&electrsd, funding_txo_b);
257246

258247
generate_blocks_and_wait(&bitcoind, &electrsd, 1);
259248
node_a.sync_wallets().unwrap();
@@ -318,6 +307,83 @@ fn channel_open_fails_when_funds_insufficient() {
318307
);
319308
}
320309

310+
#[test]
311+
fn multi_hop_sending() {
312+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
313+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
314+
315+
// Setup and fund 5 nodes
316+
let mut nodes = Vec::new();
317+
for _ in 0..5 {
318+
let config = random_config();
319+
let mut builder = NodeBuilder::from_config(config);
320+
builder.set_esplora_server(esplora_url.clone());
321+
let node = builder.build().unwrap();
322+
node.start().unwrap();
323+
nodes.push(node);
324+
}
325+
326+
let addresses = nodes.iter().map(|n| n.new_onchain_address().unwrap()).collect();
327+
let premine_amount_sat = 5_000_000;
328+
premine_and_distribute_funds(
329+
&bitcoind,
330+
&electrsd,
331+
addresses,
332+
Amount::from_sat(premine_amount_sat),
333+
);
334+
335+
for n in &nodes {
336+
n.sync_wallets().unwrap();
337+
assert_eq!(n.spendable_onchain_balance_sats().unwrap(), premine_amount_sat);
338+
assert_eq!(n.next_event(), None);
339+
}
340+
341+
// Setup channel topology:
342+
// (1M:0)- N2 -(1M:0)
343+
// / \
344+
// N0 -(100k:0)-> N1 N4
345+
// \ /
346+
// (1M:0)- N3 -(1M:0)
347+
348+
open_channel(&nodes[0], &nodes[1], 100_000, true, &electrsd);
349+
open_channel(&nodes[1], &nodes[2], 1_000_000, true, &electrsd);
350+
// We need to sync wallets in-between back-to-back channel opens from the same node so BDK
351+
// wallet picks up on the broadcast funding tx and doesn't double-spend itself.
352+
//
353+
// TODO: Remove once fixed in BDK.
354+
nodes[1].sync_wallets().unwrap();
355+
open_channel(&nodes[1], &nodes[3], 1_000_000, true, &electrsd);
356+
open_channel(&nodes[2], &nodes[4], 1_000_000, true, &electrsd);
357+
open_channel(&nodes[3], &nodes[4], 1_000_000, true, &electrsd);
358+
359+
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
360+
361+
for n in &nodes {
362+
n.sync_wallets().unwrap();
363+
}
364+
365+
expect_event!(nodes[0], ChannelReady);
366+
expect_event!(nodes[1], ChannelReady);
367+
expect_event!(nodes[1], ChannelReady);
368+
expect_event!(nodes[1], ChannelReady);
369+
expect_event!(nodes[2], ChannelReady);
370+
expect_event!(nodes[2], ChannelReady);
371+
expect_event!(nodes[3], ChannelReady);
372+
expect_event!(nodes[3], ChannelReady);
373+
expect_event!(nodes[4], ChannelReady);
374+
expect_event!(nodes[4], ChannelReady);
375+
376+
// Sleep a bit for gossip to propagate.
377+
// FIXME: This doesn't work anyways currently and should be removed when we have a solution.
378+
std::thread::sleep(std::time::Duration::from_secs(60));
379+
380+
let invoice = nodes[4].receive_payment(10000, &"asdf", 9217).unwrap();
381+
nodes[0].send_payment(&invoice).unwrap();
382+
383+
expect_event!(nodes[4], PaymentReceived);
384+
expect_event!(nodes[0], PaymentSuccessful);
385+
}
386+
321387
#[test]
322388
fn connect_to_public_testnet_esplora() {
323389
let mut config = random_config();

src/test/utils.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::builder::NodeBuilder;
22
use crate::io::test_utils::TestSyncStore;
3-
use crate::{Config, Node};
3+
use crate::{Config, Event, Node};
44
use lightning::util::logger::{Level, Logger, Record};
5+
use lightning::util::persist::KVStore;
56

67
use bitcoin::{Address, Amount, Network, OutPoint, Txid};
78

@@ -25,7 +26,7 @@ macro_rules! expect_event {
2526
($node: expr, $event_type: ident) => {{
2627
match $node.wait_next_event() {
2728
ref e @ Event::$event_type { .. } => {
28-
println!("{} got event {:?}", std::stringify!($node), e);
29+
println!("{} got event {:?}", $node.node_id(), e);
2930
$node.event_handled();
3031
}
3132
ref e => {
@@ -37,6 +38,24 @@ macro_rules! expect_event {
3738

3839
pub(crate) use expect_event;
3940

41+
macro_rules! expect_channel_pending_event {
42+
($node: expr, $counterparty_node_id: expr) => {{
43+
match $node.wait_next_event() {
44+
ref e @ Event::ChannelPending { funding_txo, counterparty_node_id, .. } => {
45+
println!("{} got event {:?}", $node.node_id(), e);
46+
assert_eq!(counterparty_node_id, $counterparty_node_id);
47+
$node.event_handled();
48+
funding_txo
49+
}
50+
ref e => {
51+
panic!("{} got unexpected event!: {:?}", std::stringify!($node), e);
52+
}
53+
}
54+
}};
55+
}
56+
57+
pub(crate) use expect_channel_pending_event;
58+
4059
// Copied over from upstream LDK
4160
#[allow(dead_code)]
4261
pub struct TestLogger {
@@ -149,7 +168,7 @@ pub fn random_config() -> Config {
149168
let listening_address_str = format!("127.0.0.1:{}", rand_port);
150169
config.listening_address = Some(listening_address_str.parse().unwrap());
151170

152-
config.log_level = Level::Trace;
171+
config.log_level = Level::Gossip;
153172

154173
config
155174
}
@@ -201,6 +220,7 @@ pub(crate) fn setup_node(electrsd: &ElectrsD, config: Config) -> Node<TestSyncSt
201220
}
202221

203222
pub fn generate_blocks_and_wait(bitcoind: &BitcoinD, electrsd: &ElectrsD, num: usize) {
223+
print!("Generating {} blocks...", num);
204224
let cur_height = bitcoind.client.get_block_count().expect("failed to get current block height");
205225
let address = bitcoind
206226
.client
@@ -209,6 +229,8 @@ pub fn generate_blocks_and_wait(bitcoind: &BitcoinD, electrsd: &ElectrsD, num: u
209229
// TODO: expect this Result once the WouldBlock issue is resolved upstream.
210230
let _block_hashes_res = bitcoind.client.generate_to_address(num as u64, &address);
211231
wait_for_block(electrsd, cur_height as usize + num);
232+
print!(" Done!");
233+
println!("\n");
212234
}
213235

214236
pub fn wait_for_block(electrsd: &ElectrsD, min_height: usize) {
@@ -301,3 +323,25 @@ pub fn premine_and_distribute_funds(
301323

302324
generate_blocks_and_wait(bitcoind, electrsd, 1);
303325
}
326+
327+
pub fn open_channel<K: KVStore + Sync + Send>(
328+
node_a: &Node<K>, node_b: &Node<K>, funding_amount_sat: u64, announce: bool,
329+
electrsd: &ElectrsD,
330+
) {
331+
node_a
332+
.connect_open_channel(
333+
node_b.node_id(),
334+
node_b.listening_address().unwrap().into(),
335+
funding_amount_sat,
336+
None,
337+
None,
338+
announce,
339+
)
340+
.unwrap();
341+
assert!(node_a.list_peers().iter().find(|c| { c.node_id == node_b.node_id() }).is_some());
342+
343+
let funding_txo_a = expect_channel_pending_event!(node_a, node_b.node_id());
344+
let funding_txo_b = expect_channel_pending_event!(node_b, node_a.node_id());
345+
assert_eq!(funding_txo_a, funding_txo_b);
346+
wait_for_tx(&electrsd, funding_txo_a.txid);
347+
}

0 commit comments

Comments
 (0)