diff --git a/Dockerfile b/Dockerfile index 7b699ac974..cc537c7ccc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,7 @@ COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/ COPY --from=is-builder /go/bin/interchain-security-pd /usr/local/bin/interchain-security-pd COPY --from=is-builder /go/bin/interchain-security-cd /usr/local/bin/interchain-security-cd +COPY --from=is-builder /go/bin/interchain-security-cdd /usr/local/bin/interchain-security-cdd # Copy in the shell scripts that run the testnet diff --git a/app/consumer-democracy/ante/msg_filter_ante.go b/app/consumer-democracy/ante/msg_filter_ante.go index 5788f12a5e..a9b2b2bd78 100644 --- a/app/consumer-democracy/ante/msg_filter_ante.go +++ b/app/consumer-democracy/ante/msg_filter_ante.go @@ -22,6 +22,7 @@ type ( } ) +// TODO Ethernal: remove this, it is duplicated (consumerante does the same thing) func NewMsgFilterDecorator(k ConsumerKeeper) MsgFilterDecorator { return MsgFilterDecorator{ ConsumerKeeper: k, diff --git a/app/consumer-democracy/ante_handler.go b/app/consumer-democracy/ante_handler.go index ea0984b41b..557a245756 100644 --- a/app/consumer-democracy/ante_handler.go +++ b/app/consumer-democracy/ante_handler.go @@ -39,6 +39,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSetUpContextDecorator(), ante.NewRejectExtensionOptionsDecorator(), consumerante.NewMsgFilterDecorator(options.ConsumerKeeper), + // TODO Ethernal add handler to disable slashing and evidence messages (issue 115) ante.NewMempoolFeeDecorator(), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), diff --git a/tests/integration/actions.go b/tests/integration/actions.go index 955e6f481d..f7b6444819 100644 --- a/tests/integration/actions.go +++ b/tests/integration/actions.go @@ -257,6 +257,77 @@ func (tr TestRun) submitConsumerProposal( } } +type submitParamChangeProposalAction struct { + chain chainID + from validatorID + deposit uint + subspace string + key string + value interface{} +} + +type paramChangeProposalJSON struct { + Title string `json:"title"` + Description string `json:"description"` + Changes []paramChangeJSON `json:"changes"` + Deposit string `json:"deposit"` +} + +type paramChangeJSON struct { + Subspace string `json:"subspace"` + Key string `json:"key"` + Value interface{} `json:"value"` +} + +func (tr TestRun) submitParamChangeProposal( + action submitParamChangeProposalAction, + verbose bool, +) { + prop := paramChangeProposalJSON{ + Title: "Param change", + Description: "Changing module params", + Changes: []paramChangeJSON{{Subspace: action.subspace, Key: action.key, Value: action.value}}, + Deposit: fmt.Sprint(action.deposit) + `stake`, + } + + bz, err := json.Marshal(prop) + if err != nil { + log.Fatal(err) + } + + jsonStr := string(bz) + if strings.Contains(jsonStr, "'") { + log.Fatal("prop json contains single quote") + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, + "/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, "/params-proposal.json")).CombinedOutput() + + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err = exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + + "tx", "gov", "submit-proposal", "param-change", + "/params-proposal.json", + + `--from`, `validator`+fmt.Sprint(action.from), + `--chain-id`, string(tr.chainConfigs[action.chain].chainId), + `--home`, tr.getValidatorHome(action.chain, action.from), + `--node`, tr.getValidatorNode(action.chain, action.from), + `--keyring-backend`, `test`, + `-b`, `block`, + `-y`, + ).CombinedOutput() + + if err != nil { + log.Fatal(err, "\n", string(bz)) + } +} + type voteGovProposalAction struct { chain chainID from []validatorID @@ -300,9 +371,10 @@ func (tr TestRun) voteGovProposal( } type startConsumerChainAction struct { - consumerChain chainID - providerChain chainID - validators []StartChainValidator + consumerChain chainID + providerChain chainID + genesisChanges string + validators []StartChainValidator } func (tr TestRun) startConsumerChain( @@ -329,10 +401,15 @@ func (tr TestRun) startConsumerChain( log.Fatal(err, "\n", string(bz)) } + genesisChanges := ".app_state.ccvconsumer = " + string(bz) + if action.genesisChanges != "" { + genesisChanges = genesisChanges + " | " + action.genesisChanges + } + tr.startChain(StartChainAction{ chain: action.consumerChain, validators: action.validators, - genesisChanges: ".app_state.ccvconsumer = " + string(bz), + genesisChanges: genesisChanges, skipGentx: true, }, verbose) } @@ -518,6 +595,88 @@ func (tr TestRun) addIbcChannel( } } +type transferChannelCompleteAction struct { + chainA chainID + chainB chainID + connectionA uint + portA string + portB string + order string + channelA uint + channelB uint +} + +func (tr TestRun) transferChannelComplete( + action transferChannelCompleteAction, + verbose bool, +) { + //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenTryCmd arguments. + chanOpenTryCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + "tx", "chan-open-try", + "--dst-chain", string(tr.chainConfigs[action.chainB].chainId), + "--src-chain", string(tr.chainConfigs[action.chainA].chainId), + "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), + "--dst-port", action.portB, + "--src-port", action.portA, + "--src-channel", "channel-"+fmt.Sprint(action.channelA), + ) + executeCommand(chanOpenTryCmd, "transferChanOpenTry") + + //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenAckCmd arguments. + chanOpenAckCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + "tx", "chan-open-ack", + "--dst-chain", string(tr.chainConfigs[action.chainA].chainId), + "--src-chain", string(tr.chainConfigs[action.chainB].chainId), + "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), + "--dst-port", action.portA, + "--src-port", action.portB, + "--dst-channel", "channel-"+fmt.Sprint(action.channelA), + "--src-channel", "channel-"+fmt.Sprint(action.channelB), + ) + executeCommand(chanOpenAckCmd, "transferChanOpenAck") + + //#nosec G204 -- Bypass linter warning for spawning subprocess with chanOpenConfirmCmd arguments. + chanOpenConfirmCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "hermes", + "tx", "chan-open-confirm", + "--dst-chain", string(tr.chainConfigs[action.chainB].chainId), + "--src-chain", string(tr.chainConfigs[action.chainA].chainId), + "--dst-connection", "connection-"+fmt.Sprint(action.connectionA), + "--dst-port", action.portB, + "--src-port", action.portA, + "--dst-channel", "channel-"+fmt.Sprint(action.channelB), + "--src-channel", "channel-"+fmt.Sprint(action.channelA), + ) + executeCommand(chanOpenConfirmCmd, "transferChanOpenConfirm") +} + +func executeCommand(cmd *exec.Cmd, cmdName string) { + if verbose { + fmt.Println(cmdName+" cmd:", cmd.String()) + } + + cmdReader, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + cmd.Stderr = cmd.Stdout + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(cmdReader) + + for scanner.Scan() { + out := scanner.Text() + if verbose { + fmt.Println(cmdName + ": " + out) + } + } + if err := scanner.Err(); err != nil { + log.Fatal(err) + } +} + type relayPacketsAction struct { chain chainID port string @@ -736,3 +895,59 @@ func (tr TestRun) unjailValidator(action unjailValidatorAction, verbose bool) { log.Fatal(err, "\n", string(bz)) } } + +type registerRepresentAction struct { + chain chainID + represents []validatorID + stakes []uint +} + +func (tr TestRun) registerRepresent( + action registerRepresentAction, + verbose bool, +) { + var wg sync.WaitGroup + for i, val := range action.represents { + wg.Add(1) + stake := action.stakes[i] + go func(val validatorID, stake uint) { + defer wg.Done() + + //#nosec G204 -- Bypass linter warning for spawning subprocess with pubKeycmd arguments. + pubKeycmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + "tendermint", "show-validator", + `--home`, tr.getValidatorHome(action.chain, val), + ) + + bzPubKey, err := pubKeycmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bzPubKey)) + } + + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, + "tx", "staking", "create-validator", + `--amount`, fmt.Sprint(stake)+"stake", + `--pubkey`, string(bzPubKey), + `--moniker`, fmt.Sprint(val), + `--commission-rate`, "0.1", + `--commission-max-rate`, "0.2", + `--commission-max-change-rate`, "0.01", + `--min-self-delegation`, "1", + `--from`, `validator`+fmt.Sprint(val), + `--chain-id`, string(tr.chainConfigs[action.chain].chainId), + `--home`, tr.getValidatorHome(action.chain, val), + `--node`, tr.getValidatorNode(action.chain, val), + `--keyring-backend`, `test`, + `-b`, `block`, + `-y`, + ).CombinedOutput() + + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + }(val, stake) + } + + wg.Wait() +} diff --git a/tests/integration/config.go b/tests/integration/config.go index 9fb890e246..ffebd002dc 100644 --- a/tests/integration/config.go +++ b/tests/integration/config.go @@ -116,6 +116,17 @@ func DefaultTestRun() TestRun { ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", }, + chainID("democ"): { + chainId: chainID("democ"), + binaryName: "interchain-security-cdd", + ipPrefix: "7.7.9", + votingWaitTime: 10, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", + }, }, } } diff --git a/tests/integration/main.go b/tests/integration/main.go index 67a4b35f48..432291fd59 100644 --- a/tests/integration/main.go +++ b/tests/integration/main.go @@ -14,6 +14,7 @@ import ( var verbose = true func main() { + fmt.Println("============================================ start happy path tests ============================================") start := time.Now() tr := DefaultTestRun() tr.ParseCLIFlags() @@ -24,7 +25,17 @@ func main() { tr.runStep(step, verbose) } - fmt.Printf("test successful - time elapsed %v\n", time.Since(start)) + fmt.Printf("happy path tests successful - time elapsed %v\n", time.Since(start)) + + fmt.Println("============================================ start democracy path tests ============================================") + start = time.Now() + tr.startDocker() + + for _, step := range democracySteps { + tr.runStep(step, verbose) + } + + fmt.Printf("democracy path tests successful - time elapsed %v\n", time.Since(start)) } func (tr TestRun) runStep(step Step, verbose bool) { @@ -38,6 +49,8 @@ func (tr TestRun) runStep(step Step, verbose bool) { tr.submitTextProposal(action, verbose) case submitConsumerProposalAction: tr.submitConsumerProposal(action, verbose) + case submitParamChangeProposalAction: + tr.submitParamChangeProposal(action, verbose) case voteGovProposalAction: tr.voteGovProposal(action, verbose) case startConsumerChainAction: @@ -48,6 +61,8 @@ func (tr TestRun) runStep(step Step, verbose bool) { tr.addIbcConnection(action, verbose) case addIbcChannelAction: tr.addIbcChannel(action, verbose) + case transferChannelCompleteAction: + tr.transferChannelComplete(action, verbose) case relayPacketsAction: tr.relayPackets(action, verbose) case delegateTokensAction: @@ -60,6 +75,8 @@ func (tr TestRun) runStep(step Step, verbose bool) { tr.invokeDowntimeSlash(action, verbose) case unjailValidatorAction: tr.unjailValidator(action, verbose) + case registerRepresentAction: + tr.registerRepresent(action, verbose) default: log.Fatalf(fmt.Sprintf(`unknown action: %#v`, action)) } diff --git a/tests/integration/state.go b/tests/integration/state.go index b8768c6963..ab74b95f46 100644 --- a/tests/integration/state.go +++ b/tests/integration/state.go @@ -17,9 +17,11 @@ import ( type State map[chainID]ChainState type ChainState struct { - ValBalances *map[validatorID]uint - Proposals *map[uint]Proposal - ValPowers *map[validatorID]uint + ValBalances *map[validatorID]uint + Proposals *map[uint]Proposal + ValPowers *map[validatorID]uint + RepresentPowers *map[validatorID]uint + Params *[]Param } type Proposal interface { @@ -44,6 +46,22 @@ type ConsumerProposal struct { func (p ConsumerProposal) isProposal() {} +type ParamsProposal struct { + Deposit uint + Status string + Subspace string + Key string + Value string +} + +func (p ParamsProposal) isProposal() {} + +type Param struct { + Subspace string + Key string + Value string +} + func (tr TestRun) getState(modelState State) State { systemState := State{} for k, modelState := range modelState { @@ -72,6 +90,16 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState chainState.ValPowers = &powers } + if modelState.RepresentPowers != nil { + representPowers := tr.getRepresentPowers(chain, *modelState.RepresentPowers) + chainState.RepresentPowers = &representPowers + } + + if modelState.Params != nil { + params := tr.getParams(chain, *modelState.Params) + chainState.Params = ¶ms + } + return chainState } @@ -141,6 +169,24 @@ func (tr TestRun) getValPowers(chain chainID, modelState map[validatorID]uint) m return actualState } +func (tr TestRun) getRepresentPowers(chain chainID, modelState map[validatorID]uint) map[validatorID]uint { + actualState := map[validatorID]uint{} + for k := range modelState { + actualState[k] = tr.getRepresentPower(chain, k) + } + + return actualState +} + +func (tr TestRun) getParams(chain chainID, modelState []Param) []Param { + actualState := []Param{} + for _, p := range modelState { + actualState = append(actualState, Param{Subspace: p.Subspace, Key: p.Key, Value: tr.getParam(chain, p)}) + } + + return actualState +} + func (tr TestRun) getBalance(chain chainID, validator validatorID) uint { //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, @@ -222,7 +268,14 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal { RevisionHeight: gjson.Get(string(bz), `content.initial_height.revision_height`).Uint(), }, } - + case "/cosmos.params.v1beta1.ParameterChangeProposal": + return ParamsProposal{ + Deposit: uint(deposit), + Status: status, + Subspace: gjson.Get(string(bz), `content.changes.0.subspace`).String(), + Key: gjson.Get(string(bz), `content.changes.0.key`).String(), + Value: gjson.Get(string(bz), `content.changes.0.value`).String(), + } } log.Fatal("unknown proposal type", string(bz)) @@ -288,6 +341,47 @@ func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { return 0 } +func (tr TestRun) getRepresentPower(chain chainID, validator validatorID) uint { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + + "query", "staking", "validator", + tr.validatorConfigs[validator].valoperAddress, + + `--node`, tr.getValidatorNode(chain, tr.getDefaultValidator(chain)), + `-o`, `json`, + ).CombinedOutput() + + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + amount := gjson.Get(string(bz), `tokens`) + + return uint(amount.Uint()) +} + +func (tr TestRun) getParam(chain chainID, param Param) string { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, + + "query", "params", "subspace", + param.Subspace, + param.Key, + + `--node`, tr.getValidatorNode(chain, tr.getDefaultValidator(chain)), + `-o`, `json`, + ).CombinedOutput() + + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + value := gjson.Get(string(bz), `value`) + + return value.String() +} + // Gets a default validator for txs and queries using the first subdirectory // of the directory of the input chain, which will be the home directory // of one of the validators. diff --git a/tests/integration/steps_democracy.go b/tests/integration/steps_democracy.go new file mode 100644 index 0000000000..c474ee0d13 --- /dev/null +++ b/tests/integration/steps_democracy.go @@ -0,0 +1,329 @@ +package main + +import ( + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" +) + +var democracySteps = []Step{ + { + action: StartChainAction{ + chain: chainID("provi"), + validators: []StartChainValidator{ + {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + }, + genesisChanges: "", // No custom genesis changes for this action + skipGentx: false, + }, + state: State{ + chainID("provi"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9500000000, + validatorID("bob"): 9500000000, + }, + }, + }, + }, + { + action: SendTokensAction{ + chain: chainID("provi"), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 2, + }, + state: State{ + chainID("provi"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9499999998, + validatorID("bob"): 9500000002, + }, + }, + }, + }, + { + action: submitConsumerProposalAction{ + chain: chainID("provi"), + from: validatorID("alice"), + deposit: 10000001, + consumerChain: chainID("democ"), + spawnTime: 0, + initialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + }, + state: State{ + chainID("provi"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9489999997, + validatorID("bob"): 9500000002, + }, + Proposals: &map[uint]Proposal{ + 1: ConsumerProposal{ + Deposit: 10000001, + Chain: chainID("democ"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + }, + }, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("provi"), + from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")}, + vote: []string{"yes", "yes", "yes"}, + propNumber: 1, + }, + state: State{ + chainID("provi"): ChainState{ + Proposals: &map[uint]Proposal{ + 1: ConsumerProposal{ + Deposit: 10000001, + Chain: chainID("democ"), + SpawnTime: 0, + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + Status: "PROPOSAL_STATUS_PASSED", + }, + }, + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9499999998, + validatorID("bob"): 9500000002, + }, + }, + }, + }, + { + action: startConsumerChainAction{ + consumerChain: chainID("democ"), + providerChain: chainID("provi"), + genesisChanges: ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"50\"", + validators: []StartChainValidator{ + {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, + }, + }, + state: State{ + chainID("provi"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9499999998, + validatorID("bob"): 9500000002, + }, + }, + chainID("democ"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 10000000000, + validatorID("bob"): 10000000000, + }, + }, + }, + }, + { + action: SendTokensAction{ + chain: chainID("democ"), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 1, + }, + state: State{ + chainID("democ"): ChainState{ + // Tx on consumer chain should not go through before ICS channel is setup + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 10000000000, + validatorID("bob"): 10000000000, + }, + }, + }, + }, + { + action: addIbcConnectionAction{ + chainA: chainID("democ"), + chainB: chainID("provi"), + clientA: 0, + clientB: 0, + order: "ordered", + }, + state: State{}, + }, + { + action: addIbcChannelAction{ + chainA: chainID("democ"), + chainB: chainID("provi"), + connectionA: 0, + portA: "consumer", + portB: "provider", + order: "ordered", + }, + state: State{}, + }, + { + action: transferChannelCompleteAction{ + chainA: chainID("democ"), + chainB: chainID("provi"), + connectionA: 0, + portA: "transfer", + portB: "transfer", + order: "unordered", + channelA: 1, + channelB: 1, + }, + state: State{}, + }, + { + action: delegateTokensAction{ + chain: chainID("provi"), + from: validatorID("alice"), + to: validatorID("alice"), + amount: 11000000, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID("democ"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 500, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: SendTokensAction{ + chain: chainID("democ"), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 1, + }, + state: State{ + chainID("democ"): ChainState{ + // Tx should not go through, ICS channel is not setup until first VSC packet has been relayed to consumer + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 10000000000, + validatorID("bob"): 10000000000, + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, + }, + state: State{ + chainID("democ"): ChainState{ + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: SendTokensAction{ + chain: chainID("democ"), + from: validatorID("alice"), + to: validatorID("bob"), + amount: 1, + }, + state: State{ + chainID("democ"): ChainState{ + // Now tx should execute + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9999999999, + validatorID("bob"): 10000000001, + }, + }, + }, + }, + // sanity checks end here + { + action: registerRepresentAction{ + chain: chainID("democ"), + represents: []validatorID{validatorID("alice"), validatorID("bob")}, + stakes: []uint{100000000, 40000000}, + }, + state: State{ + chainID("democ"): ChainState{ + RepresentPowers: &map[validatorID]uint{ + validatorID("alice"): 100000000, + validatorID("bob"): 40000000, + }, + }, + }, + }, + { + action: delegateTokensAction{ + chain: chainID("democ"), + from: validatorID("carol"), + to: validatorID("alice"), + amount: 500000, + }, + state: State{ + chainID("democ"): ChainState{ + RepresentPowers: &map[validatorID]uint{ + validatorID("alice"): 100500000, + validatorID("bob"): 40000000, + }, + // Check that delegating on gov-consumer does not change validator powers + ValPowers: &map[validatorID]uint{ + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + }, + }, + { + action: submitParamChangeProposalAction{ + chain: chainID("democ"), + from: validatorID("alice"), + deposit: 10000001, + subspace: "staking", + key: "MaxValidators", + value: 105, + }, + state: State{ + chainID("democ"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9889999998, + validatorID("bob"): 9960000001, + }, + Proposals: &map[uint]Proposal{ + 1: ParamsProposal{ + Deposit: 10000001, + Status: "PROPOSAL_STATUS_VOTING_PERIOD", + Subspace: "staking", + Key: "MaxValidators", + Value: "105", + }, + }, + }, + }, + }, + { + action: voteGovProposalAction{ + chain: chainID("democ"), + from: []validatorID{validatorID("alice"), validatorID("bob")}, + vote: []string{"yes", "no"}, + propNumber: 1, + }, + state: State{ + chainID("democ"): ChainState{ + ValBalances: &map[validatorID]uint{ + validatorID("alice"): 9899999999, + validatorID("bob"): 9960000001, + }, + Params: &([]Param{{Subspace: "staking", Key: "MaxValidators", Value: "105"}}), + }, + }, + }, +} diff --git a/x/ccv/democracy/democracy_test.go b/x/ccv/democracy/democracy_test.go index b59cd86d8e..c3dafeda8f 100644 --- a/x/ccv/democracy/democracy_test.go +++ b/x/ccv/democracy/democracy_test.go @@ -1,5 +1,6 @@ package democracy_test +// TODO Ethernal: move to e2e folder, remove commented code import ( "bytes" "fmt"