Skip to content

Commit

Permalink
Fix e2e tests + PSS e2e tests use permissionless
Browse files Browse the repository at this point in the history
  • Loading branch information
bermuell committed Aug 29, 2024
1 parent 29b1bf4 commit 91f0f0e
Show file tree
Hide file tree
Showing 9 changed files with 1,956 additions and 579 deletions.
668 changes: 462 additions & 206 deletions tests/e2e/actions.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions tests/e2e/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ var hermesTemplates = map[string]string{
// type aliases for shared types from e2e package
type (
ChainID = e2e.ChainID
ConsumerID = e2e.ConsumerID
ValidatorID = e2e.ValidatorID
ValidatorConfig = e2e.ValidatorConfig
ChainConfig = e2e.ChainConfig
Expand Down Expand Up @@ -122,6 +123,7 @@ type TestConfig struct {
timeOffset time.Duration
transformGenesis bool
name string
Consumer2ChainID map[ConsumerID]ChainID // dynamic mapping of
}

// Initialize initializes the TestConfig instance by setting the runningChains field to an empty map.
Expand Down
63 changes: 42 additions & 21 deletions tests/e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"flag"
"fmt"
"log"
"log/slog"
"os"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -246,6 +248,12 @@ var stepChoices = map[string]StepChoice{
description: "test minting without inactive validators as a sanity check",
testConfig: MintTestCfg,
},
"permissionless-ics": {
name: "permissionless-ics",
steps: stepsPermissionlessICS(),
description: "test permissionless ics",
testConfig: DefaultTestCfg,
},
"inactive-vals-outside-max-validators": {
name: "inactive-vals-outside-max-validators",
steps: stepsInactiveValsTopNReproduce(),
Expand Down Expand Up @@ -334,27 +342,27 @@ func getTestCases(selectedPredefinedTests, selectedTestFiles TestSet, providerVe
// Run default tests if no test cases were selected
if len(selectedPredefinedTests) == 0 && len(selectedTestFiles) == 0 {
selectedPredefinedTests = TestSet{
"changeover",
"happy-path",
"democracy-reward",
"democracy",
"slash-throttle",
"consumer-double-sign",
"consumer-misbehaviour",
"consumer-double-downtime",
"partial-set-security-opt-in",
"partial-set-security-top-n",
"partial-set-security-validator-set-cap",
"partial-set-security-validators-power-cap",
"partial-set-security-validators-allowlisted",
"partial-set-security-validators-denylisted",
"partial-set-security-modification-proposal",
"active-set-changes",
"inactive-provider-validators-on-consumer",
"inactive-vals-topN",
"inactive-provider-validators-governance",
"min-stake",
"inactive-vals-mint",
"changeover", // PASSED
"happy-path", // PASSED
"democracy-reward", // PASSED
"democracy", // PASSED
"slash-throttle", // PASSED
"consumer-double-sign", // TODO PERMISSIONLESS: failing
"consumer-misbehaviour", // TODO PERMISSIONLESS: failing
"consumer-double-downtime", // PASSED
"partial-set-security-opt-in", // PASSED
"partial-set-security-top-n", // PASSED
"partial-set-security-validator-set-cap", // PASSED
"partial-set-security-validators-power-cap", // PASSED
"partial-set-security-validators-allowlisted", // PASSED
"partial-set-security-validators-denylisted", // PASSED
"partial-set-security-modification-proposal", // TODO PERMISSIONLESS: failing
"active-set-changes", // PASSED
"inactive-provider-validators-on-consumer", // PASSED
"inactive-vals-topN", // TODO PERMISSIONLESS: failing
"inactive-provider-validators-governance", // PASSED
"min-stake", // PASSED
"inactive-vals-mint", // PASSED
}
if includeMultiConsumer != nil && *includeMultiConsumer {
selectedPredefinedTests = append(selectedPredefinedTests, "multiconsumer")
Expand Down Expand Up @@ -483,6 +491,18 @@ func createTestRunners(testCases []testStepsWithConfig) []TestRunner {
return runners
}

func SetupLogger() {
opts := &slog.HandlerOptions{
AddSource: false,
Level: slog.LevelInfo,
}
if *verbose {
opts.Level = slog.LevelDebug
}
logger := slog.New(slog.NewTextHandler(os.Stdout, opts))
slog.SetDefault(logger)
}

func executeTests(runners []TestRunner) error {
if parallel != nil && *parallel {
fmt.Println("=============== running all tests in parallel ===============")
Expand Down Expand Up @@ -596,6 +616,7 @@ func main() {
log.Fatalf("Error parsing command arguments %s\n", err)
}

//SetupLogger()
testCases := getTestCases(selectedTests, selectedTestfiles, providerVersions, consumerVersions)
testRunners := createTestRunners(testCases)
defer deleteTargets(testRunners)
Expand Down
87 changes: 70 additions & 17 deletions tests/e2e/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
e2e "github.com/cosmos/interchain-security/v5/tests/e2e/testlib"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
"github.com/kylelemons/godebug/pretty"
"github.com/tidwall/gjson"
"gopkg.in/yaml.v2"
Expand All @@ -38,7 +39,7 @@ type State map[ChainID]ChainState

type Chain struct {
target e2e.TargetDriver
testConfig TestConfig
testConfig *TestConfig
}

func (tr Chain) GetChainState(chain ChainID, modelState ChainState) ChainState {
Expand Down Expand Up @@ -335,7 +336,7 @@ func intPtr(i int) *int {
}

type Commands struct {
containerConfig ContainerConfig // FIXME only needed for 'Now' time tracking
containerConfig *ContainerConfig
validatorConfigs map[ValidatorID]ValidatorConfig
chainConfigs map[ChainID]ChainConfig
target e2e.PlatformDriver
Expand Down Expand Up @@ -415,6 +416,10 @@ func (tr Commands) GetReward(chain ChainID, validator ValidatorID, blockHeight u
return gjson.Get(string(bz), denomCondition).Float()
}

/* func parseProposalMsg(rawMsg gjson.Result) Proposal {
}
*/
// interchain-securityd query gov proposals
func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal {
noProposalRegex := regexp.MustCompile(`doesn't exist: key not found`)
Expand All @@ -440,6 +445,10 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal {
log.Fatal(err, "\n", propRaw)
}

messages := gjson.Get(propRaw, `proposal.messages`)
for _, msg := range messages.Array() {
fmt.Println("msg val", msg)
}
// for legacy proposal types submitted using "tx submit-legacyproposal" (cosmos-sdk/v1/MsgExecLegacyContent)
propType := gjson.Get(propRaw, `proposal.messages.0.value.content.type`).String()
rawContent := gjson.Get(propRaw, `proposal.messages.0.value.content.value`)
Expand All @@ -465,6 +474,28 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal {
Title: title,
Description: description,
}
case "/interchain_security.ccv.provider.v1.MsgUpdateConsumer":
fmt.Printf("@@@@ container.Now in state %s\n", tr.containerConfig.Now.String())

spawnTime := rawContent.Get("initialization_parameters.spawn_time").Time().Sub(tr.containerConfig.Now)
consumerId := rawContent.Get("consumer_id").String()
consumer_chain_id := ChainID("")
for _, chainCfg := range tr.chainConfigs {
if chainCfg.ConsumerId == e2e.ConsumerID(consumerId) {
consumer_chain_id = chainCfg.ChainId
}
}

Check warning

Code scanning / CodeQL

Iteration over map Warning test

Iteration over map may be a possible source of non-determinism
return e2e.ConsumerAdditionProposal{
Deposit: uint(deposit),
Chain: consumer_chain_id,
Status: status,
SpawnTime: int(spawnTime.Milliseconds()),
InitialHeight: clienttypes.Height{
RevisionNumber: rawContent.Get("initialization_parameters.initial_height.revision_number").Uint(),
RevisionHeight: rawContent.Get("initialization_parameters.initial_height.revision_height").Uint(),
},
}

case "/interchain_security.ccv.provider.v1.MsgConsumerAddition":
chainId := rawContent.Get("chain_id").String()
spawnTime := rawContent.Get("spawn_time").Time().Sub(tr.containerConfig.Now)
Expand Down Expand Up @@ -498,13 +529,13 @@ func (tr Commands) GetProposal(chain ChainID, proposal uint) Proposal {
Title: title,
Type: "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal",
}
case "/interchain_security.ccv.provider.v1.MsgConsumerRemoval":
chainId := rawContent.Get("chain_id").String()
case "/interchain_security.ccv.provider.v1.MsgRemoveConsumer":
consumerID := rawContent.Get("consumer_id").String()
stopTime := rawContent.Get("stop_time").Time().Sub(tr.containerConfig.Now)

var chain ChainID
for i, conf := range tr.chainConfigs {
if string(conf.ChainId) == chainId {
if string(conf.ConsumerId) == consumerID {
chain = i
break
}
Expand Down Expand Up @@ -738,27 +769,35 @@ func (tr Commands) GetConsumerChains(chain ChainID) map[ChainID]bool {
`-o`, `json`,
)

// TODO PERMISSIONLESS; check if this should only list launched consumer chains
bz, err := cmd.CombinedOutput()
if err != nil {
fmt.Println("@@@ failed getting consumer chains:", cmd)
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
phase := c.Get("phase").String()
if phase == types.ConsumerPhase_name[int32(types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)] ||
phase == types.ConsumerPhase_name[int32(types.ConsumerPhase_CONSUMER_PHASE_REGISTERED)] ||
phase == types.ConsumerPhase_name[int32(types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED)] {
id := c.Get("chain_id").String()
chains[ChainID(id)] = true
}
}

return chains
}

func (tr Commands) GetConsumerAddress(consumerChain ChainID, validator ValidatorID) string {
binaryName := tr.chainConfigs[ChainID("provi")].BinaryName
consumer_id := tr.chainConfigs[ChainID(consumerChain)].ConsumerId
cmd := tr.target.ExecCommand(binaryName,

"query", "provider", "validator-consumer-key",
string(consumerChain), tr.validatorConfigs[validator].ValconsAddress,
string(consumer_id), tr.validatorConfigs[validator].ValconsAddress,
`--node`, tr.GetQueryNode(ChainID("provi")),
`-o`, `json`,
)
Expand All @@ -773,10 +812,12 @@ func (tr Commands) GetConsumerAddress(consumerChain ChainID, validator Validator

func (tr Commands) GetProviderAddressFromConsumer(consumerChain ChainID, validator ValidatorID) string {
binaryName := tr.chainConfigs[ChainID("provi")].BinaryName
consumer_id := tr.chainConfigs[ChainID(consumerChain)].ConsumerId

cmd := tr.target.ExecCommand(binaryName,

"query", "provider", "validator-provider-key",
string(consumerChain), tr.validatorConfigs[validator].ConsumerValconsAddressOnProvider,
string(consumer_id), tr.validatorConfigs[validator].ConsumerValconsAddressOnProvider,
`--node`, tr.GetQueryNode(ChainID("provi")),
`-o`, `json`,
)
Expand Down Expand Up @@ -898,7 +939,11 @@ func (tr Commands) GetHasToValidate(
arr := gjson.Get(string(bz), "consumer_chain_ids").Array()
chains := []ChainID{}
for _, c := range arr {
chains = append(chains, ChainID(c.String()))
for _, chain := range tr.chainConfigs {
if chain.ConsumerId == ConsumerID(c.String()) {
chains = append(chains, chain.ChainId)
}
}

Check warning

Code scanning / CodeQL

Iteration over map Warning test

Iteration over map may be a possible source of non-determinism
}

return chains
Expand Down Expand Up @@ -969,20 +1014,26 @@ func (tr Commands) GetTrustedHeight(

func (tr Commands) GetProposedConsumerChains(chain ChainID) []string {
binaryName := tr.chainConfigs[chain].BinaryName
bz, err := tr.target.ExecCommand(binaryName,
"query", "provider", "list-proposed-consumer-chains",
cmd := tr.target.ExecCommand(binaryName,
"query", "provider", "list-consumer-chains",
`--node`, tr.GetQueryNode(chain),
`-o`, `json`,
).CombinedOutput()
)
bz, err := cmd.CombinedOutput()
if err != nil {
fmt.Println("@@@ failed getting proposed chains:", cmd)
log.Fatal(err, "\n", string(bz))
}

arr := gjson.Get(string(bz), "proposedChains").Array()
arr := gjson.Get(string(bz), "chains").Array()
chains := []string{}
for _, c := range arr {
cid := c.Get("chainID").String()
chains = append(chains, cid)
cid := c.Get("chain_id").String()
phase := c.Get("phase").String()
if phase == types.ConsumerPhase_name[int32(types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)] ||
phase == types.ConsumerPhase_name[int32(types.ConsumerPhase_CONSUMER_PHASE_REGISTERED)] {
chains = append(chains, cid)
}
}

return chains
Expand Down Expand Up @@ -1013,9 +1064,11 @@ func (tr Commands) GetQueryNodeIP(chain ChainID) string {
// GetConsumerCommissionRate returns the commission rate of the given validator on the given consumerChain
func (tr Commands) GetConsumerCommissionRate(consumerChain ChainID, validator ValidatorID) float64 {
binaryName := tr.chainConfigs[ChainID("provi")].BinaryName
consumerID := tr.chainConfigs[consumerChain].ConsumerId

cmd := tr.target.ExecCommand(binaryName,
"query", "provider", "validator-consumer-commission-rate",
string(consumerChain), tr.validatorConfigs[validator].ValconsAddress,
string(consumerID), tr.validatorConfigs[validator].ValconsAddress,
`--node`, tr.GetQueryNode(ChainID("provi")),
`-o`, `json`,
)
Expand Down
Loading

0 comments on commit 91f0f0e

Please sign in to comment.