mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Merge pull request #1130 from TheBlueMatt/2021-10-mon-fail-after-conf
Always return failure in update_monitor after funding spend
This commit is contained in:
commit
d47aebca38
14 changed files with 395 additions and 82 deletions
|
@ -191,8 +191,7 @@ mod tests {
|
|||
use lightning::{check_closed_broadcast, check_closed_event, check_added_monitors};
|
||||
use lightning::ln::features::InitFeatures;
|
||||
use lightning::ln::functional_test_utils::*;
|
||||
use lightning::ln::msgs::ErrorAction;
|
||||
use lightning::util::events::{ClosureReason, Event, MessageSendEventsProvider, MessageSendEvent};
|
||||
use lightning::util::events::{ClosureReason, MessageSendEventsProvider};
|
||||
use lightning::util::test_utils;
|
||||
use std::fs;
|
||||
#[cfg(target_os = "windows")]
|
||||
|
|
|
@ -639,8 +639,8 @@ where C::Target: chain::Filter,
|
|||
let monitor = &monitor_state.monitor;
|
||||
log_trace!(self.logger, "Updating ChannelMonitor for channel {}", log_funding_info!(monitor));
|
||||
let update_res = monitor.update_monitor(&update, &self.broadcaster, &self.fee_estimator, &self.logger);
|
||||
if let Err(e) = &update_res {
|
||||
log_error!(self.logger, "Failed to update ChannelMonitor for channel {}: {:?}", log_funding_info!(monitor), e);
|
||||
if update_res.is_err() {
|
||||
log_error!(self.logger, "Failed to update ChannelMonitor for channel {}.", log_funding_info!(monitor));
|
||||
}
|
||||
// Even if updating the monitor returns an error, the monitor's state will
|
||||
// still be changed. So, persist the updated monitor despite the error.
|
||||
|
@ -727,10 +727,18 @@ impl<ChannelSigner: Sign, C: Deref, T: Deref, F: Deref, L: Deref, P: Deref> even
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ::{check_added_monitors, get_local_commitment_txn};
|
||||
use bitcoin::BlockHeader;
|
||||
use ::{check_added_monitors, check_closed_broadcast, check_closed_event};
|
||||
use ::{expect_payment_sent, expect_payment_sent_without_paths, expect_payment_path_successful, get_event_msg};
|
||||
use ::{get_htlc_update_msgs, get_local_commitment_txn, get_revoke_commit_msgs, get_route_and_payment_hash, unwrap_send_err};
|
||||
use chain::{ChannelMonitorUpdateErr, Confirm, Watch};
|
||||
use chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
|
||||
use ln::channelmanager::PaymentSendFailure;
|
||||
use ln::features::InitFeatures;
|
||||
use ln::functional_test_utils::*;
|
||||
use util::events::MessageSendEventsProvider;
|
||||
use ln::msgs::ChannelMessageHandler;
|
||||
use util::errors::APIError;
|
||||
use util::events::{ClosureReason, MessageSendEvent, MessageSendEventsProvider};
|
||||
use util::test_utils::{OnRegisterOutput, TxOutReference};
|
||||
|
||||
/// Tests that in-block dependent transactions are processed by `block_connected` when not
|
||||
|
@ -775,4 +783,179 @@ mod tests {
|
|||
nodes[1].node.get_and_clear_pending_msg_events();
|
||||
nodes[1].node.get_and_clear_pending_events();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_async_ooo_offchain_updates() {
|
||||
// Test that if we have multiple offchain updates being persisted and they complete
|
||||
// out-of-order, the ChainMonitor waits until all have completed before informing the
|
||||
// ChannelManager.
|
||||
let chanmon_cfgs = create_chanmon_cfgs(2);
|
||||
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
|
||||
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
|
||||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
|
||||
|
||||
// Route two payments to be claimed at the same time.
|
||||
let payment_preimage_1 = route_payment(&nodes[0], &[&nodes[1]], 1_000_000).0;
|
||||
let payment_preimage_2 = route_payment(&nodes[0], &[&nodes[1]], 1_000_000).0;
|
||||
|
||||
chanmon_cfgs[1].persister.offchain_monitor_updates.lock().unwrap().clear();
|
||||
chanmon_cfgs[1].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
|
||||
|
||||
nodes[1].node.claim_funds(payment_preimage_1);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
nodes[1].node.claim_funds(payment_preimage_2);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
|
||||
chanmon_cfgs[1].persister.set_update_ret(Ok(()));
|
||||
|
||||
let persistences = chanmon_cfgs[1].persister.offchain_monitor_updates.lock().unwrap().clone();
|
||||
assert_eq!(persistences.len(), 1);
|
||||
let (funding_txo, updates) = persistences.iter().next().unwrap();
|
||||
assert_eq!(updates.len(), 2);
|
||||
|
||||
// Note that updates is a HashMap so the ordering here is actually random. This shouldn't
|
||||
// fail either way but if it fails intermittently it's depending on the ordering of updates.
|
||||
let mut update_iter = updates.iter();
|
||||
nodes[1].chain_monitor.chain_monitor.channel_monitor_updated(*funding_txo, update_iter.next().unwrap().clone()).unwrap();
|
||||
assert!(nodes[1].chain_monitor.release_pending_monitor_events().is_empty());
|
||||
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
|
||||
nodes[1].chain_monitor.chain_monitor.channel_monitor_updated(*funding_txo, update_iter.next().unwrap().clone()).unwrap();
|
||||
|
||||
// Now manually walk the commitment signed dance - because we claimed two payments
|
||||
// back-to-back it doesn't fit into the neat walk commitment_signed_dance does.
|
||||
|
||||
let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
|
||||
nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]);
|
||||
expect_payment_sent_without_paths!(nodes[0], payment_preimage_1);
|
||||
nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &updates.commitment_signed);
|
||||
check_added_monitors!(nodes[0], 1);
|
||||
let (as_first_raa, as_first_update) = get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id());
|
||||
|
||||
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_first_raa);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
let bs_second_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
|
||||
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &as_first_update);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
let bs_first_raa = get_event_msg!(nodes[1], MessageSendEvent::SendRevokeAndACK, nodes[0].node.get_our_node_id());
|
||||
|
||||
nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &bs_second_updates.update_fulfill_htlcs[0]);
|
||||
expect_payment_sent_without_paths!(nodes[0], payment_preimage_2);
|
||||
nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_second_updates.commitment_signed);
|
||||
check_added_monitors!(nodes[0], 1);
|
||||
nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_first_raa);
|
||||
expect_payment_path_successful!(nodes[0]);
|
||||
check_added_monitors!(nodes[0], 1);
|
||||
let (as_second_raa, as_second_update) = get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id());
|
||||
|
||||
nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_second_raa);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &as_second_update);
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
let bs_second_raa = get_event_msg!(nodes[1], MessageSendEvent::SendRevokeAndACK, nodes[0].node.get_our_node_id());
|
||||
|
||||
nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_second_raa);
|
||||
expect_payment_path_successful!(nodes[0]);
|
||||
check_added_monitors!(nodes[0], 1);
|
||||
}
|
||||
|
||||
fn do_chainsync_pauses_events(block_timeout: bool) {
|
||||
// When a chainsync monitor update occurs, any MonitorUpdates should be held before being
|
||||
// passed upstream to a `ChannelManager` via `Watch::release_pending_monitor_events`. This
|
||||
// tests that behavior, as well as some ways it might go wrong.
|
||||
let chanmon_cfgs = create_chanmon_cfgs(2);
|
||||
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
|
||||
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
|
||||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
let channel = create_announced_chan_between_nodes(
|
||||
&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
|
||||
|
||||
// Get a route for later and rebalance the channel somewhat
|
||||
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
|
||||
let (route, second_payment_hash, _, second_payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[1], 100_000);
|
||||
|
||||
// First route a payment that we will claim on chain and give the recipient the preimage.
|
||||
let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 1_000_000).0;
|
||||
nodes[1].node.claim_funds(payment_preimage);
|
||||
nodes[1].node.get_and_clear_pending_msg_events();
|
||||
check_added_monitors!(nodes[1], 1);
|
||||
let remote_txn = get_local_commitment_txn!(nodes[1], channel.2);
|
||||
assert_eq!(remote_txn.len(), 2);
|
||||
|
||||
// Temp-fail the block connection which will hold the channel-closed event
|
||||
chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clear();
|
||||
chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::TemporaryFailure));
|
||||
|
||||
// Connect B's commitment transaction, but only to the ChainMonitor/ChannelMonitor. The
|
||||
// channel is now closed, but the ChannelManager doesn't know that yet.
|
||||
let new_header = BlockHeader {
|
||||
version: 2, time: 0, bits: 0, nonce: 0,
|
||||
prev_blockhash: nodes[0].best_block_info().0,
|
||||
merkle_root: Default::default() };
|
||||
nodes[0].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
|
||||
&[(0, &remote_txn[0]), (1, &remote_txn[1])], nodes[0].best_block_info().1 + 1);
|
||||
assert!(nodes[0].chain_monitor.release_pending_monitor_events().is_empty());
|
||||
nodes[0].chain_monitor.chain_monitor.best_block_updated(&new_header, nodes[0].best_block_info().1 + 1);
|
||||
assert!(nodes[0].chain_monitor.release_pending_monitor_events().is_empty());
|
||||
|
||||
// If the ChannelManager tries to update the channel, however, the ChainMonitor will pass
|
||||
// the update through to the ChannelMonitor which will refuse it (as the channel is closed).
|
||||
chanmon_cfgs[0].persister.set_update_ret(Ok(()));
|
||||
unwrap_send_err!(nodes[0].node.send_payment(&route, second_payment_hash, &Some(second_payment_secret)),
|
||||
true, APIError::ChannelUnavailable { ref err },
|
||||
assert!(err.contains("ChannelMonitor storage failure")));
|
||||
check_added_monitors!(nodes[0], 2); // After the failure we generate a close-channel monitor update
|
||||
check_closed_broadcast!(nodes[0], true);
|
||||
check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: "ChannelMonitor storage failure".to_string() });
|
||||
|
||||
// However, as the ChainMonitor is still waiting for the original persistence to complete,
|
||||
// it won't yet release the MonitorEvents.
|
||||
assert!(nodes[0].chain_monitor.release_pending_monitor_events().is_empty());
|
||||
|
||||
if block_timeout {
|
||||
// After three blocks, pending MontiorEvents should be released either way.
|
||||
let latest_header = BlockHeader {
|
||||
version: 2, time: 0, bits: 0, nonce: 0,
|
||||
prev_blockhash: nodes[0].best_block_info().0,
|
||||
merkle_root: Default::default() };
|
||||
nodes[0].chain_monitor.chain_monitor.best_block_updated(&latest_header, nodes[0].best_block_info().1 + LATENCY_GRACE_PERIOD_BLOCKS);
|
||||
} else {
|
||||
for (funding_outpoint, update_ids) in chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().iter() {
|
||||
for update_id in update_ids {
|
||||
nodes[0].chain_monitor.chain_monitor.channel_monitor_updated(*funding_outpoint, *update_id).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect_payment_sent!(nodes[0], payment_preimage);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chainsync_pauses_events() {
|
||||
do_chainsync_pauses_events(false);
|
||||
do_chainsync_pauses_events(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_during_chainsync_fails_channel() {
|
||||
let chanmon_cfgs = create_chanmon_cfgs(2);
|
||||
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
|
||||
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
|
||||
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
|
||||
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
|
||||
|
||||
chanmon_cfgs[0].persister.chain_sync_monitor_persistences.lock().unwrap().clear();
|
||||
chanmon_cfgs[0].persister.set_update_ret(Err(ChannelMonitorUpdateErr::PermanentFailure));
|
||||
|
||||
connect_blocks(&nodes[0], 1);
|
||||
// Before processing events, the ChannelManager will still think the Channel is open and
|
||||
// there won't be any ChannelMonitorUpdates
|
||||
assert_eq!(nodes[0].node.list_channels().len(), 1);
|
||||
check_added_monitors!(nodes[0], 0);
|
||||
// ... however once we get events once, the channel will close, creating a channel-closed
|
||||
// ChannelMonitorUpdate.
|
||||
check_closed_broadcast!(nodes[0], true);
|
||||
check_closed_event!(nodes[0], 1, ClosureReason::ProcessingError { err: "Failed to persist ChannelMonitor update during chain sync".to_string() });
|
||||
check_added_monitors!(nodes[0], 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,14 +115,6 @@ impl Readable for ChannelMonitorUpdate {
|
|||
}
|
||||
}
|
||||
|
||||
/// General Err type for ChannelMonitor actions. Generally, this implies that the data provided is
|
||||
/// inconsistent with the ChannelMonitor being called. eg for ChannelMonitor::update_monitor this
|
||||
/// means you tried to update a monitor for a different channel or the ChannelMonitorUpdate was
|
||||
/// corrupted.
|
||||
/// Contains a developer-readable error message.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MonitorUpdateError(pub &'static str);
|
||||
|
||||
/// An event to be processed by the ChannelManager.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum MonitorEvent {
|
||||
|
@ -695,6 +687,11 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
|
|||
// remote monitor out-of-order with regards to the block view.
|
||||
holder_tx_signed: bool,
|
||||
|
||||
// If a spend of the funding output is seen, we set this to true and reject any further
|
||||
// updates. This prevents any further changes in the offchain state no matter the order
|
||||
// of block connection between ChannelMonitors and the ChannelManager.
|
||||
funding_spend_seen: bool,
|
||||
|
||||
funding_spend_confirmed: Option<Txid>,
|
||||
/// The set of HTLCs which have been either claimed or failed on chain and have reached
|
||||
/// the requisite confirmations on the claim/fail transaction (either ANTI_REORG_DELAY or the
|
||||
|
@ -760,6 +757,7 @@ impl<Signer: Sign> PartialEq for ChannelMonitorImpl<Signer> {
|
|||
self.outputs_to_watch != other.outputs_to_watch ||
|
||||
self.lockdown_from_offchain != other.lockdown_from_offchain ||
|
||||
self.holder_tx_signed != other.holder_tx_signed ||
|
||||
self.funding_spend_seen != other.funding_spend_seen ||
|
||||
self.funding_spend_confirmed != other.funding_spend_confirmed ||
|
||||
self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain
|
||||
{
|
||||
|
@ -935,6 +933,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
|
|||
(1, self.funding_spend_confirmed, option),
|
||||
(3, self.htlcs_resolved_on_chain, vec_type),
|
||||
(5, self.pending_monitor_events, vec_type),
|
||||
(7, self.funding_spend_seen, required),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -1033,6 +1032,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
|
|||
|
||||
lockdown_from_offchain: false,
|
||||
holder_tx_signed: false,
|
||||
funding_spend_seen: false,
|
||||
funding_spend_confirmed: None,
|
||||
htlcs_resolved_on_chain: Vec::new(),
|
||||
|
||||
|
@ -1044,7 +1044,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn provide_secret(&self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> {
|
||||
fn provide_secret(&self, idx: u64, secret: [u8; 32]) -> Result<(), &'static str> {
|
||||
self.inner.lock().unwrap().provide_secret(idx, secret)
|
||||
}
|
||||
|
||||
|
@ -1066,12 +1066,10 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
|
|||
|
||||
#[cfg(test)]
|
||||
fn provide_latest_holder_commitment_tx(
|
||||
&self,
|
||||
holder_commitment_tx: HolderCommitmentTransaction,
|
||||
&self, holder_commitment_tx: HolderCommitmentTransaction,
|
||||
htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
|
||||
) -> Result<(), MonitorUpdateError> {
|
||||
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(
|
||||
holder_commitment_tx, htlc_outputs)
|
||||
) -> Result<(), ()> {
|
||||
self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs).map_err(|_| ())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1112,7 +1110,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
|
|||
broadcaster: &B,
|
||||
fee_estimator: &F,
|
||||
logger: &L,
|
||||
) -> Result<(), MonitorUpdateError>
|
||||
) -> Result<(), ()>
|
||||
where
|
||||
B::Target: BroadcasterInterface,
|
||||
F::Target: FeeEstimator,
|
||||
|
@ -1687,9 +1685,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
/// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither
|
||||
/// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen
|
||||
/// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key).
|
||||
fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> {
|
||||
fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), &'static str> {
|
||||
if let Err(()) = self.commitment_secrets.provide_secret(idx, secret) {
|
||||
return Err(MonitorUpdateError("Previous secret did not match new one"));
|
||||
return Err("Previous secret did not match new one");
|
||||
}
|
||||
|
||||
// Prune HTLCs from the previous counterparty commitment tx so we don't generate failure/fulfill
|
||||
|
@ -1781,7 +1779,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
/// is important that any clones of this channel monitor (including remote clones) by kept
|
||||
/// up-to-date as our holder commitment transaction is updated.
|
||||
/// Panics if set_on_holder_tx_csv has never been called.
|
||||
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) -> Result<(), MonitorUpdateError> {
|
||||
fn provide_latest_holder_commitment_tx(&mut self, holder_commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) -> Result<(), &'static str> {
|
||||
// block for Rust 1.34 compat
|
||||
let mut new_holder_commitment_tx = {
|
||||
let trusted_tx = holder_commitment_tx.trust();
|
||||
|
@ -1804,7 +1802,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
mem::swap(&mut new_holder_commitment_tx, &mut self.current_holder_commitment_tx);
|
||||
self.prev_holder_signed_commitment_tx = Some(new_holder_commitment_tx);
|
||||
if self.holder_tx_signed {
|
||||
return Err(MonitorUpdateError("Latest holder commitment signed has already been signed, update is rejected"));
|
||||
return Err("Latest holder commitment signed has already been signed, update is rejected");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1868,7 +1866,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
self.pending_monitor_events.push(MonitorEvent::CommitmentTxConfirmed(self.funding_info.0));
|
||||
}
|
||||
|
||||
pub fn update_monitor<B: Deref, F: Deref, L: Deref>(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), MonitorUpdateError>
|
||||
pub fn update_monitor<B: Deref, F: Deref, L: Deref>(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), ()>
|
||||
where B::Target: BroadcasterInterface,
|
||||
F::Target: FeeEstimator,
|
||||
L::Target: Logger,
|
||||
|
@ -1886,12 +1884,17 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
} else if self.latest_update_id + 1 != updates.update_id {
|
||||
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
|
||||
}
|
||||
let mut ret = Ok(());
|
||||
for update in updates.updates.iter() {
|
||||
match update {
|
||||
ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => {
|
||||
log_trace!(logger, "Updating ChannelMonitor with latest holder commitment transaction info");
|
||||
if self.lockdown_from_offchain { panic!(); }
|
||||
self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone())?
|
||||
if let Err(e) = self.provide_latest_holder_commitment_tx(commitment_tx.clone(), htlc_outputs.clone()) {
|
||||
log_error!(logger, "Providing latest holder commitment transaction failed/was refused:");
|
||||
log_error!(logger, " {}", e);
|
||||
ret = Err(());
|
||||
}
|
||||
}
|
||||
ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_revocation_point } => {
|
||||
log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info");
|
||||
|
@ -1903,7 +1906,11 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
},
|
||||
ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => {
|
||||
log_trace!(logger, "Updating ChannelMonitor with commitment secret");
|
||||
self.provide_secret(*idx, *secret)?
|
||||
if let Err(e) = self.provide_secret(*idx, *secret) {
|
||||
log_error!(logger, "Providing latest counterparty commitment secret failed/was refused:");
|
||||
log_error!(logger, " {}", e);
|
||||
ret = Err(());
|
||||
}
|
||||
},
|
||||
ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => {
|
||||
log_trace!(logger, "Updating ChannelMonitor: channel force closed, should broadcast: {}", should_broadcast);
|
||||
|
@ -1928,7 +1935,11 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
}
|
||||
}
|
||||
self.latest_update_id = updates.update_id;
|
||||
Ok(())
|
||||
|
||||
if ret.is_ok() && self.funding_spend_seen {
|
||||
log_error!(logger, "Refusing Channel Monitor Update as counterparty attempted to update commitment after funding was spent");
|
||||
Err(())
|
||||
} else { ret }
|
||||
}
|
||||
|
||||
pub fn get_latest_update_id(&self) -> u64 {
|
||||
|
@ -2357,6 +2368,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
|
|||
let mut balance_spendable_csv = None;
|
||||
log_info!(logger, "Channel {} closed by funding output spend in txid {}.",
|
||||
log_bytes!(self.funding_info.0.to_channel_id()), tx.txid());
|
||||
self.funding_spend_seen = true;
|
||||
if (tx.input[0].sequence >> 8*3) as u8 == 0x80 && (tx.lock_time >> 8*3) as u8 == 0x20 {
|
||||
let (mut new_outpoints, new_outputs) = self.check_spend_counterparty_transaction(&tx, height, &logger);
|
||||
if !new_outputs.1.is_empty() {
|
||||
|
@ -3206,10 +3218,12 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
|
|||
|
||||
let mut funding_spend_confirmed = None;
|
||||
let mut htlcs_resolved_on_chain = Some(Vec::new());
|
||||
let mut funding_spend_seen = Some(false);
|
||||
read_tlv_fields!(reader, {
|
||||
(1, funding_spend_confirmed, option),
|
||||
(3, htlcs_resolved_on_chain, vec_type),
|
||||
(5, pending_monitor_events, vec_type),
|
||||
(7, funding_spend_seen, option),
|
||||
});
|
||||
|
||||
let mut secp_ctx = Secp256k1::new();
|
||||
|
@ -3259,6 +3273,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
|
|||
|
||||
lockdown_from_offchain,
|
||||
holder_tx_signed,
|
||||
funding_spend_seen: funding_spend_seen.unwrap(),
|
||||
funding_spend_confirmed,
|
||||
htlcs_resolved_on_chain: htlcs_resolved_on_chain.unwrap(),
|
||||
|
||||
|
@ -3272,6 +3287,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bitcoin::blockdata::block::BlockHeader;
|
||||
use bitcoin::blockdata::script::{Script, Builder};
|
||||
use bitcoin::blockdata::opcodes;
|
||||
use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType};
|
||||
|
@ -3280,24 +3296,128 @@ mod tests {
|
|||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::hex::FromHex;
|
||||
use bitcoin::hash_types::Txid;
|
||||
use bitcoin::hash_types::{BlockHash, Txid};
|
||||
use bitcoin::network::constants::Network;
|
||||
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
|
||||
use hex;
|
||||
use chain::BestBlock;
|
||||
|
||||
use super::ChannelMonitorUpdateStep;
|
||||
use ::{check_added_monitors, check_closed_broadcast, check_closed_event, check_spends, get_local_commitment_txn, get_monitor, get_route_and_payment_hash, unwrap_send_err};
|
||||
use chain::{BestBlock, Confirm};
|
||||
use chain::channelmonitor::ChannelMonitor;
|
||||
use chain::package::{WEIGHT_OFFERED_HTLC, WEIGHT_RECEIVED_HTLC, WEIGHT_REVOKED_OFFERED_HTLC, WEIGHT_REVOKED_RECEIVED_HTLC, WEIGHT_REVOKED_OUTPUT};
|
||||
use chain::transaction::OutPoint;
|
||||
use chain::keysinterface::InMemorySigner;
|
||||
use ln::{PaymentPreimage, PaymentHash};
|
||||
use ln::chan_utils;
|
||||
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
|
||||
use ln::channelmanager::PaymentSendFailure;
|
||||
use ln::features::InitFeatures;
|
||||
use ln::functional_test_utils::*;
|
||||
use ln::script::ShutdownScript;
|
||||
use util::errors::APIError;
|
||||
use util::events::{ClosureReason, MessageSendEventsProvider};
|
||||
use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator};
|
||||
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use util::ser::{ReadableArgs, Writeable};
|
||||
use sync::{Arc, Mutex};
|
||||
use chain::keysinterface::InMemorySigner;
|
||||
use io;
|
||||
use prelude::*;
|
||||
|
||||
fn do_test_funding_spend_refuses_updates(use_local_txn: bool) {
|
||||
// Previously, monitor updates were allowed freely even after a funding-spend transaction
|
||||
// confirmed. This would allow a race condition where we could receive a payment (including
|
||||
// the counterparty revoking their broadcasted state!) and accept it without recourse as
|
||||
// long as the ChannelMonitor receives the block first, the full commitment update dance
|
||||
// occurs after the block is connected, and before the ChannelManager receives the block.
|
||||
// Obviously this is an incredibly contrived race given the counterparty would be risking
|
||||
// their full channel balance for it, but its worth fixing nonetheless as it makes the
|
||||
// potential ChannelMonitor states simpler to reason about.
|
||||
//
|
||||
// This test checks said behavior, as well as ensuring a ChannelMonitorUpdate with multiple
|
||||
// updates is handled correctly in such conditions.
|
||||
let chanmon_cfgs = create_chanmon_cfgs(3);
|
||||
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
|
||||
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
|
||||
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
|
||||
let channel = create_announced_chan_between_nodes(
|
||||
&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
|
||||
create_announced_chan_between_nodes(
|
||||
&nodes, 1, 2, InitFeatures::known(), InitFeatures::known());
|
||||
|
||||
// Rebalance somewhat
|
||||
send_payment(&nodes[0], &[&nodes[1]], 10_000_000);
|
||||
|
||||
// First route two payments for testing at the end
|
||||
let payment_preimage_1 = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000).0;
|
||||
let payment_preimage_2 = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 1_000_000).0;
|
||||
|
||||
let local_txn = get_local_commitment_txn!(nodes[1], channel.2);
|
||||
assert_eq!(local_txn.len(), 1);
|
||||
let remote_txn = get_local_commitment_txn!(nodes[0], channel.2);
|
||||
assert_eq!(remote_txn.len(), 3); // Commitment and two HTLC-Timeouts
|
||||
check_spends!(remote_txn[1], remote_txn[0]);
|
||||
check_spends!(remote_txn[2], remote_txn[0]);
|
||||
let broadcast_tx = if use_local_txn { &local_txn[0] } else { &remote_txn[0] };
|
||||
|
||||
// Connect a commitment transaction, but only to the ChainMonitor/ChannelMonitor. The
|
||||
// channel is now closed, but the ChannelManager doesn't know that yet.
|
||||
let new_header = BlockHeader {
|
||||
version: 2, time: 0, bits: 0, nonce: 0,
|
||||
prev_blockhash: nodes[0].best_block_info().0,
|
||||
merkle_root: Default::default() };
|
||||
let conf_height = nodes[0].best_block_info().1 + 1;
|
||||
nodes[1].chain_monitor.chain_monitor.transactions_confirmed(&new_header,
|
||||
&[(0, broadcast_tx)], conf_height);
|
||||
|
||||
let (_, pre_update_monitor) = <(BlockHash, ChannelMonitor<InMemorySigner>)>::read(
|
||||
&mut io::Cursor::new(&get_monitor!(nodes[1], channel.2).encode()),
|
||||
&nodes[1].keys_manager.backing).unwrap();
|
||||
|
||||
// If the ChannelManager tries to update the channel, however, the ChainMonitor will pass
|
||||
// the update through to the ChannelMonitor which will refuse it (as the channel is closed).
|
||||
let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[1], nodes[0], 100_000);
|
||||
unwrap_send_err!(nodes[1].node.send_payment(&route, payment_hash, &Some(payment_secret)),
|
||||
true, APIError::ChannelUnavailable { ref err },
|
||||
assert!(err.contains("ChannelMonitor storage failure")));
|
||||
check_added_monitors!(nodes[1], 2); // After the failure we generate a close-channel monitor update
|
||||
check_closed_broadcast!(nodes[1], true);
|
||||
check_closed_event!(nodes[1], 1, ClosureReason::ProcessingError { err: "ChannelMonitor storage failure".to_string() });
|
||||
|
||||
// Build a new ChannelMonitorUpdate which contains both the failing commitment tx update
|
||||
// and provides the claim preimages for the two pending HTLCs. The first update generates
|
||||
// an error, but the point of this test is to ensure the later updates are still applied.
|
||||
let monitor_updates = nodes[1].chain_monitor.monitor_updates.lock().unwrap();
|
||||
let mut replay_update = monitor_updates.get(&channel.2).unwrap().iter().rev().skip(1).next().unwrap().clone();
|
||||
assert_eq!(replay_update.updates.len(), 1);
|
||||
if let ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } = replay_update.updates[0] {
|
||||
} else { panic!(); }
|
||||
replay_update.updates.push(ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage: payment_preimage_1 });
|
||||
replay_update.updates.push(ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage: payment_preimage_2 });
|
||||
|
||||
let broadcaster = TestBroadcaster::new(Arc::clone(&nodes[1].blocks));
|
||||
assert!(
|
||||
pre_update_monitor.update_monitor(&replay_update, &&broadcaster, &&chanmon_cfgs[1].fee_estimator, &nodes[1].logger)
|
||||
.is_err());
|
||||
// Even though we error'd on the first update, we should still have generated an HTLC claim
|
||||
// transaction
|
||||
let txn_broadcasted = broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
|
||||
assert!(txn_broadcasted.len() >= 2);
|
||||
let htlc_txn = txn_broadcasted.iter().filter(|tx| {
|
||||
assert_eq!(tx.input.len(), 1);
|
||||
tx.input[0].previous_output.txid == broadcast_tx.txid()
|
||||
}).collect::<Vec<_>>();
|
||||
assert_eq!(htlc_txn.len(), 2);
|
||||
check_spends!(htlc_txn[0], broadcast_tx);
|
||||
check_spends!(htlc_txn[1], broadcast_tx);
|
||||
}
|
||||
#[test]
|
||||
fn test_funding_spend_refuses_updates() {
|
||||
do_test_funding_spend_refuses_updates(true);
|
||||
do_test_funding_spend_refuses_updates(false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prune_preimages() {
|
||||
let secp_ctx = Secp256k1::new();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
//! generated/etc. This makes it a good candidate for tight integration into an existing wallet
|
||||
//! instead of having a rather-separate lightning appendage to a wallet.
|
||||
|
||||
#![cfg_attr(not(any(feature = "fuzztarget", feature = "_test_utils")), deny(missing_docs))]
|
||||
#![cfg_attr(not(any(test, feature = "fuzztarget", feature = "_test_utils")), deny(missing_docs))]
|
||||
#![cfg_attr(not(any(test, feature = "fuzztarget", feature = "_test_utils")), forbid(unsafe_code))]
|
||||
#![deny(broken_intra_doc_links)]
|
||||
|
||||
|
|
|
@ -19,11 +19,10 @@ use bitcoin::network::constants::Network;
|
|||
use chain::channelmonitor::ChannelMonitor;
|
||||
use chain::transaction::OutPoint;
|
||||
use chain::{ChannelMonitorUpdateErr, Listen, Watch};
|
||||
use ln::{PaymentPreimage, PaymentHash};
|
||||
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure};
|
||||
use ln::features::InitFeatures;
|
||||
use ln::msgs;
|
||||
use ln::msgs::{ChannelMessageHandler, ErrorAction, RoutingMessageHandler};
|
||||
use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler};
|
||||
use util::config::UserConfig;
|
||||
use util::enforcing_trait_impls::EnforcingSigner;
|
||||
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose, ClosureReason};
|
||||
|
@ -31,9 +30,6 @@ use util::errors::APIError;
|
|||
use util::ser::{ReadableArgs, Writeable};
|
||||
use util::test_utils::TestBroadcaster;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
|
||||
use ln::functional_test_utils::*;
|
||||
|
||||
use util::test_utils;
|
||||
|
|
|
@ -33,8 +33,6 @@ use bitcoin::blockdata::constants::genesis_block;
|
|||
use bitcoin::blockdata::transaction::{Transaction, TxOut};
|
||||
use bitcoin::network::constants::Network;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::hash_types::BlockHash;
|
||||
|
||||
use bitcoin::secp256k1::key::PublicKey;
|
||||
|
@ -337,9 +335,11 @@ pub fn create_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(node_a: &'a Node<'b,
|
|||
(announcement, as_update, bs_update, channel_id, tx)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_revoke_commit_msgs {
|
||||
($node: expr, $node_id: expr) => {
|
||||
{
|
||||
use util::events::MessageSendEvent;
|
||||
let events = $node.node.get_and_clear_pending_msg_events();
|
||||
assert_eq!(events.len(), 2);
|
||||
(match events[0] {
|
||||
|
@ -401,13 +401,14 @@ macro_rules! get_event {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! get_htlc_update_msgs {
|
||||
($node: expr, $node_id: expr) => {
|
||||
{
|
||||
let events = $node.node.get_and_clear_pending_msg_events();
|
||||
assert_eq!(events.len(), 1);
|
||||
match events[0] {
|
||||
MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => {
|
||||
$crate::util::events::MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => {
|
||||
assert_eq!(*node_id, $node_id);
|
||||
(*updates).clone()
|
||||
},
|
||||
|
@ -713,6 +714,7 @@ pub fn update_nodes_with_chan_announce<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, '
|
|||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! check_spends {
|
||||
($tx: expr, $($spends_txn: expr),*) => {
|
||||
{
|
||||
|
@ -777,6 +779,9 @@ macro_rules! get_closing_signed_broadcast {
|
|||
#[macro_export]
|
||||
macro_rules! check_closed_broadcast {
|
||||
($node: expr, $with_error_msg: expr) => {{
|
||||
use $crate::util::events::MessageSendEvent;
|
||||
use $crate::ln::msgs::ErrorAction;
|
||||
|
||||
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] {
|
||||
|
@ -804,6 +809,8 @@ macro_rules! check_closed_event {
|
|||
check_closed_event!($node, $events, $reason, false);
|
||||
};
|
||||
($node: expr, $events: expr, $reason: expr, $is_check_discard_funding: expr) => {{
|
||||
use $crate::util::events::Event;
|
||||
|
||||
let events = $node.node.get_and_clear_pending_events();
|
||||
assert_eq!(events.len(), $events);
|
||||
let expected_reason = $reason;
|
||||
|
@ -1012,10 +1019,12 @@ macro_rules! get_payment_preimage_hash {
|
|||
};
|
||||
($dest_node: expr, $min_value_msat: expr) => {
|
||||
{
|
||||
use bitcoin::hashes::Hash as _;
|
||||
let mut payment_count = $dest_node.network_payment_count.borrow_mut();
|
||||
let payment_preimage = PaymentPreimage([*payment_count; 32]);
|
||||
let payment_preimage = $crate::ln::PaymentPreimage([*payment_count; 32]);
|
||||
*payment_count += 1;
|
||||
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
|
||||
let payment_hash = $crate::ln::PaymentHash(
|
||||
bitcoin::hashes::sha256::Hash::hash(&payment_preimage.0[..]).into_inner());
|
||||
let payment_secret = $dest_node.node.create_inbound_payment_for_hash(payment_hash, $min_value_msat, 7200).unwrap();
|
||||
(payment_preimage, payment_hash, payment_secret)
|
||||
}
|
||||
|
@ -1023,17 +1032,18 @@ macro_rules! get_payment_preimage_hash {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! get_route_and_payment_hash {
|
||||
($send_node: expr, $recv_node: expr, $recv_value: expr) => {{
|
||||
get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV)
|
||||
$crate::get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV)
|
||||
}};
|
||||
($send_node: expr, $recv_node: expr, $last_hops: expr, $recv_value: expr, $cltv: expr) => {{
|
||||
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash!($recv_node, Some($recv_value));
|
||||
let (payment_preimage, payment_hash, payment_secret) = $crate::get_payment_preimage_hash!($recv_node, Some($recv_value));
|
||||
let payee = $crate::routing::router::Payee::from_node_id($recv_node.node.get_our_node_id())
|
||||
.with_features($crate::ln::features::InvoiceFeatures::known())
|
||||
.with_route_hints($last_hops);
|
||||
let scorer = ::util::test_utils::TestScorer::with_fixed_penalty(0);
|
||||
let route = ::routing::router::get_route(
|
||||
let scorer = $crate::util::test_utils::TestScorer::with_fixed_penalty(0);
|
||||
let route = $crate::routing::router::get_route(
|
||||
&$send_node.node.get_our_node_id(), &payee, $send_node.network_graph,
|
||||
Some(&$send_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
|
||||
$recv_value, $cltv, $send_node.logger, &scorer
|
||||
|
@ -1097,6 +1107,7 @@ macro_rules! expect_payment_received {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! expect_payment_sent_without_paths {
|
||||
($node: expr, $expected_payment_preimage: expr) => {
|
||||
expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, false);
|
||||
|
@ -1106,23 +1117,26 @@ macro_rules! expect_payment_sent_without_paths {
|
|||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! expect_payment_sent {
|
||||
($node: expr, $expected_payment_preimage: expr) => {
|
||||
expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, true);
|
||||
$crate::expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, true);
|
||||
};
|
||||
($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr) => {
|
||||
expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, true);
|
||||
$crate::expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, true);
|
||||
};
|
||||
($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => {
|
||||
($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => { {
|
||||
use bitcoin::hashes::Hash as _;
|
||||
let events = $node.node.get_and_clear_pending_events();
|
||||
let expected_payment_hash = PaymentHash(Sha256::hash(&$expected_payment_preimage.0).into_inner());
|
||||
let expected_payment_hash = $crate::ln::PaymentHash(
|
||||
bitcoin::hashes::sha256::Hash::hash(&$expected_payment_preimage.0).into_inner());
|
||||
if $expect_paths {
|
||||
assert!(events.len() > 1);
|
||||
} else {
|
||||
assert_eq!(events.len(), 1);
|
||||
}
|
||||
let expected_payment_id = match events[0] {
|
||||
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
|
||||
$crate::util::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());
|
||||
|
@ -1136,7 +1150,7 @@ macro_rules! expect_payment_sent {
|
|||
if $expect_paths {
|
||||
for i in 1..events.len() {
|
||||
match events[i] {
|
||||
Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => {
|
||||
$crate::util::events::Event::PaymentPathSuccessful { payment_id, payment_hash, .. } => {
|
||||
assert_eq!(payment_id, expected_payment_id);
|
||||
assert_eq!(payment_hash, Some(expected_payment_hash));
|
||||
},
|
||||
|
@ -1144,16 +1158,17 @@ macro_rules! expect_payment_sent {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_export]
|
||||
macro_rules! expect_payment_path_successful {
|
||||
($node: expr) => {
|
||||
let events = $node.node.get_and_clear_pending_events();
|
||||
assert_eq!(events.len(), 1);
|
||||
match events[0] {
|
||||
Event::PaymentPathSuccessful { .. } => {},
|
||||
$crate::util::events::Event::PaymentPathSuccessful { .. } => {},
|
||||
_ => panic!("Unexpected event"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,6 @@ use bitcoin::blockdata::opcodes;
|
|||
use bitcoin::blockdata::constants::genesis_block;
|
||||
use bitcoin::network::constants::Network;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::secp256k1::key::{PublicKey,SecretKey};
|
||||
|
||||
|
|
|
@ -11,16 +11,13 @@
|
|||
|
||||
use chain::channelmonitor::{ANTI_REORG_DELAY, Balance};
|
||||
use chain::transaction::OutPoint;
|
||||
use ln::{channel, PaymentPreimage, PaymentHash};
|
||||
use ln::channel;
|
||||
use ln::channelmanager::BREAKDOWN_TIMEOUT;
|
||||
use ln::features::InitFeatures;
|
||||
use ln::msgs::{ChannelMessageHandler, ErrorAction};
|
||||
use ln::msgs::ChannelMessageHandler;
|
||||
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
|
||||
use routing::network_graph::NetworkUpdate;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
|
||||
use bitcoin::blockdata::script::Builder;
|
||||
use bitcoin::blockdata::opcodes;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
//! returned errors decode to the correct thing.
|
||||
|
||||
use chain::channelmonitor::{CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
|
||||
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
|
||||
use ln::{PaymentHash, PaymentSecret};
|
||||
use ln::channelmanager::{HTLCForwardInfo, CLTV_FAR_FAR_AWAY};
|
||||
use ln::onion_utils;
|
||||
use routing::network_graph::NetworkUpdate;
|
||||
|
@ -26,7 +26,6 @@ use util::config::UserConfig;
|
|||
|
||||
use bitcoin::hash_types::BlockHash;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
|
||||
use bitcoin::secp256k1;
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
use chain::{ChannelMonitorUpdateErr, Confirm, Listen, Watch};
|
||||
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor, LATENCY_GRACE_PERIOD_BLOCKS};
|
||||
use chain::transaction::OutPoint;
|
||||
use ln::{PaymentPreimage, PaymentHash};
|
||||
use ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, ChannelManagerReadArgs, PaymentId, PaymentSendFailure};
|
||||
use ln::features::InitFeatures;
|
||||
use ln::msgs;
|
||||
use ln::msgs::{ChannelMessageHandler, ErrorAction};
|
||||
use ln::msgs::ChannelMessageHandler;
|
||||
use util::events::{ClosureReason, Event, MessageSendEvent, MessageSendEventsProvider};
|
||||
use util::test_utils;
|
||||
use util::errors::APIError;
|
||||
|
@ -26,8 +25,6 @@ use util::enforcing_trait_impls::EnforcingSigner;
|
|||
use util::ser::{ReadableArgs, Writeable};
|
||||
use io;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::{Block, BlockHeader, BlockHash};
|
||||
|
||||
use prelude::*;
|
||||
|
|
|
@ -12,10 +12,9 @@
|
|||
use chain::channelmonitor::{ANTI_REORG_DELAY, ChannelMonitor};
|
||||
use chain::transaction::OutPoint;
|
||||
use chain::{Confirm, Watch};
|
||||
use ln::PaymentHash;
|
||||
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs};
|
||||
use ln::features::InitFeatures;
|
||||
use ln::msgs::{ChannelMessageHandler, ErrorAction};
|
||||
use ln::msgs::ChannelMessageHandler;
|
||||
use routing::network_graph::NetworkUpdate;
|
||||
use util::enforcing_trait_impls::EnforcingSigner;
|
||||
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
|
||||
|
@ -25,8 +24,6 @@ use util::ser::{ReadableArgs, Writeable};
|
|||
use bitcoin::blockdata::block::{Block, BlockHeader};
|
||||
use bitcoin::blockdata::script::Builder;
|
||||
use bitcoin::blockdata::opcodes;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::hash_types::BlockHash;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
use chain::keysinterface::KeysInterface;
|
||||
use chain::transaction::OutPoint;
|
||||
use ln::{PaymentPreimage, PaymentHash};
|
||||
use ln::channelmanager::PaymentSendFailure;
|
||||
use routing::router::{Payee, get_route};
|
||||
use routing::network_graph::NetworkUpdate;
|
||||
|
@ -28,9 +27,6 @@ use util::config::UserConfig;
|
|||
use bitcoin::blockdata::script::Builder;
|
||||
use bitcoin::blockdata::opcodes;
|
||||
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
use bitcoin::hashes::Hash;
|
||||
|
||||
use regex;
|
||||
|
||||
use core::default::Default;
|
||||
|
|
|
@ -66,10 +66,10 @@ pub enum APIError {
|
|||
impl fmt::Debug for APIError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
APIError::APIMisuseError {ref err} => f.write_str(err),
|
||||
APIError::APIMisuseError {ref err} => write!(f, "Misuse error: {}", err),
|
||||
APIError::FeeRateTooHigh {ref err, ref feerate} => write!(f, "{} feerate: {}", err, feerate),
|
||||
APIError::RouteError {ref err} => f.write_str(err),
|
||||
APIError::ChannelUnavailable {ref err} => f.write_str(err),
|
||||
APIError::RouteError {ref err} => write!(f, "Route error: {}", err),
|
||||
APIError::ChannelUnavailable {ref err} => write!(f, "Channel unavailable: {}", err),
|
||||
APIError::MonitorUpdateFailed => f.write_str("Client indicated a channel monitor update failed"),
|
||||
APIError::IncompatibleShutdownScript { ref script } => {
|
||||
write!(f, "Provided a scriptpubkey format not accepted by peer: {}", script)
|
||||
|
|
|
@ -91,6 +91,7 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface {
|
|||
|
||||
pub struct TestChainMonitor<'a> {
|
||||
pub added_monitors: Mutex<Vec<(OutPoint, channelmonitor::ChannelMonitor<EnforcingSigner>)>>,
|
||||
pub monitor_updates: Mutex<HashMap<[u8; 32], Vec<channelmonitor::ChannelMonitorUpdate>>>,
|
||||
pub latest_monitor_update_id: Mutex<HashMap<[u8; 32], (OutPoint, u64, MonitorUpdateId)>>,
|
||||
pub chain_monitor: chainmonitor::ChainMonitor<EnforcingSigner, &'a TestChainSource, &'a chaininterface::BroadcasterInterface, &'a TestFeeEstimator, &'a TestLogger, &'a chainmonitor::Persist<EnforcingSigner>>,
|
||||
pub keys_manager: &'a TestKeysInterface,
|
||||
|
@ -103,6 +104,7 @@ impl<'a> TestChainMonitor<'a> {
|
|||
pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a chainmonitor::Persist<EnforcingSigner>, keys_manager: &'a TestKeysInterface) -> Self {
|
||||
Self {
|
||||
added_monitors: Mutex::new(Vec::new()),
|
||||
monitor_updates: Mutex::new(HashMap::new()),
|
||||
latest_monitor_update_id: Mutex::new(HashMap::new()),
|
||||
chain_monitor: chainmonitor::ChainMonitor::new(chain_source, broadcaster, logger, fee_estimator, persister),
|
||||
keys_manager,
|
||||
|
@ -132,6 +134,8 @@ impl<'a> chain::Watch<EnforcingSigner> for TestChainMonitor<'a> {
|
|||
assert!(channelmonitor::ChannelMonitorUpdate::read(
|
||||
&mut io::Cursor::new(&w.0)).unwrap() == update);
|
||||
|
||||
self.monitor_updates.lock().unwrap().entry(funding_txo.to_channel_id()).or_insert(Vec::new()).push(update.clone());
|
||||
|
||||
if let Some(exp) = self.expect_channel_force_closed.lock().unwrap().take() {
|
||||
assert_eq!(funding_txo.to_channel_id(), exp.0);
|
||||
assert_eq!(update.updates.len(), 1);
|
||||
|
@ -168,6 +172,9 @@ pub struct TestPersister {
|
|||
/// When we get an update_persisted_channel call with no ChannelMonitorUpdate, we insert the
|
||||
/// MonitorUpdateId here.
|
||||
pub chain_sync_monitor_persistences: Mutex<HashMap<OutPoint, HashSet<MonitorUpdateId>>>,
|
||||
/// When we get an update_persisted_channel call *with* a ChannelMonitorUpdate, we insert the
|
||||
/// MonitorUpdateId here.
|
||||
pub offchain_monitor_updates: Mutex<HashMap<OutPoint, HashSet<MonitorUpdateId>>>,
|
||||
}
|
||||
impl TestPersister {
|
||||
pub fn new() -> Self {
|
||||
|
@ -175,6 +182,7 @@ impl TestPersister {
|
|||
update_ret: Mutex::new(Ok(())),
|
||||
next_update_ret: Mutex::new(None),
|
||||
chain_sync_monitor_persistences: Mutex::new(HashMap::new()),
|
||||
offchain_monitor_updates: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +210,8 @@ impl<Signer: keysinterface::Sign> chainmonitor::Persist<Signer> for TestPersiste
|
|||
}
|
||||
if update.is_none() {
|
||||
self.chain_sync_monitor_persistences.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);
|
||||
} else {
|
||||
self.offchain_monitor_updates.lock().unwrap().entry(funding_txo).or_insert(HashSet::new()).insert(update_id);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
@ -211,6 +221,13 @@ pub struct TestBroadcaster {
|
|||
pub txn_broadcasted: Mutex<Vec<Transaction>>,
|
||||
pub blocks: Arc<Mutex<Vec<(BlockHeader, u32)>>>,
|
||||
}
|
||||
|
||||
impl TestBroadcaster {
|
||||
pub fn new(blocks: Arc<Mutex<Vec<(BlockHeader, u32)>>>) -> TestBroadcaster {
|
||||
TestBroadcaster { txn_broadcasted: Mutex::new(Vec::new()), blocks }
|
||||
}
|
||||
}
|
||||
|
||||
impl chaininterface::BroadcasterInterface for TestBroadcaster {
|
||||
fn broadcast_transaction(&self, tx: &Transaction) {
|
||||
assert!(tx.lock_time < 1_500_000_000);
|
||||
|
|
Loading…
Add table
Reference in a new issue