Skip to content

Change Amount::MAX from u64::MAX to Amount::MAX_MONEY#3693

Merged
apoelstra merged 1 commit intorust-bitcoin:masterfrom
jamillambert:1204_amount-max
Dec 9, 2024
Merged

Change Amount::MAX from u64::MAX to Amount::MAX_MONEY#3693
apoelstra merged 1 commit intorust-bitcoin:masterfrom
jamillambert:1204_amount-max

Conversation

@jamillambert
Copy link
Copy Markdown
Contributor

As discussed in #3688 and #3691 using u64::MAX causes errors when converting to f64 so MAX_MONEY is should be used as the maximum Amount.

  • Amount::MAX changed to equal MAX_MONEY
  • Add a check to add, multiply and from_str functions
  • Change tests to account for new lower maximum

Different approach to the existing PR #3692. I have only done Amount and not SignedAmount until there is feedback on which approach to use.

@github-actions github-actions bot added C-bitcoin PRs modifying the bitcoin crate C-units PRs modifying the units crate labels Dec 4, 2024
@coveralls
Copy link
Copy Markdown

coveralls commented Dec 4, 2024

Pull Request Test Coverage Report for Build 12161613662

Details

  • 26 of 26 (100.0%) changed or added relevant lines in 3 files are covered.
  • 2 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-0.01%) to 82.861%

Files with Coverage Reduction New Missed Lines %
units/src/amount/unsigned.rs 2 83.71%
Totals Coverage Status
Change from base Build 12121100676: -0.01%
Covered Lines: 20180
Relevant Lines: 24354

💛 - Coveralls

@apoelstra
Copy link
Copy Markdown
Member

utACK 0922c82c167e62e92cc57a2f9e284c5c9885dcb3 -- but I guess the tests don't pass on your first commit? If not, can you squash everything together so that they will pass on every commit? (Alternately, in your first commit, you can just add /* */ comments around the tests you intend to change later, which will lead to a cleaner diff.)

@jamillambert
Copy link
Copy Markdown
Contributor Author

I went with the easier option of squashing

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
Copy link
Copy Markdown
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK a2bf6b134e080169e2e2903b24821b3fc3251d86; successfully ran local tests

@yancyribbens
Copy link
Copy Markdown
Contributor

Different approach to the existing PR #3692. I have only done Amount and not SignedAmount until there is feedback on which approach to use.

I can just rebase these changes into 3652 since this a smaller subset of changes I propose making in 3652.

pub const MIN: Amount = Amount::ZERO;
/// The maximum value of an amount.
pub const MAX: Amount = Amount(u64::MAX);
pub const MAX: Amount = Amount::MAX_MONEY;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just remove this if we are not enforcing this in constructor and not doing #3692 ? It would be confusing to have something named MAX, but we can construct values more than that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do intend to enforce this in the constructor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change from_sat in this patch to check if the value is above MAX. The other functions that create an Amount use either checked_mul or from_str_in which do check already.

If from_sat is called with a value above MAX should it panic?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss the from_sat change in another PR. My feeling is yes, and we should introduce a new from_sat_unchecked.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If from_sat is called with a value above MAX should it panic?

In #3692 I created from_sat_unchecked which panics if above MAX and also from_sat which returns None if greater than MAX. I've based that branch off of this one and I think this PR looks good to merge as is. As for MAX_MONEY, an argument to keep it in for now is that core defines the same const named MAX_MONEY as the supply cap.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we should keep both the Rustic MAX constant and the Bitcoin MAX_MONEY constant, and just document that they're synonyms.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have opened issue #3696 as suggested below to address enforcing MAX.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks man.

Copy link
Copy Markdown
Member

@tcharding tcharding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6950c0a

@tcharding
Copy link
Copy Markdown
Member

Can you write an issue please @jamillambert "enforce MAX invariant in Amount" or some such thing. Then link to it here please.

@tcharding
Copy link
Copy Markdown
Member

Just because I hit it today; here is a pleasant example of a usecase for an Amount that is less than MAX_MONEY

"amount" : x.xxx,             (numeric) The total amount received by addresses with this label

@apoelstra
Copy link
Copy Markdown
Member

@tcharding I guess you mean "more than MAX_MONEY". And that display, depending on how it is calculated, will easily overflow the mantissa of a f64 and less-easily overflow a u64. So anything displaying it needs to have special logic anyway (or just accept that it'll be wrong).

@tcharding
Copy link
Copy Markdown
Member

Oh I was just commenting that here was an example of a float that should be able to be parsed into a type and the value be less that MAX_MONEY. It was purely out of interest.

Copy link
Copy Markdown
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6950c0a; successfully ran local tests

@apoelstra apoelstra merged commit b579e12 into rust-bitcoin:master Dec 9, 2024
@jamillambert jamillambert deleted the 1204_amount-max branch December 29, 2025 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-bitcoin PRs modifying the bitcoin crate C-units PRs modifying the units crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants