Skip to content

Commit 2de29ae

Browse files
committed
Introduce CommitmentTransaction, ChannelTransactionParameters
CommitmentTransaction maintains the per-commitment transaction fields needed to construct the associated bitcoin transactions (commitment, HTLC). It replaces passing around of Bitcoin transactions. The ChannelKeys API is modified accordingly. By regenerating the transaction when implementing a validating external signer, this allows a higher level of assurance that all relevant aspects of the transactions were checked for policy violations. ChannelTransactionParameters replaces passing around of individual per-channel fields that are needed to construct Bitcoin transactions. Eliminate ChannelStaticData in favor of ChannelTransactionParameters. Use counterparty txid instead of tx in channelmonitor update.
1 parent a294a3f commit 2de29ae

9 files changed

+1230
-839
lines changed

lightning/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Still missing tons of error-handling. See GitHub issues for suggested projects i
1212

1313
[features]
1414
fuzztarget = ["bitcoin/fuzztarget"]
15+
# Internal test utilities exposed to other repo crates
1516
_test_utils = ["hex", "regex"]
1617
# Unlog messages superior at targeted level.
1718
max_level_off = []

lightning/src/chain/channelmonitor.rs

+100-69
Large diffs are not rendered by default.

lightning/src/chain/keysinterface.rs

+83-99
Large diffs are not rendered by default.

lightning/src/ln/chan_utils.rs

+623-225
Large diffs are not rendered by default.

lightning/src/ln/channel.rs

+303-288
Large diffs are not rendered by default.

lightning/src/ln/functional_tests.rs

+19-59
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,12 @@ use util::ser::{Writeable, ReadableArgs, Readable};
3232
use util::config::UserConfig;
3333

3434
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
35-
use bitcoin::hashes::HashEngine;
36-
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
35+
use bitcoin::hash_types::{Txid, BlockHash};
3736
use bitcoin::util::bip143;
3837
use bitcoin::util::address::Address;
3938
use bitcoin::util::bip32::{ChildNumber, ExtendedPubKey, ExtendedPrivKey};
4039
use bitcoin::blockdata::block::{Block, BlockHeader};
41-
use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, SigHashType, OutPoint as BitcoinOutPoint};
40+
use bitcoin::blockdata::transaction::{Transaction, TxOut, TxIn, SigHashType};
4241
use bitcoin::blockdata::script::{Builder, Script};
4342
use bitcoin::blockdata::opcodes;
4443
use bitcoin::blockdata::constants::genesis_block;
@@ -59,7 +58,7 @@ use std::sync::atomic::Ordering;
5958
use std::mem;
6059

6160
use ln::functional_test_utils::*;
62-
use ln::chan_utils::PreCalculatedTxCreationKeys;
61+
use ln::chan_utils::CommitmentTransaction;
6362

6463
#[test]
6564
fn test_insane_channel_opens() {
@@ -1617,20 +1616,20 @@ fn test_fee_spike_violation_fails_htlc() {
16171616

16181617
// Get the EnforcingChannelKeys for each channel, which will be used to (1) get the keys
16191618
// needed to sign the new commitment tx and (2) sign the new commitment tx.
1620-
let (local_revocation_basepoint, local_htlc_basepoint, local_payment_point, local_secret, local_secret2) = {
1619+
let (local_revocation_basepoint, local_htlc_basepoint, local_secret, local_secret2) = {
16211620
let chan_lock = nodes[0].node.channel_state.lock().unwrap();
16221621
let local_chan = chan_lock.by_id.get(&chan.2).unwrap();
16231622
let chan_keys = local_chan.get_keys();
16241623
let pubkeys = chan_keys.pubkeys();
1625-
(pubkeys.revocation_basepoint, pubkeys.htlc_basepoint, pubkeys.payment_point,
1624+
(pubkeys.revocation_basepoint, pubkeys.htlc_basepoint,
16261625
chan_keys.release_commitment_secret(INITIAL_COMMITMENT_NUMBER), chan_keys.release_commitment_secret(INITIAL_COMMITMENT_NUMBER - 2))
16271626
};
1628-
let (remote_delayed_payment_basepoint, remote_htlc_basepoint, remote_payment_point, remote_secret1) = {
1627+
let (remote_delayed_payment_basepoint, remote_htlc_basepoint, remote_secret1) = {
16291628
let chan_lock = nodes[1].node.channel_state.lock().unwrap();
16301629
let remote_chan = chan_lock.by_id.get(&chan.2).unwrap();
16311630
let chan_keys = remote_chan.get_keys();
16321631
let pubkeys = chan_keys.pubkeys();
1633-
(pubkeys.delayed_payment_basepoint, pubkeys.htlc_basepoint, pubkeys.payment_point,
1632+
(pubkeys.delayed_payment_basepoint, pubkeys.htlc_basepoint,
16341633
chan_keys.release_commitment_secret(INITIAL_COMMITMENT_NUMBER - 1))
16351634
};
16361635

@@ -1643,70 +1642,31 @@ fn test_fee_spike_violation_fails_htlc() {
16431642
// Build the remote commitment transaction so we can sign it, and then later use the
16441643
// signature for the commitment_signed message.
16451644
let local_chan_balance = 1313;
1646-
let static_payment_pk = local_payment_point.serialize();
1647-
let remote_commit_tx_output = TxOut {
1648-
script_pubkey: Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0)
1649-
.push_slice(&WPubkeyHash::hash(&static_payment_pk)[..])
1650-
.into_script(),
1651-
value: local_chan_balance as u64
1652-
};
1653-
1654-
let local_commit_tx_output = TxOut {
1655-
script_pubkey: chan_utils::get_revokeable_redeemscript(&commit_tx_keys.revocation_key,
1656-
BREAKDOWN_TIMEOUT,
1657-
&commit_tx_keys.broadcaster_delayed_payment_key).to_v0_p2wsh(),
1658-
value: 95000,
1659-
};
16601645

16611646
let accepted_htlc_info = chan_utils::HTLCOutputInCommitment {
16621647
offered: false,
16631648
amount_msat: 3460001,
16641649
cltv_expiry: htlc_cltv,
1665-
payment_hash: payment_hash,
1650+
payment_hash,
16661651
transaction_output_index: Some(1),
16671652
};
16681653

1669-
let htlc_output = TxOut {
1670-
script_pubkey: chan_utils::get_htlc_redeemscript(&accepted_htlc_info, &commit_tx_keys).to_v0_p2wsh(),
1671-
value: 3460001 / 1000
1672-
};
1673-
1674-
let commit_tx_obscure_factor = {
1675-
let mut sha = Sha256::engine();
1676-
let remote_payment_point = &remote_payment_point.serialize();
1677-
sha.input(&local_payment_point.serialize());
1678-
sha.input(remote_payment_point);
1679-
let res = Sha256::from_engine(sha).into_inner();
1680-
1681-
((res[26] as u64) << 5*8) |
1682-
((res[27] as u64) << 4*8) |
1683-
((res[28] as u64) << 3*8) |
1684-
((res[29] as u64) << 2*8) |
1685-
((res[30] as u64) << 1*8) |
1686-
((res[31] as u64) << 0*8)
1687-
};
1688-
let commitment_number = 1;
1689-
let obscured_commitment_transaction_number = commit_tx_obscure_factor ^ commitment_number;
1690-
let lock_time = ((0x20 as u32) << 8*3) | ((obscured_commitment_transaction_number & 0xffffffu64) as u32);
1691-
let input = TxIn {
1692-
previous_output: BitcoinOutPoint { txid: chan.3.txid(), vout: 0 },
1693-
script_sig: Script::new(),
1694-
sequence: ((0x80 as u32) << 8*3) | ((obscured_commitment_transaction_number >> 3*8) as u32),
1695-
witness: Vec::new(),
1696-
};
1654+
let commitment_number = INITIAL_COMMITMENT_NUMBER - 1;
16971655

1698-
let commit_tx = Transaction {
1699-
version: 2,
1700-
lock_time,
1701-
input: vec![input],
1702-
output: vec![remote_commit_tx_output, htlc_output, local_commit_tx_output],
1703-
};
17041656
let res = {
17051657
let local_chan_lock = nodes[0].node.channel_state.lock().unwrap();
17061658
let local_chan = local_chan_lock.by_id.get(&chan.2).unwrap();
17071659
let local_chan_keys = local_chan.get_keys();
1708-
let pre_commit_tx_keys = PreCalculatedTxCreationKeys::new(commit_tx_keys);
1709-
local_chan_keys.sign_counterparty_commitment(feerate_per_kw, &commit_tx, &pre_commit_tx_keys, &[&accepted_htlc_info], &secp_ctx).unwrap()
1660+
let commitment_tx = CommitmentTransaction::new_with_auxiliary_htlc_data(
1661+
commitment_number,
1662+
95000,
1663+
local_chan_balance,
1664+
commit_tx_keys.clone(),
1665+
feerate_per_kw,
1666+
&mut vec![(accepted_htlc_info, ())],
1667+
&local_chan.channel_transaction_parameters.as_counterparty_broadcastable()
1668+
);
1669+
local_chan_keys.sign_counterparty_commitment(&commitment_tx, &secp_ctx).unwrap()
17101670
};
17111671

17121672
let commit_signed_msg = msgs::CommitmentSigned {

lightning/src/ln/onchaintx.rs

+44-45
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
//! The logic to build claims and bump in-flight transactions until confirmations.
1111
//!
12-
//! OnchainTxHandler objetcs are fully-part of ChannelMonitor and encapsulates all
12+
//! OnchainTxHandler objects are fully-part of ChannelMonitor and encapsulates all
1313
//! building, tracking, bumping and notifications functions.
1414
1515
use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType};
@@ -24,7 +24,7 @@ use bitcoin::secp256k1;
2424
use ln::msgs::DecodeError;
2525
use ln::channelmanager::PaymentPreimage;
2626
use ln::chan_utils;
27-
use ln::chan_utils::{TxCreationKeys, HolderCommitmentTransaction};
27+
use ln::chan_utils::{TxCreationKeys, ChannelTransactionParameters, HolderCommitmentTransaction};
2828
use chain::chaininterface::{FeeEstimator, BroadcasterInterface, ConfirmationTarget, MIN_RELAY_FEE_SAT_PER_1000_WEIGHT};
2929
use chain::channelmonitor::{ANTI_REORG_DELAY, CLTV_SHARED_CLAIM_BUFFER, InputMaterial, ClaimRequest};
3030
use chain::keysinterface::ChannelKeys;
@@ -244,14 +244,13 @@ pub struct OnchainTxHandler<ChanSigner: ChannelKeys> {
244244
holder_commitment: Option<HolderCommitmentTransaction>,
245245
// holder_htlc_sigs and prev_holder_htlc_sigs are in the order as they appear in the commitment
246246
// transaction outputs (hence the Option<>s inside the Vec). The first usize is the index in
247-
// the set of HTLCs in the HolderCommitmentTransaction (including those which do not appear in
248-
// the commitment transaction).
247+
// the set of HTLCs in the HolderCommitmentTransaction.
249248
holder_htlc_sigs: Option<Vec<Option<(usize, Signature)>>>,
250249
prev_holder_commitment: Option<HolderCommitmentTransaction>,
251250
prev_holder_htlc_sigs: Option<Vec<Option<(usize, Signature)>>>,
252-
on_holder_tx_csv: u16,
253251

254252
key_storage: ChanSigner,
253+
pub(crate) channel_transaction_parameters: ChannelTransactionParameters,
255254

256255
// Used to track claiming requests. If claim tx doesn't confirm before height timer expiration we need to bump
257256
// it (RBF or CPFP). If an input has been part of an aggregate tx at first claim try, we need to keep it within
@@ -295,9 +294,8 @@ impl<ChanSigner: ChannelKeys + Writeable> OnchainTxHandler<ChanSigner> {
295294
self.prev_holder_commitment.write(writer)?;
296295
self.prev_holder_htlc_sigs.write(writer)?;
297296

298-
self.on_holder_tx_csv.write(writer)?;
299-
300297
self.key_storage.write(writer)?;
298+
self.channel_transaction_parameters.write(writer)?;
301299

302300
writer.write_all(&byte_utils::be64_to_array(self.pending_claim_requests.len() as u64))?;
303301
for (ref ancestor_claim_txid, claim_tx_data) in self.pending_claim_requests.iter() {
@@ -344,9 +342,8 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
344342
let prev_holder_commitment = Readable::read(reader)?;
345343
let prev_holder_htlc_sigs = Readable::read(reader)?;
346344

347-
let on_holder_tx_csv = Readable::read(reader)?;
348-
349345
let key_storage = Readable::read(reader)?;
346+
let channel_parameters = Readable::read(reader)?;
350347

351348
let pending_claim_requests_len: u64 = Readable::read(reader)?;
352349
let mut pending_claim_requests = HashMap::with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
@@ -398,8 +395,8 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
398395
holder_htlc_sigs,
399396
prev_holder_commitment,
400397
prev_holder_htlc_sigs,
401-
on_holder_tx_csv,
402398
key_storage,
399+
channel_transaction_parameters: channel_parameters,
403400
claimable_outpoints,
404401
pending_claim_requests,
405402
onchain_events_waiting_threshold_conf,
@@ -410,7 +407,7 @@ impl<ChanSigner: ChannelKeys + Readable> Readable for OnchainTxHandler<ChanSigne
410407
}
411408

412409
impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
413-
pub(crate) fn new(destination_script: Script, keys: ChanSigner, on_holder_tx_csv: u16) -> Self {
410+
pub(crate) fn new(destination_script: Script, keys: ChanSigner, channel_parameters: ChannelTransactionParameters) -> Self {
414411

415412
let key_storage = keys;
416413

@@ -420,8 +417,8 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
420417
holder_htlc_sigs: None,
421418
prev_holder_commitment: None,
422419
prev_holder_htlc_sigs: None,
423-
on_holder_tx_csv,
424420
key_storage,
421+
channel_transaction_parameters: channel_parameters,
425422
pending_claim_requests: HashMap::new(),
426423
claimable_outpoints: HashMap::new(),
427424
onchain_events_waiting_threshold_conf: HashMap::new(),
@@ -654,7 +651,7 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
654651
let signed_tx = self.get_fully_signed_holder_tx(funding_redeemscript).unwrap();
655652
// Timer set to $NEVER given we can't bump tx without anchor outputs
656653
log_trace!(logger, "Going to broadcast Holder Transaction {} claiming funding output {} from {}...", signed_tx.txid(), outp.vout, outp.txid);
657-
return Some((None, self.holder_commitment.as_ref().unwrap().feerate_per_kw, signed_tx));
654+
return Some((None, self.holder_commitment.as_ref().unwrap().feerate_per_kw(), signed_tx));
658655
}
659656
_ => unreachable!()
660657
}
@@ -899,44 +896,39 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
899896
fn sign_latest_holder_htlcs(&mut self) {
900897
if let Some(ref holder_commitment) = self.holder_commitment {
901898
if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
902-
self.holder_htlc_sigs = Some(Vec::new());
903-
let ret = self.holder_htlc_sigs.as_mut().unwrap();
904-
for (htlc_idx, (holder_sig, &(ref htlc, _))) in sigs.iter().zip(holder_commitment.per_htlc.iter()).enumerate() {
905-
if let Some(tx_idx) = htlc.transaction_output_index {
906-
if ret.len() <= tx_idx as usize { ret.resize(tx_idx as usize + 1, None); }
907-
ret[tx_idx as usize] = Some((htlc_idx, holder_sig.expect("Did not receive a signature for a non-dust HTLC")));
908-
} else {
909-
assert!(holder_sig.is_none(), "Received a signature for a dust HTLC");
910-
}
911-
}
899+
self.holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs));
912900
}
913901
}
914902
}
903+
915904
fn sign_prev_holder_htlcs(&mut self) {
916905
if let Some(ref holder_commitment) = self.prev_holder_commitment {
917906
if let Ok(sigs) = self.key_storage.sign_holder_commitment_htlc_transactions(holder_commitment, &self.secp_ctx) {
918-
self.prev_holder_htlc_sigs = Some(Vec::new());
919-
let ret = self.prev_holder_htlc_sigs.as_mut().unwrap();
920-
for (htlc_idx, (holder_sig, &(ref htlc, _))) in sigs.iter().zip(holder_commitment.per_htlc.iter()).enumerate() {
921-
if let Some(tx_idx) = htlc.transaction_output_index {
922-
if ret.len() <= tx_idx as usize { ret.resize(tx_idx as usize + 1, None); }
923-
ret[tx_idx as usize] = Some((htlc_idx, holder_sig.expect("Did not receive a signature for a non-dust HTLC")));
924-
} else {
925-
assert!(holder_sig.is_none(), "Received a signature for a dust HTLC");
926-
}
927-
}
907+
self.prev_holder_htlc_sigs = Some(Self::extract_holder_sigs(holder_commitment, sigs));
928908
}
929909
}
930910
}
931911

932-
//TODO: getting lastest holder transactions should be infaillible and result in us "force-closing the channel", but we may
912+
fn extract_holder_sigs(holder_commitment: &HolderCommitmentTransaction, sigs: Vec<Signature>) -> Vec<Option<(usize, Signature)>> {
913+
let mut ret = Vec::new();
914+
for (htlc_idx, (holder_sig, htlc)) in sigs.iter().zip(holder_commitment.htlcs().iter()).enumerate() {
915+
let tx_idx = htlc.transaction_output_index.unwrap();
916+
if ret.len() <= tx_idx as usize { ret.resize(tx_idx as usize + 1, None); }
917+
ret[tx_idx as usize] = Some((htlc_idx, holder_sig.clone()));
918+
}
919+
ret
920+
}
921+
922+
//TODO: getting lastest holder transactions should be infallible and result in us "force-closing the channel", but we may
933923
// have empty holder commitment transaction if a ChannelMonitor is asked to force-close just after Channel::get_outbound_funding_created,
934924
// before providing a initial commitment transaction. For outbound channel, init ChannelMonitor at Channel::funding_signed, there is nothing
935925
// to monitor before.
936926
pub(crate) fn get_fully_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
937927
if let Some(ref mut holder_commitment) = self.holder_commitment {
938-
match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
939-
Ok(sig) => Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)),
928+
match self.key_storage.sign_holder_commitment(&holder_commitment, &self.secp_ctx) {
929+
Ok(sig) => {
930+
Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
931+
},
940932
Err(_) => return None,
941933
}
942934
} else {
@@ -947,9 +939,10 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
947939
#[cfg(any(test, feature="unsafe_revoked_tx_signing"))]
948940
pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Option<Transaction> {
949941
if let Some(ref mut holder_commitment) = self.holder_commitment {
950-
let holder_commitment = holder_commitment.clone();
951-
match self.key_storage.sign_holder_commitment(&holder_commitment, &self.secp_ctx) {
952-
Ok(sig) => Some(holder_commitment.add_holder_sig(funding_redeemscript, sig)),
942+
match self.key_storage.sign_holder_commitment(holder_commitment, &self.secp_ctx) {
943+
Ok(sig) => {
944+
Some(holder_commitment.add_holder_sig(funding_redeemscript, sig))
945+
},
953946
Err(_) => return None,
954947
}
955948
} else {
@@ -960,24 +953,30 @@ impl<ChanSigner: ChannelKeys> OnchainTxHandler<ChanSigner> {
960953
pub(crate) fn get_fully_signed_htlc_tx(&mut self, outp: &::bitcoin::OutPoint, preimage: &Option<PaymentPreimage>) -> Option<Transaction> {
961954
let mut htlc_tx = None;
962955
if self.holder_commitment.is_some() {
963-
let commitment_txid = self.holder_commitment.as_ref().unwrap().txid();
956+
let commitment_txid = self.holder_commitment.as_ref().unwrap().trust().txid();
964957
if commitment_txid == outp.txid {
965958
self.sign_latest_holder_htlcs();
966959
if let &Some(ref htlc_sigs) = &self.holder_htlc_sigs {
967960
let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
968-
htlc_tx = Some(self.holder_commitment.as_ref().unwrap()
969-
.get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_holder_tx_csv));
961+
let holder_commitment = self.holder_commitment.as_ref().unwrap();
962+
let trusted_tx = holder_commitment.trust();
963+
let counterparty_htlc_sig = holder_commitment.counterparty_htlc_sigs[*htlc_idx];
964+
htlc_tx = Some(trusted_tx
965+
.get_signed_htlc_tx(&self.channel_transaction_parameters.as_holder_broadcastable(), *htlc_idx, &counterparty_htlc_sig, htlc_sig, preimage));
970966
}
971967
}
972968
}
973969
if self.prev_holder_commitment.is_some() {
974-
let commitment_txid = self.prev_holder_commitment.as_ref().unwrap().txid();
970+
let commitment_txid = self.prev_holder_commitment.as_ref().unwrap().trust().txid();
975971
if commitment_txid == outp.txid {
976972
self.sign_prev_holder_htlcs();
977973
if let &Some(ref htlc_sigs) = &self.prev_holder_htlc_sigs {
978974
let &(ref htlc_idx, ref htlc_sig) = htlc_sigs[outp.vout as usize].as_ref().unwrap();
979-
htlc_tx = Some(self.prev_holder_commitment.as_ref().unwrap()
980-
.get_signed_htlc_tx(*htlc_idx, htlc_sig, preimage, self.on_holder_tx_csv));
975+
let holder_commitment = self.prev_holder_commitment.as_ref().unwrap();
976+
let trusted_tx = holder_commitment.trust();
977+
let counterparty_htlc_sig = holder_commitment.counterparty_htlc_sigs[*htlc_idx];
978+
htlc_tx = Some(trusted_tx
979+
.get_signed_htlc_tx(&self.channel_transaction_parameters.as_holder_broadcastable(), *htlc_idx, &counterparty_htlc_sig, htlc_sig, preimage));
981980
}
982981
}
983982
}

0 commit comments

Comments
 (0)