Skip to content

Commit

Permalink
Merge pull request #889 from jkczyz/2021-04-electrum-trait
Browse files Browse the repository at this point in the history
Define chain::Confirm trait for use by Electrum clients
  • Loading branch information
TheBlueMatt authored Apr 23, 2021
2 parents 4f6a038 + 99e2283 commit 0d75a63
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 283 deletions.
5 changes: 3 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hash_types::{BlockHash, WPubkeyHash};

use lightning::chain;
use lightning::chain::Confirm;
use lightning::chain::chainmonitor;
use lightning::chain::channelmonitor;
use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, MonitorEvent};
Expand Down Expand Up @@ -428,11 +429,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
let chain_hash = genesis_block(Network::Bitcoin).block_hash();
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
$node.transactions_confirmed(&header, 1, &txdata);
$node.transactions_confirmed(&header, &txdata, 1);
for _ in 2..100 {
header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
}
$node.update_best_block(&header, 99);
$node.best_block_updated(&header, 99);
} }
}

Expand Down
9 changes: 5 additions & 4 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};

use lightning::chain;
use lightning::chain::Listen;
use lightning::chain::{Confirm, Listen};
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
use lightning::chain::chainmonitor;
use lightning::chain::transaction::OutPoint;
Expand Down Expand Up @@ -207,9 +207,10 @@ impl<'a> MoneyLossDetector<'a> {
self.blocks_connected += 1;
let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height].0, merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 };
self.height += 1;
self.manager.transactions_confirmed(&header, self.height as u32, &txdata);
self.manager.update_best_block(&header, self.height as u32);
(*self.monitor).block_connected(&header, &txdata, self.height as u32);
self.manager.transactions_confirmed(&header, &txdata, self.height as u32);
self.manager.best_block_updated(&header, self.height as u32);
(*self.monitor).transactions_confirmed(&header, &txdata, self.height as u32);
(*self.monitor).best_block_updated(&header, self.height as u32);
if self.header_hashes.len() > self.height {
self.header_hashes[self.height] = (header.block_hash(), self.blocks_connected);
} else {
Expand Down
153 changes: 59 additions & 94 deletions lightning/src/chain/chainmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,64 +74,14 @@ where C::Target: chain::Filter,
P::Target: channelmonitor::Persist<ChannelSigner>,
{
/// Dispatches to per-channel monitors, which are responsible for updating their on-chain view
/// of a channel and reacting accordingly based on transactions in the connected block. See
/// of a channel and reacting accordingly based on transactions in the given chain data. See
/// [`ChannelMonitor::block_connected`] for details. Any HTLCs that were resolved on chain will
/// be returned by [`chain::Watch::release_pending_monitor_events`].
///
/// Calls back to [`chain::Filter`] if any monitor indicated new outputs to watch. Subsequent
/// calls must not exclude any transactions matching the new outputs nor any in-block
/// descendants of such transactions. It is not necessary to re-fetch the block to obtain
/// updated `txdata`.
pub fn block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
self.process_chain_data(header, txdata, |monitor, txdata| {
monitor.block_connected(
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

/// Dispatches to per-channel monitors, which are responsible for updating their on-chain view
/// of a channel and reacting accordingly to newly confirmed transactions. For details, see
/// [`ChannelMonitor::transactions_confirmed`].
///
/// Used instead of [`block_connected`] by clients that are notified of transactions rather than
/// blocks. May be called before or after [`update_best_block`] for transactions in the
/// corresponding block. See [`update_best_block`] for further calling expectations.
///
/// [`block_connected`]: Self::block_connected
/// [`update_best_block`]: Self::update_best_block
pub fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
self.process_chain_data(header, txdata, |monitor, txdata| {
monitor.transactions_confirmed(
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

/// Dispatches to per-channel monitors, which are responsible for updating their on-chain view
/// of a channel and reacting accordingly based on the new chain tip. For details, see
/// [`ChannelMonitor::update_best_block`].
///
/// Used instead of [`block_connected`] by clients that are notified of transactions rather than
/// blocks. May be called before or after [`transactions_confirmed`] for the corresponding
/// block.
///
/// Must be called after new blocks become available for the most recent block. Intermediary
/// blocks, however, may be safely skipped. In the event of a chain re-organization, this only
/// needs to be called for the most recent block assuming `transaction_unconfirmed` is called
/// for any affected transactions.
///
/// [`block_connected`]: Self::block_connected
/// [`transactions_confirmed`]: Self::transactions_confirmed
/// [`transaction_unconfirmed`]: Self::transaction_unconfirmed
pub fn update_best_block(&self, header: &BlockHeader, height: u32) {
self.process_chain_data(header, &[], |monitor, txdata| {
// While in practice there shouldn't be any recursive calls when given empty txdata,
// it's still possible if a chain::Filter implementation returns a transaction.
debug_assert!(txdata.is_empty());
monitor.update_best_block(
header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

fn process_chain_data<FN>(&self, header: &BlockHeader, txdata: &TransactionData, process: FN)
where
FN: Fn(&ChannelMonitor<ChannelSigner>, &TransactionData) -> Vec<TransactionOutputs>
Expand Down Expand Up @@ -172,46 +122,6 @@ where C::Target: chain::Filter,
}
}

/// Dispatches to per-channel monitors, which are responsible for updating their on-chain view
/// of a channel based on the disconnected block. See [`ChannelMonitor::block_disconnected`] for
/// details.
pub fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
monitor.block_disconnected(header, disconnected_height, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}

/// Dispatches to per-channel monitors, which are responsible for updating their on-chain view
/// of a channel based on transactions unconfirmed as a result of a chain reorganization. See
/// [`ChannelMonitor::transaction_unconfirmed`] for details.
///
/// Used instead of [`block_disconnected`] by clients that are notified of transactions rather
/// than blocks. May be called before or after [`update_best_block`] for transactions in the
/// corresponding block. See [`update_best_block`] for further calling expectations.
///
/// [`block_disconnected`]: Self::block_disconnected
/// [`update_best_block`]: Self::update_best_block
pub fn transaction_unconfirmed(&self, txid: &Txid) {
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}

/// Returns the set of txids that should be monitored for re-organization out of the chain.
pub fn get_relevant_txids(&self) -> Vec<Txid> {
let mut txids = Vec::new();
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
txids.append(&mut monitor.get_relevant_txids());
}

txids.sort_unstable();
txids.dedup();
txids
}

/// Creates a new `ChainMonitor` used to watch on-chain activity pertaining to channels.
///
/// When an optional chain source implementing [`chain::Filter`] is provided, the chain monitor
Expand All @@ -231,7 +141,7 @@ where C::Target: chain::Filter,
}
}

impl<ChannelSigner: Sign, C: Deref + Send + Sync, T: Deref + Send + Sync, F: Deref + Send + Sync, L: Deref + Send + Sync, P: Deref + Send + Sync>
impl<ChannelSigner: Sign, C: Deref, T: Deref, F: Deref, L: Deref, P: Deref>
chain::Listen for ChainMonitor<ChannelSigner, C, T, F, L, P>
where
ChannelSigner: Sign,
Expand All @@ -242,12 +152,67 @@ where
P::Target: channelmonitor::Persist<ChannelSigner>,
{
fn block_connected(&self, block: &Block, height: u32) {
let header = &block.header;
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
ChainMonitor::block_connected(self, &block.header, &txdata, height);
self.process_chain_data(header, &txdata, |monitor, txdata| {
monitor.block_connected(
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

fn block_disconnected(&self, header: &BlockHeader, height: u32) {
ChainMonitor::block_disconnected(self, header, height);
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
monitor.block_disconnected(
header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}
}

impl<ChannelSigner: Sign, C: Deref, T: Deref, F: Deref, L: Deref, P: Deref>
chain::Confirm for ChainMonitor<ChannelSigner, C, T, F, L, P>
where
ChannelSigner: Sign,
C::Target: chain::Filter,
T::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
P::Target: channelmonitor::Persist<ChannelSigner>,
{
fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
self.process_chain_data(header, txdata, |monitor, txdata| {
monitor.transactions_confirmed(
header, txdata, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

fn transaction_unconfirmed(&self, txid: &Txid) {
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
monitor.transaction_unconfirmed(txid, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}

fn best_block_updated(&self, header: &BlockHeader, height: u32) {
self.process_chain_data(header, &[], |monitor, txdata| {
// While in practice there shouldn't be any recursive calls when given empty txdata,
// it's still possible if a chain::Filter implementation returns a transaction.
debug_assert!(txdata.is_empty());
monitor.best_block_updated(
header, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger)
});
}

fn get_relevant_txids(&self) -> Vec<Txid> {
let mut txids = Vec::new();
let monitors = self.monitors.read().unwrap();
for monitor in monitors.values() {
txids.append(&mut monitor.get_relevant_txids());
}

txids.sort_unstable();
txids.dedup();
txids
}
}

Expand Down
47 changes: 29 additions & 18 deletions lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1311,11 +1311,9 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
/// outputs to watch. See [`block_connected`] for details.
///
/// Used instead of [`block_connected`] by clients that are notified of transactions rather than
/// blocks. May be called before or after [`update_best_block`] for transactions in the
/// corresponding block. See [`update_best_block`] for further calling expectations.
/// blocks. See [`chain::Confirm`] for calling expectations.
///
/// [`block_connected`]: Self::block_connected
/// [`update_best_block`]: Self::update_best_block
pub fn transactions_confirmed<B: Deref, F: Deref, L: Deref>(
&self,
header: &BlockHeader,
Expand All @@ -1337,11 +1335,9 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
/// Processes a transaction that was reorganized out of the chain.
///
/// Used instead of [`block_disconnected`] by clients that are notified of transactions rather
/// than blocks. May be called before or after [`update_best_block`] for transactions in the
/// corresponding block. See [`update_best_block`] for further calling expectations.
/// than blocks. See [`chain::Confirm`] for calling expectations.
///
/// [`block_disconnected`]: Self::block_disconnected
/// [`update_best_block`]: Self::update_best_block
pub fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
&self,
txid: &Txid,
Expand All @@ -1361,18 +1357,10 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
/// [`block_connected`] for details.
///
/// Used instead of [`block_connected`] by clients that are notified of transactions rather than
/// blocks. May be called before or after [`transactions_confirmed`] for the corresponding
/// block.
///
/// Must be called after new blocks become available for the most recent block. Intermediary
/// blocks, however, may be safely skipped. In the event of a chain re-organization, this only
/// needs to be called for the most recent block assuming `transaction_unconfirmed` is called
/// for any affected transactions.
/// blocks. See [`chain::Confirm`] for calling expectations.
///
/// [`block_connected`]: Self::block_connected
/// [`transactions_confirmed`]: Self::transactions_confirmed
/// [`transaction_unconfirmed`]: Self::transaction_unconfirmed
pub fn update_best_block<B: Deref, F: Deref, L: Deref>(
pub fn best_block_updated<B: Deref, F: Deref, L: Deref>(
&self,
header: &BlockHeader,
height: u32,
Expand All @@ -1385,7 +1373,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
F::Target: FeeEstimator,
L::Target: Logger,
{
self.inner.lock().unwrap().update_best_block(
self.inner.lock().unwrap().best_block_updated(
header, height, broadcaster, fee_estimator, logger)
}

Expand Down Expand Up @@ -2109,7 +2097,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger)
}

fn update_best_block<B: Deref, F: Deref, L: Deref>(
fn best_block_updated<B: Deref, F: Deref, L: Deref>(
&mut self,
header: &BlockHeader,
height: u32,
Expand Down Expand Up @@ -2727,6 +2715,29 @@ where
}
}

impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Confirm for (ChannelMonitor<Signer>, T, F, L)
where
T::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
{
fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
self.0.transactions_confirmed(header, txdata, height, &*self.1, &*self.2, &*self.3);
}

fn transaction_unconfirmed(&self, txid: &Txid) {
self.0.transaction_unconfirmed(txid, &*self.1, &*self.2, &*self.3);
}

fn best_block_updated(&self, header: &BlockHeader, height: u32) {
self.0.best_block_updated(header, height, &*self.1, &*self.2, &*self.3);
}

fn get_relevant_txids(&self) -> Vec<Txid> {
self.0.get_relevant_txids()
}
}

const MAX_ALLOC_SIZE: usize = 64*1024;

impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
Expand Down
Loading

0 comments on commit 0d75a63

Please sign in to comment.