Commit Graph

67 Commits

Author SHA1 Message Date
Tobin C. Harding ca6c607953
Adhere to sanity rules for amount types
From my reading of the new sanity rules (#4090) we should only have a
single constructor that accesses the inner field of the amount types.

Furthermore we have one const constructor inside the privacy boundry and
a couple outside.

Move the const constructors outside of the privacy boundry.

Internal change only.

Please note

The function being inside privacy boundary allows it to not have the
"runtime" check (most likely optimized-away after inlining). But if we
wanted to get rid of that check we should have _unchecked method
instead. But we don't want that (yet), since the check here will have
zero performance impact in optimized builds and it's not worth the
cost of dealing with unchecked constructors to optimize debug builds.
2025-04-03 13:09:40 +11:00
Tobin C. Harding 6c614d9320
units: Fix panic message
Recently I wrote a panic message that included the maximum value of an
integer however I used the max of a 16 bit value for both signed and
unsigned - this is incorrect.

Use the correct values for `u16::MAX` and `i16::MAX`.
2025-04-03 12:58:30 +11:00
Erick Cestari e744347022 Make usage of Self and type uniform across both modules
This commit standardizes the function signatures in the Amount and SignedAmount
implementations by consistently using Self as the return type instead of the concrete
type names. This makes the code more consistent, easier to maintain, and follows Rust's
idiomatic practices.

Changes:

Replace all occurrences of -> Amount with -> Self in unsigned.rs
Replace all occurrences of -> SignedAmount with -> Self in signed.rs
Make similar replacements for Option/Result return types
Use Self:: instead of the explicit type name for static method calls
2025-03-21 14:26:35 -03:00
Andrew Poelstra 2958521117
amount: remove from_sat_unchecked
Turns out we don't even need this. It is only used in one place now and
we can just stick an .expect there.
2025-03-18 19:33:03 +00:00
Andrew Poelstra d0d7a15604
amount: move MIN/MAX constants and constructors inside the privacy boundary
It's conceptually a bit tortured to have an `Amount` type defined in a
private module, with an _unchecked method allowing you to set values out
of range, which needs to be used outside of the module to *define* the
range and the constructors that check it.

Move the constants and constructors inside the privacy module, where they
can be written directly. This is easier to understand and eliminates a couple
_unchecked calls.
2025-03-18 19:33:03 +00:00
Andrew Poelstra 004d073184
amount: return i64 from parse_signed_to_satoshi
This private function is used for string-parsing an amount. It returns a
sign boolean and a u64, but its surrounding logic can be simplified if
it just returns a i64 (which is OK now since the range of `Amount` fits
into the range of i64).

Along the way we eliminate some instances of from_sat_unchecked.

Annoyingly we still need the bool to distinguish -0 from +0; when
parsing Amount we reject -0 (and we have tests for this).

This causes a couple error constructors to no longer be used outside of
unit tests. May be worth looking at whether we need them, or whether we
should be using them in parse_signed_to_satoshi.
2025-03-18 19:32:58 +00:00
Andrew Poelstra beaa2db7e5
amount: add from_sat_i32 and from_sat_u32 methods for small constants
We have a ton of calls to `from_sat_unchecked` for small constants which
were clearly in range, e.g. in fee.rs. Add a new constfn for these
cases. Don't bother making a generic Into<u32>/Into<u16> variant because
there isn't an obvious name for it.

There are 7 instances where we're using this method with values that are
out of range, which we leave as from_sat_unchecked for now.
2025-03-18 19:27:53 +00:00
Andrew Poelstra 82d9d1aeea
amount: rename `from_int_btc_const` unctions to hungarian ones
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*.
2025-03-18 19:27:51 +00:00
Tobin C. Harding 2ec1c2a044
units: Make from_int_btc_const take a 16 bit integer
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.
2025-03-18 14:49:34 +00:00
Tobin C. Harding ab4ea7c13d
Enforce the MAX_MONEY invariant in amount types
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
2025-03-13 09:07:14 +11:00
Tobin C. Harding 5d851f1c3e
Remove deprecated amount methods
When we enforce the MAX_MONEY invariant these functions would require
the function signature changing - might as well just delete them.
2025-03-11 05:37:40 +11:00
Tobin C. Harding 13595fbe7d
Fix amount whole bitcoin constructors
I royally botched the recent effort to make const amount constructors
use a smaller type. I left in an  unnecessary panic and forgot to do
both of them.

Note these function return values will change again very shortly when we
start enforcing the MAX_MONEY invariant. However the 64 to 32 bit change
is unrelated to that and is easier to review if done separately.

Whole bitcoin can not in any sane environment be greater than 21,000,000
which fits in 32 bits so we can take a 32 bit integer in the whole
bitcoin constructors without loss of utility. Doing so removes the
potential panic.

This is a breaking API change. We elect not to deprecate because we want
to keep the same function names.
2025-03-11 05:37:40 +11:00
Tobin C. Harding ac71680202
Pick one - MAX or MAX_MONEY
Just use MAX everywhere in this codebase.

After discussion in PR consensus was to just use MAX throughout the
codebase.

ref: https://github.com/rust-bitcoin/rust-bitcoin/pull/4164#discussion_r1979441438
2025-03-11 05:37:39 +11:00
Tobin C. Harding 6d70c77cf9
Enforce newtype sanity rules for amount types
The unchecked-should-be-unsafe conversation is out of scope for this
patch. We want to bite off small chunks so the constructors are left as
they currently are - we are just doing the encapsulation here. This is
in preparation for enforcing the MAX_MONEY invariant which is not
currently enforced.

As per the sanity rules policy outline in:

 https://github.com/rust-bitcoin/rust-bitcoin/discussions/4090

For both amount types create a private `encapsulate` module that
consists of exactly the type and a single constructor and a single
getter.
2025-03-11 05:37:19 +11:00
Tobin C. Harding e6f7b26d80
Use _unchecked in amount const types
We are about to start enforcing the MAX_MONEY invariant. Doing so will
change constructors to return an error type.

In preparation use the `_unchecked` constructor for all the consts.

Internal change only, no logic changes.
2025-03-11 05:32:07 +11:00
yancy 2f897e2109 Remove warning section
Since monadic handling has been introduced, panics have been replaced
with return errors.  Therefore this section is no longer applicable.
2025-03-08 10:41:20 -06:00
Tobin C. Harding 6244cb75fa
Introduce monadic AmountOpResult
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.
2025-02-10 10:06:59 +11:00
Tobin C. Harding 94f9bac6aa
Return Self::Output from ops::Rem
The ops traits return `Self::Output` not `Self`. The current code builds
because `Self` and `Self::Output` are both the same type.

Use `Self::Output` as the return value of `ops::Rem`.
2025-02-07 11:16:50 +11:00
Tobin C. Harding 13a3f490b8
Use Self instead of amount type
I claim that if the two amount modules are coded as similarly as
possible it will be easier to ensure that we have the API's uniform and
bug free. To make auditing the modules easier and less error prone use
`Self` instead of the explicit type. This makes it easier to see
differences in the modules and to ensure the differences are correct and
required.

Internal change, no logic changes whatsoever.
2025-01-25 06:46:57 +11:00
Tobin C. Harding 34e3049ae0
Use sats instead of satoshi
No one says that, just use `sats`.

Internal change only.
2025-01-24 12:16:29 +11:00
Tobin C. Harding 5eb5941215
Add FIFTY_BTC const to the amount types
The mining reward for the first epoc is 50 bitcoin. For mainnet this is
old news but for regtest it is still relevant.

Add and use a new const `FIFTY_BTC` to the `Amount` type. To keep the
amount types uniform also add it to the `SignedAmount`.
2025-01-17 10:08:09 +11:00
Jamil Lambert, PhD e316e6e719
Fix `missing_panics_doc` clippy lint in units
Change the lint to `warn` and allow for the functions that can't panic.
2025-01-15 20:52:12 +00:00
Tobin C. Harding 9d1cba4994
units: Introduce fee module
We have a bunch of functions and impl blocks scattered around the place
for calculating fee from fee rate and weight.

In an effort to make the code easier to read/understand and also easier
to audit introduce a private `fee` module and move all the code that is
related to this calculation into it.

This is in internal change only.
2025-01-08 08:17:06 +11:00
Tobin C. Harding cd908fec51
Use explicit calc getters and setters
We have a bunch of functions and impl blocks scattered around the place
for calculating fee from fee rate and weight.

In preparation for adding a `calc` module use getters and setters in
code that will move to the `calc` module.

(Remember, the `FeeRate` uses an inner sats per kwu value.)

Internal change only.
2025-01-08 08:16:39 +11:00
Tobin C. Harding 8e6784dd41
Introduce Amount::from_sat_unchecked
As we did for `SignedAmount` add a constructor to the `Amount` type that
does no checks on its argument.

(This is in preparation for enforcing the MAX_MONEY invariant.)

Use the `_unchecked` version in a single unit test. The rest of the unit
tests will be refactored later to minimise the size of this patch.
2024-12-30 06:36:00 +11:00
merge-script b2a2e8e708
Merge rust-bitcoin/rust-bitcoin#3812: Remove unnecessary floating code comment
2e482f0fdd Remove unnecessary floating code comment (Tobin C. Harding)

Pull request description:

  Code comments that comment and arbitrary block "section" of code are almost always pointless and almost always go stale over time.

  These particular code comments add almost no value.

  Remove code comments.

ACKs for top commit:
  jamillambert:
    ACK 2e482f0fdd
  apoelstra:
    ACK 2e482f0fddb55da897f0ba8ea4d3fa5bb0fba1b5; successfully ran local tests; yeah, in this case I agree

Tree-SHA512: 9cd5891e4d91af5206d99b5a2021bc82cc33e3c11d66364442a1a16866d2329ed3a005865cec1a76db80eb3191495a1710a683bc5a69284a29f164a1285b42ea
2024-12-29 18:22:40 +00:00
merge-script 779768eff9
Merge rust-bitcoin/rust-bitcoin#3769: Change method return type for to_unsigned()
e13355318e Add From impl (yancy)
364e9ff775 Change method return type (yancy)
fdf3336ed5 Add unchecked variant (yancy)

Pull request description:

  Any SignedAmount can now be cast to Amount since the range is the same.  Specifically, the range for SignedAmount is (- 21 million, 21 million) while the range for Amount is (0, 21 million).  Therefore any value from Amount can be cast to a SignedAmount and it will work.  Note it's not the same and still requires checking when going from SignedAmount to Amount since Amount can't handle the negative range.

ACKs for top commit:
  tcharding:
    ACK e13355318e

Tree-SHA512: c016b51bdd87a12eb09d9c1a82699dad1e866bf96bd3235eeb131f216f02422acb992ddb3a8135af00bbc10e240178fde5e37fb7860d9e6eaf433cf917d4d16a
2024-12-29 14:58:47 +00:00
Tobin C. Harding 2e482f0fdd
Remove unnecessary floating code comment
Code comments that comment and arbitrary block "section" of code are
almost always pointless and almost always go stale over time.

These particular code comments add almost no value.

Remove code comments.
2024-12-27 12:13:34 +11:00
yancy 364e9ff775 Change method return type
Any SignedAmount can now be cast to Amount since the range is the same.
Specifically, the range for SignedAmount is (- 21 million, 21 million)
while the range for Amount is (0, 21 million).  Therefore any value from
Amount can be cast to a SignedAmount and it will work.  Note it's not
the same and still requires checking when going from SignedAmount to
Amount since Amount can't handle the negative range.

As a side effect of changing the return type, TryFrom is no longer valid
and does not compile.  Therefore in addition to changing the return
type, TryFrom is also removed.
2024-12-24 11:31:49 -06:00
Tobin C. Harding 0a16382fa3
Rename rhs to weight
In ops functions we typically use `rhs` but for the more unconventional
`checked_*_by_*` functions lets use a more descriptive parameter name.

This is an internal change but the api files are updated because the
paramater names appear in the api text files.
2024-12-23 15:50:25 +11:00
Jamil Lambert, PhD 78f1628bf6
Add Examples to rustdocs 2024-12-19 14:05:10 +00:00
Jamil Lambert, PhD 09e184015e
Fix rustdocs in SignedAmount 2024-12-19 14:04:33 +00: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
Jamil Lambert, PhD bb29490308
Remove double spacing in rustdocs 2024-12-17 14:21:12 +00:00
Tobin C. Harding d88306fb68
units: Implement ops for amount types
Use the shiny new ops macros to implement the full set of `Add`,
`AddAssign`, `Sub`, and `SubAssign` impls we require.
2024-12-17 08:20:47 +11:00
Tobin C. Harding b31ca72b33
units: Use rhs instead of other
Be uniform and use `rhs` for all identifiers in the ops impls.

Refactor only, no logic changes.
2024-12-17 08:20:13 +11:00
merge-script 0a10d6a0ec
Merge rust-bitcoin/rust-bitcoin#3744: Change paramater type used for whole bitcoin
f97c04cf07 api: Run just check-api (Tobin C. Harding)
99b32c95b8 Change paramater type used for whole bitcoin (Tobin C. Harding)

Pull request description:

  We have multiple constructors for `Amount`, one of which accepts an integer representing whole bitcoin.

  In an attempt to make the API crystal clear change the parameter type used for whole bitcoin to `u32` instead of a `u64` which may well be mapped to sats in the mind of developers (it is in mine anyway).

ACKs for top commit:
  apoelstra:
    ACK f97c04cf07c2ac5acb5d312b573d100afa009b57; successfully ran local tests

Tree-SHA512: fb22f08f182a96ff8d067337e32174137e3d73acd2faeddc2bac974ea41f8de9ec06baa2e6fb76a2fa1a7afa7bf6b4c8f606666d966413a14d39b129e36d0674
2024-12-16 17:29:39 +00:00
Tobin C. Harding 99b32c95b8
Change paramater type used for whole bitcoin
We have multiple constructors for `Amount`, one of which accepts an
integer representing whole bitcoin.

In an attempt to make the API crystal clear change the parameter type
used for whole bitcoin to either `Into<u64>` or `u32` instead of a
`u64` which may well be mapped to sats in the mind of developers (it
is in mine anyway).
2024-12-16 13:09:28 +11:00
Tobin C. Harding b895c9aad4
units: Deprecate unchecked ops
These functions do not add value because one can just call `to_sat` and
`from_sat` if doing ops in a tight loop.

Note we need to remove these deprecated functions before we release
`units v1.0`.
2024-12-16 12:45:13 +11:00
merge-script eeb4089b3f
Merge rust-bitcoin/rust-bitcoin#3723: Use Self in amount consts
55092aab47 Use Self in amount consts (Tobin C. Harding)

Pull request description:

  Currently the consts in the `amount` modules repeat the type. For `Amount` this isn't a big deal but for `SignedAmount` its quite noisy.

  Use `Self` as the type in const declarations inside `Amount` and `SignedAmount`.

  Internal change, no logic changes.

ACKs for top commit:
  apoelstra:
    ACK 55092aab47051e740c1ee43de73e367a2f9299a3; successfully ran local tests

Tree-SHA512: 8220541f3bac85f0a40382e9545500709dac6d96496cfae76c0ff41afd937b6452e3fa12390b38f80e586a2b52baa384c580c5fe3e8ac9e80ea394b3b3ee26db
2024-12-15 14:44:42 +00:00
Jamil Lambert, PhD 01b58d668c
Add rustdoc examples 2024-12-13 09:43:56 +00:00
Jamil Lambert, PhD b881f1b54e
Add `# Errors` to rustdocs 2024-12-13 09:34:02 +00:00
Jamil Lambert, PhD 66f36b3048
Correct doc errors and add links in `unsigned` 2024-12-13 09:33:41 +00:00
Tobin C. Harding 55092aab47
Use Self in amount consts
Currently the consts in the `amount` modules repeat the type. For
`Amount` this isn't a big deal but for `SignedAmount` its quite noisy.

Use `Self` as the type in const declarations inside `Amount` and
`SignedAmount`.

Internal change, no logic changes.
2024-12-13 08:59:31 +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
Tobin C. Harding 79a229b391
units: Add pedantic lint return_self_not_must_use
As part of the effort to polish the `units` create ready for the 1.0
release; enable the pedantic lint `return_self_not_must_use`.
2024-12-11 08:50:27 +11:00
Jamil Lambert, PhD 6950c0a7b5
Change `Amount::MAX` to equal `MAX_MONEY`
To prevent rounding errors converting to and from f64 change
`Amount::MAX` to `MAX_MONEY` which is below the limit in f64 that has
issues.

Add checks to `from_str_in`, `checked_add` and `checked_mul` that the
result is below MAX, where previously a u64 overflow was relied on.

Change tests to account for new lower MAX that is within the range of
SignedAmount and does not overflow so easily

Remove overflow tests

`Amount::MAX` is now below `u64::MAX` and within the range of values for
`SignedAmount`.   These tests therefore do not overflow.
In effective_value there is no error with `Amount::MAX` and the correct
value is returned.
In psbt the removed test is effectively the same as the previous test.

Modify `Amount` tests to work with new `MAX`

Tests need to be changed that checked values above the new `MAX` or
`Amount::MAX` was out of range for `SignedAmount` which it isn't anymore
2024-12-04 14:17:00 +00:00
merge-script 58b087d946
Merge rust-bitcoin/rust-bitcoin#3674: Close `amounts` error types
fd2a5c1ec7 Close amounts error types (Tobin C. Harding)
23c77275b1 Reduce code comment lines (Tobin C. Harding)
d595f421c6 Remove whitespace between enum variants (Tobin C. Harding)

Pull request description:

  Close the two pubic enum error types in `units::amounts`. All the other structs are closed already because they either have private fields or marked `non_exhaustive`.

ACKs for top commit:
  apoelstra:
    ACK fd2a5c1ec79f337fb3695c030c9fb6b4671468f2; successfully ran local tests; thanks!

Tree-SHA512: f8d68ef821449e0829c926cf527df4b226b29c8d1d41b320a016fbf70b4b39cc54c8c218955caa0c3776158eeeae0ebacc1cc89dab67bafc399b94063324ab0e
2024-12-02 03:04:07 +00:00
Tobin C. Harding fd2a5c1ec7
Close amounts error types
Close the two pubic enum error types in `units::amounts`. All the other
structs are closed already because they either have private fields or
marked `non_exhaustive`.
2024-12-02 09:14:14 +11:00
merge-script 85d1eb8289
Merge rust-bitcoin/rust-bitcoin#3677: units: Implement `iter::Sum` for all types that implement `ops::Add`
433f70939c Implement iter::Sum for BlockInterval (Tobin C. Harding)
0369e64b56 Implement Sum for an iterator of references to amounts (Tobin C. Harding)
31f883ac00 Implement iter::Sum for FeeRate (Tobin C. Harding)

Pull request description:

  Enables summing an iterator of values. Note that this does not include either `LockTime`s. `absolute::LockTime` should not be added and for `relative::LockTime` we have https://github.com/rust-bitcoin/rust-bitcoin/issues/3676

  Close: #1638

ACKs for top commit:
  apoelstra:
    ACK 433f70939c3ecc10702ab6502e3f9bcd94dab739; successfully ran local tests; nice!
  sanket1729:
    utACK 433f70939c

Tree-SHA512: 1eda00f3bbbc61f795198ce8525a5a9b690478a8abc268da6d2e40de7d91decc28dd8211df0c6abeaf30148c7ec3907b85e3c5351972c354590569840e84d562
2024-11-29 13:28:30 +00:00