+//! The logic to monitor for on-chain transactions and create the relevant claim responses lives
+//! here.
+//! ChannelMonitor objects are generated by ChannelManager in response to relevant
+//! messages/actions, and MUST be persisted to disk (and, preferably, remotely) before progress can
+//! be made in responding to certain messages, see ManyChannelMonitor for more.
+//! Note that ChannelMonitors are an important part of the lightning trust model and a copy of the
+//! latest ChannelMonitor must always be actively monitoring for chain updates (and no out-of-date
+//! 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.
+
use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::transaction::{TxIn,TxOut,SigHashType,Transaction};
+use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
use bitcoin::blockdata::script::Script;
use bitcoin::network::serialize;
use bitcoin::util::hash::Sha256dHash;
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
+use secp256k1;
use ln::msgs::HandleError;
use ln::chan_utils;
use std::sync::{Arc,Mutex};
use std::{hash,cmp};
+/// An error enum representing a failure to persist a channel monitor update.
pub enum ChannelMonitorUpdateErr {
/// Used to indicate a temporary failure (eg connection to a watchtower failed, but is expected
/// to succeed at some point in the future).
/// which we have revoked, allowing our counterparty to claim all funds in the channel!
pub trait ManyChannelMonitor: Send + Sync {
/// Adds or updates a monitor for the given `funding_txo`.
+ /// Implementor must also ensure that the funding_txo outpoint is registered with any relevant
+ /// ChainWatchInterfaces such that the provided monitor receives block_connected callbacks with
+ /// any spends of it.
fn add_update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>;
}
/// If you're using this for local monitoring of your own channels, you probably want to use
/// `OutPoint` as the key, which will give you a ManyChannelMonitor implementation.
pub struct SimpleManyChannelMonitor<Key> {
+ #[cfg(test)] // Used in ChannelManager tests to manipulate channels directly
+ pub monitors: Mutex<HashMap<Key, ChannelMonitor>>,
+ #[cfg(not(test))]
monitors: Mutex<HashMap<Key, ChannelMonitor>>,
chain_monitor: Arc<ChainWatchInterface>,
broadcaster: Arc<BroadcasterInterface>
fn block_connected(&self, _header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) {
let monitors = self.monitors.lock().unwrap();
for monitor in monitors.values() {
- monitor.block_connected(txn_matched, height, &*self.broadcaster);
+ let txn_outputs = monitor.block_connected(txn_matched, height, &*self.broadcaster);
+ for (ref txid, ref outputs) in txn_outputs {
+ for (idx, output) in outputs.iter().enumerate() {
+ self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey);
+ }
+ }
}
}
}
impl<Key : Send + cmp::Eq + hash::Hash + 'static> SimpleManyChannelMonitor<Key> {
+ /// Creates a new object which can be used to monitor several channels given the chain
+ /// interface with which to register to receive notifications.
pub fn new(chain_monitor: Arc<ChainWatchInterface>, broadcaster: Arc<BroadcasterInterface>) -> Arc<SimpleManyChannelMonitor<Key>> {
let res = Arc::new(SimpleManyChannelMonitor {
monitors: Mutex::new(HashMap::new()),
res
}
+ /// 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> {
let mut monitors = self.monitors.lock().unwrap();
match monitors.get_mut(&key) {
match &monitor.funding_txo {
&None => self.chain_monitor.watch_all_txn(),
&Some((ref outpoint, ref script)) => {
- self.chain_monitor.install_watch_script(script);
+ self.chain_monitor.install_watch_tx(&outpoint.txid, script);
self.chain_monitor.install_watch_outpoint((outpoint.txid, outpoint.index as u32), script);
},
}
const SERIALIZATION_VERSION: u8 = 1;
const MIN_SERIALIZATION_VERSION: u8 = 1;
+/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
+/// on-chain transactions to ensure no loss of funds occurs.
+/// You MUST ensure that no ChannelMonitors for a given channel anywhere contain out-of-date
+/// information and are actively monitoring the chain.
pub struct ChannelMonitor {
funding_txo: Option<(OutPoint, Script)>,
commitment_transaction_number_obscure_factor: u64,
key_storage: KeyStorage,
delayed_payment_base_key: PublicKey,
their_htlc_base_key: Option<PublicKey>,
+ their_delayed_payment_base_key: Option<PublicKey>,
// first is the idx of the first of the two revocation points
their_cur_revocation_points: Option<(u64, PublicKey, Option<PublicKey>)>,
payment_preimages: HashMap<[u8; 32], [u8; 32]>,
destination_script: Script,
- secp_ctx: Secp256k1, //TODO: dedup this a bit...
+ secp_ctx: Secp256k1<secp256k1::All>, //TODO: dedup this a bit...
}
impl Clone for ChannelMonitor {
fn clone(&self) -> Self {
key_storage: self.key_storage.clone(),
delayed_payment_base_key: self.delayed_payment_base_key.clone(),
their_htlc_base_key: self.their_htlc_base_key.clone(),
+ their_delayed_payment_base_key: self.their_delayed_payment_base_key.clone(),
their_cur_revocation_points: self.their_cur_revocation_points.clone(),
our_to_self_delay: self.our_to_self_delay,
self.key_storage != other.key_storage ||
self.delayed_payment_base_key != other.delayed_payment_base_key ||
self.their_htlc_base_key != other.their_htlc_base_key ||
+ self.their_delayed_payment_base_key != other.their_delayed_payment_base_key ||
self.their_cur_revocation_points != other.their_cur_revocation_points ||
self.our_to_self_delay != other.our_to_self_delay ||
self.their_to_self_delay != other.their_to_self_delay ||
}
impl ChannelMonitor {
- pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
+ pub(super) fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor {
ChannelMonitor {
funding_txo: None,
commitment_transaction_number_obscure_factor: 0,
},
delayed_payment_base_key: delayed_payment_base_key.clone(),
their_htlc_base_key: None,
+ their_delayed_payment_base_key: None,
their_cur_revocation_points: None,
our_to_self_delay: our_to_self_delay,
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
}
+ /// 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> {
if self.funding_txo.is_some() {
- if other.funding_txo.is_some() && other.funding_txo.as_ref().unwrap() != self.funding_txo.as_ref().unwrap() {
+ // 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});
}
} else {
/// optional, without it this monitor cannot be used in an SPV client, but you may wish to
/// avoid this (or call unset_funding_info) on a monitor you wish to send to a watchtower as it
/// provides slightly better privacy.
+ /// It's the responsibility of the caller to register outpoint and script with passing the former
+ /// value as key to add_update_monitor.
pub(super) fn set_funding_info(&mut self, funding_info: (OutPoint, Script)) {
- //TODO: Need to register the given script here with a chain_monitor
self.funding_txo = Some(funding_info);
}
- pub(super) fn set_their_htlc_base_key(&mut self, their_htlc_base_key: &PublicKey) {
+ /// We log these base keys at channel opening to being able to rebuild redeemscript in case of leaked revoked commit tx
+ pub(super) fn set_their_base_keys(&mut self, their_htlc_base_key: &PublicKey, their_delayed_payment_base_key: &PublicKey) {
self.their_htlc_base_key = Some(their_htlc_base_key.clone());
+ self.their_delayed_payment_base_key = Some(their_delayed_payment_base_key.clone());
}
pub(super) fn set_their_to_self_delay(&mut self, their_to_self_delay: u16) {
self.funding_txo = None;
}
+ /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
pub fn get_funding_txo(&self) -> Option<OutPoint> {
match self.funding_txo {
Some((outpoint, _)) => Some(outpoint),
res.extend_from_slice(&self.delayed_payment_base_key.serialize());
res.extend_from_slice(&self.their_htlc_base_key.as_ref().unwrap().serialize());
+ res.extend_from_slice(&self.their_delayed_payment_base_key.as_ref().unwrap().serialize());
match self.their_cur_revocation_points {
Some((idx, pubkey, second_option)) => {
let delayed_payment_base_key = unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33)));
let their_htlc_base_key = Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))));
+ let their_delayed_payment_base_key = Some(unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))));
let their_cur_revocation_points = {
let first_idx = byte_utils::slice_to_be48(read_bytes!(6));
for _ in 0..remote_claimable_outpoints_len {
let txid = Sha256dHash::from(read_bytes!(32));
let outputs_count = byte_utils::slice_to_be64(read_bytes!(8));
- if outputs_count > data.len() as u64 * 32 { return None; }
+ if outputs_count > data.len() as u64 / 32 { return None; }
let mut outputs = Vec::with_capacity(outputs_count as usize);
for _ in 0..outputs_count {
outputs.push(read_htlc_in_commitment!());
key_storage,
delayed_payment_base_key,
their_htlc_base_key,
+ their_delayed_payment_base_key,
their_cur_revocation_points,
our_to_self_delay,
//we want to leave out (eg funding_txo, etc).
/// Can only fail if idx is < get_min_seen_secret
- pub fn get_secret(&self, idx: u64) -> Result<[u8; 32], HandleError> {
+ pub(super) fn get_secret(&self, idx: u64) -> Result<[u8; 32], HandleError> {
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))
Err(HandleError{err: "idx too low", action: None})
}
- pub fn get_min_seen_secret(&self) -> u64 {
+ pub(super) fn get_min_seen_secret(&self) -> u64 {
//TODO This can be optimized?
let mut min = 1 << 48;
for &(_, idx) in self.old_secrets.iter() {
/// Attempts to claim a remote commitment transaction's outputs using the revocation key and
/// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a
/// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
- /// HTLC-Success/HTLC-Timeout transactions, and claim them using the revocation key (if
- /// applicable) as well.
- fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> Vec<Transaction> {
+ /// HTLC-Success/HTLC-Timeout transactions.
+ fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>)) {
// Most secp and related errors trying to create keys means we have no hope of constructing
// a spend transaction...so we return no transactions to broadcast
let mut txn_to_broadcast = Vec::new();
+ let mut watch_outputs = Vec::new();
+
+ let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
+ let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
+
macro_rules! ignore_error {
( $thing : expr ) => {
match $thing {
Ok(a) => a,
- Err(_) => return txn_to_broadcast
+ Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs))
}
};
}
- let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
- let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid);
-
let commitment_number = 0xffffffffffff - ((((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor);
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 per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key));
- (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))),
- ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &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, &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))))
},
KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => {
- let per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_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)))
},
};
- let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &self.delayed_payment_base_key));
+ let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.delayed_payment_base_key));
let a_htlc_key = match self.their_htlc_base_key {
- None => return txn_to_broadcast,
- Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &their_htlc_base_key)),
+ None => return (txn_to_broadcast, (commitment_txid, watch_outputs)),
+ Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &their_htlc_base_key)),
};
let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key);
for (idx, outp) in tx.output.iter().enumerate() {
if outp.script_pubkey == revokeable_p2wsh {
inputs.push(TxIn {
- prev_hash: commitment_txid,
- prev_index: idx as u32,
+ previous_output: BitcoinOutPoint {
+ txid: commitment_txid,
+ vout: idx as u32,
+ },
script_sig: Script::new(),
sequence: 0xfffffffd,
witness: Vec::new(),
};
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
- (ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key)), redeemscript)
+ (self.secp_ctx.sign(&sighash, &revocation_key), redeemscript)
},
KeyStorage::SigsMode { .. } => {
unimplemented!();
} else {
$input.witness.push(revocation_pubkey.serialize().to_vec());
}
- $input.witness.push(redeemscript.into_vec());
+ $input.witness.push(redeemscript.into_bytes());
}
}
}
if htlc.transaction_output_index as usize >= tx.output.len() ||
tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 ||
tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() {
- return txn_to_broadcast; // Corrupted per_commitment_data, fuck this user
+ return (txn_to_broadcast, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
}
let input = TxIn {
- prev_hash: commitment_txid,
- prev_index: htlc.transaction_output_index,
+ previous_output: BitcoinOutPoint {
+ txid: commitment_txid,
+ vout: htlc.transaction_output_index,
+ },
script_sig: Script::new(),
sequence: 0xfffffffd,
witness: Vec::new(),
if !inputs.is_empty() || !txn_to_broadcast.is_empty() { // ie we're confident this is actually ours
// We're definitely a remote commitment transaction!
- // TODO: Register all outputs in commitment_tx with the ChainWatchInterface!
+ watch_outputs.append(&mut tx.output.clone());
self.remote_commitment_txn_on_chain.lock().unwrap().insert(commitment_txid, commitment_number);
}
- if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx
+ if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs)); } // Nothing to be done...probably a false positive/local tx
let outputs = vec!(TxOut {
script_pubkey: self.destination_script.clone(),
// already processed the block, resulting in the remote_commitment_txn_on_chain entry
// not being generated by the above conditional. Thus, to be safe, we go ahead and
// insert it here.
- // TODO: Register all outputs in commitment_tx with the ChainWatchInterface!
+ watch_outputs.append(&mut tx.output.clone());
self.remote_commitment_txn_on_chain.lock().unwrap().insert(commitment_txid, commitment_number);
if let Some(revocation_points) = self.their_cur_revocation_points {
if let Some(revocation_point) = revocation_point_option {
let (revocation_pubkey, b_htlc_key) = match self.key_storage {
KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => {
- (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))),
- ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key)))))
+ (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key))),
+ ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))
},
KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => {
(ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &revocation_base_key)),
},
};
let a_htlc_key = match self.their_htlc_base_key {
- None => return txn_to_broadcast,
+ None => return (txn_to_broadcast, (commitment_txid, watch_outputs)),
Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)),
};
let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]));
let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
- (ignore_error!(self.secp_ctx.sign(&sighash, &htlc_key)), redeemscript)
+ (self.secp_ctx.sign(&sighash, &htlc_key), redeemscript)
},
KeyStorage::SigsMode { .. } => {
unimplemented!();
$input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
$input.witness[0].push(SigHashType::All as u8);
$input.witness.push($preimage);
- $input.witness.push(redeemscript.into_vec());
+ $input.witness.push(redeemscript.into_bytes());
}
}
}
for (idx, htlc) in per_commitment_data.iter().enumerate() {
if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) {
let input = TxIn {
- prev_hash: commitment_txid,
- prev_index: htlc.transaction_output_index,
+ previous_output: BitcoinOutPoint {
+ txid: commitment_txid,
+ vout: htlc.transaction_output_index,
+ },
script_sig: Script::new(),
sequence: idx as u32, // reset to 0xfffffffd in sign_input
witness: Vec::new(),
}
}
- if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx
+ if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs)); } // Nothing to be done...probably a false positive/local tx
let outputs = vec!(TxOut {
script_pubkey: self.destination_script.clone(),
txn_to_broadcast.push(spend_tx);
}
}
- } else {
- //TODO: For each input check if its in our remote_commitment_txn_on_chain map!
}
- txn_to_broadcast
+ (txn_to_broadcast, (commitment_txid, watch_outputs))
+ }
+
+ /// Attempst to claim a remote HTLC-Success/HTLC-Timeout s outputs using the revocation key
+ fn check_spend_remote_htlc(&self, tx: &Transaction, commitment_number: u64) -> Option<Transaction> {
+ let htlc_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
+
+ macro_rules! ignore_error {
+ ( $thing : expr ) => {
+ match $thing {
+ Ok(a) => a,
+ Err(_) => return None
+ }
+ };
+ }
+
+ let secret = ignore_error!(self.get_secret(commitment_number));
+ 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 {
+ KeyStorage::PrivMode { ref revocation_base_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)))
+ },
+ KeyStorage::SigsMode { ref revocation_base_key, .. } => {
+ ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &revocation_base_key))
+ },
+ };
+ let delayed_key = match self.their_delayed_payment_base_key {
+ None => return None,
+ Some(their_delayed_payment_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &their_delayed_payment_base_key)),
+ };
+ let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.their_to_self_delay.unwrap(), &delayed_key);
+ let revokeable_p2wsh = redeemscript.to_v0_p2wsh();
+
+ let mut inputs = Vec::new();
+ let mut amount = 0;
+
+ if tx.output[0].script_pubkey == revokeable_p2wsh { //HTLC transactions have one txin, one txout
+ inputs.push(TxIn {
+ previous_output: BitcoinOutPoint {
+ txid: htlc_txid,
+ vout: 0,
+ },
+ script_sig: Script::new(),
+ sequence: 0xfffffffd,
+ witness: Vec::new(),
+ });
+ amount = tx.output[0].value;
+ }
+
+ if !inputs.is_empty() {
+ let outputs = vec!(TxOut {
+ script_pubkey: self.destination_script.clone(),
+ value: amount, //TODO: - fee
+ });
+
+ let mut spend_tx = Transaction {
+ version: 2,
+ lock_time: 0,
+ input: inputs,
+ output: outputs,
+ };
+
+ let sighash_parts = bip143::SighashComponents::new(&spend_tx);
+
+ let sig = match self.key_storage {
+ KeyStorage::PrivMode { ref revocation_base_key, .. } => {
+ let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&spend_tx.input[0], &redeemscript, amount)[..]));
+ let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
+ self.secp_ctx.sign(&sighash, &revocation_key)
+ }
+ KeyStorage::SigsMode { .. } => {
+ unimplemented!();
+ }
+ };
+ spend_tx.input[0].witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
+ spend_tx.input[0].witness[0].push(SigHashType::All as u8);
+ spend_tx.input[0].witness.push(vec!(1));
+ spend_tx.input[0].witness.push(redeemscript.into_bytes());
+
+ Some(spend_tx)
+ } else { None }
}
fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> Vec<Transaction> {
htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_timeout_tx.input[0].witness.push(Vec::new());
- htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_vec());
+ htlc_timeout_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
res.push(htlc_timeout_tx);
} else {
htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8);
htlc_success_tx.input[0].witness.push(payment_preimage.to_vec());
- htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_vec());
+ htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes());
res.push(htlc_success_tx);
}
Vec::new()
}
- fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) {
+ fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> Vec<(Sha256dHash, Vec<TxOut>)> {
+ let mut watch_outputs = Vec::new();
for tx in txn_matched {
- for txin in tx.input.iter() {
- if self.funding_txo.is_none() || (txin.prev_hash == self.funding_txo.as_ref().unwrap().0.txid && txin.prev_index == self.funding_txo.as_ref().unwrap().0.index as u32) {
- let mut txn = self.check_spend_remote_transaction(tx, height);
+ if tx.input.len() == 1 {
+ // Assuming our keys were not leaked (in which case we're screwed no matter what),
+ // commitment transactions and HTLC transactions will all only ever have one input,
+ // which is an easy way to filter out any potential non-matching txn for lazy
+ // filters.
+ let prevout = &tx.input[0].previous_output;
+ let mut txn: Vec<Transaction> = Vec::new();
+ if self.funding_txo.is_none() || (prevout.txid == self.funding_txo.as_ref().unwrap().0.txid && prevout.vout == self.funding_txo.as_ref().unwrap().0.index as u32) {
+ let (remote_txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
+ txn = remote_txn;
+ if !new_outputs.1.is_empty() {
+ watch_outputs.push(new_outputs);
+ }
if txn.is_empty() {
txn = self.check_spend_local_transaction(tx, height);
}
- for tx in txn.iter() {
- broadcaster.broadcast_transaction(tx);
+ } else {
+ let remote_commitment_txn_on_chain = self.remote_commitment_txn_on_chain.lock().unwrap();
+ if let Some(commitment_number) = remote_commitment_txn_on_chain.get(&prevout.txid) {
+ if let Some(tx) = self.check_spend_remote_htlc(tx, *commitment_number) {
+ txn.push(tx);
+ }
}
}
+ for tx in txn.iter() {
+ broadcaster.broadcast_transaction(tx);
+ }
}
}
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
}
}
}
+ watch_outputs
}
- pub fn would_broadcast_at_height(&self, height: u32) -> bool {
+ pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool {
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {
for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() {
if htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER {
#[cfg(test)]
mod tests {
- use bitcoin::util::misc::hex_bytes;
use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use crypto::digest::Digest;
+ use hex;
use ln::channelmonitor::ChannelMonitor;
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
use util::sha2::Sha256;
};
}
+ let delayed_payment_base_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
+
{
// insert_secret correct sequence
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
}
{
// insert_secret #1 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #2 incorrect (#1 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #3 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #4 incorrect (1,2,3 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #5 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #6 incorrect (5 derived from incorrect)
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1").unwrap());
monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #7 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3").unwrap());
monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap());
assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
{
// insert_secret #8 incorrect
- monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
secrets.clear();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap());
monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap());
monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap());
monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap();
test_secrets!();
secrets.push([0; 32]);
- secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap());
+ secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex::decode("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap());
assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err,
"Previous secret did not match new one");
}
#[test]
fn test_prune_preimages() {
let secp_ctx = Secp256k1::new();
- let dummy_sig = Signature::from_der(&secp_ctx, &hex_bytes("3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd").unwrap()[..]).unwrap();
+ let dummy_sig = Signature::from_der(&secp_ctx, &hex::decode("3045022100fa86fa9a36a8cd6a7bb8f06a541787d51371d067951a9461d5404de6b928782e02201c8b7c334c10aed8976a3a465be9a28abff4cb23acbf00022295b378ce1fa3cd").unwrap()[..]).unwrap();
macro_rules! dummy_keys {
() => {
- TxCreationKeys {
- per_commitment_point: PublicKey::new(),
- revocation_key: PublicKey::new(),
- a_htlc_key: PublicKey::new(),
- b_htlc_key: PublicKey::new(),
- a_delayed_payment_key: PublicKey::new(),
- b_payment_key: PublicKey::new(),
+ {
+ 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(),
+ a_htlc_key: dummy_key.clone(),
+ b_htlc_key: dummy_key.clone(),
+ a_delayed_payment_key: dummy_key.clone(),
+ b_payment_key: dummy_key.clone(),
+ }
}
}
}
// Prune with one old state and a local commitment tx holding a few overlaps with the
// old state.
- let mut monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
+ let delayed_payment_base_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap());
+ let mut monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &delayed_payment_base_key, &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new());
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]));
// Now provide a secret, pruning preimages 10-15
let mut secret = [0; 32];
- secret[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
+ secret[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secret.clone(), None).unwrap();
assert_eq!(monitor.payment_preimages.len(), 15);
test_preimages_exist!(&preimages[0..10], monitor);
test_preimages_exist!(&preimages[15..20], monitor);
// Now provide a further secret, pruning preimages 15-17
- secret[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
+ secret[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secret.clone(), None).unwrap();
assert_eq!(monitor.payment_preimages.len(), 13);
test_preimages_exist!(&preimages[0..10], monitor);
// Now update local commitment tx info, pruning only element 18 as we still care about the
// previous commitment tx's preimages too
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..5]));
- secret[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
+ secret[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secret.clone(), None).unwrap();
assert_eq!(monitor.payment_preimages.len(), 12);
test_preimages_exist!(&preimages[0..10], monitor);
// But if we do it again, we'll prune 5-10
monitor.provide_latest_local_commitment_tx_info(dummy_tx.clone(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..3]));
- secret[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
+ secret[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secret.clone(), None).unwrap();
assert_eq!(monitor.payment_preimages.len(), 5);
test_preimages_exist!(&preimages[0..5], monitor);