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

Attempt to remove the where bounds in arithmetic. #7933

Merged
7 commits merged into from
Jan 21, 2021
Merged

Conversation

kianenigma
Copy link
Contributor

Needed for #7929

So far, these where clauses have been haunting me everywhere up to the runtime. The reason for their existence is the use of <P: PerThing>, which means that we don't initially know what is the type P::Inner and if it meets all the requirements of other functions (like from_rational_approximation).

So far, I have let this be, we need generic P in some places.

During #7929, I was quite annoyed by this as the where clause literally propagates to almost every single file and function of staking, if you are to make OffchainAccuracy generic.

Note that we already tolerate and accept this in #7909 as well, but there it is cleaner because everything is wrapper in impl Pallet.

So I tried to just remove this where clause from the source, which is this PR. In essence, the only main assumption added is that type Inner is always Into<u128>. This can easily hold as long as we keep our per-things within the standard primitive types (note: unsigned types are already not allowed, so you have u8 -> u128 left). But this would disallow using per-things with higher accuracy levels such as U256 etc.

I had to shuffle a bit of From<U> for T into Into<T> for U, which to this moment still confuses me, but seemingly it was necessary since rustc does not assume it automatically. At first, I really expected just adding type Inner: Into<u128> but it is not.

@kianenigma kianenigma added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. labels Jan 19, 2021
@kianenigma kianenigma requested a review from gui1117 January 19, 2021 13:59
@@ -37,13 +38,17 @@ pub trait PerThing:
Sized + Saturating + Copy + Default + Eq + PartialEq + Ord + PartialOrd + Bounded + fmt::Debug
{
/// The data type used to build this per-thingy.
type Inner: BaseArithmetic + Unsigned + Copy + fmt::Debug;
type Inner: BaseArithmetic + Unsigned + Copy + Into<u128> + fmt::Debug;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

TLDR ^^^^^^^^^^^^^^^^^^^^^^

@gui1117
Copy link
Contributor

gui1117 commented Jan 20, 2021

I had to shuffle a bit of From for T into Into for U, which to this moment still confuses me, but seemingly it was necessary since rustc does not assume it automatically.

I think this is because: although From<T> for U implies Into<U> for T the opposite is not true. Into doesn't implies From

@gui1117
Copy link
Contributor

gui1117 commented Jan 20, 2021

TLDR: we could change from_rational_approximation to bound N: TryFrom<Self::Inner> instead of N: From<Self::Inner>, but it would make code even more tricky for probably no benefit. So I'm fine with the change you proposed.

All this is because from_rational_approximation requires N to be From<Self::Inner>
I required it because we usually used the function with N being more than Inner arithmetic.
But now that PerThing::Inner is generic in trait PerThing we need to add these where_clause everywhere even when N is u128.

But actually if N arithmetic fit into Self::Inner (i.e. N is u16 and Self::Inner is u32) then implementing from_rational_approximation is doable:

diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs
index c6a31a0ff..9304ff59f 100644
--- a/primitives/arithmetic/src/per_things.rs
+++ b/primitives/arithmetic/src/per_things.rs
@@ -362,7 +362,7 @@ macro_rules! implement_per_thing {
                        }
 
                        fn from_rational_approximation<N>(p: N, q: N) -> Self
-                       where N: Clone + Ord + From<Self::Inner> + TryInto<Self::Inner> + TryInto<Self::Upper>
+                       where N: Clone + Ord + TryFrom<Self::Inner> + TryInto<Self::Inner> + TryInto<Self::Upper>
                                + ops::Div<N, Output=N> + ops::Rem<N, Output=N> + ops::Add<N, Output=N> + Unsigned
                        {
                                let div_ceil = |x: N, f: N| -> N {
@@ -379,7 +379,23 @@ macro_rules! implement_per_thing {
                                // p should not be bigger than q.
                                let p: N = p.min(q.clone());
 
-                               let factor: N = div_ceil(q.clone(), $max.into()).max((1 as Self::Inner).into());
+                               let acc: N = if let Ok(acc) = $max.try_into() {
+                                       acc
+                               } else {
+                                       // $max doesn't fit into `N` arithmetic,
+                                       // thus $max is strictly more than `N::max_value()`,
+                                       // thus `N::max_value()` is strictly less than $max,
+                                       // but p and q are less than `N::max_value()`,
+                                       // thus p and q are less than $max,
+                                       // thus p * $max fits into `Upper` (Upper must be able to compute `$max^2`)
+                                       // and q fits into `Inner`
+                                       let part =
+                                               Self::Inner::try_from(p).expect("..") as $upper_type
+                                               * $max as $upper_type
+                                               / q as $upper_type;
+                                       return $name(part as Self::Inner)
+                               };
+                               let factor: N = div_ceil(q.clone(), acc).max((1 as Self::Inner).into());
 
                                // q cannot overflow: (q / (q/$max)) < $max. p < q hence p also cannot overflow.
                                let q_reduce: $type = (q.clone() / factor.clone())

EDIT: thinking of it again it might be wrong. Because then it allows ppl to use stuff like NonZeroU128 for N maybe, and this is not good.

Comment on lines 344 to 345
})
.collect::<Vec<_>>();
Copy link
Member

Choose a reason for hiding this comment

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

this formatting cant be right

@kianenigma
Copy link
Contributor Author

bot merge

@ghost
Copy link

ghost commented Jan 21, 2021

Waiting for commit status.

@ghost
Copy link

ghost commented Jan 21, 2021

Head SHA changed; merge aborted.

@kianenigma
Copy link
Contributor Author

bot merge

@ghost
Copy link

ghost commented Jan 21, 2021

Waiting for commit status.

@ghost ghost merged commit a7fd1e5 into master Jan 21, 2021
@ghost ghost deleted the kiz-bloody-where-clause branch January 21, 2021 09:39
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants