Skip to content

Commit 9397db6

Browse files
authored
Merge pull request #853 from TheBlueMatt/2021-03-transaction_unconfirmed
Add method to note transaction unconfirmed/reorged-out
2 parents 9577928 + 6982434 commit 9397db6

File tree

4 files changed

+199
-53
lines changed

4 files changed

+199
-53
lines changed

lightning/src/ln/channel.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ pub(super) struct Channel<Signer: Sign> {
377377

378378
/// The hash of the block in which the funding transaction was included.
379379
funding_tx_confirmed_in: Option<BlockHash>,
380-
funding_tx_confirmation_height: u64,
380+
funding_tx_confirmation_height: u32,
381381
short_channel_id: Option<u64>,
382382

383383
counterparty_dust_limit_satoshis: u64,
@@ -3591,7 +3591,7 @@ impl<Signer: Sign> Channel<Signer> {
35913591
}
35923592
}
35933593
}
3594-
self.funding_tx_confirmation_height = height as u64;
3594+
self.funding_tx_confirmation_height = height;
35953595
self.funding_tx_confirmed_in = Some(*block_hash);
35963596
self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
35973597
Ok(scid) => Some(scid),
@@ -3678,6 +3678,32 @@ impl<Signer: Sign> Channel<Signer> {
36783678
Ok((None, timed_out_htlcs))
36793679
}
36803680

3681+
/// Indicates the funding transaction is no longer confirmed in the main chain. This may
3682+
/// force-close the channel, but may also indicate a harmless reorganization of a block or two
3683+
/// before the channel has reached funding_locked and we can just wait for more blocks.
3684+
pub fn funding_transaction_unconfirmed(&mut self) -> Result<(), msgs::ErrorMessage> {
3685+
if self.funding_tx_confirmation_height != 0 {
3686+
// We handle the funding disconnection by calling update_best_block with a height one
3687+
// below where our funding was connected, implying a reorg back to conf_height - 1.
3688+
let reorg_height = self.funding_tx_confirmation_height - 1;
3689+
// We use the time field to bump the current time we set on channel updates if its
3690+
// larger. If we don't know that time has moved forward, we can just set it to the last
3691+
// time we saw and it will be ignored.
3692+
let best_time = self.update_time_counter;
3693+
match self.update_best_block(reorg_height, best_time) {
3694+
Ok((funding_locked, timed_out_htlcs)) => {
3695+
assert!(funding_locked.is_none(), "We can't generate a funding with 0 confirmations?");
3696+
assert!(timed_out_htlcs.is_empty(), "We can't have accepted HTLCs with a timeout before our funding confirmation?");
3697+
Ok(())
3698+
},
3699+
Err(e) => Err(e)
3700+
}
3701+
} else {
3702+
// We never learned about the funding confirmation anyway, just ignore
3703+
Ok(())
3704+
}
3705+
}
3706+
36813707
// Methods to get unprompted messages to send to the remote end (or where we already returned
36823708
// something in the handler for the message that prompted this message):
36833709

lightning/src/ln/channelmanager.rs

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine};
2828
use bitcoin::hashes::sha256::Hash as Sha256;
2929
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3030
use bitcoin::hashes::cmp::fixed_time_eq;
31-
use bitcoin::hash_types::BlockHash;
31+
use bitcoin::hash_types::{BlockHash, Txid};
3232

3333
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
3434
use bitcoin::secp256k1::Secp256k1;
@@ -851,6 +851,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
851851
}
852852
}
853853

854+
/// Gets the current configuration applied to all new channels, as
855+
pub fn get_current_default_configuration(&self) -> &UserConfig {
856+
&self.default_configuration
857+
}
858+
854859
/// Creates a new outbound channel to the given remote node and with the given value.
855860
///
856861
/// user_id will be provided back as user_channel_id in FundingGenerationReady events to allow
@@ -3353,7 +3358,7 @@ where
33533358
"Blocks must be disconnected in chain-order - the disconnected block must have the correct height");
33543359
*self.last_block_hash.write().unwrap() = header.prev_blockhash;
33553360

3356-
self.do_chain_event(new_height, |channel| channel.update_best_block(new_height, header.time));
3361+
self.do_chain_event(Some(new_height), |channel| channel.update_best_block(new_height, header.time));
33573362
}
33583363
}
33593364

@@ -3364,8 +3369,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33643369
F::Target: FeeEstimator,
33653370
L::Target: Logger,
33663371
{
3372+
/// Calls a function which handles an on-chain event (blocks dis/connected, transactions
3373+
/// un/confirmed, etc) on each channel, handling any resulting errors or messages generated by
3374+
/// the function.
33673375
fn do_chain_event<FN: Fn(&mut Channel<Signer>) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage>>
3368-
(&self, height: u32, f: FN) {
3376+
(&self, height_opt: Option<u32>, f: FN) {
33693377
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
33703378
// during initialization prior to the chain_monitor being fully configured in some cases.
33713379
// See the docs for `ChannelManagerReadArgs` for more.
@@ -3424,24 +3432,26 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34243432
true
34253433
});
34263434

3427-
channel_state.claimable_htlcs.retain(|&(ref payment_hash, _), htlcs| {
3428-
htlcs.retain(|htlc| {
3429-
// If height is approaching the number of blocks we think it takes us to get
3430-
// our commitment transaction confirmed before the HTLC expires, plus the
3431-
// number of blocks we generally consider it to take to do a commitment update,
3432-
// just give up on it and fail the HTLC.
3433-
if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER {
3434-
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
3435-
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height));
3436-
timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason {
3437-
failure_code: 0x4000 | 15,
3438-
data: htlc_msat_height_data
3439-
}));
3440-
false
3441-
} else { true }
3435+
if let Some(height) = height_opt {
3436+
channel_state.claimable_htlcs.retain(|&(ref payment_hash, _), htlcs| {
3437+
htlcs.retain(|htlc| {
3438+
// If height is approaching the number of blocks we think it takes us to get
3439+
// our commitment transaction confirmed before the HTLC expires, plus the
3440+
// number of blocks we generally consider it to take to do a commitment update,
3441+
// just give up on it and fail the HTLC.
3442+
if height >= htlc.cltv_expiry - HTLC_FAIL_BACK_BUFFER {
3443+
let mut htlc_msat_height_data = byte_utils::be64_to_array(htlc.value).to_vec();
3444+
htlc_msat_height_data.extend_from_slice(&byte_utils::be32_to_array(height));
3445+
timed_out_htlcs.push((HTLCSource::PreviousHopData(htlc.prev_hop.clone()), payment_hash.clone(), HTLCFailReason::Reason {
3446+
failure_code: 0x4000 | 15,
3447+
data: htlc_msat_height_data
3448+
}));
3449+
false
3450+
} else { true }
3451+
});
3452+
!htlcs.is_empty() // Only retain this entry if htlcs has at least one entry.
34423453
});
3443-
!htlcs.is_empty() // Only retain this entry if htlcs has at least one entry.
3444-
});
3454+
}
34453455
}
34463456

34473457
self.handle_init_event_channel_failures(failed_channels);
@@ -3477,7 +3487,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34773487
log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
34783488

34793489
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3480-
self.do_chain_event(height, |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new())));
3490+
self.do_chain_event(Some(height), |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new())));
34813491
}
34823492

34833493
/// Updates channel state with the current best blockchain tip. You should attempt to call this
@@ -3506,7 +3516,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
35063516
self.latest_block_height.store(height as usize, Ordering::Release);
35073517
*self.last_block_hash.write().unwrap() = block_hash;
35083518

3509-
self.do_chain_event(height, |channel| channel.update_best_block(height, header.time));
3519+
self.do_chain_event(Some(height), |channel| channel.update_best_block(height, header.time));
35103520

35113521
loop {
35123522
// Update last_node_announcement_serial to be the max of its current value and the
@@ -3522,6 +3532,61 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
35223532
}
35233533
}
35243534

3535+
/// Gets the set of txids which should be monitored for their confirmation state.
3536+
///
3537+
/// If you're providing information about reorganizations via [`transaction_unconfirmed`], this
3538+
/// is the set of transactions which you may need to call [`transaction_unconfirmed`] for.
3539+
///
3540+
/// This may be useful to poll to determine the set of transactions which must be registered
3541+
/// with an Electrum server or for which an Electrum server needs to be polled to determine
3542+
/// transaction confirmation state.
3543+
///
3544+
/// This may update after any [`transactions_confirmed`] or [`block_connected`] call.
3545+
///
3546+
/// Note that this is NOT the set of transactions which must be included in calls to
3547+
/// [`transactions_confirmed`] if they are confirmed, but a small subset of it.
3548+
///
3549+
/// [`transactions_confirmed`]: Self::transactions_confirmed
3550+
/// [`transaction_unconfirmed`]: Self::transaction_unconfirmed
3551+
/// [`block_connected`]: chain::Listen::block_connected
3552+
pub fn get_relevant_txids(&self) -> Vec<Txid> {
3553+
let channel_state = self.channel_state.lock().unwrap();
3554+
let mut res = Vec::with_capacity(channel_state.short_to_id.len());
3555+
for chan in channel_state.by_id.values() {
3556+
if let Some(funding_txo) = chan.get_funding_txo() {
3557+
res.push(funding_txo.txid);
3558+
}
3559+
}
3560+
res
3561+
}
3562+
3563+
/// Marks a transaction as having been reorganized out of the blockchain.
3564+
///
3565+
/// If a transaction is included in [`get_relevant_txids`], and is no longer in the main branch
3566+
/// of the blockchain, this function should be called to indicate that the transaction should
3567+
/// be considered reorganized out.
3568+
///
3569+
/// Once this is called, the given transaction will no longer appear on [`get_relevant_txids`],
3570+
/// though this may be called repeatedly for a given transaction without issue.
3571+
///
3572+
/// Note that if the transaction is confirmed on the main chain in a different block (indicated
3573+
/// via a call to [`transactions_confirmed`]), it may re-appear in [`get_relevant_txids`], thus
3574+
/// be very wary of race-conditions wherein the final state of a transaction indicated via
3575+
/// these APIs is not the same as its state on the blockchain.
3576+
///
3577+
/// [`transactions_confirmed`]: Self::transactions_confirmed
3578+
/// [`get_relevant_txids`]: Self::get_relevant_txids
3579+
pub fn transaction_unconfirmed(&self, txid: &Txid) {
3580+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3581+
self.do_chain_event(None, |channel| {
3582+
if let Some(funding_txo) = channel.get_funding_txo() {
3583+
if funding_txo.txid == *txid {
3584+
channel.funding_transaction_unconfirmed().map(|_| (None, Vec::new()))
3585+
} else { Ok((None, Vec::new())) }
3586+
} else { Ok((None, Vec::new())) }
3587+
});
3588+
}
3589+
35253590
/// Blocks until ChannelManager needs to be persisted or a timeout is reached. It returns a bool
35263591
/// indicating whether persistence is necessary. Only one listener on
35273592
/// `await_persistable_update` or `await_persistable_update_timeout` is guaranteed to be woken

lightning/src/ln/functional_test_utils.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub fn mine_transaction<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transac
6262
pub fn confirm_transaction_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &Transaction, conf_height: u32) {
6363
let first_connect_height = node.best_block_info().1 + 1;
6464
assert!(first_connect_height <= conf_height);
65-
if conf_height - first_connect_height >= 1 {
65+
if conf_height > first_connect_height {
6666
connect_blocks(node, conf_height - first_connect_height);
6767
}
6868
let mut block = Block {
@@ -77,6 +77,7 @@ pub fn confirm_transaction_at<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, tx: &T
7777
}
7878

7979
/// The possible ways we may notify a ChannelManager of a new block
80+
#[derive(Clone, Copy, PartialEq)]
8081
pub enum ConnectStyle {
8182
/// Calls update_best_block first, detecting transactions in the block only after receiving the
8283
/// header and height information.
@@ -281,7 +282,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
281282
let mut w = test_utils::TestVecWriter(Vec::new());
282283
self.node.write(&mut w).unwrap();
283284
<(BlockHash, ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>)>::read(&mut ::std::io::Cursor::new(w.0), ChannelManagerReadArgs {
284-
default_config: UserConfig::default(),
285+
default_config: *self.node.get_current_default_configuration(),
285286
keys_manager: self.keys_manager,
286287
fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: 253 },
287288
chain_monitor: self.chain_monitor,
@@ -1413,7 +1414,7 @@ pub fn check_preimage_claim<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, prev_txn: &Vec<
14131414
res
14141415
}
14151416

1416-
pub fn get_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b, 'c>>, a: usize, b: usize) {
1417+
pub fn handle_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b, 'c>>, a: usize, b: usize, needs_err_handle: bool, expected_error: &str) {
14171418
let events_1 = nodes[a].node.get_and_clear_pending_msg_events();
14181419
assert_eq!(events_1.len(), 2);
14191420
let as_update = match events_1[0] {
@@ -1425,25 +1426,30 @@ pub fn get_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b,
14251426
match events_1[1] {
14261427
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
14271428
assert_eq!(node_id, nodes[b].node.get_our_node_id());
1428-
assert_eq!(msg.data, "Commitment or closing transaction was confirmed on chain.");
1429+
assert_eq!(msg.data, expected_error);
1430+
if needs_err_handle {
1431+
nodes[b].node.handle_error(&nodes[a].node.get_our_node_id(), msg);
1432+
}
14291433
},
14301434
_ => panic!("Unexpected event"),
14311435
}
14321436

14331437
let events_2 = nodes[b].node.get_and_clear_pending_msg_events();
1434-
assert_eq!(events_2.len(), 2);
1438+
assert_eq!(events_2.len(), if needs_err_handle { 1 } else { 2 });
14351439
let bs_update = match events_2[0] {
14361440
MessageSendEvent::BroadcastChannelUpdate { ref msg } => {
14371441
msg.clone()
14381442
},
14391443
_ => panic!("Unexpected event"),
14401444
};
1441-
match events_2[1] {
1442-
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
1443-
assert_eq!(node_id, nodes[a].node.get_our_node_id());
1444-
assert_eq!(msg.data, "Commitment or closing transaction was confirmed on chain.");
1445-
},
1446-
_ => panic!("Unexpected event"),
1445+
if !needs_err_handle {
1446+
match events_2[1] {
1447+
MessageSendEvent::HandleError { node_id, action: msgs::ErrorAction::SendErrorMessage { ref msg } } => {
1448+
assert_eq!(node_id, nodes[a].node.get_our_node_id());
1449+
assert_eq!(msg.data, expected_error);
1450+
},
1451+
_ => panic!("Unexpected event"),
1452+
}
14471453
}
14481454

14491455
for node in nodes {
@@ -1452,6 +1458,10 @@ pub fn get_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b,
14521458
}
14531459
}
14541460

1461+
pub fn get_announce_close_broadcast_events<'a, 'b, 'c>(nodes: &Vec<Node<'a, 'b, 'c>>, a: usize, b: usize) {
1462+
handle_announce_close_broadcast_events(nodes, a, b, false, "Commitment or closing transaction was confirmed on chain.");
1463+
}
1464+
14551465
#[cfg(test)]
14561466
macro_rules! get_channel_value_stat {
14571467
($node: expr, $channel_id: expr) => {{

0 commit comments

Comments
 (0)