Adds an implementation of div by NonZeroU64 for Amount, FeeRate, and Weight
types. Also adds a div by NonZeroI64 for SignedAmount. The operations
helps to prevent div-by-zero errors at compile time, rather than runtime.
It follows same pattern as existing div operations
but leverages safety guarantees offered by non-zero types
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`.
Currently we use a std numeric type for the output of various `Div`
implementations while other ops use `NumOpResult`. This makes it
difficult to chain operations.
Throughout the crate use `Output = NumOpResult<Foo>` when implementing
`Div`.
Later we want to enable users differentiating between an overflow and a
div-by-zero. Explicitly do not implement that yet, done separately to
assist review.
We currently use the `NumOpResult` for operations involving more than
just amount types (e.g. `FeeRate`) however when the `result` module was
written we only used amount types.
To make the intention of the custom result types more clear introduce a
top level `result` module and move the general code there. Leave the
amount implementations in the `amount` module. Note that both `result`
modules are private.
Move the `OptionExt` impls because later we will add a bunch more of them.
Internal change only, no logic changes.
We have `from_int_btc_const` on both `Amount` and `SignedAmount` because
the "real" `from_int_btc` is generic over the integer type it accepts,
which means that it cannot be a constfn. But we do want a constfn.
However, just because `from_int_btc_const` exists for the sake of
constfn doesn't mean that that's what it *is*. So rename these methods
to reflect what they *are*.
The `from_int_btc_const` constructors are specifically designed for
easily creating amount types in const context but currently they return
an error which is annoying to handle in const context. If we make the
`whole_bitcoin` parameter a 16 bit integer this gives us a nicer const
constructor with the downside that it can only create values upto a
maximum of
- unsigned: 65_536
- signed: 32_767
That is plenty high enough for most use cases.
Then use the new `from_int_btc_const` in associated consts.
Note that because `from_sat` checks max (and min) values we must
define max and min from sats directly.
Enforcing the MAX_MONEY invariant is quite involved because it means
multiple things:
- Constructing amounts is now fallible
- Converting from unsigned to signed is now infallible
- Taking the absolute value is now infallible
- Integer overflow is illuminated in various places
Details:
- Update from_sat to check the invariant
- Fix all docs including examples
- Use the unchecked constructor in test code
- Comment any other use of the unchecked constructor
- Deprecate unchecked_abs
- Fail serde (using the horrible string error variant)
- Try not to use the unchecked constructor in rustdocs, no need to encourage unsuspecting users to use it.
- Use ? in rustdoc examples (required by Rust API guidlines)
- Remove TryFrom<Amount> for SignedAmount because the conversion is now infallible. Add a From impl.
- Fix the arbitrary impls
- Maintain correct formatting
- Remove private check_max function as its no longer needed
There is an as yet unresolved discussion about the unchecked amount
constructor. In an effort to focus the amount of changes required later
and also to make the `tests` module uniform use the `sat` and `ssat`
constructor functions everywhere.
Internal change only, no logic changes.
Throughout the `amount::tests` module we use `sat` and `ssat` as aliases
to amount constructors but in on test we use them as `Denomination`
variables. To assist clarity and so we can introduce uniform usage of
the constructor aliases change the variable names to use the `den_`
prefix.
Internal change only, no logic changes.
0a9f14f7b0 Implement Div by amount for amount types (Tobin C. Harding)
b57bfb9bc5 Add missing Mul impls for amount types (Tobin C. Harding)
501c9ab89e Test amount ops that involve an integer (Tobin C. Harding)
851080d3b1 Add more add/sub tests (Tobin C. Harding)
47923957b1 Improve add/sub tests for amount types (Tobin C. Harding)
8bb9ce3e47 Add tests for amount op int (Tobin C. Harding)
Pull request description:
Improve the test coverage and add missing implementations of math operations for the amount types.
Along the way close#4030.
ACKs for top commit:
apoelstra:
ACK 0a9f14f7b036c5232449d058fb6d425c8376d87a; successfully ran local tests; nice!
Tree-SHA512: f303b2a90b5bb9e77091e047f8325821a5c89f52dfe242d849968dba0d097d3868d444009c2c05b9d7c0e91fa2ce6898cdc4733977699ca4b1ae226562878cdf
It is semantically valid to divide an amount by another amount. The
result of the operation is an integer.
Note that we cannot implement `Div` by `NumOpResult` because there is no
way to show the div by invalid case.
Implement `Div` by amount for both amount types.
Add a few macros to test `Add` and `Sub` impls for both amount types,
all combos of type and res (eg `Amount` and `NumOpResult<Amount>`), and
all combos of references.
The `NumOpResult` type is way more ergonomic to use if it derives
`Copy`. This restricts the `NumOpResult` to being `Copy` as well.
This does restrict what we can include in the error type in the future.
Derive Copy for `NumOpResult` and `NumOpResult`.
We would like to return an error when doing math ops on amount types.
We cannot however use the stdlib `Result` or `Option` because we want to
implement ops on the result type.
Add an `AmountOpResult` type. Return this type from all math operations
on `Amount` and `SignedAmount`.
Implement `core::iter::Sum` for the new type to allow summing iterators
of amounts - somewhat ugly to use, see tests for example usage.
13a3f490b8 Use Self instead of amount type (Tobin C. Harding)
34e3049ae0 Use sats instead of satoshi (Tobin C. Harding)
00b71a670f Use from_sat_unchecked for hardcoded ints (Tobin C. Harding)
8fdec67f7d Change local var ua to sat (Tobin C. Harding)
c6f056672b Change local var sa to ssat (Tobin C. Harding)
f3e853e07a units: Do trivial refactor of amount::tests (Tobin C. Harding)
dbec9807f9 Shorten identifiers by removing _in_sats (Tobin C. Harding)
154a4420fc Stop using FQP on Amount type (Tobin C. Harding)
8e16a48252 Run the formatter (Tobin C. Harding)
Pull request description:
Do a bunch of refactorings to tease out changes from #3794.
The first 8 are uncontroversial. The 9th one is subjective. The last one is unusual but IMO worth doing because of the relationship between the two amount modules.
Do note that this PR is 100% internal changes - please please don't bike shed this to death.
ACKs for top commit:
apoelstra:
ACK 13a3f490b80e4c8f8e1753111a914315eefd73e6; successfully ran local tests; lgtm
Tree-SHA512: e2ef0e7fbdaaf632a9840920a227a901fbeb55a29398013cd6cb764b1ff7c0a7c5a1648fd8f606e8b5f7523943886f5eff54cf4054d24349feb72f0b4de05b91
We have an `_unchecked` amount constructor that makes no assumptions
about the argument. We would like to start enforcing MAX_MONEY but the
diff to introduce this is massive. In an effort to make it smaller we
can do all the hardcoded ints first. We did this already but a bunch
more snuck in or were missed.
In any amount constructor that passes in a hardcoded const as a decimal
integer (i.e., not hex) use the `_unchecked` version.
Done in preparation for enforcing MAX_MONEY.
4dcdf73cfa Add `µBTC` and `µbtc` to tests (Jamil Lambert, PhD)
afba28e188 Change `uBTC` to `µBTC` in rustdocs (Jamil Lambert, PhD)
2ca24f00f2 Add `µBTC` as a recognized `str` form of `uBTC` (Jamil Lambert, PhD)
Pull request description:
`µ` is the correct letter for the SI unit micro but is not on most standard keyboards. `u` was used instead because it looks similar.
Add `µBTC` to the list of recognized strings for MicroBitcoin. This is an addition only, `uBTC` still works as normal.
Change `uBTC` to `µBTC` in the rustdocs. The examples have been left as `uBTC` since this is easier for most people to use.
Add `µBTC` and `µbtc` to the tests.
Close#3941
ACKs for top commit:
apoelstra:
ACK 4dcdf73cfa896b2c095cda9064c6e0a0e9aeec2b; successfully ran local tests
storopoli:
ACK 4dcdf73cfa
tcharding:
ACK 4dcdf73cfa
Tree-SHA512: 0f6e8b8b9c04f1a4dc6536c0420b2ded568ab96d2301b7d488807cb26003b91a787a6cf9023705c731682580f73ae5247f3f3b1e8646e4eb720c5a65da582933
bfba2a85dd Kill remaining mutants (Shing Him Ng)
871fa08f61 Fix typo in serde docs (Shing Him Ng)
462c7a1130 Add weekly cargo-mutants workflow (Shing Him Ng)
Pull request description:
This PR introduces `cargo-mutants` via a Github weekly workflow, similar to how the formatter job runs. It can also be updated to run against [incremental changes in a PR](https://mutants.rs/pr-diff.html) or to create an issues that list the new mutants. To address #3796, I've configured it to only run in `units` for now since that's nearing 1.0.
Here's a [sample run](https://github.com/shinghim/rust-bitcoin/actions/runs/12457984710) i did in my fork, if anyone would like to see what's in the `mutants-out` artifact that gets generated.
ACKs for top commit:
tcharding:
ACK bfba2a85dd
apoelstra:
ACK bfba2a85ddaad6b366a7502cbda1ff2462dfd4c7; successfully ran local tests
Tree-SHA512: e4a44b6f5121e4238c1c3576616f551f4f43349cf5fd5ac1d6331f958a4458753a55519bdafc16965cb2e67201ef6c91b188c79ffcc222f780c421df9a701063
7482fcd934 Run just check-api (jrakibi)
bcc38c40e0 Add Amount division by FeeRate (jrakibi)
Pull request description:
Add checked_div_by_fee_rate method to Amount that computes the maximum weight for a transaction with a given fee rate. This complements the existing `fee = fee_rate * weight `and `fee_rate = fee / weight` operations
- Add `checked_div_by_fee_rate` method that returns Option<Weight>
- Implement` Div<FeeRate>` for Amount for operator syntax support
- Use `floor` division to ensure weight doesn't exceed intended fee
This allows calculating the maximum transaction weight possible for a given fee amount and fee rate.
Closes#3814
ACKs for top commit:
apoelstra:
ACK 7482fcd934c09e3cd6cd25fd4328960b02f8e976; successfully ran local tests
tcharding:
ACK 7482fcd934
Tree-SHA512: 622ca42bde1f67782a3c2996efcba0132fedb5e984f594603aece974de6acdeb4b22d63239d29d46fb8623c8082841c33b1d5b9ad2ea51e2f63e6f5d859daa7e
Implement `checked_div_by_fee_rate_floor` and `checked_div_by_fee_rate_ceil` methods to compute the maximum and minimum transaction weights.
These methods provide precise weight calculations using both floor and ceiling divisions.
- Introduce `checked_div_by_fee_rate_floor` for floor-based weight division.
- Add `checked_div_by_fee_rate_ceil` for ceiling-based weight division.
- Update `ops::Div` implementation for `Amount` to use floor division by default.
- Include unit tests to validate both floor and ceiling division methods.
As we do in other places in the `amount::tests` module; use a local
`sat` variable bound to the `Amount::from_sat` constructor.
Internal change, no logic changes.
As we do in other places in the `amount::tests` module; use a local
`ssat` variable bound to the `SignedAmount::from_sat` constructor.
Internal change, no logic changes.
Reorder assertions in `units::amount::tests` to follow got, want order
Makes debugging easier, as there's no need to check the test to verify the order.
We have a `_unchecked` constructor now for both `Amount` and
`SignedAmount`. In preparation for enforcing the `MAX_MONEY` invariant
use the `_unchecked` constructor throughout the codebase to construct
amounts from hard coded integer values.
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