Skip to content

Commit 97b27d4

Browse files
committed
Test v0.7 manual claim upgrades
Cover manually claiming and failing BOLT11 for-hash invoices that were created before upgrading, so the new ID-based APIs keep handling legacy payment-hash IDs. Co-Authored-By: HAL 9000
1 parent 6cc849f commit 97b27d4

2 files changed

Lines changed: 276 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ regex = "1.5.6"
9999
criterion = { version = "0.7.0", features = ["async_tokio"] }
100100
ldk-node-062 = { package = "ldk-node", version = "=0.6.2" }
101101
ldk-node-070 = { package = "ldk-node", version = "=0.7.0" }
102+
lightning-types-0-3 = { package = "lightning-types", version = "0.3.2" }
102103

103104
[target.'cfg(not(no_download))'.dev-dependencies]
104105
electrsd = { version = "0.36.1", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_29_0"] }

tests/upgrade_downgrade_tests.rs

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,281 @@
1313
//
1414
// TODO(@benthecarman) Bring back after 0.8 is cut.
1515

16+
#![cfg(not(feature = "uniffi"))]
17+
18+
mod common;
19+
20+
use std::str::FromStr;
21+
use std::time::Duration;
22+
23+
use crate::common::{
24+
expect_channel_pending_event, expect_channel_ready_event, expect_event,
25+
expect_payment_claimable_event, expect_payment_received_event, expect_payment_successful_event,
26+
generate_blocks_and_wait, generate_listening_addresses, premine_and_distribute_funds,
27+
random_config, random_storage_path, setup_bitcoind_and_electrsd, setup_node, wait_for_tx,
28+
TestChainSource,
29+
};
30+
use bitcoin::hashes::sha256::Hash as Sha256;
31+
use bitcoin::hashes::Hash;
32+
use bitcoin::secp256k1::PublicKey;
33+
use bitcoin::Amount;
34+
use ldk_node::config::Config;
35+
use ldk_node::entropy::NodeEntropy;
36+
use ldk_node::lightning::ln::channelmanager::PaymentId;
37+
use ldk_node::lightning::ln::msgs::SocketAddress as CurrentSocketAddress;
38+
use ldk_node::lightning_invoice::Bolt11Invoice as CurrentBolt11Invoice;
39+
use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus};
40+
use ldk_node::{Builder, Event, Node};
41+
use lightning_types::payment::{PaymentHash, PaymentPreimage};
42+
use lightning_types_0_3::payment::PaymentHash as OldPaymentHash;
43+
44+
const RECEIVER_SEED_BYTES: [u8; 64] = [43; 64];
45+
const CHANNEL_AMOUNT_SAT: u64 = 500_000;
46+
const CLAIM_AMOUNT_MSAT: u64 = 100_000;
47+
const FAIL_AMOUNT_MSAT: u64 = 200_000;
48+
49+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
50+
async fn v0_7_for_hash_payments_can_be_manually_resolved_after_upgrade() {
51+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
52+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
53+
let chain_source = TestChainSource::Esplora(&electrsd);
54+
55+
let payer_config = random_config();
56+
let payer = setup_node(&chain_source, payer_config);
57+
58+
let receiver_storage_path = random_storage_path().to_str().unwrap().to_owned();
59+
let receiver_addresses = generate_listening_addresses();
60+
let old_receiver_addresses = to_v0_7_socket_addresses(&receiver_addresses);
61+
let old_receiver =
62+
build_v0_7_receiver(receiver_storage_path.clone(), old_receiver_addresses, &esplora_url);
63+
64+
let payer_addr = payer.onchain_payment().new_address().unwrap();
65+
premine_and_distribute_funds(
66+
&bitcoind.client,
67+
&electrsd.client,
68+
vec![payer_addr],
69+
Amount::from_sat(1_000_000),
70+
)
71+
.await;
72+
payer.sync_wallets().unwrap();
73+
old_receiver.sync_wallets().unwrap();
74+
75+
let old_receiver_addr = to_current_socket_address(
76+
old_receiver.listening_addresses().unwrap().first().unwrap().clone(),
77+
);
78+
payer
79+
.open_channel(
80+
old_receiver.node_id(),
81+
old_receiver_addr.clone(),
82+
CHANNEL_AMOUNT_SAT,
83+
None,
84+
None,
85+
)
86+
.unwrap();
87+
88+
let funding_txo_a = expect_channel_pending_event!(payer, old_receiver.node_id());
89+
let funding_txo_b = expect_v0_7_channel_pending(&old_receiver, payer.node_id()).await;
90+
assert_eq!(funding_txo_a, funding_txo_b);
91+
wait_for_tx(&electrsd.client, funding_txo_a.txid).await;
92+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
93+
payer.sync_wallets().unwrap();
94+
old_receiver.sync_wallets().unwrap();
95+
expect_channel_ready_event!(payer, old_receiver.node_id());
96+
expect_v0_7_channel_ready(&old_receiver, payer.node_id()).await;
97+
wait_for_current_channel_usable(&payer, old_receiver.node_id(), CLAIM_AMOUNT_MSAT).await;
98+
99+
let invoice_description = ldk_node_070::lightning_invoice::Bolt11InvoiceDescription::Direct(
100+
ldk_node_070::lightning_invoice::Description::new("upgrade manual".to_owned()).unwrap(),
101+
);
102+
let claim_preimage = [42u8; 32];
103+
let claim_hash = payment_hash_from_preimage(claim_preimage);
104+
let claim_invoice = old_receiver
105+
.bolt11_payment()
106+
.receive_for_hash(
107+
CLAIM_AMOUNT_MSAT,
108+
&invoice_description,
109+
3600,
110+
OldPaymentHash(claim_hash.0),
111+
)
112+
.unwrap()
113+
.to_string();
114+
115+
let fail_preimage = [43u8; 32];
116+
let fail_hash = payment_hash_from_preimage(fail_preimage);
117+
let fail_invoice = old_receiver
118+
.bolt11_payment()
119+
.receive_for_hash(FAIL_AMOUNT_MSAT, &invoice_description, 3600, OldPaymentHash(fail_hash.0))
120+
.unwrap()
121+
.to_string();
122+
123+
old_receiver.stop().unwrap();
124+
125+
let receiver = build_current_receiver(receiver_storage_path, receiver_addresses, &esplora_url);
126+
assert_eq!(receiver.node_id(), old_receiver.node_id());
127+
assert_legacy_manual_payment(&receiver, claim_hash, CLAIM_AMOUNT_MSAT);
128+
assert_legacy_manual_payment(&receiver, fail_hash, FAIL_AMOUNT_MSAT);
129+
130+
payer.connect(receiver.node_id(), old_receiver_addr, true).unwrap();
131+
wait_for_current_channel_usable(&payer, receiver.node_id(), CLAIM_AMOUNT_MSAT).await;
132+
133+
let claim_invoice = CurrentBolt11Invoice::from_str(&claim_invoice).unwrap();
134+
let payer_claim_id = payer.bolt11_payment().send(&claim_invoice, None).unwrap();
135+
let (claim_payment_id, claimable_amount_msat) =
136+
expect_payment_claimable_event!(receiver, claim_hash, CLAIM_AMOUNT_MSAT);
137+
assert_eq!(claim_payment_id, PaymentId(claim_hash.0));
138+
receiver
139+
.bolt11_payment()
140+
.claim_for_id(claim_payment_id, claimable_amount_msat, PaymentPreimage(claim_preimage))
141+
.unwrap();
142+
let received_payment_id = expect_payment_received_event!(receiver, CLAIM_AMOUNT_MSAT);
143+
assert_eq!(received_payment_id, claim_payment_id);
144+
expect_payment_successful_event!(payer, payer_claim_id, None);
145+
assert_eq!(receiver.payment(&claim_payment_id).unwrap().status, PaymentStatus::Succeeded);
146+
147+
let fail_invoice = CurrentBolt11Invoice::from_str(&fail_invoice).unwrap();
148+
let payer_fail_id = payer.bolt11_payment().send(&fail_invoice, None).unwrap();
149+
let (fail_payment_id, _) =
150+
expect_payment_claimable_event!(receiver, fail_hash, FAIL_AMOUNT_MSAT);
151+
assert_eq!(fail_payment_id, PaymentId(fail_hash.0));
152+
receiver.bolt11_payment().fail_for_id(fail_payment_id).unwrap();
153+
expect_event!(payer, PaymentFailed);
154+
assert_eq!(payer.payment(&payer_fail_id).unwrap().status, PaymentStatus::Failed);
155+
assert_eq!(receiver.payment(&fail_payment_id).unwrap().status, PaymentStatus::Failed);
156+
157+
payer.stop().unwrap();
158+
receiver.stop().unwrap();
159+
}
160+
161+
fn build_v0_7_receiver(
162+
storage_path: String,
163+
listening_addresses: Vec<ldk_node_070::lightning::ln::msgs::SocketAddress>, esplora_url: &str,
164+
) -> ldk_node_070::Node {
165+
let mut config = ldk_node_070::config::Config::default();
166+
config.network = bitcoin::Network::Regtest;
167+
config.storage_dir_path = storage_path;
168+
config.anchor_channels_config = None;
169+
170+
let mut builder = ldk_node_070::Builder::from_config(config);
171+
builder.set_entropy_seed_bytes(RECEIVER_SEED_BYTES);
172+
builder.set_listening_addresses(listening_addresses).unwrap();
173+
builder.set_node_alias("upgrade-receiver".to_string()).unwrap();
174+
builder.set_chain_source_esplora(esplora_url.to_owned(), None);
175+
176+
let node = builder.build().unwrap();
177+
node.start().unwrap();
178+
node
179+
}
180+
181+
fn build_current_receiver(
182+
storage_path: String, listening_addresses: Vec<CurrentSocketAddress>, esplora_url: &str,
183+
) -> Node {
184+
let mut config = Config::default();
185+
config.network = bitcoin::Network::Regtest;
186+
config.storage_dir_path = storage_path;
187+
config.listening_addresses = Some(listening_addresses);
188+
config.node_alias = common::random_node_alias();
189+
190+
let mut builder = Builder::from_config(config);
191+
builder.set_chain_source_esplora(esplora_url.to_owned(), None);
192+
let node = builder.build(NodeEntropy::from_seed_bytes(RECEIVER_SEED_BYTES)).unwrap();
193+
node.start().unwrap();
194+
node
195+
}
196+
197+
fn payment_hash_from_preimage(preimage: [u8; 32]) -> PaymentHash {
198+
PaymentHash(Sha256::hash(&preimage).to_byte_array())
199+
}
200+
201+
fn assert_legacy_manual_payment(node: &Node, payment_hash: PaymentHash, amount_msat: u64) {
202+
let payment_id = PaymentId(payment_hash.0);
203+
let payment = node.payment(&payment_id).unwrap();
204+
assert_eq!(payment.id, payment_id);
205+
assert_eq!(payment.amount_msat, Some(amount_msat));
206+
assert_eq!(payment.direction, PaymentDirection::Inbound);
207+
assert_eq!(payment.status, PaymentStatus::Pending);
208+
assert!(matches!(payment.kind, PaymentKind::Bolt11 { preimage: None, .. }));
209+
}
210+
211+
fn to_current_socket_address(
212+
address: ldk_node_070::lightning::ln::msgs::SocketAddress,
213+
) -> CurrentSocketAddress {
214+
match address {
215+
ldk_node_070::lightning::ln::msgs::SocketAddress::TcpIpV4 { addr, port } => {
216+
CurrentSocketAddress::TcpIpV4 { addr, port }
217+
},
218+
_ => panic!("unexpected non-IPv4 test address: {:?}", address),
219+
}
220+
}
221+
222+
fn to_v0_7_socket_addresses(
223+
addresses: &[CurrentSocketAddress],
224+
) -> Vec<ldk_node_070::lightning::ln::msgs::SocketAddress> {
225+
addresses
226+
.iter()
227+
.map(|address| match address {
228+
CurrentSocketAddress::TcpIpV4 { addr, port } => {
229+
ldk_node_070::lightning::ln::msgs::SocketAddress::TcpIpV4 {
230+
addr: *addr,
231+
port: *port,
232+
}
233+
},
234+
_ => panic!("unexpected non-IPv4 test address: {:?}", address),
235+
})
236+
.collect()
237+
}
238+
239+
async fn expect_v0_7_channel_pending(
240+
node: &ldk_node_070::Node, expected_counterparty: PublicKey,
241+
) -> bitcoin::OutPoint {
242+
match next_v0_7_event(node).await {
243+
ldk_node_070::Event::ChannelPending { counterparty_node_id, funding_txo, .. } => {
244+
assert_eq!(counterparty_node_id, expected_counterparty);
245+
node.event_handled().unwrap();
246+
funding_txo
247+
},
248+
event => panic!("{} got unexpected event: {:?}", node.node_id(), event),
249+
}
250+
}
251+
252+
async fn expect_v0_7_channel_ready(node: &ldk_node_070::Node, expected_counterparty: PublicKey) {
253+
match next_v0_7_event(node).await {
254+
ldk_node_070::Event::ChannelReady { counterparty_node_id, .. } => {
255+
assert_eq!(counterparty_node_id, Some(expected_counterparty));
256+
node.event_handled().unwrap();
257+
},
258+
event => panic!("{} got unexpected event: {:?}", node.node_id(), event),
259+
}
260+
}
261+
262+
async fn next_v0_7_event(node: &ldk_node_070::Node) -> ldk_node_070::Event {
263+
tokio::time::timeout(Duration::from_secs(common::INTEROP_TIMEOUT_SECS), node.next_event_async())
264+
.await
265+
.unwrap_or_else(|_| panic!("{} timed out waiting for event", node.node_id()))
266+
}
267+
268+
async fn wait_for_current_channel_usable(
269+
node: &Node, counterparty_node_id: PublicKey, min_outbound_amount_msat: u64,
270+
) {
271+
let deadline = tokio::time::Instant::now() + Duration::from_secs(180);
272+
while tokio::time::Instant::now() < deadline {
273+
let is_usable = node.list_channels().iter().any(|c| {
274+
c.counterparty.node_id == counterparty_node_id
275+
&& c.is_usable
276+
&& c.next_outbound_htlc_limit_msat >= min_outbound_amount_msat
277+
});
278+
if is_usable {
279+
return;
280+
}
281+
tokio::time::sleep(Duration::from_millis(100)).await;
282+
}
283+
panic!(
284+
"channel from {} to {} not ready to send {} msat within 180s",
285+
node.node_id(),
286+
counterparty_node_id,
287+
min_outbound_amount_msat
288+
);
289+
}
290+
16291
// To keep monitoring whether the serialized node/channel/payment state remains
17292
// understandable by v0.7.0, these tests intentionally write current state through
18293
// the legacy v1 filesystem-store implementation via `build_with_store`, then

0 commit comments

Comments
 (0)