impl LocalCommitmentTransaction {
#[cfg(test)]
pub fn dummy() -> Self {
+ let dummy_input = TxIn {
+ previous_output: OutPoint {
+ txid: Default::default(),
+ vout: 0,
+ },
+ script_sig: Default::default(),
+ sequence: 0,
+ witness: vec![vec![], vec![], vec![]]
+ };
Self { tx: Transaction {
version: 2,
- input: Vec::new(),
+ input: vec![dummy_input],
output: Vec::new(),
lock_time: 0,
} }
if self.their_to_self_delay.is_none() {
return Err(MonitorUpdateError("Got a local commitment tx info update before we'd set basic information about the channel"));
}
+ // Returning a monitor error before updating tracking points means in case of using
+ // a concurrent watchtower implementation for same channel, if this one doesn't
+ // reject update as we do, you MAY have the latest local valid commitment tx onchain
+ // for which you want to spend outputs. We're NOT robust again this scenario right
+ // now but we should consider it later.
+ if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx.clone()) {
+ return Err(MonitorUpdateError("Local commitment signed has already been signed, no further update of LOCAL commitment transaction is allowed"));
+ }
self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take();
self.current_local_signed_commitment_tx = Some(LocalSignedTx {
txid: commitment_tx.txid(),
- tx: commitment_tx.clone(),
+ tx: commitment_tx,
revocation_key: local_keys.revocation_key,
a_htlc_key: local_keys.a_htlc_key,
b_htlc_key: local_keys.b_htlc_key,
feerate_per_kw,
htlc_outputs,
});
- self.onchain_tx_handler.provide_latest_local_tx(commitment_tx);
Ok(())
}
}
}
- pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction) {
+ pub(super) fn provide_latest_local_tx(&mut self, tx: LocalCommitmentTransaction) -> Result<(), ()> {
+ // To prevent any unsafe state discrepancy between offchain and onchain, once local
+ // commitment transaction has been signed due to an event (either block height for
+ // HTLC-timeout or channel force-closure), don't allow any further update of local
+ // commitment transaction view to avoid delivery of revocation secret to counterparty
+ // for the aformentionned signed transaction.
+ if let Some(ref local_commitment) = self.local_commitment {
+ if local_commitment.has_local_sig() { return Err(()) }
+ }
self.prev_local_commitment = self.local_commitment.take();
self.local_commitment = Some(tx);
+ Ok(())
}
}