-
Notifications
You must be signed in to change notification settings - Fork 406
Make Channel
's block connection API more electrum-friendly
#838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Channel
's block connection API more electrum-friendly
#838
Conversation
lightning/src/ln/channelmanager.rs
Outdated
@@ -3400,7 +3400,7 @@ 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 pending_msg_events = &mut channel_state.pending_msg_events; | |||
channel_state.by_id.retain(|_, v| { | |||
if v.block_disconnected(header) { | |||
if v.block_disconnected(header, new_height) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be the old height of the disconnected block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I dont think so? Thew new argument is passed into update_best_block
in channel and handled the same as a new block (and the header part ignored, except to get the time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess my confusion here is because in ChainMonitor
and ChannelMonitor
, the height is that of the disconnected header, which is inconsistent with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note new_height
is calculated by fetching the height from the local latest_block_height
variable, not from the user. In later commits, that variable is checked against what the user passes in.
lightning/src/ln/channel.rs
Outdated
if Some(header.block_hash()) == self.funding_tx_confirmed_in { | ||
self.funding_tx_confirmations = self.minimum_depth as u64 - 1; | ||
pub fn block_disconnected(&mut self, header: &BlockHeader, new_height: u32) -> bool { | ||
if self.update_best_block(new_height, header.time).is_err() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this be the header of the disconnected block rather than the best block? Presumably the best block will come from the next call to block_connected
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, that API needs to be clarified - I dropped the Channel::block_disconnected method.
21939e9
to
f4bd6cc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you plan also to dry-up ChannelManager::block_disconnected
in ChannelManager::update_best_block
?
/// | ||
/// 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this requirement holds right now ? We don't have a ChannelState::Reorged
blocking any further non post-shutdown calls, it should rather say "force_shutdown() should be the next call" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm? It could be clarified, but not just force_shutdown
is the next call, but force_shutdown
is the only allowed call ever again on this Channel
(and the stuff for get_channel_update
). This is true in any "return channel-closing-error" case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree on the only call allowed, my remark was more on the how of this restriction. After this PR, if we return from Channel::update_best_block
, we'll call force_shutdown
in ChannelManager::do_chain_event
.
I believe a more straightforward API would be to call force_shutdown
directly inside update_best_block
thus avoiding caller to forget to call force_shutdown
. State transition to ShutdownComplete
is only done in this latter method.
At least comment should say, "If we return Err, force_shutdown
must be called" ?
lightning/src/ln/channel.rs
Outdated
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 transaction was confirmed on chain.".to_owned() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future we might consider to dry-up that kind of messages. Otherwise, even if your light-client shelter its connections to an Electrum server behind Tor, a malicious server can still delay announcement of commitment transaction to observe a concomitant error message as a collusioning channel peer. And thus link your Lightning node to its validation backend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, possibly, we'd need to be very careful, however, that we handle several cases identically - eg it would be very easy to return a dummy error message, but it be detectable exactly which case we hit by observing other behavior.
// may have already happened for this block). | ||
// XXX: Test this case! | ||
if let Some(funding_locked) = self.check_get_funding_locked(height) { | ||
return Ok(Some(funding_locked)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I understand the rational of this special case -- Making 1-conf lock-in functional with regards to order of block confirmation/transaction announcement. But this should be documented pretty clearly in our API that either transactions_confirmed
or update_best_block
might generate FundingLocked
in function of minimum_depth
value. Really counter-intuitive to have a channel configuration variable changing by which method an event is expected to be delivered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but we don't document which message events a function may generate in any other place? What makes this site special - in general the PeerHandler should just be polling for new message events regularly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would serve more as a friendly note for library developers than library users. It was surprising at first sight with the old API model in mind, now I get it.
lightning/src/ln/channelmanager.rs
Outdated
/// XXX: Note that in the case that a transaction which was provided via this method is | ||
/// reorganized out of the best chain, the only current way to correctly handle the any | ||
/// associated channel force-closure is to walk the chain back from the current tip with | ||
/// repeated `block_disconnected` calls, followed by an `update_best_block` call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is calling update_best_block
requirement true ? ChannelManager::block_disconnected
is calling Channel::update_best_block
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm, docs unclear - I meant to go from the fork point to the new tip. In any case, I'm going to work on updating block_disconnected to build a cleaner API so I'll just fix it with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs is better now by mentioning both reorg fork point and new best-chain tip as required called for update_best_block
. Thanks
lightning/src/ln/channelmanager.rs
Outdated
|
||
/// Updates channel state with the current best blockchain tip. You should attempt to call this | ||
/// quickly after a new block becomes available, however it does not need to be called for each | ||
/// new block. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"It does not need to be called for each new block" What about check_get_funding_locked()
to account for confirmations ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really sure what you're asking? check_get_funding_locked
handles skipped blocks fine, or, it should?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better now. I think you can add a small comment on check_get_funding_locked
"Confirmations are accounted with an absolute height and not incrementally. This method might be only be called when new chain tip reach, after multiple block connections".
Fixing tests over here: https://github.com/valentinewallace/rust-lightning/tree/make-tests-compile (will update this comment as I go)
|
} else { | ||
self.monitor_pending_funding_locked = true; | ||
return Ok((None, timed_out_htlcs)); | ||
for inp in tx.input.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code block looks like it might be convenient to isolate in a utility method somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends on the if let Some(funding_txo)
, though, and its also nice to do it in the same transaction walk loop to avoid looping twice per channel.
lightning/src/ln/channel.rs
Outdated
|
||
self.update_time_counter = cmp::max(self.update_time_counter, highest_header_time); | ||
|
||
if self.funding_tx_confirmation_height > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps too short a repeated code fragment to extract, but maybe worth considering? Something like update_confirmation_height
or similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can move it around a bit to clean it up, actually, relying on the fact that check_get_funding_locked
will never return a funding_locked if we also want to fail the channel due to the < minimum_depth / 2
check.
f4bd6cc
to
bb99ef5
Compare
Thanks for the work on this last week @valentinewallace. This is now rebased on #846 and should be passing all the tests. I'll add a few tests for things tomorrow and then it should be good to go. |
c406072
to
6abdd28
Compare
Codecov Report
@@ Coverage Diff @@
## main #838 +/- ##
==========================================
+ Coverage 90.59% 90.63% +0.04%
==========================================
Files 51 51
Lines 27109 27204 +95
==========================================
+ Hits 24560 24657 +97
+ Misses 2549 2547 -2
Continue to review full report at Codecov.
|
4940ffa
to
3a55b08
Compare
3a55b08
to
9a1e392
Compare
Still needs more tests, but now has no PR dependencies and I think is code/doc-complete (though I'd very much welcome suggestions on making the docs more clear). |
879a162
to
4dadc9d
Compare
Added tests which I'm somewhat happy with. I think there may end up being a followup to tweak the API further, but I'd prefer to land this as-is first. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went through commit-by-commit, so please disregard anything that changed in a later commit.
lightning/src/ln/channel.rs
Outdated
if self.funding_tx_confirmations > 0 { | ||
if self.funding_tx_confirmations == self.minimum_depth as u64 { | ||
if self.funding_tx_confirmation_height > 0 { | ||
let funding_tx_confirmations = height as i64 - self.funding_tx_confirmation_height as i64 + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is i64
needed in case of a reorg?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if you call with a lower height it could underflow and go negative.
lightning/src/ln/channel.rs
Outdated
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS); | ||
if (non_shutdown_state >= ChannelState::ChannelFunded as u32 || | ||
(non_shutdown_state & ChannelState::OurFundingLocked as u32) == ChannelState::OurFundingLocked as u32) && | ||
funding_tx_confirmations < self.minimum_depth as i64 / 2 { | ||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A one-line comment explaining this would be useful or the reader.
lightning/src/ln/channelmanager.rs
Outdated
@@ -3400,7 +3400,7 @@ 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 pending_msg_events = &mut channel_state.pending_msg_events; | |||
channel_state.by_id.retain(|_, v| { | |||
if v.block_disconnected(header) { | |||
if v.block_disconnected(header, new_height) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess my confusion here is because in ChainMonitor
and ChannelMonitor
, the height is that of the disconnected header, which is inconsistent with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly minor points. Test changes sounds good to me, will look twice.
lightning/src/ln/channel.rs
Outdated
true | ||
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) { | ||
// We got a reorg but not enough to trigger a force close, just update | ||
// funding_tx_confirmed_in and return. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this PR, funding_tx_confirmed_in
is directly set in transactions_confirmed
so I don't think it makes sense to mention it here ?
I even think you can cut this branch if you initialize need_commitment_update
to false ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, its an exception to the next (channel_state < ChannelFunded) panic. Updated comments.
lightning/src/ln/channel.rs
Outdated
false | ||
}; | ||
|
||
//TODO: Note that this must be a duplicate of the previous commitment point they sent us, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this comment mentions the commitment point they send us when in fact it's us sending our commitment point to be used in next holder commitment transaction ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its completely stale nonsense based on my misunderstanding the spec in 2017, and it hasn't been touched since. I've removed it.
} else { | ||
if self.is_outbound() { | ||
for input in tx.input.iter() { | ||
if input.witness.is_empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we hit this branch, it does mean the confirmed transaction matches our expectation (tx.txid() = funding_txo.index
) so we might be okay there, even if we're exposed to malleation during tx-relay.
That said our expected funding_txo
might belong to a malleable transaction given as such by get_outbound_funding_created
and in fact this method should recall that funding_txo
MUST NOT belong to a malleable transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, technically by then we're ok, but its also a critical bug in the implementation of the wallet calling LDK, so we should do something. Honestly, I think we should probably replace the whole FundingTransactionBroadcastable path to make the user provide us the transaction, but that's a separate PR.
@@ -3537,112 +3647,32 @@ impl<Signer: Sign> Channel<Signer> { | |||
} | |||
}); | |||
|
|||
if self.funding_tx_confirmations > 0 { | |||
self.funding_tx_confirmations += 1; | |||
self.update_time_counter = cmp::max(self.update_time_counter, highest_header_time); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we have a risk of breaking bolt 7 requirement by setting update_time_counter
to highest header time ? "MUST set timestamp to greater than 0, AND to greater than any previously-sent channel_update for this short_channel_id."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its a cmp::max
so it should never go down? But we definitely need to do this because many clients filter updates based on the timestamp, so we need the time to be at least as of very recently (without having a "real" time source).
return Ok((None, timed_out_htlcs)); | ||
} | ||
} | ||
if funding_tx_confirmations < self.minimum_depth as i64 / 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you document the divide by 2 usage ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, its arbitrary. I think we should drop it entirely and replace with "funding tx conf is now 0", but there's enough changes in this PR already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly some confusion on my part it seems. :P
self.manager.block_connected(&header, &txdata, self.height as u32); | ||
self.manager.transactions_confirmed(&header, self.height as u32, &txdata); | ||
self.manager.update_best_block(&header, self.height as u32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I missed that this wasn't using the Listen
version of block_connected
. Nevermind.
node.node.block_connected(&block.header, &txdata, height); | ||
node.node.block_connected(&block, height); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that I confused block_connected
with update_best_block
when I wrote that comment. I understand the change now.
lightning/src/ln/channel.rs
Outdated
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() { | ||
let funding_txo = self.get_funding_txo().unwrap(); | ||
if tx.txid() == funding_txo.txid { | ||
let txo_idx = funding_txo.index as usize; | ||
if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() || | ||
tx.output[txo_idx].value != self.channel_value_satoshis { | ||
if self.is_outbound() { | ||
// If we generated the funding transaction and it doesn't match what it | ||
// should, the client is really broken and we should just panic and | ||
// tell them off. That said, because hash collisions happen with high | ||
// probability in fuzztarget mode, if we're fuzzing we just close the | ||
// channel and move on. | ||
#[cfg(not(feature = "fuzztarget"))] | ||
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); | ||
for &(index_in_block, tx) in txdata.iter() { | ||
if let Some(funding_txo) = self.get_funding_txo() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May have misread this. I think I was referring to:
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
and
if let Some(funding_txo) = self.get_funding_txo() {
but did't catch the move inside the for-loop.
6ea63e2
to
22f280c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me, just have to squash ?
panic!("Client called ChannelManager::funding_transaction_generated with bogus transaction!"); | ||
} | ||
self.channel_state = ChannelState::ShutdownComplete as u32; | ||
self.update_time_counter += 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we going to send any channel gossip if we fail here before ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably not - we can't have announced the channel yet. I'm gonna leave this unless you feel strongly - its generally "correct" to increment the counter before failure, even if we don't need it here.
/// | ||
/// 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> { | ||
pub fn update_best_block(&mut self, height: u32, highest_header_time: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's highest_header_time
there ? Block timestamp or MTP or local client reception of Electrum header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case its just the header.time
, which is max current time + 2 hours. We just use it to ensure our gossip messages aren't too far in the past.
// the funding transaction's confirmation count has dipped below minimum_depth / 2, | ||
// close the channel and hope we can get the latest state on chain (because presumably | ||
// the funding transaction is at least still in the mempool of most nodes). | ||
if funding_tx_confirmations < self.minimum_depth as i64 / 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For low-conf chans (e.g 1 or 2 confs) eventually we could attach a CPFP and rebroadcast to avoid canceling payments already sold-out. If bumping feerate is lower than the ongoing-to-be-lost HTLCs received as holder balance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this only triggers on a disconnect, ie if the transaction was confirmed, but is now less-confirmed. Honestly I think we should drop this entirely, its kinda dumb, but that shouldn't be in this PR.
// the funding transaction's confirmation count has dipped below minimum_depth / 2, | ||
// close the channel and hope we can get the latest state on chain (because presumably | ||
// the funding transaction is at least still in the mempool of most nodes). | ||
if funding_tx_confirmations < self.minimum_depth as i64 / 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this expected to break test coverage ?
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index dd026398..48602544 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -3664,7 +3664,7 @@ impl<Signer: Sign> Channel<Signer> {
// the funding transaction's confirmation count has dipped below minimum_depth / 2,
// close the channel and hope we can get the latest state on chain (because presumably
// the funding transaction is at least still in the mempool of most nodes).
- if funding_tx_confirmations < self.minimum_depth as i64 / 2 {
+ if funding_tx_confirmations < self.minimum_depth as i64 / 4 {
return Err(msgs::ErrorMessage {
channel_id: self.channel_id(),
data: format!("Funding transaction was un-confirmed. Locked at {} confs, now have {} confs.", self.minimum_depth, funding_tx_confirmations),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, likely not, I'm not sure how much coverage we have for the "confs went down, close channel" stuff, and we should drop it anyway.
Previously, we expected every block to be connected in-order, allowing us to track confirmations by simply incrementing a counter for each new block connected. In anticipation of moving to a update-height model in the next commit, this moves to tracking confirmations by simply storing the height at which the funding transaction was confirmed. This commit also corrects our "funding was reorganized out of the best chain" heuristic, instead of a flat 6 blocks, it uses half the confirmation count required as the point at which we force-close. Even still, for low confirmation counts (eg 1 block), an ill-timed reorg may still cause spurious force-closes, though that behavior is not new in this commit.
Electrum clients primarily operate in a world where they query (and subscribe to notifications for) transactions by script_pubkeys. They may never learn very much about the actual blockchain and orient their events around individual transactions, not the blockchain. This makes our ChannelManager interface somewhat more amenable to such a client by splitting `block_connected` into `transactions_confirmed` and `update_best_block`. The first handles checking the funding transaction and storing its height/confirmation block, whereas the second handles funding_locked and reorg logic. Sadly, this interface is somewhat easy to misuse - notifying the channel of the funding transaction being reorganized out of the chain is complicated when the only notification received is that a new block is connected at a given height. This will be addressed in a future commit.
22f280c
to
945f213
Compare
Squashed fixup commits with only one wording diff:
|
When we force-close a channel, for whatever reason, it is nice to send an error message to our peer. This allows them to closes the channel on their end instead of trying to send through it and failing. Further, it may induce them to broadcast their commitment transaction, possibly getting that confirmed and saving us on fees. This commit adds a few more cases where we should have been sending error messages but weren't. It also includes an almost-global replace in tests of the second argument in `check_closed_broadcast!()` from false to true (indicating an error message is expected). There are only a few exceptions, notably those where the closure is the result of our counterparty having sent *us* an error message.
This also moves the scanning of the block for commitment transactions into channel, unifying the error path.
945f213
to
7f2f046
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 7f2f046
No other concerns after my last review.
Code Review ACK 7f2f046 Okay to revise later the closing-channel-on-reorg feature. |
See the similar commit that operates on `Channel`'s internal API for more details on the reasoning.
It is now entirely redundant with ChannelManager::update_best_block and is still accessible via `Listen::block_disconnected`.
See comment in the diff for more details
7f2f046
to
47ad3d6
Compare
Ugh, noticed CI was broken due to bad doc links. The fix diff is pure doc and trivial, so I'm going to merge this after CI passes:
|
This is very much a WIP, but we're gonna YOLO this one into the Java bindings to see if the API works. It breaks a ton of tests which rely on bogus blockchain structure, but we need to fix those either way. At least some tests pass, right?