|
2 | 2 | //! spendable on-chain outputs which the user owns and is responsible for using just as any other
|
3 | 3 | //! on-chain output which is theirs.
|
4 | 4 |
|
5 |
| -use bitcoin::blockdata::transaction::{Transaction, OutPoint, TxOut}; |
| 5 | +use bitcoin::blockdata::transaction::{Transaction, OutPoint, TxOut, SigHashType}; |
6 | 6 | use bitcoin::blockdata::script::{Script, Builder};
|
7 | 7 | use bitcoin::blockdata::opcodes;
|
8 | 8 | use bitcoin::network::constants::Network;
|
@@ -215,6 +215,13 @@ pub trait ChannelKeys : Send+Clone {
|
215 | 215 | /// making the callee generate it via some util function we expose)!
|
216 | 216 | 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>), ()>;
|
217 | 217 |
|
| 218 | + /// Create a signature for a local commitment transaction |
| 219 | + /// |
| 220 | + /// TODO: Document the things someone using this interface should enforce before signing. |
| 221 | + /// TODO: Add more input vars to enable better checking (preferably removing commitment_tx and |
| 222 | + /// making the callee generate it via some util function we expose)! |
| 223 | + fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &mut Transaction, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>); |
| 224 | + |
218 | 225 | /// Create a signature for a (proposed) closing transaction.
|
219 | 226 | ///
|
220 | 227 | /// Note that, due to rounding, there may be one "missing" satoshi, and either party may have
|
@@ -342,6 +349,35 @@ impl ChannelKeys for InMemoryChannelKeys {
|
342 | 349 | Ok((commitment_sig, htlc_sigs))
|
343 | 350 | }
|
344 | 351 |
|
| 352 | + fn sign_local_commitment<T: secp256k1::Signing + secp256k1::Verification>(&self, local_commitment_tx: &mut Transaction, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) { |
| 353 | + if local_commitment_tx.input.len() != 1 { panic!("Commitment transactions must have input count == 1!"); } |
| 354 | + let has_local_sig = if local_commitment_tx.input[0].witness.len() == 4 { |
| 355 | + assert!(!local_commitment_tx.input[0].witness[1].is_empty()); |
| 356 | + assert!(!local_commitment_tx.input[0].witness[2].is_empty()); |
| 357 | + true |
| 358 | + } else { |
| 359 | + assert_eq!(local_commitment_tx.input[0].witness.len(), 3); |
| 360 | + assert!(local_commitment_tx.input[0].witness[0].is_empty()); |
| 361 | + assert!(local_commitment_tx.input[0].witness[1].is_empty() || local_commitment_tx.input[0].witness[2].is_empty()); |
| 362 | + false |
| 363 | + }; |
| 364 | + if has_local_sig { return; } |
| 365 | + |
| 366 | + let sighash = hash_to_message!(&bip143::SighashComponents::new(&local_commitment_tx) |
| 367 | + .sighash_all(&local_commitment_tx.input[0], funding_redeemscript, channel_value_satoshis)[..]); |
| 368 | + let our_sig = secp_ctx.sign(&sighash, &self.funding_key); |
| 369 | + |
| 370 | + if local_commitment_tx.input[0].witness[1].is_empty() { |
| 371 | + local_commitment_tx.input[0].witness[1] = our_sig.serialize_der().to_vec(); |
| 372 | + local_commitment_tx.input[0].witness[1].push(SigHashType::All as u8); |
| 373 | + } else { |
| 374 | + local_commitment_tx.input[0].witness[2] = our_sig.serialize_der().to_vec(); |
| 375 | + local_commitment_tx.input[0].witness[2].push(SigHashType::All as u8); |
| 376 | + } |
| 377 | + |
| 378 | + local_commitment_tx.input[0].witness.push(funding_redeemscript.as_bytes().to_vec()); |
| 379 | + } |
| 380 | + |
345 | 381 | fn sign_closing_transaction<T: secp256k1::Signing>(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<T>) -> Result<Signature, ()> {
|
346 | 382 | if closing_tx.input.len() != 1 { return Err(()); }
|
347 | 383 | if closing_tx.input[0].witness.len() != 0 { return Err(()); }
|
|
0 commit comments