-
Notifications
You must be signed in to change notification settings - Fork 415
Drop the need for fork headers when calling Listen's disconnect #3876
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
base: main
Are you sure you want to change the base?
Changes from all commits
7ae4f68
3b99b55
7ff5313
9fc599f
9385161
4ae8fcc
a6985eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,7 @@ use bitcoin::hash_types::BlockHash; | |
use bitcoin::pow::Work; | ||
|
||
use lightning::chain; | ||
use lightning::chain::Listen; | ||
use lightning::chain::{BestBlock, Listen}; | ||
|
||
use std::future::Future; | ||
use std::ops::Deref; | ||
|
@@ -398,12 +398,15 @@ where | |
} | ||
|
||
/// Notifies the chain listeners of disconnected blocks. | ||
fn disconnect_blocks(&mut self, mut disconnected_blocks: Vec<ValidatedBlockHeader>) { | ||
for header in disconnected_blocks.drain(..) { | ||
fn disconnect_blocks(&mut self, disconnected_blocks: Vec<ValidatedBlockHeader>) { | ||
for header in disconnected_blocks.iter() { | ||
if let Some(cached_header) = self.header_cache.block_disconnected(&header.block_hash) { | ||
assert_eq!(cached_header, header); | ||
assert_eq!(cached_header, *header); | ||
} | ||
self.chain_listener.block_disconnected(&header.header, header.height); | ||
} | ||
if let Some(block) = disconnected_blocks.last() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're now happy to use the fork point, why are we keeping a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its needed by the cache, which I didn't want to change in this PR - #3876 (comment) |
||
let best_block = BestBlock::new(block.header.prev_blockhash, block.height - 1); | ||
self.chain_listener.blocks_disconnected(best_block); | ||
} | ||
} | ||
|
||
|
@@ -615,7 +618,7 @@ mod chain_notifier_tests { | |
let new_tip = fork_chain.tip(); | ||
let old_tip = main_chain.tip(); | ||
let chain_listener = &MockChainListener::new() | ||
.expect_block_disconnected(*old_tip) | ||
.expect_blocks_disconnected(*old_tip) | ||
.expect_block_connected(*new_tip); | ||
let mut notifier = | ||
ChainNotifier { header_cache: &mut main_chain.header_cache(0..=2), chain_listener }; | ||
|
@@ -635,8 +638,7 @@ mod chain_notifier_tests { | |
let new_tip = fork_chain.tip(); | ||
let old_tip = main_chain.tip(); | ||
let chain_listener = &MockChainListener::new() | ||
.expect_block_disconnected(*old_tip) | ||
.expect_block_disconnected(*main_chain.at_height(2)) | ||
.expect_blocks_disconnected(*main_chain.at_height(2)) | ||
.expect_block_connected(*new_tip); | ||
let mut notifier = | ||
ChainNotifier { header_cache: &mut main_chain.header_cache(0..=3), chain_listener }; | ||
|
@@ -656,7 +658,7 @@ mod chain_notifier_tests { | |
let new_tip = fork_chain.tip(); | ||
let old_tip = main_chain.tip(); | ||
let chain_listener = &MockChainListener::new() | ||
.expect_block_disconnected(*old_tip) | ||
.expect_blocks_disconnected(*old_tip) | ||
.expect_block_connected(*fork_chain.at_height(2)) | ||
.expect_block_connected(*new_tip); | ||
let mut notifier = | ||
|
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.
Should we change the
Cache
API accordingly?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 it seems somewhat disjoint from this PR, given there's further work to do in
lightning-block-sync
anyway, so I kinda wanted to keep it as small as can be.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.
Mhh, might be good to document somewhere what steps you deem left before you'd consider the transition to this new approach complete. I guess all of them should land before the next release then, to not end up with a half-migrated codebase in the release?
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 mean the API/stuff in
lightning
in in a perfectly fine state after this PR, andlightning-block-sync
just deserves a bit of efficiency in dropping a vec and improving the cache afterwards. This PR obviously doesn't accomplish the goals that #3600 set out to, but is just a step towards it (the "complicated" step that requires making sure all thelightning
-internal stuff isn't broken by changing the API).AFAIU, to get to the point that bitcoind (and all) syncs support swapping to a new chain during a reorg and don't fetch a pile of redundant blocks we need to:
BestBlock
contain a list of 6(ish?) block hashes, not onelightning-block-sync
(and eventuallylightning-transaction-sync
) to do the sync without leaning on the cachelightning-block-sync
doesn't have any spare vecs or whatever lying around.Uh oh!
There was an error while loading. Please reload this page.
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 still think it would make sense to open an issue for this larger refactoring you're planning, as there are connected aspects to discuss that don't really belong in this PR.
For example, how do we imagine this to work exactly, especially for the
Confirm
/lightning-transaction-sync
case?For Esplora, we currently retrieve the tip hash, retrieve the header and the block status (including the hight), before we call
best_block_updated
, which is already 3 costly RTTs. If we now would require to track the 6 most-recent hashes, we'd need to make at least 5 more subsequent calls (bringing this it at least 8 RTTs per sync round) to retrieve the hashes at[(height-5)..(height-1)]
. But, given that these are individual calls, there is no way to tell if any reorg happened during some of these calls, so they are inherently race-y.For Electrum, the results would be very similar for the polling client in its current form. Note we eventually want to switch the client to a streaming version making use of Electum's subscription model though, and requiring 'last 6 blocks' would probably require us to resort to costly polling again.
If we'd otherwise extend the client to start tracking more of the chain state (i.e., actually tracking a local chain 6-suffix) across rounds this would complicate the client logic quite a bit and make it even more susceptible to race conditions.
TLDR: I still maintain all of this would be/is resulting in a major refactor across our chain syncing crates and logic, and it would be great to discuss what we imagine to be involved and the corresponding trade-offs before we just jump into it heads first.