Skip to content

Commit

Permalink
added initial provider interchain tests
Browse files Browse the repository at this point in the history
  • Loading branch information
stana-miric committed Oct 18, 2024
1 parent cdb8166 commit 8e0d617
Show file tree
Hide file tree
Showing 10 changed files with 3,051 additions and 0 deletions.
253 changes: 253 additions & 0 deletions tests/interchain/chainsuite/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
package chainsuite

import (
"context"
"encoding/json"
"fmt"
"strconv"
"sync"

sdkmath "cosmossdk.io/math"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"golang.org/x/sync/errgroup"
)

// This moniker is hardcoded into interchaintest
const validatorMoniker = "validator"

type Chain struct {
*cosmos.CosmosChain
ValidatorWallets []ValidatorWallet
RelayerWallet ibc.Wallet
}

type ValidatorWallet struct {
Moniker string
Address string
ValoperAddress string
}

func chainFromCosmosChain(cosmos *cosmos.CosmosChain, relayerWallet ibc.Wallet) (*Chain, error) {
c := &Chain{CosmosChain: cosmos}
wallets, err := getValidatorWallets(context.Background(), c)
if err != nil {
return nil, err
}
c.ValidatorWallets = wallets
c.RelayerWallet = relayerWallet
return c, nil
}

// CreateProviderChain creates a single new chain with the given version and returns the chain object.
func CreateProviderChain(ctx context.Context, testName interchaintest.TestName, spec *interchaintest.ChainSpec) (*Chain, error) {
cf := interchaintest.NewBuiltinChainFactory(
GetLogger(ctx),
[]*interchaintest.ChainSpec{spec},
)

chains, err := cf.Chains(testName.Name())
if err != nil {
return nil, err
}
cosmosChain := chains[0].(*cosmos.CosmosChain)
relayerWallet, err := cosmosChain.BuildRelayerWallet(ctx, "relayer-"+cosmosChain.Config().ChainID)
if err != nil {
return nil, err
}

ic := interchaintest.NewInterchain().AddChain(cosmosChain, ibc.WalletAmount{
Address: relayerWallet.FormattedAddress(),
Denom: cosmosChain.Config().Denom,
Amount: sdkmath.NewInt(TotalValidatorFunds),
})

dockerClient, dockerNetwork := GetDockerContext(ctx)

if err := ic.Build(ctx, GetRelayerExecReporter(ctx), interchaintest.InterchainBuildOptions{
Client: dockerClient,
NetworkID: dockerNetwork,
TestName: testName.Name(),
}); err != nil {
return nil, err
}

chain, err := chainFromCosmosChain(cosmosChain, relayerWallet)
if err != nil {
return nil, err
}
return chain, nil
}

func getValidatorWallets(ctx context.Context, chain *Chain) ([]ValidatorWallet, error) {
wallets := make([]ValidatorWallet, len(chain.Validators))
lock := new(sync.Mutex)
eg := new(errgroup.Group)
for i := 0; i < len(chain.Validators); i++ {
i := i
eg.Go(func() error {
// This moniker is hardcoded into the chain's genesis process.
moniker := validatorMoniker
address, err := chain.Validators[i].KeyBech32(ctx, moniker, "acc")
if err != nil {
return err
}
valoperAddress, err := chain.Validators[i].KeyBech32(ctx, moniker, "val")
if err != nil {
return err
}
lock.Lock()
defer lock.Unlock()
wallets[i] = ValidatorWallet{
Moniker: moniker,
Address: address,
ValoperAddress: valoperAddress,
}
return nil
})
}
if err := eg.Wait(); err != nil {
return nil, err
}
return wallets, nil
}

func (c *Chain) WaitForProposalStatus(ctx context.Context, proposalID string, status govv1.ProposalStatus) error {
propID, err := strconv.ParseInt(proposalID, 10, 64)
if err != nil {
return err
}
chainHeight, err := c.Height(ctx)
if err != nil {
return err
}
maxHeight := chainHeight + UpgradeDelta
_, err = cosmos.PollForProposalStatusV1(ctx, c.CosmosChain, chainHeight, maxHeight, uint64(propID), status)
return err
}

func (c *Chain) VoteForProposal(ctx context.Context, proposalID string, vote string) error {
propID, err := strconv.ParseInt(proposalID, 10, 64)
if err != nil {
return err
}
err = c.VoteOnProposalAllValidators(ctx, uint64(propID), vote)
if err != nil {
return err
}

return nil
}

func (c *Chain) SubmitAndVoteForProposal(ctx context.Context, prop cosmos.TxProposalv1, vote string) (string, error) {

propTx, err := c.SubmitProposal(ctx, validatorMoniker, prop)
if err != nil {
return "", err
}

if err := c.WaitForProposalStatus(ctx, propTx.ProposalID, govv1.StatusVotingPeriod); err != nil {
return "", err
}

if err := c.VoteForProposal(ctx, propTx.ProposalID, vote); err != nil {
return "", err
}

return propTx.ProposalID, nil
}

// builds proposal message, submits, votes and wait for proposal expected status
func (c *Chain) ExecuteProposalMsg(ctx context.Context, proposalMsg cosmos.ProtoMessage, proposer string, chainName string, vote string, expectedStatus govv1.ProposalStatus, expedited bool) error {
proposal, err := c.BuildProposal([]cosmos.ProtoMessage{proposalMsg}, chainName, "summary", "", GovMinDepositString, proposer, false)
if err != nil {
return err
}

// submit and vote for the proposal
proposalId, err := c.SubmitAndVoteForProposal(ctx, proposal, vote)
if err != nil {
return err
}

if err = c.WaitForProposalStatus(ctx, proposalId, expectedStatus); err != nil {
return err
}

return nil
}

func (c *Chain) OptIn(ctx context.Context, consumerID string, valIndex int) error {
_, err := c.Validators[valIndex].ExecTx(ctx, validatorMoniker, "provider", "opt-in", consumerID)
return err
}

func (c *Chain) ListConsumerChains(ctx context.Context) (ListConsumerChainsResponse, error) {
queryRes, _, err := c.GetNode().ExecQuery(
ctx,
"provider", "list-consumer-chains",
)
if err != nil {
return ListConsumerChainsResponse{}, err
}

var queryResponse ListConsumerChainsResponse
err = json.Unmarshal([]byte(queryRes), &queryResponse)
if err != nil {
return ListConsumerChainsResponse{}, err
}

return queryResponse, nil
}

func (c *Chain) GetConsumerChain(ctx context.Context, consumerId string) (ConsumerResponse, error) {
queryRes, _, err := c.GetNode().ExecQuery(
ctx,
"provider", "consumer-chain", consumerId,
)
if err != nil {
return ConsumerResponse{}, err
}

var queryResponse ConsumerResponse
err = json.Unmarshal([]byte(queryRes), &queryResponse)
if err != nil {
return ConsumerResponse{}, err
}

return queryResponse, nil
}

func (c *Chain) GetConsumerGenesis(ctx context.Context, consumerId string) (ConsumerGenesisResponse, error) {
queryRes, _, err := c.GetNode().ExecQuery(
ctx,
"provider", "consumer-genesis", consumerId,
)
if err != nil {
return ConsumerGenesisResponse{}, err
}

var queryResponse ConsumerGenesisResponse
err = json.Unmarshal([]byte(queryRes), &queryResponse)
if err != nil {
return ConsumerGenesisResponse{}, err
}

return queryResponse, nil
}

func (c *Chain) GetConsumerChainByChainId(ctx context.Context, chainId string) (ConsumerChain, error) {
chains, err := c.ListConsumerChains(ctx)
if err != nil {
return ConsumerChain{}, err
}

for _, chain := range chains.Chains {
if chain.ChainID == chainId {
return chain, nil
}
}
return ConsumerChain{}, fmt.Errorf("chain not found")
}
55 changes: 55 additions & 0 deletions tests/interchain/chainsuite/chain_spec_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package chainsuite

import (
"strconv"

"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"

"github.com/strangelove-ventures/interchaintest/v8"
)

func GetProviderSpec() *interchaintest.ChainSpec {
fullNodes := FullNodeCount
validators := ValidatorCount

return &interchaintest.ChainSpec{
Name: ProviderChainID,
NumFullNodes: &fullNodes,
NumValidators: &validators,
Version: ProviderImageVersion,
ChainConfig: ibc.ChainConfig{
Type: CosmosChainType,
Bin: ProviderBin,
Bech32Prefix: ProviderBech32Prefix,
Denom: Stake,
GasPrices: GasPrices + Stake,
GasAdjustment: 2.0,
TrustingPeriod: "504h",
ConfigFileOverrides: map[string]any{
"config/config.toml": DefaultConfigToml(),
},
Images: []ibc.DockerImage{{
Repository: ProviderImageName,
UidGid: "1025:1025",
}},
ModifyGenesis: cosmos.ModifyGenesis(providerModifiedGenesis()),
ModifyGenesisAmounts: DefaultGenesisAmounts(Stake),
},
}
}

func providerModifiedGenesis() []cosmos.GenesisKV {
return []cosmos.GenesisKV{
cosmos.NewGenesisKV("app_state.staking.params.unbonding_time", ProviderUnbondingTime.String()),
cosmos.NewGenesisKV("app_state.gov.params.voting_period", GovVotingPeriod.String()),
cosmos.NewGenesisKV("app_state.gov.params.max_deposit_period", GovDepositPeriod.String()),
cosmos.NewGenesisKV("app_state.gov.params.min_deposit.0.denom", Stake),
cosmos.NewGenesisKV("app_state.gov.params.min_deposit.0.amount", strconv.Itoa(GovMinDepositAmount)),
cosmos.NewGenesisKV("app_state.slashing.params.signed_blocks_window", strconv.Itoa(ProviderSlashingWindow)),
cosmos.NewGenesisKV("app_state.slashing.params.downtime_jail_duration", DowntimeJailDuration.String()),
cosmos.NewGenesisKV("app_state.provider.params.slash_meter_replenish_period", ProviderReplenishPeriod),
cosmos.NewGenesisKV("app_state.provider.params.slash_meter_replenish_fraction", ProviderReplenishFraction),
cosmos.NewGenesisKV("app_state.provider.params.blocks_per_epoch", "1"),
}
}
62 changes: 62 additions & 0 deletions tests/interchain/chainsuite/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package chainsuite

import (
"time"

"github.com/strangelove-ventures/interchaintest/v8/testutil"

sdkmath "cosmossdk.io/math"
sdktypes "github.com/cosmos/cosmos-sdk/types"
)

const (
ProviderImageName = "ghcr.io/cosmos/interchain-security"
ProviderImageVersion = "v6.1.0"
ProviderBin = "interchain-security-pd"
ProviderBech32Prefix = "cosmos"
ProviderValOperPrefix = "cosmosvaloper"
ProviderChainID = "ics-provider"
Stake = "stake"
DowntimeJailDuration = 10 * time.Second
ProviderSlashingWindow = 10
ProviderUnbondingTime = 10 * time.Second
ProviderReplenishPeriod = "2s"
ProviderReplenishFraction = "1.00"
GovMinDepositAmount = 1000
GovMinDepositString = "1000" + Stake
GovDepositPeriod = 10 * time.Second
GovVotingPeriod = 15 * time.Second
GasPrices = "0.005"
UpgradeDelta = 30
SlashingWindowConsumer = 20
CommitTimeout = 4 * time.Second
TotalValidatorFunds = 11_000_000_000
ValidatorFunds = 30_000_000
ValidatorCount = 1
FullNodeCount = 0
ChainSpawnWait = 155 * time.Second
CosmosChainType = "cosmos"
GovModuleAddress = "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn"
)

func DefaultConfigToml() testutil.Toml {
configToml := make(testutil.Toml)
consensusToml := make(testutil.Toml)
consensusToml["timeout_commit"] = CommitTimeout
configToml["consensus"] = consensusToml
configToml["block_sync"] = false
configToml["fast_sync"] = false
return configToml
}

func DefaultGenesisAmounts(denom string) func(i int) (sdktypes.Coin, sdktypes.Coin) {
return func(i int) (sdktypes.Coin, sdktypes.Coin) {
return sdktypes.Coin{
Denom: denom,
Amount: sdkmath.NewInt(TotalValidatorFunds),
}, sdktypes.Coin{
Denom: denom,
Amount: sdkmath.NewInt(ValidatorFunds),
}
}
}
Loading

0 comments on commit 8e0d617

Please sign in to comment.