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
improve relative locktime API #2549
improve relative locktime API #2549
Conversation
Pull Request Test Coverage Report for Build 8382382642Details
💛 - Coveralls |
CI failing because my doccomment links are broken. I should learn to check that locally.. |
f7717c8
to
cbf749c
Compare
Ready for review. |
@@ -40,6 +40,46 @@ pub enum LockTime { | |||
} |
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, there was From<u16>
, well, I don't really like 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.
Given that this type is basically only used within the LockTime::Height
enum variant, where it is very clear what a bare number is supposed to mean, I think it's fine. Same with Time
, though the interpretation of the number as "512-second intervals" is maybe surprising.
But sure, I can drop the From
impls in a new commit if they bother you. They are not very discoverable and gain little ergonomics over just using LockTime::from_height
/from_time
.
|
||
/// Constructs a `LockTime` from `n`, expecting `n` to be a 16-bit count of blocks. | ||
#[inline] | ||
pub fn from_height(n: u16) -> Self { LockTime::Blocks(Height(n)) } |
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.
Could be const
.
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.
Done.
/// This function is a little awkward to use, and users may wish to instead use | ||
/// [`Self::from_seconds_floor`] or [`Self::from_seconds_ceil`]. | ||
#[inline] | ||
pub fn from_512_second_intervals(intervals: u16) -> Self { LockTime::Time(Time(intervals)) } |
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.
const
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.
Done.
/// Will return an error if the input cannot be encoded in 16 bits. | ||
#[inline] | ||
pub fn from_seconds_floor(seconds: u32) -> Result<Self, Error> { | ||
Time::from_seconds_floor(seconds).map(LockTime::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.
Can be const
with more complicated code. I'm not sure if worth it.
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.
Done in new commit. Wasn't too bad, I think it was worth it.
/// Will return an error if the input cannot be encoded in 16 bits. | ||
#[inline] | ||
pub fn from_seconds_ceil(seconds: u32) -> Result<Self, Error> { | ||
Time::from_seconds_ceil(seconds).map(LockTime::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.
Complicated const
again.
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.
Done in new commit. Wasn't too bad, I think it was worth it.
Ok(Time::from_512_second_intervals(interval)) | ||
} else { | ||
Err(Error::IntegerOverflow(seconds)) | ||
} |
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.
Could be const
too with a bit uglier code.
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.
Done in new commit. Wasn't too bad, I think it was worth it.
@@ -222,6 +262,10 @@ impl Height { | |||
/// The maximum relative block height. | |||
pub const MAX: Self = Height(u16::max_value()); | |||
|
|||
/// Create a [`Height`] using a count of blocks. | |||
#[inline] | |||
pub fn from_height(blocks: u16) -> Self { Height(blocks) } |
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.
Trivial const
.
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.
Done.
/// | ||
/// This method will **not** round-trip with [`Self::to_consensus_u32`], because relative | ||
/// locktimes only use some bits of the underlying `u32` value and discard the rest. If | ||
/// you want to preserve the full value, you should use the [`Sequence`] type instead. |
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, this looks like a foot gun. Is it really needed? Just decoding Sequence
and converting that is less error-prone and more explicit.
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.
Yeah, I considered this. I could go either way on it. I'm not sure that making users go through Sequence
makes this flow any less footgunny.
But I can remove this if you feel strongly about it.
I'd maybe like to add a method to script to encode a Sequence
number directly into script, if there isn't one, so that users would never need a u32
.
match *self { | ||
LockTime::Blocks(_) => true, | ||
LockTime::Time(_) => 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.
Could just use matches!
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.
Done.
cbf749c
to
8e43684
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 8e43684
In one of the resolved conversations it was noted that this doesn't implement |
Needs rebase mate. |
8e43684
to
b72cc8c
Compare
Wow, super bad process by me. I previously ack'ed this PR and now I've given a 9-comment review. Therefore, every comment is a can-do-in-followup-PR |
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 b72cc8c
b72cc8c
to
2f1bd57
Compare
Addressed all comments except the one about the ZERO constant. |
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 b72cc8c
Thanks man! |
Needs rebase again bro |
2f1bd57
to
d3fe9ac
Compare
Done. |
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.
Error getter can be done later, and the failure to add it is a review fail by me for not noticing earlier. I"m planning on going over all the errors ... again ... next release.
In commit 2799ecdf relative locktime: add "obvious" constructors
the last line of the commit log is stale, from_consensus
change is in a later PR.
ACK d3fe9ac
/// Error returned when a sequence number is parsed as a lock time, but its | ||
/// "disable" flag is set. | ||
#[derive(Debug, Clone, Eq, PartialEq)] | ||
pub struct DisabledLockTimeError(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.
This is a leaf error type so we should probably provide a getter if I remembered correctly and that is the policy we settled upon.
Adds constructors to allow directly creating locktimes from time or block counts; adds a flooring constructor to Time to match the ceiling one; adds an explicit constructor to Height since the From<u16> was not very discoverable.
…imes and Sequence
This gives a way to determine whether a CSV will pass, given a sequence number, in a type-safe way where you can't get the two things backward.
Copy these from absolute::LockTime. While we are at it, make the functions in absolute::LockTime const.
d3fe9ac
to
04715e3
Compare
Rebased on master, added an accessor to the error type, and fixed the commit message. |
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 04715e3
@sanket1729 have you got time to review this guy please? I'd love to have a play with the |
@tcharding I don't think we can get rid of So really all this PR will do for us is simplify the implementation of |
The Oooh, I see
|
Sorry for the noise @sanket1729 |
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 04715e3
Oh that's right! I knew there was something dumb in Miniscript that necessitated these types.. |
Well, rust-miniscript does have a few APIs (satisfaction/PSBT) that interact with the "real" types that come with rust-bitcoin. These are currently a bit awkward and weird and will definitely be improved by this PR. |
While implementing rust-bitcoin/rust-miniscript#654 I ran into a number of limitations of the
relative::LockTime
API. This fixes these byabsolute::LockTime
torelative::LockTime
, adjusting comments and functionality accordingly.Sequence
numbers, as well as a method to check whether a locktime is satisfied by a given sequence number.Fixes #2547
Fixes #2545
Fixes #2540