-
Notifications
You must be signed in to change notification settings - Fork 115
Proposals v2 iteration2 #152
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
Proposals v2 iteration2 #152
Conversation
- add iteration 2 codex and engine modules
- delete codex/Cargo.lock - delete engine/Cargo.lock - update gitignore
bedeho
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
Execution model: The model seems very complex, and its not clear how exactly to naturally use it for different types. I already see that the
proposal_codeis not per say meant to be literal WASM code fragments, and it would be very impractical to expect that sort of heavy setup and handling in a codex module. I think the much simpler approach of passing a dispatchable, like is done indemocracy, is extremely simple and clean. The codex would simply hold the dispatchables it wanted to run, and guard with root origin check. -
We did not actually properly define what the side-effect of the text proposal should be. I think we should not confuse the proposal body, with the main proposition itself, as the body will possibly include a broader rationale, links to referecnes etc. The actual text proposal being voted on should be a standalone parameter I think. The side-effect would be that the proposal text is stored as in some state in the codex engine. In the future perhaps it should be stored somewhere else, but for now we may as well put it there, although I do like the idea of the codex being stateless.
-
As I point out later in the review, actors should not be identified with accounts, but with some configurable role identifier, at least in the engine. In the runtime, we probably want ot use the membership id for the proposer type, and the council member id for the voter type.
-
Just to confirm, is it the case that the codex crate is only consuming anything in the proposals engine crate via crate based dependency management? There is no use of relative paths of modules in the directory tree?
1. Execution modelI'm not sure it is possible. There are no dispatchable extrinsic before runtime compilation. In democracy, proposal associated type defined as and instantiated variant is Where And you cannot have serialized extrinsic call inside of the neighbor extrinsic. I tried to do that in my first iteration. And this exactly the reason why I suggest to create proposal parameters on the frontend - to be able to pack extrinsic call together with parameters and create a proposal like 'democracy' does. Current implementation reintroduces such approach with full control over the code. Not fully understand about WASM. The code can be compiled with no_std and works in runtime. 2. Text proposalFor now, it is no more than the model of the actual proposals. From your comments:
3. Actors and accountsI can introduce a separate entity not connected with account_id, but we still need an account_id to place a stake. Current stakes module depends on Currency which is bound to the AccountId. And what should we do when account_id changes when we have an ongoing proposal? 4. Codex and engine cratesNot sure I understood you properly:
|
- introduce ProposalId type - change BTreeSet to the linked_map
- change VoteExistsByProposalByAccount to proposal_id first key - clear cache on proposal finalization
- rename and refactor tally() method in functional style - introduce internal type FinalizedProposalData
|
On account change during active proposal: |
|
I will implement max active proposals as a new feature during the current iteration. |
|
On 'voter' and 'proposer': for now, I added associated types ProposerId and VoterId and removed account_id dependency. The exact relation between ProposerId and ProposerOrigin (VoterId and VoterOrigin) I will elaborate after Rome - when I connect council and membership modules to the codex. |
bedeho
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
I see that you opt to have mutable variables in a few places. I think we should try to minimize this.
-
Something struck me as I was reviewing this about how we would do slashing: I recall we agreed that there should be a separate quorum and threshold for this action. If this is the case, then we must wait the full voting period before trying to decide whether to accept or slash a proposal, otherwise the engine is sensitive to the accidental order in which people may choose to vote. Please check my logic here.
| pub tally_results: Option<TallyResult<BlockNumber>>, | ||
|
|
||
| /// Votes for the proposal | ||
| pub votes: Vec<Vote<VoterId>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
This is OK, but its starts to become a performance issue if the engine is to be used with a large number of voters, as you will have to load/write back all current votes each time anyone votes. I did not mean for this field to be lifted out of storage, but in practice I think it will be OK, at least for us.
-
Make this a BTreeMap, using the VoterId as key, then we get greater semantic clarity, and runtime guarantees of no double voting, and checks for past voting in O(nlogn) time, rather than O(n).
-
Drop
VoterIdproperty fromVote, it is redundant, and opens up room for bugs, where a vote has different id value than key that maps to it.
--
Updated
Above I assumed that votes had replaced VoteExistsByProposalByVoter, which actually was not needed, but I see now that it has not. Now it is very unclear to me what the purpose is? it seems related to the computation in update_tally_results, which also appears needlessly complicated. I suspect I am missing something, so let me outline what I would have thought was the obvious approach.
-
Proposalhas fields for counting abstentions, approvals and rejections. This is fine, because it is always well defined to have these in life cycle of a proposal. Initial values are set to 0. -
Whenever a vote is submitted, increment the relevant counter. If quorum is reached, then we can update the state suitably.
-
In
on_finalizedcheck all active proposals for whether they may have expired in this block, in which case, update the state suitablly
Is this not sufficient?
| pub status: ProposalStatus, | ||
|
|
||
| /// Tally result for the proposal | ||
| pub tally_results: Option<TallyResult<BlockNumber>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this an optional?
For all states of a proposal, it is well defined to have cumulative counter values set, this type choice gives the impression that there is some set of states
Even the TallyResult type seems to have little value at this point.
Migrating from TallyResults and vote calculation in the end of block to vote calculation on the vote() extrinsic call.
Migrating out from TallyResults
- refactor map-filter-map pattern to the filter_map - add comments
bedeho
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Update Repo Cover Images
Copied PR to the development branch: original PR and commit history can be found here -
mnaamani#2