Skip to content

Commit 324c50a

Browse files
committed
Enforce signing counterparty commitment only after revocation
1 parent 7972740 commit 324c50a

File tree

3 files changed

+26
-0
lines changed

3 files changed

+26
-0
lines changed

lightning/src/chain/keysinterface.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ pub trait BaseSign {
230230
//
231231
// TODO: Document the things someone using this interface should enforce before signing.
232232
fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()>;
233+
/// Validate the counterparty's revocation.
234+
///
235+
/// This is required in order for the signer to make sure that the state has moved
236+
/// forward and it is safe to sign the next counterparty commitment.
237+
fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey);
233238

234239
/// Create a signatures for a holder's commitment transaction and its claiming HTLC transactions.
235240
/// This will only ever be called with a non-revoked commitment_tx. This will be called with the
@@ -592,6 +597,9 @@ impl BaseSign for InMemorySigner {
592597
Ok((commitment_sig, htlc_sigs))
593598
}
594599

600+
fn validate_counterparty_revocation(&self, _idx: u64, _secret: &SecretKey) {
601+
}
602+
595603
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
596604
let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key);
597605
let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &self.counterparty_pubkeys().funding_pubkey);

lightning/src/ln/channel.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,6 +2765,12 @@ impl<Signer: Sign> Channel<Signer> {
27652765
*self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
27662766
}
27672767

2768+
let secret = SecretKey::from_slice(&msg.per_commitment_secret)
2769+
.map_err(|_| ChannelError::Close("Malformed commitment secret".to_owned()))?;
2770+
self.holder_signer.validate_counterparty_revocation(
2771+
self.cur_counterparty_commitment_transaction_number + 1,
2772+
&secret
2773+
);
27682774
self.commitment_secrets.provide_secret(self.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
27692775
.map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
27702776
self.latest_monitor_update_id += 1;

lightning/src/util/enforcing_trait_impls.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,21 @@ impl BaseSign for EnforcingSigner {
122122
// These commitment numbers are backwards counting. We expect either the same as the previously encountered,
123123
// or the next one.
124124
assert!(last_commitment_number == actual_commitment_number || last_commitment_number - 1 == actual_commitment_number, "{} doesn't come after {}", actual_commitment_number, last_commitment_number);
125+
// Ensure that the counterparty doesn't get more than two broadcastable commitments -
126+
// the last and the one we are trying to sign
127+
assert!(actual_commitment_number >= state.last_counterparty_revoked_commitment - 2, "cannot sign a commitment if second to last wasn't revoked - signing {} revoked {}", actual_commitment_number, state.last_counterparty_revoked_commitment);
125128
state.last_counterparty_commitment = cmp::min(last_commitment_number, actual_commitment_number)
126129
}
127130

128131
Ok(self.inner.sign_counterparty_commitment(commitment_tx, secp_ctx).unwrap())
129132
}
130133

134+
fn validate_counterparty_revocation(&self, idx: u64, _secret: &SecretKey) {
135+
let mut state = self.state.lock().unwrap();
136+
assert!(idx == state.last_counterparty_revoked_commitment || idx == state.last_counterparty_revoked_commitment - 1, "expecting to validate the current or next counterparty revocation - trying {}, current {}", idx, state.last_counterparty_revoked_commitment);
137+
state.last_counterparty_revoked_commitment = idx;
138+
}
139+
131140
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
132141
let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
133142
let commitment_txid = trusted_tx.txid();
@@ -230,6 +239,8 @@ impl EnforcingSigner {
230239
pub struct EnforcementState {
231240
/// The last counterparty commitment number we signed, backwards counting
232241
pub last_counterparty_commitment: u64,
242+
/// The last counterparty commitment they revoked, backwards counting
243+
pub last_counterparty_revoked_commitment: u64,
233244
/// The last holder commitment number we revoked, backwards counting
234245
pub last_holder_revoked_commitment: u64,
235246
/// The last validated holder commitment number, backwards counting
@@ -241,6 +252,7 @@ impl EnforcementState {
241252
pub fn new() -> Self {
242253
EnforcementState {
243254
last_counterparty_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
255+
last_counterparty_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
244256
last_holder_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
245257
last_holder_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
246258
}

0 commit comments

Comments
 (0)