Commit Graph

64 Commits

Author SHA1 Message Date
Tobin C. Harding dca4266205
units: Fix rustdoc column width
We've done a bit of renaming which has adversely effected rustdoc column
width, fix it up.
2025-05-08 10:16:57 +10:00
Tobin C. Harding d557caf552
Run the formatter 2025-05-08 10:16:56 +10:00
Tobin C. Harding 7c2115b68f
Rename MtpInterval to NumberOf512Seconds
Name the type exactly what it is. This used to be `Time`, then we tried
`MtpInterval`.

Note that this makes some of the original function names overly verbose
e.g., `NumberOf512seconds::from_512_second_intervals()` but given the
curlyness of locktimes too verbose is better than too terse. Also this
type, along with `NumberOfBlocks` is not going to be in very wide use so
the ergonomic hit is worth the additional clarity.
2025-05-08 10:12:23 +10:00
Tobin C. Harding 3a97ea2259
Rename HeightInterval to NumberOfBlocks
Name this type exactly what it is. Note for the error we just use
'height' even though this is a bit stale but the general concept is ok
in the error type because the name is long already.
2025-05-08 10:12:22 +10:00
Tobin C. Harding c3b7457f6c
Rename Mtp to MedianTimePast
Favour expressiveness over terseness for
`units::locktime::absolute::Mtp` (formerly `Time`) because in general
locktimes are curly AF.
2025-05-08 10:09:09 +10:00
Andrew Poelstra 72d5fbad73
units: stop using MtpAndHeight in locktime::relative is_satisfied_by methods
Keep using it in primitives; will remove it there in the next commit.
2025-05-06 18:51:03 +00:00
Andrew Poelstra 4300271f0c
units: add constructor for absolute::Mtp from timestamps
This is a convenience method to allow direct construction of
absolute::Mtp rather than going through units::BlockMtp.
2025-05-06 15:50:46 +00:00
Andrew Poelstra cb882c5ce1
units: add global `BlockMtpInterval` type
See the previous commit message for justification; for sensible
arithmetic on block timestamps we need the ability to do MTP
calculations on arbitrary MTPs and arbitrary intervals between them.
However, the absolute::Mtp and relative::MtpInterval types are severely
limited in both range and precision.

Also adds a bunch of arithmetic ops to match the existing ops for
BlockHeight and BlockInterval. These panic on overflow, just like the
underlying std arithmetic, which I think is reasonable behavior for
types which are documented as being thin wrappers around u32.

We may want to add checked_add, checked_sub and maybe checked_sum
methods, but that's out of scope for this PR.
2025-05-06 15:19:36 +00:00
Andrew Poelstra 826acb8273
units: rename relative::HeightInterval constructors
Rename `value` to `to_height` to be symmetric with `from_height`;
deprecate `to_consensus_u32` which had no symmetric `from_consensus_u32`
and was only used to implement the corresponding methods in primitives
and bitcoin.
2025-05-03 03:12:08 +00:00
Andrew Poelstra 39b4f7670d
units: rename relative::Height to HeightInterval
This is disruptive, but makes the type name consistent with
`MtpInterval` and also greatly improves clarity, helping to distinguish
between absolute and relative locktimes and reminding the author (and
reviewer) of locktime code that this needs to be a diff.
2025-05-03 03:12:08 +00:00
Andrew Poelstra d3619cc1bc
units: deprecate relative::MtpInterval::to_consensus_u32
This method is weird. It's basically just used internally to implement
the locktime methods in `primitives` and `bitcoin`. It has no symmetric
from_consensus_u32.

Conversely the constructors from 512-second intervals have no symmetric
to_* method -- the inverse of these functions is called `value`, which
is a meaningless and undiscoverable name.
2025-05-03 03:12:07 +00:00
Andrew Poelstra 1a6b8b4c7a
units: rename relative::Time to MtpInterval
The name `Time` is misleading. In fact this represents an interval
between MTPs.
2025-05-03 03:12:07 +00:00
Andrew Poelstra 39b057fade
units: rename absolute::Height consensus functions
As with absolute::Mtp, there is no "consensus encoding" of a block
height, except that obtained by converting it to a locktime. For
symmetry with `Mtp`, rename the methods.
2025-05-03 03:12:05 +00:00
Andrew Poelstra 5a8f33f380
units: rename absolute::Mtp consensus functions
There is no "consensus encoding" for a MTP. The intention for these
methods was that a user could interpret the MTP as a locktime and then
consensus-encode that locktime. However, it was instead interpreted as
the MTP representing a *blocktime* as it is consensus-encoded in a block
header.

Evidence of this misinterpretation is in several doccomments, which
casually refer to the Mtp (which used to be just called Time) as a
"block time", which is simply incorrect.
2025-05-02 17:44:58 +00:00
Andrew Poelstra 8ffcd2cf30
units: rename absolute::Time to absolute::Mtp
This is not a generic UNIX timestamp, but rather a MTP restricted to
have values between 500 million and u32::MAX. Most importantly, it is
*not* a blocktime, which is what is implied by its name and
constructors.
2025-05-02 17:44:58 +00:00
Jamil Lambert, PhD 7bcdd5ff66
Add regression tests for Display impl
The output of `Display` should not change in stable crates for types
that have well defined formatting and ones that implement `FromStr`.
Error types do not need to be tested.

Add missing tests for all implementations in `units`.
2025-04-30 18:21:09 +01:00
merge-script f9bc0f517d
Merge rust-bitcoin/rust-bitcoin#4344: Locktime MtpAndHeight
8b47068a2e feat(locktime): implement MtpAndHeight structure and validation logic (aagbotemi)

Pull request description:

  This PR fixes #4299

  - Computed MtpAndHeight structure
  - Checked if relative time and height is satisfied by MtpAndHeight
  - Compared the Ordering of MtpAndHeight with time and height
  - Checked MtpAndHeight satisfaction and comparison in Locktime
  - Added unit tests for all the implementation

  I've reviewed and adhered to the contribution guidelines

ACKs for top commit:
  apoelstra:
    ACK 8b47068a2efada30aec21c61ae4be0da4d8e8fc8; successfully ran local tests
  Kixunil:
    ACK 8b47068a2e
  tcharding:
    ACK 8b47068a2e

Tree-SHA512: b00d1384d5deaa038b486ca9d77ad33cfa6cd8c987e08407863f2be8d540014bdcc971cd9d46acb51a2d105341accc04ba151e5cccb276e8352a5d45b33097eb
2025-04-28 13:49:12 +00:00
aagbotemi 8b47068a2e
feat(locktime): implement MtpAndHeight structure and validation logic
- Add MtpAndHeight for relative locktime checks
- Include unit tests for time/height comparisons
- Fix API design for mtp_as_time() error handling
- Update documentation and dependencies
- Fix BlockTime, CI, remove Ordering, and PR discussion fixed
- Fix UTXO height and timestamps
- Fix: chain_state and utxo_state handled seperately for is_satisfied_by
- Fix: panic on overflow fixed with check_add
- Fix: documentation updated and trailing whitespaces removed
- docs(mtpheight): documentation updated
- used accessors to_height and to_mtp over From impl
2025-04-25 12:24:23 +01:00
Jamil Lambert, PhD 913360b112
Make struct titles consistent
Structs had various phrasings of titles.

Make the wording consistent by concisely stating what it is, instead of
what it does.

Make the wording of all error structs consistent.
2025-04-15 21:23:31 +01:00
lfgtwo 89d61304af chore: remove needless question mark 2025-03-29 01:00:06 +08:00
Shing Him Ng bfba2a85dd Kill remaining mutants 2025-01-21 17:01:36 -06:00
Jamil Lambert, PhD f9be30ddbe
units: Fix `missing_errors_doc` clippy lint
Change the lint to `warn` in `units/Cargo.toml`.
Allow `missing_errors_doc` in `amount/serde.rs` and `fee_rate/serde.rs`.
Add missing `# Errors` sections to rustdocs where the lint gives a
warning.
2025-01-15 20:44:19 +00:00
Tobin C. Harding 55a999e0b5
Add serde roundtrip tests to relative locktime types
As we do for absolute locktime types add a couple of `serde` roundtrip
tests to the relative locktime types.
2025-01-06 17:56:15 +11:00
Shing Him Ng 286bf900b1 Address mutants in units
Preemptively addressing these mutants before introducing the
cargo-mutants workflow

There are several types of changes:
- Changes that address mutants that were actually missing
- Changes that address test values that cause `cargo-mutants` to think
  mutants were missed. For example, `cargo-mutants` will replace the
return values for unsigned integer types with 0 and 1. While a function
might be tested, the test might be testing the function with a call that
results in 0 or 1. When `cargo-mutants` substitutes the function call
with `Ok(1)`, the test will still pass, and it will consider this a
mutant.  `cargo-mutants` also replaces operations (+, -, /, %), bitwise
operations (&, |, ^, etc), so an operation such as `3 - 2` results in a
mutant because changing it to `3 / 2` yields the same result
- TODOs to ignore functions/impls in the future
2025-01-03 21:17:20 -06:00
Tobin C. Harding 0d8e9ef096
Remove usage of impl_from_infallible in leaf crates
Rust macros, while at times useful, are a maintenance nightmare. And
we have been bitten by calling macros from other crates multiple times
in the past.

In a push to just use less macros remove the usage of the
`impl_from_infallible` macro in all the leaf crates and just write the
code.
2025-01-02 07:51:21 +11:00
merge-script 1c405524e8
Merge rust-bitcoin/rust-bitcoin#3777: Implement Arbitrary for units types
04dfe8dd45 Add api test to check Arbitrary impls (Shing Him Ng)
678fc71b88 Implement Arbitrary for units types (Shing Him Ng)

Pull request description:

  Implement Arbitrary for the rest of the types in `units`. Also moved the implementation in `FeeRate` right before the `tests` module

  Closes #3705

ACKs for top commit:
  apoelstra:
    ACK 04dfe8dd45fae9b55dacfe9eb0d73ea306db14ba; successfully ran local tests
  tcharding:
    ACK 04dfe8dd45

Tree-SHA512: 156bd26d4de85d484711d476df1d2758805387125209f0307aa786dd1585ff9953dbe41b0864b00ae101419176647e3bde7994ed9257c18307d161463b1c8d2e
2024-12-21 17:30:19 +00:00
Shing Him Ng 678fc71b88 Implement Arbitrary for units types 2024-12-19 17:00:35 -06:00
Tobin C. Harding 5290a93a38
units: Add all pedantic lints
Add all the pedantic lints to the repository by way of the repository
manifest. Then enable these lints in the `units` manifest.

Some things worth mentioning:

- Fix `needless_pass_by_value` by adding derives to `FormatOptions`.
- Fix lint `cast_lossless` using `cargo clippy --fix``
- While fixing `lint enum_glob_use` introduce a new style to the
codebase; import enums using a single character. Doing so prevents
namespace clashes, improves clarity, and maintains terseness.

Audit:

Use the following lints locally and audit all the warnings, they produce
many false positives so we can't enable them permentently.

- `cast_possible_truncation`
- `cast_possible_lint`
- `cast_sign_loss`
2024-12-18 08:25:12 +11:00
merge-script 8e52f758b5
Merge rust-bitcoin/rust-bitcoin#3715: units: Add `must_use`
2fd8614f5d units: Add additional must_use (Tobin C. Harding)
79a229b391 units: Add pedantic lint return_self_not_must_use (Tobin C. Harding)

Pull request description:

  Enable return_self_must_use and also run the linter locally with must_use_candidate.

  Add must_use attribute as required excluding obvious functions (conversion, getters, etc).

  Done as part of https://github.com/rust-bitcoin/rust-bitcoin/issues/3185

ACKs for top commit:
  apoelstra:
    ACK 2fd8614f5d091377f179440b04ec71f4853fd187; successfully ran local tests; nice! will one-ACK merge

Tree-SHA512: 90868846d6877830ca2b6931e8b94208434acc5a7b21808a32e2e1568c0ad33185644b931cae500e6619b8b4f19c39bce6922502d9233173722ef0e6455edba6
2024-12-11 18:22:02 +00:00
Tobin C. Harding adaf4ac086
Set avoid-breaking-exported-api to false
These lints are valuable, lets get at em.

Changes are API breaking but because the changes make functions consume
self for types that are `Copy` downstream should not notice the breaks.
2024-12-11 10:11:50 +11:00
Tobin C. Harding 2fd8614f5d
units: Add additional must_use
Use the `must_use_candidate` clippy lint to find all functions that are
candidates for having `must_use`.

Add `must_use` attribute but exclude obvious functions like `from_`,
`to_`, and `new`.

This patch is subjective.
2024-12-11 09:19:19 +11:00
Jamil Lambert, PhD 1649b68589
Standardize wording to `constructs a new`
There is a range of different wordings used in the docs of constructor
type functions.

Change all to start with `Constructs a new` or `Constructs an empty`.
2024-11-05 13:02:26 +00:00
Jamil Lambert, PhD 27f94d5540
Replace `creates` with `constructs`
In functions that act like constructors there is a mixture of the usage
of `creates` and `constructs`.

Replace all occurrences of `creates` with `constructs` in the first line
of docs of constructor like functions.
2024-11-05 12:47:28 +00:00
Fmt Bot 5ecf7f2d67 2024-11-03 automated rustfmt nightly 2024-11-03 01:21:14 +00:00
Tobin C. Harding ff20249bdc
Remove unneeded feature gate
We can use the `parse::hex_remove_optional_prefix` now without the
feature gate.
2024-11-02 07:42:57 +11:00
Tobin C. Harding 88f6621e30
Split parse macros
Done in preparation for enabling no-alloc builds.

Split the macro calls to handle `str` separately from `alloc` types.
2024-11-02 07:42:57 +11:00
Tobin C. Harding 3f2e760d1f
Replace String with InputString in ParseIntError
Currently the `ParseIntError` contains an owned copy of the input
string, this is causing us to have to use `alloc` everywhere.

We already have a alloc-friendly string replacement type, the
`InputString` - use it.
2024-11-01 17:31:22 +11:00
Tobin C. Harding aa5c78430c
Replace invalidInteger with ParseIntError
We have a special type for wrapping integer parsing errors, use it.

To test this I added the following tests:

    #[test]
    pub fn debug_absolute_error_conversion_height() {
        let invalid_height = LOCK_TIME_THRESHOLD + 1;
        let _ = Height::from_consensus(invalid_height).unwrap();
    }

    #[test]
    pub fn debug_absolute_error_conversion_time() {
        let invalid_time =  LOCK_TIME_THRESHOLD - 1;
        let _ = Time::from_consensus(invalid_time).unwrap();
    }

    #[test]
    #[cfg(feature = "std")]
    pub fn debug_absolute_error_conversion_height_string() {
        let invalid_height = std::format!("{:x}", LOCK_TIME_THRESHOLD + 1);
        let _ = Height::from_hex(&invalid_height).unwrap();
    }

    #[test]
    #[cfg(feature = "std")]
    pub fn debug_absolute_error_conversion_time_string() {
        let invalid_time = std::format!("{:x}", LOCK_TIME_THRESHOLD - 1);
        let _ = Time::from_hex(&invalid_time).unwrap();
    }

    #[test]
    #[cfg(feature = "std")]
    pub fn debug_absolute_error_height_invalid_hex_string() {
        let _ = Height::from_hex("somerandomshit").unwrap();
    }

    #[test]
    #[cfg(feature = "std")]
    pub fn debug_absolute_error_time_invalid_hex_string() {
        let _ = Time::from_hex("somerandomshit").unwrap();
    }

Which resulted in the following output

Before:

---- locktime::absolute::tests::debug_absolute_error_conversion_height stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height' panicked at units/src/locktime/absolute.rs:431:56:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Blocks, input: 500000001 }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- locktime::absolute::tests::debug_absolute_error_conversion_height_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height_string' panicked at units/src/locktime/absolute.rs:444:51:
called `Result::unwrap()` on an `Err` value: ParseHeightError(Conversion(500000001))

---- locktime::absolute::tests::debug_absolute_error_conversion_time stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time' panicked at units/src/locktime/absolute.rs:437:52:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Seconds, input: 499999999 }

---- locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string' panicked at units/src/locktime/absolute.rs:457:52:
called `Result::unwrap()` on an `Err` value: ParseHeightError(InvalidInteger { source: ParseIntError { kind: InvalidDigit }, input: "somerandomshit" })

---- locktime::absolute::tests::debug_absolute_error_conversion_time_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time_string' panicked at units/src/locktime/absolute.rs:451:47:
called `Result::unwrap()` on an `Err` value: ParseTimeError(Conversion(499999999))

---- locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string' panicked at units/src/locktime/absolute.rs:464:50:
called `Result::unwrap()` on an `Err` value: ParseTimeError(InvalidInteger { source: ParseIntError { kind: InvalidDigit }, input: "somerandomshit" })

After:

---- locktime::absolute::tests::debug_absolute_error_conversion_height stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height' panicked at units/src/locktime/absolute.rs:432:56:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Blocks, input: 500000001 }

---- locktime::absolute::tests::debug_absolute_error_conversion_height_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_height_string' panicked at units/src/locktime/absolute.rs:445:51:
called `Result::unwrap()` on an `Err` value: ParseHeightError(Conversion(500000001))

---- locktime::absolute::tests::debug_absolute_error_conversion_time stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time' panicked at units/src/locktime/absolute.rs:438:52:
called `Result::unwrap()` on an `Err` value: ConversionError { unit: Seconds, input: 499999999 }

---- locktime::absolute::tests::debug_absolute_error_conversion_time_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_conversion_time_string' panicked at units/src/locktime/absolute.rs:452:47:
called `Result::unwrap()` on an `Err` value: ParseTimeError(Conversion(499999999))

---- locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_height_invalid_hex_string' panicked at units/src/locktime/absolute.rs:458:52:
called `Result::unwrap()` on an `Err` value: ParseHeightError(ParseInt(ParseIntError { input: "somerandomshit", bits: 32, is_signed: false, source: ParseIntError { kind: InvalidDigit } }))

---- locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string stdout ----
thread 'locktime::absolute::tests::debug_absolute_error_time_invalid_hex_string' panicked at units/src/locktime/absolute.rs:465:50:
called `Result::unwrap()` on an `Err` value: ParseTimeError(ParseInt(ParseIntError { input: "somerandomshit", bits: 32, is_signed: false, source: ParseIntError { kind: InvalidDigit } }))
2024-11-01 17:31:22 +11:00
Tobin C. Harding 9b7a706bfd
Remove From<ParseIntError>
The errors in `units::locktime::absolute` are complex, I'd like to make
them more simple so they are more understandable.

I have no clue why this is implemented - remove it.
2024-11-01 17:31:22 +11:00
Tobin C. Harding c90f4b6033
Fix bug in error output
`ParseTimeError` should say "block time" not "block height". This looks
like a cut'n pasta error because the `ParseHeightError` uses the same
string.
2024-11-01 17:31:21 +11:00
Christian Lewe de319670ae feat: Create relative lock times at compile time
Also mark these methods as const. Because <u32 as From<u16>>::from
is not available in const contexts, I had to cast u16 as u32. I try to
avoid casts as much as I can, but in this case a cast seems unavoidable.
Casting u16 as u32 should be safe on all architectures.
2024-09-28 18:29:15 +02:00
Christian Lewe 53e1fb6b0c feat: Create absolute lock time at compile time
Mark the from_consensus and to_consensus methods of the absolute
lock time structs as const. In theory. these methods do some sanity
checking and wrap a u32 value in a newtype. This should be possible
to do in const. Marking the methods as const should not break existing
call sites.
2024-09-28 18:14:35 +02:00
Tobin C. Harding 8f5bde9f17
units: Fix typo in measured
Its "time is measured" not "time is measure".
2024-09-04 14:45:05 +10:00
Shing Him Ng a76c13f675 Add more unit test coverage for relative LockTime 2024-07-16 12:19:13 -05:00
Shing Him Ng 7874db8fc3 Throw error instead of panic when from_second_ceil input is too large 2024-07-15 07:55:41 -05:00
Tobin C. Harding 40bee24de7
Run the formatter
I don't want to wait for the bot, just run the formatter now.

No manual changes.
2024-07-11 11:21:53 +10:00
merge-script 0511f44d99
Merge rust-bitcoin/rust-bitcoin#2994: Remove private prelude module from `units` crate
1cce1b5aa6 Remove private prelude module from units crate (Jamil Lambert, PhD)

Pull request description:

  The private prelude module has been removed from the units crate and instead imports are stated in full when needed.  As discussed in #2926.

ACKs for top commit:
  Kixunil:
    ACK 1cce1b5aa6
  apoelstra:
    ACK 1cce1b5aa6

Tree-SHA512: 58b93ff66f74399938bc1a7f59fe8d2a21d0437c7e90e0c190d3d6a8de30f9c9268c8e4288d1db287b4d190624968937b1ad6c6e54d29025370e47e71be925c1
2024-07-10 21:56:03 +00:00
Jamil Lambert, PhD 1cce1b5aa6 Remove private prelude module from units crate
The private prelude module has been removed from the units crate and
instead imports are stated in full when needed.
2024-07-10 09:14:33 +01:00
merge-script 13e27acb16
Merge rust-bitcoin/rust-bitcoin#2957: Fix rustdocs in `units` crate
6dd5af9678 Add missing links (Jamil Lambert, PhD)
47e367f011 Standardize error headings (Jamil Lambert, PhD)
75f317a689 Fix rustdoc grammar (Jamil Lambert, PhD)
573f8ce724 Add backticks to rustdoc links (Jamil Lambert, PhD)

Pull request description:

  The rustdocs in the `units` crate has been reviewed and improved.

  Some of the links were missing backticks, these have been added.

  Some grammatical changes have been made to improve the documentation.

  The use of links was inconsistent and has been changed to have links everywhere that seemed appropriate.

  A couple of error headings were added and a description as to why a capital M is not accepted in the denomination for MegaSatoshi or MegaBitcoin.

ACKs for top commit:
  apoelstra:
    ACK 6dd5af9678
  tcharding:
    ACK 6dd5af9678

Tree-SHA512: f5481a7c3aa99d7882cda9ccda9df9e27f092ff91ef584f07dc887f38bfe12e5ea801cfa7f42bb4022301860489ee6be55557752a8cbe70932f258ea753495dc
2024-07-09 14:13:32 +00:00
Jamil Lambert, PhD 6dd5af9678 Add missing links
The use of links in the rustdocs was inconsistent.

Links have been added when missing.

[`locktime::absolute::Height`] and [`locktime::relative::Height`] did
not work and `(crate::locktime)` was appended to fix it.
2024-07-08 08:53:13 +01:00