Skip to content

Commit

Permalink
Chore: port ConsumerRemovalProposal handler to main (#429)
Browse files Browse the repository at this point in the history
* Feat: add consumer removal proposal to proposal handler

* remove comment

* add integration tests

* update integration tests

* Delete .yarn-integrity

* update tests after reviews

* nits

* other nit, good to approve

Co-authored-by: Matija Salopek <matija.salopek994@gmail.com>
Co-authored-by: Shawn Marshall-Spitzbart <44221603+smarshall-spitzbart@users.noreply.github.com>
Co-authored-by: MSalopek <35486649+MSalopek@users.noreply.github.com>
Co-authored-by: Jehan <jehan.tremback@gmail.com>
  • Loading branch information
5 people authored Nov 4, 2022
1 parent 36610e9 commit 9241d1f
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 22 deletions.
3 changes: 2 additions & 1 deletion app/provider/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ var (
upgradeclient.CancelProposalHandler,
ibcclientclient.UpdateClientProposalHandler,
ibcclientclient.UpgradeProposalHandler,
ibcproviderclient.ProposalHandler,
ibcproviderclient.ConsumerAdditionProposalHandler,
ibcproviderclient.ConsumerRemovalProposalHandler,
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
Expand Down
63 changes: 61 additions & 2 deletions tests/integration/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func (tr TestRun) submitTextProposal(
}
}

type submitConsumerProposalAction struct {
type submitConsumerAdditionProposalAction struct {
chain chainID
from validatorID
deposit uint
Expand All @@ -194,7 +194,7 @@ type submitConsumerProposalAction struct {
}

func (tr TestRun) submitConsumerAdditionProposal(
action submitConsumerProposalAction,
action submitConsumerAdditionProposalAction,
verbose bool,
) {
spawnTime := tr.containerConfig.now.Add(time.Duration(action.spawnTime) * time.Millisecond)
Expand Down Expand Up @@ -247,6 +247,65 @@ func (tr TestRun) submitConsumerAdditionProposal(
}
}

type submitConsumerRemovalProposalAction struct {
chain chainID
from validatorID
deposit uint
consumerChain chainID
stopTimeOffset time.Duration // offset from time.Now()
}

func (tr TestRun) submitConsumerRemovalProposal(
action submitConsumerRemovalProposalAction,
verbose bool,
) {
stopTime := tr.containerConfig.now.Add(action.stopTimeOffset)
prop := client.ConsumerRemovalProposalJSON{
Title: fmt.Sprintf("Stop the %v chain", action.consumerChain),
Description: "It was a great chain",
ChainId: string(tr.chainConfigs[action.consumerChain].chainId),
StopTime: stopTime,
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, "/temp-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", "consumer-removal",
"/temp-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 submitParamChangeProposalAction struct {
chain chainID
from validatorID
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ func (tr *TestRun) runStep(step Step, verbose bool) {
tr.sendTokens(action, verbose)
case submitTextProposalAction:
tr.submitTextProposal(action, verbose)
case submitConsumerProposalAction:
case submitConsumerAdditionProposalAction:
tr.submitConsumerAdditionProposal(action, verbose)
case submitConsumerRemovalProposalAction:
tr.submitConsumerRemovalProposal(action, verbose)
case submitParamChangeProposalAction:
tr.submitParamChangeProposal(action, verbose)
case voteGovProposalAction:
Expand Down
68 changes: 64 additions & 4 deletions tests/integration/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type ChainState struct {
RepresentativePowers *map[validatorID]uint
Params *[]Param
Rewards *Rewards
ConsumerChains *map[chainID]bool
}

type Proposal interface {
Expand All @@ -36,14 +37,25 @@ type TextProposal struct {

func (p TextProposal) isProposal() {}

type ConsumerProposal struct {
type ConsumerAdditionProposal struct {
Deposit uint
Chain chainID
SpawnTime int
InitialHeight clienttypes.Height
Status string
}

func (p ConsumerAdditionProposal) isProposal() {}

type ConsumerRemovalProposal struct {
Deposit uint
Chain chainID
StopTime int
Status string
}

func (p ConsumerRemovalProposal) isProposal() {}

type Rewards struct {
IsRewarded map[validatorID]bool
//if true it will calculate if the validator/delegator is rewarded between 2 successive blocks,
Expand All @@ -54,8 +66,6 @@ type Rewards struct {
IsNativeDenom bool
}

func (p ConsumerProposal) isProposal() {}

type ParamsProposal struct {
Deposit uint
Status string
Expand Down Expand Up @@ -115,6 +125,11 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState
chainState.Rewards = &rewards
}

if modelState.ConsumerChains != nil {
chains := tr.getConsumerChains(chain)
chainState.ConsumerChains = &chains
}

return chainState
}

Expand Down Expand Up @@ -315,7 +330,7 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal {
}
}

return ConsumerProposal{
return ConsumerAdditionProposal{
Deposit: uint(deposit),
Status: status,
Chain: chain,
Expand All @@ -325,6 +340,25 @@ func (tr TestRun) getProposal(chain chainID, proposal uint) Proposal {
RevisionHeight: gjson.Get(string(bz), `content.initial_height.revision_height`).Uint(),
},
}
case "/interchain_security.ccv.provider.v1.ConsumerRemovalProposal":
chainId := gjson.Get(string(bz), `content.chain_id`).String()
stopTime := gjson.Get(string(bz), `content.stop_time`).Time().Sub(tr.containerConfig.now)

var chain chainID
for i, conf := range tr.chainConfigs {
if string(conf.chainId) == chainId {
chain = i
break
}
}

return ConsumerRemovalProposal{
Deposit: uint(deposit),
Status: status,
Chain: chain,
StopTime: int(stopTime.Milliseconds()),
}

case "/cosmos.params.v1beta1.ParameterChangeProposal":
return ParamsProposal{
Deposit: uint(deposit),
Expand Down Expand Up @@ -439,6 +473,32 @@ func (tr TestRun) getParam(chain chainID, param Param) string {
return value.String()
}

// getConsumerChains returns a list of consumer chains that're being secured by the provider chain,
// determined by querying the provider chain.
func (tr TestRun) getConsumerChains(chain chainID) map[chainID]bool {
//#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments.
cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName,

"query", "provider", "list-consumer-chains",
`--node`, tr.getQueryNode(chain),
`-o`, `json`,
)

bz, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err, "\n", string(bz))
}

arr := gjson.Get(string(bz), "chains").Array()
chains := make(map[chainID]bool)
for _, c := range arr {
id := c.Get("chain_id").String()
chains[chainID(id)] = true
}

return chains
}

func (tr TestRun) getValidatorNode(chain chainID, validator validatorID) string {
return "tcp://" + tr.getValidatorIP(chain, validator) + ":26658"
}
Expand Down
1 change: 1 addition & 0 deletions tests/integration/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var happyPathSteps = concatSteps(
stepsDelegate("consu"),
stepsUnbondRedelegate("consu"),
stepsDowntime("consu"),
stepsStopChain("consu"),
)

var democracySteps = concatSteps(
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/steps_start_chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step {
},
},
{
action: submitConsumerProposalAction{
action: submitConsumerAdditionProposalAction{
chain: chainID("provi"),
from: validatorID("alice"),
deposit: 10000001,
Expand All @@ -61,7 +61,7 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step {
validatorID("bob"): 9500000002,
},
Proposals: &map[uint]Proposal{
1: ConsumerProposal{
1: ConsumerAdditionProposal{
Deposit: 10000001,
Chain: chainID(consumerName),
SpawnTime: 0,
Expand All @@ -82,7 +82,7 @@ func stepsStartChains(consumerName string, setupTransferChan bool) []Step {
state: State{
chainID("provi"): ChainState{
Proposals: &map[uint]Proposal{
1: ConsumerProposal{
1: ConsumerAdditionProposal{
Deposit: 10000001,
Chain: chainID(consumerName),
SpawnTime: 0,
Expand Down
60 changes: 60 additions & 0 deletions tests/integration/steps_stop_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import "time"

// submits a consumer-removal proposal and removes the chain
func stepsStopChain(consumerName string) []Step {
s := []Step{
{
action: submitConsumerRemovalProposalAction{
chain: chainID("provi"),
from: validatorID("bob"),
deposit: 10000001,
consumerChain: chainID(consumerName),
stopTimeOffset: 0 * time.Millisecond,
},
state: State{
chainID("provi"): ChainState{
ValBalances: &map[validatorID]uint{
validatorID("bob"): 9490000001,
},
Proposals: &map[uint]Proposal{
2: ConsumerRemovalProposal{
Deposit: 10000001,
Chain: chainID(consumerName),
StopTime: 0,
Status: "PROPOSAL_STATUS_VOTING_PERIOD",
},
},
ConsumerChains: &map[chainID]bool{"consu": true}, // consumer chain not yet removed
},
},
},
{
action: voteGovProposalAction{
chain: chainID("provi"),
from: []validatorID{validatorID("alice"), validatorID("bob"), validatorID("carol")},
vote: []string{"yes", "yes", "yes"},
propNumber: 2,
},
state: State{
chainID("provi"): ChainState{
Proposals: &map[uint]Proposal{
2: ConsumerRemovalProposal{
Deposit: 10000001,
Chain: chainID(consumerName),
StopTime: 0,
Status: "PROPOSAL_STATUS_PASSED",
},
},
ValBalances: &map[validatorID]uint{
validatorID("bob"): 9500000002,
},
ConsumerChains: &map[chainID]bool{}, // Consumer chain is now removed
},
},
},
}

return s
}
Loading

0 comments on commit 9241d1f

Please sign in to comment.