Skip to content

Commit 423f1b1

Browse files
authored
Merge pull request #1064 from lightning-signer/2021-08-closing-tx-phase2
2 parents b3be420 + eebc0a9 commit 423f1b1

File tree

4 files changed

+207
-72
lines changed

4 files changed

+207
-72
lines changed

lightning/src/chain/keysinterface.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use util::ser::{Writeable, Writer, Readable};
3434

3535
use chain::transaction::OutPoint;
3636
use ln::chan_utils;
37-
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction};
37+
use ln::chan_utils::{HTLCOutputInCommitment, make_funding_redeemscript, ChannelPublicKeys, HolderCommitmentTransaction, ChannelTransactionParameters, CommitmentTransaction, ClosingTransaction};
3838
use ln::msgs::UnsignedChannelAnnouncement;
3939
use ln::script::ShutdownScript;
4040

@@ -322,7 +322,7 @@ pub trait BaseSign {
322322
///
323323
/// Note that, due to rounding, there may be one "missing" satoshi, and either party may have
324324
/// chosen to forgo their output as dust.
325-
fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
325+
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
326326

327327
/// Signs a channel announcement message with our funding key, proving it comes from one
328328
/// of the channel participants.
@@ -671,17 +671,10 @@ impl BaseSign for InMemorySigner {
671671
Err(())
672672
}
673673

674-
fn sign_closing_transaction(&self, closing_tx: &Transaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
675-
if closing_tx.input.len() != 1 { return Err(()); }
676-
if closing_tx.input[0].witness.len() != 0 { return Err(()); }
677-
if closing_tx.output.len() > 2 { return Err(()); }
678-
674+
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
679675
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
680676
let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);
681-
682-
let sighash = hash_to_message!(&bip143::SigHashCache::new(closing_tx)
683-
.signature_hash(0, &channel_funding_redeemscript, self.channel_value_satoshis, SigHashType::All)[..]);
684-
Ok(secp_ctx.sign(&sighash, &self.funding_key))
677+
Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
685678
}
686679

687680
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {

lightning/src/ln/chan_utils.rs

+170-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use bitcoin::hash_types::{Txid, PubkeyHash};
2323
use ln::{PaymentHash, PaymentPreimage};
2424
use ln::msgs::DecodeError;
2525
use util::ser::{Readable, Writeable, Writer};
26-
use util::byte_utils;
26+
use util::{byte_utils, transaction_utils};
2727

2828
use bitcoin::hash_types::WPubkeyHash;
2929
use bitcoin::secp256k1::key::{SecretKey, PublicKey};
@@ -80,6 +80,50 @@ pub fn build_commitment_secret(commitment_seed: &[u8; 32], idx: u64) -> [u8; 32]
8080
res
8181
}
8282

83+
/// Build a closing transaction
84+
pub fn build_closing_transaction(to_holder_value_sat: u64, to_counterparty_value_sat: u64, to_holder_script: Script, to_counterparty_script: Script, funding_outpoint: OutPoint) -> Transaction {
85+
let txins = {
86+
let mut ins: Vec<TxIn> = Vec::new();
87+
ins.push(TxIn {
88+
previous_output: funding_outpoint,
89+
script_sig: Script::new(),
90+
sequence: 0xffffffff,
91+
witness: Vec::new(),
92+
});
93+
ins
94+
};
95+
96+
let mut txouts: Vec<(TxOut, ())> = Vec::new();
97+
98+
if to_counterparty_value_sat > 0 {
99+
txouts.push((TxOut {
100+
script_pubkey: to_counterparty_script,
101+
value: to_counterparty_value_sat
102+
}, ()));
103+
}
104+
105+
if to_holder_value_sat > 0 {
106+
txouts.push((TxOut {
107+
script_pubkey: to_holder_script,
108+
value: to_holder_value_sat
109+
}, ()));
110+
}
111+
112+
transaction_utils::sort_outputs(&mut txouts, |_, _| { cmp::Ordering::Equal }); // Ordering doesnt matter if they used our pubkey...
113+
114+
let mut outputs: Vec<TxOut> = Vec::new();
115+
for out in txouts.drain(..) {
116+
outputs.push(out.0);
117+
}
118+
119+
Transaction {
120+
version: 2,
121+
lock_time: 0,
122+
input: txins,
123+
output: outputs,
124+
}
125+
}
126+
83127
/// Implements the per-commitment secret storage scheme from
84128
/// [BOLT 3](https://github.com/lightningnetwork/lightning-rfc/blob/dcbf8583976df087c79c3ce0b535311212e6812d/03-transactions.md#efficient-per-commitment-secret-storage).
85129
///
@@ -846,7 +890,130 @@ impl BuiltCommitmentTransaction {
846890
}
847891
}
848892

849-
/// This class tracks the per-transaction information needed to build a commitment transaction and to
893+
/// This class tracks the per-transaction information needed to build a closing transaction and will
894+
/// actually build it and sign.
895+
///
896+
/// This class can be used inside a signer implementation to generate a signature given the relevant
897+
/// secret key.
898+
pub struct ClosingTransaction {
899+
to_holder_value_sat: u64,
900+
to_counterparty_value_sat: u64,
901+
to_holder_script: Script,
902+
to_counterparty_script: Script,
903+
built: Transaction,
904+
}
905+
906+
impl ClosingTransaction {
907+
/// Construct an object of the class
908+
pub fn new(
909+
to_holder_value_sat: u64,
910+
to_counterparty_value_sat: u64,
911+
to_holder_script: Script,
912+
to_counterparty_script: Script,
913+
funding_outpoint: OutPoint,
914+
) -> Self {
915+
let built = build_closing_transaction(
916+
to_holder_value_sat, to_counterparty_value_sat,
917+
to_holder_script.clone(), to_counterparty_script.clone(),
918+
funding_outpoint
919+
);
920+
ClosingTransaction {
921+
to_holder_value_sat,
922+
to_counterparty_value_sat,
923+
to_holder_script,
924+
to_counterparty_script,
925+
built
926+
}
927+
}
928+
929+
/// Trust our pre-built transaction.
930+
///
931+
/// Applies a wrapper which allows access to the transaction.
932+
///
933+
/// This should only be used if you fully trust the builder of this object. It should not
934+
/// be used by an external signer - instead use the verify function.
935+
pub fn trust(&self) -> TrustedClosingTransaction {
936+
TrustedClosingTransaction { inner: self }
937+
}
938+
939+
/// Verify our pre-built transaction.
940+
///
941+
/// Applies a wrapper which allows access to the transaction.
942+
///
943+
/// An external validating signer must call this method before signing
944+
/// or using the built transaction.
945+
pub fn verify(&self, funding_outpoint: OutPoint) -> Result<TrustedClosingTransaction, ()> {
946+
let built = build_closing_transaction(
947+
self.to_holder_value_sat, self.to_counterparty_value_sat,
948+
self.to_holder_script.clone(), self.to_counterparty_script.clone(),
949+
funding_outpoint
950+
);
951+
if self.built != built {
952+
return Err(())
953+
}
954+
Ok(TrustedClosingTransaction { inner: self })
955+
}
956+
957+
/// The value to be sent to the holder, or zero if the output will be omitted
958+
pub fn to_holder_value_sat(&self) -> u64 {
959+
self.to_holder_value_sat
960+
}
961+
962+
/// The value to be sent to the counterparty, or zero if the output will be omitted
963+
pub fn to_counterparty_value_sat(&self) -> u64 {
964+
self.to_counterparty_value_sat
965+
}
966+
967+
/// The destination of the holder's output
968+
pub fn to_holder_script(&self) -> &Script {
969+
&self.to_holder_script
970+
}
971+
972+
/// The destination of the counterparty's output
973+
pub fn to_counterparty_script(&self) -> &Script {
974+
&self.to_counterparty_script
975+
}
976+
}
977+
978+
/// A wrapper on ClosingTransaction indicating that the built bitcoin
979+
/// transaction is trusted.
980+
///
981+
/// See trust() and verify() functions on CommitmentTransaction.
982+
///
983+
/// This structure implements Deref.
984+
pub struct TrustedClosingTransaction<'a> {
985+
inner: &'a ClosingTransaction,
986+
}
987+
988+
impl<'a> Deref for TrustedClosingTransaction<'a> {
989+
type Target = ClosingTransaction;
990+
991+
fn deref(&self) -> &Self::Target { self.inner }
992+
}
993+
994+
impl<'a> TrustedClosingTransaction<'a> {
995+
/// The pre-built Bitcoin commitment transaction
996+
pub fn built_transaction(&self) -> &Transaction {
997+
&self.inner.built
998+
}
999+
1000+
/// Get the SIGHASH_ALL sighash value of the transaction.
1001+
///
1002+
/// This can be used to verify a signature.
1003+
pub fn get_sighash_all(&self, funding_redeemscript: &Script, channel_value_satoshis: u64) -> Message {
1004+
let sighash = &bip143::SigHashCache::new(&self.inner.built).signature_hash(0, funding_redeemscript, channel_value_satoshis, SigHashType::All)[..];
1005+
hash_to_message!(sighash)
1006+
}
1007+
1008+
/// Sign a transaction, either because we are counter-signing the counterparty's transaction or
1009+
/// because we are about to broadcast a holder transaction.
1010+
pub fn sign<T: secp256k1::Signing>(&self, funding_key: &SecretKey, funding_redeemscript: &Script, channel_value_satoshis: u64, secp_ctx: &Secp256k1<T>) -> Signature {
1011+
let sighash = self.get_sighash_all(funding_redeemscript, channel_value_satoshis);
1012+
secp_ctx.sign(&sighash, funding_key)
1013+
}
1014+
}
1015+
1016+
/// This class tracks the per-transaction information needed to build a commitment transaction and will
8501017
/// actually build it and sign. It is used for holder transactions that we sign only when needed
8511018
/// and for transactions we sign for the counterparty.
8521019
///
@@ -1110,7 +1277,7 @@ impl CommitmentTransaction {
11101277
/// Applies a wrapper which allows access to these fields.
11111278
///
11121279
/// This should only be used if you fully trust the builder of this object. It should not
1113-
/// be used by an external signer - instead use the verify function.
1280+
/// be used by an external signer - instead use the verify function.
11141281
pub fn trust(&self) -> TrustedCommitmentTransaction {
11151282
TrustedCommitmentTransaction { inner: self }
11161283
}

0 commit comments

Comments
 (0)