Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Introduce checked_div for PerThings and checked_rational_mul_correction#14673

Open
Gioyik wants to merge 4 commits intomasterfrom
gio/checked_fn
Open

Introduce checked_div for PerThings and checked_rational_mul_correction#14673
Gioyik wants to merge 4 commits intomasterfrom
gio/checked_fn

Conversation

@Gioyik
Copy link
Member

@Gioyik Gioyik commented Jul 28, 2023

Fixes paritytech/polkadot-sdk#199

Introduces checked_div and checked_rational_mul_correction

Notes:

  • checked_div() in PerThings have to options to complete the division, however, I am not sure which one would be the best, both seem to output the same.
  • The checked behavior of checked_rational_mul_correction can be introduced for multiply_by_rational_with_rounding, however it implies changing all the tests and developers using it might need to change it to expect Option<u128> instead of u128. So I am holding changes if this is not desired.

@Gioyik Gioyik changed the title introduce checked_div for PerThings and checked_rational_mul_correction Introduce checked_div for PerThings and checked_rational_mul_correction Jul 28, 2023
@Gioyik Gioyik marked this pull request as ready for review July 31, 2023 17:48
@Gioyik Gioyik requested a review from a team July 31, 2023 17:48
@Gioyik
Copy link
Member Author

Gioyik commented Jul 31, 2023

there are many panic! in the fixed_point.rs file that I think can be moved to the safe and unchecked_ function logic.

@ggwpez do you think it's fine to make the switch in those files and include it in this PR or those should stay as panic!?

/// Take the remainder of `x / denom` and multiply by `numer / denom`. The result can be added
/// to `x / denom * numer` for an accurate result.
fn rational_mul_correction<N, P>(x: N, numer: P::Inner, denom: P::Inner, rounding: Rounding) -> N
fn unchecked_rational_mul_correction<N, P>(
Copy link
Member

@gavofyork gavofyork Aug 1, 2023

Choose a reason for hiding this comment

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

Existing Rust idioms have checked_ arithmetic variants with prefixing, not unchecked variants. We will stay with those unless/until a very strong argument to break with Rust idioms are presented.

Copy link
Member Author

Choose a reason for hiding this comment

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

super interesting, I was discussing with @ggwpez over chat the rational behind the checked and why functions do not behave as checked ones by default.

this clarifies everything

Copy link
Member

@gavofyork gavofyork left a comment

Choose a reason for hiding this comment

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

Cannot be accepted in the present state.

@kianenigma
Copy link
Contributor

bot fmt

@command-bot
Copy link

command-bot bot commented Aug 2, 2023

@kianenigma https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3320751 was started for your command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh". Check out https://gitlab.parity.io/parity/mirrors/substrate/-/pipelines?page=1&scope=all&username=group_605_bot to know what else is being executed currently.

Comment bot cancel 1-78f2445a-1362-4601-9d6a-9cd93bf5bc56 to cancel this command or bot cancel to cancel all commands in this pull request.

@command-bot
Copy link

command-bot bot commented Aug 2, 2023

@kianenigma Command "$PIPELINE_SCRIPTS_DIR/commands/fmt/fmt.sh" has finished. Result: https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3320751 has finished. If any artifacts were generated, you can download them from https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3320751/artifacts/download.

@Gioyik
Copy link
Member Author

Gioyik commented Aug 2, 2023

now there are checked_ functions with Result<>. One question, in these two calls:

https://github.com/paritytech/substrate/blob/gio/checked_fn/primitives/arithmetic/src/per_things.rs#L482
https://github.com/paritytech/substrate/blob/gio/checked_fn/primitives/arithmetic/src/per_things.rs#L495

do we want to replace with the checked version of the function?

@Gioyik Gioyik requested review from gavofyork and ggwpez August 2, 2023 18:47
@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: test-linux-stable
Logs: https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3321459

@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: test-linux-stable-int
Logs: https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/3321465

}

/// Returns 2^128 / a
/// `checked_div()` could be used here but is not possible to `unwrap()` inside a `const fn`
Copy link
Member

Choose a reason for hiding this comment

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

I think you can use a match or if in const functions.

But for this function i would probably make more sense to add a checked_div128 function instead of changing it.

return Err("Division by zero")
}

Ok(multiply_by_rational_with_rounding(a, b, c, r))
Copy link
Member

Choose a reason for hiding this comment

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

As a general consideration of design:
I think its easier to put the actual logic inside the checked_ function such that the unchecked variant is just checked_function().expect() or checked_function.unwrap_or(whatever) since otherwise you have the case like now, where the checked variant does not have any logic and can therefore not ensure that it wont ever panic.

Comment on lines -194 to -196
if c == 0 {
return None
}
Copy link
Member

Choose a reason for hiding this comment

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

This is actually making it less secure, which is why i would rather put the logic in the checked variant (basically same comment as above).

Comment on lines +511 to +514
if P::Inner::is_zero(&denom) {
return Err("Division by zero")
}
Ok(rational_mul_correction::<N, P>(x, numer, denom, rounding))
Copy link
Member

Choose a reason for hiding this comment

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

Now you have the implication that the underlying function can only error iff denom is null, which is an implementation detail. Again i would rather move the logic into the checked variant and then call it from the unchecked one.

impl CheckedDiv for $name {
#[inline]
fn checked_div(&self, rhs: &Self) -> Option<Self> {
let q = rhs.0;
Copy link
Member

Choose a reason for hiding this comment

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

I think there should be an rhs.is_zero()

return None
}

Some(*self / *rhs)
Copy link
Member

Choose a reason for hiding this comment

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

probably want to use the deconstruct() function here to get the inner value.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce checked PerThing arithmetics

5 participants