While these transactions were still valid, we incorrectly assumed that
they would propagate with a locktime of `current_height + 1`, when in
reality, only those with a locktime strictly lower than the next height
in the chain are allowed to enter the mempool.
preprocessed_requests.push(req);
}
preprocessed_requests.push(req);
}
- // Claim everything up to and including cur_height + 1
- let remaining_locked_packages = self.locktimed_packages.split_off(&(cur_height + 2));
+ // Claim everything up to and including `cur_height`
+ let remaining_locked_packages = self.locktimed_packages.split_off(&(cur_height + 1));
for (pop_height, mut entry) in self.locktimed_packages.iter_mut() {
log_trace!(logger, "Restoring delayed claim of package(s) at their timelock at {}.", pop_height);
preprocessed_requests.append(&mut entry);
for (pop_height, mut entry) in self.locktimed_packages.iter_mut() {
log_trace!(logger, "Restoring delayed claim of package(s) at their timelock at {}.", pop_height);
preprocessed_requests.append(&mut entry);
}
}
fn absolute_tx_timelock(&self, current_height: u32) -> u32 {
}
}
fn absolute_tx_timelock(&self, current_height: u32) -> u32 {
- // We use `current_height + 1` as our default locktime to discourage fee sniping and because
+ // We use `current_height` as our default locktime to discourage fee sniping and because
// transactions with it always propagate.
let absolute_timelock = match self {
// transactions with it always propagate.
let absolute_timelock = match self {
- PackageSolvingData::RevokedOutput(_) => current_height + 1,
- PackageSolvingData::RevokedHTLCOutput(_) => current_height + 1,
- PackageSolvingData::CounterpartyOfferedHTLCOutput(_) => current_height + 1,
- PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => cmp::max(outp.htlc.cltv_expiry, current_height + 1),
+ PackageSolvingData::RevokedOutput(_) => current_height,
+ PackageSolvingData::RevokedHTLCOutput(_) => current_height,
+ PackageSolvingData::CounterpartyOfferedHTLCOutput(_) => current_height,
+ PackageSolvingData::CounterpartyReceivedHTLCOutput(ref outp) => cmp::max(outp.htlc.cltv_expiry, current_height),
// HTLC timeout/success transactions rely on a fixed timelock due to the counterparty's
// signature.
PackageSolvingData::HolderHTLCOutput(ref outp) => {
// HTLC timeout/success transactions rely on a fixed timelock due to the counterparty's
// signature.
PackageSolvingData::HolderHTLCOutput(ref outp) => {
- PackageSolvingData::HolderFundingOutput(_) => current_height + 1,
+ PackageSolvingData::HolderFundingOutput(_) => current_height,
}
{
let height = self.best_block.read().unwrap().height();
}
{
let height = self.best_block.read().unwrap().height();
- // Transactions are evaluated as final by network mempools at the next block. However, the modules
- // constituting our Lightning node might not have perfect sync about their blockchain views. Thus, if
- // the wallet module is in advance on the LDK view, allow one more block of headroom.
- if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 2 {
+ // Transactions are evaluated as final by network mempools if their locktime is strictly
+ // lower than the next block height. However, the modules constituting our Lightning
+ // node might not have perfect sync about their blockchain views. Thus, if the wallet
+ // module is ahead of LDK, only allow one more block of headroom.
+ if !funding_transaction.input.iter().all(|input| input.sequence == Sequence::MAX) && LockTime::from(funding_transaction.lock_time).is_block_height() && funding_transaction.lock_time.0 > height + 1 {
return Err(APIError::APIMisuseError {
err: "Funding transaction absolute timelock is non-final".to_owned()
});
return Err(APIError::APIMisuseError {
err: "Funding transaction absolute timelock is non-final".to_owned()
});
#[cfg(feature = "std")] {
eprintln!("Connecting block using Block Connection Style: {:?}", *node.connect_style.borrow());
}
#[cfg(feature = "std")] {
eprintln!("Connecting block using Block Connection Style: {:?}", *node.connect_style.borrow());
}
+ // Update the block internally before handing it over to LDK, to ensure our assertions regarding
+ // transaction broadcast are correct.
+ node.blocks.lock().unwrap().push((block.clone(), height));
if !skip_intermediaries {
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
match *node.connect_style.borrow() {
if !skip_intermediaries {
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
match *node.connect_style.borrow() {
}
call_claimable_balances(node);
node.node.test_process_background_events();
}
call_claimable_balances(node);
node.node.test_process_background_events();
- node.blocks.lock().unwrap().push((block, height));
}
pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) {
}
pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32) {
mine_transaction(&nodes[0], &remote_txn[0]);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
mine_transaction(&nodes[0], &remote_txn[0]);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
assert_eq!(claim_txn.len(), 3);
let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
assert_eq!(claim_txn.len(), 3);
test_txn_broadcast(&nodes[1], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::NONE);
mine_transaction(&nodes[0], &revoked_local_txn[0]);
test_txn_broadcast(&nodes[1], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::NONE);
mine_transaction(&nodes[0], &revoked_local_txn[0]);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
// Verify broadcast of revoked HTLC-timeout
let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
check_added_monitors!(nodes[0], 1);
// Verify broadcast of revoked HTLC-timeout
let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT);
check_added_monitors!(nodes[0], 1);
// Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()]});
// Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
let header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[1].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[1], &Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone(), node_txn[1].clone()]});
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
{
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
{
let mut added_monitors = nodes[1].chain_monitor.added_monitors.lock().unwrap();
assert_eq!(added_monitors.len(), 1);
assert_eq!(commitment_spend.input.len(), 2);
assert_eq!(commitment_spend.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert_eq!(commitment_spend.input[1].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert_eq!(commitment_spend.input.len(), 2);
assert_eq!(commitment_spend.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert_eq!(commitment_spend.input[1].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
- assert_eq!(commitment_spend.lock_time.0, nodes[1].best_block_info().1 + 1);
+ assert_eq!(commitment_spend.lock_time.0, nodes[1].best_block_info().1);
assert!(commitment_spend.output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
// We don't bother to check that B can claim the HTLC output on its commitment tx here as
// we already checked the same situation with A.
assert!(commitment_spend.output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
// We don't bother to check that B can claim the HTLC output on its commitment tx here as
// we already checked the same situation with A.
// Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[0], &Block { header, txdata: vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()] });
// Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: nodes[0].best_block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42};
connect_block(&nodes[0], &Block { header, txdata: vec![node_a_commitment_tx[0].clone(), commitment_spend.clone()] });
- connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let events = nodes[0].node.get_and_clear_pending_events();
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
let events = nodes[0].node.get_and_clear_pending_events();
check_spends!(commitment_tx[0], chan_1.3);
mine_transaction(&nodes[0], &commitment_tx[0]);
check_spends!(commitment_tx[0], chan_1.3);
mine_transaction(&nodes[0], &commitment_tx[0]);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + MIN_CLTV_EXPIRY_DELTA as u32); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
_ => panic!("Unexpected event"),
}
MessageSendEvent::BroadcastChannelUpdate { .. } => {},
_ => panic!("Unexpected event"),
}
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
// Check B's monitor was able to send back output descriptor event for timeout tx on A's commitment tx
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
// Check B's monitor was able to send back output descriptor event for timeout tx on A's commitment tx
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(revoked_htlc_txn.len(), 1);
let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(revoked_htlc_txn.len(), 1);
check_spends!(b_txn[0], commitment_tx[0]);
assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
check_spends!(b_txn[0], commitment_tx[0]);
assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
- assert_eq!(b_txn[0].lock_time.0, nodes[1].best_block_info().1 + 1); // Success tx
+ assert_eq!(b_txn[0].lock_time.0, nodes[1].best_block_info().1); // Success tx
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 40 + MIN_CLTV_EXPIRY_DELTA as u32 - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - 40 + MIN_CLTV_EXPIRY_DELTA as u32); // Confirm blocks until the HTLC expires
let htlc_timeout_tx;
{ // Extract one of the two HTLC-Timeout transaction
let htlc_timeout_tx;
{ // Extract one of the two HTLC-Timeout transaction
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
// Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx
mine_transaction(&nodes[0], &local_txn_1[0]);
// Timeout HTLC on A's chain and so it can generate a HTLC-Timeout tx
mine_transaction(&nodes[0], &local_txn_1[0]);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
timeout_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().drain(..)
.filter(|tx| tx.input[0].previous_output.txid == bs_commitment_tx[0].txid()).collect();
check_spends!(timeout_tx[0], bs_commitment_tx[0]);
timeout_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().drain(..)
.filter(|tx| tx.input[0].previous_output.txid == bs_commitment_tx[0].txid()).collect();
check_spends!(timeout_tx[0], bs_commitment_tx[0]);
if !revoked {
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
} else {
if !revoked {
assert_eq!(timeout_tx[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
} else {
- assert_eq!(timeout_tx[0].lock_time.0, 12);
+ assert_eq!(timeout_tx[0].lock_time.0, 11);
}
// We fail non-dust-HTLC 2 by broadcast of local timeout/revocation-claim tx
mine_transaction(&nodes[0], &timeout_tx[0]);
}
// We fail non-dust-HTLC 2 by broadcast of local timeout/revocation-claim tx
mine_transaction(&nodes[0], &timeout_tx[0]);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[1], true);
check_added_monitors!(nodes[1], 1);
check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[1], 49); // Confirm blocks until the HTLC expires (note CLTV was explicitly 50 above)
+ connect_blocks(&nodes[1], 50); // Confirm blocks until the HTLC expires (note CLTV was explicitly 50 above)
let revoked_htlc_txn = {
let txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
let revoked_htlc_txn = {
let txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
expect_payment_claimed!(nodes[1], payment_hash, 3_000_000);
mine_transaction(&nodes[1], &remote_txn[0]);
check_added_monitors!(nodes[1], 2);
expect_payment_claimed!(nodes[1], payment_hash, 3_000_000);
mine_transaction(&nodes[1], &remote_txn[0]);
check_added_monitors!(nodes[1], 2);
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
// One or more claim tx should have been broadcast, check it
let timeout;
// One or more claim tx should have been broadcast, check it
let timeout;
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
check_closed_broadcast!(nodes[0], true);
check_added_monitors!(nodes[0], 1);
check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed);
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV);
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
let htlc_timeout = {
let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(events.len(), 1);
let mut tx = match events[0] {
Event::FundingGenerationReady { ref channel_value_satoshis, ref output_script, .. } => {
assert_eq!(events.len(), 1);
let mut tx = match events[0] {
Event::FundingGenerationReady { ref channel_value_satoshis, ref output_script, .. } => {
- // Timelock the transaction _beyond_ the best client height + 2.
- Transaction { version: chan_id as i32, lock_time: PackedLockTime(best_height + 3), input: vec![input], output: vec![TxOut {
+ // Timelock the transaction _beyond_ the best client height + 1.
+ Transaction { version: chan_id as i32, lock_time: PackedLockTime(best_height + 2), input: vec![input], output: vec![TxOut {
value: *channel_value_satoshis, script_pubkey: output_script.clone(),
}]}
},
value: *channel_value_satoshis, script_pubkey: output_script.clone(),
}]}
},
- // However, transaction should be accepted if it's in a +2 headroom from best block.
+ // However, transaction should be accepted if it's in a +1 headroom from best block.
tx.lock_time = PackedLockTime(tx.lock_time.0 - 1);
assert!(nodes[0].node.funding_transaction_generated(&temp_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).is_ok());
get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
tx.lock_time = PackedLockTime(tx.lock_time.0 - 1);
assert!(nodes[0].node.funding_transaction_generated(&temp_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).is_ok());
get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
// When the HTLC timeout output is spendable in the next block, A should broadcast it
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
// When the HTLC timeout output is spendable in the next block, A should broadcast it
- connect_blocks(&nodes[0], htlc_cltv_timeout - nodes[0].best_block_info().1 - 1);
+ connect_blocks(&nodes[0], htlc_cltv_timeout - nodes[0].best_block_info().1);
let a_broadcast_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(a_broadcast_txn.len(), 2);
assert_eq!(a_broadcast_txn[0].input.len(), 1);
let a_broadcast_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(a_broadcast_txn.len(), 2);
assert_eq!(a_broadcast_txn[0].input.len(), 1);
// HTLC has been spent, even after the HTLC expires. We'll also fail the inbound HTLC, but it
// won't do anything as the channel is already closed.
// HTLC has been spent, even after the HTLC expires. We'll also fail the inbound HTLC, but it
// won't do anything as the channel is already closed.
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV);
let as_htlc_timeout_claim = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(as_htlc_timeout_claim.len(), 1);
check_spends!(as_htlc_timeout_claim[0], as_txn[0]);
let as_htlc_timeout_claim = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(as_htlc_timeout_claim.len(), 1);
check_spends!(as_htlc_timeout_claim[0], as_txn[0]);
// The next few blocks for B look the same as for A, though for the opposite HTLC
nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
// The next few blocks for B look the same as for A, though for the opposite HTLC
nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - (ANTI_REORG_DELAY - 1) - 1);
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV - (ANTI_REORG_DELAY - 1));
expect_pending_htlcs_forwardable_conditions!(nodes[1],
[HTLCDestination::FailedPayment { payment_hash: to_b_failed_payment_hash }]);
let bs_htlc_timeout_claim = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
expect_pending_htlcs_forwardable_conditions!(nodes[1],
[HTLCDestination::FailedPayment { payment_hash: to_b_failed_payment_hash }]);
let bs_htlc_timeout_claim = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
mine_transaction(&nodes[0], &commitment_tx);
// Connect blocks until the HTLC's expiration is met, expecting a transaction broadcast.
mine_transaction(&nodes[0], &commitment_tx);
// Connect blocks until the HTLC's expiration is met, expecting a transaction broadcast.
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV);
let htlc_timeout_tx = {
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
assert_eq!(txn.len(), 1);
let htlc_timeout_tx = {
let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
assert_eq!(txn.len(), 1);
};
// Connect blocks up to one before the HTLC expires. This should not result in a claim/retry.
};
// Connect blocks up to one before the HTLC expires. This should not result in a claim/retry.
- connect_blocks(&nodes[0], htlc_expiry - nodes[0].best_block_info().1 - 2);
+ connect_blocks(&nodes[0], htlc_expiry - nodes[0].best_block_info().1 - 1);
check_htlc_retry(false, false);
// Connect one more block, producing our first claim.
check_htlc_retry(false, false);
// Connect one more block, producing our first claim.
mine_transaction(&nodes[0], &bs_commitment_tx[0]);
mine_transaction(&nodes[1], &bs_commitment_tx[0]);
if !use_dust {
mine_transaction(&nodes[0], &bs_commitment_tx[0]);
mine_transaction(&nodes[1], &bs_commitment_tx[0]);
if !use_dust {
- connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1 + (MIN_CLTV_EXPIRY_DELTA as u32));
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1 + (MIN_CLTV_EXPIRY_DELTA as u32));
+ connect_blocks(&nodes[0], TEST_FINAL_CLTV + (MIN_CLTV_EXPIRY_DELTA as u32));
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV + (MIN_CLTV_EXPIRY_DELTA as u32));
let as_htlc_timeout = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
check_spends!(as_htlc_timeout[0], bs_commitment_tx[0]);
assert_eq!(as_htlc_timeout.len(), 1);
let as_htlc_timeout = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
check_spends!(as_htlc_timeout[0], bs_commitment_tx[0]);
assert_eq!(as_htlc_timeout.len(), 1);
if claim_htlc {
confirm_transaction(&nodes[1], &cs_commitment_tx[1]);
} else {
if claim_htlc {
confirm_transaction(&nodes[1], &cs_commitment_tx[1]);
} else {
- connect_blocks(&nodes[1], htlc_expiry - nodes[1].best_block_info().1);
+ connect_blocks(&nodes[1], htlc_expiry - nodes[1].best_block_info().1 + 1);
let bs_htlc_timeout_tx = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(bs_htlc_timeout_tx.len(), 1);
confirm_transaction(&nodes[1], &bs_htlc_timeout_tx[0]);
let bs_htlc_timeout_tx = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
assert_eq!(bs_htlc_timeout_tx.len(), 1);
confirm_transaction(&nodes[1], &bs_htlc_timeout_tx[0]);
// Give node 1 node 2's commitment transaction and get its response (timing the HTLC out)
mine_transaction(&nodes[1], &node_2_commitment_txn[0]);
// Give node 1 node 2's commitment transaction and get its response (timing the HTLC out)
mine_transaction(&nodes[1], &node_2_commitment_txn[0]);
- connect_blocks(&nodes[1], TEST_FINAL_CLTV - 1); // Confirm blocks until the HTLC expires
+ connect_blocks(&nodes[1], TEST_FINAL_CLTV); // Confirm blocks until the HTLC expires
let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
assert_eq!(node_1_commitment_txn.len(), 1); // ChannelMonitor: 1 offered HTLC-Timeout
check_spends!(node_1_commitment_txn[0], node_2_commitment_txn[0]);
let node_1_commitment_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
assert_eq!(node_1_commitment_txn.len(), 1); // ChannelMonitor: 1 offered HTLC-Timeout
check_spends!(node_1_commitment_txn[0], node_2_commitment_txn[0]);
fn broadcast_transaction(&self, tx: &Transaction) {
let lock_time = tx.lock_time.0;
assert!(lock_time < 1_500_000_000);
fn broadcast_transaction(&self, tx: &Transaction) {
let lock_time = tx.lock_time.0;
assert!(lock_time < 1_500_000_000);
- if lock_time > self.blocks.lock().unwrap().len() as u32 + 1 && lock_time < 500_000_000 {
+ if bitcoin::LockTime::from(tx.lock_time).is_block_height() && lock_time > self.blocks.lock().unwrap().last().unwrap().1 {
for inp in tx.input.iter() {
if inp.sequence != Sequence::MAX {
panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time);
for inp in tx.input.iter() {
if inp.sequence != Sequence::MAX {
panic!("We should never broadcast a transaction before its locktime ({})!", tx.lock_time);