-
Notifications
You must be signed in to change notification settings - Fork 115
Proposals system. Version 2. Iteration6 #194
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 system. Version 2. Iteration6 #194
Conversation
Add ‘max number of threads by same author in a row’ limit
- add ActorOriginValidator trait - update create_thread() with ThreadAuthorOriginValidator
- upgrade add_post() and update_post() with PostAuthorOriginValidator
- add ThreadCreated, PostCreated, PostUpdated events - add tests - move error messages to the separate module
- add ThreadAuthorId param stub - update mock and tests
Migrated to the WasmBuilder.
…g_cleanup Runtime warning cleanup
- delete proposals workspace - update proposals Cargo.toml’s (engine, codex, discussions) - update global workspace
Add #![allow(array_into_iter)] to runtime/lib.rs srml_staking_reward_curve::build! - substrate macro produces a warning. We need to remove this attribute after post-Rome substrate upgrade.
- convert PostAuthorId to the MemberId in proposal discussion module - change validate_actor_origin() to the ensure_actor_origin() - convert ensure_actor_origin() from bool to Result<(), &’static str>
- move actor_origin_validator trait and implementation into the membership crate - add actor_validation to the engine
- add governance dependency - implement ActorOriginValidator for council voting (CouncilOriginValidator) - change mocks - add tests
- implement VotersParameters::total_voters_count() using council size for proposals engine module - cargo fmt
- change ensure_actor_origin() signature - remove error - introduce built-in error messages
- create new StakeData structure with stake_id field in the engine module - add souce_account_id field to the stake_data - change stake_id field to the StakeData in the Proposal structure
- add StakingEventHandler for engine module - add storage map StakesProposals - add refund_proposal_stake() callback
- delete proposals from the governance module - clear the runtime from link to proposals version 1
- migrate discussions - create codex errors conversion helpers - update tests
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.
-
This review goes beyond the diff in the PR, because it was frankly really hard to just follow that, given how long ago I looked at this, and also because prior reviews did not go that in depth on different extrinsics, as we were just getting started.
-
In general, types with postfix "data" indicate a sloppy name or bad type, unless they literally represent unstructured data without any internal meaning. There is at least
StakeDataandFinalizationDatain this iteration. For the former, I think it should not exist (as you will see in the review), and for the latter, see next section. -
Question: Is there any reason to check origin on pure
Modulemethods? doesnet seem to make sense? the calling code will perform the origin check. Perhaps this is why we have the akward double origin thing... its not needed?
Engine
-
When a council changed, I think we agreed to reset all the current votes and reset the finalization deadline. That is currently not implemented, right?
-
execute_proposalappears to have a bug, as it unconditionally removes fromPendingExecutionProposalIds, even if the first guard rejects the proposal. Moreover, the routine does not check that the proposal actually exists, yet it does check that it has the right state. This seems a bit inconsistent. I think that if its going to make an assumption without checking, it needs not check for any even weaker assumptions. Moreover, its also a bit akward that it is rechecking whether the given proposal is finalized, despite the caller already having done this check in computationget_approved_proposal_with_expired_grace_period_ids, that should be avoidable in the same code path by picking the right representations. Have a look, it may not be worth changing so much, but I wanted to draw your attention to it. -
For
FinalizationData- I think there is a crisper name could be
FinalizedProposalStatus - The field
finalization_errorshould reflect that this is specifically the serialized error associated with unstaking. When reading it I first thought this is what held the error related to execution as well, but that is indeed separate, so name should be sharpened. Also, something needs to be done to very clearly signal that this is no normal error, but indeed the broken invariant error. At the very least the comment must say so, but perhaps also the name, e.g.encoded_unstaking_error_due_to_broken_runtime. Its a bit long, but the length helps to grab the attention to how distinct this field is. - Lets drop
finalized_at. Its purely archival, and so query node should hold it, and it's not even clear that we will, in the end, hold the entire proposal itself after it is executed.
- I think there is a crisper name could be
-
Did we not decide that, for the time being, we will not store broken invariant errors in storage, simply for the benefit of archiving error messages. We would use either console logging or something else to capture them? Unfortunately, we should have written down what we decided. At any rate, this sort of storing of errors seems to do little if anything of increasing safety or blocking further state corruption, which are the strong reasons for handling broken runtimes in some way.
-
The only reason we have
ActiveProposalIdsis so that more effectively iterate only the proposals that are active when trying to finalize. This also why we need to limit how many can be active at once.This is as intended, but I want to explore an alternative. If you think its an improvement, lets make an issue out of it and have someone work on it at a later time:
We drop
ActiveProposalIdsand the limit on the number of active proposals, as well as any iteration inon_finalized. Instead, a new mapfinalize_at_block: T::BlockNumber => T::ProposalIdis introduced, and a mapping is introduced whenever a proposal is created. This map is checked everyon_finalized, but there is no iteration, you just check for the specific block you are on. There is an implicit limit that only one proposal can be finalized per block, and that is enforced upon proposal creation.It seems this is both safer, as there is no enumeration and iteration, and we drop one parameter value, and we have no limit on the number of simultaneous proposals in flight.
What do you think?
The same would apply to
PendingExecutionProposalIds. -
Seems like this storage map should be dropped, and instead just hold the value as a field in the
struct Proposal.pub ProposalCode get(fn proposal_codes): map T::ProposalId => Vec<u8>;
Codex
Looks great!
Discussion system
Looks great!
| /// Created stake id for the proposal | ||
| pub stake_id: Option<StakeId>, | ||
| /// Stake data for the proposal | ||
| pub stake_data: Option<StakeData<StakeId, AccountId>>, |
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 state variable is basically set if there is staking, and unset when there is finalization in finalize_proposal. This is a rational policy. However, the representation is not 100% safe: we still allow the representation of illegal states, even though we need not. In particular stake_data = Some(x) when status = ProposalStatus::Finalized(y).
- This particular principle of using the type system fully is something I think we cannot compromise, so I think we must change this.
- An alternative "workaround" is to never clear
stake_data, then the representation is fully safe. However, I think this approach does not make sense, as we should in general not use state just for archival purposes. The query system will hold all such information if it's needed. For even things likeFinalizationData::finalized_atneed not exist for the same reason.
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.
Yes, we were going to decide whether to remove stake information from the system on proposal finalization.
| >; | ||
|
|
||
| // Simplification of the 'Proposal' type | ||
| type ProposalObject<T> = Proposal< |
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.
ProposalObjectis not a great name. I think the full workaround is to just haveProposalacceptT, rather than unbundled set of types. The general syntatic overhead is nicer. Personally I have mixed both approaches, but in the end I think just takingTis easier on the eyes.
Here is a convention about it from a while back #36 (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.
Agree, will change to 'ProposalOf' similar with BalanceOf
| system::Trait | ||
| + timestamp::Trait | ||
| + stake::Trait | ||
| + membership::members::Trait |
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.
Let's not require full membership and governance module configuration trait Trait, just to get constraints for Ids. This means any user of the engine must involve these traits. Let just use normal integer id constraints.
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.
Governance module dependency is needed to create CouncilManager. We can move it to the council module, but then the governance module will be dependent upon the membership module.
| type MaxActiveProposalLimit: Get<u32>; | ||
|
|
||
| /// Proposals executable code. Can be instantiated by external module Call enum members. | ||
| type ProposalCode: Parameter + Dispatchable<Origin = Self::Origin> + Default; |
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.
The constraint here captures some runtime dispatchable + a set of parameters for used in a call to it. Is that orrect? If so, perhaps we can find a better name than this, as it alludes to raw code being involved, which threw me a bit off when reading the implementation. How about DispatchableCall ? Likewise when you look at create_proposal rather than saying proposal_code: Vec<u8>, which really makes it seem like perhaps this is raw byte code. This could be encoded_dispatchable_call: Vec<u8>, etc. for other places.
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.
Ok.
We didn't discuss it yet. I will add it to my backlog. |
|
We need Also, we moved |
Proposal veto and cancellation cannot be predicted |
We have a rule with the exact opposite: And the rule, in general, makes sense, because, for example, WASM code can be 'heavy'. And proposal object is encoded and decoded multiple times during its lifetime. |
|
Work to be done using this issue |
Move CouncilManager, MemberhipOriginValidator to the runtime. Issue link: Joystream#226
Fix tests for moved CouncilManager and MemberhipOriginValidator in the runtime proposal integration
- move StakingEventsHandler to the runtime integration folder from the proposals engine module.
- rename StakeData to the ActiveStake - rename ProposalCode to the DispatchableCallCode - rename ProposalObject to the ProposalOf
Add calls: - add ensure_create_proposal_parameters_are_valid() call - add ensure_can_create_thread() call to the create_proposals_* extrinsics in the codex
- move memberhip validation to the codex proposal creation extrinsics - remove actor validation in the create_proposal (engine) and create_thread(discussion) API methods.
- remove root_account_id from valid member origin
- rename it to the encoded_unstaking_error_due_to_broken_runtime
- move proposal stake data from the proposal to its statuses
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.
Great job!
Features
ActorOriginValidatorin the common module for future integration with the membership and council modulesActorOriginValidatorimplementation -MembershipOriginValidator)ActorOriginValidatorandVotersParametersimplementations with tests -CouncilManagerMembershipValidatorandCouncilManagerStakingEventsHandlerintegration with theContentWorkingGroupStakingEventHandlerset_countil()is public now for testing purposes (it's guarded byensure_root()))Related issues
Iteration 5 features (was skipped)
EnsureOriginto theActorOriginValidatormodel (was rewritten during the 6th iteration )