6.4 KiB
6.4 KiB
Implementation (1/2)
State
Procedures
Procedures
define the rule according to which votes are run. There can only
be one active procedure at any given time. If governance wants to change a
procedure, either to modify a value or add/remove a parameter, a new procedure
has to be created and the previous one rendered inactive.
type Procedure struct {
VotingPeriod int64 // Length of the voting period. Initial value: 2 weeks
MinDeposit int64 // Minimum deposit for a proposal to enter voting period.
OptionSet []string // Options available to voters. {Yes, No, NoWithVeto, Abstain}
ProposalTypes []string // Types available to submitters. {PlainTextProposal, SoftwareUpgradeProposal}
Threshold rational.Rational // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
Veto rational.Rational // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
MaxDepositPeriod int64 // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
GovernancePenalty int64 // Penalty if validator does not vote
IsActive bool // If true, procedure is active. Only one procedure can have isActive true.
}
Proposals
Proposals
are item to be voted on.
type Proposal struct {
Title string // Title of the proposal
Description string // Description of the proposal
Type string // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
Deposit int64 // Current deposit on this proposal. Initial value is set at InitialDeposit
SubmitBlock int64 // Height of the block where TxGovSubmitProposal was included
VotingStartBlock int64 // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
InitTotalVotingPower int64 // Total voting power when proposal enters voting period (default 0)
InitProcedureNumber int16 // Procedure number of the active procedure when proposal enters voting period (default -1)
Votes map[string]int64 // Votes for each option (Yes, No, NoWithVeto, Abstain)
}
We also introduce a type ValidatorGovInfo
type ValidatorGovInfo struct {
InitVotingPower int64 // Voting power of validator when proposal enters voting period
Minus int64 // Minus of validator, used to compute validator's voting power
}
Stores
Stores are KVStores in the multistore. The key to find the store is the first parameter in the list
Procedures
: a mappingmap[int16]Procedure
of procedures indexed by theirProcedureNumber
. First ever procedure is found at index '1'. Index '0' is reserved for parameterActiveProcedureNumber
which returns the number of the current procedure.Proposals
: A mappingmap[int64]Proposal
of proposals indexed by theirproposalID
Deposits
: A mappingmap[[]byte]int64
of deposits indexed by<proposalID>:<depositorPubKey>
as[]byte
. Given aproposalID
and aPubKey
, returns deposit (nil
ifPubKey
has not deposited on the proposal)Options
: A mappingmap[[]byte]string
of options indexed by<proposalID>:<voterPubKey>:<validatorPubKey>
as[]byte
. Given aproposalID
, aPubKey
and a validator'sPubKey
, returns option chosen by thisPubKey
for this validator (nil
ifPubKey
has not voted under this validator)ValidatorGovInfos
: A mappingmap[[]byte]ValidatorGovInfo
of validator's governance infos indexed by<proposalID>:<validatorGovPubKey>
. Returnsnil
if proposal has not entered voting period or ifPubKey
was not the governance public key of a validator when proposal entered voting period.
For pseudocode purposes, here are the two function we will use to read or write in stores:
load(StoreKey, Key)
: Retrieve item stored at keyKey
in store found at keyStoreKey
in the multistorestore(StoreKey, Key, value)
: Write valueValue
at keyKey
in store found at keyStoreKey
in the multistore
Proposal Processing Queue
Store:
ProposalProcessingQueue
: A queuequeue[proposalID]
containing all theProposalIDs
of proposals that reachedMinDeposit
. Each round, the oldest element ofProposalProcessingQueue
is checked duringBeginBlock
to see ifCurrentBlock == VotingStartBlock + InitProcedure.VotingPeriod
. If it is, then the application checks if validators inInitVotingPowerList
have voted and, if not, appliesGovernancePenalty
. After that proposal is ejected fromProposalProcessingQueue
and the next element of the queue is evaluated. Note that if a proposal is urgent and accepted under the special condition, itsProposalID
must be ejected fromProposalProcessingQueue
.
And the pseudocode for the ProposalProcessingQueue
:
in BeginBlock do
checkProposal() // First call of the recursive function
// Recursive function. First call in BeginBlock
func checkProposal()
if (ProposalProcessingQueue.Peek() == nil)
return
else
proposalID = ProposalProcessingQueue.Peek()
proposal = load(Proposals, proposalID)
initProcedure = load(Procedures, proposal.InitProcedureNumber)
if (proposal.Votes['Yes']/proposal.InitTotalVotingPower >= 2/3)
// proposal was urgent and accepted under the special condition
// no punishment
ProposalProcessingQueue.pop()
checkProposal()
else if (CurrentBlock == proposal.VotingStartBlock + initProcedure.VotingPeriod)
activeProcedureNumber = load(Procedures, '0')
activeProcedure = load(Procedures, activeProcedureNumber)
for each validator in CurrentBondedValidators
validatorGovInfo = load(multistore, ValidatorGovInfos, validator.GovPubKey)
if (validatorGovInfo.InitVotingPower != nil)
// validator was bonded when vote started
validatorOption = load(Options, validator.GovPubKey)
if (validatorOption == nil)
// validator did not vote
slash validator by activeProcedure.GovernancePenalty
ProposalProcessingQueue.pop()
checkProposal()