Skip to content

Commit 463ba15

Browse files
committed
Fix premature claims broadcast
A claim transaction with locktime T can only be mined at block heights of T+1 or above, so it should only be broadcast at height T or above. Due to an off-by-one bug, we were broadcasting some claim transactions too early at T-1. AFAICT, nothing bad resulted from this bug -- later rebroadcasts of the transaction would eventually succeed once the correct height was reached.
1 parent ddeaab6 commit 463ba15

File tree

1 file changed

+176
-1
lines changed

1 file changed

+176
-1
lines changed

lightning/src/chain/onchaintx.rs

+176-1
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
786786
let mut preprocessed_requests = Vec::with_capacity(requests.len());
787787
for req in requests {
788788
let package_locktime = req.package_locktime(cur_height);
789-
if package_locktime > cur_height + 1 {
789+
if package_locktime > cur_height {
790790
log_info!(logger, "Delaying claim of package until its timelock at {} (current height {}), the following outpoints are spent:", package_locktime, cur_height);
791791
for outpoint in req.outpoints() {
792792
log_info!(logger, " Outpoint {}", outpoint);
@@ -1276,3 +1276,178 @@ impl<ChannelSigner: EcdsaChannelSigner> OnchainTxHandler<ChannelSigner> {
12761276
&self.channel_transaction_parameters.channel_type_features
12771277
}
12781278
}
1279+
1280+
#[cfg(test)]
1281+
mod tests {
1282+
use bitcoin::hash_types::Txid;
1283+
use bitcoin::hashes::sha256::Hash as Sha256;
1284+
use bitcoin::hashes::Hash;
1285+
use bitcoin::Network;
1286+
use bitcoin::{key::Secp256k1, secp256k1::PublicKey, secp256k1::SecretKey, ScriptBuf};
1287+
use types::features::ChannelTypeFeatures;
1288+
1289+
use crate::chain::chaininterface::{ConfirmationTarget, LowerBoundedFeeEstimator};
1290+
use crate::chain::package::{HolderHTLCOutput, PackageSolvingData, PackageTemplate};
1291+
use crate::chain::transaction::OutPoint;
1292+
use crate::ln::chan_utils::{
1293+
ChannelPublicKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters,
1294+
HTLCOutputInCommitment, HolderCommitmentTransaction,
1295+
};
1296+
use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint};
1297+
use crate::ln::functional_test_utils::create_dummy_block;
1298+
use crate::sign::InMemorySigner;
1299+
use crate::types::payment::{PaymentHash, PaymentPreimage};
1300+
use crate::util::test_utils::{TestBroadcaster, TestFeeEstimator, TestLogger};
1301+
1302+
use super::OnchainTxHandler;
1303+
1304+
// Test that all claims with locktime equal to or less than the current height are broadcast
1305+
// immediately while claims with locktime greater than the current height are only broadcast
1306+
// once the locktime is reached.
1307+
#[test]
1308+
fn test_broadcast_height() {
1309+
let secp_ctx = Secp256k1::new();
1310+
let signer = InMemorySigner::new(
1311+
&secp_ctx,
1312+
SecretKey::from_slice(&[41; 32]).unwrap(),
1313+
SecretKey::from_slice(&[41; 32]).unwrap(),
1314+
SecretKey::from_slice(&[41; 32]).unwrap(),
1315+
SecretKey::from_slice(&[41; 32]).unwrap(),
1316+
SecretKey::from_slice(&[41; 32]).unwrap(),
1317+
[41; 32],
1318+
0,
1319+
[0; 32],
1320+
[0; 32],
1321+
);
1322+
let counterparty_pubkeys = ChannelPublicKeys {
1323+
funding_pubkey: PublicKey::from_secret_key(
1324+
&secp_ctx,
1325+
&SecretKey::from_slice(&[44; 32]).unwrap(),
1326+
),
1327+
revocation_basepoint: RevocationBasepoint::from(PublicKey::from_secret_key(
1328+
&secp_ctx,
1329+
&SecretKey::from_slice(&[45; 32]).unwrap(),
1330+
)),
1331+
payment_point: PublicKey::from_secret_key(
1332+
&secp_ctx,
1333+
&SecretKey::from_slice(&[46; 32]).unwrap(),
1334+
),
1335+
delayed_payment_basepoint: DelayedPaymentBasepoint::from(PublicKey::from_secret_key(
1336+
&secp_ctx,
1337+
&SecretKey::from_slice(&[47; 32]).unwrap(),
1338+
)),
1339+
htlc_basepoint: HtlcBasepoint::from(PublicKey::from_secret_key(
1340+
&secp_ctx,
1341+
&SecretKey::from_slice(&[48; 32]).unwrap(),
1342+
)),
1343+
};
1344+
let funding_outpoint = OutPoint { txid: Txid::all_zeros(), index: u16::MAX };
1345+
1346+
// Use non-anchor channels so that HTLC-Timeouts are broadcast immediately instead of sent
1347+
// to the user for external funding.
1348+
let chan_params = ChannelTransactionParameters {
1349+
holder_pubkeys: signer.holder_channel_pubkeys.clone(),
1350+
holder_selected_contest_delay: 66,
1351+
is_outbound_from_holder: true,
1352+
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
1353+
pubkeys: counterparty_pubkeys,
1354+
selected_contest_delay: 67,
1355+
}),
1356+
funding_outpoint: Some(funding_outpoint),
1357+
channel_type_features: ChannelTypeFeatures::only_static_remote_key(),
1358+
};
1359+
1360+
// Create an OnchainTxHandler for a commitment containing HTLCs with CLTV expiries of 0, 1,
1361+
// and 2 blocks.
1362+
let mut htlcs = Vec::new();
1363+
for i in 0..3 {
1364+
let preimage = PaymentPreimage([i; 32]);
1365+
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).to_byte_array());
1366+
htlcs.push((
1367+
HTLCOutputInCommitment {
1368+
offered: true,
1369+
amount_msat: 10000,
1370+
cltv_expiry: i as u32,
1371+
payment_hash: hash,
1372+
transaction_output_index: Some(i as u32),
1373+
},
1374+
(),
1375+
));
1376+
}
1377+
let holder_commit = HolderCommitmentTransaction::dummy(&mut htlcs);
1378+
let mut tx_handler = OnchainTxHandler::new(
1379+
1000000,
1380+
[0; 32],
1381+
ScriptBuf::new(),
1382+
signer,
1383+
chan_params,
1384+
holder_commit,
1385+
secp_ctx,
1386+
);
1387+
1388+
// Create a broadcaster with current block height 1.
1389+
let broadcaster = TestBroadcaster::new(Network::Testnet);
1390+
{
1391+
let mut blocks = broadcaster.blocks.lock().unwrap();
1392+
let genesis_hash = blocks[0].0.block_hash();
1393+
blocks.push((create_dummy_block(genesis_hash, 0, Vec::new()), 1));
1394+
}
1395+
1396+
let fee_estimator = TestFeeEstimator::new(253);
1397+
let fee_estimator = LowerBoundedFeeEstimator::new(&fee_estimator);
1398+
let logger = TestLogger::new();
1399+
1400+
// Request claiming of each HTLC on the holder's commitment, with current block height 1.
1401+
let holder_commit_txid = tx_handler.get_unsigned_holder_commitment_tx().compute_txid();
1402+
let mut requests = Vec::new();
1403+
for (htlc, _) in htlcs {
1404+
requests.push(PackageTemplate::build_package(
1405+
holder_commit_txid,
1406+
htlc.transaction_output_index.unwrap(),
1407+
PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build_offered(
1408+
htlc.amount_msat,
1409+
htlc.cltv_expiry,
1410+
ChannelTypeFeatures::only_static_remote_key(),
1411+
)),
1412+
0,
1413+
));
1414+
}
1415+
tx_handler.update_claims_view_from_requests(
1416+
requests,
1417+
1,
1418+
1,
1419+
&&broadcaster,
1420+
ConfirmationTarget::UrgentOnChainSweep,
1421+
&fee_estimator,
1422+
&logger,
1423+
);
1424+
1425+
// HTLC-Timeouts should be broadcast for the HTLCs with expiries at heights 0 and 1. The
1426+
// HTLC with expiry at height 2 should not be claimed yet.
1427+
let txs_broadcasted = broadcaster.txn_broadcast();
1428+
assert_eq!(txs_broadcasted.len(), 2);
1429+
assert!(txs_broadcasted[0].lock_time.to_consensus_u32() <= 1);
1430+
assert!(txs_broadcasted[1].lock_time.to_consensus_u32() <= 1);
1431+
1432+
// Advance to block height 2, and reprocess pending claims.
1433+
{
1434+
let mut blocks = broadcaster.blocks.lock().unwrap();
1435+
let block1_hash = blocks[1].0.block_hash();
1436+
blocks.push((create_dummy_block(block1_hash, 0, Vec::new()), 2));
1437+
}
1438+
tx_handler.update_claims_view_from_requests(
1439+
Vec::new(),
1440+
2,
1441+
2,
1442+
&&broadcaster,
1443+
ConfirmationTarget::UrgentOnChainSweep,
1444+
&fee_estimator,
1445+
&logger,
1446+
);
1447+
1448+
// The final HTLC-Timeout should now be broadcast.
1449+
let txs_broadcasted = broadcaster.txn_broadcast();
1450+
assert_eq!(txs_broadcasted.len(), 1);
1451+
assert_eq!(txs_broadcasted[0].lock_time.to_consensus_u32(), 2);
1452+
}
1453+
}

0 commit comments

Comments
 (0)