Merge bitcoindevkit/bdk#2037: Add median-time-past (MTP) calculation to CheckPoint
b6235360e7232ad8bba2b12049eacdd2a6f9b3ca feat(core): add median-time-past calculation to CheckPoint (志宇)
Pull request description:
## Description
This PR adds the ability to calculate median-time-past (MTP) for `CheckPoint` structures, implementing the functionality described in #2036.
## Notes to the reviewers
`CheckPoint::median_time_past` calculates the MTP value by looking at the previous 11 blocks (including the current block).
### Why `ToBlockTime` is a separate trait from `ToBlockHash`
`ToBlockTime` is intentionally kept as a separate trait with a non-optional return type (`fn to_blocktime(&self) -> u32`).
For operations like MTP calculation, block times are either fully available or the calculation is meaningless — there's no useful "partial" or "best-effort" result. By using a separate trait, we get compile-time guarantees: methods like `median_time_past()` use `where D: ToBlockTime` bounds, making it explicit which checkpoint data types support time-based operations. Types without block time data (e.g., `BlockHash`, `BlockId`) simply don't implement the trait.
#### How this differs from `prev_blockhash`
In contrast, `prev_blockhash() -> Option<BlockHash>` is a method on `ToBlockHash` rather than a separate trait. The `Option` return serves a different purpose — it allows graceful degradation. A `CheckPoint<BlockId>` chain is still useful even without hash linkage validation; callers can simply skip verification when `None` is returned. Additionally, `None` at genesis is semantically meaningful (it marks the chain root), not an error condition.
For MTP, there's no equivalent "skip if unavailable" — you either have all 11 timestamps or the calculation fails. This binary requirement is better expressed as a trait bound than runtime `Option` handling.
## Changelog notice
### Added
- Introduced `ToBlockTime` trait for types that can return a block time.
- Added `median_time_past()` method to `CheckPoint` for calculating MTP according to BIP113
## Checklists
### All Submissions:
* [x] I've signed all my commits
* [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
* [x] I ran `cargo fmt` and `cargo clippy` before committing
### New Features:
* [x] I've added tests for the new feature
* [x] I've added docs for the new feature
Fixes #2036
ACKs for top commit:
ValuedMammal:
ACK
b6235360e7232ad8bba2b12049eacdd2a6f9b3ca
Tree-SHA512: fac1c06d27d44a4e419ca53bca3a7d38efe7f7a73fbf60508013a2a4b46c5081d47e02f1d1df5250315203770326db90c436c852c693215c493daa036e6cab9d