Skip to content
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

Migrate Gov module to Simapp #5738

Merged
merged 25 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3fa47df
migrate test TestDeposits from gov to simapp
jgimeno Mar 2, 2020
0c93812
migrate TestIncrementProposalNumber to simap
jgimeno Mar 2, 2020
2afd22f
migrate TestProposalQueues to use simapp
jgimeno Mar 2, 2020
eedd2b2
migrate part of proposal to simapp
jgimeno Mar 2, 2020
0039614
migrate TestActivateVotingPeriod to simapp
jgimeno Mar 2, 2020
2c231e2
TestGetProposalsFiltered migrate to simapp
jgimeno Mar 2, 2020
80bfd0d
migrate TestQueries to new test simapp
jgimeno Mar 2, 2020
8c0d32c
migrate TestTallyNoOneVotes to use simapp
jgimeno Mar 2, 2020
e24734f
migrate TestTallyNoQuorum to use simapp
jgimeno Mar 2, 2020
88e3a22
migrate TestTallyOnlyValidatorsAllYes to simapp
jgimeno Mar 2, 2020
1cf4a7e
migrate TestTallyOnlyValidators51No to use simapp
jgimeno Mar 2, 2020
84b7fe5
migrate TestTallyOnlyValidators51Yes to use simapp
jgimeno Mar 2, 2020
c3b18df
migrate TestTallyOnlyValidatorsVetoed test
jgimeno Mar 2, 2020
b83755f
migrate TestTallyOnlyValidatorsAbstainPasses to simapp
jgimeno Mar 2, 2020
759181c
migrate TestTallyOnlyValidatorsAbstainFails into simapp
jgimeno Mar 2, 2020
46a70d5
migrate TestTallyOnlyValidatorsNonVoter to simapp
jgimeno Mar 2, 2020
9f25188
migreate TestTallyDelgatorOverride to simapp
jgimeno Mar 2, 2020
73e1e3a
refactor TestTallyDelgatorInherit to use simapp
jgimeno Mar 2, 2020
8d4d10d
refactor TestTallyDelgatorMultipleOverride to use simapp
jgimeno Mar 2, 2020
7d34306
add tally test TestTallyDelgatorMultipleInherit
jgimeno Mar 2, 2020
275b78f
add TestTallyJailedValidator to simapp
jgimeno Mar 2, 2020
894b2e5
refactor old tally test
jgimeno Mar 2, 2020
e266c40
refactor vote test
jgimeno Mar 2, 2020
eba38af
end of gov refactoring
jgimeno Mar 2, 2020
c0fd5cb
Merge branch 'master' into jonathan/4875-gov-use-simapp
jgimeno Mar 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions x/gov/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov"
keep "github.com/cosmos/cosmos-sdk/x/gov/keeper"
"github.com/cosmos/cosmos-sdk/x/staking"
)

Expand Down Expand Up @@ -212,7 +211,7 @@ func TestTickPassedVotingPeriod(t *testing.T) {
activeQueue.Close()

proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))}
newProposalMsg := gov.NewMsgSubmitProposal(keep.TestProposal, proposalCoins, addrs[0])
newProposalMsg := gov.NewMsgSubmitProposal(TestProposal, proposalCoins, addrs[0])

res, err := govHandler(ctx, newProposalMsg)
require.NoError(t, err)
Expand Down Expand Up @@ -277,7 +276,7 @@ func TestProposalPassedEndblocker(t *testing.T) {
require.NotNil(t, macc)
initialModuleAccCoins := app.BankKeeper.GetAllBalances(ctx, macc.GetAddress())

proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal)
proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal)
require.NoError(t, err)

proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))}
Expand Down Expand Up @@ -329,7 +328,7 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) {
// Create a proposal where the handler will pass for the test proposal
// because the value of contextKeyBadProposal is true.
ctx = ctx.WithValue(contextKeyBadProposal, true)
proposal, err := app.GovKeeper.SubmitProposal(ctx, keep.TestProposal)
proposal, err := app.GovKeeper.SubmitProposal(ctx, TestProposal)
require.NoError(t, err)

proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)))
Expand Down
15 changes: 12 additions & 3 deletions x/gov/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ import (
"github.com/tendermint/tendermint/crypto/ed25519"

sdk "github.com/cosmos/cosmos-sdk/types"
keep "github.com/cosmos/cosmos-sdk/x/gov/keeper"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/staking"
)

var (
valTokens = sdk.TokensFromConsensusPower(42)
valTokens = sdk.TokensFromConsensusPower(42)
TestProposal = types.NewTextProposal("Test", "description")
TestDescription = staking.NewDescription("T", "E", "S", "T", "Z")
TestCommissionRates = staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec())
)

// SortAddresses - Sorts Addresses
Expand Down Expand Up @@ -83,11 +86,17 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context,
valTokens := sdk.TokensFromConsensusPower(powerAmt[i])
valCreateMsg := staking.NewMsgCreateValidator(
addrs[i], pubkeys[i], sdk.NewCoin(sdk.DefaultBondDenom, valTokens),
keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(),
TestDescription, TestCommissionRates, sdk.OneInt(),
)

res, err := stakingHandler(ctx, valCreateMsg)
require.NoError(t, err)
require.NotNil(t, res)
}
}

// ProposalEqual checks if two proposals are equal (note: slow, for tests only)
func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool {
return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA),
types.ModuleCdc.MustMarshalBinaryBare(proposalB))
}
9 changes: 4 additions & 5 deletions x/gov/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
keep "github.com/cosmos/cosmos-sdk/x/gov/keeper"
)

func TestImportExportQueues(t *testing.T) {
Expand All @@ -28,7 +27,7 @@ func TestImportExportQueues(t *testing.T) {
ctx = app.BaseApp.NewContext(false, abci.Header{})

// Create two proposals, put the second into the voting period
proposal := keep.TestProposal
proposal := TestProposal
proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)
proposalID1 := proposal1.ProposalID
Expand Down Expand Up @@ -116,7 +115,7 @@ func TestEqualProposals(t *testing.T) {
app.BeginBlock(abci.RequestBeginBlock{Header: header})

// Submit two proposals
proposal := keep.TestProposal
proposal := TestProposal
proposal1, err := app.GovKeeper.SubmitProposal(ctx, proposal)
require.NoError(t, err)

Expand All @@ -125,7 +124,7 @@ func TestEqualProposals(t *testing.T) {

// They are similar but their IDs should be different
require.NotEqual(t, proposal1, proposal2)
require.False(t, keep.ProposalEqual(proposal1, proposal2))
require.False(t, ProposalEqual(proposal1, proposal2))

// Now create two genesis blocks
state1 := gov.GenesisState{Proposals: []gov.Proposal{proposal1}}
Expand All @@ -137,7 +136,7 @@ func TestEqualProposals(t *testing.T) {
proposal1.ProposalID = 55
proposal2.ProposalID = 55
require.Equal(t, proposal1, proposal1)
require.True(t, keep.ProposalEqual(proposal1, proposal2))
require.True(t, ProposalEqual(proposal1, proposal2))

// Reassign proposals into state
state1.Proposals[0] = proposal1
Expand Down
61 changes: 61 additions & 0 deletions x/gov/keeper/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package keeper_test

import (
"bytes"

"github.com/cosmos/cosmos-sdk/simapp/codec"

"github.com/cosmos/cosmos-sdk/simapp"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking"

"github.com/cosmos/cosmos-sdk/x/gov/types"
)

var (
TestProposal = types.NewTextProposal("Test", "description")
)

// ProposalEqual checks if two proposals are equal (note: slow, for tests only)
func ProposalEqual(proposalA types.Proposal, proposalB types.Proposal) bool {
return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA),
types.ModuleCdc.MustMarshalBinaryBare(proposalB))
}

func createValidators(ctx sdk.Context, app *simapp.SimApp, powers []int64) ([]sdk.AccAddress, []sdk.ValAddress) {
addrs := simapp.AddTestAddrsIncremental(app, ctx, 5, sdk.NewInt(30000000))
valAddrs := simapp.ConvertAddrsToValAddrs(addrs)
pks := simapp.CreateTestPubKeys(5)

appCodec := codec.NewAppCodec(app.Codec())
app.StakingKeeper = staking.NewKeeper(
appCodec,
app.GetKey(staking.StoreKey),
app.BankKeeper,
app.SupplyKeeper,
app.GetSubspace(staking.ModuleName),
)

val1 := staking.NewValidator(valAddrs[0], pks[0], staking.Description{})
val2 := staking.NewValidator(valAddrs[1], pks[1], staking.Description{})
val3 := staking.NewValidator(valAddrs[2], pks[2], staking.Description{})

app.StakingKeeper.SetValidator(ctx, val1)
app.StakingKeeper.SetValidator(ctx, val2)
app.StakingKeeper.SetValidator(ctx, val3)
app.StakingKeeper.SetValidatorByConsAddr(ctx, val1)
app.StakingKeeper.SetValidatorByConsAddr(ctx, val2)
app.StakingKeeper.SetValidatorByConsAddr(ctx, val3)
app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val1)
app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val2)
app.StakingKeeper.SetNewValidatorByPowerIndex(ctx, val3)

_, _ = app.StakingKeeper.Delegate(ctx, addrs[0], sdk.TokensFromConsensusPower(powers[0]), sdk.Unbonded, val1, true)
_, _ = app.StakingKeeper.Delegate(ctx, addrs[1], sdk.TokensFromConsensusPower(powers[1]), sdk.Unbonded, val2, true)
_, _ = app.StakingKeeper.Delegate(ctx, addrs[2], sdk.TokensFromConsensusPower(powers[2]), sdk.Unbonded, val3, true)

_ = staking.EndBlocker(ctx, app.StakingKeeper)

return addrs, valAddrs
}
2 changes: 1 addition & 1 deletion x/gov/keeper/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd
// Check if deposit has provided sufficient total funds to transition the proposal into the voting period
activatedVotingPeriod := false
if proposal.Status == types.StatusDepositPeriod && proposal.TotalDeposit.IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) {
keeper.activateVotingPeriod(ctx, proposal)
keeper.ActivateVotingPeriod(ctx, proposal)
activatedVotingPeriod = true
}

Expand Down
60 changes: 33 additions & 27 deletions x/gov/keeper/deposit_test.go
Original file line number Diff line number Diff line change
@@ -1,98 +1,104 @@
package keeper
package keeper_test

import (
"testing"
"time"

"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
)

func TestDeposits(t *testing.T) {
ctx, _, bk, keeper, _, _ := createTestInput(t, false, 100)
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})

TestAddrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(10000000))

tp := TestProposal
proposal, err := keeper.SubmitProposal(ctx, tp)
proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
require.NoError(t, err)
proposalID := proposal.ProposalID

fourStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)))
fiveStake := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5)))

addr0Initial := bk.GetAllBalances(ctx, TestAddrs[0])
addr1Initial := bk.GetAllBalances(ctx, TestAddrs[1])
addr0Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[0])
addr1Initial := app.BankKeeper.GetAllBalances(ctx, TestAddrs[1])

require.True(t, proposal.TotalDeposit.IsEqual(sdk.NewCoins()))

// Check no deposits at beginning
deposit, found := keeper.GetDeposit(ctx, proposalID, TestAddrs[1])
deposit, found := app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1])
require.False(t, found)
proposal, ok := keeper.GetProposal(ctx, proposalID)
proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.True(t, proposal.VotingStartTime.Equal(time.Time{}))

// Check first deposit
votingStarted, err := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake)
votingStarted, err := app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake)
require.NoError(t, err)
require.False(t, votingStarted)
deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0])
deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0])
require.True(t, found)
require.Equal(t, fourStake, deposit.Amount)
require.Equal(t, TestAddrs[0], deposit.Depositor)
proposal, ok = keeper.GetProposal(ctx, proposalID)
proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake, proposal.TotalDeposit)
require.Equal(t, addr0Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[0]))
require.Equal(t, addr0Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]))

// Check a second deposit from same address
votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake)
votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake)
require.NoError(t, err)
require.False(t, votingStarted)
deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0])
deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[0])
require.True(t, found)
require.Equal(t, fourStake.Add(fiveStake...), deposit.Amount)
require.Equal(t, TestAddrs[0], deposit.Depositor)
proposal, ok = keeper.GetProposal(ctx, proposalID)
proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake.Add(fiveStake...), proposal.TotalDeposit)
require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), bk.GetAllBalances(ctx, TestAddrs[0]))
require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]))

// Check third deposit from a new address
votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake)
votingStarted, err = app.GovKeeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake)
require.NoError(t, err)
require.True(t, votingStarted)
deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1])
deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1])
require.True(t, found)
require.Equal(t, TestAddrs[1], deposit.Depositor)
require.Equal(t, fourStake, deposit.Amount)
proposal, ok = keeper.GetProposal(ctx, proposalID)
proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.Equal(t, fourStake.Add(fiveStake...).Add(fourStake...), proposal.TotalDeposit)
require.Equal(t, addr1Initial.Sub(fourStake), bk.GetAllBalances(ctx, TestAddrs[1]))
require.Equal(t, addr1Initial.Sub(fourStake), app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]))

// Check that proposal moved to voting period
proposal, ok = keeper.GetProposal(ctx, proposalID)
proposal, ok = app.GovKeeper.GetProposal(ctx, proposalID)
require.True(t, ok)
require.True(t, proposal.VotingStartTime.Equal(ctx.BlockHeader().Time))

// Test deposit iterator
// NOTE order of deposits is determined by the addresses
deposits := keeper.GetAllDeposits(ctx)
deposits := app.GovKeeper.GetAllDeposits(ctx)
require.Len(t, deposits, 2)
require.Equal(t, deposits, keeper.GetDeposits(ctx, proposalID))
require.Equal(t, deposits, app.GovKeeper.GetDeposits(ctx, proposalID))
require.Equal(t, TestAddrs[0], deposits[0].Depositor)
require.Equal(t, fourStake.Add(fiveStake...), deposits[0].Amount)
require.Equal(t, TestAddrs[1], deposits[1].Depositor)
require.Equal(t, fourStake, deposits[1].Amount)

// Test Refund Deposits
deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1])
deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1])
require.True(t, found)
require.Equal(t, fourStake, deposit.Amount)
keeper.RefundDeposits(ctx, proposalID)
deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1])
app.GovKeeper.RefundDeposits(ctx, proposalID)
deposit, found = app.GovKeeper.GetDeposit(ctx, proposalID, TestAddrs[1])
require.False(t, found)
require.Equal(t, addr0Initial, bk.GetAllBalances(ctx, TestAddrs[0]))
require.Equal(t, addr1Initial, bk.GetAllBalances(ctx, TestAddrs[1]))
require.Equal(t, addr0Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]))
require.Equal(t, addr1Initial, app.BankKeeper.GetAllBalances(ctx, TestAddrs[1]))
}
35 changes: 20 additions & 15 deletions x/gov/keeper/keeper_test.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,56 @@
package keeper
package keeper_test

import (
"testing"

"github.com/stretchr/testify/require"

abci "github.com/tendermint/tendermint/abci/types"

"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)

func TestIncrementProposalNumber(t *testing.T) {
ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})

tp := TestProposal
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
keeper.SubmitProposal(ctx, tp)
proposal6, err := keeper.SubmitProposal(ctx, tp)
app.GovKeeper.SubmitProposal(ctx, tp)
app.GovKeeper.SubmitProposal(ctx, tp)
app.GovKeeper.SubmitProposal(ctx, tp)
app.GovKeeper.SubmitProposal(ctx, tp)
app.GovKeeper.SubmitProposal(ctx, tp)
proposal6, err := app.GovKeeper.SubmitProposal(ctx, tp)
require.NoError(t, err)

require.Equal(t, uint64(6), proposal6.ProposalID)
}

func TestProposalQueues(t *testing.T) {
ctx, _, _, keeper, _, _ := createTestInput(t, false, 100) // nolint: dogsled
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})

// create test proposals
tp := TestProposal
proposal, err := keeper.SubmitProposal(ctx, tp)
proposal, err := app.GovKeeper.SubmitProposal(ctx, tp)
require.NoError(t, err)

inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime)
inactiveIterator := app.GovKeeper.InactiveProposalQueueIterator(ctx, proposal.DepositEndTime)
require.True(t, inactiveIterator.Valid())

proposalID := types.GetProposalIDFromBytes(inactiveIterator.Value())
require.Equal(t, proposalID, proposal.ProposalID)
inactiveIterator.Close()

keeper.activateVotingPeriod(ctx, proposal)
app.GovKeeper.ActivateVotingPeriod(ctx, proposal)

proposal, ok := keeper.GetProposal(ctx, proposal.ProposalID)
proposal, ok := app.GovKeeper.GetProposal(ctx, proposal.ProposalID)
require.True(t, ok)

activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime)
activeIterator := app.GovKeeper.ActiveProposalQueueIterator(ctx, proposal.VotingEndTime)
require.True(t, activeIterator.Valid())
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
app.Codec().UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.ProposalID)
activeIterator.Close()
}
2 changes: 1 addition & 1 deletion x/gov/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) {
store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID))
}

func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal types.Proposal) {
func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) {
proposal.VotingStartTime = ctx.BlockHeader().Time
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)
Expand Down
Loading