Skip to content

Commit 9a2b8f2

Browse files
committed
Randomize candidate paths during route selection.
1 parent 5ed2985 commit 9a2b8f2

File tree

4 files changed

+65
-258
lines changed

4 files changed

+65
-258
lines changed

lightning-invoice/src/utils.rs

Lines changed: 16 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, SignOrCreationError};
44
use payment::{Payer, Router};
55

6-
use crate::{prelude::*, Description, InvoiceDescription, Sha256};
76
use bech32::ToBase32;
87
use bitcoin_hashes::{Hash, sha256};
8+
use crate::prelude::*;
99
use lightning::chain;
1010
use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
1111
use lightning::chain::keysinterface::{Recipient, KeysInterface, Sign};
@@ -50,77 +50,14 @@ use sync::Mutex;
5050
/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
5151
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
5252
pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
53-
amt_msat: Option<u64>, description: String, payment_hash: PaymentHash, payment_secret: PaymentSecret,
54-
phantom_route_hints: Vec<PhantomRouteHints>, keys_manager: K, network: Currency,
53+
amt_msat: Option<u64>, description: String, payment_hash: PaymentHash, payment_secret:
54+
PaymentSecret, phantom_route_hints: Vec<PhantomRouteHints>, keys_manager: K, network: Currency
5555
) -> Result<Invoice, SignOrCreationError<()>> where K::Target: KeysInterface {
56-
let description = Description::new(description).map_err(SignOrCreationError::CreationError)?;
57-
let description = InvoiceDescription::Direct(&description,);
58-
_create_phantom_invoice::<Signer, K>(
59-
amt_msat, description, payment_hash, payment_secret, phantom_route_hints, keys_manager, network,
60-
)
61-
}
62-
63-
#[cfg(feature = "std")]
64-
/// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
65-
/// See [`PhantomKeysManager`] for more information on phantom node payments.
66-
///
67-
/// `phantom_route_hints` parameter:
68-
/// * Contains channel info for all nodes participating in the phantom invoice
69-
/// * Entries are retrieved from a call to [`ChannelManager::get_phantom_route_hints`] on each
70-
/// participating node
71-
/// * It is fine to cache `phantom_route_hints` and reuse it across invoices, as long as the data is
72-
/// updated when a channel becomes disabled or closes
73-
/// * Note that if too many channels are included in [`PhantomRouteHints::channels`], the invoice
74-
/// may be too long for QR code scanning. To fix this, `PhantomRouteHints::channels` may be pared
75-
/// down
76-
///
77-
/// `description_hash` is a SHA-256 hash of the description text
78-
///
79-
/// `payment_hash` and `payment_secret` come from [`ChannelManager::create_inbound_payment`] or
80-
/// [`ChannelManager::create_inbound_payment_for_hash`]. These values can be retrieved from any
81-
/// participating node.
82-
///
83-
/// Note that the provided `keys_manager`'s `KeysInterface` implementation must support phantom
84-
/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
85-
/// requirement).
86-
///
87-
/// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager
88-
/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
89-
/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
90-
pub fn create_phantom_invoice_with_description_hash<Signer: Sign, K: Deref>(
91-
amt_msat: Option<u64>, description_hash: Sha256, payment_hash: PaymentHash,
92-
payment_secret: PaymentSecret, phantom_route_hints: Vec<PhantomRouteHints>,
93-
keys_manager: K, network: Currency,
94-
) -> Result<Invoice, SignOrCreationError<()>> where K::Target: KeysInterface
95-
{
96-
97-
_create_phantom_invoice::<Signer, K>(
98-
amt_msat,
99-
InvoiceDescription::Hash(&description_hash),
100-
payment_hash, payment_secret, phantom_route_hints, keys_manager, network,
101-
)
102-
}
103-
104-
#[cfg(feature = "std")]
105-
fn _create_phantom_invoice<Signer: Sign, K: Deref>(
106-
amt_msat: Option<u64>, description: InvoiceDescription, payment_hash: PaymentHash,
107-
payment_secret: PaymentSecret, phantom_route_hints: Vec<PhantomRouteHints>,
108-
keys_manager: K, network: Currency,
109-
) -> Result<Invoice, SignOrCreationError<()>> where K::Target: KeysInterface
110-
{
11156
if phantom_route_hints.len() == 0 {
112-
return Err(SignOrCreationError::CreationError(
113-
CreationError::MissingRouteHints,
114-
));
57+
return Err(SignOrCreationError::CreationError(CreationError::MissingRouteHints))
11558
}
116-
let invoice = match description {
117-
InvoiceDescription::Direct(description) => {
118-
InvoiceBuilder::new(network).description(description.0.clone())
119-
}
120-
InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
121-
};
122-
123-
let mut invoice = invoice
59+
let mut invoice = InvoiceBuilder::new(network)
60+
.description(description)
12461
.current_timestamp()
12562
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
12663
.payment_secret(payment_secret)
@@ -189,57 +126,12 @@ where
189126
let duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)
190127
.expect("for the foreseeable future this shouldn't happen");
191128
create_invoice_from_channelmanager_and_duration_since_epoch(
192-
channelmanager, keys_manager, network, amt_msat, description, duration
193-
)
194-
}
195-
196-
#[cfg(feature = "std")]
197-
/// Utility to construct an invoice. Generally, unless you want to do something like a custom
198-
/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
199-
/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
200-
/// doesn't have to store preimage/payment secret information and (b) `ChannelManager` can verify
201-
/// that the payment secret is valid when the invoice is paid.
202-
/// Use this variant if you want to pass the `description_hash` to the invoice.
203-
pub fn create_invoice_from_channelmanager_with_description_hash<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
204-
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
205-
amt_msat: Option<u64>, description_hash: Sha256,
206-
) -> Result<Invoice, SignOrCreationError<()>>
207-
where
208-
M::Target: chain::Watch<Signer>,
209-
T::Target: BroadcasterInterface,
210-
K::Target: KeysInterface<Signer = Signer>,
211-
F::Target: FeeEstimator,
212-
L::Target: Logger,
213-
{
214-
use std::time::SystemTime;
215-
216-
let duration = SystemTime::now()
217-
.duration_since(SystemTime::UNIX_EPOCH)
218-
.expect("for the foreseeable future this shouldn't happen");
219-
220-
create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
221-
channelmanager, keys_manager, network, amt_msat, description_hash, duration,
222-
)
223-
}
224-
225-
/// See [`create_invoice_from_channelmanager_with_description_hash`]
226-
/// This version can be used in a `no_std` environment, where [`std::time::SystemTime`] is not
227-
/// available and the current time is supplied by the caller.
228-
pub fn create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
229-
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
230-
amt_msat: Option<u64>, description_hash: Sha256, duration_since_epoch: Duration,
231-
) -> Result<Invoice, SignOrCreationError<()>>
232-
where
233-
M::Target: chain::Watch<Signer>,
234-
T::Target: BroadcasterInterface,
235-
K::Target: KeysInterface<Signer = Signer>,
236-
F::Target: FeeEstimator,
237-
L::Target: Logger,
238-
{
239-
_create_invoice_from_channelmanager_and_duration_since_epoch(
240-
channelmanager, keys_manager, network, amt_msat,
241-
InvoiceDescription::Hash(&description_hash),
242-
duration_since_epoch,
129+
channelmanager,
130+
keys_manager,
131+
network,
132+
amt_msat,
133+
description,
134+
duration
243135
)
244136
}
245137

@@ -250,26 +142,6 @@ pub fn create_invoice_from_channelmanager_and_duration_since_epoch<Signer: Sign,
250142
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
251143
amt_msat: Option<u64>, description: String, duration_since_epoch: Duration,
252144
) -> Result<Invoice, SignOrCreationError<()>>
253-
where
254-
M::Target: chain::Watch<Signer>,
255-
T::Target: BroadcasterInterface,
256-
K::Target: KeysInterface<Signer = Signer>,
257-
F::Target: FeeEstimator,
258-
L::Target: Logger,
259-
{
260-
_create_invoice_from_channelmanager_and_duration_since_epoch(
261-
channelmanager, keys_manager, network, amt_msat,
262-
InvoiceDescription::Direct(
263-
&Description::new(description).map_err(SignOrCreationError::CreationError)?,
264-
),
265-
duration_since_epoch,
266-
)
267-
}
268-
269-
fn _create_invoice_from_channelmanager_and_duration_since_epoch<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>(
270-
channelmanager: &ChannelManager<Signer, M, T, K, F, L>, keys_manager: K, network: Currency,
271-
amt_msat: Option<u64>, description: InvoiceDescription, duration_since_epoch: Duration,
272-
) -> Result<Invoice, SignOrCreationError<()>>
273145
where
274146
M::Target: chain::Watch<Signer>,
275147
T::Target: BroadcasterInterface,
@@ -281,19 +153,12 @@ where
281153

282154
// `create_inbound_payment` only returns an error if the amount is greater than the total bitcoin
283155
// supply.
284-
let (payment_hash, payment_secret) = channelmanager
285-
.create_inbound_payment(amt_msat, DEFAULT_EXPIRY_TIME.try_into().unwrap())
156+
let (payment_hash, payment_secret) = channelmanager.create_inbound_payment(
157+
amt_msat, DEFAULT_EXPIRY_TIME.try_into().unwrap())
286158
.map_err(|()| SignOrCreationError::CreationError(CreationError::InvalidAmount))?;
287159
let our_node_pubkey = channelmanager.get_our_node_id();
288-
289-
let invoice = match description {
290-
InvoiceDescription::Direct(description) => {
291-
InvoiceBuilder::new(network).description(description.0.clone())
292-
}
293-
InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0),
294-
};
295-
296-
let mut invoice = invoice
160+
let mut invoice = InvoiceBuilder::new(network)
161+
.description(description)
297162
.duration_since_epoch(duration_since_epoch)
298163
.payee_pub_key(our_node_pubkey)
299164
.payment_hash(Hash::from_slice(&payment_hash.0).unwrap())
@@ -542,22 +407,6 @@ mod test {
542407
assert_eq!(events.len(), 2);
543408
}
544409

545-
#[test]
546-
fn test_create_invoice_with_description_hash() {
547-
let chanmon_cfgs = create_chanmon_cfgs(2);
548-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
549-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
550-
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
551-
let description_hash = crate::Sha256(Hash::hash("Testing description_hash".as_bytes()));
552-
let invoice = ::utils::create_invoice_from_channelmanager_with_description_hash_and_duration_since_epoch(
553-
&nodes[1].node, nodes[1].keys_manager, Currency::BitcoinTestnet, Some(10_000),
554-
description_hash, Duration::from_secs(1234567),
555-
).unwrap();
556-
assert_eq!(invoice.amount_pico_btc(), Some(100_000));
557-
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
558-
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Testing description_hash".as_bytes()))));
559-
}
560-
561410
#[test]
562411
fn test_hints_includes_single_channels_to_nodes() {
563412
let chanmon_cfgs = create_chanmon_cfgs(3);
@@ -839,29 +688,6 @@ mod test {
839688
}
840689
}
841690

842-
#[test]
843-
#[cfg(feature = "std")]
844-
fn create_phantom_invoice_with_description_hash() {
845-
let chanmon_cfgs = create_chanmon_cfgs(3);
846-
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
847-
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
848-
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
849-
850-
let payment_amt = 20_000;
851-
let (payment_hash, payment_secret) = nodes[1].node.create_inbound_payment(Some(payment_amt), 3600).unwrap();
852-
let route_hints = vec![
853-
nodes[1].node.get_phantom_route_hints(),
854-
nodes[2].node.get_phantom_route_hints(),
855-
];
856-
857-
let description_hash = crate::Sha256(Hash::hash("Description hash phantom invoice".as_bytes()));
858-
let invoice = ::utils::create_phantom_invoice_with_description_hash::<EnforcingSigner,&test_utils::TestKeysInterface>(Some(payment_amt), description_hash, payment_hash, payment_secret, route_hints, &nodes[1].keys_manager, Currency::BitcoinTestnet).unwrap();
859-
860-
assert_eq!(invoice.amount_pico_btc(), Some(200_000));
861-
assert_eq!(invoice.min_final_cltv_expiry(), MIN_FINAL_CLTV_EXPIRY as u64);
862-
assert_eq!(invoice.description(), InvoiceDescription::Hash(&crate::Sha256(Sha256::hash("Description hash phantom invoice".as_bytes()))));
863-
}
864-
865691
#[test]
866692
#[cfg(feature = "std")]
867693
fn test_multi_node_hints_includes_single_channels_to_participating_nodes() {

lightning/src/ln/channelmanager.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5505,12 +5505,6 @@ where
55055505
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
55065506
self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger)
55075507
.map(|(a, b)| (a, Vec::new(), b)));
5508-
5509-
let last_best_block_height = self.best_block.read().unwrap().height();
5510-
if height < last_best_block_height {
5511-
let timestamp = self.highest_seen_timestamp.load(Ordering::Acquire);
5512-
self.do_chain_event(Some(last_best_block_height), |channel| channel.best_block_updated(last_best_block_height, timestamp as u32, self.genesis_hash.clone(), self.get_our_node_id(), &self.logger));
5513-
}
55145508
}
55155509

55165510
fn best_block_updated(&self, header: &BlockHeader, height: u32) {

lightning/src/ln/functional_tests.rs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3940,32 +3940,6 @@ fn test_funding_peer_disconnect() {
39403940
assert!(found_announcement);
39413941
}
39423942

3943-
#[test]
3944-
fn test_funding_locked_without_best_block_updated() {
3945-
// Previously, if we were offline when a funding transaction was locked in, and then we came
3946-
// back online, calling best_block_updated once followed by transactions_confirmed, we'd not
3947-
// generate a funding_locked until a later best_block_updated. This tests that we generate the
3948-
// funding_locked immediately instead.
3949-
let chanmon_cfgs = create_chanmon_cfgs(2);
3950-
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
3951-
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
3952-
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
3953-
*nodes[0].connect_style.borrow_mut() = ConnectStyle::BestBlockFirstSkippingBlocks;
3954-
3955-
let funding_tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 0, InitFeatures::known(), InitFeatures::known());
3956-
3957-
let conf_height = nodes[0].best_block_info().1 + 1;
3958-
connect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH);
3959-
let block_txn = [funding_tx];
3960-
let conf_txn: Vec<_> = block_txn.iter().enumerate().collect();
3961-
let conf_block_header = nodes[0].get_block_header(conf_height);
3962-
nodes[0].node.transactions_confirmed(&conf_block_header, &conf_txn[..], conf_height);
3963-
3964-
// Ensure nodes[0] generates a funding_locked after the transactions_confirmed
3965-
let as_funding_locked = get_event_msg!(nodes[0], MessageSendEvent::SendFundingLocked, nodes[1].node.get_our_node_id());
3966-
nodes[1].node.handle_funding_locked(&nodes[0].node.get_our_node_id(), &as_funding_locked);
3967-
}
3968-
39693943
#[test]
39703944
fn test_drop_messages_peer_disconnect_dual_htlc() {
39713945
// Test that we can handle reconnecting when both sides of a channel have pending

0 commit comments

Comments
 (0)