Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Farmer voting #485

Merged
merged 27 commits into from May 25, 2022
Merged

Farmer voting #485

merged 27 commits into from May 25, 2022

Conversation

nazar-pc
Copy link
Member

@nazar-pc nazar-pc commented May 22, 2022

Brace yourself, this is a big one!

Unfortunately a few refactorings were necessary along the way and it was painful to move them out, so they are part of this PR.

The primary goal of this PR is to introduce initial concept of voting. Farmers can solve with a reduced difficulty in additional to regular difficulty to have a chance of creating a vote on top of the parent block. Vote currently is just a transaction, there is no incentive (yet) for farmers to include it, but we'll change that later. For such vote farmer will also get a reward. Votes are also subject to equivocation just like block producers, though all of the logic is contained within runtime.

Votes on top of block N can only be included in block N+1 or N+2 (this is because delay between N and N+1 might be too small for vote to actually propagate over the network, which would result in many votes lost).

Voting is disabled (as useless) when solution range adjustment isn't active.

Since there are new ways to equivocate it is possible that block author itself equivocates, in which case they don't get block reward or fees, all that instead goes to storage escrow for future farmers.

While implementing voting signatures I decided to finally create a separate reward signing context for Sr25519 crypto that is separate from Substrate's, just like we have a separate context for solutions.

Along the way when working on tests I noticed that the way reward address was implemented was incorrect and it shouldn't have treated public key of the farmer and reward address as the same type. Those are distinct and in fact different in tests (there we use u64 as account ID instead), so that had to change, which involved a lot of changes throughout the codebase on all levels.

Some other tweaks like avoiding floats in solution range adjustment or making Piece contain Vec<u8> instead of [u8; 4096] (such that Polkadot.js API doesn't complain about arrays over 256 bytes and doesn't break explorer) were done as well.

I recommend to go through individual commits to see what changes were done and look at refactoring, but for actual logic and test checks final diff would be the most helpful IMO.

…extend solution ranges with voting properties
… signing/signature to reward signing/signature with context that is distinct from Substrate's default
…it compatible with Polkadot.js api and generally decrease stack size requirements
…andom errors in tests and wasn't correct in case those types didn't match (like typically the case in tests)
…quivocation yet), send all rewards of equivocated farmer into storage escrow
…validate errors more specifically, add slot validation test
…ty of solutions doesn't downgrade due to more votes found (especially with big solution range initially)
Base automatically changed from fix-incorrect-plot-sizes-estimation to main May 23, 2022 00:19
@nazar-pc
Copy link
Member Author

@liuchengxu we had another CI error, might be the same as before, I can't recall: https://github.com/subspace/subspace/runs/6555767954

@nazar-pc
Copy link
Member Author

Last 3 commits should not have been merged here, but 🤷‍♂️

…istory size to u128 numbers, avoid potential overflows in total space pledged calculation
@liuchengxu
Copy link
Contributor

Yeah, the CI failure you linked indeed looks like the same issue we have met before. Now I'm more inclined to believe it's Windows-specific as all the failures so far happened on Windows, and it also seems to be indeterministic, don't know how to reproduce it, making it harder to dig into it. Haven't checked the commits during the last Substrate upgrade, not sure if it can be really helpful but will have a look today.

i1i1
i1i1 previously approved these changes May 24, 2022
Copy link
Contributor

@i1i1 i1i1 left a comment

Choose a reason for hiding this comment

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

LGTM overall

@@ -107,6 +107,14 @@ struct Salts {
next: Option<Salt>,
}

struct AbortOnDrop<T>(JoinHandle<T>);
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a good wrapper in the rust-analyzer which is called Defer in go like manner. It has only constructor - a FnOnce closure which will be called on drop. Should we try to use smth like this?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure what you mean by that

Copy link
Contributor

@i1i1 i1i1 May 24, 2022

Choose a reason for hiding this comment

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

I mean that it would remove those class of struct overall. You can just call:

let _defer = Defer::new(|| handle.abort());

It would remove unnecessary boilerplate with implementing drop every time.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we had that use case more often I think it'd be fine, but we have just one-off here. If you notice another use case for this, feel free to create a more general purpose utility.

i1i1
i1i1 previously approved these changes May 24, 2022
…t allows slot number to be the same in the block as in the vote
let current_block_number = frame_system::Pallet::<T>::current_block_number();

if current_block_number <= One::one() || height <= One::one() {
debug!(
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, why not error!? and the other ones.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is a potentially user-provided transaction, also transactions can be late for inclusion even if they were valid initially. No need to print errors in node's logs if someone submits invalid transaction.

Copy link
Contributor

@liuchengxu liuchengxu left a comment

Choose a reason for hiding this comment

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

Looks reasonable overall, I didn't really look into all of them though. Just a few minor comments/questions.

vedhavyas
vedhavyas previously approved these changes May 25, 2022
Copy link
Member

@vedhavyas vedhavyas left a comment

Choose a reason for hiding this comment

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

LGTM. I did more focus look on the voting and its associated tests. Somehow RuntimeDebug -> Debug and other refactors added some noise though 😉

@nazar-pc nazar-pc merged commit 7dfd4b3 into main May 25, 2022
@nazar-pc nazar-pc deleted the farmer-voting branch May 25, 2022 23:29
slot_info.solution_range,
slot_info.salt,
) {
// Try to first find a block authoring solution, then if not found try to find a vote
Copy link
Member

Choose a reason for hiding this comment

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

How heavy is a call to find_by_range()? I think you could save almost everyone (except winner and voters) one call if you first check for voting_solution_range since block authoring solution_range is contained within it.
Right now the winner only does 1 call and everyone else 2. If you first check voting range, the winner and voters will do 2 calls and everyone else 1.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we just check for voting_solution_range we'll potentially find solutions that are only sufficient for voting, but not block authoring, hence block authoring frequency will decrease even if we have corresponding commitments.

The call itself isn't very heavy, but it is a database access, so it isn't free for sure.

I think we can optimize it a bit though, will submit a PR later.

Copy link
Member

Choose a reason for hiding this comment

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

I didn't mean only check for voting, I meant first check for voting, and if yes, then check also for authoring. So everyone checks for voting, and then voters and a potential winner check for authoring too, who gets the closest to target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants