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

Generic Normalize impl for arithmetic and npos-elections #6374

Merged
10 commits merged into from
Jun 24, 2020

Conversation

kianenigma
Copy link
Contributor

Context:

When converting certain types to one another, we typically lose some accuracy based on what type of PerThing we are using. This is normal, as these types are limited.

When it comes to staking, we want to make sure that this always compensated. For example, we have an Assignment saying that someone's stake should be distributed between [a, b, c] by [33%, 33%, 33%]. This is actually a plausible example, and we have to make sure we always inject a 1% into this to have it add up to 100%.

Same story applies to when we are dealing with stake values. If I own 100 tokens, and my weight distribution is [66, 33], then we need to inject to 1 which has been lost due to rounding errors.

This is critically important for offchain phragmen as well, since validators need to compute the score offchain, which is a function of stake values, and it must be exactly the same one as computed on-chain on the validation phase, hence these rounding errors could cause a mismatch. The submit_solution fuzzer in staking particularly checks and catches bugs related to this.

Before

We had a pitiful, minimal and potentially buggy implementation for this operation here:

if fill {
// NOTE: we can do this better.
// https://revs.runtime-revolution.com/getting-100-with-rounded-percentages-273ffa70252b
if let Some(leftover) = stake.checked_sub(sum) {
if let Some(last) = distribution.last_mut() {
last.1 = last.1.saturating_add(leftover);
}
} else if let Some(excess) = sum.checked_sub(stake) {
if let Some(last) = distribution.last_mut() {
last.1 = last.1.saturating_sub(excess);
}
}
}

in which we simply and blindly added all the leftovers of any accuracy loss to the last element.

Now

We do this much better, and in a generic way. See trait Normalizable and fn normalize().

The implementation is not idea, but fast, and based on our need in which the errors are almost always small, it is the most sensible.

Next

This was part of a much bigger refactor that I am doing toward the second goal of #6242, but I don't want to again submit a PR with 10K additions and have it impossible to review. So this PR is generally a step toward breaking things down. Almost no logic in staking is changed here, so I see it is nicely isolated.

A follow up will further revamp npos-elections and add implementations for our new election algorithms.

Discussion

  • Perhaps the name normalizable is not idea. I couldn't find a better one from the math context.
  • 📢 Ideally, I want to implement Normalizable for all Vec<T> where T is some unsigned number, and and Vec<P> where P is some PerThing. But we can't do this. So I've moved the impl for PerThing to the macro and implement it individually for each one, i.e. Vec<Perbill>. But this is pretty useless, since npos-elections always works with P: PerThing, not directly a Perbill.

@kianenigma kianenigma added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C3-medium PR touches the given topic and has a medium impact on builders. labels Jun 17, 2020
@kianenigma kianenigma added C1-low PR touches the given topic and has a low impact on builders. and removed C3-medium PR touches the given topic and has a medium impact on builders. labels Jun 17, 2020
primitives/arithmetic/src/lib.rs Outdated Show resolved Hide resolved
primitives/arithmetic/src/lib.rs Outdated Show resolved Hide resolved
primitives/arithmetic/src/lib.rs Show resolved Hide resolved
primitives/arithmetic/src/lib.rs Outdated Show resolved Hide resolved
primitives/arithmetic/src/lib.rs Show resolved Hide resolved
Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
@kianenigma
Copy link
Contributor Author

@thiolliere @drahnr Thanks for the reviews. All reviews either resolved or written down why otherwise. Please resolve the comments if you agree, else elaborate why.

Copy link
Contributor

@gui1117 gui1117 left a comment

Choose a reason for hiding this comment

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

looks good to me

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
@kianenigma
Copy link
Contributor Author

bot merge

@ghost
Copy link

ghost commented Jun 24, 2020

Waiting for commit status...

@ghost
Copy link

ghost commented Jun 24, 2020

Merge failed - String("2 of 8 required status checks have not succeeded: 1 expected and 1 pending.")

@sjeohp-zz
Copy link

bot merge

@ghost
Copy link

ghost commented Jun 24, 2020

Trying merge.

@ghost ghost merged commit 357279d into master Jun 24, 2020
@ghost ghost deleted the kiz-impl-max-score-1-normalize-stuff branch June 24, 2020 13:32
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.

7 participants