X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fmod.rs;h=24eb09e7090b212ea9867aba9844ed6993c83735;hb=62edee568985e3362bd1609c6089d05428023925;hp=8f27e40baeaf1e3b5d43dade8a05da0bb08dfdcb;hpb=a8038a8234b70bc261f633a9e2b40adebebcd8d4;p=rust-lightning diff --git a/lightning/src/chain/mod.rs b/lightning/src/chain/mod.rs index 8f27e40b..24eb09e7 100644 --- a/lightning/src/chain/mod.rs +++ b/lightning/src/chain/mod.rs @@ -10,11 +10,13 @@ //! Structs and traits which allow other parts of rust-lightning to interact with the blockchain. use bitcoin::blockdata::block::{Block, BlockHeader}; +use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::hash_types::{BlockHash, Txid}; +use bitcoin::network::constants::Network; -use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateErr, MonitorEvent}; +use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, MonitorEvent}; use chain::keysinterface::Sign; use chain::transaction::{OutPoint, TransactionData}; @@ -28,6 +30,35 @@ pub mod keysinterface; pub(crate) mod onchaintx; pub(crate) mod package; +/// The best known block as identified by its hash and height. +#[derive(Clone, Copy, PartialEq)] +pub struct BestBlock { + block_hash: BlockHash, + height: u32, +} + +impl BestBlock { + /// Constructs a `BestBlock` that represents the genesis block at height 0 of the given + /// network. + pub fn from_genesis(network: Network) -> Self { + BestBlock { + block_hash: genesis_block(network).header.block_hash(), + height: 0, + } + } + + /// Returns a `BestBlock` as identified by the given block hash and height. + pub fn new(block_hash: BlockHash, height: u32) -> Self { + BestBlock { block_hash, height } + } + + /// Returns the best block hash. + pub fn block_hash(&self) -> BlockHash { self.block_hash } + + /// Returns the best block height. + pub fn height(&self) -> u32 { self.height } +} + /// An error when accessing the chain via [`Access`]. #[derive(Clone)] pub enum AccessError { @@ -56,9 +87,20 @@ pub trait Access { /// sourcing chain data using a block-oriented API should prefer this interface over [`Confirm`]. /// Such clients fetch the entire header chain whereas clients using [`Confirm`] only fetch headers /// when needed. +/// +/// By using [`Listen::filtered_block_connected`] this interface supports clients fetching the +/// entire header chain and only blocks with matching transaction data using BIP 157 filters or +/// other similar filtering. pub trait Listen { + /// Notifies the listener that a block was added at the given height, with the transaction data + /// possibly filtered. + fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32); + /// Notifies the listener that a block was added at the given height. - fn block_connected(&self, block: &Block, height: u32); + fn block_connected(&self, block: &Block, height: u32) { + let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); + self.filtered_block_connected(&block.header, &txdata, height); + } /// Notifies the listener that a block was removed at the given height. fn block_disconnected(&self, header: &BlockHeader, height: u32); @@ -144,6 +186,71 @@ pub trait Confirm { fn get_relevant_txids(&self) -> Vec; } +/// An error enum representing a failure to persist a channel monitor update. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ChannelMonitorUpdateErr { + /// Used to indicate a temporary failure (eg connection to a watchtower or remote backup of + /// our state failed, but is expected to succeed at some point in the future). + /// + /// Such a failure will "freeze" a channel, preventing us from revoking old states or + /// submitting new commitment transactions to the counterparty. Once the update(s) that failed + /// have been successfully applied, a [`MonitorEvent::UpdateCompleted`] event should be returned + /// via [`Watch::release_pending_monitor_events`] which will then restore the channel to an + /// operational state. + /// + /// Note that a given ChannelManager will *never* re-generate a given ChannelMonitorUpdate. If + /// you return a TemporaryFailure you must ensure that it is written to disk safely before + /// writing out the latest ChannelManager state. + /// + /// Even when a channel has been "frozen" updates to the ChannelMonitor can continue to occur + /// (eg if an inbound HTLC which we forwarded was claimed upstream resulting in us attempting + /// to claim it on this channel) and those updates must be applied wherever they can be. At + /// least one such updated ChannelMonitor must be persisted otherwise PermanentFailure should + /// be returned to get things on-chain ASAP using only the in-memory copy. Obviously updates to + /// the channel which would invalidate previous ChannelMonitors are not made when a channel has + /// been "frozen". + /// + /// Note that even if updates made after TemporaryFailure succeed you must still provide a + /// [`MonitorEvent::UpdateCompleted`] to ensure you have the latest monitor and re-enable + /// normal channel operation. Note that this is normally generated through a call to + /// [`ChainMonitor::channel_monitor_updated`]. + /// + /// Note that the update being processed here will not be replayed for you when you return a + /// [`MonitorEvent::UpdateCompleted`] event via [`Watch::release_pending_monitor_events`], so + /// you must store the update itself on your own local disk prior to returning a + /// TemporaryFailure. You may, of course, employ a journaling approach, storing only the + /// ChannelMonitorUpdate on disk without updating the monitor itself, replaying the journal at + /// reload-time. + /// + /// For deployments where a copy of ChannelMonitors and other local state are backed up in a + /// remote location (with local copies persisted immediately), it is anticipated that all + /// updates will return TemporaryFailure until the remote copies could be updated. + /// + /// [`ChainMonitor::channel_monitor_updated`]: chainmonitor::ChainMonitor::channel_monitor_updated + TemporaryFailure, + /// Used to indicate no further channel monitor updates will be allowed (eg we've moved on to a + /// different watchtower and cannot update with all watchtowers that were previously informed + /// of this channel). + /// + /// At reception of this error, ChannelManager will force-close the channel and return at + /// least a final ChannelMonitorUpdate::ChannelForceClosed which must be delivered to at + /// least one ChannelMonitor copy. Revocation secret MUST NOT be released and offchain channel + /// update must be rejected. + /// + /// This failure may also signal a failure to update the local persisted copy of one of + /// the channel monitor instance. + /// + /// Note that even when you fail a holder commitment transaction update, you must store the + /// update to ensure you can claim from it in case of a duplicate copy of this ChannelMonitor + /// broadcasts it (e.g distributed channel-monitor deployment) + /// + /// In case of distributed watchtowers deployment, the new version must be written to disk, as + /// state may have been stored but rejected due to a block forcing a commitment broadcast. This + /// storage is used to claim outputs of rejected state confirmed onchain by another watchtower, + /// lagging behind on block processing. + PermanentFailure, +} + /// The `Watch` trait defines behavior for watching on-chain activity pertaining to channels as /// blocks are connected and disconnected. /// @@ -162,9 +269,7 @@ pub trait Confirm { /// funds in the channel. See [`ChannelMonitorUpdateErr`] for more details about how to handle /// multiple instances. /// -/// [`ChannelMonitor`]: channelmonitor::ChannelMonitor -/// [`ChannelMonitorUpdateErr`]: channelmonitor::ChannelMonitorUpdateErr -/// [`PermanentFailure`]: channelmonitor::ChannelMonitorUpdateErr::PermanentFailure +/// [`PermanentFailure`]: ChannelMonitorUpdateErr::PermanentFailure pub trait Watch { /// Watches a channel identified by `funding_txo` using `monitor`. /// @@ -172,6 +277,9 @@ pub trait Watch { /// with any spends of outputs returned by [`get_outputs_to_watch`]. In practice, this means /// calling [`block_connected`] and [`block_disconnected`] on the monitor. /// + /// Note: this interface MUST error with `ChannelMonitorUpdateErr::PermanentFailure` if + /// the given `funding_txo` has previously been registered via `watch_channel`. + /// /// [`get_outputs_to_watch`]: channelmonitor::ChannelMonitor::get_outputs_to_watch /// [`block_connected`]: channelmonitor::ChannelMonitor::block_connected /// [`block_disconnected`]: channelmonitor::ChannelMonitor::block_disconnected @@ -183,11 +291,17 @@ pub trait Watch { /// [`ChannelMonitorUpdateErr`] for invariants around returning an error. /// /// [`update_monitor`]: channelmonitor::ChannelMonitor::update_monitor - /// [`ChannelMonitorUpdateErr`]: channelmonitor::ChannelMonitorUpdateErr fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr>; /// Returns any monitor events since the last call. Subsequent calls must only return new /// events. + /// + /// Note that after any block- or transaction-connection calls to a [`ChannelMonitor`], no + /// further events may be returned here until the [`ChannelMonitor`] has been fully persisted + /// to disk. + /// + /// For details on asynchronous [`ChannelMonitor`] updating and returning + /// [`MonitorEvent::UpdateCompleted`] here, see [`ChannelMonitorUpdateErr::TemporaryFailure`]. fn release_pending_monitor_events(&self) -> Vec; } @@ -208,7 +322,7 @@ pub trait Watch { /// processed later. Then, in order to block until the data has been processed, any [`Watch`] /// invocation that has called the `Filter` must return [`TemporaryFailure`]. /// -/// [`TemporaryFailure`]: channelmonitor::ChannelMonitorUpdateErr::TemporaryFailure +/// [`TemporaryFailure`]: ChannelMonitorUpdateErr::TemporaryFailure /// [BIP 157]: https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki /// [BIP 158]: https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki pub trait Filter { @@ -252,8 +366,8 @@ pub struct WatchedOutput { } impl Listen for core::ops::Deref { - fn block_connected(&self, block: &Block, height: u32) { - (**self).block_connected(block, height); + fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + (**self).filtered_block_connected(header, txdata, height); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { @@ -266,9 +380,9 @@ where T::Target: Listen, U::Target: Listen, { - fn block_connected(&self, block: &Block, height: u32) { - self.0.block_connected(block, height); - self.1.block_connected(block, height); + fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + self.0.filtered_block_connected(header, txdata, height); + self.1.filtered_block_connected(header, txdata, height); } fn block_disconnected(&self, header: &BlockHeader, height: u32) {