Skip to content

Commit c0112bb

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 05ea413 commit c0112bb

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;
@@ -86,24 +86,13 @@ fn do_channel_full_cycle<K: KVStore + Sync + Send>(
8686
.unwrap();
8787

8888
assert_eq!(node_a.list_peers().first().unwrap().node_id, node_b.node_id());
89-
expect_event!(node_a, ChannelPending);
89+
let funding_txo_a = expect_channel_pending_event!(node_a, node_b.node_id());
90+
let funding_txo_b = expect_channel_pending_event!(node_b, node_a.node_id());
91+
assert_eq!(funding_txo_a, funding_txo_b);
9092

91-
let funding_txo = match node_b.wait_next_event() {
92-
ref e @ Event::ChannelPending { funding_txo, .. } => {
93-
println!("{} got event {:?}", std::stringify!(node_b), e);
94-
assert_eq!(node_b.next_event().as_ref(), Some(e));
95-
node_b.event_handled();
96-
funding_txo
97-
}
98-
ref e => {
99-
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
100-
}
101-
};
102-
103-
wait_for_tx(&electrsd, funding_txo.txid);
93+
wait_for_tx(&electrsd, funding_txo_a.txid);
10494

10595
if !allow_0conf {
106-
println!("\n .. generating blocks ..");
10796
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
10897
}
10998

@@ -276,7 +265,7 @@ fn do_channel_full_cycle<K: KVStore + Sync + Send>(
276265
expect_event!(node_a, ChannelClosed);
277266
expect_event!(node_b, ChannelClosed);
278267

279-
wait_for_outpoint_spend(&electrsd, funding_txo);
268+
wait_for_outpoint_spend(&electrsd, funding_txo_b);
280269

281270
generate_blocks_and_wait(&bitcoind, &electrsd, 1);
282271
node_a.sync_wallets().unwrap();
@@ -341,6 +330,83 @@ fn channel_open_fails_when_funds_insufficient() {
341330
);
342331
}
343332

333+
#[test]
334+
fn multi_hop_sending() {
335+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
336+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
337+
338+
// Setup and fund 5 nodes
339+
let mut nodes = Vec::new();
340+
for _ in 0..5 {
341+
let config = random_config();
342+
let mut builder = NodeBuilder::from_config(config);
343+
builder.set_esplora_server(esplora_url.clone());
344+
let node = builder.build().unwrap();
345+
node.start().unwrap();
346+
nodes.push(node);
347+
}
348+
349+
let addresses = nodes.iter().map(|n| n.new_onchain_address().unwrap()).collect();
350+
let premine_amount_sat = 5_000_000;
351+
premine_and_distribute_funds(
352+
&bitcoind,
353+
&electrsd,
354+
addresses,
355+
Amount::from_sat(premine_amount_sat),
356+
);
357+
358+
for n in &nodes {
359+
n.sync_wallets().unwrap();
360+
assert_eq!(n.spendable_onchain_balance_sats().unwrap(), premine_amount_sat);
361+
assert_eq!(n.next_event(), None);
362+
}
363+
364+
// Setup channel topology:
365+
// (1M:0)- N2 -(1M:0)
366+
// / \
367+
// N0 -(100k:0)-> N1 N4
368+
// \ /
369+
// (1M:0)- N3 -(1M:0)
370+
371+
open_channel(&nodes[0], &nodes[1], 100_000, true, &electrsd);
372+
open_channel(&nodes[1], &nodes[2], 1_000_000, true, &electrsd);
373+
// We need to sync wallets in-between back-to-back channel opens from the same node so BDK
374+
// wallet picks up on the broadcast funding tx and doesn't double-spend itself.
375+
//
376+
// TODO: Remove once fixed in BDK.
377+
nodes[1].sync_wallets().unwrap();
378+
open_channel(&nodes[1], &nodes[3], 1_000_000, true, &electrsd);
379+
open_channel(&nodes[2], &nodes[4], 1_000_000, true, &electrsd);
380+
open_channel(&nodes[3], &nodes[4], 1_000_000, true, &electrsd);
381+
382+
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
383+
384+
for n in &nodes {
385+
n.sync_wallets().unwrap();
386+
}
387+
388+
expect_event!(nodes[0], ChannelReady);
389+
expect_event!(nodes[1], ChannelReady);
390+
expect_event!(nodes[1], ChannelReady);
391+
expect_event!(nodes[1], ChannelReady);
392+
expect_event!(nodes[2], ChannelReady);
393+
expect_event!(nodes[2], ChannelReady);
394+
expect_event!(nodes[3], ChannelReady);
395+
expect_event!(nodes[3], ChannelReady);
396+
expect_event!(nodes[4], ChannelReady);
397+
expect_event!(nodes[4], ChannelReady);
398+
399+
// Sleep a bit for gossip to propagate.
400+
// FIXME: This doesn't work anyways currently and should be removed when we have a solution.
401+
std::thread::sleep(std::time::Duration::from_secs(60));
402+
403+
let invoice = nodes[4].receive_payment(10000, &"asdf", 9217).unwrap();
404+
nodes[0].send_payment(&invoice).unwrap();
405+
406+
expect_event!(nodes[4], PaymentReceived);
407+
expect_event!(nodes[0], PaymentSuccessful);
408+
}
409+
344410
#[test]
345411
fn connect_to_public_testnet_esplora() {
346412
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)