//!
use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::transaction::Transaction;
use bitcoin::blockdata::constants::genesis_block;
use bitcoin::network::constants::Network;
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
use chain::transaction::{OutPoint, TransactionData};
+// Since this struct is returned in `list_channels` methods, expose it here in case users want to
+// construct one themselves.
+pub use ln::channel::CounterpartyForwardingInfo;
use ln::channel::{Channel, ChannelError};
use ln::features::{InitFeatures, NodeFeatures};
use routing::router::{Route, RouteHop};
pub(super) latest_block_height: AtomicUsize,
#[cfg(not(test))]
latest_block_height: AtomicUsize,
- last_block_hash: Mutex<BlockHash>,
+ last_block_hash: RwLock<BlockHash>,
secp_ctx: Secp256k1<secp256k1::All>,
#[cfg(any(test, feature = "_test_utils"))]
logger: L,
}
+/// Chain-related parameters used to construct a new `ChannelManager`.
+///
+/// Typically, the block-specific parameters are derived from the best block hash for the network,
+/// as a newly constructed `ChannelManager` will not have created any channels yet. These parameters
+/// are not needed when deserializing a previously constructed `ChannelManager`.
+pub struct ChainParameters {
+ /// The network for determining the `chain_hash` in Lightning messages.
+ pub network: Network,
+
+ /// The hash of the latest block successfully connected.
+ pub latest_hash: BlockHash,
+
+ /// The height of the latest block successfully connected.
+ ///
+ /// Used to track on-chain channel funding outputs and send payments with reliable timelocks.
+ pub latest_height: usize,
+}
+
/// Whenever we release the `ChannelManager`'s `total_consistency_lock`, from read mode, it is
-/// desirable to notify any listeners on `wait_timeout`/`wait` that new updates are available for
-/// persistence. Therefore, this struct is responsible for locking the total consistency lock and,
-/// upon going out of scope, sending the aforementioned notification (since the lock being released
-/// indicates that the updates are ready for persistence).
+/// desirable to notify any listeners on `await_persistable_update_timeout`/
+/// `await_persistable_update` that new updates are available for persistence. Therefore, this
+/// struct is responsible for locking the total consistency lock and, upon going out of scope,
+/// sending the aforementioned notification (since the lock being released indicates that the
+/// updates are ready for persistence).
struct PersistenceNotifierGuard<'a> {
persistence_notifier: &'a PersistenceNotifier,
// We hold onto this result so the lock doesn't get released immediately.
}
}
-/// The amount of time we require our counterparty wait to claim their money (ie time between when
-/// we, or our watchtower, must check for them having broadcast a theft transaction).
-pub(crate) const BREAKDOWN_TIMEOUT: u16 = 6 * 24;
-/// The amount of time we're willing to wait to claim money back to us
-pub(crate) const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7;
+/// The amount of time in blocks we require our counterparty wait to claim their money (ie time
+/// between when we, or our watchtower, must check for them having broadcast a theft transaction).
+///
+/// This can be increased (but not decreased) through [`ChannelHandshakeConfig::our_to_self_delay`]
+///
+/// [`ChannelHandshakeConfig::our_to_self_delay`]: crate::util::config::ChannelHandshakeConfig::our_to_self_delay
+pub const BREAKDOWN_TIMEOUT: u16 = 6 * 24;
+/// The amount of time in blocks we're willing to wait to claim money back to us. This matches
+/// the maximum required amount in lnd as of March 2021.
+pub(crate) const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 2 * 6 * 24 * 7;
/// The minimum number of blocks between an inbound HTLC's CLTV and the corresponding outbound
-/// HTLC's CLTV. This should always be a few blocks greater than channelmonitor::CLTV_CLAIM_BUFFER,
-/// ie the node we forwarded the payment on to should always have enough room to reliably time out
-/// the HTLC via a full update_fail_htlc/commitment_signed dance before we hit the
-/// CLTV_CLAIM_BUFFER point (we static assert that it's at least 3 blocks more).
-const CLTV_EXPIRY_DELTA: u16 = 6 * 12; //TODO?
+/// HTLC's CLTV. The current default represents roughly six hours of blocks at six blocks/hour.
+///
+/// This can be increased (but not decreased) through [`ChannelConfig::cltv_expiry_delta`]
+///
+/// [`ChannelConfig::cltv_expiry_delta`]: crate::util::config::ChannelConfig::cltv_expiry_delta
+// This should always be a few blocks greater than channelmonitor::CLTV_CLAIM_BUFFER,
+// i.e. the node we forwarded the payment on to should always have enough room to reliably time out
+// the HTLC via a full update_fail_htlc/commitment_signed dance before we hit the
+// CLTV_CLAIM_BUFFER point (we static assert that it's at least 3 blocks more).
+pub const MIN_CLTV_EXPIRY_DELTA: u16 = 6 * 6;
pub(super) const CLTV_FAR_FAR_AWAY: u32 = 6 * 24 * 7; //TODO?
// Check that our CLTV_EXPIRY is at least CLTV_CLAIM_BUFFER + ANTI_REORG_DELAY + LATENCY_GRACE_PERIOD_BLOCKS,
// LATENCY_GRACE_PERIOD_BLOCKS.
#[deny(const_err)]
#[allow(dead_code)]
-const CHECK_CLTV_EXPIRY_SANITY: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - CLTV_CLAIM_BUFFER - ANTI_REORG_DELAY - LATENCY_GRACE_PERIOD_BLOCKS;
+const CHECK_CLTV_EXPIRY_SANITY: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - CLTV_CLAIM_BUFFER - ANTI_REORG_DELAY - LATENCY_GRACE_PERIOD_BLOCKS;
// Check for ability of an attacker to make us fail on-chain by delaying inbound claim. See
// ChannelMontior::would_broadcast_at_height for a description of why this is needed.
#[deny(const_err)]
#[allow(dead_code)]
-const CHECK_CLTV_EXPIRY_SANITY_2: u32 = CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
+const CHECK_CLTV_EXPIRY_SANITY_2: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2*CLTV_CLAIM_BUFFER;
/// Details of a channel, as returned by ChannelManager::list_channels and ChannelManager::list_usable_channels
#[derive(Clone)]
/// True if the channel is (a) confirmed and funding_locked messages have been exchanged, (b)
/// the peer is connected, and (c) no monitor update failure is pending resolution.
pub is_live: bool,
+
+ /// Information on the fees and requirements that the counterparty requires when forwarding
+ /// payments to us through this channel.
+ pub counterparty_forwarding_info: Option<CounterpartyForwardingInfo>,
}
/// If a payment fails to send, it can be in one of several states. This enum is returned as the
///
/// panics if channel_value_satoshis is >= `MAX_FUNDING_SATOSHIS`!
///
- /// Users must provide the current blockchain height from which to track onchain channel
- /// funding outpoints and send payments with reliable timelocks.
- ///
/// Users need to notify the new ChannelManager when a new block is connected or
- /// disconnected using its `block_connected` and `block_disconnected` methods.
- pub fn new(network: Network, fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, current_blockchain_height: usize) -> Self {
+ /// disconnected using its `block_connected` and `block_disconnected` methods, starting
+ /// from after `params.latest_hash`.
+ pub fn new(fee_est: F, chain_monitor: M, tx_broadcaster: T, logger: L, keys_manager: K, config: UserConfig, params: ChainParameters) -> Self {
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
ChannelManager {
default_configuration: config.clone(),
- genesis_hash: genesis_block(network).header.block_hash(),
+ genesis_hash: genesis_block(params.network).header.block_hash(),
fee_estimator: fee_est,
chain_monitor,
tx_broadcaster,
- latest_block_height: AtomicUsize::new(current_blockchain_height),
- last_block_hash: Mutex::new(Default::default()),
+ latest_block_height: AtomicUsize::new(params.latest_height),
+ last_block_hash: RwLock::new(params.latest_hash),
secp_ctx,
channel_state: Mutex::new(ChannelHolder{
/// Creates a new outbound channel to the given remote node and with the given value.
///
- /// user_id will be provided back as user_channel_id in FundingGenerationReady and
- /// FundingBroadcastSafe events to allow tracking of which events correspond with which
- /// create_channel call. Note that user_channel_id defaults to 0 for inbound channels, so you
- /// may wish to avoid using 0 for user_id here.
+ /// user_id will be provided back as user_channel_id in FundingGenerationReady events to allow
+ /// tracking of which events correspond with which create_channel call. Note that the
+ /// user_channel_id defaults to 0 for inbound channels, so you may wish to avoid using 0 for
+ /// user_id here. user_id has no meaning inside of LDK, it is simply copied to events and
+ /// otherwise ignored.
///
/// If successful, will generate a SendOpenChannel message event, so you should probably poll
/// PeerManager::process_events afterwards.
outbound_capacity_msat,
user_id: channel.get_user_id(),
is_live: channel.is_live(),
+ counterparty_forwarding_info: channel.counterparty_forwarding_info(),
});
}
}
if fee.is_none() || msg.amount_msat < fee.unwrap() || (msg.amount_msat - fee.unwrap()) < *amt_to_forward { // fee_insufficient
break Some(("Prior hop has deviated from specified fees parameters or origin node has obsolete ones", 0x1000 | 12, Some(self.get_channel_update(chan).unwrap())));
}
- if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + CLTV_EXPIRY_DELTA as u64 { // incorrect_cltv_expiry
+ if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + chan.get_cltv_expiry_delta() as u64 { // incorrect_cltv_expiry
break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, Some(self.get_channel_update(chan).unwrap())));
}
let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
short_channel_id,
timestamp: chan.get_update_time_counter(),
flags: (!were_node_one) as u8 | ((!chan.is_live() as u8) << 1),
- cltv_expiry_delta: CLTV_EXPIRY_DELTA,
+ cltv_expiry_delta: chan.get_cltv_expiry_delta(),
htlc_minimum_msat: chan.get_counterparty_htlc_minimum_msat(),
htlc_maximum_msat: OptionalField::Present(chan.get_announced_htlc_max_msat()),
fee_base_msat: chan.get_holder_fee_base_msat(&self.fee_estimator),
/// Call this upon creation of a funding transaction for the given channel.
///
- /// Note that ALL inputs in the transaction pointed to by funding_txo MUST spend SegWit outputs
- /// or your counterparty can steal your funds!
+ /// Returns an [`APIError::APIMisuseError`] if the funding_transaction spent non-SegWit outputs
+ /// or if no output was found which matches the parameters in [`Event::FundingGenerationReady`].
///
/// Panics if a funding transaction has already been provided for this channel.
///
- /// May panic if the funding_txo is duplicative with some other channel (note that this should
- /// be trivially prevented by using unique funding transaction keys per-channel).
- pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_txo: OutPoint) {
+ /// May panic if the output found in the funding transaction is duplicative with some other
+ /// channel (note that this should be trivially prevented by using unique funding transaction
+ /// keys per-channel).
+ ///
+ /// Do NOT broadcast the funding transaction yourself. When we have safely received our
+ /// counterparty's signature the funding transaction will automatically be broadcast via the
+ /// [`BroadcasterInterface`] provided when this `ChannelManager` was constructed.
+ ///
+ /// Note that this includes RBF or similar transaction replacement strategies - lightning does
+ /// not currently support replacing a funding transaction on an existing channel. Instead,
+ /// create a new channel with a conflicting funding transaction.
+ pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], funding_transaction: Transaction) -> Result<(), APIError> {
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+ for inp in funding_transaction.input.iter() {
+ if inp.witness.is_empty() {
+ return Err(APIError::APIMisuseError {
+ err: "Funding transaction must be fully signed and spend Segwit outputs".to_owned()
+ });
+ }
+ }
+
let (chan, msg) = {
let (res, chan) = match self.channel_state.lock().unwrap().by_id.remove(temporary_channel_id) {
Some(mut chan) => {
- (chan.get_outbound_funding_created(funding_txo, &self.logger)
+ let mut output_index = None;
+ let expected_spk = chan.get_funding_redeemscript().to_v0_p2wsh();
+ for (idx, outp) in funding_transaction.output.iter().enumerate() {
+ if outp.script_pubkey == expected_spk && outp.value == chan.get_value_satoshis() {
+ if output_index.is_some() {
+ return Err(APIError::APIMisuseError {
+ err: "Multiple outputs matched the expected script and value".to_owned()
+ });
+ }
+ if idx > u16::max_value() as usize {
+ return Err(APIError::APIMisuseError {
+ err: "Transaction had more than 2^16 outputs, which is not supported".to_owned()
+ });
+ }
+ output_index = Some(idx as u16);
+ }
+ }
+ if output_index.is_none() {
+ return Err(APIError::APIMisuseError {
+ err: "No output matched the script_pubkey and value in the FundingGenerationReady event".to_owned()
+ });
+ }
+ let funding_txo = OutPoint { txid: funding_transaction.txid(), index: output_index.unwrap() };
+
+ (chan.get_outbound_funding_created(funding_transaction, funding_txo, &self.logger)
.map_err(|e| if let ChannelError::Close(msg) = e {
MsgHandleErrInternal::from_finish_shutdown(msg, chan.channel_id(), chan.force_shutdown(true), None)
} else { unreachable!(); })
, chan)
},
- None => return
+ None => { return Err(APIError::ChannelUnavailable { err: "No such channel".to_owned() }) },
};
match handle_error!(self, res, chan.get_counterparty_node_id()) {
Ok(funding_msg) => {
(chan, funding_msg)
},
- Err(_) => { return; }
+ Err(_) => { return Err(APIError::ChannelUnavailable {
+ err: "Error deriving keys or signing initial commitment transactions - either our RNG or our counterparty's RNG is broken or the Signer refused to sign".to_owned()
+ }) },
}
};
e.insert(chan);
}
}
+ Ok(())
}
fn get_announcement_sigs(&self, chan: &Channel<Signer>) -> Option<msgs::AnnouncementSignatures> {
return;
}
- let (raa, commitment_update, order, pending_forwards, mut pending_failures, needs_broadcast_safe, funding_locked) = channel.monitor_updating_restored(&self.logger);
+ let (raa, commitment_update, order, pending_forwards, mut pending_failures, funding_broadcastable, funding_locked) = channel.monitor_updating_restored(&self.logger);
if !pending_forwards.is_empty() {
htlc_forwards.push((channel.get_short_channel_id().expect("We can't have pending forwards before funding confirmation"), funding_txo.clone(), pending_forwards));
}
handle_cs!();
},
}
- if needs_broadcast_safe {
- pending_events.push(events::Event::FundingBroadcastSafe {
- funding_txo: channel.get_funding_txo().unwrap(),
- user_channel_id: channel.get_user_id(),
- });
+ if let Some(tx) = funding_broadcastable {
+ self.tx_broadcaster.broadcast_transaction(&tx);
}
if let Some(msg) = funding_locked {
pending_msg_events.push(events::MessageSendEvent::SendFundingLocked {
fn internal_funding_created(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingCreated) -> Result<(), MsgHandleErrInternal> {
let ((funding_msg, monitor), mut chan) = {
+ let last_block_hash = *self.last_block_hash.read().unwrap();
let mut channel_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_lock;
match channel_state.by_id.entry(msg.temporary_channel_id.clone()) {
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.temporary_channel_id));
}
- (try_chan_entry!(self, chan.get_mut().funding_created(msg, &self.logger), channel_state, chan), chan.remove())
+ (try_chan_entry!(self, chan.get_mut().funding_created(msg, last_block_hash, &self.logger), channel_state, chan), chan.remove())
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.temporary_channel_id))
}
}
fn internal_funding_signed(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), MsgHandleErrInternal> {
- let (funding_txo, user_id) = {
+ let funding_tx = {
+ let last_block_hash = *self.last_block_hash.read().unwrap();
let mut channel_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_lock;
match channel_state.by_id.entry(msg.channel_id) {
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
}
- let monitor = match chan.get_mut().funding_signed(&msg, &self.logger) {
+ let (monitor, funding_tx) = match chan.get_mut().funding_signed(&msg, last_block_hash, &self.logger) {
Ok(update) => update,
Err(e) => try_chan_entry!(self, Err(e), channel_state, chan),
};
if let Err(e) = self.chain_monitor.watch_channel(chan.get().get_funding_txo().unwrap(), monitor) {
return_monitor_err!(self, e, channel_state, chan, RAACommitmentOrder::RevokeAndACKFirst, false, false);
}
- (chan.get().get_funding_txo().unwrap(), chan.get().get_user_id())
+ funding_tx
},
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
}
};
- let mut pending_events = self.pending_events.lock().unwrap();
- pending_events.push(events::Event::FundingBroadcastSafe {
- funding_txo,
- user_channel_id: user_id,
- });
+ self.tx_broadcaster.broadcast_transaction(&funding_tx);
Ok(())
}
Ok(())
}
+ fn internal_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) -> Result<(), MsgHandleErrInternal> {
+ let mut channel_state_lock = self.channel_state.lock().unwrap();
+ let channel_state = &mut *channel_state_lock;
+ let chan_id = match channel_state.short_to_id.get(&msg.contents.short_channel_id) {
+ Some(chan_id) => chan_id.clone(),
+ None => {
+ // It's not a local channel
+ return Ok(())
+ }
+ };
+ match channel_state.by_id.entry(chan_id) {
+ hash_map::Entry::Occupied(mut chan) => {
+ if chan.get().get_counterparty_node_id() != *counterparty_node_id {
+ // TODO: see issue #153, need a consistent behavior on obnoxious behavior from random node
+ return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), chan_id));
+ }
+ try_chan_entry!(self, chan.get_mut().channel_update(&msg), channel_state, chan);
+ },
+ hash_map::Entry::Vacant(_) => unreachable!()
+ }
+ Ok(())
+ }
+
fn internal_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) -> Result<(), MsgHandleErrInternal> {
let mut channel_state_lock = self.channel_state.lock().unwrap();
let channel_state = &mut *channel_state_lock;
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
// during initialization prior to the chain_monitor being fully configured in some cases.
// See the docs for `ChannelManagerReadArgs` for more.
- let header_hash = header.block_hash();
- log_trace!(self.logger, "Block {} at height {} connected", header_hash, height);
+ let block_hash = header.block_hash();
+ log_trace!(self.logger, "Block {} at height {} connected", block_hash, height);
+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+
+ assert_eq!(*self.last_block_hash.read().unwrap(), header.prev_blockhash,
+ "Blocks must be connected in chain-order - the connected header must build on the last connected header");
+ assert_eq!(self.latest_block_height.load(Ordering::Acquire) as u64, height as u64 - 1,
+ "Blocks must be connected in chain-order - the connected header must build on the last connected header");
+ self.latest_block_height.store(height as usize, Ordering::Release);
+ *self.last_block_hash.write().unwrap() = block_hash;
+
let mut failed_channels = Vec::new();
let mut timed_out_htlcs = Vec::new();
{
for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
}
- self.latest_block_height.store(height as usize, Ordering::Release);
- *self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header_hash;
+
loop {
// Update last_node_announcement_serial to be the max of its current value and the
// block timestamp. This should keep us close to the current time without relying on
// during initialization prior to the chain_monitor being fully configured in some cases.
// See the docs for `ChannelManagerReadArgs` for more.
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+
+ assert_eq!(*self.last_block_hash.read().unwrap(), header.block_hash(),
+ "Blocks must be disconnected in chain-order - the disconnected header must be the last connected header");
+ self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
+ *self.last_block_hash.write().unwrap() = header.prev_blockhash;
+
let mut failed_channels = Vec::new();
{
let mut channel_lock = self.channel_state.lock().unwrap();
}
});
}
+
self.handle_init_event_channel_failures(failed_channels);
- self.latest_block_height.fetch_sub(1, Ordering::AcqRel);
- *self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header.block_hash();
}
/// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool
- /// indicating whether persistence is necessary. Only one listener on `wait_timeout` is
- /// guaranteed to be woken up.
+ /// indicating whether persistence is necessary. Only one listener on
+ /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken
+ /// up.
/// Note that the feature `allow_wallclock_use` must be enabled to use this function.
#[cfg(any(test, feature = "allow_wallclock_use"))]
- pub fn wait_timeout(&self, max_wait: Duration) -> bool {
+ pub fn await_persistable_update_timeout(&self, max_wait: Duration) -> bool {
self.persistence_notifier.wait_timeout(max_wait)
}
- /// Blocks until ChannelManager needs to be persisted. Only one listener on `wait` is
- /// guaranteed to be woken up.
- pub fn wait(&self) {
+ /// Blocks until ChannelManager needs to be persisted. Only one listener on
+ /// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken
+ /// up.
+ pub fn await_persistable_update(&self) {
self.persistence_notifier.wait()
}
let _ = handle_error!(self, self.internal_announcement_signatures(counterparty_node_id, msg), *counterparty_node_id);
}
+ fn handle_channel_update(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelUpdate) {
+ let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
+ let _ = handle_error!(self, self.internal_channel_update(counterparty_node_id, msg), *counterparty_node_id);
+ }
+
fn handle_channel_reestablish(&self, counterparty_node_id: &PublicKey, msg: &msgs::ChannelReestablish) {
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
let _ = handle_error!(self, self.internal_channel_reestablish(counterparty_node_id, msg), *counterparty_node_id);
&events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => true,
&events::MessageSendEvent::SendChannelRangeQuery { .. } => false,
&events::MessageSendEvent::SendShortIdsQuery { .. } => false,
+ &events::MessageSendEvent::SendReplyChannelRange { .. } => false,
}
});
}
}
/// Used to signal to the ChannelManager persister that the manager needs to be re-persisted to
-/// disk/backups, through `wait_timeout` and `wait`.
+/// disk/backups, through `await_persistable_update_timeout` and `await_persistable_update`.
struct PersistenceNotifier {
/// Users won't access the persistence_lock directly, but rather wait on its bool using
/// `wait_timeout` and `wait`.
self.genesis_hash.write(writer)?;
(self.latest_block_height.load(Ordering::Acquire) as u32).write(writer)?;
- self.last_block_hash.lock().unwrap().write(writer)?;
+ self.last_block_hash.read().unwrap().write(writer)?;
let channel_state = self.channel_state.lock().unwrap();
let mut unfunded_channels = 0;
let mut short_to_id = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
for _ in 0..channel_count {
let mut channel: Channel<Signer> = Channel::read(reader, &args.keys_manager)?;
- if channel.last_block_connected != Default::default() && channel.last_block_connected != last_block_hash {
- return Err(DecodeError::InvalidValue);
- }
-
let funding_txo = channel.get_funding_txo().ok_or(DecodeError::InvalidValue)?;
funding_txo_set.insert(funding_txo.clone());
if let Some(ref mut monitor) = args.channel_monitors.get_mut(&funding_txo) {
tx_broadcaster: args.tx_broadcaster,
latest_block_height: AtomicUsize::new(latest_block_height as usize),
- last_block_hash: Mutex::new(last_block_hash),
+ last_block_hash: RwLock::new(last_block_hash),
secp_ctx,
channel_state: Mutex::new(ChannelHolder {