use bitcoin::consensus::encode;
use bitcoin::util::hash::BitcoinHash;
-use bitcoin_hashes::Hash;
-use bitcoin_hashes::sha256::Hash as Sha256;
-use bitcoin_hashes::hash160::Hash as Hash160;
-use bitcoin_hashes::sha256d::Hash as Sha256dHash;
+use bitcoin::hashes::Hash;
+use bitcoin::hashes::sha256::Hash as Sha256;
+use bitcoin::hashes::hash160::Hash as Hash160;
+use bitcoin::hash_types::{Txid, BlockHash};
-use secp256k1::{Secp256k1,Signature};
-use secp256k1::key::{SecretKey,PublicKey};
-use secp256k1;
+use bitcoin::secp256k1::{Secp256k1,Signature};
+use bitcoin::secp256k1::key::{SecretKey,PublicKey};
+use bitcoin::secp256k1;
use ln::msgs::DecodeError;
use ln::chan_utils;
#[derive(Clone, PartialEq)]
struct LocalSignedTx {
/// txid of the transaction in tx, just used to make comparison faster
- txid: Sha256dHash,
+ txid: Txid,
revocation_key: PublicKey,
a_htlc_key: PublicKey,
b_htlc_key: PublicKey,
preimage: Option<PaymentPreimage>,
amount: u64,
},
- Funding {}
+ Funding {
+ funding_redeemscript: Script,
+ }
}
impl Writeable for InputMaterial {
preimage.write(writer)?;
writer.write_all(&byte_utils::be64_to_array(*amount))?;
},
- &InputMaterial::Funding {} => {
+ &InputMaterial::Funding { ref funding_redeemscript } => {
writer.write_all(&[3; 1])?;
+ funding_redeemscript.write(writer)?;
}
}
Ok(())
}
},
3 => {
- InputMaterial::Funding {}
+ InputMaterial::Funding {
+ funding_redeemscript: Readable::read(reader)?,
+ }
}
_ => return Err(DecodeError::InvalidValue),
};
keys: ChanSigner,
funding_info: (OutPoint, Script),
- current_remote_commitment_txid: Option<Sha256dHash>,
- prev_remote_commitment_txid: Option<Sha256dHash>,
+ current_remote_commitment_txid: Option<Txid>,
+ prev_remote_commitment_txid: Option<Txid>,
their_htlc_base_key: PublicKey,
their_delayed_payment_base_key: PublicKey,
their_to_self_delay: u16,
commitment_secrets: CounterpartyCommitmentSecrets,
- remote_claimable_outpoints: HashMap<Sha256dHash, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
+ remote_claimable_outpoints: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
/// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain.
/// Nor can we figure out their commitment numbers without the commitment transaction they are
/// spending. Thus, in order to claim them via revocation key, we track all the remote
/// commitment transactions which we find on-chain, mapping them to the commitment number which
/// can be used to derive the revocation key and claim the transactions.
- remote_commitment_txn_on_chain: HashMap<Sha256dHash, (u64, Vec<Script>)>,
+ remote_commitment_txn_on_chain: HashMap<Txid, (u64, Vec<Script>)>,
/// Cache used to make pruning of payment_preimages faster.
/// Maps payment_hash values to commitment numbers for remote transactions for non-revoked
/// remote transactions (ie should remain pretty small).
// interface knows about the TXOs that we want to be notified of spends of. We could probably
// be smart and derive them from the above storage fields, but its much simpler and more
// Obviously Correct (tm) if we just keep track of them explicitly.
- outputs_to_watch: HashMap<Sha256dHash, Vec<Script>>,
+ outputs_to_watch: HashMap<Txid, Vec<Script>>,
#[cfg(test)]
pub onchain_tx_handler: OnchainTxHandler<ChanSigner>,
#[cfg(not(test))]
onchain_tx_handler: OnchainTxHandler<ChanSigner>,
- // Used to detect programming bug due to unsafe monitor update sequence { ChannelForceClosed, LatestLocalCommitmentTXInfo }
+ // This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the
+ // channel has been force-closed. After this is set, no further local commitment transaction
+ // updates may occur, and we panic!() if one is provided.
lockdown_from_offchain: bool,
+ // Set once we've signed a local commitment transaction and handed it over to our
+ // OnchainTxHandler. After this is set, no future updates to our local commitment transactions
+ // may occur, and we fail any such monitor updates.
+ local_tx_signed: bool,
+
// We simply modify last_block_hash in Channel's block_connected so that serialization is
// consistent but hopefully the users' copy handles block_connected in a consistent way.
// (we do *not*, however, update them in update_monitor to ensure any local user copies keep
// their last_block_hash from its state and not based on updated copies that didn't run through
// the full block_connected).
- pub(crate) last_block_hash: Sha256dHash,
+ pub(crate) last_block_hash: BlockHash,
secp_ctx: Secp256k1<secp256k1::All>, //TODO: dedup this a bit...
logger: Arc<Logger>,
}
self.pending_htlcs_updated != other.pending_htlcs_updated ||
self.pending_events.len() != other.pending_events.len() || // We trust events to round-trip properly
self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf ||
- self.outputs_to_watch != other.outputs_to_watch
+ self.outputs_to_watch != other.outputs_to_watch ||
+ self.lockdown_from_offchain != other.lockdown_from_offchain ||
+ self.local_tx_signed != other.local_tx_signed
{
false
} else {
self.onchain_tx_handler.write(writer)?;
self.lockdown_from_offchain.write(writer)?;
+ self.local_tx_signed.write(writer)?;
Ok(())
}
let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay, logger.clone());
- let local_tx_sequence = initial_local_commitment_tx.without_valid_witness().input[0].sequence as u64;
- let local_tx_locktime = initial_local_commitment_tx.without_valid_witness().lock_time as u64;
+ let local_tx_sequence = initial_local_commitment_tx.unsigned_tx.input[0].sequence as u64;
+ let local_tx_locktime = initial_local_commitment_tx.unsigned_tx.lock_time as u64;
let local_commitment_tx = LocalSignedTx {
txid: initial_local_commitment_tx.txid(),
revocation_key: initial_local_commitment_tx.local_keys.revocation_key,
onchain_tx_handler,
lockdown_from_offchain: false,
+ local_tx_signed: false,
last_block_hash: Default::default(),
secp_ctx: Secp256k1::new(),
/// up-to-date as our local commitment transaction is updated.
/// Panics if set_their_to_self_delay has never been called.
pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>) -> Result<(), MonitorUpdateError> {
+ if self.local_tx_signed {
+ return Err(MonitorUpdateError("A local commitment tx has already been signed, no new local commitment txn can be sent to our counterparty"));
+ }
let txid = commitment_tx.txid();
- let sequence = commitment_tx.without_valid_witness().input[0].sequence as u64;
- let locktime = commitment_tx.without_valid_witness().lock_time as u64;
+ let sequence = commitment_tx.unsigned_tx.input[0].sequence as u64;
+ let locktime = commitment_tx.unsigned_tx.lock_time as u64;
let mut new_local_commitment_tx = LocalSignedTx {
txid,
revocation_key: commitment_tx.local_keys.revocation_key,
/// Gets a list of txids, with their output scripts (in the order they appear in the
/// transaction), which we must learn about spends of via block_connected().
- pub fn get_outputs_to_watch(&self) -> &HashMap<Sha256dHash, Vec<Script>> {
+ pub fn get_outputs_to_watch(&self) -> &HashMap<Txid, Vec<Script>> {
&self.outputs_to_watch
}
/// Generally useful when deserializing as during normal operation the return values of
/// block_connected are sufficient to ensure all relevant outpoints are being monitored (note
/// that the get_funding_txo outpoint and transaction must also be monitored for!).
- pub fn get_monitored_outpoints(&self) -> Vec<(Sha256dHash, u32, &Script)> {
+ pub fn get_monitored_outpoints(&self) -> Vec<(Txid, u32, &Script)> {
let mut res = Vec::with_capacity(self.remote_commitment_txn_on_chain.len() * 2);
for (ref txid, &(_, ref outputs)) in self.remote_commitment_txn_on_chain.iter() {
for (idx, output) in outputs.iter().enumerate() {
/// HTLC-Success/HTLC-Timeout transactions.
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
/// revoked remote commitment tx
- fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<ClaimRequest>, (Sha256dHash, Vec<TxOut>)) {
+ fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<ClaimRequest>, (Txid, 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 claimable_outpoints = Vec::new();
}
/// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key
- fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> (Vec<ClaimRequest>, Option<(Sha256dHash, Vec<TxOut>)>) {
+ fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> (Vec<ClaimRequest>, Option<(Txid, Vec<TxOut>)>) {
let htlc_txid = tx.txid();
if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 {
return (Vec::new(), None)
for &(ref htlc, _, _) in local_tx.htlc_outputs.iter() {
if let Some(transaction_output_index) = htlc.transaction_output_index {
- let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) { Some(*preimage) } else { None };
- claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: local_tx.txid, vout: transaction_output_index as u32 }, witness_data: InputMaterial::LocalHTLC { preimage, amount: htlc.amount_msat / 1000 }});
+ claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: local_tx.txid, vout: transaction_output_index as u32 },
+ witness_data: InputMaterial::LocalHTLC {
+ preimage: if !htlc.offered {
+ if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) {
+ Some(preimage.clone())
+ } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
+ }
+ } else { None },
+ amount: htlc.amount_msat,
+ }});
watch_outputs.push(commitment_tx.output[transaction_output_index as usize].clone());
}
}
/// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
/// revoked using data in local_claimable_outpoints.
/// Should not be used if check_spend_revoked_transaction succeeds.
- fn check_spend_local_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<ClaimRequest>, (Sha256dHash, Vec<TxOut>)) {
+ fn check_spend_local_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec<ClaimRequest>, (Txid, Vec<TxOut>)) {
let commitment_txid = tx.txid();
let mut claim_requests = Vec::new();
let mut watch_outputs = Vec::new();
/// In any-case, choice is up to the user.
pub fn get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> {
log_trace!(self, "Getting signed latest local commitment transaction!");
- if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx() {
+ self.local_tx_signed = true;
+ if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) {
let txid = commitment_tx.txid();
let mut res = vec![commitment_tx];
for htlc in self.current_local_commitment_tx.htlc_outputs.iter() {
- if let Some(htlc_index) = htlc.0.transaction_output_index {
- let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
- if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
+ if let Some(vout) = htlc.0.transaction_output_index {
+ let preimage = if !htlc.0.offered {
+ if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
+ }
+ } else { None };
+ if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
+ &::bitcoin::OutPoint { txid, vout }, &preimage) {
res.push(htlc_tx);
}
}
#[cfg(test)]
pub fn unsafe_get_latest_local_commitment_txn(&mut self) -> Vec<Transaction> {
log_trace!(self, "Getting signed copy of latest local commitment transaction!");
- if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx() {
+ if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(&self.funding_redeemscript) {
let txid = commitment_tx.txid();
let mut res = vec![commitment_tx];
for htlc in self.current_local_commitment_tx.htlc_outputs.iter() {
- if let Some(htlc_index) = htlc.0.transaction_output_index {
- let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None };
- if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) {
+ if let Some(vout) = htlc.0.transaction_output_index {
+ let preimage = if !htlc.0.offered {
+ if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
+ }
+ } else { None };
+ if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
+ &::bitcoin::OutPoint { txid, vout }, &preimage) {
res.push(htlc_tx);
}
}
/// Eventually this should be pub and, roughly, implement ChainListener, however this requires
/// &mut self, as well as returns new spendable outputs and outpoints to watch for spending of
/// on-chain.
- fn block_connected<B: Deref, F: Deref>(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: B, fee_estimator: F)-> Vec<(Sha256dHash, Vec<TxOut>)>
+ fn block_connected<B: Deref, F: Deref>(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F)-> Vec<(Txid, Vec<TxOut>)>
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator
{
}
let should_broadcast = self.would_broadcast_at_height(height);
if should_broadcast {
- claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding {}});
+ claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }});
}
if should_broadcast {
- if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx() {
+ if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) {
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_local_state(&commitment_tx, &self.current_local_commitment_tx);
if !new_outputs.is_empty() {
watch_outputs.push((self.current_local_commitment_tx.txid.clone(), new_outputs));
watch_outputs
}
- fn block_disconnected<B: Deref, F: Deref>(&mut self, height: u32, block_hash: &Sha256dHash, broadcaster: B, fee_estimator: F)
+ fn block_disconnected<B: Deref, F: Deref>(&mut self, height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F)
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator
{
const MAX_ALLOC_SIZE: usize = 64*1024;
-impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (Sha256dHash, ChannelMonitor<ChanSigner>) {
+impl<ChanSigner: ChannelKeys + Readable> ReadableArgs<Arc<Logger>> for (BlockHash, ChannelMonitor<ChanSigner>) {
fn read<R: ::std::io::Read>(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
macro_rules! unwrap_obj {
($key: expr) => {
let remote_claimable_outpoints_len: u64 = Readable::read(reader)?;
let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64));
for _ in 0..remote_claimable_outpoints_len {
- let txid: Sha256dHash = Readable::read(reader)?;
+ let txid: Txid = Readable::read(reader)?;
let htlcs_count: u64 = Readable::read(reader)?;
let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32));
for _ in 0..htlcs_count {
let remote_commitment_txn_on_chain_len: u64 = Readable::read(reader)?;
let mut remote_commitment_txn_on_chain = HashMap::with_capacity(cmp::min(remote_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32));
for _ in 0..remote_commitment_txn_on_chain_len {
- let txid: Sha256dHash = Readable::read(reader)?;
+ let txid: Txid = Readable::read(reader)?;
let commitment_number = <U48 as Readable>::read(reader)?.0;
let outputs_count = <u64 as Readable>::read(reader)?;
let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 8));
}
}
- let last_block_hash: Sha256dHash = Readable::read(reader)?;
+ let last_block_hash: BlockHash = Readable::read(reader)?;
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
let mut onchain_events_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
}
let outputs_to_watch_len: u64 = Readable::read(reader)?;
- let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<Sha256dHash>() + mem::size_of::<Vec<Script>>())));
+ let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<Txid>() + mem::size_of::<Vec<Script>>())));
for _ in 0..outputs_to_watch_len {
let txid = Readable::read(reader)?;
let outputs_len: u64 = Readable::read(reader)?;
let onchain_tx_handler = ReadableArgs::read(reader, logger.clone())?;
let lockdown_from_offchain = Readable::read(reader)?;
+ let local_tx_signed = Readable::read(reader)?;
Ok((last_block_hash.clone(), ChannelMonitor {
latest_update_id,
onchain_tx_handler,
lockdown_from_offchain,
+ local_tx_signed,
last_block_hash,
secp_ctx: Secp256k1::new(),
use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType};
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
use bitcoin::util::bip143;
- use bitcoin_hashes::Hash;
- use bitcoin_hashes::sha256::Hash as Sha256;
- use bitcoin_hashes::sha256d::Hash as Sha256dHash;
- use bitcoin_hashes::hex::FromHex;
+ use bitcoin::hashes::Hash;
+ use bitcoin::hashes::sha256::Hash as Sha256;
+ use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hash_types::Txid;
use hex;
use chain::transaction::OutPoint;
use ln::channelmanager::{PaymentPreimage, PaymentHash};
use ln::chan_utils;
use ln::chan_utils::{HTLCOutputInCommitment, LocalCommitmentTransaction};
use util::test_utils::TestLogger;
- use secp256k1::key::{SecretKey,PublicKey};
- use secp256k1::Secp256k1;
+ use bitcoin::secp256k1::key::{SecretKey,PublicKey};
+ use bitcoin::secp256k1::Secp256k1;
use rand::{thread_rng,Rng};
use std::sync::Arc;
use chain::keysinterface::InMemoryChannelKeys;
// old state.
let mut monitor = ChannelMonitor::new(keys,
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
- (OutPoint { txid: Sha256dHash::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
+ (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[44; 32]).unwrap()),
&PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap()),
10, Script::new(), 46, 0, LocalCommitmentTransaction::dummy(), logger.clone());
}
let script_pubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script();
- let txid = Sha256dHash::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap();
+ let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap();
// Justice tx with 1 to_local, 2 revoked offered HTLCs, 1 revoked received HTLCs
let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };