Skip to content

Commit

Permalink
testing: e2e tests for soft opt out (#857)
Browse files Browse the repository at this point in the history
* add steps for opt out testing

* comments

* set soft opt out thresh in consumer genesis

---------

Co-authored-by: Marius Poke <marius.poke@posteo.de>
  • Loading branch information
shaspitz and mpoke authored Apr 19, 2023
1 parent 7bfb7b5 commit 6089b61
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 12 deletions.
9 changes: 5 additions & 4 deletions tests/e2e/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,10 @@ func (tr TestRun) voteGovProposal(
}

type startConsumerChainAction struct {
consumerChain chainID
providerChain chainID
validators []StartChainValidator
consumerChain chainID
providerChain chainID
validators []StartChainValidator
genesisChanges string
}

func (tr TestRun) startConsumerChain(
Expand Down Expand Up @@ -545,7 +546,7 @@ func (tr TestRun) startConsumerChain(
consumerGenesis := ".app_state.ccvconsumer = " + string(bz)
consumerGenesisChanges := tr.chainConfigs[action.consumerChain].genesisChanges
if consumerGenesisChanges != "" {
consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges
consumerGenesis = consumerGenesis + " | " + consumerGenesisChanges + " | " + action.genesisChanges
}

tr.startChain(StartChainAction{
Expand Down
63 changes: 57 additions & 6 deletions tests/e2e/step_delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,69 @@ func stepsUnbond(consumerName string) []Step {
}
}

// stepsRedelegate tests redelegation and resulting validator power changes.
func stepsRedelegate(consumerName string) []Step {
// stepsRedelegateForOptOut tests redelegation, and sets up voting powers s.t
// alice will have less than 5% of the total voting power. This is needed to
// test opt-out functionality.
func stepsRedelegateForOptOut(consumerName string) []Step {
return []Step{
{
action: redelegateTokensAction{
chain: chainID("provi"),
src: validatorID("alice"),
dst: validatorID("carol"),
txSender: validatorID("alice"),
// Leave alice with majority stake so non-faulty validators maintain more than
amount: 450000000,
},
state: State{
chainID("provi"): ChainState{
ValPowers: &map[validatorID]uint{
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
chainID(consumerName): ChainState{
ValPowers: &map[validatorID]uint{
// Voting power changes not seen by consumer yet
validatorID("alice"): 510,
validatorID("bob"): 500,
validatorID("carol"): 500,
},
},
},
},
{
action: relayPacketsAction{
chain: chainID("provi"),
port: "provider",
channel: 0,
},
state: State{
chainID(consumerName): ChainState{
ValPowers: &map[validatorID]uint{
// Now power changes are seen by consumer
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
},
},
}
}

// stepsRedelegate tests redelegation and resulting validator power changes.
func stepsRedelegate(consumerName string) []Step {
return []Step{
{
action: redelegateTokensAction{
chain: chainID("provi"),
src: validatorID("carol"),
dst: validatorID("alice"),
txSender: validatorID("carol"),
// redelegate s.t. alice has majority stake so non-faulty validators maintain more than
// 2/3 voting power during downtime tests below, avoiding chain halt
amount: 1000000,
amount: 449000000,
},
state: State{
chainID("provi"): ChainState{
Expand All @@ -152,9 +203,9 @@ func stepsRedelegate(consumerName string) []Step {
chainID(consumerName): ChainState{
ValPowers: &map[validatorID]uint{
// Voting power changes not seen by consumer yet
validatorID("alice"): 510,
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 500,
validatorID("carol"): 950,
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ var happyPathSteps = concatSteps(
stepsDelegate("consu"),
stepsAssignConsumerKeyOnStartedChain("consu", "bob"),
stepsUnbond("consu"),
stepsRedelegateForOptOut("consu"),
stepsDowntimeWithOptOut("consu"),
stepsRedelegate("consu"),
stepsDowntime("consu"),
stepsRejectEquivocationProposal("consu", 2), // prop to tombstone bob is rejected
Expand Down
57 changes: 55 additions & 2 deletions tests/e2e/steps_downtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,62 @@ func stepsDowntime(consumerName string) []Step {
},
},
},
}
}

// TODO: Test full unbonding functionality, tracked as: https://github.com/cosmos/interchain-security/issues/311

// stepsDowntimeWithOptOut returns steps validating that alice can incur downtime
// and not be slashed/jailed, since her voting power is less than 5% of the total.
//
// Note: 60 / (60 + 500 + 950) ~= 0.04
func stepsDowntimeWithOptOut(consumerName string) []Step {
return []Step{
{
action: downtimeSlashAction{
chain: chainID(consumerName),
validator: validatorID("alice"),
},
state: State{
// powers not affected on either chain
chainID("provi"): ChainState{
ValPowers: &map[validatorID]uint{
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
chainID(consumerName): ChainState{
ValPowers: &map[validatorID]uint{
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
},
},
{
action: relayPacketsAction{
chain: chainID("provi"),
port: "provider",
channel: 0,
},
state: State{
chainID("provi"): ChainState{
ValPowers: &map[validatorID]uint{
// alice is not slashed or jailed due to soft opt out
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
chainID(consumerName): ChainState{
ValPowers: &map[validatorID]uint{
validatorID("alice"): 60,
validatorID("bob"): 500,
validatorID("carol"): 950,
},
},
},
},
}
}

Expand Down
6 changes: 6 additions & 0 deletions tests/e2e/steps_start_chains.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint
{id: validatorID("alice"), stake: 500000000, allocation: 10000000000},
{id: validatorID("carol"), stake: 500000000, allocation: 10000000000},
},
// For consumers that're launching with the provider being on an earlier version
// of ICS before the soft opt-out threshold was introduced, we need to set the
// soft opt-out threshold to 0.05 in the consumer genesis to ensure that the
// consumer binary doesn't panic. Sdk requires that all params are set to valid
// values from the genesis file.
genesisChanges: ".app_state.ccvconsumer.params.soft_opt_out_threshold = \"0.05\"",
},
state: State{
chainID("provi"): ChainState{
Expand Down

0 comments on commit 6089b61

Please sign in to comment.