Skip to content

Commit 83fd719

Browse files
author
Antoine Riard
committed
Implement claiming of revoked HTLC transactions by ChannelMonitor
Refactor check_spend_remote_transaction in part to check_spend_remote_htlc to avoid lock mess in block_connected. We need remote_commitment_txn_on_chain to match remote HTLC tx
1 parent 7cb6525 commit 83fd719

File tree

1 file changed

+100
-7
lines changed

1 file changed

+100
-7
lines changed

src/ln/channelmonitor.rs

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -926,8 +926,7 @@ impl ChannelMonitor {
926926
/// Attempts to claim a remote commitment transaction's outputs using the revocation key and
927927
/// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a
928928
/// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
929-
/// HTLC-Success/HTLC-Timeout transactions, and claim them using the revocation key (if
930-
/// applicable) as well.
929+
/// HTLC-Success/HTLC-Timeout transactions.
931930
fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>)) {
932931
// Most secp and related errors trying to create keys means we have no hope of constructing
933932
// a spend transaction...so we return no transactions to broadcast
@@ -1207,13 +1206,98 @@ impl ChannelMonitor {
12071206
txn_to_broadcast.push(spend_tx);
12081207
}
12091208
}
1210-
} else {
1211-
//TODO: For each input check if its in our remote_commitment_txn_on_chain map!
12121209
}
12131210

12141211
(txn_to_broadcast, (commitment_txid, watch_outputs))
12151212
}
12161213

1214+
/// Attempst to claim a remote HTLC-Success/HTLC-Timeout s outputs using the revocation key
1215+
fn check_spend_remote_htlc(&self, tx: &Transaction, commitment_number: u64) -> Vec<Transaction> {
1216+
1217+
let mut txn_to_broadcast = Vec::new();
1218+
1219+
let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers!
1220+
1221+
macro_rules! ignore_error {
1222+
( $thing : expr ) => {
1223+
match $thing {
1224+
Ok(a) => a,
1225+
Err(_) => return txn_to_broadcast
1226+
}
1227+
};
1228+
}
1229+
1230+
let secret = self.get_secret(commitment_number).unwrap();
1231+
let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));
1232+
let revocation_pubkey = match self.key_storage {
1233+
KeyStorage::PrivMode { ref revocation_base_key, .. } => {
1234+
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
1235+
ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))
1236+
},
1237+
KeyStorage::SigsMode { ref revocation_base_key, .. } => {
1238+
let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key);
1239+
ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &revocation_base_key))
1240+
},
1241+
};
1242+
let delayed_key = match self.their_delayed_payment_base_key {
1243+
None => return txn_to_broadcast,
1244+
Some(their_delayed_payment_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &their_delayed_payment_base_key)),
1245+
};
1246+
let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.their_to_self_delay.unwrap(), &delayed_key);
1247+
let revokeable_p2wsh = redeemscript.to_v0_p2wsh();
1248+
1249+
let mut inputs = Vec::new();
1250+
let mut amount = 0;
1251+
1252+
if tx.output[0].script_pubkey == revokeable_p2wsh { //HTLC transactions have one txin, one txout
1253+
inputs.push(TxIn {
1254+
previous_output: BitcoinOutPoint {
1255+
txid: commitment_txid,
1256+
vout: 0,
1257+
},
1258+
script_sig: Script::new(),
1259+
sequence: 0xfffffffd,
1260+
witness: Vec::new(),
1261+
});
1262+
amount = tx.output[0].value;
1263+
}
1264+
1265+
if !inputs.is_empty() {
1266+
let outputs = vec!(TxOut {
1267+
script_pubkey: self.destination_script.clone(),
1268+
value: amount, //TODO: - fee
1269+
});
1270+
1271+
let mut spend_tx = Transaction {
1272+
version: 2,
1273+
lock_time: 0,
1274+
input: inputs,
1275+
output: outputs,
1276+
};
1277+
1278+
1279+
let sighash_parts = bip143::SighashComponents::new(&spend_tx);
1280+
1281+
let sig = match self.key_storage {
1282+
KeyStorage::PrivMode { ref revocation_base_key, .. } => {
1283+
let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&spend_tx.input[0], &redeemscript, amount)[..]));
1284+
let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key));
1285+
self.secp_ctx.sign(&sighash, &revocation_key)
1286+
}
1287+
KeyStorage::SigsMode { .. } => {
1288+
unimplemented!();
1289+
}
1290+
};
1291+
spend_tx.input[0].witness.push(sig.serialize_der(&self.secp_ctx).to_vec());
1292+
spend_tx.input[0].witness[0].push(SigHashType::All as u8);
1293+
spend_tx.input[0].witness.push(vec!(1));
1294+
spend_tx.input[0].witness.push(redeemscript.into_bytes());
1295+
1296+
txn_to_broadcast.push(spend_tx);
1297+
}
1298+
txn_to_broadcast
1299+
}
1300+
12171301
fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> Vec<Transaction> {
12181302
let mut res = Vec::with_capacity(local_tx.htlc_outputs.len());
12191303

@@ -1274,20 +1358,29 @@ impl ChannelMonitor {
12741358

12751359
fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> Vec<(Sha256dHash, Vec<TxOut>)> {
12761360
let mut watch_outputs = Vec::new();
1361+
let mut txn: Vec<Transaction> = Vec::new();
12771362
for tx in txn_matched {
12781363
for txin in tx.input.iter() {
12791364
if self.funding_txo.is_none() || (txin.previous_output.txid == self.funding_txo.as_ref().unwrap().0.txid && txin.previous_output.vout == self.funding_txo.as_ref().unwrap().0.index as u32) {
1280-
let (mut txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
1365+
let (mut remote_txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
1366+
txn.append(&mut remote_txn);
12811367
if !new_outputs.1.is_empty() {
12821368
watch_outputs.push(new_outputs);
12831369
}
12841370
if txn.is_empty() {
12851371
txn = self.check_spend_local_transaction(tx, height);
12861372
}
1287-
for tx in txn.iter() {
1288-
broadcaster.broadcast_transaction(tx);
1373+
} else {
1374+
let remote_commitment_txn_on_chain = self.remote_commitment_txn_on_chain.lock().unwrap();
1375+
for (txid, commitment_number) in remote_commitment_txn_on_chain.iter() {
1376+
if txin.previous_output.txid == *txid {
1377+
txn.append(&mut self.check_spend_remote_htlc(tx, *commitment_number));
1378+
}
12891379
}
12901380
}
1381+
for tx in txn.iter() {
1382+
broadcaster.broadcast_transaction(tx);
1383+
}
12911384
}
12921385
}
12931386
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {

0 commit comments

Comments
 (0)