//! ChannelMonitors should do so). Thus, if you're building rust-lightning into an HSM or other
//! security-domain-separated system design, you should consider having multiple paths for
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
-//!
-//! [`chain::Watch`]: ../trait.Watch.html
use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::{TxOut,Transaction};
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use chain::transaction::{OutPoint, TransactionData};
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
+use chain::Filter;
use util::logger::Logger;
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48};
use util::byte_utils;
use util::events::Event;
-use std::cell::RefCell;
use std::collections::{HashMap, HashSet, hash_map};
use std::{cmp, mem};
use std::io::Error;
/// The only instance where update_id values are not strictly increasing is the case where we
/// allow post-force-close updates with a special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. See
/// its docs for more details.
- ///
- /// [`CLOSED_CHANNEL_UPDATE_ID`]: constant.CLOSED_CHANNEL_UPDATE_ID.html
pub update_id: u64,
}
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
/// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the
/// preimage claim backward will lead to loss of funds.
-///
-/// [`chain::Watch`]: ../trait.Watch.html
#[derive(Clone, PartialEq)]
pub struct HTLCUpdate {
pub(crate) payment_hash: PaymentHash,
/// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events
/// gotten are fully handled before re-serializing the new state.
///
-/// Note that the deserializer is only implemented for (Sha256dHash, ChannelMonitor), which
+/// Note that the deserializer is only implemented for (BlockHash, ChannelMonitor), which
/// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
/// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the
/// returned block hash and the the current chain and then reconnecting blocks to get to the
channel_parameters: &ChannelTransactionParameters,
funding_redeemscript: Script, channel_value_satoshis: u64,
commitment_transaction_number_obscure_factor: u64,
- initial_holder_commitment_tx: HolderCommitmentTransaction) -> ChannelMonitor<Signer> {
+ initial_holder_commitment_tx: HolderCommitmentTransaction,
+ last_block_hash: BlockHash) -> ChannelMonitor<Signer> {
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize());
lockdown_from_offchain: false,
holder_tx_signed: false,
- last_block_hash: Default::default(),
+ last_block_hash,
secp_ctx,
}),
}
/// Gets a list of txids, with their output scripts (in the order they appear in the
/// transaction), which we must learn about spends of via block_connected().
- ///
- /// (C-not exported) because we have no HashMap bindings
- pub fn get_outputs_to_watch(&self) -> HashMap<Txid, Vec<(u32, Script)>> {
- self.inner.lock().unwrap().get_outputs_to_watch().clone()
+ pub fn get_outputs_to_watch(&self) -> Vec<(Txid, Vec<(u32, Script)>)> {
+ self.inner.lock().unwrap().get_outputs_to_watch()
+ .iter().map(|(txid, outputs)| (*txid, outputs.clone())).collect()
+ }
+
+ /// Loads the funding txo and outputs to watch into the given `chain::Filter` by repeatedly
+ /// calling `chain::Filter::register_output` and `chain::Filter::register_tx` until all outputs
+ /// have been registered.
+ pub fn load_outputs_to_watch<F: Deref>(&self, filter: &F) where F::Target: chain::Filter {
+ let lock = self.inner.lock().unwrap();
+ filter.register_tx(&lock.get_funding_txo().0.txid, &lock.get_funding_txo().1);
+ for (txid, outputs) in lock.get_outputs_to_watch().iter() {
+ for (index, script_pubkey) in outputs.iter() {
+ assert!(*index <= u16::max_value() as u32);
+ filter.register_output(&OutPoint { txid: *txid, index: *index as u16 }, script_pubkey);
+ }
+ }
}
/// Get the list of HTLCs who's status has been updated on chain. This should be called by
/// ChannelManager via [`chain::Watch::release_pending_monitor_events`].
- ///
- /// [`chain::Watch::release_pending_monitor_events`]: ../trait.Watch.html#tymethod.release_pending_monitor_events
pub fn get_and_clear_pending_monitor_events(&self) -> Vec<MonitorEvent> {
self.inner.lock().unwrap().get_and_clear_pending_monitor_events()
}
F::Target: FeeEstimator,
L::Target: Logger,
{
- let block_hash = header.block_hash();
- log_trace!(logger, "Block {} at height {} disconnected", block_hash, height);
+ log_trace!(logger, "Block {} at height {} disconnected", header.block_hash(), height);
if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) {
//We may discard:
self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger);
- self.last_block_hash = block_hash;
+ self.last_block_hash = header.prev_blockhash;
}
/// Filters a block's `txdata` for transactions spending watched outputs or for any child
/// stored channel data). Note that you **must** persist every new monitor to
/// disk. See the `Persist` trait documentation for more details.
///
- /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`,
+ /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`,
/// and [`ChannelMonitorUpdateErr`] for requirements when returning errors.
- ///
- /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk
- /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
/// Update one channel's data. The provided `ChannelMonitor` has already
/// them in batches. The size of each monitor grows `O(number of state updates)`
/// whereas updates are small and `O(1)`.
///
- /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`,
+ /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`,
/// [`ChannelMonitorUpdate::write`] for writing out an update, and
/// [`ChannelMonitorUpdateErr`] for requirements when returning errors.
- ///
- /// [`ChannelMonitor::update_monitor`]: struct.ChannelMonitor.html#impl-1
- /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk
- /// [`ChannelMonitorUpdate::write`]: struct.ChannelMonitorUpdate.html#method.write
- /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
}
-impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Listen for (RefCell<ChannelMonitor<Signer>>, T, F, L)
+impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Listen for (ChannelMonitor<Signer>, T, F, L)
where
T::Target: BroadcasterInterface,
F::Target: FeeEstimator,
{
fn block_connected(&self, block: &Block, height: u32) {
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
- self.0.borrow_mut().block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3);
+ self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3);
}
fn block_disconnected(&self, header: &BlockHeader, height: u32) {
- self.0.borrow_mut().block_disconnected(header, height, &*self.1, &*self.2, &*self.3);
+ self.0.block_disconnected(header, height, &*self.1, &*self.2, &*self.3);
}
}
#[cfg(test)]
mod tests {
+ use bitcoin::blockdata::constants::genesis_block;
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType};
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::hex::FromHex;
use bitcoin::hash_types::Txid;
+ use bitcoin::network::constants::Network;
use hex;
use chain::channelmonitor::ChannelMonitor;
use chain::transaction::OutPoint;
};
// Prune with one old state and a holder commitment tx holding a few overlaps with the
// old state.
+ let last_block_hash = genesis_block(Network::Testnet).block_hash();
let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
(OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
&channel_parameters,
Script::new(), 46, 0,
- HolderCommitmentTransaction::dummy());
+ HolderCommitmentTransaction::dummy(), last_block_hash);
monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..10])).unwrap();
let dummy_txid = dummy_tx.txid();