From: Matt Corallo <649246+TheBlueMatt@users.noreply.github.com> Date: Thu, 28 May 2020 19:34:42 +0000 (+0000) Subject: Merge pull request #620 from TheBlueMatt/2020-05-pre-bindings-cleanups X-Git-Tag: v0.0.12~61 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=2087032e7a823f6c63a64dac951e0f4843bc4667;hp=-c;p=rust-lightning Merge pull request #620 from TheBlueMatt/2020-05-pre-bindings-cleanups Pre-C Bindings Cleanup --- 2087032e7a823f6c63a64dac951e0f4843bc4667 diff --combined fuzz/src/chanmon_consistency.rs index b5fc307a,3a236cdf..c5c3c9f3 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@@ -96,7 -96,9 +96,9 @@@ impl TestChannelMonitor } } } - impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { + impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { + type Keys = EnforcingChannelKeys; + fn add_monitor(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { let mut ser = VecWriter(Vec::new()); monitor.write_for_disk(&mut ser).unwrap(); @@@ -164,7 -166,6 +166,7 @@@ impl KeysInterface for KeyProvider SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_id]).unwrap(), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_id], channel_value_satoshis, + (0, 0), )) } @@@ -196,7 -197,7 +198,7 @@@ pub fn do_test std::hash::Hash for Peer<'a> } } + type ChannelMan = ChannelManager< + EnforcingChannelKeys, + Arc, Arc, Arc, Arc>>, + Arc, Arc, Arc, Arc>; + type PeerMan<'a> = PeerManager, Arc, Arc, Arc>>, Arc>; + struct MoneyLossDetector<'a> { - manager: Arc, Arc, Arc, Arc>>, Arc, Arc, Arc, Arc>>, - monitor: Arc, Arc, Arc, Arc>>, - handler: PeerManager, Arc, Arc, Arc, Arc>>, Arc, Arc, Arc, Arc>>, Arc>, + manager: Arc, + monitor: Arc, Arc, Arc, Arc>>, + handler: PeerMan<'a>, peers: &'a RefCell<[bool; 256]>, funding_txn: Vec, @@@ -149,9 -156,9 +156,9 @@@ } impl<'a> MoneyLossDetector<'a> { pub fn new(peers: &'a RefCell<[bool; 256]>, - manager: Arc, Arc, Arc, Arc>>, Arc, Arc, Arc, Arc>>, + manager: Arc, monitor: Arc, Arc, Arc, Arc>>, - handler: PeerManager, Arc, Arc, Arc, Arc>>, Arc, Arc, Arc, Arc>>, Arc>) -> Self { + handler: PeerMan<'a>) -> Self { MoneyLossDetector { manager, monitor, @@@ -262,7 -269,6 +269,7 @@@ impl KeysInterface for KeyProvider SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, ctr]).unwrap(), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr], channel_value_satoshis, + (0, 0), ) } else { InMemoryChannelKeys::new( @@@ -274,7 -280,6 +281,7 @@@ SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, ctr]).unwrap(), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr], channel_value_satoshis, + (0, 0), ) }) } @@@ -334,7 -339,7 +341,7 @@@ pub fn do_test(data: &[u8], logger: &Ar config.channel_options.fee_proportional_millionths = slice_to_be32(get_slice!(4)); config.channel_options.announced_channel = get_slice!(1)[0] != 0; config.peer_channel_config_limits.min_dust_limit_satoshis = 0; - let channelmanager = Arc::new(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0).unwrap()); + let channelmanager = Arc::new(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0)); let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret()); let net_graph_msg_handler = Arc::new(NetGraphMsgHandler::new(watch.clone(), Arc::clone(&logger))); @@@ -478,7 -483,7 +485,7 @@@ let funding_output = 'search_loop: loop { let funding_txid = tx.txid(); if let None = loss_detector.txids_confirmed.get(&funding_txid) { - let outpoint = OutPoint::new(funding_txid, 0); + let outpoint = OutPoint { txid: funding_txid, index: 0 }; for chan in channelmanager.list_channels() { if chan.channel_id == outpoint.to_channel_id() { tx.version += 1; diff --combined lightning/src/chain/keysinterface.rs index 4e4d182a,47eafa35..9de35f0e --- a/lightning/src/chain/keysinterface.rs +++ b/lightning/src/chain/keysinterface.rs @@@ -49,66 -49,43 +49,66 @@@ pub enum SpendableOutputDescriptor output: TxOut, }, /// An output to a P2WSH script which can be spent with a single signature after a CSV delay. - /// The private key which should be used to sign the transaction is provided, as well as the - /// full witness redeemScript which is hashed in the output script_pubkey. + /// /// The witness in the spending input should be: - /// (MINIMALIF standard rule) - /// - /// Note that the nSequence field in the input must be set to_self_delay (which corresponds to - /// the transaction not being broadcastable until at least to_self_delay blocks after the input - /// confirms). + /// (MINIMALIF standard rule) + /// + /// Note that the nSequence field in the spending input must be set to to_self_delay + /// (which means the transaction is not broadcastable until at least to_self_delay + /// blocks after the outpoint confirms). + /// /// These are generally the result of a "revocable" output to us, spendable only by us unless - /// it is an output from us having broadcast an old state (which should never happen). + /// it is an output from an old state which we broadcast (which should never happen). + /// + /// To derive the delayed_payment key which is used to sign for this input, you must pass the + /// local delayed_payment_base_key (ie the private key which corresponds to the pubkey in + /// ChannelKeys::pubkeys().delayed_payment_basepoint) and the provided per_commitment_point to + /// chan_utils::derive_private_key. The public key can be generated without the secret key + /// using chan_utils::derive_public_key and only the delayed_payment_basepoint which appears in + /// ChannelKeys::pubkeys(). + /// + /// To derive the remote_revocation_pubkey provided here (which is used in the witness + /// script generation), you must pass the remote revocation_basepoint (which appears in the + /// call to ChannelKeys::set_remote_channel_pubkeys) and the provided per_commitment point + /// to chan_utils::derive_public_revocation_key. + /// + /// The witness script which is hashed and included in the output script_pubkey may be + /// regenerated by passing the revocation_pubkey (derived as above), our delayed_payment pubkey + /// (derived as above), and the to_self_delay contained here to + /// chan_utils::get_revokeable_redeemscript. + // + // TODO: we need to expose utility methods in KeyManager to do all the relevant derivation. DynamicOutputP2WSH { /// The outpoint which is spendable outpoint: OutPoint, - /// The secret key which must be used to sign the spending transaction - key: SecretKey, - /// The witness redeemScript which is hashed to create the script_pubkey in the given output - witness_script: Script, + /// Per commitment point to derive delayed_payment_key by key holder + per_commitment_point: PublicKey, /// The nSequence value which must be set in the spending input to satisfy the OP_CSV in /// the witness_script. to_self_delay: u16, /// The output which is referenced by the given outpoint output: TxOut, + /// The channel keys state used to proceed to derivation of signing key. Must + /// be pass to KeysInterface::derive_channel_keys. + key_derivation_params: (u64, u64), + /// The remote_revocation_pubkey used to derive witnessScript + remote_revocation_pubkey: PublicKey }, - // TODO: Note that because key is now static and exactly what is provided by us, we should drop - // this in favor of StaticOutput: - /// An output to a P2WPKH, spendable exclusively by the given private key. + /// An output to a P2WPKH, spendable exclusively by our payment key (ie the private key which + /// corresponds to the public key in ChannelKeys::pubkeys().payment_point). /// The witness in the spending input, is, thus, simply: - /// + /// + /// /// These are generally the result of our counterparty having broadcast the current state, /// allowing us to claim the non-HTLC-encumbered outputs immediately. - DynamicOutputP2WPKH { + StaticOutputRemotePayment { /// The outpoint which is spendable outpoint: OutPoint, - /// The secret key which must be used to sign the spending transaction - key: SecretKey, /// The output which is reference by the given outpoint output: TxOut, + /// The channel keys state used to proceed to derivation of signing key. Must + /// be pass to KeysInterface::derive_channel_keys. + key_derivation_params: (u64, u64), } } @@@ -120,22 -97,19 +120,22 @@@ impl Writeable for SpendableOutputDescr outpoint.write(writer)?; output.write(writer)?; }, - &SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => { + &SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref key_derivation_params, ref remote_revocation_pubkey } => { 1u8.write(writer)?; outpoint.write(writer)?; - key.write(writer)?; - witness_script.write(writer)?; + per_commitment_point.write(writer)?; to_self_delay.write(writer)?; output.write(writer)?; + key_derivation_params.0.write(writer)?; + key_derivation_params.1.write(writer)?; + remote_revocation_pubkey.write(writer)?; }, - &SpendableOutputDescriptor::DynamicOutputP2WPKH { ref outpoint, ref key, ref output } => { + &SpendableOutputDescriptor::StaticOutputRemotePayment { ref outpoint, ref output, ref key_derivation_params } => { 2u8.write(writer)?; outpoint.write(writer)?; - key.write(writer)?; output.write(writer)?; + key_derivation_params.0.write(writer)?; + key_derivation_params.1.write(writer)?; }, } Ok(()) @@@ -151,44 -125,21 +151,22 @@@ impl Readable for SpendableOutputDescri }), 1u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WSH { outpoint: Readable::read(reader)?, - key: Readable::read(reader)?, - witness_script: Readable::read(reader)?, + per_commitment_point: Readable::read(reader)?, to_self_delay: Readable::read(reader)?, output: Readable::read(reader)?, + key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?), + remote_revocation_pubkey: Readable::read(reader)?, }), - 2u8 => Ok(SpendableOutputDescriptor::DynamicOutputP2WPKH { + 2u8 => Ok(SpendableOutputDescriptor::StaticOutputRemotePayment { outpoint: Readable::read(reader)?, - key: Readable::read(reader)?, output: Readable::read(reader)?, + key_derivation_params: (Readable::read(reader)?, Readable::read(reader)?), }), _ => Err(DecodeError::InvalidValue), } } } - /// A trait to describe an object which can get user secrets and key material. - pub trait KeysInterface: Send + Sync { - /// A type which implements ChannelKeys which will be returned by get_channel_keys. - type ChanKeySigner : ChannelKeys; - - /// Get node secret key (aka node_id or network_key) - fn get_node_secret(&self) -> SecretKey; - /// Get destination redeemScript to encumber static protocol exit points. - fn get_destination_script(&self) -> Script; - /// Get shutdown_pubkey to use as PublicKey at channel closure - fn get_shutdown_pubkey(&self) -> PublicKey; - /// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you - /// restarted with some stale data! - fn get_channel_keys(&self, inbound: bool, channel_value_satoshis: u64) -> Self::ChanKeySigner; - /// Get a secret and PRNG seed for construting an onion packet - fn get_onion_rand(&self) -> (SecretKey, [u8; 32]); - /// Get a unique temporary channel id. Channels will be referred to by this until the funding - /// transaction is created, at which point they will use the outpoint in the funding - /// transaction. - fn get_channel_id(&self) -> [u8; 32]; - } - /// Set of lightning keys needed to operate a channel as described in BOLT 3. /// /// Signing services could be implemented on a hardware wallet. In this case, @@@ -233,10 -184,6 +211,10 @@@ pub trait ChannelKeys : Send+Clone fn commitment_seed<'a>(&'a self) -> &'a [u8; 32]; /// Gets the local channel public keys and basepoints fn pubkeys<'a>(&'a self) -> &'a ChannelPublicKeys; + /// Gets arbitrary identifiers describing the set of keys which are provided back to you in + /// some SpendableOutputDescriptor types. These should be sufficient to identify this + /// ChannelKeys object uniquely and lookup or re-derive its keys. + fn key_derivation_params(&self) -> (u64, u64); /// Create a signature for a remote commitment transaction and associated HTLC transactions. /// @@@ -277,49 -224,6 +255,49 @@@ /// return value must contain a signature. fn sign_local_commitment_htlc_transactions(&self, local_commitment_tx: &LocalCommitmentTransaction, local_csv: u16, secp_ctx: &Secp256k1) -> Result>, ()>; + /// Create a signature for the given input in a transaction spending an HTLC or commitment + /// transaction output when our counterparty broadcasts an old state. + /// + /// A justice transaction may claim multiples outputs at the same time if timelocks are + /// similar, but only a signature for the input at index `input` should be signed for here. + /// It may be called multiples time for same output(s) if a fee-bump is needed with regards + /// to an upcoming timelock expiration. + /// + /// Amount is value of the output spent by this input, committed to in the BIP 143 signature. + /// + /// per_commitment_key is revocation secret which was provided by our counterparty when they + /// revoked the state which they eventually broadcast. It's not a _local_ secret key and does + /// not allow the spending of any funds by itself (you need our local revocation_secret to do + /// so). + /// + /// htlc holds HTLC elements (hash, timelock) if the output being spent is a HTLC output, thus + /// changing the format of the witness script (which is committed to in the BIP 143 + /// signatures). + /// + /// on_remote_tx_csv is the relative lock-time that that our counterparty would have to set on + /// their transaction were they to spend the same output. It is included in the witness script + /// and thus committed to in the BIP 143 signature. + fn sign_justice_transaction(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option, on_remote_tx_csv: u16, secp_ctx: &Secp256k1) -> Result; + + /// Create a signature for a claiming transaction for a HTLC output on a remote commitment + /// transaction, either offered or received. + /// + /// Such a transaction may claim multiples offered outputs at same time if we know the + /// preimage for each when we create it, but only the input at index `input` should be + /// signed for here. It may be called multiple times for same output(s) if a fee-bump is + /// needed with regards to an upcoming timelock expiration. + /// + /// Witness_script is either a offered or received script as defined in BOLT3 for HTLC + /// outputs. + /// + /// Amount is value of the output spent by this input, committed to in the BIP 143 signature. + /// + /// Per_commitment_point is the dynamic point corresponding to the channel state + /// detected onchain. It has been generated by our counterparty and is used to derive + /// channel state keys, which are then included in the witness script and committed to in the + /// BIP 143 signature. + fn sign_remote_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result; + /// Create a signature for a (proposed) closing transaction. /// /// Note that, due to rounding, there may be one "missing" satoshi, and either party may have @@@ -341,6 -245,28 +319,28 @@@ fn set_remote_channel_pubkeys(&mut self, channel_points: &ChannelPublicKeys); } + /// A trait to describe an object which can get user secrets and key material. + pub trait KeysInterface: Send + Sync { + /// A type which implements ChannelKeys which will be returned by get_channel_keys. + type ChanKeySigner : ChannelKeys; + + /// Get node secret key (aka node_id or network_key) + fn get_node_secret(&self) -> SecretKey; + /// Get destination redeemScript to encumber static protocol exit points. + fn get_destination_script(&self) -> Script; + /// Get shutdown_pubkey to use as PublicKey at channel closure + fn get_shutdown_pubkey(&self) -> PublicKey; + /// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you + /// restarted with some stale data! + fn get_channel_keys(&self, inbound: bool, channel_value_satoshis: u64) -> Self::ChanKeySigner; + /// Get a secret and PRNG seed for constructing an onion packet + fn get_onion_rand(&self) -> (SecretKey, [u8; 32]); + /// Get a unique temporary channel id. Channels will be referred to by this until the funding + /// transaction is created, at which point they will use the outpoint in the funding + /// transaction. + fn get_channel_id(&self) -> [u8; 32]; + } + #[derive(Clone)] /// A simple implementation of ChannelKeys that just keeps the private keys in memory. pub struct InMemoryChannelKeys { @@@ -362,8 -288,6 +362,8 @@@ pub(crate) remote_channel_pubkeys: Option, /// The total value of this channel channel_value_satoshis: u64, + /// Key derivation parameters + key_derivation_params: (u64, u64), } impl InMemoryChannelKeys { @@@ -376,8 -300,7 +376,8 @@@ delayed_payment_base_key: SecretKey, htlc_base_key: SecretKey, commitment_seed: [u8; 32], - channel_value_satoshis: u64) -> InMemoryChannelKeys { + channel_value_satoshis: u64, + key_derivation_params: (u64, u64)) -> InMemoryChannelKeys { let local_channel_pubkeys = InMemoryChannelKeys::make_local_keys(secp_ctx, &funding_key, &revocation_base_key, &payment_key, &delayed_payment_base_key, @@@ -392,7 -315,6 +392,7 @@@ channel_value_satoshis, local_channel_pubkeys, remote_channel_pubkeys: None, + key_derivation_params, } } @@@ -411,8 -333,6 +411,8 @@@ htlc_basepoint: from_secret(&htlc_base_key), } } + + fn remote_pubkeys<'a>(&'a self) -> &'a ChannelPublicKeys { self.remote_channel_pubkeys.as_ref().unwrap() } } impl ChannelKeys for InMemoryChannelKeys { @@@ -423,7 -343,6 +423,7 @@@ fn htlc_base_key(&self) -> &SecretKey { &self.htlc_base_key } fn commitment_seed(&self) -> &[u8; 32] { &self.commitment_seed } fn pubkeys<'a>(&'a self) -> &'a ChannelPublicKeys { &self.local_channel_pubkeys } + fn key_derivation_params(&self) -> (u64, u64) { self.key_derivation_params } fn sign_remote_commitment(&self, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()> { if commitment_tx.input.len() != 1 { return Err(()); } @@@ -475,54 -394,6 +475,54 @@@ local_commitment_tx.get_htlc_sigs(&self.htlc_base_key, local_csv, secp_ctx) } + fn sign_justice_transaction(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option, on_remote_tx_csv: u16, secp_ctx: &Secp256k1) -> Result { + let revocation_key = match chan_utils::derive_private_revocation_key(&secp_ctx, &per_commitment_key, &self.revocation_base_key) { + Ok(revocation_key) => revocation_key, + Err(_) => return Err(()) + }; + let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); + let revocation_pubkey = match chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint) { + Ok(revocation_pubkey) => revocation_pubkey, + Err(_) => return Err(()) + }; + let witness_script = if let &Some(ref htlc) = htlc { + let remote_htlcpubkey = match chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.remote_pubkeys().htlc_basepoint) { + Ok(remote_htlcpubkey) => remote_htlcpubkey, + Err(_) => return Err(()) + }; + let local_htlcpubkey = match chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint) { + Ok(local_htlcpubkey) => local_htlcpubkey, + Err(_) => return Err(()) + }; + chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &remote_htlcpubkey, &local_htlcpubkey, &revocation_pubkey) + } else { + let remote_delayedpubkey = match chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.remote_pubkeys().delayed_payment_basepoint) { + Ok(remote_delayedpubkey) => remote_delayedpubkey, + Err(_) => return Err(()) + }; + chan_utils::get_revokeable_redeemscript(&revocation_pubkey, on_remote_tx_csv, &remote_delayedpubkey) + }; + let sighash_parts = bip143::SighashComponents::new(&justice_tx); + let sighash = hash_to_message!(&sighash_parts.sighash_all(&justice_tx.input[input], &witness_script, amount)[..]); + return Ok(secp_ctx.sign(&sighash, &revocation_key)) + } + + fn sign_remote_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result { + if let Ok(htlc_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key) { + let witness_script = if let Ok(revocation_pubkey) = chan_utils::derive_public_revocation_key(&secp_ctx, &per_commitment_point, &self.pubkeys().revocation_basepoint) { + if let Ok(remote_htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.remote_pubkeys().htlc_basepoint) { + if let Ok(local_htlcpubkey) = chan_utils::derive_public_key(&secp_ctx, &per_commitment_point, &self.pubkeys().htlc_basepoint) { + chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &remote_htlcpubkey, &local_htlcpubkey, &revocation_pubkey) + } else { return Err(()) } + } else { return Err(()) } + } else { return Err(()) }; + let sighash_parts = bip143::SighashComponents::new(&htlc_tx); + let sighash = hash_to_message!(&sighash_parts.sighash_all(&htlc_tx.input[input], &witness_script, amount)[..]); + return Ok(secp_ctx.sign(&sighash, &htlc_key)) + } + Err(()) + } + fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1) -> Result { if closing_tx.input.len() != 1 { return Err(()); } if closing_tx.input[0].witness.len() != 0 { return Err(()); } @@@ -558,8 -429,6 +558,8 @@@ impl Writeable for InMemoryChannelKeys self.commitment_seed.write(writer)?; self.remote_channel_pubkeys.write(writer)?; self.channel_value_satoshis.write(writer)?; + self.key_derivation_params.0.write(writer)?; + self.key_derivation_params.1.write(writer)?; Ok(()) } @@@ -580,8 -449,6 +580,8 @@@ impl Readable for InMemoryChannelKeys InMemoryChannelKeys::make_local_keys(&secp_ctx, &funding_key, &revocation_base_key, &payment_key, &delayed_payment_base_key, &htlc_base_key); + let params_1 = Readable::read(reader)?; + let params_2 = Readable::read(reader)?; Ok(InMemoryChannelKeys { funding_key, @@@ -592,8 -459,7 +592,8 @@@ commitment_seed, channel_value_satoshis, local_channel_pubkeys, - remote_channel_pubkeys + remote_channel_pubkeys, + key_derivation_params: (params_1, params_2), }) } } @@@ -617,9 -483,7 +617,9 @@@ pub struct KeysManager channel_id_master_key: ExtendedPrivKey, channel_id_child_index: AtomicUsize, - unique_start: Sha256State, + seed: [u8; 32], + starting_time_secs: u64, + starting_time_nanos: u32, } impl KeysManager { @@@ -642,7 -506,7 +642,7 @@@ /// Note that until the 0.1 release there is no guarantee of backward compatibility between /// versions. Once the library is more fully supported, the docs will be updated to include a /// detailed description of the guarantee. - pub fn new(seed: &[u8; 32], network: Network, starting_time_secs: u64, starting_time_nanos: u32) -> KeysManager { + pub fn new(seed: &[u8; 32], network: Network, starting_time_secs: u64, starting_time_nanos: u32) -> Self { let secp_ctx = Secp256k1::signing_only(); match ExtendedPrivKey::new_master(network.clone(), seed) { Ok(master_key) => { @@@ -664,6 -528,11 +664,6 @@@ let session_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted"); let channel_id_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted"); - let mut unique_start = Sha256::engine(); - unique_start.input(&byte_utils::be64_to_array(starting_time_secs)); - unique_start.input(&byte_utils::be32_to_array(starting_time_nanos)); - unique_start.input(seed); - KeysManager { secp_ctx, node_secret, @@@ -676,40 -545,40 +676,40 @@@ channel_id_master_key, channel_id_child_index: AtomicUsize::new(0), - unique_start, + seed: *seed, + starting_time_secs, + starting_time_nanos, } }, Err(_) => panic!("Your rng is busted"), } } -} - -impl KeysInterface for KeysManager { - type ChanKeySigner = InMemoryChannelKeys; - - fn get_node_secret(&self) -> SecretKey { - self.node_secret.clone() - } - - fn get_destination_script(&self) -> Script { - self.destination_script.clone() - } - - fn get_shutdown_pubkey(&self) -> PublicKey { - self.shutdown_pubkey.clone() + fn derive_unique_start(&self) -> Sha256State { + let mut unique_start = Sha256::engine(); + unique_start.input(&byte_utils::be64_to_array(self.starting_time_secs)); + unique_start.input(&byte_utils::be32_to_array(self.starting_time_nanos)); + unique_start.input(&self.seed); + unique_start } + /// Derive an old set of ChannelKeys for per-channel secrets based on a key derivation + /// parameters. + /// Key derivation parameters are accessible through a per-channel secrets + /// ChannelKeys::key_derivation_params and is provided inside DynamicOuputP2WSH in case of + /// onchain output detection for which a corresponding delayed_payment_key must be derived. + pub fn derive_channel_keys(&self, channel_value_satoshis: u64, params_1: u64, params_2: u64) -> InMemoryChannelKeys { + let chan_id = ((params_1 & 0xFFFF_FFFF_0000_0000) >> 32) as u32; + let mut unique_start = Sha256::engine(); + unique_start.input(&byte_utils::be64_to_array(params_2)); + unique_start.input(&byte_utils::be32_to_array(params_1 as u32)); + unique_start.input(&self.seed); - fn get_channel_keys(&self, _inbound: bool, channel_value_satoshis: u64) -> InMemoryChannelKeys { // We only seriously intend to rely on the channel_master_key for true secure // entropy, everything else just ensures uniqueness. We rely on the unique_start (ie // starting_time provided in the constructor) to be unique. - let mut sha = self.unique_start.clone(); - - let child_ix = self.channel_child_index.fetch_add(1, Ordering::AcqRel); - let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); - sha.input(&child_privkey.private_key.key[..]); + let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(chan_id).expect("key space exhausted")).expect("Your RNG is busted"); + unique_start.input(&child_privkey.private_key.key[..]); - let seed = Sha256::from_engine(sha).into_inner(); + let seed = Sha256::from_engine(unique_start).into_inner(); let commitment_seed = { let mut sha = Sha256::engine(); @@@ -740,35 -609,12 +740,35 @@@ delayed_payment_base_key, htlc_base_key, commitment_seed, - channel_value_satoshis + channel_value_satoshis, + (params_1, params_2), ) } +} + +impl KeysInterface for KeysManager { + type ChanKeySigner = InMemoryChannelKeys; + + fn get_node_secret(&self) -> SecretKey { + self.node_secret.clone() + } + + fn get_destination_script(&self) -> Script { + self.destination_script.clone() + } + + fn get_shutdown_pubkey(&self) -> PublicKey { + self.shutdown_pubkey.clone() + } + + fn get_channel_keys(&self, _inbound: bool, channel_value_satoshis: u64) -> InMemoryChannelKeys { + let child_ix = self.channel_child_index.fetch_add(1, Ordering::AcqRel); + let ix_and_nanos: u64 = (child_ix as u64) << 32 | (self.starting_time_nanos as u64); + self.derive_channel_keys(channel_value_satoshis, ix_and_nanos, self.starting_time_secs) + } fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) { - let mut sha = self.unique_start.clone(); + let mut sha = self.derive_unique_start(); let child_ix = self.session_child_index.fetch_add(1, Ordering::AcqRel); let child_privkey = self.session_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); @@@ -784,7 -630,7 +784,7 @@@ } fn get_channel_id(&self) -> [u8; 32] { - let mut sha = self.unique_start.clone(); + let mut sha = self.derive_unique_start(); let child_ix = self.channel_id_child_index.fetch_add(1, Ordering::AcqRel); let child_privkey = self.channel_id_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted"); diff --combined lightning/src/ln/chan_utils.rs index 53a6e25f,949d008c..a97a5a60 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@@ -5,7 -5,8 +5,8 @@@ use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction, SigHashType}; - use bitcoin::consensus::encode::{self, Decodable, Encodable}; + use bitcoin::consensus::encode::{Decodable, Encodable}; + use bitcoin::consensus::encode; use bitcoin::util::bip143; use bitcoin::hashes::{Hash, HashEngine}; @@@ -171,11 -172,8 +172,11 @@@ impl Readable for CounterpartyCommitmen } } -/// Derives a per-commitment-transaction private key (eg an htlc key or payment key) from the base -/// private key for that type of key and the per_commitment_point (available in TxCreationKeys) +/// Derives a per-commitment-transaction private key (eg an htlc key or delayed_payment key) +/// from the base secret and the per_commitment_point. +/// +/// Note that this is infallible iff we trust that at least one of the two input keys are randomly +/// generated (ie our own). pub fn derive_private_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result { let mut sha = Sha256::engine(); sha.input(&per_commitment_point.serialize()); @@@ -187,13 -185,7 +188,13 @@@ Ok(key) } -pub(super) fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result { +/// Derives a per-commitment-transaction public key (eg an htlc key or a delayed_payment key) +/// from the base point and the per_commitment_key. This is the public equivalent of +/// derive_private_key - using only public keys to derive a public key instead of private keys. +/// +/// Note that this is infallible iff we trust that at least one of the two input keys are randomly +/// generated (ie our own). +pub fn derive_public_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result { let mut sha = Sha256::engine(); sha.input(&per_commitment_point.serialize()); sha.input(&base_point.serialize()); @@@ -203,11 -195,10 +204,11 @@@ base_point.combine(&hashkey) } -/// Derives a revocation key from its constituent parts. +/// Derives a per-commitment-transaction revocation key from its constituent parts. +/// /// Note that this is infallible iff we trust that at least one of the two input keys are randomly /// generated (ie our own). -pub(super) fn derive_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { +pub fn derive_private_revocation_key(secp_ctx: &Secp256k1, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result { let revocation_base_point = PublicKey::from_secret_key(&secp_ctx, &revocation_base_secret); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); @@@ -234,13 -225,7 +235,13 @@@ Ok(part_a) } -pub(super) fn derive_public_revocation_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result { +/// Derives a per-commitment-transaction revocation public key from its constituent parts. This is +/// the public equivalend of derive_private_revocation_key - using only public keys to derive a +/// public key instead of private keys. +/// +/// Note that this is infallible iff we trust that at least one of the two input keys are randomly +/// generated (ie our own). +pub fn derive_public_revocation_key(secp_ctx: &Secp256k1, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result { let rev_append_commit_hash_key = { let mut sha = Sha256::engine(); sha.input(&revocation_base_point.serialize()); @@@ -289,9 -274,9 +290,9 @@@ pub struct ChannelPublicKeys /// on-chain channel lock-in 2-of-2 multisig output. pub funding_pubkey: PublicKey, /// The base point which is used (with derive_public_revocation_key) to derive per-commitment - /// revocation keys. The per-commitment revocation private key is then revealed by the owner of - /// a commitment transaction so that their counterparty can claim all available funds if they - /// broadcast an old state. + /// revocation keys. This is combined with the per-commitment-secret generated by the + /// counterparty to create a secret which the counterparty can reveal to revoke previous + /// states. pub revocation_basepoint: PublicKey, /// The public key which receives our immediately spendable primary channel balance in /// remote-broadcasted commitment transactions. This key is static across every commitment @@@ -327,10 -312,9 +328,10 @@@ impl TxCreationKeys } } -/// Gets the "to_local" output redeemscript, ie the script which is time-locked or spendable by -/// the revocation key -pub(super) fn get_revokeable_redeemscript(revocation_key: &PublicKey, to_self_delay: u16, delayed_payment_key: &PublicKey) -> Script { +/// A script either spendable by the revocation +/// key or the delayed_payment_key and satisfying the relative-locktime OP_CSV constrain. +/// Encumbering a `to_local` output on a commitment transaction or 2nd-stage HTLC transactions. +pub fn get_revokeable_redeemscript(revocation_key: &PublicKey, to_self_delay: u16, delayed_payment_key: &PublicKey) -> Script { Builder::new().push_opcode(opcodes::all::OP_IF) .push_slice(&revocation_key.serialize()) .push_opcode(opcodes::all::OP_ELSE) diff --combined lightning/src/ln/channel.rs index b0f8ef9a,6ddaa8fd..8d55804f --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@@ -1486,7 -1486,7 +1486,7 @@@ impl Channel: Send + Sync { - /// Adds a monitor for the given `funding_txo`. - /// - /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with - /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected - /// callbacks with the funding transaction, or any spends of it. - /// - /// Further, the implementer must also ensure that each output returned in - /// monitor.get_outputs_to_watch() is registered to ensure that the provided monitor learns about - /// any spends of any of the outputs. - /// - /// Any spends of outputs which should have been registered which aren't passed to - /// ChannelMonitors via block_connected may result in FUNDS LOSS. - fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; - - /// Updates a monitor for the given `funding_txo`. - /// - /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with - /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected - /// callbacks with the funding transaction, or any spends of it. - /// - /// Further, the implementer must also ensure that each output returned in - /// monitor.get_watch_outputs() is registered to ensure that the provided monitor learns about - /// any spends of any of the outputs. - /// - /// Any spends of outputs which should have been registered which aren't passed to - /// ChannelMonitors via block_connected may result in FUNDS LOSS. - fn update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr>; - - /// Used by ChannelManager to get list of HTLC resolved onchain and which needed to be updated - /// with success or failure. - /// - /// You should probably just call through to - /// ChannelMonitor::get_and_clear_pending_htlcs_updated() for each ChannelMonitor and return - /// the full list. - fn get_and_clear_pending_htlcs_updated(&self) -> Vec; - } - /// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a /// watchtower or watch our own channels. /// @@@ -320,12 -260,14 +260,14 @@@ impl ManyChannelMonitor for SimpleManyChannelMonitor + impl ManyChannelMonitor for SimpleManyChannelMonitor where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, C::Target: ChainWatchInterface, { + type Keys = ChanSigner; + fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { match self.add_monitor_by_key(funding_txo, monitor) { Ok(_) => Ok(()), @@@ -428,84 -370,24 +370,84 @@@ struct LocalSignedTx htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, } +/// We use this to track remote commitment transactions and htlcs outputs and +/// use it to generate any justice or 2nd-stage preimage/timeout transactions. +#[derive(PartialEq)] +struct RemoteCommitmentTransaction { + remote_delayed_payment_base_key: PublicKey, + remote_htlc_base_key: PublicKey, + on_remote_tx_csv: u16, + per_htlc: HashMap> +} + +impl Writeable for RemoteCommitmentTransaction { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + self.remote_delayed_payment_base_key.write(w)?; + self.remote_htlc_base_key.write(w)?; + w.write_all(&byte_utils::be16_to_array(self.on_remote_tx_csv))?; + w.write_all(&byte_utils::be64_to_array(self.per_htlc.len() as u64))?; + for (ref txid, ref htlcs) in self.per_htlc.iter() { + w.write_all(&txid[..])?; + w.write_all(&byte_utils::be64_to_array(htlcs.len() as u64))?; + for &ref htlc in htlcs.iter() { + htlc.write(w)?; + } + } + Ok(()) + } +} +impl Readable for RemoteCommitmentTransaction { + fn read(r: &mut R) -> Result { + let remote_commitment_transaction = { + let remote_delayed_payment_base_key = Readable::read(r)?; + let remote_htlc_base_key = Readable::read(r)?; + let on_remote_tx_csv: u16 = Readable::read(r)?; + let per_htlc_len: u64 = Readable::read(r)?; + let mut per_htlc = HashMap::with_capacity(cmp::min(per_htlc_len as usize, MAX_ALLOC_SIZE / 64)); + for _ in 0..per_htlc_len { + let txid: Txid = Readable::read(r)?; + let htlcs_count: u64 = Readable::read(r)?; + let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32)); + for _ in 0..htlcs_count { + let htlc = Readable::read(r)?; + htlcs.push(htlc); + } + if let Some(_) = per_htlc.insert(txid, htlcs) { + return Err(DecodeError::InvalidValue); + } + } + RemoteCommitmentTransaction { + remote_delayed_payment_base_key, + remote_htlc_base_key, + on_remote_tx_csv, + per_htlc, + } + }; + Ok(remote_commitment_transaction) + } +} + /// When ChannelMonitor discovers an onchain outpoint being a step of a channel and that it needs /// to generate a tx to push channel state forward, we cache outpoint-solving tx material to build /// a new bumped one in case of lenghty confirmation delay #[derive(Clone, PartialEq)] pub(crate) enum InputMaterial { Revoked { - witness_script: Script, - pubkey: Option, - key: SecretKey, - is_htlc: bool, + per_commitment_point: PublicKey, + remote_delayed_payment_base_key: PublicKey, + remote_htlc_base_key: PublicKey, + per_commitment_key: SecretKey, + input_descriptor: InputDescriptors, amount: u64, + htlc: Option, + on_remote_tx_csv: u16, }, RemoteHTLC { - witness_script: Script, - key: SecretKey, + per_commitment_point: PublicKey, + remote_delayed_payment_base_key: PublicKey, + remote_htlc_base_key: PublicKey, preimage: Option, - amount: u64, - locktime: u32, + htlc: HTLCOutputInCommitment }, LocalHTLC { preimage: Option, @@@ -519,24 -401,21 +461,24 @@@ impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount} => { + &InputMaterial::Revoked { ref per_commitment_point, ref remote_delayed_payment_base_key, ref remote_htlc_base_key, ref per_commitment_key, ref input_descriptor, ref amount, ref htlc, ref on_remote_tx_csv} => { writer.write_all(&[0; 1])?; - witness_script.write(writer)?; - pubkey.write(writer)?; - writer.write_all(&key[..])?; - is_htlc.write(writer)?; + per_commitment_point.write(writer)?; + remote_delayed_payment_base_key.write(writer)?; + remote_htlc_base_key.write(writer)?; + writer.write_all(&per_commitment_key[..])?; + input_descriptor.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; + htlc.write(writer)?; + on_remote_tx_csv.write(writer)?; }, - &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { + &InputMaterial::RemoteHTLC { ref per_commitment_point, ref remote_delayed_payment_base_key, ref remote_htlc_base_key, ref preimage, ref htlc} => { writer.write_all(&[1; 1])?; - witness_script.write(writer)?; - key.write(writer)?; + per_commitment_point.write(writer)?; + remote_delayed_payment_base_key.write(writer)?; + remote_htlc_base_key.write(writer)?; preimage.write(writer)?; - writer.write_all(&byte_utils::be64_to_array(*amount))?; - writer.write_all(&byte_utils::be32_to_array(*locktime))?; + htlc.write(writer)?; }, &InputMaterial::LocalHTLC { ref preimage, ref amount } => { writer.write_all(&[2; 1])?; @@@ -556,37 -435,31 +498,37 @@@ impl Readable for InputMaterial fn read(reader: &mut R) -> Result { let input_material = match ::read(reader)? { 0 => { - let witness_script = Readable::read(reader)?; - let pubkey = Readable::read(reader)?; - let key = Readable::read(reader)?; - let is_htlc = Readable::read(reader)?; + let per_commitment_point = Readable::read(reader)?; + let remote_delayed_payment_base_key = Readable::read(reader)?; + let remote_htlc_base_key = Readable::read(reader)?; + let per_commitment_key = Readable::read(reader)?; + let input_descriptor = Readable::read(reader)?; let amount = Readable::read(reader)?; + let htlc = Readable::read(reader)?; + let on_remote_tx_csv = Readable::read(reader)?; InputMaterial::Revoked { - witness_script, - pubkey, - key, - is_htlc, - amount + per_commitment_point, + remote_delayed_payment_base_key, + remote_htlc_base_key, + per_commitment_key, + input_descriptor, + amount, + htlc, + on_remote_tx_csv } }, 1 => { - let witness_script = Readable::read(reader)?; - let key = Readable::read(reader)?; + let per_commitment_point = Readable::read(reader)?; + let remote_delayed_payment_base_key = Readable::read(reader)?; + let remote_htlc_base_key = Readable::read(reader)?; let preimage = Readable::read(reader)?; - let amount = Readable::read(reader)?; - let locktime = Readable::read(reader)?; + let htlc = Readable::read(reader)?; InputMaterial::RemoteHTLC { - witness_script, - key, + per_commitment_point, + remote_delayed_payment_base_key, + remote_htlc_base_key, preimage, - amount, - locktime + htlc } }, 2 => { @@@ -785,7 -658,7 +727,7 @@@ pub struct ChannelMonitor, + broadcasted_local_revokable_script: Option<(Script, PublicKey, PublicKey)>, remote_payment_script: Script, shutdown_script: Script, @@@ -794,13 -667,15 +736,13 @@@ current_remote_commitment_txid: Option, prev_remote_commitment_txid: Option, - their_htlc_base_key: PublicKey, - their_delayed_payment_base_key: PublicKey, + remote_tx_cache: RemoteCommitmentTransaction, funding_redeemscript: Script, channel_value_satoshis: u64, // first is the idx of the first of the two revocation points their_cur_revocation_points: Option<(u64, PublicKey, Option)>, - our_to_self_delay: u16, - their_to_self_delay: u16, + on_local_tx_csv: u16, commitment_secrets: CounterpartyCommitmentSecrets, remote_claimable_outpoints: HashMap>)>>, @@@ -870,6 -745,70 +812,70 @@@ secp_ctx: Secp256k1, //TODO: dedup this a bit... } + /// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between + /// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing + /// events to it, while also taking any add/update_monitor events and passing them to some remote + /// server(s). + /// + /// In general, you must always have at least one local copy in memory, which must never fail to + /// update (as it is responsible for broadcasting the latest state in case the channel is closed), + /// and then persist it to various on-disk locations. If, for some reason, the in-memory copy fails + /// to update (eg out-of-memory or some other condition), you must immediately shut down without + /// taking any further action such as writing the current state to disk. This should likely be + /// accomplished via panic!() or abort(). + /// + /// Note that any updates to a channel's monitor *must* be applied to each instance of the + /// channel's monitor everywhere (including remote watchtowers) *before* this function returns. If + /// an update occurs and a remote watchtower is left with old state, it may broadcast transactions + /// which we have revoked, allowing our counterparty to claim all funds in the channel! + /// + /// User needs to notify implementors of ManyChannelMonitor when a new block is connected or + /// disconnected using their `block_connected` and `block_disconnected` methods. However, rather + /// than calling these methods directly, the user should register implementors as listeners to the + /// BlockNotifier and call the BlockNotifier's `block_(dis)connected` methods, which will notify + /// all registered listeners in one go. + pub trait ManyChannelMonitor: Send + Sync { + /// The concrete type which signs for transactions and provides access to our channel public + /// keys. + type Keys: ChannelKeys; + + /// Adds a monitor for the given `funding_txo`. + /// + /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with + /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected + /// callbacks with the funding transaction, or any spends of it. + /// + /// Further, the implementer must also ensure that each output returned in + /// monitor.get_outputs_to_watch() is registered to ensure that the provided monitor learns about + /// any spends of any of the outputs. + /// + /// Any spends of outputs which should have been registered which aren't passed to + /// ChannelMonitors via block_connected may result in FUNDS LOSS. + fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; + + /// Updates a monitor for the given `funding_txo`. + /// + /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with + /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected + /// callbacks with the funding transaction, or any spends of it. + /// + /// Further, the implementer must also ensure that each output returned in + /// monitor.get_watch_outputs() is registered to ensure that the provided monitor learns about + /// any spends of any of the outputs. + /// + /// Any spends of outputs which should have been registered which aren't passed to + /// ChannelMonitors via block_connected may result in FUNDS LOSS. + fn update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr>; + + /// Used by ChannelManager to get list of HTLC resolved onchain and which needed to be updated + /// with success or failure. + /// + /// You should probably just call through to + /// ChannelMonitor::get_and_clear_pending_htlcs_updated() for each ChannelMonitor and return + /// the full list. + fn get_and_clear_pending_htlcs_updated(&self) -> Vec; + } + #[cfg(any(test, feature = "fuzztarget"))] /// Used only in testing and fuzztarget to check serialization roundtrips don't change the /// underlying object @@@ -884,11 -823,13 +890,11 @@@ impl PartialE self.funding_info != other.funding_info || self.current_remote_commitment_txid != other.current_remote_commitment_txid || self.prev_remote_commitment_txid != other.prev_remote_commitment_txid || - self.their_htlc_base_key != other.their_htlc_base_key || - self.their_delayed_payment_base_key != other.their_delayed_payment_base_key || + self.remote_tx_cache != other.remote_tx_cache || self.funding_redeemscript != other.funding_redeemscript || self.channel_value_satoshis != other.channel_value_satoshis || 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 || + self.on_local_tx_csv != other.on_local_tx_csv || self.commitment_secrets != other.commitment_secrets || self.remote_claimable_outpoints != other.remote_claimable_outpoints || self.remote_commitment_txn_on_chain != other.remote_commitment_txn_on_chain || @@@ -951,7 -892,8 +957,7 @@@ impl ChannelMonitor { pub(super) fn new(keys: ChanSigner, shutdown_pubkey: &PublicKey, - our_to_self_delay: u16, destination_script: &Script, funding_info: (OutPoint, Script), - their_htlc_base_key: &PublicKey, their_delayed_payment_base_key: &PublicKey, - their_to_self_delay: u16, funding_redeemscript: Script, channel_value_satoshis: u64, + on_remote_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script), + remote_htlc_base_key: &PublicKey, remote_delayed_payment_base_key: &PublicKey, + on_local_tx_csv: u16, funding_redeemscript: Script, channel_value_satoshis: u64, commitment_transaction_number_obscure_factor: u64, initial_local_commitment_tx: LocalCommitmentTransaction) -> ChannelMonitor { @@@ -1116,9 -1059,7 +1122,9 @@@ let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize()); let remote_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script(); - let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay); + let remote_tx_cache = RemoteCommitmentTransaction { remote_delayed_payment_base_key: *remote_delayed_payment_base_key, remote_htlc_base_key: *remote_htlc_base_key, on_remote_tx_csv, per_htlc: HashMap::new() }; + + let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), on_local_tx_csv); 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; @@@ -1153,12 -1094,14 +1159,12 @@@ current_remote_commitment_txid: None, prev_remote_commitment_txid: None, - their_htlc_base_key: their_htlc_base_key.clone(), - their_delayed_payment_base_key: their_delayed_payment_base_key.clone(), + remote_tx_cache, funding_redeemscript, channel_value_satoshis: channel_value_satoshis, their_cur_revocation_points: None, - our_to_self_delay, - their_to_self_delay, + on_local_tx_csv, commitment_secrets: CounterpartyCommitmentSecrets::new(), remote_claimable_outpoints: HashMap::new(), @@@ -1256,7 -1199,7 +1262,7 @@@ log_trace!(logger, "New potential remote commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx)); self.prev_remote_commitment_txid = self.current_remote_commitment_txid.take(); self.current_remote_commitment_txid = Some(new_txid); - self.remote_claimable_outpoints.insert(new_txid, htlc_outputs); + self.remote_claimable_outpoints.insert(new_txid, htlc_outputs.clone()); self.current_remote_commitment_number = commitment_number; //TODO: Merge this into the other per-remote-transaction output storage stuff match self.their_cur_revocation_points { @@@ -1277,20 -1220,13 +1283,20 @@@ self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); } } + let mut htlcs = Vec::with_capacity(htlc_outputs.len()); + for htlc in htlc_outputs { + if htlc.0.transaction_output_index.is_some() { + htlcs.push(htlc.0); + } + } + self.remote_tx_cache.per_htlc.insert(new_txid, htlcs); } /// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The /// monitor watches for timeouts and may broadcast it if we approach such a timeout. Thus, it /// is important that any clones of this channel monitor (including remote clones) by kept /// up-to-date as our local commitment transaction is updated. - /// Panics if set_their_to_self_delay has never been called. + /// Panics if set_on_local_tx_csv has never been called. pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>) -> 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")); @@@ -1493,16 -1429,19 +1499,16 @@@ let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let b_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().htlc_basepoint)); - let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key)); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_htlc_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.remote_tx_cache.remote_delayed_payment_base_key)); - let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); + let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.remote_tx_cache.on_remote_tx_csv, &delayed_key); let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); // First, process non-htlc outputs (to_local & to_remote) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let witness_data = InputMaterial::Revoked { witness_script: revokeable_redeemscript.clone(), pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: outp.value }; - claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); + let witness_data = InputMaterial::Revoked { per_commitment_point, remote_delayed_payment_base_key: self.remote_tx_cache.remote_delayed_payment_base_key, remote_htlc_base_key: self.remote_tx_cache.remote_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value, htlc: None, on_remote_tx_csv: self.remote_tx_cache.on_remote_tx_csv}; + claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.remote_tx_cache.on_remote_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); } } @@@ -1510,11 -1449,13 +1516,11 @@@ if let Some(ref per_commitment_data) = per_commitment_option { for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); if transaction_output_index as usize >= tx.output.len() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 || - tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { + tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } - let witness_data = InputMaterial::Revoked { witness_script: expected_script, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: true, amount: tx.output[transaction_output_index as usize].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, remote_delayed_payment_base_key: self.remote_tx_cache.remote_delayed_payment_base_key, remote_htlc_base_key: self.remote_tx_cache.remote_htlc_base_key, per_commitment_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value, htlc: Some(htlc.clone()), on_remote_tx_csv: self.remote_tx_cache.on_remote_tx_csv}; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@@ -1632,24 -1573,24 +1638,24 @@@ if revocation_points.0 == commitment_number + 1 { Some(point) } else { None } } else { None }; if let Some(revocation_point) = revocation_point_option { - let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &self.keys.pubkeys().revocation_basepoint)); - let b_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &self.keys.pubkeys().htlc_basepoint)); - let htlc_privkey = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &self.keys.htlc_base_key())); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &self.their_htlc_base_key)); + self.remote_payment_script = { + // Note that the Network here is ignored as we immediately drop the address for the + // script_pubkey version + let payment_hash160 = WPubkeyHash::hash(&PublicKey::from_secret_key(&self.secp_ctx, &self.keys.payment_key()).serialize()); + Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script() + }; // Then, try to find htlc outputs for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); if transaction_output_index as usize >= tx.output.len() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 || - tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { + tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None }; let aggregable = if !htlc.offered { false } else { true }; if preimage.is_some() || !htlc.offered { - let witness_data = InputMaterial::RemoteHTLC { witness_script: expected_script, key: htlc_privkey, preimage, amount: htlc.amount_msat / 1000, locktime: htlc.cltv_expiry }; + let witness_data = InputMaterial::RemoteHTLC { per_commitment_point: *revocation_point, remote_delayed_payment_base_key: self.remote_tx_cache.remote_delayed_payment_base_key, remote_htlc_base_key: self.remote_tx_cache.remote_htlc_base_key, preimage, htlc: htlc.clone() }; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@@ -1679,19 -1620,25 +1685,19 @@@ let secret = if let Some(secret) = self.get_secret(commitment_number) { secret } else { return (Vec::new(), None); }; let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); - let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.their_delayed_payment_base_key)); - let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); log_trace!(logger, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let witness_data = InputMaterial::Revoked { witness_script: redeemscript, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: tx.output[0].value }; - let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); + let witness_data = InputMaterial::Revoked { per_commitment_point, remote_delayed_payment_base_key: self.remote_tx_cache.remote_delayed_payment_base_key, remote_htlc_base_key: self.remote_tx_cache.remote_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value, htlc: None, on_remote_tx_csv: self.remote_tx_cache.on_remote_tx_csv }; + let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.remote_tx_cache.on_remote_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); (claimable_outpoints, Some((htlc_txid, tx.output.clone()))) } - fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec, Vec, Option<(Script, SecretKey, Script)>) { + fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec, Vec, Option<(Script, PublicKey, PublicKey)>) { let mut claim_requests = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); - let redeemscript = chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.their_to_self_delay, &local_tx.delayed_payment_key); - let broadcasted_local_revokable_script = if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, &local_tx.per_commitment_point, self.keys.delayed_payment_base_key()) { - Some((redeemscript.to_v0_p2wsh(), local_delayedkey, redeemscript)) - } else { None }; + let redeemscript = chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.on_local_tx_csv, &local_tx.delayed_payment_key); + let broadcasted_local_revokable_script = Some((redeemscript.to_v0_p2wsh(), local_tx.per_commitment_point.clone(), local_tx.revocation_key.clone())); for &(ref htlc, _, _) in local_tx.htlc_outputs.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { @@@ -2190,19 -2137,18 +2196,19 @@@ if broadcasted_local_revokable_script.0 == outp.script_pubkey { spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH { outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, - key: broadcasted_local_revokable_script.1, - witness_script: broadcasted_local_revokable_script.2.clone(), - to_self_delay: self.their_to_self_delay, + per_commitment_point: broadcasted_local_revokable_script.1, + to_self_delay: self.on_local_tx_csv, output: outp.clone(), + key_derivation_params: self.keys.key_derivation_params(), + remote_revocation_pubkey: broadcasted_local_revokable_script.2.clone(), }); break; } } else if self.remote_payment_script == outp.script_pubkey { - spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WPKH { + spendable_output = Some(SpendableOutputDescriptor::StaticOutputRemotePayment { outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, - key: self.keys.payment_key().clone(), output: outp.clone(), + key_derivation_params: self.keys.key_derivation_params(), }); break; } else if outp.script_pubkey == self.shutdown_script { @@@ -2253,9 -2199,9 +2259,9 @@@ impl::read(reader)? { 0 => { let revokable_address = Readable::read(reader)?; - let local_delayedkey = Readable::read(reader)?; + let per_commitment_point = Readable::read(reader)?; let revokable_script = Readable::read(reader)?; - Some((revokable_address, local_delayedkey, revokable_script)) + Some((revokable_address, per_commitment_point, revokable_script)) }, 1 => { None }, _ => return Err(DecodeError::InvalidValue), @@@ -2274,7 -2220,8 +2280,7 @@@ let current_remote_commitment_txid = Readable::read(reader)?; let prev_remote_commitment_txid = Readable::read(reader)?; - let their_htlc_base_key = Readable::read(reader)?; - let their_delayed_payment_base_key = Readable::read(reader)?; + let remote_tx_cache = Readable::read(reader)?; let funding_redeemscript = Readable::read(reader)?; let channel_value_satoshis = Readable::read(reader)?; @@@ -2293,7 -2240,8 +2299,7 @@@ } }; - let our_to_self_delay: u16 = Readable::read(reader)?; - let their_to_self_delay: u16 = Readable::read(reader)?; + let on_local_tx_csv: u16 = Readable::read(reader)?; let commitment_secrets = Readable::read(reader)?; @@@ -2482,12 -2430,14 +2488,12 @@@ current_remote_commitment_txid, prev_remote_commitment_txid, - their_htlc_base_key, - their_delayed_payment_base_key, + remote_tx_cache, funding_redeemscript, channel_value_satoshis, their_cur_revocation_points, - our_to_self_delay, - their_to_self_delay, + on_local_tx_csv, commitment_secrets, remote_claimable_outpoints, @@@ -2605,7 -2555,6 +2611,7 @@@ mod tests SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], 0, + (0, 0) ); // Prune with one old state and a local commitment tx holding a few overlaps with the diff --combined lightning/src/ln/functional_tests.rs index f2ea0c02,da475569..13125a36 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@@ -822,7 -822,7 +822,7 @@@ fn pre_funding_lock_shutdown_test() nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![tx.clone()]}, 1); nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![tx.clone()]}, 1); - nodes[0].node.close_channel(&OutPoint::new(tx.txid(), 0).to_channel_id()).unwrap(); + nodes[0].node.close_channel(&OutPoint { txid: tx.txid(), index: 0 }.to_channel_id()).unwrap(); let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()); nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown); let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); @@@ -3111,7 -3111,7 +3111,7 @@@ fn test_force_close_fail_back() // Now check that if we add the preimage to ChannelMonitor it broadcasts our HTLC-Success.. { let mut monitors = nodes[2].chan_monitor.simple_monitor.monitors.lock().unwrap(); - monitors.get_mut(&OutPoint::new(Txid::from_slice(&payment_event.commitment_msg.channel_id[..]).unwrap(), 0)).unwrap() + monitors.get_mut(&OutPoint{ txid: Txid::from_slice(&payment_event.commitment_msg.channel_id[..]).unwrap(), index: 0 }).unwrap() .provide_payment_preimage(&our_payment_hash, &our_payment_preimage); } nodes[2].block_notifier.block_connected_checked(&header, 1, &[&tx], &[1]); @@@ -4265,7 -4265,7 +4265,7 @@@ fn test_manager_serialize_deserialize_i } macro_rules! check_spendable_outputs { - ($node: expr, $der_idx: expr) => { + ($node: expr, $der_idx: expr, $keysinterface: expr, $chan_value: expr) => { { let events = $node.chan_monitor.simple_monitor.get_and_clear_pending_events(); let mut txn = Vec::new(); @@@ -4274,7 -4274,7 +4274,7 @@@ Event::SpendableOutputs { ref outputs } => { for outp in outputs { match *outp { - SpendableOutputDescriptor::DynamicOutputP2WPKH { ref outpoint, ref key, ref output } => { + SpendableOutputDescriptor::StaticOutputRemotePayment { ref outpoint, ref output, ref key_derivation_params } => { let input = TxIn { previous_output: outpoint.clone(), script_sig: Script::new(), @@@ -4292,17 -4292,16 +4292,17 @@@ output: vec![outp], }; let secp_ctx = Secp256k1::new(); - let remotepubkey = PublicKey::from_secret_key(&secp_ctx, &key); + let keys = $keysinterface.derive_channel_keys($chan_value, key_derivation_params.0, key_derivation_params.1); + let remotepubkey = PublicKey::from_secret_key(&secp_ctx, &keys.payment_key()); let witness_script = Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: remotepubkey}, Network::Testnet).script_pubkey(); let sighash = Message::from_slice(&bip143::SighashComponents::new(&spend_tx).sighash_all(&spend_tx.input[0], &witness_script, output.value)[..]).unwrap(); - let remotesig = secp_ctx.sign(&sighash, key); + let remotesig = secp_ctx.sign(&sighash, &keys.payment_key()); spend_tx.input[0].witness.push(remotesig.serialize_der().to_vec()); spend_tx.input[0].witness[0].push(SigHashType::All as u8); spend_tx.input[0].witness.push(remotepubkey.serialize().to_vec()); txn.push(spend_tx); }, - SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref key, ref witness_script, ref to_self_delay, ref output } => { + SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref key_derivation_params, ref remote_revocation_pubkey } => { let input = TxIn { previous_output: outpoint.clone(), script_sig: Script::new(), @@@ -4320,18 -4319,12 +4320,18 @@@ output: vec![outp], }; let secp_ctx = Secp256k1::new(); - let sighash = Message::from_slice(&bip143::SighashComponents::new(&spend_tx).sighash_all(&spend_tx.input[0], witness_script, output.value)[..]).unwrap(); - let local_delaysig = secp_ctx.sign(&sighash, key); - spend_tx.input[0].witness.push(local_delaysig.serialize_der().to_vec()); - spend_tx.input[0].witness[0].push(SigHashType::All as u8); - spend_tx.input[0].witness.push(vec!()); - spend_tx.input[0].witness.push(witness_script.clone().into_bytes()); + let keys = $keysinterface.derive_channel_keys($chan_value, key_derivation_params.0, key_derivation_params.1); + if let Ok(delayed_payment_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, keys.delayed_payment_base_key()) { + + let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); + let witness_script = chan_utils::get_revokeable_redeemscript(remote_revocation_pubkey, *to_self_delay, &delayed_payment_pubkey); + let sighash = Message::from_slice(&bip143::SighashComponents::new(&spend_tx).sighash_all(&spend_tx.input[0], &witness_script, output.value)[..]).unwrap(); + let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key); + spend_tx.input[0].witness.push(local_delayedsig.serialize_der().to_vec()); + spend_tx.input[0].witness[0].push(SigHashType::All as u8); + spend_tx.input[0].witness.push(vec!()); //MINIMALIF + spend_tx.input[0].witness.push(witness_script.clone().into_bytes()); + } else { panic!() } txn.push(spend_tx); }, SpendableOutputDescriptor::StaticOutput { ref outpoint, ref output } => { @@@ -4404,7 -4397,7 +4404,7 @@@ fn test_claim_sizeable_push_msat() nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()] }, 0); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], node_txn[0]); } @@@ -4434,7 -4427,7 +4434,7 @@@ fn test_claim_on_remote_sizeable_push_m check_added_monitors!(nodes[1], 1); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 2); assert_eq!(spend_txn[0], spend_txn[1]); check_spends!(spend_txn[0], node_txn[0]); @@@ -4467,7 -4460,7 +4467,7 @@@ fn test_claim_on_remote_revoked_sizeabl nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 3); assert_eq!(spend_txn[0], spend_txn[1]); // to_remote output on revoked remote commitment_tx check_spends!(spend_txn[0], revoked_local_txn[0]); @@@ -4518,7 -4511,7 +4518,7 @@@ fn test_static_spendable_outputs_preima nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], node_txn[0]); } @@@ -4565,7 -4558,7 +4565,7 @@@ fn test_static_spendable_outputs_timeou connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); expect_payment_failed!(nodes[1], our_payment_hash, true); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 3); // SpendableOutput: remote_commitment_tx.to_remote (*2), timeout_tx.output (*1) check_spends!(spend_txn[2], node_txn[0].clone()); } @@@ -4601,7 -4594,7 +4601,7 @@@ fn test_static_spendable_outputs_justic nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone()] }, 1); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], node_txn[0]); } @@@ -4656,7 -4649,7 +4656,7 @@@ fn test_static_spendable_outputs_justic connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); // Check B's ChannelMonitor was able to generate the right spendable output descriptor - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 2); check_spends!(spend_txn[0], node_txn[0]); check_spends!(spend_txn[1], node_txn[2]); @@@ -4706,7 -4699,7 +4706,7 @@@ fn test_static_spendable_outputs_justic connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.bitcoin_hash()); // Check A's ChannelMonitor was able to generate the right spendable output descriptor - let spend_txn = check_spendable_outputs!(nodes[0], 1); + let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000); assert_eq!(spend_txn.len(), 5); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking assert_eq!(spend_txn[0], spend_txn[1]); assert_eq!(spend_txn[0], spend_txn[2]); @@@ -4976,7 -4969,7 +4976,7 @@@ fn test_dynamic_spendable_outputs_local connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 201, true, header_201.bitcoin_hash()); // Verify that B is able to spend its own HTLC-Success tx thanks to spendable output event given back by its ChannelMonitor - let spend_txn = check_spendable_outputs!(nodes[1], 1); + let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 2); check_spends!(spend_txn[0], node_txn[0]); check_spends!(spend_txn[1], node_txn[1]); @@@ -5273,86 -5266,13 +5273,86 @@@ fn test_dynamic_spendable_outputs_local expect_payment_failed!(nodes[0], our_payment_hash, true); // Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor - let spend_txn = check_spendable_outputs!(nodes[0], 1); + let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000); assert_eq!(spend_txn.len(), 3); assert_eq!(spend_txn[0], spend_txn[1]); check_spends!(spend_txn[0], local_txn[0]); check_spends!(spend_txn[2], htlc_timeout); } +#[test] +fn test_key_derivation_params() { + // This test is a copy of test_dynamic_spendable_outputs_local_htlc_timeout_tx, with + // a key manager rotation to test that key_derivation_params returned in DynamicOutputP2WSH + // let us re-derive the channel key set to then derive a delayed_payment_key. + + let chanmon_cfgs = create_chanmon_cfgs(3); + + // We manually create the node configuration to backup the seed. + let mut rng = thread_rng(); + let mut seed = [0; 32]; + rng.fill_bytes(&mut seed); + let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); + let chan_monitor = test_utils::TestChannelMonitor::new(&chanmon_cfgs[0].chain_monitor, &chanmon_cfgs[0].tx_broadcaster, &chanmon_cfgs[0].logger, &chanmon_cfgs[0].fee_estimator); + let node = NodeCfg { chain_monitor: &chanmon_cfgs[0].chain_monitor, logger: &chanmon_cfgs[0].logger, tx_broadcaster: &chanmon_cfgs[0].tx_broadcaster, fee_estimator: &chanmon_cfgs[0].fee_estimator, chan_monitor, keys_manager, node_seed: seed }; + let mut node_cfgs = create_node_cfgs(3, &chanmon_cfgs); + node_cfgs.remove(0); + node_cfgs.insert(0, node); + + let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); + let nodes = create_network(3, &node_cfgs, &node_chanmgrs); + + // Create some initial channels + // Create a dummy channel to advance index by one and thus test re-derivation correctness + // for node 0 + let chan_0 = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::known(), InitFeatures::known()); + let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); + assert_ne!(chan_0.3.output[0].script_pubkey, chan_1.3.output[0].script_pubkey); + + let (_, our_payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1])[..], 9000000); + let local_txn_0 = get_local_commitment_txn!(nodes[0], chan_0.2); + let local_txn_1 = get_local_commitment_txn!(nodes[0], chan_1.2); + assert_eq!(local_txn_1[0].input.len(), 1); + check_spends!(local_txn_1[0], chan_1.3); + + // We check funding pubkey are unique + let (from_0_funding_key_0, from_0_funding_key_1) = (PublicKey::from_slice(&local_txn_0[0].input[0].witness[3][2..35]), PublicKey::from_slice(&local_txn_0[0].input[0].witness[3][36..69])); + let (from_1_funding_key_0, from_1_funding_key_1) = (PublicKey::from_slice(&local_txn_1[0].input[0].witness[3][2..35]), PublicKey::from_slice(&local_txn_1[0].input[0].witness[3][36..69])); + if from_0_funding_key_0 == from_1_funding_key_0 + || from_0_funding_key_0 == from_1_funding_key_1 + || from_0_funding_key_1 == from_1_funding_key_0 + || from_0_funding_key_1 == from_1_funding_key_1 { + panic!("Funding pubkeys aren't unique"); + } + + // Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![local_txn_1[0].clone()] }, 200); + check_closed_broadcast!(nodes[0], false); + check_added_monitors!(nodes[0], 1); + + let htlc_timeout = { + let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(node_txn[0].input.len(), 1); + assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[0], local_txn_1[0]); + node_txn[0].clone() + }; + + let header_201 = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected(&Block { header: header_201, txdata: vec![htlc_timeout.clone()] }, 201); + connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 201, true, header_201.bitcoin_hash()); + expect_payment_failed!(nodes[0], our_payment_hash, true); + + // Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor + let new_keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); + let spend_txn = check_spendable_outputs!(nodes[0], 1, new_keys_manager, 100000); + assert_eq!(spend_txn.len(), 3); + assert_eq!(spend_txn[0], spend_txn[1]); + check_spends!(spend_txn[0], local_txn_1[0]); + check_spends!(spend_txn[2], htlc_timeout); +} + #[test] fn test_static_output_closing_tx() { let chanmon_cfgs = create_chanmon_cfgs(2); @@@ -5369,14 -5289,14 +5369,14 @@@ nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![closing_tx.clone()] }, 0); connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[0], 2); + let spend_txn = check_spendable_outputs!(nodes[0], 2, node_cfgs[0].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], closing_tx); nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![closing_tx.clone()] }, 0); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[1], 2); + let spend_txn = check_spendable_outputs!(nodes[1], 2, node_cfgs[1].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], closing_tx); } @@@ -6980,7 -6900,7 +6980,7 @@@ fn test_upfront_shutdown_script() // We test that in case of peer committing upfront to a script, if it changes at closing, we refuse to sign let flags = InitFeatures::known(); let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1000000, 1000000, flags.clone(), flags.clone()); - nodes[0].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap(); + nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap(); let mut node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id()); node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh(); // Test we enforce upfront_scriptpbukey if by providing a diffrent one at closing that we disconnect peer @@@ -6990,7 -6910,7 +6990,7 @@@ // We test that in case of peer committing upfront to a script, if it doesn't change at closing, we sign let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1000000, 1000000, flags.clone(), flags.clone()); - nodes[0].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap(); + nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap(); let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id()); // We test that in case of peer committing upfront to a script, if it oesn't change at closing, we sign nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown); @@@ -7004,7 -6924,7 +7004,7 @@@ // We test that if case of peer non-signaling we don't enforce committed script at channel opening let flags_no = InitFeatures::known().clear_upfront_shutdown_script(); let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, flags_no, flags.clone()); - nodes[0].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap(); + nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap(); let mut node_1_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()); node_1_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh(); nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_1_shutdown); @@@ -7018,7 -6938,7 +7018,7 @@@ // We test that if user opt-out, we provide a zero-length script at channel opening and we are able to close // channel smoothly, opt-out is from channel initiator here let chan = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 1000000, 1000000, flags.clone(), flags.clone()); - nodes[1].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap(); + nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap(); let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh(); nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown); @@@ -7032,7 -6952,7 +7032,7 @@@ //// We test that if user opt-out, we provide a zero-length script at channel opening and we are able to close //// channel smoothly let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000, flags.clone(), flags.clone()); - nodes[1].node.close_channel(&OutPoint::new(chan.3.txid(), 0).to_channel_id()).unwrap(); + nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id()).unwrap(); let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh(); nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown); @@@ -7218,7 -7138,7 +7218,7 @@@ fn test_data_loss_protect() let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![node_txn[0].clone()]}, 0); connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 0, true, header.bitcoin_hash()); - let spend_txn = check_spendable_outputs!(nodes[0], 1); + let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000); assert_eq!(spend_txn.len(), 1); check_spends!(spend_txn[0], node_txn[0]); } @@@ -7839,7 -7759,7 +7839,7 @@@ fn test_bump_txn_sanitize_tracking_maps connect_blocks(&nodes[0].block_notifier, 5, 130, false, header_130.bitcoin_hash()); { let monitors = nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap(); - if let Some(monitor) = monitors.get(&OutPoint::new(chan.3.txid(), 0)) { + if let Some(monitor) = monitors.get(&OutPoint { txid: chan.3.txid(), index: 0 }) { assert!(monitor.onchain_tx_handler.pending_claim_requests.is_empty()); assert!(monitor.onchain_tx_handler.claimable_outpoints.is_empty()); } diff --combined lightning/src/ln/peer_handler.rs index e75c2c96,009fa73f..12d72846 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@@ -10,15 -10,16 +10,16 @@@ use bitcoin::secp256k1::key::{SecretKey use ln::features::InitFeatures; use ln::msgs; - use ln::msgs::ChannelMessageHandler; + use ln::msgs::{ChannelMessageHandler, RoutingMessageHandler}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; -use util::ser::VecWriter; +use util::ser::{VecWriter, Writeable}; use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use ln::wire; use ln::wire::Encode; use util::byte_utils; use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; + use routing::network_graph::NetGraphMsgHandler; use std::collections::{HashMap,hash_map,HashSet,LinkedList}; use std::sync::{Arc, Mutex}; @@@ -31,13 -32,15 +32,15 @@@ use bitcoin::hashes::sha256::HashEngin use bitcoin::hashes::{HashEngine, Hash}; /// Provides references to trait impls which handle different types of messages. - pub struct MessageHandler where CM::Target: msgs::ChannelMessageHandler { + pub struct MessageHandler where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler { /// A message handler which handles messages specific to channels. Usually this is just a /// ChannelManager object. pub chan_handler: CM, /// A message handler which handles messages updating our knowledge of the network channel /// graph. Usually this is just a NetGraphMsgHandlerMonitor object. - pub route_handler: Arc, + pub route_handler: RM, } /// Provides an object which can be used to send data to and which uniquely identifies a connection @@@ -83,7 -86,7 +86,7 @@@ pub trait SocketDescriptor : cmp::Eq + pub struct PeerHandleError { /// Used to indicate that we probably can't make any future connections to this peer, implying /// we should go ahead and force-close any channels we have with it. - no_connection_possible: bool, + pub no_connection_possible: bool, } impl fmt::Debug for PeerHandleError { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { @@@ -171,7 -174,7 +174,7 @@@ fn _check_usize_is_32_or_64() /// lifetimes). Other times you can afford a reference, which is more efficient, in which case /// SimpleRefPeerManager is the more appropriate type. Defining these type aliases prevents /// issues such as overly long function definitions. - pub type SimpleArcPeerManager = Arc, Arc>>; + pub type SimpleArcPeerManager = Arc, Arc, Arc>>, Arc>>; /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference /// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't @@@ -179,7 -182,7 +182,7 @@@ /// usage of lightning-net-tokio (since tokio::spawn requires parameters with static lifetimes). /// But if this is not necessary, using a reference is more efficient. Defining these type aliases /// helps with issues such as long function definitions. - pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, SD, M, T, F, L> = PeerManager, &'e L>; + pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, SD, M, T, F, C, L> = PeerManager, &'e NetGraphMsgHandler<&'g C, &'f L>, &'f L>; /// A PeerManager manages a set of peers, described by their SocketDescriptor and marshalls socket /// events into messages which it passes on to its MessageHandlers. @@@ -189,8 -192,11 +192,11 @@@ /// essentially you should default to using a SimpleRefPeerManager, and use a /// SimpleArcPeerManager when you require a PeerManager with a static lifetime, such as when /// you're using lightning-net-tokio. - pub struct PeerManager where CM::Target: msgs::ChannelMessageHandler, L::Target: Logger { - message_handler: MessageHandler, + pub struct PeerManager where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { + message_handler: MessageHandler, peers: Mutex>, our_node_secret: SecretKey, ephemeral_key_midstate: Sha256Engine, @@@ -213,11 -219,14 +219,14 @@@ macro_rules! encode_msg /// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds. /// PeerIds may repeat, but only after socket_disconnected() has been called. - impl PeerManager where CM::Target: msgs::ChannelMessageHandler, L::Target: Logger { + impl PeerManager where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { /// Constructs a new PeerManager with the given message handlers and node_id secret key /// ephemeral_random_data is used to derive per-connection ephemeral keys and must be /// cryptographically secure random bytes. - pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: L) -> PeerManager { + pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: L) -> Self { let mut ephemeral_key_midstate = Sha256::engine(); ephemeral_key_midstate.input(ephemeral_random_data); @@@ -459,17 -468,6 +468,17 @@@ } } + /// Append a message to a peer's pending outbound/write buffer, and update the map of peers needing sends accordingly. + fn enqueue_message(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, descriptor: Descriptor, message: &M) { + let mut buffer = VecWriter(Vec::new()); + wire::write(message, &mut buffer).unwrap(); // crash if the write failed + let encoded_message = buffer.0; + + log_trace!(self.logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_message[..])); + peers_needing_send.insert(descriptor); + } + fn do_read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { let pause_read = { let mut peers_lock = self.peers.lock().unwrap(); @@@ -492,6 -490,16 +501,6 @@@ if peer.pending_read_buffer_pos == peer.pending_read_buffer.len() { peer.pending_read_buffer_pos = 0; - macro_rules! encode_and_send_msg { - ($msg: expr) => { - { - log_trace!(self.logger, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(&$msg)[..])); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } - } - } - macro_rules! try_potential_handleerror { ($thing: expr) => { match $thing { @@@ -509,7 -517,7 +518,7 @@@ }, msgs::ErrorAction::SendErrorMessage { msg } => { log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - encode_and_send_msg!(msg); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &msg); continue; }, } @@@ -555,7 -563,7 +564,7 @@@ } let resp = msgs::Init { features }; - encode_and_send_msg!(resp); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); }, NextNoiseStep::ActThree => { let their_node_id = try_potential_handleerror!(peer.channel_encryptor.process_act_three(&peer.pending_read_buffer[..])); @@@ -654,7 -662,7 +663,7 @@@ } let resp = msgs::Init { features }; - encode_and_send_msg!(resp); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); } self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); @@@ -683,7 -691,7 +692,7 @@@ wire::Message::Ping(msg) => { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - encode_and_send_msg!(resp); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); } }, wire::Message::Pong(_msg) => { @@@ -1159,13 -1167,8 +1168,8 @@@ #[cfg(test)] mod tests { - use bitcoin::secp256k1::Signature; - use bitcoin::BitcoinHash; - use bitcoin::network::constants::Network; - use bitcoin::blockdata::constants::genesis_block; use ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor}; use ln::msgs; - use ln::features::ChannelFeatures; use util::events; use util::test_utils; @@@ -1175,9 -1178,8 +1179,8 @@@ use rand::{thread_rng, Rng}; use std; - use std::cmp::min; use std::sync::{Arc, Mutex}; - use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::atomic::Ordering; #[derive(Clone)] struct FileDescriptor { @@@ -1207,18 -1209,18 +1210,18 @@@ struct PeerManagerCfg { chan_handler: test_utils::TestChannelMessageHandler, + routing_handler: test_utils::TestRoutingMessageHandler, logger: test_utils::TestLogger, } fn create_peermgr_cfgs(peer_count: usize) -> Vec { let mut cfgs = Vec::new(); for _ in 0..peer_count { - let chan_handler = test_utils::TestChannelMessageHandler::new(); - let logger = test_utils::TestLogger::new(); cfgs.push( PeerManagerCfg{ - chan_handler, - logger, + chan_handler: test_utils::TestChannelMessageHandler::new(), + logger: test_utils::TestLogger::new(), + routing_handler: test_utils::TestRoutingMessageHandler::new(), } ); } @@@ -1226,22 -1228,19 +1229,19 @@@ cfgs } - fn create_network<'a>(peer_count: usize, cfgs: &'a Vec, routing_handlers: Option<&'a Vec>>) -> Vec> { + fn create_network<'a>(peer_count: usize, cfgs: &'a Vec) -> Vec> { let mut peers = Vec::new(); let mut rng = thread_rng(); let mut ephemeral_bytes = [0; 32]; rng.fill_bytes(&mut ephemeral_bytes); for i in 0..peer_count { - let router = if let Some(routers) = routing_handlers { routers[i].clone() } else { - Arc::new(test_utils::TestRoutingMessageHandler::new()) - }; let node_id = { let mut key_slice = [0;32]; rng.fill_bytes(&mut key_slice); SecretKey::from_slice(&key_slice).unwrap() }; - let msg_handler = MessageHandler { chan_handler: &cfgs[i].chan_handler, route_handler: router }; + let msg_handler = MessageHandler { chan_handler: &cfgs[i].chan_handler, route_handler: &cfgs[i].routing_handler }; let peer = PeerManager::new(msg_handler, node_id, &ephemeral_bytes, &cfgs[i].logger); peers.push(peer); } @@@ -1249,7 -1248,7 +1249,7 @@@ peers } - fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { + fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let secp_ctx = Secp256k1::new(); let a_id = PublicKey::from_secret_key(&secp_ctx, &peer_a.our_node_secret); let mut fd_a = FileDescriptor { fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())) }; @@@ -1262,7 -1261,7 +1262,7 @@@ (fd_a.clone(), fd_b.clone()) } - fn establish_connection_and_read_events<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { + fn establish_connection_and_read_events<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let (mut fd_a, mut fd_b) = establish_connection(peer_a, peer_b); assert_eq!(peer_b.read_event(&mut fd_b, &fd_a.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); assert_eq!(peer_a.read_event(&mut fd_a, &fd_b.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); @@@ -1275,7 -1274,7 +1275,7 @@@ // push a DisconnectPeer event to remove the node flagged by id let cfgs = create_peermgr_cfgs(2); let chan_handler = test_utils::TestChannelMessageHandler::new(); - let mut peers = create_network(2, &cfgs, None); + let mut peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); @@@ -1297,7 -1296,7 +1297,7 @@@ fn test_timer_tick_occurred() { // Create peers, a vector of two peer managers, perform initial set up and check that peers[0] has one Peer. let cfgs = create_peermgr_cfgs(2); - let peers = create_network(2, &cfgs, None); + let peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); @@@ -1310,119 -1309,13 +1310,13 @@@ assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 0); } - pub struct TestRoutingMessageHandler { - pub chan_upds_recvd: AtomicUsize, - pub chan_anns_recvd: AtomicUsize, - pub chan_anns_sent: AtomicUsize, - } - - impl TestRoutingMessageHandler { - pub fn new() -> Self { - TestRoutingMessageHandler { - chan_upds_recvd: AtomicUsize::new(0), - chan_anns_recvd: AtomicUsize::new(0), - chan_anns_sent: AtomicUsize::new(0), - } - } - - } - impl msgs::RoutingMessageHandler for TestRoutingMessageHandler { - fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result { - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_channel_announcement(&self, _msg: &msgs::ChannelAnnouncement) -> Result { - self.chan_anns_recvd.fetch_add(1, Ordering::AcqRel); - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result { - self.chan_upds_recvd.fetch_add(1, Ordering::AcqRel); - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {} - fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option, Option)> { - let mut chan_anns = Vec::new(); - const TOTAL_UPDS: u64 = 100; - let end: u64 = min(starting_point + batch_amount as u64, TOTAL_UPDS - self.chan_anns_sent.load(Ordering::Acquire) as u64); - for i in starting_point..end { - let chan_upd_1 = get_dummy_channel_update(i); - let chan_upd_2 = get_dummy_channel_update(i); - let chan_ann = get_dummy_channel_announcement(i); - - chan_anns.push((chan_ann, Some(chan_upd_1), Some(chan_upd_2))); - } - - self.chan_anns_sent.fetch_add(chan_anns.len(), Ordering::AcqRel); - chan_anns - } - - fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec { - Vec::new() - } - - fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { - true - } - } - - fn get_dummy_channel_announcement(short_chan_id: u64) -> msgs::ChannelAnnouncement { - use bitcoin::secp256k1::ffi::Signature as FFISignature; - let secp_ctx = Secp256k1::new(); - let network = Network::Testnet; - let node_1_privkey = SecretKey::from_slice(&[42; 32]).unwrap(); - let node_2_privkey = SecretKey::from_slice(&[41; 32]).unwrap(); - let node_1_btckey = SecretKey::from_slice(&[40; 32]).unwrap(); - let node_2_btckey = SecretKey::from_slice(&[39; 32]).unwrap(); - let unsigned_ann = msgs::UnsignedChannelAnnouncement { - features: ChannelFeatures::known(), - chain_hash: genesis_block(network).header.bitcoin_hash(), - short_channel_id: short_chan_id, - node_id_1: PublicKey::from_secret_key(&secp_ctx, &node_1_privkey), - node_id_2: PublicKey::from_secret_key(&secp_ctx, &node_2_privkey), - bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, &node_1_btckey), - bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, &node_2_btckey), - excess_data: Vec::new(), - }; - - msgs::ChannelAnnouncement { - node_signature_1: Signature::from(FFISignature::new()), - node_signature_2: Signature::from(FFISignature::new()), - bitcoin_signature_1: Signature::from(FFISignature::new()), - bitcoin_signature_2: Signature::from(FFISignature::new()), - contents: unsigned_ann, - } - } - - fn get_dummy_channel_update(short_chan_id: u64) -> msgs::ChannelUpdate { - use bitcoin::secp256k1::ffi::Signature as FFISignature; - let network = Network::Testnet; - msgs::ChannelUpdate { - signature: Signature::from(FFISignature::new()), - contents: msgs::UnsignedChannelUpdate { - chain_hash: genesis_block(network).header.bitcoin_hash(), - short_channel_id: short_chan_id, - timestamp: 0, - flags: 0, - cltv_expiry_delta: 0, - htlc_minimum_msat: 0, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: vec![], - } - } - } - #[test] fn test_do_attempt_write_data() { // Create 2 peers with custom TestRoutingMessageHandlers and connect them. let cfgs = create_peermgr_cfgs(2); - let mut routing_handlers: Vec> = Vec::new(); - let mut routing_handlers_concrete: Vec> = Vec::new(); - for _ in 0..2 { - let routing_handler = Arc::new(TestRoutingMessageHandler::new()); - routing_handlers.push(routing_handler.clone()); - routing_handlers_concrete.push(routing_handler.clone()); - } - let peers = create_network(2, &cfgs, Some(&routing_handlers)); + cfgs[0].routing_handler.request_full_sync.store(true, Ordering::Release); + cfgs[1].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); // By calling establish_connect, we trigger do_attempt_write_data between // the peers. Previously this function would mistakenly enter an infinite loop @@@ -1438,10 -1331,10 +1332,10 @@@ // Check that each peer has received the expected number of channel updates and channel // announcements. - assert_eq!(routing_handlers_concrete[0].clone().chan_upds_recvd.load(Ordering::Acquire), 100); - assert_eq!(routing_handlers_concrete[0].clone().chan_anns_recvd.load(Ordering::Acquire), 50); - assert_eq!(routing_handlers_concrete[1].clone().chan_upds_recvd.load(Ordering::Acquire), 100); - assert_eq!(routing_handlers_concrete[1].clone().chan_anns_recvd.load(Ordering::Acquire), 50); + assert_eq!(cfgs[0].routing_handler.chan_upds_recvd.load(Ordering::Acquire), 100); + assert_eq!(cfgs[0].routing_handler.chan_anns_recvd.load(Ordering::Acquire), 50); + assert_eq!(cfgs[1].routing_handler.chan_upds_recvd.load(Ordering::Acquire), 100); + assert_eq!(cfgs[1].routing_handler.chan_anns_recvd.load(Ordering::Acquire), 50); } #[test] @@@ -1449,11 -1342,8 +1343,8 @@@ // Inbound peer 0 requests initial_routing_sync, but outbound peer 1 does not. { let cfgs = create_peermgr_cfgs(2); - let routing_handlers: Vec> = vec![ - Arc::new(test_utils::TestRoutingMessageHandler::new().set_request_full_sync()), - Arc::new(test_utils::TestRoutingMessageHandler::new()), - ]; - let peers = create_network(2, &cfgs, Some(&routing_handlers)); + cfgs[0].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); let peer_0 = peers[0].peers.lock().unwrap(); @@@ -1469,11 -1359,8 +1360,8 @@@ // Outbound peer 1 requests initial_routing_sync, but inbound peer 0 does not. { let cfgs = create_peermgr_cfgs(2); - let routing_handlers: Vec> = vec![ - Arc::new(test_utils::TestRoutingMessageHandler::new()), - Arc::new(test_utils::TestRoutingMessageHandler::new().set_request_full_sync()), - ]; - let peers = create_network(2, &cfgs, Some(&routing_handlers)); + cfgs[1].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); let peer_0 = peers[0].peers.lock().unwrap(); diff --combined lightning/src/util/macro_logger.rs index 196ba9ea,7594041d..01038646 --- a/lightning/src/util/macro_logger.rs +++ b/lightning/src/util/macro_logger.rs @@@ -43,7 -43,7 +43,7 @@@ macro_rules! log_bytes pub(crate) struct DebugFundingChannelId<'a>(pub &'a Txid, pub u16); impl<'a> std::fmt::Display for DebugFundingChannelId<'a> { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - for i in OutPoint::new(self.0.clone(), self.1).to_channel_id().iter() { + for i in (OutPoint { txid: self.0.clone(), index: self.1 }).to_channel_id().iter() { write!(f, "{:02x}", i)?; } Ok(()) @@@ -132,7 -132,7 +132,7 @@@ impl<'a> std::fmt::Display for DebugSpe &SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, .. } => { write!(f, "DynamicOutputP2WSH {}:{} marked for spending", outpoint.txid, outpoint.vout)?; } - &SpendableOutputDescriptor::DynamicOutputP2WPKH { ref outpoint, .. } => { + &SpendableOutputDescriptor::StaticOutputRemotePayment { ref outpoint, .. } => { write!(f, "DynamicOutputP2WPKH {}:{} marked for spending", outpoint.txid, outpoint.vout)?; } } diff --combined lightning/src/util/test_utils.rs index 0e9c2025,e426ec2d..91af4202 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@@ -3,15 -3,16 +3,16 @@@ use chain::chaininterface::{Confirmatio use chain::transaction::OutPoint; use chain::keysinterface; use ln::channelmonitor; - use ln::features::InitFeatures; + use ln::features::{ChannelFeatures, InitFeatures}; use ln::msgs; - use ln::msgs::LightningError; use ln::channelmonitor::HTLCUpdate; use util::enforcing_trait_impls::EnforcingChannelKeys; use util::events; use util::logger::{Logger, Level, Record}; use util::ser::{Readable, Writer, Writeable}; + use bitcoin::BitcoinHash; + use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::script::{Builder, Script}; use bitcoin::blockdata::block::Block; @@@ -19,11 -20,12 +20,12 @@@ use bitcoin::blockdata::opcodes use bitcoin::network::constants::Network; use bitcoin::hash_types::{Txid, BlockHash}; - use bitcoin::secp256k1::{SecretKey, PublicKey}; + use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1, Signature}; use std::time::{SystemTime, UNIX_EPOCH}; use std::sync::Mutex; - use std::mem; + use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + use std::{cmp, mem}; use std::collections::HashMap; pub struct TestVecWriter(pub Vec); @@@ -66,7 -68,9 +68,9 @@@ impl<'a> TestChannelMonitor<'a> } } } - impl<'a> channelmonitor::ManyChannelMonitor for TestChannelMonitor<'a> { + impl<'a> channelmonitor::ManyChannelMonitor for TestChannelMonitor<'a> { + type Keys = EnforcingChannelKeys; + fn add_monitor(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { // At every point where we get a monitor update, we should be able to send a useful monitor // to a watchtower and disk... @@@ -170,41 -174,105 +174,105 @@@ impl events::MessageSendEventsProvider } } + fn get_dummy_channel_announcement(short_chan_id: u64) -> msgs::ChannelAnnouncement { + use bitcoin::secp256k1::ffi::Signature as FFISignature; + let secp_ctx = Secp256k1::new(); + let network = Network::Testnet; + let node_1_privkey = SecretKey::from_slice(&[42; 32]).unwrap(); + let node_2_privkey = SecretKey::from_slice(&[41; 32]).unwrap(); + let node_1_btckey = SecretKey::from_slice(&[40; 32]).unwrap(); + let node_2_btckey = SecretKey::from_slice(&[39; 32]).unwrap(); + let unsigned_ann = msgs::UnsignedChannelAnnouncement { + features: ChannelFeatures::known(), + chain_hash: genesis_block(network).header.bitcoin_hash(), + short_channel_id: short_chan_id, + node_id_1: PublicKey::from_secret_key(&secp_ctx, &node_1_privkey), + node_id_2: PublicKey::from_secret_key(&secp_ctx, &node_2_privkey), + bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, &node_1_btckey), + bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, &node_2_btckey), + excess_data: Vec::new(), + }; + + msgs::ChannelAnnouncement { + node_signature_1: Signature::from(FFISignature::new()), + node_signature_2: Signature::from(FFISignature::new()), + bitcoin_signature_1: Signature::from(FFISignature::new()), + bitcoin_signature_2: Signature::from(FFISignature::new()), + contents: unsigned_ann, + } + } + + fn get_dummy_channel_update(short_chan_id: u64) -> msgs::ChannelUpdate { + use bitcoin::secp256k1::ffi::Signature as FFISignature; + let network = Network::Testnet; + msgs::ChannelUpdate { + signature: Signature::from(FFISignature::new()), + contents: msgs::UnsignedChannelUpdate { + chain_hash: genesis_block(network).header.bitcoin_hash(), + short_channel_id: short_chan_id, + timestamp: 0, + flags: 0, + cltv_expiry_delta: 0, + htlc_minimum_msat: 0, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: vec![], + } + } + } + pub struct TestRoutingMessageHandler { - request_full_sync: bool, + pub chan_upds_recvd: AtomicUsize, + pub chan_anns_recvd: AtomicUsize, + pub chan_anns_sent: AtomicUsize, + pub request_full_sync: AtomicBool, } impl TestRoutingMessageHandler { pub fn new() -> Self { TestRoutingMessageHandler { - request_full_sync: false, + chan_upds_recvd: AtomicUsize::new(0), + chan_anns_recvd: AtomicUsize::new(0), + chan_anns_sent: AtomicUsize::new(0), + request_full_sync: AtomicBool::new(false), } } - - pub fn set_request_full_sync(mut self) -> Self { - self.request_full_sync = true; - self - } } impl msgs::RoutingMessageHandler for TestRoutingMessageHandler { - fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result { - Err(LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) + fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result { + Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) } - fn handle_channel_announcement(&self, _msg: &msgs::ChannelAnnouncement) -> Result { - Err(LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) + fn handle_channel_announcement(&self, _msg: &msgs::ChannelAnnouncement) -> Result { + self.chan_anns_recvd.fetch_add(1, Ordering::AcqRel); + Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) } - fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result { - Err(LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) + fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result { + self.chan_upds_recvd.fetch_add(1, Ordering::AcqRel); + Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) } fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {} - fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option, Option)> { - Vec::new() + fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option, Option)> { + let mut chan_anns = Vec::new(); + const TOTAL_UPDS: u64 = 100; + let end: u64 = cmp::min(starting_point + batch_amount as u64, TOTAL_UPDS - self.chan_anns_sent.load(Ordering::Acquire) as u64); + for i in starting_point..end { + let chan_upd_1 = get_dummy_channel_update(i); + let chan_upd_2 = get_dummy_channel_update(i); + let chan_ann = get_dummy_channel_announcement(i); + + chan_anns.push((chan_ann, Some(chan_upd_1), Some(chan_upd_2))); + } + + self.chan_anns_sent.fetch_add(chan_anns.len(), Ordering::AcqRel); + chan_anns } + fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec { Vec::new() } + fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { - self.request_full_sync + self.request_full_sync.load(Ordering::Acquire) } } @@@ -283,9 -351,6 +351,9 @@@ impl TestKeysInterface override_channel_id_priv: Mutex::new(None), } } + pub fn derive_channel_keys(&self, channel_value_satoshis: u64, user_id_1: u64, user_id_2: u64) -> EnforcingChannelKeys { + EnforcingChannelKeys::new(self.backing.derive_channel_keys(channel_value_satoshis, user_id_1, user_id_2)) + } } pub struct TestChainWatcher {