ADR 0016: Consensus Parameters Change Proposal
Component
Oasis Core
Changelog
- 2022-09-15: Initial version
Status
Proposed
Context
Currently consensus parameters can only be changed with an upgrade governance proposal which is effective but not very efficient. Upgrades require downtime during which binaries need to be updated, nodes restarted and synced, consensus network version has to be increased etc. We would like to avoid this cumbersome procedure and change the parameters of a consensus module as fast and as simple as possible without affecting the performance of the consensus layer.
Decision
Implement governance proposal which changes consensus parameters only.
Implementation
New proposal
A new type of governance proposal named ChangeParametersProposal
should be
added to the consensus layer. The proposal should contain two non-empty fields:
-
the name of the consensus
Module
the changes should be applied to, and, -
a CBOR-encoded document
Changes
describing parameter changes.
// ChangeParametersProposal is a consensus parameters change proposal.
type ChangeParametersProposal struct {
// Module identifies the consensus backend module to which changes should be
// applied.
Module string `json:"module"`
// Changes are consensus parameter changes that should be applied to
// the module.
Changes cbor.RawMessage `json:"changes"`
}
Both fields should be validated before proposal submission to avoid having
invalid proposals with empty fields. A more in-depth validation should be done
by consensus modules during submission to ensure that the encoded Changes
are
complete and well-formed and that there is exactly one module to which changes
will be applied.
// ValidateBasic performs a basic validation on the change parameters proposal.
func (p *ChangeParametersProposal) ValidateBasic() error {
// Validate that both fields are set.
}
The new proposal should be added to the ProposalContent
. The extension should
still allow only one proposal at a time, so we must not forget to update
the code responsible for validation.
type ProposalContent struct {
...
ChangeParameters *ChangeParametersProposal `json:"change_parameters,omitempty"`
}
Parameter changes
Each consensus module should carefully scope which parameters are allowed to be changed. For example, a governance module could allow changing only the gas costs and the voting period, while the staking module would allow changing all parameters.
// ConsensusParameterChanges define allowed governance consensus parameter
// changes.
type ConsensusParameterChanges struct {
// GasCosts are the new gas costs.
GasCosts *transaction.Costs `json:"gas_costs,omitempty"`
// VotingPeriod is the new voting period.
VotingPeriod *beacon.EpochTime `json:"voting_period,omitempty"`
}
To prevent invalid proposals being submitted, ConsensusParameterChanges
should expose validation method which can be used to check if changes are
valid (e.g. changes are not empty, parameters have the right ranges).
// SanityCheck performs a sanity check on the consensus parameters changes.
func (c *ConsensusParameterChanges) SanityCheck() error {
// Validate changes.
}
How changes are executed is up to the module implementation.
// Apply applies changes to the given consensus parameters.
func (c *ConsensusParameterChanges) Apply(params *ConsensusParameters) error {
// Apply changes.
}
Submission
When a new ChangeParametersProposal
is submitted a basic validation is
performed first which checks whether the Module
name and Changes
are set
correctly. Afterwards, a validation message is broadcasted to all modules
requesting them to validate the proposal. Only the module for which Changes
are intended should act and reply to the message, other modules should silently
ignore it. In case no module replies, the proposal is immediately rejected
as not being supported.
The module should carefully examine the proposal, check whether the proposal
is well-formed, Changes
are not empty and deserialize correctly to the
expected format, deserialized parameter changes are valid etc. If all checks
succeed, the module should respond with a confirmation message. Otherwise,
an error describing why proposal is invalid should be returned as a response.
Note: Validation at this stage cannot always be complete as valid parameter values are not necessary independent of each other. If multiple proposals are being executed at the same time, the resulting parameters can be invalid even though validation of each proposal passed. Therefore, another validation is required when the proposal is about to be executed.
Execution
If ChangeParametersProposal
closes as accepted (vote passed), the governance
module will execute the proposal by broadcasting a message containing
the proposal to all modules. Notification can be done using the same message
dispatch mechanism as in the submission phase. Once messages are delivered,
only one module will act and try to apply Changes
.
That module should first fetch current consensus parameters, then apply
proposed Changes
and finally validate the result. Validation of parameters
is necessary as mentioned in the submission phase. If validation succeeds,
the consensus parameters are updated and proposal is marked as passed.
Otherwise, the proposal is marked as failed and the proposed parameter
changes are discarded.
// SanityCheck performs a sanity check on the consensus parameters.
func (p *ConsensusParameters) SanityCheck() error {
// Validate parameters.
}
How to enable the new proposal
Adding a new proposal type is a consensus breaking change. To make it non-breaking we introduce a new governance consensus parameter which disables the new type by default and can be enabled via governance. When disabled, the governance module will treat the new proposal type as invalid, thus not violating the consensus.
type ConsensusParameters struct {
...
// EnableChangeParametersProposal is true iff change parameters proposals are
// allowed.
EnableChangeParametersProposal bool `json:"enable_change_parameters_proposal,omitempty"`
}
Consequences
Positive
-
Agile and zero-downtime consensus parameter changes.
-
Separation of consensus parameter changes and consensus upgrades.
Negative
- Introduction of a new governance consensus parameter which enables new proposals in the upgrade handler. New parameters can always be considered as a minor disadvantage as they usually increase the complexity of the code.
Neutral
References
No references.