Some(orig_monitor) => return orig_monitor.insert_combine(monitor),
None => {}
};
- match monitor.funding_txo {
- None => self.chain_monitor.watch_all_txn(),
- Some(outpoint) => self.chain_monitor.install_watch_outpoint((outpoint.txid, outpoint.index as u32)),
+ 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_outpoint((outpoint.txid, outpoint.index as u32), script);
+ },
}
monitors.insert(key, monitor);
Ok(())
const MIN_SERIALIZATION_VERSION: u8 = 1;
pub struct ChannelMonitor {
- funding_txo: Option<OutPoint>,
+ funding_txo: Option<(OutPoint, Script)>,
commitment_transaction_number_obscure_factor: u64,
key_storage: KeyStorage,
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", msg: None})
+ return Err(HandleError{err: "Previous secret did not match new one", action: None})
}
}
self.old_secrets[pos as usize] = (secret, idx);
}
pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), HandleError> {
- match self.funding_txo {
- Some(txo) => if other.funding_txo.is_some() && other.funding_txo.unwrap() != txo {
- return Err(HandleError{err: "Funding transaction outputs are not identical!", msg: None});
- },
- None => if other.funding_txo.is_some() {
- self.funding_txo = other.funding_txo;
+ if self.funding_txo.is_some() {
+ if other.funding_txo.is_some() && other.funding_txo.as_ref().unwrap() != self.funding_txo.as_ref().unwrap() {
+ return Err(HandleError{err: "Funding transaction outputs are not identical!", action: None});
}
+ } else {
+ self.funding_txo = other.funding_txo.take();
}
let other_min_secret = other.get_min_seen_secret();
let our_min_secret = self.get_min_seen_secret();
/// 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.
- pub(super) fn set_funding_info(&mut self, funding_info: OutPoint) {
+ 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 fn get_funding_txo(&self) -> Option<OutPoint> {
- self.funding_txo
+ match self.funding_txo {
+ Some((outpoint, _)) => Some(outpoint),
+ None => None
+ }
}
/// Serializes into a vec, with various modes for the exposed pub fns
res.push(SERIALIZATION_VERSION);
res.push(MIN_SERIALIZATION_VERSION);
- match self.funding_txo {
- Some(outpoint) => {
+ match &self.funding_txo {
+ &Some((ref outpoint, ref script)) => {
res.extend_from_slice(&outpoint.txid[..]);
res.extend_from_slice(&byte_utils::be16_to_array(outpoint.index));
+ res.extend_from_slice(&byte_utils::be64_to_array(script.len() as u64));
+ res.extend_from_slice(&script[..]);
},
- None => {
+ &None => {
// We haven't even been initialized...not sure why anyone is serializing us, but
// not much to give them.
return res;
// Technically this can fail and serialize fail a round-trip, but only for serialization of
// barely-init'd ChannelMonitors that we can't do anything with.
- let funding_txo = Some(OutPoint {
+ let outpoint = OutPoint {
txid: Sha256dHash::from(read_bytes!(32)),
index: byte_utils::slice_to_be16(read_bytes!(2)),
- });
+ };
+ let script_len = byte_utils::slice_to_be64(read_bytes!(8));
+ let funding_txo = Some((outpoint, Script::from(read_bytes!(script_len).to_vec())));
let commitment_transaction_number_obscure_factor = byte_utils::slice_to_be48(read_bytes!(6));
let key_storage = match read_bytes!(1)[0] {
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!());
}
}
assert!(idx < self.get_min_seen_secret());
- Err(HandleError{err: "idx too low", msg: None})
+ Err(HandleError{err: "idx too low", action: None})
}
pub fn get_min_seen_secret(&self) -> u64 {
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 = (((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor;
+ 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));
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 commitment_txid with the ChainWatchInterface!
+ // TODO: Register all outputs in commitment_tx with the ChainWatchInterface!
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
// 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!
self.remote_commitment_txn_on_chain.lock().unwrap().insert(commitment_txid, commitment_number);
if let Some(revocation_points) = self.their_cur_revocation_points {
fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) {
for tx in txn_matched {
for txin in tx.input.iter() {
- if self.funding_txo.is_none() || (txin.prev_hash == self.funding_txo.unwrap().txid && txin.prev_index == self.funding_txo.unwrap().index as u32) {
+ 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 txn.is_empty() {
txn = self.check_spend_local_transaction(tx, height);