Have MTP in checkpoint data and report missing blocks#2186
Have MTP in checkpoint data and report missing blocks#2186evanlinjin wants to merge 2 commits intobitcoindevkit:masterfrom
Conversation
Introduce `WithMtp<D>` so that `CheckPoint<WithMtp<D>>` carries a compile-time guarantee that the median-time-past (BIP-0113) is available at every checkpoint, without walking 11 ancestor blocks per lookup. `CheckPoint::mtp()` returns the stored value. Rename `median_time_past` to `compute_mtp` to make the chain-walking cost explicit at the call site and to contrast it with the cheap `mtp()` accessor on `CheckPoint<WithMtp<D>>`.
Change `CheckPoint::compute_mtp` to return `Result<u32, MissingBlocks>` instead of `Option<u32>`. On failure, `MissingBlocks` lists every height in the MTP window (`h-10..=h`) that the chain is missing, enabling callers to drive a fetch-retry loop against their chain source. This is motivated by light-client chain sources such as Electrum, which do not expose MTP values directly. Callers need to know precisely which block headers to fetch; a bare `None` forces either eager full-chain prefetching or blind re-walking.
|
I'm wondering whether we should get rid of the The other approach is to go the other way and introduce a |
notmandatory
left a comment
There was a problem hiding this comment.
This generally looks like a reasonable performance optimization. Would blockchain clients be responsible for recomputing the recent mpc values in the case of a reorg?
| /// Returns the precomputed median-time-past (MTP) stored on this checkpoint. | ||
| /// | ||
| /// Unlike [`CheckPoint::compute_mtp`], this does not walk the chain — the MTP was computed | ||
| /// when the checkpoint was constructed and is guaranteed to be present by the type system. |
There was a problem hiding this comment.
Is it worth mentioning here that the MTP value returned here would be in accurate in the case of a reorg that happens after the MTP was calculated?
Wouldn't any custom |
|
@notmandatory Thanks for the review!
The main intention behind the PR is not about performance (the previous PR description was misleading and I've updated it!). The idea is to enforce MTP value per checkpoint at compile time - if you use So the chain source must return the MTP value per block in order to be compatible with
So currently, yes if they want the |
Description
Context: #2076 (comment)
Carries median-time-past (MTP) on each checkpoint at the type level, and reworks
compute_mtpso callers can drive fetch-retry loops when ancestor blocks are missing.WithMtp<D>wrapper:CheckPoint<WithMtp<D>>is a compile-time guarantee that MTP is present on every checkpoint in the chain. Code that needs MTP can takeCheckPoint<WithMtp<D>>and read it viaCheckPoint::mtp()without ever having to handle a "MTP couldn't be computed" case — the type system rules that out. Compare to the alternative of computing MTP on demand, which forces every consumer to deal with the failure path even when the chain source already has the data.compute_mtpreturnsResult<u32, MissingBlocks>instead ofOption<u32>.MissingBlockslists every height in the MTP window (h-10..=h) that the chain is missing, so callers — especially light-client chain sources like Electrum that don't expose MTP directly — can batch-fetch exactly the headers they need and retry.median_time_past→compute_mtpto distinguish the chain-walking constructor from themtp()accessor onCheckPoint<WithMtp<D>>.Notes to the reviewers
Breaking change, marked
feat(core)!. Two API breaks:median_time_past→compute_mtpcompute_mtpreturnsResult<u32, MissingBlocks>(wasOption<u32>)Changelog notice
Checklists
All Submissions:
New Features: