Skip to content

Add from_int_btc method to Amount#1870

Merged
apoelstra merged 2 commits intorust-bitcoin:masterfrom
yancyribbens:from-btc-const
Jun 14, 2023
Merged

Add from_int_btc method to Amount#1870
apoelstra merged 2 commits intorust-bitcoin:masterfrom
yancyribbens:from-btc-const

Conversation

@yancyribbens
Copy link
Copy Markdown
Contributor

@yancyribbens yancyribbens commented May 24, 2023

Followup PR from #1811

Added a const associated function from_int_btc() for Amount. panic() in const context is only available after 1.57+ so a work around is provided.

@yancyribbens yancyribbens force-pushed the from-btc-const branch 2 times, most recently from f435a2f to c57a7e0 Compare May 24, 2023 10:33
@yancyribbens
Copy link
Copy Markdown
Contributor Author

hmm this compiles fine on my local machine but I didn't notice the warning "invalid feature rust_v_1_57 .." which causes CI to fail. Looks like this needs more work.

@tcharding
Copy link
Copy Markdown
Member

tcharding commented May 24, 2023

Should be using conditional configuration option not a feature (that means
#[cfg(rust_v_X_Y)]). There is another instance of using it as a feature in the code currently which is wrong.

@apoelstra
Copy link
Copy Markdown
Member

We could also tack an _unchecked suffix onto it and then do something nasty (e.g. replace with 0) on invalid input.

Even without _unchecked I wouldn't be too opposed to having it silently replace with MAX_MONEY, or do an infinite loop, or something. It just feels bad to compiler-gate a method to deal with an error case which should never happen.

@yancyribbens
Copy link
Copy Markdown
Contributor Author

We could also just add 'unchecked` to the end and let the default behavior of overflow in release mode or panic in debug mode happen. I'm fine with that as long as unchecked is added. I think it could happen if applications don't sanitize user input.

@apoelstra
Copy link
Copy Markdown
Member

or panic in debug mode happen

Well, we can't panic under any circumstances because we're trying to make a constfn.

We could overflow in both release and debug mode, I suppose.

@yancyribbens
Copy link
Copy Markdown
Contributor Author

I'm afk right now so I can't test, however I was thinking const fn will still panic in debug mode if for example u64::max * 2 is calculated, otherwise in release mode it silently overflows.

@yancyribbens
Copy link
Copy Markdown
Contributor Author

I tested on the rust playground and I guess since it's const fn the compiler won't allow overflows to compile. Although I'm not sure how the sementics work with const fn if user args are provided. Maybe that's not possible.

@apoelstra
Copy link
Copy Markdown
Member

I tested on the rust playground and I guess since it's const fn the compiler won't allow overflows to compile. Although I'm not sure how the sementics work with const fn if user args are provided. Maybe that's not possible.

This is potentially very cool, if we can exploit that by transforming arbitrary "invalid inputs" into integer overflows.

@tcharding
Copy link
Copy Markdown
Member

tcharding commented May 26, 2023

How about this, it leaks the internal representation in the docs but every dev knows that bitcoin is stored in sats as a u64.

    /// Creates an [`Amount`] from a value representing a whole number of bitcoin.
    ///
    /// Internally computes the number of satoshis (ie, `btc * 100_000_000`)
    /// saturating at the numeric bounds of `u64`.
    pub const fn saturating_from_int_btc(btc: u64) -> Amount {
        Amount(btc.saturating_mul(100_000_000))
    }

and a unit test

    #[test]
    fn const_saturating_from_int_btc_overflow() {
        let got = Amount::saturating_from_int_btc(u64::MAX - 10);
        let want = Amount(u64::MAX);
        assert_eq!(got, want);
    }

@tcharding
Copy link
Copy Markdown
Member

OT: Why don't we have a const SATS_PER_BITCOIN instead of all the 100_000_000 in the code base?

@junderw
Copy link
Copy Markdown
Contributor

junderw commented May 26, 2023

OT: Why don't we have a const SATS_PER_BITCOIN instead of all the 100_000_000 in the code base?

Amount::ONE_BTC exists... maybe use that everywhere?

@junderw
Copy link
Copy Markdown
Contributor

junderw commented May 26, 2023

How about this

If we make a saturating one, I'd expect it to saturate to a whole BTC... maybe even 21 mil (MAX_BTC)

u64::MAX is kind of weird, since it's not a whole bitcoin.

@tcharding
Copy link
Copy Markdown
Member

tcharding commented May 26, 2023

How about this

If we make a saturating one, I'd expect it to saturate to a whole BTC... maybe even 21 mil (MAX_BTC)

Let's not have the whole "what does max bitcoin amount mean" debate here, its been argued before and is unlikely to be resolved IMO.

u64::MAX is kind of weird, since it's not a whole bitcoin.

I was under the impression that everyone knows that bitcoin (in general not just in rust-bitcoin) uses ints not floats so this behaviour is obvious but that's coming from the perspective of a low level C guy with a history of disliking floats - am I wrong?

@junderw
Copy link
Copy Markdown
Contributor

junderw commented May 26, 2023

I just think it's weird that

184467440737 will result in Amount(18446744073700000000)
but
184467440738 and above will result in Amount(18446744073709551615)

Since the whole point of the function is to turn 10 into 10 BTC worth of an Amount...

But again, I think this is just personal preference, and if it's documented anything is fine.

@tcharding
Copy link
Copy Markdown
Member

Cool, thanks for getting the bounds. So if I understand you clearly this leads to something like (excluding the exact name):

pub const: u64 MAX_EXPRESSIBLE_WHOLE_BITCOIN_IN_SATS = 18446744073700000000;

and we saturate to that. I agree with the sentiment, the reason I'd like to avoid this is because it provides an answer to the "what is the meaning of max bitcoin" question. Currently we implicitly define max bitcoin as u64::MAX sats and so far we have been unable to get any improvement on that, at least that is how I understood the debate.

What if, in this PR, we saturate to Amount::MAX, state as such in the docs, then leave the whole "what is Amount::MAX, and what does it even mean" discussion for later work on the amount module (which is getting a bunch of work at the moment). Would that be a good compromise?

@junderw
Copy link
Copy Markdown
Contributor

junderw commented May 26, 2023

Sounds perfect.

BTC_MAX (21 mil BTC) and MAX seems confusing though.

@apoelstra
Copy link
Copy Markdown
Member

apoelstra commented May 26, 2023

concept ACK from me on saturating as long as it's documented. The warning should probably be in bold, and we should briefly explain that we'd like to just panic but can't in a constfn at our current MSRV. I don't care where we saturate at. I mildly prefer we not provide an exposed constant for this because that will commit us to it. (Though OTOH if we commit to anything, u64::MAX seems like the most technically justifiable value.)

I also think that we should explore whether we can just use * rather than saturating_mul, and if that will give us the desired "panic in debug mode, overflow in release mode, refuse to compile in a compile-time-evaluated constfn" behavior.

@tcharding
Copy link
Copy Markdown
Member

You continue prodding finally tweaked my interest, it behaves as we want - see: #1883

@Kixunil
Copy link
Copy Markdown
Collaborator

Kixunil commented May 27, 2023

I'm not convinced saturating is that useful, we should just use the array out of bounds trick to panic in const.

@yancyribbens
Copy link
Copy Markdown
Contributor Author

I also don't see why we should bother with saurating_mul. As I understand, const context evaluates when compiled, and if there is an overflow it's better to have a compiler error and not compile instead of saturating.

apoelstra added a commit that referenced this pull request May 28, 2023
0046bb8 Fix usage of cfg(rust_1_53) (Tobin C. Harding)
c3450f3 Remove stale usage of doc(cfg) (Tobin C. Harding)

Pull request description:

  These build cfg options are not features, fix broken usage. And remove stale docsrs attribute while we are at it. Bad rust-bitcoin devs.

  Found while reviewing #1870

ACKs for top commit:
  apoelstra:
    ACK 0046bb8
  Kixunil:
    ACK 0046bb8

Tree-SHA512: 7053affef6654ff203c93590bf081e165f019feb040aa8c55259ffe4e15eaf0e7522f6e5a4f6f62e8f578420b0313f4b7b17c46b741b7fcfd05750e5c5976589
@yancyribbens
Copy link
Copy Markdown
Contributor Author

I'm not convinced saturating is that useful, we should just use the array out of bounds trick to panic in const.

It looks like there is a lint that prevents the array oob trick 🤦

@yancyribbens
Copy link
Copy Markdown
Contributor Author

If the OOB trick isn't possible, maybe feature gate this so it's only available in 1.57+?

@apoelstra
Copy link
Copy Markdown
Member

You could either disable the lint or just remove the let binding.

@tcharding tcharding added the waiting for author This can only progress if the author responds to a request. label Jun 6, 2023
@yancyribbens
Copy link
Copy Markdown
Contributor Author

Sorry for the delay, was afk for a bit

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.

Thanks man, looks good!

ACK b7b5e0452f337c442640bb870488b666059b32d3

There are a bunch more places this new function could be used if you get super motivated (git grep _000_000).

tcharding
tcharding previously approved these changes Jun 10, 2023
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.

This shouldn't really be in here but I won't hold you up for it :)

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.

Doh, will fix

@yancyribbens
Copy link
Copy Markdown
Contributor Author

git grep _000_000

Oh nice, git grep is dope. Or better yet, git grep -n _000_000 so one can find the line num.

@yancyribbens yancyribbens force-pushed the from-btc-const branch 2 times, most recently from 701b24d to 88df011 Compare June 10, 2023 11:05
@tcharding
Copy link
Copy Markdown
Member

I use a shell alias to git grep -IPn --color=always

tcharding
tcharding previously approved these changes Jun 11, 2023
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 88df0115f5b919195fd6dced10f56902ee380bb9

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should have # Panics section.

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.

Lucky we have @Kixunil on review to catch the things that I miss :)

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.

Thanks, I added a panic section

@yancyribbens yancyribbens force-pushed the from-btc-const branch 3 times, most recently from f370406 to c99c3db Compare June 12, 2023 23:30
@yancyribbens
Copy link
Copy Markdown
Contributor Author

There are a bunch more places this new function could be used if you get super motivated (git grep _000_000).

This is the const version, so it's really only useful for other const functions.

@tcharding
Copy link
Copy Markdown
Member

tcharding commented Jun 13, 2023

Woops :) Yes its const but its also more terse. Not to worry, we can do it at another time.

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.

A bunch of unrelated changes have snuck into the PR, can you remove them or explain them please? (The PR describtion is stale now too.)

Thanks man

Comment on lines 204 to 210
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.

Did you mean to put this in here? Its unrelated to the PR.

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.

Crap, looks like a bad git rebase.

Comment on lines 1620 to 1621
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.

Suggested change
#[should_panic]
#[test]
#[should_panic]
#[test]

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.

Suggested change
fn from_int_btc_panic() {
fn from_int_btc_overflow() {

@yancyribbens
Copy link
Copy Markdown
Contributor Author

A bunch of unrelated changes have snuck into the PR, can you remove them or explain them please? (The PR describtion is stale now too.)

Thanks man

Sorry about that. It looks like I pulled in some old state from master on accident.

@tcharding
Copy link
Copy Markdown
Member

ACK 9f7449b

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 9f7449b

@apoelstra apoelstra merged commit b1078fe into rust-bitcoin:master Jun 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting for author This can only progress if the author responds to a request.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants