Skip to content

Commit 4525790

Browse files
committed
Enforce signing counterparty commitment only after revocation
1 parent 55d131a commit 4525790

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
@@ -229,6 +229,11 @@ pub trait BaseSign {
229229
//
230230
// TODO: Document the things someone using this interface should enforce before signing.
231231
fn sign_counterparty_commitment(&self, commitment_tx: &CommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()>;
232+
/// Validate the counterparty's revocation.
233+
///
234+
/// This is required in order for the signer to make sure that the state has moved
235+
/// forward and it is safe to sign the next counterparty commitment.
236+
fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey);
232237

233238
/// Create a signatures for a holder's commitment transaction and its claiming HTLC transactions.
234239
/// 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
@@ -2615,6 +2615,12 @@ impl<Signer: Sign> Channel<Signer> {
26152615
*self.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None;
26162616
}
26172617

2618+
let secret = SecretKey::from_slice(&msg.per_commitment_secret)
2619+
.map_err(|_| ChannelError::Close("Malformed commitment secret".to_owned()))?;
2620+
self.holder_signer.validate_counterparty_revocation(
2621+
self.cur_counterparty_commitment_transaction_number + 1,
2622+
&secret
2623+
);
26182624
self.commitment_secrets.provide_secret(self.cur_counterparty_commitment_transaction_number + 1, msg.per_commitment_secret)
26192625
.map_err(|_| ChannelError::Close("Previous secrets did not match new one".to_owned()))?;
26202626
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
@@ -117,12 +117,21 @@ impl BaseSign for EnforcingSigner {
117117
// These commitment numbers are backwards counting. We expect either the same as the previously encountered,
118118
// or the next one.
119119
assert!(last_commitment_number == actual_commitment_number || last_commitment_number - 1 == actual_commitment_number, "{} doesn't come after {}", actual_commitment_number, last_commitment_number);
120+
// Ensure that the counterparty doesn't get more than two broadcastable commitments -
121+
// the last and the one we are trying to sign
122+
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);
120123
state.last_counterparty_commitment = Some(cmp::min(last_commitment_number, actual_commitment_number))
121124
}
122125

123126
Ok(self.inner.sign_counterparty_commitment(commitment_tx, secp_ctx).unwrap())
124127
}
125128

129+
fn validate_counterparty_revocation(&self, idx: u64, _secret: &SecretKey) {
130+
let mut state = self.state.lock().unwrap();
131+
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);
132+
state.last_counterparty_revoked_commitment = idx;
133+
}
134+
126135
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
127136
let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
128137
let commitment_txid = trusted_tx.txid();
@@ -225,6 +234,8 @@ impl EnforcingSigner {
225234
pub struct EnforcementState {
226235
/// The last counterparty commitment number we signed, backwards counting
227236
pub last_counterparty_commitment: Option<u64>,
237+
/// The last counterparty commitment they revoked, backwards counting
238+
pub last_counterparty_revoked_commitment: u64,
228239
/// The last holder commitment number we revoked, backwards counting
229240
pub last_holder_revoked_commitment: u64,
230241
/// The last validated holder commitment number, backwards counting
@@ -236,6 +247,7 @@ impl EnforcementState {
236247
pub fn new() -> Self {
237248
EnforcementState {
238249
last_counterparty_commitment: None,
250+
last_counterparty_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
239251
last_holder_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
240252
last_holder_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
241253
}

0 commit comments

Comments
 (0)