Skip to content

Conversation

@ecioppettini
Copy link
Contributor

@ecioppettini ecioppettini commented Feb 9, 2022

Change the tally to be done incrementally (with each vote)

Some comments on a few things, briefly paraphrasing the original story. The git history is a bit messy, but I guess we'll squash anyway.

VoteCast certificate

Tally is computed incrementally, e.g. the system takes the current voting power, user’s choice, multiplies them and adds to the tally.

With the current implementation the voting power is taken at the moment of the vote, initially I wanted to keep the immutable snapshot of the TokenDistribution inside the VotePlanManager from the start, but then the order of MintToken fragments and VotePlan fragments in the block0 would matter, and I think it's a bit fragile. In any case, the behavior is the same since the voting power won't change.

Ballots are no longer stored in the ledger state.
The voting ledger stores whether a user voted for the proposal or not.
Based on this the ledger prevents a user from casting a vote more than once for the same proposal.

There were a few tests that used the stored payloads for validation, I rewrote those so the assertions are based on the tally result instead.

EncryptedTally certificate

This certificate is no longer needed and should be removed.

Questions here

I kept the binary tag number unused, mostly because it may lead to a better error if we use a new version of the library to read and old fragment for some reason, but maybe it's better to compact things (there is a TODO for this in the code).

Also, are we updating the abnf file? I think we are not, so I didn't bother.

Getting the state of vote tallying as an API user

GET /api/v0/vote/active/plans

The vote tally was available via this endpoint from the start, the only difference now is that it is available for the whole duration of the voting process (e.g. could be non-optional).

This needs to be done in jormungandr too, of course, but I removed the Option from the VoteProposalStatus.

There is only one thing that I'd like to clarify here, the total_stake in the private tally is now taken at the moment the statuses are requested. I didn't want to store it from the beginning for the same thing I mentioned above, if there are MintToken certificates processed after the VotePlan then we won't consider them, unless we add some extra code to handle that case in Ledger::new.

I don't expect this to be a performance concern at the moment, since we likely won't have that many tokens, but it depends on how often the statuses are requested too. Although, to be honest, I'm not quite convinced the total_stake should be part of the tally state, but I guess it's coupled for pragmatic reasons.

@ecioppettini ecioppettini self-assigned this Feb 9, 2022

assert_eq!(
vote_plan_manager
.start_private_tally(token_distribution, block_date, committee_id)
Copy link
Contributor Author

@ecioppettini ecioppettini Feb 9, 2022

Choose a reason for hiding this comment

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

I removed this test since start_private_tally is not there anymore... And I don't see this testing anything else, but it's weird to delete a test, so I would appreciate a second pair of eyes at this.

@zeegomo
Copy link
Contributor

zeegomo commented Feb 9, 2022

but then the order of MintToken fragments and VotePlan fragments in the block0 would matter, and I think it's a bit fragile

Contrasting feeling for this. On one side, we usually put starting conditions in block0 besides basic account creation, but on the other hand block0 is just a block like all others, and ordering is an important property of blocks.
We should also consider VotePlans submitted after block0.

Also, are we updating the abnf file? I think we are not, so I didn't bother.

I updated it for the update proposal changes, but not sure it reflects everything. I would like it to be maintained, it's an easy way to look at chain formats without having to dig through the code.

with current implementation the voting power is taken at the moment of the vote
In any case, the behavior is the same since the voting power won't change

This only works because token transfers are not implemented, but they are not guaranteed to remain so forever (actually there are good reasons to implement that). Please add a big disclaimer in the code for this.

@ecioppettini
Copy link
Contributor Author

ecioppettini commented Feb 9, 2022

Contrasting feeling for this. On one side, we usually put starting conditions in block0 besides basic account creation, but on the other hand block0 is just a block like all others, and ordering is an important property of blocks.
We should also consider VotePlans submitted after block0.

I mean, I think the order should matter... It's just that in this case it's a bit strange, currently the VotePlanManager creation is tied to the VotePlan certificate, but to me it would make more sense if it's instanced just when it is the actual voting date. Like, to me it makes no sense that a VotePlan should only see the tokens that were declared before, since the actual voting will be in the future.

This only works because token transfers are not implemented, but they are not guaranteed to remain so forever (actually there are good reasons to implement that). Please add a big disclaimer in the code for this.

I'm not sure a disclaimer about what? The issue is that I actually don't know what do we want even if we allowed transfers. My point was that currently both solutions are the same, so there is no much reason to choose one over the other right now.

Like, I think one option could be to take a 'snapshot' at the moment the voting starts, and even if you transfer after that, we would use the initial voting power. In this case I would actually change the current code.

But another option could be to use the voting power at the moment of the vote, and lock them (or lock them before, it's the same) after that. If we allow minting during the voting period then we would also have to wait for the end of the voting period to know the total stake... In this case I think the current way is closest, and I don't feel like a disclaimer adds too much information, in this where should we even put it? in the vote cast handler?

@zeegomo
Copy link
Contributor

zeegomo commented Feb 10, 2022

Like, to me it makes no sense that a VotePlan should only see the tokens that were declared before, since the actual voting will be in the future.

Probably something like freezing when voting starts? There was this idea of forbidding transfers when a voteplan is in the voting stage

I'm not sure a disclaimer about what?

Just a disclaimer that when we want to implement token transfers we should think of a solution for this. I was thinking to put that in the relevant part of tokens implementation

@eugene-babichenko
Copy link
Contributor

@zeegomo @Enzoc4 you expressed some good concerns, but I think that we should come back to this when minting and transfers during the blockchain run are actually possible.

@eugene-babichenko
Copy link
Contributor

I think we can also remove rayon from dependencies.

@eugene-babichenko
Copy link
Contributor

Ran benchmarks on my laptop, no significant impact on vote casting performance.

Copy link
Contributor

@eugene-babichenko eugene-babichenko left a comment

Choose a reason for hiding this comment

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

Could you please add a test for zero token votes? Should be good to go after that.

Enzo Cioppettini added 17 commits February 22, 2022 12:57
I think in the future we may want to move it inside again, but for the
time being this simplifies the ledger initialization, since otherwise
the order of MintToken and VotePlan fragments would matter, which is OK
but IMHO a bit fragile.
by using normal borrows, at the expense of making the tests slightly
more verbose
a remnant from the moment I deleted the EncryptedVoteTally cert
Previously this was done only on the `EncryptedVoteTally` certificate.
So currently the committee end/finish date are not used for private
voteplans.

This reintroduces those checks, but moves them to the moment of
decrypting the tally. This is not exactly the same behaviour as before,
since previously we were only verifying that the decrypted shares were
submitted after the committee start date (because otherwise the tally
was None, so there is nothing to decrypt).

Also, add tests for these cases, since we were only testing the public
case.
since the vote/tally date validations should account for it
it's not possible anymore to cast a vote with 0 voting power, and there
is already a test for that, so asserting that it is an error here
wouldn't add that much information, so for now, just test with an empty
tally.
result
.add_vote(Choice::new(u8::try_from(choice).unwrap()), weight)
.map_err(|error| match error {
VoteError::InvalidChoice { options, choice } => {
Copy link
Contributor

Choose a reason for hiding this comment

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

How can this actually happen? We build the tally with the correct number of options ourselves

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, I think it can't, Tally::verify should take care of validating that, I think?

@ecioppettini ecioppettini merged commit 1626503 into master Feb 25, 2022
@ecioppettini ecioppettini deleted the incremental-tally branch February 25, 2022 23:01
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.

4 participants