Revamp gov spec
This commit is contained in:
parent
6bb27c1d99
commit
5735075b05
|
@ -11,32 +11,38 @@ has to be created and the previous one rendered inactive.
|
|||
|
||||
```go
|
||||
|
||||
type VoteType byte
|
||||
type Vote byte
|
||||
|
||||
const (
|
||||
VoteTypeYes = 0x1
|
||||
VoteTypeNo = 0x2
|
||||
VoteTypeNoWithVeto = 0x3
|
||||
VoteTypeAbstain = 0x4
|
||||
VoteYes = 0x1
|
||||
VoteNo = 0x2
|
||||
VoteNoWithVeto = 0x3
|
||||
VoteAbstain = 0x4
|
||||
)
|
||||
|
||||
type ProposalType byte
|
||||
|
||||
const (
|
||||
ProposalTypePlainText = 0x1
|
||||
ProposalTypePlainText = 0x1
|
||||
ProposalTypeSoftwareUpgrade = 0x2
|
||||
)
|
||||
|
||||
type ProposalStatus byte
|
||||
|
||||
const (
|
||||
ProposalStatusOpen = 0x1 // Proposal is submitted. Participants can deposit on it but not vote
|
||||
ProposalStatusActive = 0x2 // MinDeposit is reachhed, participants can vote
|
||||
ProposalStatusAccepted = 0x3 // Proposal has been accepted
|
||||
ProposalStatusRejected = 0x4 // Proposal has been rejected
|
||||
)
|
||||
|
||||
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.
|
||||
VoteTypes []VoteType // Vote types available to voters.
|
||||
ProposalTypes []ProposalType // Proposal types available to submitters.
|
||||
MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period.
|
||||
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
|
||||
GovernancePenalty sdk.Rat // Penalty if validator does not vote
|
||||
|
||||
IsActive bool // If true, procedure is active. Only one procedure can have isActive true.
|
||||
}
|
||||
|
@ -53,18 +59,17 @@ The current active procedure is stored in a global `params` KVStore.
|
|||
}
|
||||
```
|
||||
|
||||
### Votes
|
||||
### ValidatorGovInfo
|
||||
|
||||
This type is used in a temp map when tallying
|
||||
|
||||
```go
|
||||
type Votes struct {
|
||||
Yes int64
|
||||
No int64
|
||||
NoWithVeto int64
|
||||
Abstain int64
|
||||
type ValidatorGovInfo struct {
|
||||
Minus sdk.Rat
|
||||
Vote Vote
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Proposals
|
||||
|
||||
`Proposals` are an item to be voted on.
|
||||
|
@ -77,37 +82,34 @@ type Proposal struct {
|
|||
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||
Deposits []Deposit // List of deposits on the proposal
|
||||
SubmitBlock int64 // Height of the block where TxGovSubmitProposal was included
|
||||
Submitter crypto.Address // Address of the submitter
|
||||
Submitter sdk.Address // Address of the submitter
|
||||
|
||||
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)
|
||||
InitProcedure Procedure // Active Procedure when proposal enters voting period
|
||||
CurrentStatus ProposalStatus // Current status of the proposal
|
||||
|
||||
Votes Votes // Total votes for each option
|
||||
YesVotes sdk.Rat
|
||||
NoVotes sdk.Rat
|
||||
NoWithVetoVotes sdk.Rat
|
||||
AbstainVotes sdk.Rat
|
||||
}
|
||||
```
|
||||
|
||||
We also introduce a type `ValidatorGovInfo`
|
||||
We also mention a method to update the tally for a given proposal:
|
||||
|
||||
```go
|
||||
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
|
||||
}
|
||||
func (proposal Proposal) updateTally(vote byte, amount sdk.Rat)
|
||||
```
|
||||
|
||||
### Stores
|
||||
|
||||
*Stores are KVStores in the multistore. The key to find the store is the first parameter in the list*
|
||||
*Stores are KVStores in the multistore. The key to find the store is the first parameter in the list*`
|
||||
|
||||
We will use one KVStore `Governance` to store two mappings:
|
||||
|
||||
* A mapping from `proposalID` to `Proposal`
|
||||
* A mapping from `proposalID:addresses:address` to `Vote`. This mapping allows us to query all addresses that voted on the proposal along with their vote by doing a range query on `proposalID:addresses`
|
||||
|
||||
* `Proposals: int64 => Proposal` maps `proposalID` to the `Proposal`
|
||||
`proposalID`
|
||||
* `Options: <proposalID | voterAddress | validatorAddress> => VoteType`: maps to the vote of the `voterAddress` for `proposalID` re its delegation to `validatorAddress`.
|
||||
Returns 0x0 If `voterAddress` has not voted under this validator.
|
||||
* `ValidatorGovInfos: <proposalID | validatorAddress> => ValidatorGovInfo`: maps to the gov info for the `validatorAddress` and `proposalID`.
|
||||
Returns `nil` if proposal has not entered voting period or if `address` was not the
|
||||
address 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:
|
||||
|
||||
|
@ -121,16 +123,14 @@ For pseudocode purposes, here are the two function we will use to read or write
|
|||
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest
|
||||
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if
|
||||
`CurrentBlock == VotingStartBlock + InitProcedure.VotingPeriod`. If it is,
|
||||
then the application checks if validators in `InitVotingPowerList` have voted
|
||||
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted
|
||||
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded.
|
||||
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
|
||||
Note that if a proposal is accepted under the special condition,
|
||||
its `ProposalID` must be ejected from `ProposalProcessingQueue`.
|
||||
|
||||
And the pseudocode for the `ProposalProcessingQueue`:
|
||||
|
||||
```go
|
||||
in BeginBlock do
|
||||
in EndBlock do
|
||||
|
||||
checkProposal() // First call of the recursive function
|
||||
|
||||
|
@ -141,58 +141,55 @@ And the pseudocode for the `ProposalProcessingQueue`:
|
|||
if (proposalID == nil)
|
||||
return
|
||||
|
||||
proposal = load(Proposals, proposalID)
|
||||
proposal = load(Governance, proposalID)
|
||||
|
||||
if (proposal.Votes.YesVotes/proposal.InitTotalVotingPower > 2/3)
|
||||
if (CurrentBlock == proposal.VotingStartBlock + proposal.Procedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive)
|
||||
|
||||
// proposal accepted early by super-majority
|
||||
// no punishments; refund deposits
|
||||
// End of voting period, tally
|
||||
|
||||
ProposalProcessingQueue.pop()
|
||||
|
||||
var newDeposits []Deposits
|
||||
validators = stakeKeeper.getAllValidators()
|
||||
tmpValMap := map(sdk.Address)ValidatorGovInfo
|
||||
|
||||
// XXX: why do we need to reset deposits? cant we just clear it ?
|
||||
for each (amount, depositer) in proposal.Deposits
|
||||
newDeposits.append[{0, depositer}]
|
||||
depositer.AtomBalance += amount
|
||||
// Initiate mapping at 0. Validators that remain at 0 at the end of tally will be punished
|
||||
for each validator in validators
|
||||
tmpValMap(validator).Minus = 0
|
||||
|
||||
voterIterator = rangeQuery(Governance, <proposalID|addresses>) //return all the addresses that voted on the proposal
|
||||
|
||||
proposal.Deposits = newDeposits
|
||||
store(Proposals, proposalID, proposal)
|
||||
// Tally
|
||||
for each (voterAddress, vote) in voterIterator
|
||||
delegations = stakeKeeper.getDelegations(voterAddress) // get all delegations for current voter
|
||||
|
||||
checkProposal()
|
||||
for each delegation in delegations
|
||||
tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares
|
||||
proposal.updateTally(vote, delegation.Shares)
|
||||
|
||||
else if (CurrentBlock == proposal.VotingStartBlock + proposal.Procedure.VotingPeriod)
|
||||
_, isVal = stakeKeeper.getValidator(voterAddress)
|
||||
if (isVal)
|
||||
tmpValMap(voterAddress).Vote = vote
|
||||
|
||||
ProposalProcessingQueue.pop()
|
||||
activeProcedure = load(params, 'ActiveProcedure')
|
||||
|
||||
for each validator in CurrentBondedValidators
|
||||
validatorGovInfo = load(ValidatorGovInfos, <proposalID | validator.Address>)
|
||||
|
||||
if (validatorGovInfo.InitVotingPower != nil)
|
||||
// validator was bonded when vote started
|
||||
|
||||
validatorOption = load(Options, <proposalID | validator.Address>)
|
||||
if (validatorOption == nil)
|
||||
// validator did not vote
|
||||
slash validator by activeProcedure.GovernancePenalty
|
||||
|
||||
|
||||
totalNonAbstain = proposal.Votes.YesVotes + proposal.Votes.NoVotes + proposal.Votes.NoWithVetoVotes
|
||||
if( proposal.Votes.YesVotes/totalNonAbstain > 0.5 AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < 1/3)
|
||||
// Slash validators that did not vote, or update tally if they voted
|
||||
for each validator in validators
|
||||
if (!tmpValMap(validator).HasVoted)
|
||||
slash validator by proposal.Procedure.GovernancePenalty
|
||||
else
|
||||
proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus))
|
||||
|
||||
// Check if proposal is accepted or rejected
|
||||
totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes
|
||||
if (proposal.Votes.YesVotes/totalNonAbstain > proposal.InitProcedure.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < proposal.InitProcedure.Veto)
|
||||
// proposal was accepted at the end of the voting period
|
||||
// refund deposits (non-voters already punished)
|
||||
|
||||
var newDeposits []Deposits
|
||||
|
||||
proposal.CurrentStatus = ProposalStatusAccepted
|
||||
for each (amount, depositer) in proposal.Deposits
|
||||
newDeposits.append[{0, depositer}]
|
||||
depositer.AtomBalance += amount
|
||||
|
||||
proposal.Deposits = newDeposits
|
||||
store(Proposals, proposalID, proposal)
|
||||
else
|
||||
// proposal was rejected
|
||||
proposal.CurrentStatus = ProposalStatusRejected
|
||||
|
||||
checkProposal()
|
||||
store(Governance, proposalID, proposal)
|
||||
checkProposal()
|
||||
```
|
||||
|
|
|
@ -12,7 +12,7 @@ type TxGovSubmitProposal struct {
|
|||
Title string // Title of the proposal
|
||||
Description string // Description of the proposal
|
||||
Type ProposalType // Type of proposal
|
||||
InitialDeposit int64 // Initial deposit paid by sender. Must be strictly positive.
|
||||
InitialDeposit sdk.Coins // Initial deposit paid by sender. Must be strictly positive.
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -22,8 +22,7 @@ type TxGovSubmitProposal struct {
|
|||
* Initialise `Proposals` attributes
|
||||
* Decrease balance of sender by `InitialDeposit`
|
||||
* If `MinDeposit` is reached:
|
||||
* Push `proposalID` in `ProposalProcessingQueueEnd`
|
||||
* Store each validator's voting power in `ValidatorGovInfos`
|
||||
* Push `proposalID` in `ProposalProcessingQueue`
|
||||
|
||||
A `TxGovSubmitProposal` transaction can be handled according to the following
|
||||
pseudocode.
|
||||
|
@ -34,16 +33,16 @@ pseudocode.
|
|||
|
||||
upon receiving txGovSubmitProposal from sender do
|
||||
|
||||
if !correctlyFormatted(txGovSubmitProposal) then
|
||||
if !correctlyFormatted(txGovSubmitProposal)
|
||||
// check if proposal is correctly formatted. Includes fee payment.
|
||||
throw
|
||||
|
||||
initialDeposit = txGovSubmitProposal.InitialDeposit
|
||||
if (initialDeposit <= 0) OR (sender.AtomBalance < initialDeposit) then
|
||||
if (initialDeposit.Atoms <= 0) OR (sender.AtomBalance < initialDeposit.Atoms)
|
||||
// InitialDeposit is negative or null OR sender has insufficient funds
|
||||
throw
|
||||
|
||||
sender.AtomBalance -= initialDeposit
|
||||
sender.AtomBalance -= initialDeposit.Atoms
|
||||
|
||||
proposalID = generate new proposalID
|
||||
proposal = NewProposal()
|
||||
|
@ -55,35 +54,25 @@ upon receiving txGovSubmitProposal from sender do
|
|||
proposal.SubmitBlock = CurrentBlock
|
||||
proposal.Deposits.append({initialDeposit, sender})
|
||||
proposal.Submitter = sender
|
||||
proposal.Votes.Yes = 0
|
||||
proposal.Votes.No = 0
|
||||
proposal.Votes.NoWithVeto = 0
|
||||
proposal.Votes.Abstain = 0
|
||||
proposal.YesVotes = 0
|
||||
proposal.NoVotes = 0
|
||||
proposal.NoWithVetoVotes = 0
|
||||
proposal.AbstainVotes = 0
|
||||
|
||||
activeProcedure = load(params, 'ActiveProcedure')
|
||||
|
||||
if (initialDeposit < activeProcedure.MinDeposit) then
|
||||
if (initialDeposit < activeProcedure.MinDeposit)
|
||||
// MinDeposit is not reached
|
||||
|
||||
proposal.CurrentStatus = ProposalStatusOpen
|
||||
proposal.VotingStartBlock = -1
|
||||
proposal.InitTotalVotingPower = 0
|
||||
|
||||
else
|
||||
// MinDeposit is reached
|
||||
|
||||
proposal.CurrentStatus = ProposalStatusActive
|
||||
proposal.VotingStartBlock = CurrentBlock
|
||||
proposal.InitTotalVotingPower = TotalVotingPower
|
||||
proposal.InitProcedure = activeProcedure
|
||||
|
||||
for each validator in CurrentBondedValidators
|
||||
// Store voting power of each bonded validator
|
||||
|
||||
validatorGovInfo = new ValidatorGovInfo
|
||||
validatorGovInfo.InitVotingPower = validator.VotingPower
|
||||
validatorGovInfo.Minus = 0
|
||||
|
||||
store(ValidatorGovInfos, <proposalID | validator.Address>, validatorGovInfo)
|
||||
|
||||
ProposalProcessingQueue.push(proposalID)
|
||||
|
||||
store(Proposals, proposalID, proposal) // Store proposal in Proposals mapping
|
||||
|
@ -98,8 +87,8 @@ Once a proposal is submitted, if
|
|||
|
||||
```go
|
||||
type TxGovDeposit struct {
|
||||
ProposalID int64 // ID of the proposal
|
||||
Deposit int64 // Number of Atoms to add to the proposal's deposit
|
||||
ProposalID int64 // ID of the proposal
|
||||
Deposit sdk.Coins // Number of Atoms to add to the proposal's deposit
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -109,7 +98,6 @@ type TxGovDeposit struct {
|
|||
* Increase `proposal.TotalDeposit` by sender's `deposit`
|
||||
* If `MinDeposit` is reached:
|
||||
* Push `proposalID` in `ProposalProcessingQueueEnd`
|
||||
* Store each validator's voting power in `ValidatorGovInfos`
|
||||
|
||||
A `TxGovDeposit` transaction has to go through a number of checks to be valid.
|
||||
These checks are outlined in the following pseudocode.
|
||||
|
@ -121,57 +109,40 @@ These checks are outlined in the following pseudocode.
|
|||
upon receiving txGovDeposit from sender do
|
||||
// check if proposal is correctly formatted. Includes fee payment.
|
||||
|
||||
if !correctlyFormatted(txGovDeposit) then
|
||||
if !correctlyFormatted(txGovDeposit)
|
||||
throw
|
||||
|
||||
proposal = load(Proposals, txGovDeposit.ProposalID)
|
||||
|
||||
if (proposal == nil) then
|
||||
if (proposal == nil)
|
||||
// There is no proposal for this proposalID
|
||||
throw
|
||||
|
||||
if (txGovDeposit.Deposit <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit)
|
||||
// deposit is negative or null OR sender has insufficient funds
|
||||
throw
|
||||
|
||||
|
||||
activeProcedure = load(params, 'ActiveProcedure')
|
||||
|
||||
if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.TotalDeposit >= activeProcedure.MinDeposit) OR (CurrentBlock >= proposal.SubmitBlock + activeProcedure.MaxDepositPeriod)
|
||||
// deposit is negative or null
|
||||
// OR sender has insufficient funds
|
||||
// OR minDeposit has already been reached
|
||||
// OR Maximum deposit period reached
|
||||
|
||||
if (proposal.TotalDeposit >= activeProcedure.MinDeposit) then
|
||||
// MinDeposit was reached
|
||||
// TODO: shouldnt we do something here ?
|
||||
throw
|
||||
|
||||
else
|
||||
if (CurrentBlock >= proposal.SubmitBlock + activeProcedure.MaxDepositPeriod) then
|
||||
// Maximum deposit period reached
|
||||
throw
|
||||
// sender can deposit
|
||||
sender.AtomBalance -= txGovDeposit.Deposit.Atoms
|
||||
|
||||
proposal.Deposits.append({txGovVote.Deposit, sender})
|
||||
proposal.TotalDeposit.Plus(txGovDeposit.Deposit)
|
||||
|
||||
if (proposal.TotalDeposit >= activeProcedure.MinDeposit)
|
||||
// MinDeposit is reached, vote opens
|
||||
|
||||
// sender can deposit
|
||||
|
||||
sender.AtomBalance -= txGovDeposit.Deposit
|
||||
proposal.VotingStartBlock = CurrentBlock
|
||||
proposal.CurrentStatus = ProposalStatusActive
|
||||
proposal.InitProcedure = activeProcedure
|
||||
ProposalProcessingQueue.push(txGovDeposit.ProposalID)
|
||||
|
||||
proposal.Deposits.append({txGovVote.Deposit, sender})
|
||||
proposal.TotalDeposit += txGovDeposit.Deposit
|
||||
|
||||
if (proposal.TotalDeposit >= activeProcedure.MinDeposit) then
|
||||
// MinDeposit is reached, vote opens
|
||||
|
||||
proposal.VotingStartBlock = CurrentBlock
|
||||
proposal.InitTotalVotingPower = TotalVotingPower
|
||||
proposal.InitProcedure = activeProcedure
|
||||
|
||||
for each validator in CurrentBondedValidators
|
||||
// Store voting power of each bonded validator
|
||||
|
||||
validatorGovInfo = NewValidatorGovInfo()
|
||||
validatorGovInfo.InitVotingPower = validator.VotingPower
|
||||
validatorGovInfo.Minus = 0
|
||||
|
||||
store(ValidatorGovInfos, <proposalID | validator.Address>, validatorGovInfo)
|
||||
|
||||
ProposalProcessingQueue.push(txGovDeposit.ProposalID)
|
||||
|
||||
store(Proposals, txGovVote.ProposalID, proposal)
|
||||
store(Proposals, txGovVote.ProposalID, proposal)
|
||||
```
|
||||
|
||||
### Vote
|
||||
|
@ -183,26 +154,14 @@ vote on the proposal.
|
|||
```go
|
||||
type TxGovVote struct {
|
||||
ProposalID int64 // proposalID of the proposal
|
||||
Option string // option from OptionSet chosen by the voter
|
||||
ValidatorAddress crypto.address // Address of the validator voter wants to tie its vote to
|
||||
Vote byte // option from OptionSet chosen by the voter
|
||||
}
|
||||
```
|
||||
|
||||
**State modifications:**
|
||||
* If sender is not a validator and validator has not voted, initialize or
|
||||
increase minus of validator by sender's `voting power`
|
||||
* If sender is not a validator and validator has voted, decrease
|
||||
votes of `validatorOption` by sender's `voting power`
|
||||
* If sender is not a validator, increase votes of `txGovVote.Option`
|
||||
by sender's `voting power`
|
||||
* If sender is a validator, increase votes of `txGovVote.Option` by
|
||||
validator's `InitVotingPower - minus` (`minus` can be equal to 0)
|
||||
* Record `Vote` of sender
|
||||
|
||||
Votes need to be tied to a validator in order to compute validator's voting
|
||||
power. If a delegator is bonded to multiple validators, it will have to send
|
||||
one transaction per validator (the UI should facilitate this so that multiple
|
||||
transactions can be sent in one "vote flow"). If the sender is the validator
|
||||
itself, then it will input its own address as `ValidatorAddress`
|
||||
*Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker*
|
||||
|
||||
Next is a pseudocode proposal of the way `TxGovVote` transactions are
|
||||
handled:
|
||||
|
@ -214,91 +173,24 @@ handled:
|
|||
upon receiving txGovVote from sender do
|
||||
// check if proposal is correctly formatted. Includes fee payment.
|
||||
|
||||
if !correctlyFormatted(txGovDeposit) then
|
||||
if !correctlyFormatted(txGovDeposit)
|
||||
throw
|
||||
|
||||
proposal = load(Proposals, txGovDeposit.ProposalID)
|
||||
|
||||
if (proposal == nil) then
|
||||
if (proposal == nil)
|
||||
// There is no proposal for this proposalID
|
||||
throw
|
||||
|
||||
validator = load(CurrentValidators, txGovVote.ValidatorAddress)
|
||||
|
||||
if (proposal.VotingStartBlock >= 0) AND
|
||||
(CurrentBlock <= proposal.VotingStartBlock + proposal.InitProcedure.VotingPeriod)
|
||||
|
||||
// Sender can vote if
|
||||
// Vote has started AND if
|
||||
// Vote had notended
|
||||
|
||||
store(Governance, <txGovVote.ProposalID|addresses|sender>, txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end.
|
||||
|
||||
|
||||
if !proposal.InitProcedure.OptionSet.includes(txGovVote.Option) OR
|
||||
(validator == nil) then
|
||||
|
||||
// Throws if
|
||||
// Option is not in Option Set of procedure that was active when vote opened OR if
|
||||
// ValidatorAddress is not the address of a current validator
|
||||
|
||||
throw
|
||||
|
||||
option = load(Options, <txGovVote.ProposalID>:<sender>:<txGovVote.ValidatorAddress>)
|
||||
|
||||
if (option != nil)
|
||||
// sender has already voted with the Atoms bonded to ValidatorAddress
|
||||
throw
|
||||
|
||||
if (proposal.VotingStartBlock < 0) OR
|
||||
(CurrentBlock > proposal.VotingStartBlock + proposal.InitProcedure.VotingPeriod) OR
|
||||
(proposal.VotingStartBlock < lastBondingBlock(sender, txGovVote.ValidatorAddress) OR
|
||||
(proposal.VotingStartBlock < lastUnbondingBlock(sender, txGovVote.Address) OR
|
||||
(proposal.Votes.YesVotes/proposal.InitTotalVotingPower >= 2/3) then
|
||||
|
||||
// Throws if
|
||||
// Vote has not started OR if
|
||||
// Vote had ended OR if
|
||||
// sender bonded Atoms to ValidatorAddress after start of vote OR if
|
||||
// sender unbonded Atoms from ValidatorAddress after start of vote OR if
|
||||
// special condition is met, i.e. proposal is accepted and closed
|
||||
|
||||
throw
|
||||
|
||||
validatorGovInfo = load(ValidatorGovInfos, <txGovVote.ProposalID>:<validator.ValidatorAddress>)
|
||||
|
||||
if (validatorGovInfo == nil)
|
||||
// validator became validator after proposal entered voting period
|
||||
throw
|
||||
|
||||
// sender can vote, check if sender == validator and store sender's option in Options
|
||||
|
||||
store(Options, <txGovVote.ProposalID>:<sender>:<txGovVote.ValidatorAddress>, txGovVote.Option)
|
||||
|
||||
if (sender != validator.address)
|
||||
// Here, sender is not the Address of the validator whose Address is txGovVote.ValidatorAddress
|
||||
|
||||
if sender does not have bonded Atoms to txGovVote.ValidatorAddress then
|
||||
// check in Staking module
|
||||
throw
|
||||
|
||||
validatorOption = load(Options, <txGovVote.ProposalID>:<sender>:<txGovVote.ValidatorAddress>)
|
||||
|
||||
if (validatorOption == nil)
|
||||
// Validator has not voted already
|
||||
|
||||
validatorGovInfo.Minus += sender.bondedAmounTo(txGovVote.ValidatorAddress)
|
||||
store(ValidatorGovInfos, <txGovVote.ProposalID>:<validator.ValidatorAddress>, validatorGovInfo)
|
||||
|
||||
else
|
||||
// Validator has already voted
|
||||
// Reduce votes of option chosen by validator by sender's bonded Amount
|
||||
|
||||
proposal.Votes.validatorOption -= sender.bondedAmountTo(txGovVote.ValidatorAddress)
|
||||
|
||||
// increase votes of option chosen by sender by bonded Amount
|
||||
|
||||
senderOption = txGovVote.Option
|
||||
propoal.Votes.senderOption -= sender.bondedAmountTo(txGovVote.ValidatorAddress)
|
||||
|
||||
store(Proposals, txGovVote.ProposalID, proposal)
|
||||
|
||||
|
||||
else
|
||||
// sender is the address of the validator whose main Address is txGovVote.ValidatorAddress
|
||||
// i.e. sender == validator
|
||||
|
||||
proposal.Votes.validatorOption += (validatorGovInfo.InitVotingPower - validatorGovInfo.Minus)
|
||||
|
||||
store(Proposals, txGovVote.ProposalID, proposal)
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue