Fix locktime calculations and improve API#36
Fix locktime calculations and improve API#36ValuedMammal merged 2 commits intobitcoindevkit:masterfrom
Conversation
a10729c to
9f83bf8
Compare
174c73f to
bdc7fcf
Compare
aagbotemi
left a comment
There was a problem hiding this comment.
Thank you for working on this PR @evanlinjin. I left some review
src/input.rs
Outdated
| if let (Some(relative::LockTime::Blocks(lt_height)), Some(conf_status)) = | ||
| (self.plan.relative_timelock(), self.status) | ||
| { | ||
| let height_diff = spending_height.saturating_sub(conf_status.height.to_consensus_u32()); | ||
| return lt_height.to_consensus_u32() > height_diff; |
There was a problem hiding this comment.
When status is None (unconfirmed), this returns false, incorrectly marking the input as not timelocked. Should return true when status.is_none() && relative_lock.is_some().
src/input.rs
Outdated
| if let (Some(relative::LockTime::Time(lt_time)), Some(conf_status)) = | ||
| (self.plan.relative_timelock(), self.status) | ||
| { | ||
| let time_diff = tip_mtp | ||
| .to_consensus_u32() | ||
| .saturating_sub(conf_status.prev_mtp?.to_consensus_u32()); | ||
| return Some(lt_time.value() as u32 * 512 > time_diff); | ||
| } | ||
|
|
||
| Some(false) |
There was a problem hiding this comment.
When status is None (unconfirmed), this returns Some(false), incorrectly marking the input as not timelocked. Unconfirmed inputs with relative time locks should return Some(true).
bdc7fcf to
85b311f
Compare
Add comprehensive unit tests covering edge cases for is_block_timelocked, is_time_timelocked, and is_timelocked methods: - Unconfirmed inputs with relative timelocks (must be considered locked) - Missing prev_mtp for relative time locks (returns None) - No-lock and wrong-lock-type scenarios (return false/Some(false)) - Combined is_timelocked method with various lock combinations These tests cover the bug cases identified in PR bitcoindevkit#36 review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@ValuedMammal @aagbotemi Thank you for the reviews. Tests in #38 have also been updated to cover these edge cases. |
src/input.rs
Outdated
|
|
||
| /// Whether this is locked by any timelock constraint. | ||
| /// | ||
| /// Returns `None` if a time-based lock exists but `spending_mtp` is not provided or |
There was a problem hiding this comment.
📌 "spending_mtp" doesn't appear in the function.
src/input_candidates.rs
Outdated
| spend_height: absolute::Height, | ||
| spend_mtp: Option<absolute::Time>, |
There was a problem hiding this comment.
📌 Should it be spend_height or tip_height? Also consider rename to just filter_unspendable.
There was a problem hiding this comment.
Good point. Addressed both.
| /// Previous block's MTP (median time past) value as per BIP-0068, if available. | ||
| pub prev_mtp: Option<absolute::Time>, |
There was a problem hiding this comment.
nit: the docs for prev_mtp don't explain what happens when it's None
Correctly calculate spendability of coins that are timelocked by taking MTP into account. API changes are a result of the different requirements between relative and absolute locktimes.
85b311f to
302faff
Compare
|
ACK a35ecbf |
Description
Previously, time-based locktimes are based on header timestamps, but they should be based on MTP.
Changes
TxStatustoConfirmationStatus.is_timelockedmethod into two methods as time-based and block-based timelocks have different required metadata.Testing
Testing is done in #38 as they require some unreleased changes in upstream crates.