Skip to content

Commit

Permalink
test: add integration test for the ibc tokenfilter (#1474)
Browse files Browse the repository at this point in the history
Closes: #1249

Adds a test suite under `testing/tokenfilter` that does the
following:
- ensures that native celestia tokens can be sent out from celestia and
can return
- ensures that other chains can't send tokens to celestia chains and
that their balance is unaffected.
  • Loading branch information
cmwaters authored Mar 15, 2023
1 parent 95a155d commit 953860c
Show file tree
Hide file tree
Showing 4 changed files with 399 additions and 0 deletions.
26 changes: 26 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import (
qgbmodule "github.com/celestiaorg/celestia-app/x/qgb"
qgbmodulekeeper "github.com/celestiaorg/celestia-app/x/qgb/keeper"
qgbmoduletypes "github.com/celestiaorg/celestia-app/x/qgb/types"
ibctestingtypes "github.com/cosmos/ibc-go/v6/testing/types"
)

const (
Expand Down Expand Up @@ -577,6 +578,31 @@ func (app *App) ModuleAccountAddrs() map[string]bool {
return modAccAddrs
}

// GetBaseApp implements the TestingApp interface.
func (app *App) GetBaseApp() *baseapp.BaseApp {
return app.BaseApp
}

// GetStakingKeeper implements the TestingApp interface.
func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper {
return app.StakingKeeper
}

// GetIBCKeeper implements the TestingApp interface.
func (app *App) GetIBCKeeper() *ibckeeper.Keeper {
return app.IBCKeeper
}

// GetScopedIBCKeeper implements the TestingApp interface.
func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper {
return app.ScopedIBCKeeper
}

// GetTxConfig implements the TestingApp interface.
func (app *App) GetTxConfig() client.TxConfig {
return app.txConfig
}

// LegacyAmino returns SimApp's amino codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
Expand Down
7 changes: 7 additions & 0 deletions app/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package app

import (
"encoding/json"

"github.com/cosmos/cosmos-sdk/codec"
)

// The genesis state of the blockchain is represented here as a map of raw json
Expand All @@ -12,3 +14,8 @@ import (
// the ModuleBasicManager which populates json from each BasicModule
// object provided to it during init.
type GenesisState map[string]json.RawMessage

// NewDefaultGenesisState generates the default state for the application.
func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState {
return ModuleBasics.DefaultGenesis(cdc)
}
229 changes: 229 additions & 0 deletions testing/tokenfilter/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package tokenfilter

import (
"encoding/json"
"testing"
"time"

"cosmossdk.io/math"
"github.com/celestiaorg/celestia-app/app"
"github.com/celestiaorg/celestia-app/app/encoding"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/ethereum/go-ethereum/common"

sdk "github.com/cosmos/cosmos-sdk/types"
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"
ibctesting "github.com/cosmos/ibc-go/v6/testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/ibc-go/v6/testing/mock"
"github.com/cosmos/ibc-go/v6/testing/simapp"
)

// NewTestChainWithValSet initializes a new TestChain instance with the given validator set
// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of
// bond denom to use for tests.
//
// The first block height is committed to state in order to allow for client creations on
// counterparty chains. The TestChain will return with a block height starting at 2.
//
// Time management is handled by the Coordinator in order to ensure synchrony between chains.
// Each update of any chain increments the block header time for all chains by 5 seconds.
//
// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this
// constructor function.
//
// CONTRACT: Validator array must be provided in the order expected by Tendermint.
// i.e. sorted first by power and then lexicographically by address.
func NewTestChainWithValSet(t *testing.T, coord *ibctesting.Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctesting.TestChain {
genAccs := []authtypes.GenesisAccount{}
genBals := []banktypes.Balance{}
senderAccs := []ibctesting.SenderAccount{}

// generate genesis accounts
for i := 0; i < ibctesting.MaxAccounts; i++ {
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0)
amount, ok := sdk.NewIntFromString("10000000000000000000")
require.True(t, ok)

// add sender account
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)),
}

genAccs = append(genAccs, acc)
genBals = append(genBals, balance)

senderAcc := ibctesting.SenderAccount{
SenderAccount: acc,
SenderPrivKey: senderPrivKey,
}

senderAccs = append(senderAccs, senderAcc)
}

app := SetupWithGenesisValSet(t, valSet, genAccs, chainID, sdk.DefaultPowerReduction, genBals...)

// create current header and call begin block
header := tmproto.Header{
ChainID: chainID,
Height: 1,
Time: coord.CurrentTime.UTC(),
}

txConfig := app.GetTxConfig()

chain := &ibctesting.TestChain{
T: t,
Coordinator: coord,
ChainID: chainID,
App: app,
CurrentHeader: header,
QueryServer: app.GetIBCKeeper(),
TxConfig: txConfig,
Codec: app.AppCodec(),
Vals: valSet,
NextVals: valSet,
Signers: signers,
SenderPrivKey: senderAccs[0].SenderPrivKey,
SenderAccount: senderAccs[0].SenderAccount,
SenderAccounts: senderAccs,
}

coord.CommitBlock(chain)

return chain
}

// NewTestChain initializes a new test chain with a default of 4 validators.
// Use this function if the tests do not need custom control over the validator set.
func NewTestChain(t *testing.T, coord *ibctesting.Coordinator, chainID string) *ibctesting.TestChain {
var (
validatorsPerChain = 4
validators []*tmtypes.Validator
signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain)
)

// generate validators private/public key
for i := 0; i < validatorsPerChain; i++ {
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
validators = append(validators, tmtypes.NewValidator(pubKey, 1))
signersByAddress[pubKey.Address().String()] = privVal
}

// construct validator set;
// Note that the validators are sorted by voting power
// or, if equal, by address lexical order
valSet := tmtypes.NewValidatorSet(validators)

return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress)
}

// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t testing.TB, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction math.Int, balances ...banktypes.Balance) ibctesting.TestingApp {
db := dbm.NewMemDB()
encCdc := encoding.MakeConfig(app.ModuleEncodingRegisters...)
genesisState := app.NewDefaultGenesisState(encCdc.Codec)
app := app.New(
log.NewNopLogger(), db, nil, true, map[int64]bool{}, app.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{},
)

// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)

validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))

bondAmt := sdk.TokensFromConsensusPower(1, powerReduction)

for _, val := range valSet.Validators {
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
require.NoError(t, err)
pkAny, err := codectypes.NewAnyWithValue(pk)
require.NoError(t, err)
evmAddress := common.HexToAddress(crypto.CRandHex(common.AddressLength))
validator := stakingtypes.Validator{
OperatorAddress: sdk.ValAddress(val.Address).String(),
ConsensusPubkey: pkAny,
Jailed: false,
Status: stakingtypes.Bonded,
Tokens: bondAmt,
DelegatorShares: sdk.OneDec(),
Description: stakingtypes.Description{},
UnbondingHeight: int64(0),
UnbondingTime: time.Unix(0, 0).UTC(),
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
MinSelfDelegation: sdk.ZeroInt(),
EvmAddress: evmAddress.Hex(),
}

validators = append(validators, validator)
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
}

// set validators and delegations
var stakingGenesis stakingtypes.GenesisState
app.AppCodec().MustUnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingGenesis)

bondDenom := stakingGenesis.Params.BondDenom

// add bonded amount to bonded pool module account
balances = append(balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
Coins: sdk.Coins{sdk.NewCoin(bondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))},
})

// set validators and delegations
stakingGenesis = *stakingtypes.NewGenesisState(stakingGenesis.Params, validators, delegations)
genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis)

// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)

stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)

// init chain will set the validator set and initialize the genesis accounts
app.InitChain(
abci.RequestInitChain{
ChainId: chainID,
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
)

// commit genesis changes
app.Commit()
app.BeginBlock(
abci.RequestBeginBlock{
Header: tmproto.Header{
ChainID: chainID,
Height: app.LastBlockHeight() + 1,
AppHash: app.LastCommitID().Hash,
ValidatorsHash: valSet.Hash(),
NextValidatorsHash: valSet.Hash(),
},
},
)

return app
}
Loading

0 comments on commit 953860c

Please sign in to comment.