Skip to content

Commit fe695b8

Browse files
fedekunzejackzampolin
authored andcommitted
Merge PR #4460: Gov Keys and Iterators
* refactor gov keys * iterators and renamings * invert queue key order * changelog * fix tests * update alias.go * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * rename keys * rename functions * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * address Aleks' comments * fix test * address Karoly's comments
1 parent 3962b3c commit fe695b8

File tree

18 files changed

+791
-536
lines changed

18 files changed

+791
-536
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#4437 Replace governance module store keys to use `[]byte` instead of `string`.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#4439 Implement governance module iterators.

x/gov/alias.go

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -48,52 +48,61 @@ const (
4848

4949
var (
5050
// functions aliases
51-
RegisterCodec = types.RegisterCodec
52-
RegisterProposalTypeCodec = types.RegisterProposalTypeCodec
53-
ValidateAbstract = types.ValidateAbstract
54-
ErrUnknownProposal = types.ErrUnknownProposal
55-
ErrInactiveProposal = types.ErrInactiveProposal
56-
ErrAlreadyActiveProposal = types.ErrAlreadyActiveProposal
57-
ErrAlreadyFinishedProposal = types.ErrAlreadyFinishedProposal
58-
ErrAddressNotStaked = types.ErrAddressNotStaked
59-
ErrInvalidProposalContent = types.ErrInvalidProposalContent
60-
ErrInvalidProposalType = types.ErrInvalidProposalType
61-
ErrInvalidVote = types.ErrInvalidVote
62-
ErrInvalidGenesis = types.ErrInvalidGenesis
63-
ErrNoProposalHandlerExists = types.ErrNoProposalHandlerExists
64-
KeyProposal = types.KeyProposal
65-
KeyDeposit = types.KeyDeposit
66-
KeyVote = types.KeyVote
67-
KeyDepositsSubspace = types.KeyDepositsSubspace
68-
KeyVotesSubspace = types.KeyVotesSubspace
69-
PrefixActiveProposalQueueTime = types.PrefixActiveProposalQueueTime
70-
KeyActiveProposalQueueProposal = types.KeyActiveProposalQueueProposal
71-
PrefixInactiveProposalQueueTime = types.PrefixInactiveProposalQueueTime
72-
KeyInactiveProposalQueueProposal = types.KeyInactiveProposalQueueProposal
73-
NewMsgSubmitProposal = types.NewMsgSubmitProposal
74-
NewMsgDeposit = types.NewMsgDeposit
75-
NewMsgVote = types.NewMsgVote
76-
NewProposal = types.NewProposal
77-
ProposalStatusFromString = types.ProposalStatusFromString
78-
ValidProposalStatus = types.ValidProposalStatus
79-
NewTallyResult = types.NewTallyResult
80-
NewTallyResultFromMap = types.NewTallyResultFromMap
81-
EmptyTallyResult = types.EmptyTallyResult
82-
NewTextProposal = types.NewTextProposal
83-
NewSoftwareUpgradeProposal = types.NewSoftwareUpgradeProposal
84-
RegisterProposalType = types.RegisterProposalType
85-
ContentFromProposalType = types.ContentFromProposalType
86-
IsValidProposalType = types.IsValidProposalType
87-
ProposalHandler = types.ProposalHandler
88-
VoteOptionFromString = types.VoteOptionFromString
89-
ValidVoteOption = types.ValidVoteOption
51+
RegisterCodec = types.RegisterCodec
52+
RegisterProposalTypeCodec = types.RegisterProposalTypeCodec
53+
ValidateAbstract = types.ValidateAbstract
54+
NewDeposit = types.NewDeposit
55+
ErrUnknownProposal = types.ErrUnknownProposal
56+
ErrInactiveProposal = types.ErrInactiveProposal
57+
ErrAlreadyActiveProposal = types.ErrAlreadyActiveProposal
58+
ErrAlreadyFinishedProposal = types.ErrAlreadyFinishedProposal
59+
ErrAddressNotStaked = types.ErrAddressNotStaked
60+
ErrInvalidProposalContent = types.ErrInvalidProposalContent
61+
ErrInvalidProposalType = types.ErrInvalidProposalType
62+
ErrInvalidVote = types.ErrInvalidVote
63+
ErrInvalidGenesis = types.ErrInvalidGenesis
64+
ErrNoProposalHandlerExists = types.ErrNoProposalHandlerExists
65+
ProposalKey = types.ProposalKey
66+
ActiveProposalByTimeKey = types.ActiveProposalByTimeKey
67+
ActiveProposalQueueKey = types.ActiveProposalQueueKey
68+
InactiveProposalByTimeKey = types.InactiveProposalByTimeKey
69+
InactiveProposalQueueKey = types.InactiveProposalQueueKey
70+
DepositsKey = types.DepositsKey
71+
DepositKey = types.DepositKey
72+
VotesKey = types.VotesKey
73+
VoteKey = types.VoteKey
74+
SplitProposalKey = types.SplitProposalKey
75+
SplitActiveProposalQueueKey = types.SplitActiveProposalQueueKey
76+
SplitInactiveProposalQueueKey = types.SplitInactiveProposalQueueKey
77+
SplitKeyDeposit = types.SplitKeyDeposit
78+
SplitKeyVote = types.SplitKeyVote
79+
NewMsgSubmitProposal = types.NewMsgSubmitProposal
80+
NewMsgDeposit = types.NewMsgDeposit
81+
NewMsgVote = types.NewMsgVote
82+
NewProposal = types.NewProposal
83+
ProposalStatusFromString = types.ProposalStatusFromString
84+
ValidProposalStatus = types.ValidProposalStatus
85+
NewTallyResult = types.NewTallyResult
86+
NewTallyResultFromMap = types.NewTallyResultFromMap
87+
EmptyTallyResult = types.EmptyTallyResult
88+
NewTextProposal = types.NewTextProposal
89+
NewSoftwareUpgradeProposal = types.NewSoftwareUpgradeProposal
90+
RegisterProposalType = types.RegisterProposalType
91+
ContentFromProposalType = types.ContentFromProposalType
92+
IsValidProposalType = types.IsValidProposalType
93+
ProposalHandler = types.ProposalHandler
94+
NewVote = types.NewVote
95+
VoteOptionFromString = types.VoteOptionFromString
96+
ValidVoteOption = types.ValidVoteOption
9097

9198
// variable aliases
9299
ModuleCdc = types.ModuleCdc
93-
KeyDelimiter = types.KeyDelimiter
94-
KeyNextProposalID = types.KeyNextProposalID
95-
PrefixActiveProposalQueue = types.PrefixActiveProposalQueue
96-
PrefixInactiveProposalQueue = types.PrefixInactiveProposalQueue
100+
ProposalsKeyPrefix = types.ProposalsKeyPrefix
101+
ActiveProposalQueuePrefix = types.ActiveProposalQueuePrefix
102+
InactiveProposalQueuePrefix = types.InactiveProposalQueuePrefix
103+
ProposalIDKey = types.ProposalIDKey
104+
DepositsKeyPrefix = types.DepositsKeyPrefix
105+
VotesKeyPrefix = types.VotesKeyPrefix
97106
)
98107

99108
type (

x/gov/deposit.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package gov
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
"github.com/cosmos/cosmos-sdk/x/gov/types"
6+
)
7+
8+
// GetDeposit gets the deposit of a specific depositor on a specific proposal
9+
func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) (deposit Deposit, found bool) {
10+
store := ctx.KVStore(keeper.storeKey)
11+
bz := store.Get(types.DepositKey(proposalID, depositorAddr))
12+
if bz == nil {
13+
return deposit, false
14+
}
15+
16+
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &deposit)
17+
return deposit, true
18+
}
19+
20+
func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, deposit Deposit) {
21+
store := ctx.KVStore(keeper.storeKey)
22+
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit)
23+
store.Set(types.DepositKey(proposalID, depositorAddr), bz)
24+
}
25+
26+
// AddDeposit adds or updates a deposit of a specific depositor on a specific proposal
27+
// Activates voting period when appropriate
28+
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
29+
// Checks to see if proposal exists
30+
proposal, ok := keeper.GetProposal(ctx, proposalID)
31+
if !ok {
32+
return ErrUnknownProposal(keeper.codespace, proposalID), false
33+
}
34+
35+
// Check if proposal is still depositable
36+
if (proposal.Status != StatusDepositPeriod) && (proposal.Status != StatusVotingPeriod) {
37+
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
38+
}
39+
40+
// Send coins from depositor's account to DepositedCoinsAccAddr account
41+
// TODO: Don't use an account for this purpose; it's clumsy and prone to misuse.
42+
err := keeper.ck.SendCoins(ctx, depositorAddr, DepositedCoinsAccAddr, depositAmount)
43+
if err != nil {
44+
return err, false
45+
}
46+
47+
// Update proposal
48+
proposal.TotalDeposit = proposal.TotalDeposit.Add(depositAmount)
49+
keeper.SetProposal(ctx, proposal)
50+
51+
// Check if deposit has provided sufficient total funds to transition the proposal into the voting period
52+
activatedVotingPeriod := false
53+
if proposal.Status == StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) {
54+
keeper.activateVotingPeriod(ctx, proposal)
55+
activatedVotingPeriod = true
56+
}
57+
58+
// Add or update deposit object
59+
deposit, found := keeper.GetDeposit(ctx, proposalID, depositorAddr)
60+
if found {
61+
deposit.Amount = deposit.Amount.Add(depositAmount)
62+
} else {
63+
deposit = NewDeposit(proposalID, depositorAddr, depositAmount)
64+
}
65+
66+
keeper.setDeposit(ctx, proposalID, depositorAddr, deposit)
67+
68+
return nil, activatedVotingPeriod
69+
}
70+
71+
// GetAllDeposits returns all the deposits from the store
72+
func (keeper Keeper) GetAllDeposits(ctx sdk.Context) (deposits Deposits) {
73+
keeper.IterateAllDeposits(ctx, func(deposit Deposit) bool {
74+
deposits = append(deposits, deposit)
75+
return false
76+
})
77+
return
78+
}
79+
80+
// GetDeposits returns all the deposits from a proposal
81+
func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) (deposits Deposits) {
82+
keeper.IterateDeposits(ctx, proposalID, func(deposit Deposit) bool {
83+
deposits = append(deposits, deposit)
84+
return false
85+
})
86+
return
87+
}
88+
89+
// GetDepositsIterator gets all the deposits on a specific proposal as an sdk.Iterator
90+
func (keeper Keeper) GetDepositsIterator(ctx sdk.Context, proposalID uint64) sdk.Iterator {
91+
store := ctx.KVStore(keeper.storeKey)
92+
return sdk.KVStorePrefixIterator(store, types.DepositsKey(proposalID))
93+
}
94+
95+
// RefundDeposits refunds and deletes all the deposits on a specific proposal
96+
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
97+
store := ctx.KVStore(keeper.storeKey)
98+
99+
keeper.IterateDeposits(ctx, proposalID, func(deposit Deposit) bool {
100+
err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositor, deposit.Amount)
101+
if err != nil {
102+
panic(err)
103+
}
104+
store.Delete(DepositKey(proposalID, deposit.Depositor))
105+
return false
106+
})
107+
}
108+
109+
// DeleteDeposits deletes all the deposits on a specific proposal without refunding them
110+
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) {
111+
store := ctx.KVStore(keeper.storeKey)
112+
113+
keeper.IterateDeposits(ctx, proposalID, func(deposit Deposit) bool {
114+
err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount)
115+
if err != nil {
116+
panic(err)
117+
}
118+
119+
store.Delete(DepositKey(proposalID, deposit.Depositor))
120+
return false
121+
})
122+
}

x/gov/endblocker.go

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,100 +7,85 @@ import (
77
"github.com/cosmos/cosmos-sdk/x/gov/tags"
88
)
99

10-
// Called every block, process inflation, update validator set
10+
// EndBlocker called every block, process inflation, update validator set
1111
func EndBlocker(ctx sdk.Context, keeper Keeper) sdk.Tags {
1212
logger := keeper.Logger(ctx)
1313
resTags := sdk.NewTags()
1414

15-
inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
16-
defer inactiveIterator.Close()
17-
for ; inactiveIterator.Valid(); inactiveIterator.Next() {
18-
var proposalID uint64
15+
// delete inactive proposal from store and its deposits
16+
keeper.IterateInactiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal Proposal) bool {
17+
keeper.DeleteProposal(ctx, proposal.ProposalID)
18+
keeper.DeleteDeposits(ctx, proposal.ProposalID)
1919

20-
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
21-
inactiveProposal, ok := keeper.GetProposal(ctx, proposalID)
22-
if !ok {
23-
panic(fmt.Sprintf("proposal %d does not exist", proposalID))
24-
}
25-
26-
keeper.DeleteProposal(ctx, proposalID)
27-
keeper.DeleteDeposits(ctx, proposalID) // delete any associated deposits (burned)
28-
29-
resTags = resTags.AppendTag(tags.ProposalID, fmt.Sprintf("%d", proposalID))
20+
resTags = resTags.AppendTag(tags.ProposalID, fmt.Sprintf("%d", proposal.ProposalID))
3021
resTags = resTags.AppendTag(tags.ProposalResult, tags.ActionProposalDropped)
3122

3223
logger.Info(
3324
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
34-
inactiveProposal.ProposalID,
35-
inactiveProposal.GetTitle(),
25+
proposal.ProposalID,
26+
proposal.GetTitle(),
3627
keeper.GetDepositParams(ctx).MinDeposit,
37-
inactiveProposal.TotalDeposit,
28+
proposal.TotalDeposit,
3829
),
3930
)
40-
}
31+
return false
32+
})
4133

4234
// fetch active proposals whose voting periods have ended (are passed the block time)
43-
activeIterator := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
44-
defer activeIterator.Close()
45-
for ; activeIterator.Valid(); activeIterator.Next() {
46-
var proposalID uint64
47-
48-
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
49-
activeProposal, ok := keeper.GetProposal(ctx, proposalID)
50-
if !ok {
51-
panic(fmt.Sprintf("proposal %d does not exist", proposalID))
52-
}
53-
passes, burnDeposits, tallyResults := tally(ctx, keeper, activeProposal)
54-
35+
keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal Proposal) bool {
5536
var tagValue, logMsg string
5637

38+
passes, burnDeposits, tallyResults := tally(ctx, keeper, proposal)
39+
5740
if burnDeposits {
58-
keeper.DeleteDeposits(ctx, activeProposal.ProposalID)
41+
keeper.DeleteDeposits(ctx, proposal.ProposalID)
5942
} else {
60-
keeper.RefundDeposits(ctx, activeProposal.ProposalID)
43+
keeper.RefundDeposits(ctx, proposal.ProposalID)
6144
}
6245

6346
if passes {
64-
handler := keeper.router.GetRoute(activeProposal.ProposalRoute())
47+
handler := keeper.router.GetRoute(proposal.ProposalRoute())
6548
cacheCtx, writeCache := ctx.CacheContext()
6649

6750
// The proposal handler may execute state mutating logic depending
6851
// on the proposal content. If the handler fails, no state mutation
6952
// is written and the error message is logged.
70-
err := handler(cacheCtx, activeProposal.Content)
53+
err := handler(cacheCtx, proposal.Content)
7154
if err == nil {
72-
activeProposal.Status = StatusPassed
55+
proposal.Status = StatusPassed
7356
tagValue = tags.ActionProposalPassed
7457
logMsg = "passed"
7558

7659
// write state to the underlying multi-store
7760
writeCache()
7861
} else {
79-
activeProposal.Status = StatusFailed
62+
proposal.Status = StatusFailed
8063
tagValue = tags.ActionProposalFailed
8164
logMsg = fmt.Sprintf("passed, but failed on execution: %s", err.ABCILog())
8265
}
8366
} else {
84-
activeProposal.Status = StatusRejected
67+
proposal.Status = StatusRejected
8568
tagValue = tags.ActionProposalRejected
8669
logMsg = "rejected"
8770
}
8871

89-
activeProposal.FinalTallyResult = tallyResults
72+
proposal.FinalTallyResult = tallyResults
9073

91-
keeper.SetProposal(ctx, activeProposal)
92-
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.VotingEndTime, activeProposal.ProposalID)
74+
keeper.SetProposal(ctx, proposal)
75+
keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalID, proposal.VotingEndTime)
9376

9477
logger.Info(
9578
fmt.Sprintf(
9679
"proposal %d (%s) tallied; result: %s",
97-
activeProposal.ProposalID, activeProposal.GetTitle(), logMsg,
80+
proposal.ProposalID, proposal.GetTitle(), logMsg,
9881
),
9982
)
10083

101-
resTags = resTags.AppendTag(tags.ProposalID, fmt.Sprintf("%d", proposalID))
84+
resTags = resTags.AppendTag(tags.ProposalID, fmt.Sprintf("%d", proposal.ProposalID))
10285
resTags = resTags.AppendTag(tags.ProposalResult, tagValue)
103-
}
86+
87+
return false
88+
})
10489

10590
return resTags
10691
}

x/gov/endblocker_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func TestTickPassedVotingPeriod(t *testing.T) {
232232
proposal, ok := input.keeper.GetProposal(ctx, activeProposalID)
233233
require.True(t, ok)
234234
require.Equal(t, StatusVotingPeriod, proposal.Status)
235-
depositsIterator := input.keeper.GetDeposits(ctx, proposalID)
235+
depositsIterator := input.keeper.GetDepositsIterator(ctx, proposalID)
236236
require.True(t, depositsIterator.Valid())
237237
depositsIterator.Close()
238238
activeQueue.Close()

0 commit comments

Comments
 (0)