Merge pull request #620 from TheBlueMatt/2020-05-pre-bindings-cleanups
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Thu, 28 May 2020 19:34:42 +0000 (19:34 +0000)
committerGitHub <noreply@github.com>
Thu, 28 May 2020 19:34:42 +0000 (19:34 +0000)
Pre-C Bindings Cleanup

12 files changed:
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning/src/chain/keysinterface.rs
lightning/src/ln/chan_utils.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmonitor.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/onchaintx.rs
lightning/src/ln/peer_handler.rs
lightning/src/util/enforcing_trait_impls.rs
lightning/src/util/macro_logger.rs
lightning/src/util/test_utils.rs

index 3a236cdfb46ea03ff7c5e4dd47ebc3950668d42b..c5c3c9f3a8327f03aae74f0d117b6cc3c0f62cda 100644 (file)
@@ -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),
                ))
        }
 
index d8053e48f52f94604bbe16e8455a2718a72c80df..df3b20b038639f299f43987c4bc16545d8bb5100 100644 (file)
@@ -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(
@@ -280,6 +281,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, 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),
                        )
                })
        }
index 47eafa35a89bdf242c765e9eea0be25ae56e292e..9de35f0ef43d78b2a5c9f63c7fa47d8ecd856bb1 100644 (file)
@@ -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:
-       /// <BIP 143 signature generated with the given key> <empty vector> (MINIMALIF standard rule)
-       /// <witness_script as provided>
-       /// 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).
+       /// <BIP 143 signature> <empty vector> (MINIMALIF standard rule) <provided witnessScript>
+       ///
+       /// 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:
-       /// <BIP 143 signature generated with the given key> <public key derived from the given key>
+       /// <BIP 143 signature> <payment key>
+       ///
        /// 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),
        }
 }
 
@@ -97,19 +120,22 @@ impl Writeable for SpendableOutputDescriptor {
                                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(())
@@ -125,15 +151,16 @@ impl Readable for SpendableOutputDescriptor {
                        }),
                        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),
                }
@@ -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.
        ///
@@ -224,6 +255,49 @@ pub trait ChannelKeys : Send+Clone {
        /// return value must contain a signature.
        fn sign_local_commitment_htlc_transactions<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &LocalCommitmentTransaction, local_csv: u16, secp_ctx: &Secp256k1<T>) -> Result<Vec<Option<Signature>>, ()>;
 
+       /// 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<T: secp256k1::Signing + secp256k1::Verification>(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option<HTLCOutputInCommitment>, on_remote_tx_csv: u16, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
+
+       /// 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<T: secp256k1::Signing + secp256k1::Verification>(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()>;
+
        /// Create a signature for a (proposed) closing transaction.
        ///
        /// Note that, due to rounding, there may be one "missing" satoshi, and either party may have
@@ -288,6 +362,8 @@ pub struct InMemoryChannelKeys {
        pub(crate) remote_channel_pubkeys: Option<ChannelPublicKeys>,
        /// The total value of this channel
        channel_value_satoshis: u64,
+       /// Key derivation parameters
+       key_derivation_params: (u64, u64),
 }
 
 impl InMemoryChannelKeys {
@@ -300,7 +376,8 @@ impl InMemoryChannelKeys {
                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,
@@ -315,6 +392,7 @@ impl InMemoryChannelKeys {
                        channel_value_satoshis,
                        local_channel_pubkeys,
                        remote_channel_pubkeys: None,
+                       key_derivation_params,
                }
        }
 
@@ -333,6 +411,8 @@ impl InMemoryChannelKeys {
                        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 {
@@ -343,6 +423,7 @@ impl ChannelKeys for InMemoryChannelKeys {
        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<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
                if commitment_tx.input.len() != 1 { return Err(()); }
@@ -394,6 +475,54 @@ impl ChannelKeys for InMemoryChannelKeys {
                local_commitment_tx.get_htlc_sigs(&self.htlc_base_key, local_csv, secp_ctx)
        }
 
+       fn sign_justice_transaction<T: secp256k1::Signing + secp256k1::Verification>(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option<HTLCOutputInCommitment>, on_remote_tx_csv: u16, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
+               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<T: secp256k1::Signing + secp256k1::Verification>(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
+               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<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
                if closing_tx.input.len() != 1 { return Err(()); }
                if closing_tx.input[0].witness.len() != 0 { return Err(()); }
@@ -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(())
        }
@@ -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,
@@ -459,7 +592,8 @@ impl Readable for InMemoryChannelKeys {
                        commitment_seed,
                        channel_value_satoshis,
                        local_channel_pubkeys,
-                       remote_channel_pubkeys
+                       remote_channel_pubkeys,
+                       key_derivation_params: (params_1, params_2),
                })
        }
 }
@@ -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 {
@@ -528,11 +664,6 @@ impl KeysManager {
                                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,
@@ -545,40 +676,40 @@ impl KeysManager {
                                        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();
@@ -609,12 +740,35 @@ impl KeysInterface for KeysManager {
                        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");
@@ -630,7 +784,7 @@ impl KeysInterface for KeysManager {
        }
 
        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");
index 949d008c0d7d23ff69af82e8c80f568814875233..a97a5a6088fd28fb27ac4115d8f3e63edba2570a 100644 (file)
@@ -172,8 +172,11 @@ impl Readable for CounterpartyCommitmentSecrets {
        }
 }
 
-/// 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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
        let mut sha = Sha256::engine();
        sha.input(&per_commitment_point.serialize());
@@ -185,7 +188,13 @@ pub fn derive_private_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_co
        Ok(key)
 }
 
-pub(super) fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
+/// 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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
        let mut sha = Sha256::engine();
        sha.input(&per_commitment_point.serialize());
        sha.input(&base_point.serialize());
@@ -195,10 +204,11 @@ pub(super) fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>,
        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<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
+pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_secret: &SecretKey, revocation_base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
        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);
 
@@ -225,7 +235,13 @@ pub(super) fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Se
        Ok(part_a)
 }
 
-pub(super) fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
+/// 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<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
        let rev_append_commit_hash_key = {
                let mut sha = Sha256::engine();
                sha.input(&revocation_base_point.serialize());
@@ -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
@@ -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)
index 6ddaa8fd8241bde04ef1baff5a2df86167006b95..8d55804f41d62a8c83825f1dc7b02df8f52a10c9 100644 (file)
@@ -4439,6 +4439,7 @@ mod tests {
                        // These aren't set in the test vectors:
                        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
                        10_000_000,
+                       (0, 0)
                );
 
                assert_eq!(PublicKey::from_secret_key(&secp_ctx, chan_keys.funding_key()).serialize()[..],
index b054258319485be03ee5ddac0aaa4b8500f6d4e5..6d10fdb4f05f049d2d035873d1b986514a0335b4 100644 (file)
@@ -31,7 +31,7 @@ use ln::msgs::DecodeError;
 use ln::chan_utils;
 use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, LocalCommitmentTransaction, HTLCType};
 use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
-use ln::onchaintx::OnchainTxHandler;
+use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
 use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface, FeeEstimator};
 use chain::transaction::OutPoint;
 use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys};
@@ -370,24 +370,84 @@ struct LocalSignedTx {
        htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
 }
 
+/// 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<Txid, Vec<HTLCOutputInCommitment>>
+}
+
+impl Writeable for RemoteCommitmentTransaction {
+       fn write<W: Writer>(&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: ::std::io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+               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<PublicKey>,
-               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<HTLCOutputInCommitment>,
+               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<PaymentPreimage>,
-               amount: u64,
-               locktime: u32,
+               htlc: HTLCOutputInCommitment
        },
        LocalHTLC {
                preimage: Option<PaymentPreimage>,
@@ -401,21 +461,24 @@ pub(crate) enum InputMaterial {
 impl Writeable for InputMaterial  {
        fn write<W: Writer>(&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])?;
@@ -435,31 +498,37 @@ impl Readable for InputMaterial {
        fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
                let input_material = match <u8 as Readable>::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 => {
@@ -658,7 +727,7 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
        commitment_transaction_number_obscure_factor: u64,
 
        destination_script: Script,
-       broadcasted_local_revokable_script: Option<(Script, SecretKey, Script)>,
+       broadcasted_local_revokable_script: Option<(Script, PublicKey, PublicKey)>,
        remote_payment_script: Script,
        shutdown_script: Script,
 
@@ -667,15 +736,13 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
        current_remote_commitment_txid: Option<Txid>,
        prev_remote_commitment_txid: Option<Txid>,
 
-       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<PublicKey>)>,
 
-       our_to_self_delay: u16,
-       their_to_self_delay: u16,
+       on_local_tx_csv: u16,
 
        commitment_secrets: CounterpartyCommitmentSecrets,
        remote_claimable_outpoints: HashMap<Txid, Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
@@ -823,13 +890,11 @@ impl<ChanSigner: ChannelKeys> PartialEq for ChannelMonitor<ChanSigner> {
                        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 ||
@@ -892,8 +957,7 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
                self.current_remote_commitment_txid.write(writer)?;
                self.prev_remote_commitment_txid.write(writer)?;
 
-               writer.write_all(&self.their_htlc_base_key.serialize())?;
-               writer.write_all(&self.their_delayed_payment_base_key.serialize())?;
+               self.remote_tx_cache.write(writer)?;
                self.funding_redeemscript.write(writer)?;
                self.channel_value_satoshis.write(writer)?;
 
@@ -915,8 +979,7 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
                        },
                }
 
-               writer.write_all(&byte_utils::be16_to_array(self.our_to_self_delay))?;
-               writer.write_all(&byte_utils::be16_to_array(self.their_to_self_delay))?;
+               writer.write_all(&byte_utils::be16_to_array(self.on_local_tx_csv))?;
 
                self.commitment_secrets.write(writer)?;
 
@@ -1047,9 +1110,9 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
 
 impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
        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<ChanSigner> {
 
@@ -1059,7 +1122,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                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;
@@ -1094,14 +1159,12 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        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(),
@@ -1199,7 +1262,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                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 {
@@ -1220,13 +1283,20 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                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<Signature>, Option<HTLCSource>)>) -> Result<(), MonitorUpdateError> {
                if self.local_tx_signed {
                        return Err(MonitorUpdateError("A local commitment tx has already been signed, no new local commitment txn can be sent to our counterparty"));
@@ -1429,19 +1499,16 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        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});
                                }
                        }
 
@@ -1449,13 +1516,11 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                        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 });
                                        }
                                }
@@ -1573,24 +1638,24 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                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 });
                                                        }
                                                }
@@ -1620,25 +1685,19 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                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<ClaimRequest>, Vec<TxOut>, Option<(Script, SecretKey, Script)>) {
+       fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec<ClaimRequest>, Vec<TxOut>, 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 {
@@ -2137,18 +2196,19 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                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 {
@@ -2199,9 +2259,9 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor
                let broadcasted_local_revokable_script = match <u8 as Readable>::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),
@@ -2220,8 +2280,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor
                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)?;
 
@@ -2240,8 +2299,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor
                        }
                };
 
-               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)?;
 
@@ -2430,14 +2488,12 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for (BlockHash, ChannelMonitor
                        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,
@@ -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
index da47556968db1a7c05cb486bace634389b52f7ea..13125a36ddaebdd251cc12293394a8da276980c2 100644 (file)
@@ -4265,7 +4265,7 @@ fn test_manager_serialize_deserialize_inconsistent_monitor() {
 }
 
 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 @@ macro_rules! check_spendable_outputs {
                                        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,16 +4292,17 @@ macro_rules! check_spendable_outputs {
                                                                                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(),
@@ -4319,12 +4320,18 @@ macro_rules! check_spendable_outputs {
                                                                                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 } => {
@@ -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]);
 }
@@ -4427,7 +4434,7 @@ fn test_claim_on_remote_sizeable_push_msat() {
        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]);
@@ -4460,7 +4467,7 @@ fn test_claim_on_remote_revoked_sizeable_push_msat() {
        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]);
@@ -4511,7 +4518,7 @@ fn test_static_spendable_outputs_preimage_tx() {
        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]);
 }
@@ -4558,7 +4565,7 @@ fn test_static_spendable_outputs_timeout_tx() {
        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());
 }
@@ -4594,7 +4601,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() {
        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]);
 }
@@ -4649,7 +4656,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() {
        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]);
@@ -4699,7 +4706,7 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
        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]);
@@ -4969,7 +4976,7 @@ fn test_dynamic_spendable_outputs_local_htlc_success_tx() {
        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]);
@@ -5266,13 +5273,86 @@ fn test_dynamic_spendable_outputs_local_htlc_timeout_tx() {
        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);
@@ -5289,14 +5369,14 @@ fn test_static_output_closing_tx() {
        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);
 }
@@ -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]);
 }
index f263ddf434b5d83f4c78be7b6bf72fca7fd56d8e..c99dc87d6cb4225a2223ddf2d5a809c0dc78e213 100644 (file)
@@ -6,7 +6,6 @@
 use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType};
 use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
 use bitcoin::blockdata::script::Script;
-use bitcoin::util::bip143;
 
 use bitcoin::hash_types::Txid;
 
@@ -16,7 +15,8 @@ use bitcoin::secp256k1;
 use ln::msgs::DecodeError;
 use ln::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
 use ln::channelmanager::PaymentPreimage;
-use ln::chan_utils::{HTLCType, LocalCommitmentTransaction};
+use ln::chan_utils;
+use ln::chan_utils::{TxCreationKeys, LocalCommitmentTransaction};
 use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
 use chain::keysinterface::ChannelKeys;
 use util::logger::Logger;
@@ -92,8 +92,8 @@ impl Readable for ClaimTxBumpMaterial {
        }
 }
 
-#[derive(PartialEq)]
-pub(super) enum InputDescriptors {
+#[derive(PartialEq, Clone, Copy)]
+pub(crate) enum InputDescriptors {
        RevokedOfferedHTLC,
        RevokedReceivedHTLC,
        OfferedHTLC,
@@ -101,6 +101,53 @@ pub(super) enum InputDescriptors {
        RevokedOutput, // either a revoked to_local output on commitment tx, a revoked HTLC-Timeout output or a revoked HTLC-Success output
 }
 
+impl Writeable for InputDescriptors {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+               match self {
+                       &InputDescriptors::RevokedOfferedHTLC => {
+                               writer.write_all(&[0; 1])?;
+                       },
+                       &InputDescriptors::RevokedReceivedHTLC => {
+                               writer.write_all(&[1; 1])?;
+                       },
+                       &InputDescriptors::OfferedHTLC => {
+                               writer.write_all(&[2; 1])?;
+                       },
+                       &InputDescriptors::ReceivedHTLC => {
+                               writer.write_all(&[3; 1])?;
+                       }
+                       &InputDescriptors::RevokedOutput => {
+                               writer.write_all(&[4; 1])?;
+                       }
+               }
+               Ok(())
+       }
+}
+
+impl Readable for InputDescriptors {
+       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
+               let input_descriptor = match <u8 as Readable>::read(reader)? {
+                       0 => {
+                               InputDescriptors::RevokedOfferedHTLC
+                       },
+                       1 => {
+                               InputDescriptors::RevokedReceivedHTLC
+                       },
+                       2 => {
+                               InputDescriptors::OfferedHTLC
+                       },
+                       3 => {
+                               InputDescriptors::ReceivedHTLC
+                       },
+                       4 => {
+                               InputDescriptors::RevokedOutput
+                       }
+                       _ => return Err(DecodeError::InvalidValue),
+               };
+               Ok(input_descriptor)
+       }
+}
+
 macro_rules! subtract_high_prio_fee {
        ($logger: ident, $fee_estimator: expr, $value: expr, $predicted_weight: expr, $used_feerate: expr) => {
                {
@@ -193,7 +240,7 @@ pub struct OnchainTxHandler<ChanSigner: ChannelKeys> {
        local_htlc_sigs: Option<Vec<Option<(usize, Signature)>>>,
        prev_local_commitment: Option<LocalCommitmentTransaction>,
        prev_local_htlc_sigs: Option<Vec<Option<(usize, Signature)>>>,
-       local_csv: u16,
+       on_local_tx_csv: u16,
 
        key_storage: ChanSigner,
 
@@ -237,7 +284,7 @@ impl<ChanSigner: ChannelKeys + Writeable> OnchainTxHandler<ChanSigner> {
                self.prev_local_commitment.write(writer)?;
                self.prev_local_htlc_sigs.write(writer)?;
 
-               self.local_csv.write(writer)?;
+               self.on_local_tx_csv.write(writer)?;
 
                self.key_storage.write(writer)?;
 
@@ -285,7 +332,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
                let prev_local_commitment = Readable::read(reader)?;
                let prev_local_htlc_sigs = Readable::read(reader)?;
 
-               let local_csv = Readable::read(reader)?;
+               let on_local_tx_csv = Readable::read(reader)?;
 
                let key_storage = Readable::read(reader)?;
 
@@ -338,7 +385,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
                        local_htlc_sigs,
                        prev_local_commitment,
                        prev_local_htlc_sigs,
-                       local_csv,
+                       on_local_tx_csv,
                        key_storage,
                        claimable_outpoints,
                        pending_claim_requests,
@@ -349,7 +396,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
 }
 
 impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
-       pub(super) fn new(destination_script: Script, keys: ChanSigner, local_csv: u16) -> Self {
+       pub(super) fn new(destination_script: Script, keys: ChanSigner, on_local_tx_csv: u16) -> Self {
 
                let key_storage = keys;
 
@@ -359,7 +406,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                        local_htlc_sigs: None,
                        prev_local_commitment: None,
                        prev_local_htlc_sigs: None,
-                       local_csv,
+                       on_local_tx_csv,
                        key_storage,
                        pending_claim_requests: HashMap::new(),
                        claimable_outpoints: HashMap::new(),
@@ -487,13 +534,13 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                let mut dynamic_fee = true;
                for per_outp_material in cached_claim_datas.per_input_material.values() {
                        match per_outp_material {
-                               &InputMaterial::Revoked { ref witness_script, ref is_htlc, ref amount, .. } => {
-                                       inputs_witnesses_weight += Self::get_witnesses_weight(if !is_htlc { &[InputDescriptors::RevokedOutput] } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::OfferedHTLC) { &[InputDescriptors::RevokedOfferedHTLC] } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::AcceptedHTLC) { &[InputDescriptors::RevokedReceivedHTLC] } else { unreachable!() });
+                               &InputMaterial::Revoked { ref input_descriptor, ref amount, .. } => {
+                                       inputs_witnesses_weight += Self::get_witnesses_weight(&[*input_descriptor]);
                                        amt += *amount;
                                },
-                               &InputMaterial::RemoteHTLC { ref preimage, ref amount, .. } => {
+                               &InputMaterial::RemoteHTLC { ref preimage, ref htlc, .. } => {
                                        inputs_witnesses_weight += Self::get_witnesses_weight(if preimage.is_some() { &[InputDescriptors::OfferedHTLC] } else { &[InputDescriptors::ReceivedHTLC] });
-                                       amt += *amount;
+                                       amt += htlc.amount_msat / 1000;
                                },
                                &InputMaterial::LocalHTLC { .. } => {
                                        dynamic_fee = false;
@@ -526,34 +573,48 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
 
                        for (i, (outp, per_outp_material)) in cached_claim_datas.per_input_material.iter().enumerate() {
                                match per_outp_material {
-                                       &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount } => {
-                                               let sighash_parts = bip143::SighashComponents::new(&bumped_tx);
-                                               let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]);
-                                               let sig = self.secp_ctx.sign(&sighash, &key);
-                                               bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
-                                               bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
-                                               if *is_htlc {
-                                                       bumped_tx.input[i].witness.push(pubkey.unwrap().clone().serialize().to_vec());
-                                               } else {
-                                                       bumped_tx.input[i].witness.push(vec!(1));
+                                       &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 } => {
+                                               if let Ok(chan_keys) = TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, remote_delayed_payment_base_key, remote_htlc_base_key, &self.key_storage.pubkeys().revocation_basepoint, &self.key_storage.pubkeys().htlc_basepoint) {
+
+                                                       let witness_script = if let Some(ref htlc) = *htlc {
+                                                               chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &chan_keys.a_htlc_key, &chan_keys.b_htlc_key, &chan_keys.revocation_key)
+                                                       } else {
+                                                               chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, *on_remote_tx_csv, &chan_keys.a_delayed_payment_key)
+                                                       };
+
+                                                       if let Ok(sig) = self.key_storage.sign_justice_transaction(&bumped_tx, i, *amount, &per_commitment_key, htlc, *on_remote_tx_csv, &self.secp_ctx) {
+                                                               bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
+                                                               bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
+                                                               if htlc.is_some() {
+                                                                       bumped_tx.input[i].witness.push(chan_keys.revocation_key.clone().serialize().to_vec());
+                                                               } else {
+                                                                       bumped_tx.input[i].witness.push(vec!(1));
+                                                               }
+                                                               bumped_tx.input[i].witness.push(witness_script.clone().into_bytes());
+                                                       } else { return None; }
+                                                       //TODO: panic ?
+
+                                                       log_trace!(logger, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if *input_descriptor == InputDescriptors::RevokedOutput { "to_local" } else if *input_descriptor == InputDescriptors::RevokedOfferedHTLC { "offered" } else if *input_descriptor == InputDescriptors::RevokedReceivedHTLC { "received" } else { "" }, outp.vout, outp.txid, new_feerate);
                                                }
-                                               bumped_tx.input[i].witness.push(witness_script.clone().into_bytes());
-                                               log_trace!(logger, "Going to broadcast Penalty Transaction {} claiming revoked {} output {} from {} with new feerate {}...", bumped_tx.txid(), if !is_htlc { "to_local" } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::OfferedHTLC) { "offered" } else if HTLCType::scriptlen_to_htlctype(witness_script.len()) == Some(HTLCType::AcceptedHTLC) { "received" } else { "" }, outp.vout, outp.txid, new_feerate);
                                        },
-                                       &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => {
-                                               if !preimage.is_some() { bumped_tx.lock_time = *locktime }; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation
-                                               let sighash_parts = bip143::SighashComponents::new(&bumped_tx);
-                                               let sighash = hash_to_message!(&sighash_parts.sighash_all(&bumped_tx.input[i], &witness_script, *amount)[..]);
-                                               let sig = self.secp_ctx.sign(&sighash, &key);
-                                               bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
-                                               bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
-                                               if let &Some(preimage) = preimage {
-                                                       bumped_tx.input[i].witness.push(preimage.clone().0.to_vec());
-                                               } else {
-                                                       bumped_tx.input[i].witness.push(vec![]);
+                                       &InputMaterial::RemoteHTLC { ref per_commitment_point, ref remote_delayed_payment_base_key, ref remote_htlc_base_key, ref preimage, ref htlc } => {
+                                               if let Ok(chan_keys) = TxCreationKeys::new(&self.secp_ctx, &per_commitment_point, remote_delayed_payment_base_key, remote_htlc_base_key, &self.key_storage.pubkeys().revocation_basepoint, &self.key_storage.pubkeys().htlc_basepoint) {
+                                                       let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &chan_keys.a_htlc_key, &chan_keys.b_htlc_key, &chan_keys.revocation_key);
+
+                                                       if !preimage.is_some() { bumped_tx.lock_time = htlc.cltv_expiry }; // Right now we don't aggregate time-locked transaction, if we do we should set lock_time before to avoid breaking hash computation
+                                                       if let Ok(sig) = self.key_storage.sign_remote_htlc_transaction(&bumped_tx, i, &htlc.amount_msat / 1000, &per_commitment_point, htlc, &self.secp_ctx) {
+                                                               bumped_tx.input[i].witness.push(sig.serialize_der().to_vec());
+                                                               bumped_tx.input[i].witness[0].push(SigHashType::All as u8);
+                                                               if let &Some(preimage) = preimage {
+                                                                       bumped_tx.input[i].witness.push(preimage.0.to_vec());
+                                                               } else {
+                                                                       // Due to BIP146 (MINIMALIF) this must be a zero-length element to relay.
+                                                                       bumped_tx.input[i].witness.push(vec![]);
+                                                               }
+                                                               bumped_tx.input[i].witness.push(witness_script.clone().into_bytes());
+                                                       }
+                                                       log_trace!(logger, "Going to broadcast Claim Transaction {} claiming remote {} htlc output {} from {} with new feerate {}...", bumped_tx.txid(), if preimage.is_some() { "offered" } else { "received" }, outp.vout, outp.txid, new_feerate);
                                                }
-                                               bumped_tx.input[i].witness.push(witness_script.clone().into_bytes());
-                                               log_trace!(logger, "Going to broadcast Claim Transaction {} claiming remote {} htlc output {} from {} with new feerate {}...", bumped_tx.txid(), if preimage.is_some() { "offered" } else { "received" }, outp.vout, outp.txid, new_feerate);
                                        },
                                        _ => unreachable!()
                                }
@@ -823,7 +884,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
 
        fn sign_latest_local_htlcs(&mut self) {
                if let Some(ref local_commitment) = self.local_commitment {
-                       if let Ok(sigs) = self.key_storage.sign_local_commitment_htlc_transactions(local_commitment, self.local_csv, &self.secp_ctx) {
+                       if let Ok(sigs) = self.key_storage.sign_local_commitment_htlc_transactions(local_commitment, self.on_local_tx_csv, &self.secp_ctx) {
                                self.local_htlc_sigs = Some(Vec::new());
                                let ret = self.local_htlc_sigs.as_mut().unwrap();
                                for (htlc_idx, (local_sig, &(ref htlc, _))) in sigs.iter().zip(local_commitment.per_htlc.iter()).enumerate() {
@@ -839,7 +900,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
        }
        fn sign_prev_local_htlcs(&mut self) {
                if let Some(ref local_commitment) = self.prev_local_commitment {
-                       if let Ok(sigs) = self.key_storage.sign_local_commitment_htlc_transactions(local_commitment, self.local_csv, &self.secp_ctx) {
+                       if let Ok(sigs) = self.key_storage.sign_local_commitment_htlc_transactions(local_commitment, self.on_local_tx_csv, &self.secp_ctx) {
                                self.prev_local_htlc_sigs = Some(Vec::new());
                                let ret = self.prev_local_htlc_sigs.as_mut().unwrap();
                                for (htlc_idx, (local_sig, &(ref htlc, _))) in sigs.iter().zip(local_commitment.per_htlc.iter()).enumerate() {
@@ -891,7 +952,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                                if let &Some(ref htlc_sigs) = &self.local_htlc_sigs {
                                        let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
                                        htlc_tx = Some(self.local_commitment.as_ref().unwrap()
-                                               .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.local_csv));
+                                               .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_local_tx_csv));
                                }
                        }
                }
@@ -902,7 +963,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
                                if let &Some(ref htlc_sigs) = &self.prev_local_htlc_sigs {
                                        let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
                                        htlc_tx = Some(self.prev_local_commitment.as_ref().unwrap()
-                                               .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.local_csv));
+                                               .get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_local_tx_csv));
                                }
                        }
                }
index 009fa73f939e21ace76acb54acd205e56b2fa70a..12d7284661dee0c68c2fc377d9d6451141232a00 100644 (file)
@@ -12,7 +12,7 @@ use ln::features::InitFeatures;
 use ln::msgs;
 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;
@@ -468,6 +468,17 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                }
        }
 
+       /// Append a message to a peer's pending outbound/write buffer, and update the map of peers needing sends accordingly.
+       fn enqueue_message<M: Encode + Writeable>(&self, peers_needing_send: &mut HashSet<Descriptor>, 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<bool, PeerHandleError> {
                let pause_read = {
                        let mut peers_lock = self.peers.lock().unwrap();
@@ -490,16 +501,6 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                                                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 {
@@ -517,7 +518,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                                                                                                },
                                                                                                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;
                                                                                                },
                                                                                        }
@@ -563,7 +564,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                                                                        }
 
                                                                        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[..]));
@@ -662,7 +663,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                                                                                                        }
 
                                                                                                        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);
@@ -691,7 +692,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, L: Deref> PeerManager<D
                                                                                        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) => {
index d8db20f0f9a6008d9b23e8f85072a85ed48609fa..9a1b3ccf983b7493a172e95a58f8be2971e8d0bd 100644 (file)
@@ -58,6 +58,7 @@ impl ChannelKeys for EnforcingChannelKeys {
        fn htlc_base_key(&self) -> &SecretKey { self.inner.htlc_base_key() }
        fn commitment_seed(&self) -> &[u8; 32] { self.inner.commitment_seed() }
        fn pubkeys<'a>(&'a self) -> &'a ChannelPublicKeys { self.inner.pubkeys() }
+       fn key_derivation_params(&self) -> (u64, u64) { self.inner.key_derivation_params() }
 
        fn sign_remote_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, feerate_per_kw: u64, commitment_tx: &Transaction, keys: &TxCreationKeys, htlcs: &[&HTLCOutputInCommitment], to_self_delay: u16, secp_ctx: &Secp256k1<T>) -> Result<(Signature, Vec<Signature>), ()> {
                if commitment_tx.input.len() != 1 { panic!("lightning commitment transactions have a single input"); }
@@ -103,6 +104,14 @@ impl ChannelKeys for EnforcingChannelKeys {
                Ok(self.inner.sign_local_commitment_htlc_transactions(local_commitment_tx, local_csv, secp_ctx).unwrap())
        }
 
+       fn sign_justice_transaction<T: secp256k1::Signing + secp256k1::Verification>(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &Option<HTLCOutputInCommitment>, on_remote_tx_csv: u16, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
+               Ok(self.inner.sign_justice_transaction(justice_tx, input, amount, per_commitment_key, htlc, on_remote_tx_csv, secp_ctx).unwrap())
+       }
+
+       fn sign_remote_htlc_transaction<T: secp256k1::Signing + secp256k1::Verification>(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
+               Ok(self.inner.sign_remote_htlc_transaction(htlc_tx, input, amount, per_commitment_point, htlc, secp_ctx).unwrap())
+       }
+
        fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
                Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
        }
index 7594041de7d4cd3a4bc7b4d08d72b9245f17029e..01038646f2b5dcafaee30e059a0c4fa115c369ee 100644 (file)
@@ -132,7 +132,7 @@ impl<'a> std::fmt::Display for DebugSpendable<'a> {
                        &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)?;
                        }
                }
index e426ec2d340a6967955016352a6b78aa8e09569c..91af4202d28be148a7e333673fbb486089e5a061 100644 (file)
@@ -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 {