use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, keysinterface::EntropySource};
use crate::chain::channelmonitor::ChannelMonitor;
use crate::chain::transaction::OutPoint;
+use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose};
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
-use crate::ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, PaymentId, MIN_CLTV_EXPIRY_DELTA};
+use crate::ln::channelmanager::{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};
use crate::ln::features::InitFeatures;
use crate::ln::msgs;
use crate::ln::msgs::{ChannelMessageHandler,RoutingMessageHandler};
-use crate::util::events::ClosureReason;
use crate::util::enforcing_trait_impls::EnforcingSigner;
use crate::util::scid_utils;
use crate::util::test_utils;
use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
-use crate::util::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose};
use crate::util::errors::APIError;
use crate::util::config::UserConfig;
use crate::util::ser::{ReadableArgs, Writeable};
scid
}
/// Mine a single block containing the given transaction
-pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) {
+///
+/// Returns the SCID a channel confirmed in the given transaction will have, assuming the funding
+/// output is the 1st output in the transaction.
+pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction) -> u64 {
let height = node.best_block_info().1 + 1;
- confirm_transaction_at(node, tx, height);
+ confirm_transaction_at(node, tx, height)
}
/// Mine a single block containing the given transactions
pub fn mine_transactions<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, txn: &[&Transaction]) {
let mut per_peer_state_lock;
let mut peer_state_lock;
let chan = get_channel_ref!($node, $counterparty_node, per_peer_state_lock, peer_state_lock, $channel_id);
- chan.get_feerate()
+ chan.get_feerate_sat_per_1000_weight()
}
}
}
assert_eq!(added_monitors[0].0, funding_output);
added_monitors.clear();
}
+ expect_channel_pending_event(&node_b, &node_a.node.get_our_node_id());
node_a.node.handle_funding_signed(&node_b.node.get_our_node_id(), &get_event_msg!(node_b, MessageSendEvent::SendFundingSigned, node_a.node.get_our_node_id()));
{
assert_eq!(added_monitors[0].0, funding_output);
added_monitors.clear();
}
+ expect_channel_pending_event(&node_a, &node_b.node.get_our_node_id());
let events_4 = node_a.node.get_and_clear_pending_events();
assert_eq!(events_4.len(), 0);
MessageSendEvent::SendFundingSigned { node_id, msg } => {
assert_eq!(*node_id, initiator.node.get_our_node_id());
initiator.node.handle_funding_signed(&receiver.node.get_our_node_id(), &msg);
+ expect_channel_pending_event(&initiator, &receiver.node.get_our_node_id());
+ expect_channel_pending_event(&receiver, &initiator.node.get_our_node_id());
check_added_monitors!(initiator, 1);
assert_eq!(initiator.tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
MessageSendEvent::SendChannelReady { node_id, msg } => {
assert_eq!(*node_id, initiator.node.get_our_node_id());
initiator.node.handle_channel_ready(&receiver.node.get_our_node_id(), &msg);
+ expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id());
}
_ => panic!("Unexpected event"),
}
receiver.node.handle_channel_ready(&initiator.node.get_our_node_id(), &as_channel_ready);
+ expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id());
let as_channel_update = get_event_msg!(initiator, MessageSendEvent::SendChannelUpdate, receiver.node.get_our_node_id());
let bs_channel_update = get_event_msg!(receiver, MessageSendEvent::SendChannelUpdate, initiator.node.get_our_node_id());
assert_eq!(initiator.node.list_usable_channels().len(), initiator_channels + 1);
assert_eq!(receiver.node.list_usable_channels().len(), receiver_channels + 1);
- expect_channel_ready_event(&initiator, &receiver.node.get_our_node_id());
- expect_channel_ready_event(&receiver, &initiator.node.get_our_node_id());
-
(tx, as_channel_ready.channel_id)
}
check_added_monitors!(nodes[b], 1);
let cs_funding_signed = get_event_msg!(nodes[b], MessageSendEvent::SendFundingSigned, nodes[a].node.get_our_node_id());
+ expect_channel_pending_event(&nodes[b], &nodes[a].node.get_our_node_id());
+
nodes[a].node.handle_funding_signed(&nodes[b].node.get_our_node_id(), &cs_funding_signed);
+ expect_channel_pending_event(&nodes[a], &nodes[b].node.get_our_node_id());
check_added_monitors!(nodes[a], 1);
+ assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
+ assert_eq!(nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap()[0], tx);
+ nodes[a].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
+
let conf_height = core::cmp::max(nodes[a].best_block_info().1 + 1, nodes[b].best_block_info().1 + 1);
confirm_transaction_at(&nodes[a], &tx, conf_height);
connect_blocks(&nodes[a], CHAN_CONFIRM_DEPTH - 1);
/// Check that a channel's closing channel update has been broadcasted, and optionally
/// check whether an error message event has occurred.
-pub fn check_closed_broadcast(node: &Node, with_error_msg: bool) -> Option<msgs::ErrorMessage> {
+pub fn check_closed_broadcast(node: &Node, num_channels: usize, with_error_msg: bool) -> Vec<msgs::ErrorMessage> {
let msg_events = node.node.get_and_clear_pending_msg_events();
- assert_eq!(msg_events.len(), if with_error_msg { 2 } else { 1 });
- match msg_events[0] {
- MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
- assert_eq!(msg.contents.flags & 2, 2);
- },
- _ => panic!("Unexpected event"),
- }
- if with_error_msg {
- match msg_events[1] {
+ assert_eq!(msg_events.len(), if with_error_msg { num_channels * 2 } else { num_channels });
+ msg_events.into_iter().filter_map(|msg_event| {
+ match msg_event {
+ MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
+ assert_eq!(msg.contents.flags & 2, 2);
+ None
+ },
MessageSendEvent::HandleError { action: msgs::ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => {
+ assert!(with_error_msg);
// TODO: Check node_id
Some(msg.clone())
},
_ => panic!("Unexpected event"),
}
- } else { None }
+ }).collect()
}
/// Check that a channel's closing channel update has been broadcasted, and optionally
#[macro_export]
macro_rules! check_closed_broadcast {
($node: expr, $with_error_msg: expr) => {
- $crate::ln::functional_test_utils::check_closed_broadcast(&$node, $with_error_msg)
+ $crate::ln::functional_test_utils::check_closed_broadcast(&$node, 1, $with_error_msg).pop()
}
}
}
#[macro_export]
+/// Don't use this, use the identically-named function instead.
macro_rules! expect_pending_htlcs_forwardable_conditions {
- ($node: expr, $expected_failures: expr) => {{
- let expected_failures = $expected_failures;
- let events = $node.node.get_and_clear_pending_events();
- match events[0] {
- $crate::util::events::Event::PendingHTLCsForwardable { .. } => { },
- _ => panic!("Unexpected event {:?}", events),
- };
-
- let count = expected_failures.len() + 1;
- assert_eq!(events.len(), count);
-
- if expected_failures.len() > 0 {
- expect_htlc_handling_failed_destinations!(events, expected_failures)
- }
- }}
+ ($node: expr, $expected_failures: expr) => {
+ $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures);
+ }
}
#[macro_export]
($events: expr, $expected_failures: expr) => {{
for event in $events {
match event {
- $crate::util::events::Event::PendingHTLCsForwardable { .. } => { },
- $crate::util::events::Event::HTLCHandlingFailed { ref failed_next_destination, .. } => {
+ $crate::events::Event::PendingHTLCsForwardable { .. } => { },
+ $crate::events::Event::HTLCHandlingFailed { ref failed_next_destination, .. } => {
assert!($expected_failures.contains(&failed_next_destination))
},
_ => panic!("Unexpected destination"),
}}
}
+/// Checks that an [`Event::PendingHTLCsForwardable`] is available in the given events and, if
+/// there are any [`Event::HTLCHandlingFailed`] events their [`HTLCDestination`] is included in the
+/// `expected_failures` set.
+pub fn expect_pending_htlcs_forwardable_conditions(events: Vec<Event>, expected_failures: &[HTLCDestination]) {
+ match events[0] {
+ Event::PendingHTLCsForwardable { .. } => { },
+ _ => panic!("Unexpected event {:?}", events),
+ };
+
+ let count = expected_failures.len() + 1;
+ assert_eq!(events.len(), count);
+
+ if expected_failures.len() > 0 {
+ expect_htlc_handling_failed_destinations!(events, expected_failures)
+ }
+}
+
#[macro_export]
/// Clears (and ignores) a PendingHTLCsForwardable event
+///
+/// Don't use this, call [`expect_pending_htlcs_forwardable_conditions()`] with an empty failure
+/// set instead.
macro_rules! expect_pending_htlcs_forwardable_ignore {
- ($node: expr) => {{
- expect_pending_htlcs_forwardable_conditions!($node, vec![]);
- }};
+ ($node: expr) => {
+ $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &[]);
+ }
}
#[macro_export]
/// Clears (and ignores) PendingHTLCsForwardable and HTLCHandlingFailed events
+///
+/// Don't use this, call [`expect_pending_htlcs_forwardable_conditions()`] instead.
macro_rules! expect_pending_htlcs_forwardable_and_htlc_handling_failed_ignore {
- ($node: expr, $expected_failures: expr) => {{
- expect_pending_htlcs_forwardable_conditions!($node, $expected_failures);
- }};
+ ($node: expr, $expected_failures: expr) => {
+ $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures);
+ }
}
#[macro_export]
/// Handles a PendingHTLCsForwardable event
macro_rules! expect_pending_htlcs_forwardable {
($node: expr) => {{
- expect_pending_htlcs_forwardable_ignore!($node);
+ $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &[]);
$node.node.process_pending_htlc_forwards();
// Ensure process_pending_htlc_forwards is idempotent.
/// Handles a PendingHTLCsForwardable and HTLCHandlingFailed event
macro_rules! expect_pending_htlcs_forwardable_and_htlc_handling_failed {
($node: expr, $expected_failures: expr) => {{
- expect_pending_htlcs_forwardable_and_htlc_handling_failed_ignore!($node, $expected_failures);
+ $crate::ln::functional_test_utils::expect_pending_htlcs_forwardable_conditions($node.node.get_and_clear_pending_events(), &$expected_failures);
$node.node.process_pending_htlc_forwards();
// Ensure process_pending_htlc_forwards is idempotent.
if fail_backwards {
expect_pending_htlcs_forwardable_and_htlc_handling_failed!(node_a,
- vec![crate::util::events::HTLCDestination::NextHopChannel{ node_id: Some(node_b.node.get_our_node_id()), channel_id: commitment_signed.channel_id }]);
+ vec![crate::events::HTLCDestination::NextHopChannel{ node_id: Some(node_b.node.get_our_node_id()), channel_id: commitment_signed.channel_id }]);
check_added_monitors!(node_a, 1);
let node_a_per_peer_state = node_a.node.per_peer_state.read().unwrap();
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
- $crate::util::events::Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, via_channel_id: _, via_user_channel_id: _ } => {
+ $crate::events::Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, via_channel_id: _, via_user_channel_id: _ } => {
assert_eq!($expected_payment_hash, *payment_hash);
assert_eq!($expected_recv_value, amount_msat);
assert_eq!($expected_receiver_node_id, receiver_node_id.unwrap());
match purpose {
- $crate::util::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
+ $crate::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
assert_eq!(&$expected_payment_preimage, payment_preimage);
assert_eq!($expected_payment_secret, *payment_secret);
},
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
- $crate::util::events::Event::PaymentClaimed { ref payment_hash, amount_msat, .. } => {
+ $crate::events::Event::PaymentClaimed { ref payment_hash, amount_msat, .. } => {
assert_eq!($expected_payment_hash, *payment_hash);
assert_eq!($expected_recv_value, amount_msat);
},
assert_eq!(events.len(), 1);
}
let expected_payment_id = match events[0] {
- $crate::util::events::Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
+ $crate::events::Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
assert_eq!($expected_payment_preimage, *payment_preimage);
assert_eq!(expected_payment_hash, *payment_hash);
assert!(fee_paid_msat.is_some());
if $expect_paths {
for i in 1..events.len() {
match events[i] {
- $crate::util::events::Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => {
+ $crate::events::Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => {
assert_eq!(payment_id, expected_payment_id);
assert_eq!(payment_hash, Some(expected_payment_hash));
},
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
- $crate::util::events::Event::PaymentPathSuccessful { .. } => {},
+ $crate::events::Event::PaymentPathSuccessful { .. } => {},
_ => panic!("Unexpected event"),
}
}
let events = $node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
- Event::PaymentForwarded { fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id } => {
+ Event::PaymentForwarded {
+ fee_earned_msat, prev_channel_id, claim_from_onchain_tx, next_channel_id,
+ outbound_amount_forwarded_msat: _
+ } => {
assert_eq!(fee_earned_msat, $expected_fee);
if fee_earned_msat.is_some() {
// Is the event prev_channel_id in one of the channels between the two nodes?
}
#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
-pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
+pub fn expect_channel_pending_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
let events = node.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
match events[0] {
- crate::util::events::Event::ChannelReady{ ref counterparty_node_id, .. } => {
+ crate::events::Event::ChannelPending { ref counterparty_node_id, .. } => {
assert_eq!(*expected_counterparty_node_id, *counterparty_node_id);
},
_ => panic!("Unexpected event"),
}
}
+#[cfg(any(test, feature = "_bench_unstable", feature = "_test_utils"))]
+pub fn expect_channel_ready_event<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, expected_counterparty_node_id: &PublicKey) {
+ let events = node.node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ crate::events::Event::ChannelReady{ ref counterparty_node_id, .. } => {
+ assert_eq!(*expected_counterparty_node_id, *counterparty_node_id);
+ },
+ _ => panic!("Unexpected event"),
+ }
+}
pub struct PaymentFailedConditions<'a> {
pub(crate) expected_htlc_error_data: Option<(u16, &'a [u8])>,
) {
if conditions.expected_mpp_parts_remain { assert_eq!(payment_failed_events.len(), 1); } else { assert_eq!(payment_failed_events.len(), 2); }
let expected_payment_id = match &payment_failed_events[0] {
- Event::PaymentPathFailed { payment_hash, payment_failed_permanently, path, retry, payment_id, failure, short_channel_id,
+ Event::PaymentPathFailed { payment_hash, payment_failed_permanently, payment_id, failure,
#[cfg(test)]
error_code,
#[cfg(test)]
error_data, .. } => {
assert_eq!(*payment_hash, expected_payment_hash, "unexpected payment_hash");
assert_eq!(*payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value");
- assert!(retry.is_some(), "expected retry.is_some()");
- assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path");
- assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path");
- if let Some(scid) = short_channel_id {
- assert!(retry.as_ref().unwrap().payment_params.previously_failed_channels.contains(&scid));
- }
-
#[cfg(test)]
{
assert!(error_code.is_some(), "expected error_code.is_some() = true");
pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route, expected_paths: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) -> PaymentId {
let payment_id = PaymentId(origin_node.keys_manager.backing.get_secure_random_bytes());
- origin_node.node.send_payment(&route, our_payment_hash, &Some(our_payment_secret), payment_id).unwrap();
+ origin_node.node.send_payment_with_route(&route, our_payment_hash,
+ RecipientOnionFields::secret_only(our_payment_secret), payment_id).unwrap();
check_added_monitors!(origin_node, expected_paths.len());
pass_along_route(origin_node, expected_paths, recv_value, our_payment_hash, our_payment_secret);
payment_id
assert_eq!(hop.pubkey, node.node.get_our_node_id());
}
- let (_, our_payment_hash, our_payment_preimage) = get_payment_preimage_hash!(expected_route.last().unwrap());
- unwrap_send_err!(origin_node.node.send_payment(&route, our_payment_hash, &Some(our_payment_preimage), PaymentId(our_payment_hash.0)), true, APIError::ChannelUnavailable { ref err },
+ let (_, our_payment_hash, our_payment_secret) = get_payment_preimage_hash!(expected_route.last().unwrap());
+ unwrap_send_err!(origin_node.node.send_payment_with_route(&route, our_payment_hash,
+ RecipientOnionFields::secret_only(our_payment_secret), PaymentId(our_payment_hash.0)),
+ true, APIError::ChannelUnavailable { ref err },
assert!(err.contains("Cannot send value that would put us over the max HTLC value in flight our peer will accept")));
}