use secp256k1::key::{SecretKey,PublicKey};
use secp256k1;
-use ln::msgs::{DecodeError, HandleError};
+use ln::msgs::DecodeError;
use ln::chan_utils;
use ln::chan_utils::HTLCOutputInCommitment;
use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface};
PermanentFailure,
}
+/// General Err type for ChannelMonitor actions. Generally, this implies that the data provided is
+/// inconsistent with the ChannelMonitor being called. eg for ChannelMonitor::insert_combine this
+/// means you tried to merge two monitors for different channels or for a channel which was
+/// restored from a backup and then generated new commitment updates.
+/// Contains a human-readable error message.
+#[derive(Debug)]
+pub struct MonitorUpdateError(pub &'static str);
+
/// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between
/// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing
/// events to it, while also taking any add_update_monitor events and passing them to some remote
}
/// Adds or udpates the monitor which monitors the channel referred to by the given key.
- pub fn add_update_monitor_by_key(&self, key: Key, monitor: ChannelMonitor) -> Result<(), HandleError> {
+ pub fn add_update_monitor_by_key(&self, key: Key, monitor: ChannelMonitor) -> Result<(), MonitorUpdateError> {
let mut monitors = self.monitors.lock().unwrap();
match monitors.get_mut(&key) {
Some(orig_monitor) => {
/// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither
/// needed by local commitment transactions HTCLs nor by remote ones. Unless we haven't already seen remote
/// commitment transaction's secret, they are de facto pruned (we can use revocation key).
- pub(super) fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), HandleError> {
+ pub(super) fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> {
let pos = ChannelMonitor::place_secret(idx);
for i in 0..pos {
let (old_secret, old_idx) = self.old_secrets[i as usize];
if ChannelMonitor::derive_secret(secret, pos, old_idx) != old_secret {
- return Err(HandleError{err: "Previous secret did not match new one", action: None})
+ return Err(MonitorUpdateError("Previous secret did not match new one"));
}
}
self.old_secrets[pos as usize] = (secret, idx);
Ok(())
}
- /// Tracks the next revocation point which may be required to claim HTLC outputs which we know
- /// the preimage of in case the remote end force-closes using their latest state. When called at
- /// channel opening revocation point is the CURRENT one used for first commitment tx. Needed in case of sizeable push_msat.
- pub(super) fn provide_their_next_revocation_point(&mut self, their_next_revocation_point: Option<(u64, PublicKey)>) {
- if let Some(new_revocation_point) = their_next_revocation_point {
- match self.their_cur_revocation_points {
- Some(old_points) => {
- if old_points.0 == new_revocation_point.0 + 1 {
- self.their_cur_revocation_points = Some((old_points.0, old_points.1, Some(new_revocation_point.1)));
- } else if old_points.0 == new_revocation_point.0 + 2 {
- if let Some(old_second_point) = old_points.2 {
- self.their_cur_revocation_points = Some((old_points.0 - 1, old_second_point, Some(new_revocation_point.1)));
- } else {
- self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
- }
- } else {
- self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
- }
- },
- None => {
- self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None));
- }
- }
- }
- }
-
/// Informs this monitor of the latest remote (ie non-broadcastable) commitment transaction.
/// The monitor watches for it to be broadcasted and then uses the HTLC information (and
/// possibly future revocation/preimage information) to claim outputs where possible.
/// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
- pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<HTLCOutputInCommitment>, commitment_number: u64) {
+ pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<HTLCOutputInCommitment>, commitment_number: u64, their_revocation_point: PublicKey) {
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
// so that a remote monitor doesn't learn anything unless there is a malicious close.
// (only maybe, sadly we cant do the same for local info, as we need to be aware of
}
self.remote_claimable_outpoints.insert(unsigned_commitment_tx.txid(), htlc_outputs);
self.current_remote_commitment_number = commitment_number;
+ //TODO: Merge this into the other per-remote-transaction output storage stuff
+ match self.their_cur_revocation_points {
+ Some(old_points) => {
+ if old_points.0 == commitment_number + 1 {
+ self.their_cur_revocation_points = Some((old_points.0, old_points.1, Some(their_revocation_point)));
+ } else if old_points.0 == commitment_number + 2 {
+ if let Some(old_second_point) = old_points.2 {
+ self.their_cur_revocation_points = Some((old_points.0 - 1, old_second_point, Some(their_revocation_point)));
+ } else {
+ self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None));
+ }
+ } else {
+ self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None));
+ }
+ },
+ None => {
+ self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None));
+ }
+ }
}
/// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The
/// Combines this ChannelMonitor with the information contained in the other ChannelMonitor.
/// After a successful call this ChannelMonitor is up-to-date and is safe to use to monitor the
/// chain for new blocks/transactions.
- pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), HandleError> {
+ pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), MonitorUpdateError> {
if self.funding_txo.is_some() {
// We should be able to compare the entire funding_txo, but in fuzztarget its trivially
// easy to collide the funding_txo hash and have a different scriptPubKey.
if other.funding_txo.is_some() && other.funding_txo.as_ref().unwrap().0 != self.funding_txo.as_ref().unwrap().0 {
- return Err(HandleError{err: "Funding transaction outputs are not identical!", action: None});
+ return Err(MonitorUpdateError("Funding transaction outputs are not identical!"));
}
} else {
self.funding_txo = other.funding_txo.take();
//we want to leave out (eg funding_txo, etc).
/// Can only fail if idx is < get_min_seen_secret
- pub(super) fn get_secret(&self, idx: u64) -> Result<[u8; 32], HandleError> {
+ pub(super) fn get_secret(&self, idx: u64) -> Option<[u8; 32]> {
for i in 0..self.old_secrets.len() {
if (idx & (!((1 << i) - 1))) == self.old_secrets[i].1 {
- return Ok(ChannelMonitor::derive_secret(self.old_secrets[i].0, i as u8, idx))
+ return Some(ChannelMonitor::derive_secret(self.old_secrets[i].0, i as u8, idx))
}
}
assert!(idx < self.get_min_seen_secret());
- Err(HandleError{err: "idx too low", action: None})
+ None
}
pub(super) fn get_min_seen_secret(&self) -> u64 {
if commitment_number >= self.get_min_seen_secret() {
let secret = self.get_secret(commitment_number).unwrap();
let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));
- let (revocation_pubkey, b_htlc_key) = match self.key_storage {
- KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, .. } => {
+ let (revocation_pubkey, b_htlc_key, local_payment_key) = match self.key_storage {
+ KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key, ref payment_base_key, .. } => {
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
(ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key))),
- ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))),
+ Some(ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, &per_commitment_point, &payment_base_key))))
},
KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => {
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
(ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &revocation_base_key)),
- ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &htlc_base_key)))
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &htlc_base_key)),
+ None)
},
};
let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key.unwrap()));
let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key);
let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh();
+ let local_payment_p2wpkh = if let Some(payment_key) = local_payment_key {
+ // Note that the Network here is ignored as we immediately drop the address for the
+ // script_pubkey version.
+ let payment_hash160 = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &payment_key).serialize());
+ Some(Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script())
+ } else { None };
+
let mut total_value = 0;
let mut values = Vec::new();
let mut inputs = Vec::new();
htlc_idxs.push(None);
values.push(outp.value);
total_value += outp.value;
- } else if outp.script_pubkey.is_v0_p2wpkh() {
- match self.key_storage {
- KeyStorage::PrivMode { ref payment_base_key, .. } => {
- let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
- if let Ok(local_key) = chan_utils::derive_private_key(&self.secp_ctx, &per_commitment_point, &payment_base_key) {
- spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WPKH {
- outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 },
- key: local_key,
- output: outp.clone(),
- });
- }
- }
- KeyStorage::SigsMode { .. } => {
- //TODO: we need to ensure an offline client will generate the event when it
- // cames back online after only the watchtower saw the transaction
- }
- }
+ } else if Some(&outp.script_pubkey) == local_payment_p2wpkh.as_ref() {
+ spendable_outputs.push(SpendableOutputDescriptor::DynamicOutputP2WPKH {
+ outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 },
+ key: local_payment_key.unwrap(),
+ output: outp.clone(),
+ });
}
}
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
};
-
for (idx, outp) in tx.output.iter().enumerate() {
if outp.script_pubkey.is_v0_p2wpkh() {
match self.key_storage {
output: outp.clone(),
});
}
- }
- KeyStorage::SigsMode { .. } => {
- //TODO: we need to ensure an offline client will generate the event when it
- // cames back online after only the watchtower saw the transaction
- }
+ },
+ KeyStorage::SigsMode { .. } => {}
}
break; // Only to_remote ouput is claimable
}
};
}
- let secret = ignore_error!(self.get_secret(commitment_number));
+ let secret = if let Some(secret) = self.get_secret(commitment_number) { secret } else { return (None, None); };
let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
let revocation_pubkey = match self.key_storage {
/// Generate a spendable output event when closing_transaction get registered onchain.
fn check_spend_closing_transaction(&self, tx: &Transaction) -> Option<SpendableOutputDescriptor> {
- if tx.input[0].sequence == 0xFFFFFFFF && tx.input[0].witness.last().unwrap().len() == 71 {
+ if tx.input[0].sequence == 0xFFFFFFFF && !tx.input[0].witness.is_empty() && tx.input[0].witness.last().unwrap().len() == 71 {
match self.key_storage {
KeyStorage::PrivMode { ref shutdown_pubkey, .. } => {
let our_channel_close_key_hash = Hash160::from_data(&shutdown_pubkey.serialize());
idx -= 1;
}
assert_eq!(monitor.get_min_seen_secret(), idx + 1);
- assert!(monitor.get_secret(idx).is_err());
+ assert!(monitor.get_secret(idx).is_none());
};
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
- assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
- assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
- assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
secrets.push([0; 32]);
secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap());
- assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err,
+ assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().0,
"Previous secret did not match new one");
}
}
let logger = Arc::new(TestLogger::new());
let dummy_sig = Signature::from_der(&secp_ctx, &hex::decode("3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd").unwrap()[..]).unwrap();
+ let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
macro_rules! dummy_keys {
() => {
{
- let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
TxCreationKeys {
per_commitment_point: dummy_key.clone(),
revocation_key: dummy_key.clone(),
monitor.set_their_to_self_delay(10);
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..10]));
- monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655);
- monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654);
- monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653);
- monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652);
+ monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key);
+ monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key);
+ monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key);
+ monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key);
for &(ref preimage, ref hash) in preimages.iter() {
monitor.provide_payment_preimage(hash, preimage);
}