Skip to content

Commit 3e149b1

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 d84c084 commit 3e149b1

File tree

1 file changed

+97
-7
lines changed

1 file changed

+97
-7
lines changed

src/ln/channelmonitor.rs

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -924,8 +924,7 @@ impl ChannelMonitor {
924924
/// Attempts to claim a remote commitment transaction's outputs using the revocation key and
925925
/// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a
926926
/// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for
927-
/// HTLC-Success/HTLC-Timeout transactions, and claim them using the revocation key (if
928-
/// applicable) as well.
927+
/// HTLC-Success/HTLC-Timeout transactions.
929928
fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> (Vec<Transaction>, (Sha256dHash, Vec<TxOut>)) {
930929
// Most secp and related errors trying to create keys means we have no hope of constructing
931930
// a spend transaction...so we return no transactions to broadcast
@@ -1205,13 +1204,97 @@ impl ChannelMonitor {
12051204
txn_to_broadcast.push(spend_tx);
12061205
}
12071206
}
1208-
} else {
1209-
//TODO: For each input check if its in our remote_commitment_txn_on_chain map!
12101207
}
12111208

12121209
(txn_to_broadcast, (commitment_txid, watch_outputs))
12131210
}
12141211

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

@@ -1273,19 +1356,26 @@ impl ChannelMonitor {
12731356
fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> Vec<(Sha256dHash, Vec<TxOut>)> {
12741357
let mut watch_outputs = Vec::new();
12751358
for tx in txn_matched {
1359+
let mut txn: Vec<Transaction> = Vec::new();
12761360
for txin in tx.input.iter() {
12771361
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) {
1278-
let (mut txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
1362+
let (remote_txn, new_outputs) = self.check_spend_remote_transaction(tx, height);
1363+
txn = remote_txn;
12791364
if !new_outputs.1.is_empty() {
12801365
watch_outputs.push(new_outputs);
12811366
}
12821367
if txn.is_empty() {
12831368
txn = self.check_spend_local_transaction(tx, height);
12841369
}
1285-
for tx in txn.iter() {
1286-
broadcaster.broadcast_transaction(tx);
1370+
} else {
1371+
let remote_commitment_txn_on_chain = self.remote_commitment_txn_on_chain.lock().unwrap();
1372+
for commitment_number in remote_commitment_txn_on_chain.get(&txin.previous_output.txid) {
1373+
txn = self.check_spend_remote_htlc(tx, *commitment_number);
12871374
}
12881375
}
1376+
for tx in txn.iter() {
1377+
broadcaster.broadcast_transaction(tx);
1378+
}
12891379
}
12901380
}
12911381
if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx {

0 commit comments

Comments
 (0)