Skip to content

Commit

Permalink
Implement chain startup
Browse files Browse the repository at this point in the history
  • Loading branch information
p-offtermatt committed Nov 2, 2023
1 parent 5f96643 commit 2285a4c
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package main

import (
"fmt"
"testing"
"time"

ibctesting "github.com/cosmos/ibc-go/v7/testing"
"github.com/stretchr/testify/suite"

sdk "github.com/cosmos/cosmos-sdk/types"
slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
Expand All @@ -19,9 +19,7 @@ import (
)

type CoreSuite struct {
suite.Suite

initState InitState
t *testing.T

// simulate a relayed path
simibc simibc.RelayedPath
Expand All @@ -46,15 +44,11 @@ func (s *CoreSuite) chainID(chain string) string {

// chain returns the TestChain for a given chain identifier
func (s *CoreSuite) chain(chain string) *ibctesting.TestChain {
return map[string]*ibctesting.TestChain{P: s.providerChain(), C: s.consumerChain()}[chain]
return s.simibc.Chain(chain)
}

func (s *CoreSuite) providerChain() *ibctesting.TestChain {
return s.simibc.Chain(ibctesting.GetChainID(0))
}

func (s *CoreSuite) consumerChain() *ibctesting.TestChain {
return s.simibc.Chain(ibctesting.GetChainID(1))
return s.chain("provider")
}

func (b *CoreSuite) providerStakingKeeper() stakingkeeper.Keeper {
Expand All @@ -65,8 +59,8 @@ func (b *CoreSuite) providerSlashingKeeper() slashingkeeper.Keeper {
return b.providerChain().App.(*appProvider.App).SlashingKeeper
}

func (b *CoreSuite) consumerKeeper() consumerkeeper.Keeper {
return b.consumerChain().App.(*appConsumer.App).ConsumerKeeper
func (b *CoreSuite) consumerKeeper(chain string) consumerkeeper.Keeper {
return b.chain(chain).App.(*appConsumer.App).ConsumerKeeper
}

// height returns the height of the current header of chain
Expand Down Expand Up @@ -97,16 +91,18 @@ func (s *CoreSuite) consAddr(i int64) sdk.ConsAddress {
// isJailed returns the jail status of validator with id (ix) i
func (s *CoreSuite) isJailed(i int64) bool {
val, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i))
s.Require().Truef(found, "GetValidator() -> !found")
if !found {
s.t.Errorf("GetValidator(%v) -> !found", s.validator(i))
}
return val.IsJailed()
}

// consumerPower returns the power on the consumer chain for
// consumerPower returns the power on the consumer chain chain for
// validator with id (ix) i
func (s *CoreSuite) consumerPower(i int64) (int64, error) {
v, found := s.consumerKeeper().GetCCValidator(s.ctx(C), s.validator(i))
func (s *CoreSuite) consumerPower(i int64, chain string) (int64, error) {
v, found := s.consumerKeeper(chain).GetCCValidator(s.ctx(C), s.validator(i))
if !found {
return 0, fmt.Errorf("GetCCValidator() -> !found")
return 0, fmt.Errorf("GetCCValidator(%v) -> !found", s.validator(i))
}
return v.Power, nil
}
Expand All @@ -115,23 +111,29 @@ func (s *CoreSuite) consumerPower(i int64) (int64, error) {
// the delegator account to the validator with id (ix) i
func (s *CoreSuite) delegation(i int64) int64 {
d, found := s.providerStakingKeeper().GetDelegation(s.ctx(P), s.delegator(), s.validator(i))
s.Require().Truef(found, "GetDelegation() -> !found")
if !found {
s.t.Errorf("GetDelegation(%v) -> !found", s.validator(i))
}
return d.Shares.TruncateInt64()
}

// validatorStatus returns the validator status for validator with id (ix) i
// on the provider chain
func (s *CoreSuite) validatorStatus(i int64) stakingtypes.BondStatus {
v, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i))
s.Require().Truef(found, "GetValidator() -> !found")
if !found {
s.t.Errorf("GetValidator(%v) -> !found", s.validator(i))
}
return v.GetStatus()
}

// providerTokens returns the number of tokens that the validator with
// id (ix) i has delegated to it in total on the provider chain
func (s *CoreSuite) providerTokens(i int64) int64 {
v, found := s.providerStakingKeeper().GetValidator(s.ctx(P), s.validator(i))
s.Require().Truef(found, "GetValidator() -> !found")
if !found {
s.t.Errorf("GetValidator(%v) -> !found", s.validator(i))
}
return v.Tokens.Int64()
}

Expand Down Expand Up @@ -170,14 +172,14 @@ func (s *CoreSuite) undelegate(val, amt int64) {

// consumerSlash simulates a slash event occurring on the consumer chain.
// It can be for a downtime or doublesign.
func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool) {
func (s *CoreSuite) consumerSlash(val sdk.ConsAddress, h int64, isDowntime bool, chain string) {
kind := stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN
if isDowntime {
kind = stakingtypes.Infraction_INFRACTION_DOWNTIME
}
ctx := s.ctx(C)
before := len(ctx.EventManager().Events())
s.consumerKeeper().SlashWithInfractionReason(ctx, val, h, 0, sdk.Dec{}, kind)
s.consumerKeeper(chain).SlashWithInfractionReason(ctx, val, h, 0, sdk.Dec{}, kind)
// consumer module emits packets on slash, so these must be collected.
evts := ctx.EventManager().Events()
packets := simibc.ParsePacketsFromEvents(evts[before:])
Expand All @@ -200,11 +202,11 @@ func (s *CoreSuite) deliver(chain string, numPackets int) {
s.simibc.DeliverPackets(s.chainID(chain), numPackets)
}

// func (s *CoreSuite) endAndBeginBlock(chain string) {
// s.simibc.EndAndBeginBlock(s.chainID(chain), s.initState.BlockInterval, func() {
// s.compareModelAndSystemState()
// })
// }
func (s *CoreSuite) endAndBeginBlock(chain string, timeAdvancement time.Duration) {
s.simibc.EndAndBeginBlock(s.chainID(chain), timeAdvancement, func() {
// s.compareModelAndSystemState()
})
}

// // compareModelAndSystemState compares the state in the SUT to the state in the
// // the model.
Expand Down
2 changes: 0 additions & 2 deletions tests/difference/core/quint_model/driver/driver/.gitignore

This file was deleted.

126 changes: 93 additions & 33 deletions tests/difference/core/quint_model/driver/mbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,43 @@ import (
"testing"
"time"

"cosmossdk.io/api/tendermint/abci"
abcitypes "github.com/cometbft/cometbft/abci/types"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cometbft/cometbft/types"
cmttypes "github.com/cometbft/cometbft/types"
"github.com/cosmos/cosmos-sdk/baseapp"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
icstestingutils "github.com/cosmos/interchain-security/v3/testutil/ibc_testing"
"github.com/cosmos/interchain-security/v3/testutil/integration"
"github.com/informalsystems/itf-go/itf"
"github.com/stretchr/testify/require"

authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
consumertypes "github.com/cosmos/interchain-security/v3/x/ccv/consumer/types"
ccvtypes "github.com/cosmos/interchain-security/v3/x/ccv/types"

ibctesting "github.com/cosmos/ibc-go/v7/testing"
)

const INITIAL_ACCOUNT_BALANCE = 1000000000
const (
INITIAL_ACCOUNT_BALANCE = 1000000000

// Parameters used in the staking module
StakingParamsMaxEntries = 10000
StakingParamsMaxValidators = 100
StakingParamsUnbondingTime = 5 * 7 * 24 * time.Hour // 5 weeks
)

// Parameters used by CometBFT
var (
ConsensusParams = cmttypes.DefaultConsensusParams()
)

func getAppBytesAndSenders(
t *testing.T,
chainID string,
app ibctesting.TestingApp,
genesis map[string]json.RawMessage,
Expand Down Expand Up @@ -68,29 +83,48 @@ func getAppBytesAndSenders(
genesisAuth := authtypes.NewGenesisState(authtypes.DefaultParams(), accounts)
genesis[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(genesisAuth)

// create initial validator set and its delegations
stakingValidators := make([]stakingtypes.Validator, 0, len(nodes))
delegations := make([]stakingtypes.Delegation, 0, len(nodes))

// Sum bonded is needed for BondedPool account
sumBonded := sdk.NewInt(0)
initValPowers := []abci.ValidatorUpdate{}
initValPowers := []abcitypes.ValidatorUpdate{}

for i, val := range nodes {
tokens := sdk.NewInt(int64(val.VotingPower))
_, valSetVal := initialValSet.GetByAddress(val.Address.Bytes())
valAccount := accounts[i]
if valSetVal == nil {
log.Panicf("error getting validator with address %v from valSet %v", val, initialValSet)
}
tokens := sdk.NewInt(valSetVal.VotingPower)
sumBonded = sumBonded.Add(tokens)

pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
require.NoError(b.suite.T(), err)
if err != nil {
log.Panicf("error getting pubkey for val %v", val)
}
pkAny, err := codectypes.NewAnyWithValue(pk)
require.NoError(b.suite.T(), err)
if err != nil {
log.Panicf("error getting pubkeyAny for val %v", val)
}

var valStatus stakingtypes.BondStatus
if val.VotingPower > 0 {
valStatus = stakingtypes.Bonded
} else {
valStatus = stakingtypes.Unbonded
}

delShares := sdk.NewDec(tokens.Int64()) // as many shares as tokens

validator := stakingtypes.Validator{
OperatorAddress: sdk.ValAddress(val.Address).String(),
ConsensusPubkey: pkAny,
Jailed: false,
Status: status,
Status: valStatus,
Tokens: tokens,
DelegatorShares: sumShares,
DelegatorShares: delShares,
Description: stakingtypes.Description{},
UnbondingHeight: int64(0),
UnbondingTime: time.Unix(0, 0).UTC(),
Expand All @@ -101,13 +135,11 @@ func getAppBytesAndSenders(
stakingValidators = append(stakingValidators, validator)

// Store delegation from the model delegator account
delegations = append(delegations, stakingtypes.NewDelegation(accounts[0].GetAddress(), val.Address.Bytes(), delShares))
// Remaining delegation is from extra account
delegations = append(delegations, stakingtypes.NewDelegation(accounts[1].GetAddress(), val.Address.Bytes(), sumShares.Sub(delShares)))
delegations = append(delegations, stakingtypes.NewDelegation(valAccount.GetAddress(), val.Address.Bytes(), delShares))

// add initial validator powers so consumer InitGenesis runs correctly
pub, _ := val.ToProto()
initValPowers = append(initValPowers, abci.ValidatorUpdate{
initValPowers = append(initValPowers, abcitypes.ValidatorUpdate{
Power: val.VotingPower,
PubKey: pub.PubKey,
})
Expand All @@ -123,17 +155,17 @@ func getAppBytesAndSenders(
bondDenom = genesisStaking.Params.BondDenom
}

if genesis[consumertypes.ModuleName] != nil {
app.AppCodec().MustUnmarshalJSON(genesis[consumertypes.ModuleName], &genesisConsumer)
if genesis[ccvtypes.ModuleName] != nil {
app.AppCodec().MustUnmarshalJSON(genesis[ccvtypes.ModuleName], &genesisConsumer)
genesisConsumer.Provider.InitialValSet = initValPowers
genesisConsumer.Params.Enabled = true
genesis[consumertypes.ModuleName] = app.AppCodec().MustMarshalJSON(&genesisConsumer)
genesis[ccvtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&genesisConsumer)
}

// Set model parameters
genesisStaking.Params.MaxEntries = uint32(b.initState.MaxEntries)
genesisStaking.Params.MaxValidators = uint32(b.initState.MaxValidators)
genesisStaking.Params.UnbondingTime = b.initState.UnbondingP
genesisStaking.Params.MaxEntries = StakingParamsMaxEntries
genesisStaking.Params.MaxValidators = StakingParamsMaxValidators
genesisStaking.Params.UnbondingTime = StakingParamsUnbondingTime
genesisStaking = *stakingtypes.NewGenesisState(genesisStaking.Params, stakingValidators, delegations)
genesis[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&genesisStaking)

Expand All @@ -154,38 +186,43 @@ func getAppBytesAndSenders(
genesis[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(genesisBank)

stateBytes, err := json.MarshalIndent(genesis, "", " ")
require.NoError(b.suite.T(), err)
if err != nil {
log.Panicf("error marshalling genesis: %v", err)
}

return stateBytes, senderAccounts
}

func newChain(
t *testing.T,
coord *ibctesting.Coordinator,
appInit icstestingutils.AppIniter,
chainID string,
validators *tmtypes.ValidatorSet,
signers map[string]tmtypes.PrivValidator,
validators *cmttypes.ValidatorSet,
signers map[string]cmttypes.PrivValidator,
nodes []*cmttypes.Validator,
) *ibctesting.TestChain {
app, genesis := appInit()

baseapp.SetChainID(chainID)(app.GetBaseApp())

stateBytes, senderAccounts := b.getAppBytesAndSenders(chainID, app, genesis, validators)
stateBytes, senderAccounts := getAppBytesAndSenders(chainID, app, genesis, validators, nodes)

protoConsParams := ConsensusParams.ToProto()
app.InitChain(
abci.RequestInitChain{
abcitypes.RequestInitChain{
ChainId: chainID,
Validators: []abci.ValidatorUpdate{},
ConsensusParams: b.initState.ConsensusParams,
Validators: []abcitypes.ValidatorUpdate{},
ConsensusParams: &protoConsParams,
AppStateBytes: stateBytes,
},
)

app.Commit()

app.BeginBlock(
abci.RequestBeginBlock{
Header: tmproto.Header{
abcitypes.RequestBeginBlock{
Header: cmtproto.Header{
ChainID: chainID,
Height: app.LastBlockHeight() + 1,
AppHash: app.LastCommitID().Hash,
Expand All @@ -196,11 +233,11 @@ func newChain(
)

chain := &ibctesting.TestChain{
T: b.suite.T(),
T: t,
Coordinator: coord,
ChainID: chainID,
App: app,
CurrentHeader: tmproto.Header{
CurrentHeader: cmtproto.Header{
ChainID: chainID,
Height: 1,
Time: coord.CurrentTime.UTC(),
Expand Down Expand Up @@ -308,8 +345,30 @@ func TestItfTrace(t *testing.T) {
t.Log(addressMap)
t.Log(signers)

// get a slice of validators in the right order
nodes := make([]*cmttypes.Validator, len(valNames))
for i, valName := range valNames {
nodes[i] = addressMap[valName]
}

initValUpdates := types.TM2PB.ValidatorUpdates(valSet)

t.Log("Creating coordinator")
coordinator := ibctesting.NewCoordinator(t, len(consumers))
coordinator := ibctesting.NewCoordinator(t, 0) // start without chains, which we add later

// start provider
t.Log("Creating provider chain")
providerChain := newChain(t, coordinator, icstestingutils.ProviderAppIniter, "provider", valSet, signers, nodes)
coordinator.Chains["provider"] = providerChain

// start consumer chains
for _, chain := range consumers {
t.Logf("Creating consumer chain %v", chain)
consumerChain := newChain(t, coordinator, icstestingutils.ConsumerAppIniter(initValUpdates), chain, valSet, signers, nodes)
coordinator.Chains[chain] = consumerChain
}

t.Log("Started chains")

// initializing the provider chain

Expand All @@ -330,7 +389,8 @@ func TestItfTrace(t *testing.T) {
case "VotingPowerChange":
node := lastAction["validator"].Value.(string)
newVotingPower := lastAction["newVotingPower"].Value.(int64)
t.Log(node, newVotingPower)
t.Logf("Setting provider voting power of %v to %v", node, newVotingPower)

case "EndAndBeginBlockForProvider":
timeAdvancement := lastAction["timeAdvancement"].Value.(int64)
consumersToStart := lastAction["consumersToStart"].Value.(itf.ListExprType)
Expand Down

0 comments on commit 2285a4c

Please sign in to comment.