Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functional tests for BOLT 12 Offers payment flow #2697

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7779,15 +7779,15 @@ where
let payment_paths = self.create_blinded_payment_paths(amount_msats, payment_secret)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

#[cfg(not(feature = "no-std"))]
#[cfg(feature = "std")]
let builder = refund.respond_using_derived_keys(
payment_paths, payment_hash, expanded_key, entropy
)?;
#[cfg(feature = "no-std")]
#[cfg(not(feature = "std"))]
let created_at = Duration::from_secs(
self.highest_seen_timestamp.load(Ordering::Acquire) as u64
);
#[cfg(feature = "no-std")]
#[cfg(not(feature = "std"))]
let builder = refund.respond_using_derived_keys_no_std(
payment_paths, payment_hash, created_at, expanded_key, entropy
)?;
Expand Down Expand Up @@ -9224,17 +9224,17 @@ where
},
};

#[cfg(feature = "no-std")]
#[cfg(not(feature = "std"))]
let created_at = Duration::from_secs(
self.highest_seen_timestamp.load(Ordering::Acquire) as u64
);

if invoice_request.keys.is_some() {
#[cfg(not(feature = "no-std"))]
#[cfg(feature = "std")]
let builder = invoice_request.respond_using_derived_keys(
payment_paths, payment_hash
);
#[cfg(feature = "no-std")]
#[cfg(not(feature = "std"))]
let builder = invoice_request.respond_using_derived_keys_no_std(
payment_paths, payment_hash, created_at
);
Expand All @@ -9243,9 +9243,9 @@ where
Err(error) => Some(OffersMessage::InvoiceError(error.into())),
}
} else {
#[cfg(not(feature = "no-std"))]
#[cfg(feature = "std")]
let builder = invoice_request.respond_with(payment_paths, payment_hash);
#[cfg(feature = "no-std")]
#[cfg(not(feature = "std"))]
let builder = invoice_request.respond_with_no_std(
payment_paths, payment_hash, created_at
);
Expand Down Expand Up @@ -12487,7 +12487,7 @@ pub mod bench {
use bitcoin::blockdata::locktime::absolute::LockTime;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::{Block, Transaction, TxOut};
use bitcoin::{Transaction, TxOut};

use crate::sync::{Arc, Mutex, RwLock};

Expand Down Expand Up @@ -12527,7 +12527,7 @@ pub mod bench {
let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) };
let logger_a = test_utils::TestLogger::with_id("node a".to_owned());
let scorer = RwLock::new(test_utils::TestScorer::new());
let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &scorer);
let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(network, &logger_a)), &logger_a, &scorer);

let mut config: UserConfig = Default::default();
config.channel_config.max_dust_htlc_exposure = MaxDustHTLCExposure::FeeRateMultiplier(5_000_000 / 253);
Expand Down
7 changes: 7 additions & 0 deletions lightning/src/ln/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,13 @@ impl<T: sealed::AnchorsZeroFeeHtlcTx> Features<T> {
}
}

impl<T: sealed::RouteBlinding> Features<T> {
#[cfg(test)]
pub(crate) fn clear_route_blinding(&mut self) {
<T as sealed::RouteBlinding>::clear_bits(&mut self.flags);
}
}

#[cfg(test)]
impl<T: sealed::UnknownFeature> Features<T> {
pub(crate) fn unknown() -> Self {
Expand Down
92 changes: 70 additions & 22 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,29 @@
//! nodes for functional tests.

use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, chainmonitor::Persist};
use crate::sign::EntropySource;
use crate::chain::channelmonitor::ChannelMonitor;
use crate::chain::transaction::OutPoint;
use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
use crate::events::bump_transaction::{BumpTransactionEvent, BumpTransactionEventHandler, Wallet, WalletSource};
use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
use crate::routing::router::{self, PaymentParameters, Route, RouteParameters};
use crate::ln::features::InitFeatures;
use crate::ln::msgs;
use crate::ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
use crate::util::test_channel_signer::TestChannelSigner;
use crate::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMessageHandler};
use crate::ln::peer_handler::IgnoringMessageHandler;
use crate::onion_message::messenger::OnionMessenger;
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
use crate::routing::router::{self, PaymentParameters, Route, RouteParameters};
use crate::sign::{EntropySource, RandomBytes};
use crate::util::config::{UserConfig, MaxDustHTLCExposure};
use crate::util::errors::APIError;
#[cfg(test)]
use crate::util::logger::Logger;
use crate::util::scid_utils;
use crate::util::test_channel_signer::TestChannelSigner;
use crate::util::test_utils;
use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
use crate::util::errors::APIError;
use crate::util::config::{UserConfig, MaxDustHTLCExposure};
use crate::util::ser::{ReadableArgs, Writeable};
#[cfg(test)]
use crate::util::logger::Logger;

use bitcoin::blockdata::block::{Block, Header, Version};
use bitcoin::blockdata::locktime::absolute::LockTime;
Expand All @@ -43,13 +45,14 @@ use bitcoin::network::constants::Network;
use bitcoin::pow::CompactTarget;
use bitcoin::secp256k1::{PublicKey, SecretKey};

use alloc::rc::Rc;
use core::cell::RefCell;
use core::iter::repeat;
use core::mem;
use core::ops::Deref;
use crate::io;
use crate::prelude::*;
use core::cell::RefCell;
use alloc::rc::Rc;
use crate::sync::{Arc, Mutex, LockTestExt, RwLock};
use core::mem;
use core::iter::repeat;

pub const CHAN_CONFIRM_DEPTH: u32 = 10;

Expand Down Expand Up @@ -388,6 +391,7 @@ pub struct NodeCfg<'a> {
pub tx_broadcaster: &'a test_utils::TestBroadcaster,
pub fee_estimator: &'a test_utils::TestFeeEstimator,
pub router: test_utils::TestRouter<'a>,
pub message_router: test_utils::TestMessageRouter<'a>,
pub chain_monitor: test_utils::TestChainMonitor<'a>,
pub keys_manager: &'a test_utils::TestKeysInterface,
pub logger: &'a test_utils::TestLogger,
Expand All @@ -407,6 +411,26 @@ type TestChannelManager<'node_cfg, 'chan_mon_cfg> = ChannelManager<
&'chan_mon_cfg test_utils::TestLogger,
>;

type TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg> = OnionMessenger<
DedicatedEntropy,
&'node_cfg test_utils::TestKeysInterface,
&'chan_mon_cfg test_utils::TestLogger,
&'node_cfg test_utils::TestMessageRouter<'chan_mon_cfg>,
&'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>,
IgnoringMessageHandler,
>;

/// For use with [`OnionMessenger`] otherwise `test_restored_packages_retry` will fail. This is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinda unfortunate how brittle that test is. Opened #2827.

/// because that test uses older serialized data produced by calling [`EntropySource`] in a specific
/// manner. Using the same [`EntropySource`] with [`OnionMessenger`] would introduce another call,
/// causing the produced data to no longer match.
pub struct DedicatedEntropy(RandomBytes);

impl Deref for DedicatedEntropy {
type Target = RandomBytes;
fn deref(&self) -> &Self::Target { &self.0 }
}

pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> {
pub chain_source: &'chan_mon_cfg test_utils::TestChainSource,
pub tx_broadcaster: &'chan_mon_cfg test_utils::TestBroadcaster,
Expand All @@ -415,6 +439,7 @@ pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> {
pub chain_monitor: &'node_cfg test_utils::TestChainMonitor<'chan_mon_cfg>,
pub keys_manager: &'chan_mon_cfg test_utils::TestKeysInterface,
pub node: &'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>,
pub onion_messenger: TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg>,
pub network_graph: &'node_cfg NetworkGraph<&'chan_mon_cfg test_utils::TestLogger>,
pub gossip_sync: P2PGossipSync<&'node_cfg NetworkGraph<&'chan_mon_cfg test_utils::TestLogger>, &'chan_mon_cfg test_utils::TestChainSource, &'chan_mon_cfg test_utils::TestLogger>,
pub node_seed: [u8; 32],
Expand All @@ -432,6 +457,14 @@ pub struct Node<'chan_man, 'node_cfg: 'chan_man, 'chan_mon_cfg: 'node_cfg> {
&'chan_mon_cfg test_utils::TestLogger,
>,
}

impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
pub fn init_features(&self, peer_node_id: &PublicKey) -> InitFeatures {
self.override_init_features.borrow().clone()
.unwrap_or_else(|| self.node.init_features() | self.onion_messenger.provided_init_features(peer_node_id))
}
}

#[cfg(feature = "std")]
impl<'a, 'b, 'c> std::panic::UnwindSafe for Node<'a, 'b, 'c> {}
#[cfg(feature = "std")]
Expand Down Expand Up @@ -599,7 +632,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
node_signer: self.keys_manager,
signer_provider: self.keys_manager,
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) },
router: &test_utils::TestRouter::new(Arc::new(network_graph), &scorer),
router: &test_utils::TestRouter::new(Arc::new(network_graph), &self.logger, &scorer),
chain_monitor: self.chain_monitor,
tx_broadcaster: &broadcaster,
logger: &self.logger,
Expand Down Expand Up @@ -1054,6 +1087,7 @@ macro_rules! reload_node {

$new_channelmanager = _reload_node(&$node, $new_config, &chanman_encoded, $monitors_encoded);
$node.node = &$new_channelmanager;
$node.onion_messenger.set_offers_handler(&$new_channelmanager);
};
($node: expr, $chanman_encoded: expr, $monitors_encoded: expr, $persister: ident, $new_chain_monitor: ident, $new_channelmanager: ident) => {
reload_node!($node, $crate::util::config::UserConfig::default(), $chanman_encoded, $monitors_encoded, $persister, $new_chain_monitor, $new_channelmanager);
Expand Down Expand Up @@ -2897,7 +2931,8 @@ pub fn create_node_cfgs_with_persisters<'a>(node_count: usize, chanmon_cfgs: &'a
logger: &chanmon_cfgs[i].logger,
tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster,
fee_estimator: &chanmon_cfgs[i].fee_estimator,
router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].scorer),
router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].logger, &chanmon_cfgs[i].scorer),
message_router: test_utils::TestMessageRouter::new(network_graph.clone()),
chain_monitor,
keys_manager: &chanmon_cfgs[i].keys_manager,
node_seed: seed,
Expand Down Expand Up @@ -2951,14 +2986,19 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC
let connect_style = Rc::new(RefCell::new(ConnectStyle::random_style()));

for i in 0..node_count {
let dedicated_entropy = DedicatedEntropy(RandomBytes::new([i as u8; 32]));
let onion_messenger = OnionMessenger::new(
dedicated_entropy, cfgs[i].keys_manager, cfgs[i].logger, &cfgs[i].message_router,
&chan_mgrs[i], IgnoringMessageHandler {},
);
let gossip_sync = P2PGossipSync::new(cfgs[i].network_graph.as_ref(), None, cfgs[i].logger);
let wallet_source = Arc::new(test_utils::TestWalletSource::new(SecretKey::from_slice(&[i as u8 + 1; 32]).unwrap()));
nodes.push(Node{
chain_source: cfgs[i].chain_source, tx_broadcaster: cfgs[i].tx_broadcaster,
fee_estimator: cfgs[i].fee_estimator, router: &cfgs[i].router,
chain_monitor: &cfgs[i].chain_monitor, keys_manager: &cfgs[i].keys_manager,
node: &chan_mgrs[i], network_graph: cfgs[i].network_graph.as_ref(), gossip_sync,
node_seed: cfgs[i].node_seed, network_chan_count: chan_count.clone(),
node_seed: cfgs[i].node_seed, onion_messenger, network_chan_count: chan_count.clone(),
network_payment_count: payment_count.clone(), logger: cfgs[i].logger,
blocks: Arc::clone(&cfgs[i].tx_broadcaster.blocks),
connect_style: Rc::clone(&connect_style),
Expand All @@ -2973,16 +3013,24 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec<NodeC

for i in 0..node_count {
for j in (i+1)..node_count {
nodes[i].node.peer_connected(&nodes[j].node.get_our_node_id(), &msgs::Init {
features: nodes[j].override_init_features.borrow().clone().unwrap_or_else(|| nodes[j].node.init_features()),
let node_id_i = nodes[i].node.get_our_node_id();
let node_id_j = nodes[j].node.get_our_node_id();

let init_i = msgs::Init {
features: nodes[i].init_features(&node_id_j),
networks: None,
remote_network_address: None,
}, true).unwrap();
nodes[j].node.peer_connected(&nodes[i].node.get_our_node_id(), &msgs::Init {
features: nodes[i].override_init_features.borrow().clone().unwrap_or_else(|| nodes[i].node.init_features()),
};
let init_j = msgs::Init {
features: nodes[j].init_features(&node_id_i),
networks: None,
remote_network_address: None,
}, false).unwrap();
};

nodes[i].node.peer_connected(&node_id_j, &init_j, true).unwrap();
nodes[j].node.peer_connected(&node_id_i, &init_i, false).unwrap();
nodes[i].onion_messenger.peer_connected(&node_id_j, &init_j, true).unwrap();
nodes[j].onion_messenger.peer_connected(&node_id_i, &init_i, false).unwrap();
}
}

Expand Down
5 changes: 3 additions & 2 deletions lightning/src/ln/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5533,8 +5533,9 @@ fn test_key_derivation_params() {
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[0].chain_source), &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator, &chanmon_cfgs[0].persister, &keys_manager);
let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &chanmon_cfgs[0].logger));
let scorer = RwLock::new(test_utils::TestScorer::new());
let router = test_utils::TestRouter::new(network_graph.clone(), &scorer);
let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, router, chain_monitor, keys_manager: &keys_manager, network_graph, node_seed: seed, override_init_features: alloc::rc::Rc::new(core::cell::RefCell::new(None)) };
let router = test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[0].logger, &scorer);
let message_router = test_utils::TestMessageRouter::new(network_graph.clone());
let node = NodeCfg { chain_source: &chanmon_cfgs[0].chain_source, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, router, message_router, chain_monitor, keys_manager: &keys_manager, network_graph, node_seed: seed, override_init_features: alloc::rc::Rc::new(core::cell::RefCell::new(None)) };
let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
node_cfgs.remove(0);
node_cfgs.insert(0, node);
Expand Down
3 changes: 3 additions & 0 deletions lightning/src/ln/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ mod shutdown_tests;
#[cfg(all(test, async_signing))]
#[allow(unused_mut)]
mod async_signer_tests;
#[cfg(test)]
#[allow(unused_mut)]
mod offers_tests;

pub use self::peer_channel_encryptor::LN_MAX_MSG_LEN;

Expand Down
Loading
Loading