/// Provides an outpoint which must be watched for, providing any transactions which spend the
/// given outpoint.
- fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32));
+ fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32), out_script: &Script);
/// Indicates that a listener needs to see all transactions.
fn watch_all_txn(&self);
self.reentered.fetch_add(1, Ordering::Relaxed);
}
- fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32)) {
+ fn install_watch_outpoint(&self, outpoint: (Sha256dHash, u32), _out_script: &Script) {
let mut watched = self.watched.lock().unwrap();
watched.1.push(outpoint);
self.reentered.fetch_add(1, Ordering::Relaxed);
self.does_match_tx_unguarded (tx, &watched)
}
- fn does_match_tx_unguarded (&self, tx: &Transaction, watched: &MutexGuard<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>) -> bool {
+ fn does_match_tx_unguarded(&self, tx: &Transaction, watched: &MutexGuard<(Vec<Script>, Vec<(Sha256dHash, u32)>, bool)>) -> bool {
if watched.2 {
return true;
}
}
let funding_txo = OutPoint::new(msg.funding_txid, msg.funding_output_index);
- self.channel_monitor.set_funding_info(funding_txo);
+ let funding_txo_script = self.get_funding_redeemscript().to_v0_p2wsh();
+ self.channel_monitor.set_funding_info((funding_txo, funding_txo_script));
let (remote_initial_commitment_tx, our_signature) = match self.funding_created_signature(&msg.signature) {
Ok(res) => res,
panic!("Should not have advanced channel commitment tx numbers prior to funding_created");
}
- self.channel_monitor.set_funding_info(funding_txo);
+ let funding_txo_script = self.get_funding_redeemscript().to_v0_p2wsh();
+ self.channel_monitor.set_funding_info((funding_txo, funding_txo_script));
let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() {
Ok(res) => res,
use bitcoin::util::hash::Sha256dHash;
use bitcoin::util::bip143;
use bitcoin::network::serialize::serialize;
+ use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use ln::channel::{Channel,ChannelKeys,HTLCOutput,HTLCState,HTLCOutputInCommitment,TxCreationKeys};
use ln::channel::MAX_FUNDING_SATOSHIS;
chan.our_dust_limit_satoshis = 546;
let funding_info = OutPoint::new(Sha256dHash::from_hex("8984484a580b825b9972d7adb15050b3ab624ccd731946b3eeddb92f4e7ef6be").unwrap(), 0);
- chan.channel_monitor.set_funding_info(funding_info);
+ chan.channel_monitor.set_funding_info((funding_info, Script::new()));
chan.their_payment_basepoint = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &hex_bytes("4444444444444444444444444444444444444444444444444444444444444444").unwrap()[..]).unwrap()).unwrap();
assert_eq!(chan.their_payment_basepoint.serialize()[..],
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_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,
}
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 {
+ 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!", msg: None});
- },
- None => if other.funding_txo.is_some() {
- self.funding_txo = other.funding_txo;
}
+ } 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] {
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);