mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 23:08:36 +01:00
Move ChannelManager to Channel's new block data API
This also moves the scanning of the block for commitment transactions into channel, unifying the error path.
This commit is contained in:
parent
871f414367
commit
60b962a18e
2 changed files with 69 additions and 99 deletions
|
@ -7,7 +7,6 @@
|
||||||
// You may not use this file except in accordance with one or both of these
|
// You may not use this file except in accordance with one or both of these
|
||||||
// licenses.
|
// licenses.
|
||||||
|
|
||||||
use bitcoin::blockdata::block::BlockHeader;
|
|
||||||
use bitcoin::blockdata::script::{Script,Builder};
|
use bitcoin::blockdata::script::{Script,Builder};
|
||||||
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
|
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
|
||||||
use bitcoin::blockdata::opcodes;
|
use bitcoin::blockdata::opcodes;
|
||||||
|
@ -3502,47 +3501,63 @@ impl<Signer: Sign> Channel<Signer> {
|
||||||
self.network_sync == UpdateStatus::DisabledMarked
|
self.network_sync == UpdateStatus::DisabledMarked
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transactions_confirmed(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData) -> Result<(), msgs::ErrorMessage> {
|
/// When a transaction is confirmed, we check whether it is or spends the funding transaction
|
||||||
|
/// In the first case, we store the confirmation height and calculating the short channel id.
|
||||||
|
/// In the second, we simply return an Err indicating we need to be force-closed now.
|
||||||
|
pub fn transactions_confirmed<L: Deref>(&mut self, block_hash: &BlockHash, height: u32, txdata: &TransactionData, logger: &L)
|
||||||
|
-> Result<(), msgs::ErrorMessage> where L::Target: Logger {
|
||||||
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
|
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
|
||||||
if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
|
for &(index_in_block, tx) in txdata.iter() {
|
||||||
for &(index_in_block, tx) in txdata.iter() {
|
if let Some(funding_txo) = self.get_funding_txo() {
|
||||||
let funding_txo = self.get_funding_txo().unwrap();
|
// If we haven't yet sent a funding_locked, but are in FundingSent (ignoring
|
||||||
if tx.txid() == funding_txo.txid {
|
// whether they've sent a funding_locked or not), check if we should send one.
|
||||||
let txo_idx = funding_txo.index as usize;
|
if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
|
||||||
if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
|
if tx.txid() == funding_txo.txid {
|
||||||
tx.output[txo_idx].value != self.channel_value_satoshis {
|
let txo_idx = funding_txo.index as usize;
|
||||||
if self.is_outbound() {
|
if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
|
||||||
// If we generated the funding transaction and it doesn't match what it
|
tx.output[txo_idx].value != self.channel_value_satoshis {
|
||||||
// should, the client is really broken and we should just panic and
|
if self.is_outbound() {
|
||||||
// tell them off. That said, because hash collisions happen with high
|
// If we generated the funding transaction and it doesn't match what it
|
||||||
// probability in fuzztarget mode, if we're fuzzing we just close the
|
// should, the client is really broken and we should just panic and
|
||||||
// channel and move on.
|
// tell them off. That said, because hash collisions happen with high
|
||||||
#[cfg(not(feature = "fuzztarget"))]
|
// probability in fuzztarget mode, if we're fuzzing we just close the
|
||||||
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
|
// channel and move on.
|
||||||
}
|
#[cfg(not(feature = "fuzztarget"))]
|
||||||
self.channel_state = ChannelState::ShutdownComplete as u32;
|
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
|
||||||
self.update_time_counter += 1;
|
}
|
||||||
return Err(msgs::ErrorMessage {
|
self.channel_state = ChannelState::ShutdownComplete as u32;
|
||||||
channel_id: self.channel_id(),
|
self.update_time_counter += 1;
|
||||||
data: "funding tx had wrong script/value".to_owned()
|
return Err(msgs::ErrorMessage {
|
||||||
});
|
channel_id: self.channel_id(),
|
||||||
} else {
|
data: "funding tx had wrong script/value or output index".to_owned()
|
||||||
if self.is_outbound() {
|
});
|
||||||
for input in tx.input.iter() {
|
} else {
|
||||||
if input.witness.is_empty() {
|
if self.is_outbound() {
|
||||||
// We generated a malleable funding transaction, implying we've
|
for input in tx.input.iter() {
|
||||||
// just exposed ourselves to funds loss to our counterparty.
|
if input.witness.is_empty() {
|
||||||
#[cfg(not(feature = "fuzztarget"))]
|
// We generated a malleable funding transaction, implying we've
|
||||||
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
|
// just exposed ourselves to funds loss to our counterparty.
|
||||||
|
#[cfg(not(feature = "fuzztarget"))]
|
||||||
|
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.funding_tx_confirmation_height = height as u64;
|
||||||
|
self.funding_tx_confirmed_in = Some(*block_hash);
|
||||||
|
self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
|
||||||
|
Ok(scid) => Some(scid),
|
||||||
|
Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.funding_tx_confirmation_height = height as u64;
|
}
|
||||||
self.funding_tx_confirmed_in = Some(*block_hash);
|
}
|
||||||
self.short_channel_id = match scid_from_parts(height as u64, index_in_block as u64, txo_idx as u64) {
|
for inp in tx.input.iter() {
|
||||||
Ok(scid) => Some(scid),
|
if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
|
||||||
Err(_) => panic!("Block was bogus - either height was > 16 million, had > 16 million transactions, or had > 65k outputs"),
|
log_trace!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.channel_id()));
|
||||||
}
|
return Err(msgs::ErrorMessage {
|
||||||
|
channel_id: self.channel_id(),
|
||||||
|
data: "Commitment or closing transaction was confirmed on chain.".to_owned()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3635,35 +3650,6 @@ impl<Signer: Sign> Channel<Signer> {
|
||||||
Ok((None, timed_out_htlcs))
|
Ok((None, timed_out_htlcs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we receive a new block, we (a) check whether the block contains the funding
|
|
||||||
/// transaction (which would start us counting blocks until we send the funding_signed), and
|
|
||||||
/// (b) check the height of the block against outbound holding cell HTLCs in case we need to
|
|
||||||
/// give up on them prematurely and time them out. Everything else (e.g. commitment
|
|
||||||
/// transaction broadcasts, channel closure detection, HTLC transaction broadcasting, etc) is
|
|
||||||
/// handled by the ChannelMonitor.
|
|
||||||
///
|
|
||||||
/// If we return Err, the channel may have been closed, at which point the standard
|
|
||||||
/// requirements apply - no calls may be made except those explicitly stated to be allowed
|
|
||||||
/// post-shutdown.
|
|
||||||
/// Only returns an ErrorAction of DisconnectPeer, if Err.
|
|
||||||
///
|
|
||||||
/// May return some HTLCs (and their payment_hash) which have timed out and should be failed
|
|
||||||
/// back.
|
|
||||||
pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
|
|
||||||
self.transactions_confirmed(&header.block_hash(), height, txdata)?;
|
|
||||||
self.update_best_block(height, header.time)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called by channelmanager based on chain blocks being disconnected.
|
|
||||||
/// Returns true if we need to close the channel now due to funding transaction
|
|
||||||
/// unconfirmation/reorg.
|
|
||||||
pub fn block_disconnected(&mut self, header: &BlockHeader, new_height: u32) -> bool {
|
|
||||||
if self.update_best_block(new_height, header.time).is_err() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods to get unprompted messages to send to the remote end (or where we already returned
|
// Methods to get unprompted messages to send to the remote end (or where we already returned
|
||||||
// something in the handler for the message that prompted this message):
|
// something in the handler for the message that prompted this message):
|
||||||
|
|
||||||
|
|
|
@ -3334,7 +3334,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
||||||
let short_to_id = &mut channel_state.short_to_id;
|
let short_to_id = &mut channel_state.short_to_id;
|
||||||
let pending_msg_events = &mut channel_state.pending_msg_events;
|
let pending_msg_events = &mut channel_state.pending_msg_events;
|
||||||
channel_state.by_id.retain(|_, channel| {
|
channel_state.by_id.retain(|_, channel| {
|
||||||
let res = channel.block_connected(header, txdata, height);
|
let res = channel.transactions_confirmed(&block_hash, height, txdata, &self.logger)
|
||||||
|
.and_then(|_| channel.update_best_block(height, header.time));
|
||||||
if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
|
if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
|
||||||
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
|
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
|
||||||
let chan_update = self.get_channel_update(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
|
let chan_update = self.get_channel_update(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
|
||||||
|
@ -3360,38 +3361,23 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
||||||
short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
|
short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
|
||||||
}
|
}
|
||||||
} else if let Err(e) = res {
|
} else if let Err(e) = res {
|
||||||
|
if let Some(short_id) = channel.get_short_channel_id() {
|
||||||
|
short_to_id.remove(&short_id);
|
||||||
|
}
|
||||||
|
// It looks like our counterparty went on-chain or funding transaction was
|
||||||
|
// reorged out of the main chain. Close the channel.
|
||||||
|
failed_channels.push(channel.force_shutdown(true));
|
||||||
|
if let Ok(update) = self.get_channel_update(&channel) {
|
||||||
|
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
|
||||||
|
msg: update
|
||||||
|
});
|
||||||
|
}
|
||||||
pending_msg_events.push(events::MessageSendEvent::HandleError {
|
pending_msg_events.push(events::MessageSendEvent::HandleError {
|
||||||
node_id: channel.get_counterparty_node_id(),
|
node_id: channel.get_counterparty_node_id(),
|
||||||
action: msgs::ErrorAction::SendErrorMessage { msg: e },
|
action: msgs::ErrorAction::SendErrorMessage { msg: e },
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let Some(funding_txo) = channel.get_funding_txo() {
|
|
||||||
for &(_, tx) in txdata.iter() {
|
|
||||||
for inp in tx.input.iter() {
|
|
||||||
if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
|
|
||||||
log_trace!(self.logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(channel.channel_id()));
|
|
||||||
if let Some(short_id) = channel.get_short_channel_id() {
|
|
||||||
short_to_id.remove(&short_id);
|
|
||||||
}
|
|
||||||
// It looks like our counterparty went on-chain. Close the channel.
|
|
||||||
failed_channels.push(channel.force_shutdown(true));
|
|
||||||
if let Ok(update) = self.get_channel_update(&channel) {
|
|
||||||
pending_msg_events.push(events::MessageSendEvent::BroadcastChannelUpdate {
|
|
||||||
msg: update
|
|
||||||
});
|
|
||||||
}
|
|
||||||
pending_msg_events.push(events::MessageSendEvent::HandleError {
|
|
||||||
node_id: channel.get_counterparty_node_id(),
|
|
||||||
action: msgs::ErrorAction::SendErrorMessage {
|
|
||||||
msg: msgs::ErrorMessage { channel_id: channel.channel_id(), data: "Commitment or closing transaction was confirmed on chain.".to_owned() }
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3456,8 +3442,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
||||||
let channel_state = &mut *channel_lock;
|
let channel_state = &mut *channel_lock;
|
||||||
let short_to_id = &mut channel_state.short_to_id;
|
let short_to_id = &mut channel_state.short_to_id;
|
||||||
let pending_msg_events = &mut channel_state.pending_msg_events;
|
let pending_msg_events = &mut channel_state.pending_msg_events;
|
||||||
channel_state.by_id.retain(|channel_id, v| {
|
channel_state.by_id.retain(|_, v| {
|
||||||
if v.block_disconnected(header, new_height) {
|
if let Err(err_msg) = v.update_best_block(new_height, header.time) {
|
||||||
if let Some(short_id) = v.get_short_channel_id() {
|
if let Some(short_id) = v.get_short_channel_id() {
|
||||||
short_to_id.remove(&short_id);
|
short_to_id.remove(&short_id);
|
||||||
}
|
}
|
||||||
|
@ -3469,9 +3455,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
|
||||||
}
|
}
|
||||||
pending_msg_events.push(events::MessageSendEvent::HandleError {
|
pending_msg_events.push(events::MessageSendEvent::HandleError {
|
||||||
node_id: v.get_counterparty_node_id(),
|
node_id: v.get_counterparty_node_id(),
|
||||||
action: msgs::ErrorAction::SendErrorMessage {
|
action: msgs::ErrorAction::SendErrorMessage { msg: err_msg },
|
||||||
msg: msgs::ErrorMessage { channel_id: *channel_id, data: "Funding transaction was un-confirmed.".to_owned() }
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue