diff --git a/testutil/network/network.go b/testutil/network/network.go new file mode 100644 index 0000000000..cb3987e86e --- /dev/null +++ b/testutil/network/network.go @@ -0,0 +1,467 @@ +package network + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + tmcfg "github.com/tendermint/tendermint/config" + tmflags "github.com/tendermint/tendermint/libs/cli/flags" + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/node" + tmclient "github.com/tendermint/tendermint/rpc/client" + dbm "github.com/tendermint/tm-db" + "google.golang.org/grpc" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/api" + srvconfig "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/params" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil" + 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" + "github.com/cosmos/cosmos-sdk/x/genutil" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// package-wide network lock to only allow one test network at a time +var lock = new(sync.Mutex) + +// AppConstructor defines a function which accepts a network configuration and +// creates an ABCI Application to provide to Tendermint. +type AppConstructor = func(val Validator) servertypes.Application + +// NewAppConstructor returns a new simapp AppConstructor +func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { + return func(val Validator) servertypes.Application { + return simapp.NewSimApp( + val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, + encodingCfg, + simapp.EmptyAppOptions{}, + baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), + ) + } +} + +// Config defines the necessary configuration used to bootstrap and start an +// in-process local testing network. +type Config struct { + Codec codec.Codec + LegacyAmino *codec.LegacyAmino // TODO: Remove! + InterfaceRegistry codectypes.InterfaceRegistry + + TxConfig client.TxConfig + AccountRetriever client.AccountRetriever + AppConstructor AppConstructor // the ABCI application constructor + GenesisState map[string]json.RawMessage // custom genesis state to provide + TimeoutCommit time.Duration // the consensus commitment timeout + ChainID string // the network chain-id + NumValidators int // the total number of validators to create and bond + Mnemonics []string // custom user-provided validator operator mnemonics + BondDenom string // the staking bond denomination + Denoms []string // list of additional denoms could be used on network + MinGasPrices string // the minimum gas prices each validator will accept + AccountTokens sdk.Int // the amount of unique validator tokens (e.g. 1000node0) + StakingTokens sdk.Int // the amount of tokens each validator has available to stake + BondedTokens sdk.Int // the amount of tokens each validator stakes + PruningStrategy string // the pruning strategy each validator will have + EnableLogging bool // enable Tendermint logging to STDOUT + CleanupDir bool // remove base temporary directory during cleanup + SigningAlgo string // signing algorithm for keys + KeyringOptions []keyring.Option +} + +// Network defines a local in-process testing network using SimApp. It can be +// configured to start any number of validators, each with its own RPC and API +// clients. Typically, this test network would be used in client and integration +// testing where user input is expected. +// +// Note, due to Tendermint constraints in regard to RPC functionality, there +// may only be one test network running at a time. Thus, any caller must be +// sure to Cleanup after testing is finished in order to allow other tests +// to create networks. In addition, only the first validator will have a valid +// RPC and API server/client. +type Network struct { + T *testing.T + BaseDir string + Validators []*Validator + + Config Config +} + +// Validator defines an in-process Tendermint validator node. Through this object, +// a client can make RPC and API calls and interact with any client command +// or handler. +type Validator struct { + AppConfig *srvconfig.Config + ClientCtx client.Context + Ctx *server.Context + Dir string + NodeID string + PubKey cryptotypes.PubKey + Moniker string + APIAddress string + RPCAddress string + P2PAddress string + Address sdk.AccAddress + ValAddress sdk.ValAddress + RPCClient tmclient.Client + + tmNode *node.Node + api *api.Server + grpc *grpc.Server + grpcWeb *http.Server +} + +// New creates a new Network for integration tests. +func New(t *testing.T, cfg Config) *Network { + // only one caller/test can create and use a network at a time + t.Log("acquiring test network lock") + lock.Lock() + + baseDir, err := os.MkdirTemp(t.TempDir(), cfg.ChainID) + require.NoError(t, err) + t.Logf("created temporary directory: %s", baseDir) + + network := &Network{ + T: t, + BaseDir: baseDir, + Validators: make([]*Validator, cfg.NumValidators), + Config: cfg, + } + + t.Log("preparing test network...") + + monikers := make([]string, cfg.NumValidators) + nodeIDs := make([]string, cfg.NumValidators) + valPubKeys := make([]cryptotypes.PubKey, cfg.NumValidators) + + var ( + genAccounts []authtypes.GenesisAccount + genBalances []banktypes.Balance + genFiles []string + ) + + buf := bufio.NewReader(os.Stdin) + + // generate private keys, node IDs, and initial transactions + for i := 0; i < cfg.NumValidators; i++ { + appCfg := srvconfig.DefaultConfig() + appCfg.Pruning = cfg.PruningStrategy + appCfg.MinGasPrices = cfg.MinGasPrices + appCfg.API.Enable = true + appCfg.API.Swagger = false + appCfg.Telemetry.Enabled = false + + ctx := server.NewDefaultContext() + tmCfg := ctx.Config + tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit + + // Only allow the first validator to expose an RPC, API and gRPC + // server/client due to Tendermint in-process constraints. + apiAddr := "" + tmCfg.RPC.ListenAddress = "" + appCfg.GRPC.Enable = false + appCfg.GRPCWeb.Enable = false + if i == 0 { + apiListenAddr, _, err := server.FreeTCPAddr() + require.NoError(t, err) + appCfg.API.Address = apiListenAddr + + apiURL, err := url.Parse(apiListenAddr) + require.NoError(t, err) + apiAddr = fmt.Sprintf("http://%s:%s", apiURL.Hostname(), apiURL.Port()) + + rpcAddr, _, err := server.FreeTCPAddr() + require.NoError(t, err) + tmCfg.RPC.ListenAddress = rpcAddr + + _, grpcPort, err := server.FreeTCPAddr() + require.NoError(t, err) + appCfg.GRPC.Address = fmt.Sprintf("0.0.0.0:%s", grpcPort) + appCfg.GRPC.Enable = true + + _, grpcWebPort, err := server.FreeTCPAddr() + require.NoError(t, err) + appCfg.GRPCWeb.Address = fmt.Sprintf("0.0.0.0:%s", grpcWebPort) + appCfg.GRPCWeb.Enable = true + } + + logger := log.NewNopLogger() + if cfg.EnableLogging { + logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + logger, _ = tmflags.ParseLogLevel("info", logger, tmcfg.DefaultLogLevel) + } + + ctx.Logger = logger + + nodeDirName := fmt.Sprintf("node%d", i) + nodeDir := filepath.Join(network.BaseDir, nodeDirName, "simd") + clientDir := filepath.Join(network.BaseDir, nodeDirName, "simcli") + gentxsDir := filepath.Join(network.BaseDir, "gentxs") + + require.NoError(t, os.MkdirAll(filepath.Join(nodeDir, "config"), 0o755)) + require.NoError(t, os.MkdirAll(clientDir, 0o755)) + + tmCfg.SetRoot(nodeDir) + tmCfg.Moniker = nodeDirName + monikers[i] = nodeDirName + + proxyAddr, _, err := server.FreeTCPAddr() + require.NoError(t, err) + tmCfg.ProxyApp = proxyAddr + + p2pAddr, _, err := server.FreeTCPAddr() + require.NoError(t, err) + + tmCfg.P2P.ListenAddress = p2pAddr + tmCfg.P2P.AddrBookStrict = false + tmCfg.P2P.AllowDuplicateIP = true + + nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(tmCfg) + require.NoError(t, err) + nodeIDs[i] = nodeID + valPubKeys[i] = pubKey + + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.KeyringOptions...) + require.NoError(t, err) + + keyringAlgos, _ := kb.SupportedAlgorithms() + algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos) + require.NoError(t, err) + + var mnemonic string + if i < len(cfg.Mnemonics) { + mnemonic = cfg.Mnemonics[i] + } + + addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, mnemonic, true, algo) + require.NoError(t, err) + + info := map[string]string{"secret": secret} + infoBz, err := json.Marshal(info) + require.NoError(t, err) + + // save private key seed words + require.NoError(t, writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, infoBz)) + + balances := make(sdk.Coins, 0, len(cfg.Denoms)+1) + balances = append(balances, sdk.NewCoin(cfg.BondDenom, cfg.StakingTokens)) + + for _, denom := range cfg.Denoms { + balances = append(balances, sdk.NewCoin(denom, cfg.AccountTokens)) + } + + genFiles = append(genFiles, tmCfg.GenesisFile()) + genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()}) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0)) + + commission, err := sdk.NewDecFromStr("0.5") + require.NoError(t, err) + + createValMsg, err := stakingtypes.NewMsgCreateValidator( + sdk.ValAddress(addr), + valPubKeys[i], + sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens), + stakingtypes.NewDescription(nodeDirName, "", "", "", ""), + stakingtypes.NewCommissionRates(commission, sdk.OneDec(), sdk.OneDec()), + sdk.OneInt(), + ) + require.NoError(t, err) + + p2pURL, err := url.Parse(p2pAddr) + require.NoError(t, err) + + memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port()) + fee := sdk.NewCoins(sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), sdk.NewInt(0))) + txBuilder := cfg.TxConfig.NewTxBuilder() + require.NoError(t, txBuilder.SetMsgs(createValMsg)) + txBuilder.SetFeeAmount(fee) // Arbitrary fee + txBuilder.SetGasLimit(1000000) // Need at least 100386 + txBuilder.SetMemo(memo) + + txFactory := tx.Factory{} + txFactory = txFactory. + WithChainID(cfg.ChainID). + WithMemo(memo). + WithKeybase(kb). + WithTxConfig(cfg.TxConfig) + + err = tx.Sign(txFactory, nodeDirName, txBuilder, true) + require.NoError(t, err) + + txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + require.NoError(t, writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz)) + + srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config/app.toml"), appCfg) + + cctx := client.Context{}. + WithKeyringDir(clientDir). + WithKeyring(kb). + WithHomeDir(tmCfg.RootDir). + WithChainID(cfg.ChainID). + WithInterfaceRegistry(cfg.InterfaceRegistry). + WithCodec(cfg.Codec). + WithLegacyAmino(cfg.LegacyAmino). + WithTxConfig(cfg.TxConfig). + WithAccountRetriever(cfg.AccountRetriever) + + network.Validators[i] = &Validator{ + AppConfig: appCfg, + ClientCtx: cctx, + Ctx: ctx, + Dir: filepath.Join(network.BaseDir, nodeDirName), + NodeID: nodeID, + PubKey: pubKey, + Moniker: nodeDirName, + RPCAddress: tmCfg.RPC.ListenAddress, + P2PAddress: tmCfg.P2P.ListenAddress, + APIAddress: apiAddr, + Address: addr, + ValAddress: sdk.ValAddress(addr), + } + } + + require.NoError(t, initGenFiles(cfg, genAccounts, genBalances, genFiles)) + require.NoError(t, collectGenFiles(cfg, network.Validators, network.BaseDir)) + + t.Log("starting test network...") + for _, v := range network.Validators { + require.NoError(t, startInProcess(cfg, v)) + } + + t.Log("started test network") + + // Ensure we clean up incase any test was abruptly halted (e.g. SIGINT) as any + // defer in a test would not be called. + server.TrapSignal(network.Cleanup) + + return network +} + +// LatestHeight returns the latest height of the network or an error if the +// query fails or no validators exist. +func (n *Network) LatestHeight() (int64, error) { + if len(n.Validators) == 0 { + return 0, errors.New("no validators available") + } + + status, err := n.Validators[0].RPCClient.Status(context.Background()) + if err != nil { + return 0, err + } + + return status.SyncInfo.LatestBlockHeight, nil +} + +// WaitForHeight performs a blocking check where it waits for a block to be +// committed after a given block. If that height is not reached within a timeout, +// an error is returned. Regardless, the latest height queried is returned. +func (n *Network) WaitForHeight(h int64) (int64, error) { + return n.WaitForHeightWithTimeout(h, 10*time.Second) +} + +// WaitForHeightWithTimeout is the same as WaitForHeight except the caller can +// provide a custom timeout. +func (n *Network) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, error) { + ticker := time.NewTicker(time.Second) + timeout := time.After(t) + + if len(n.Validators) == 0 { + return 0, errors.New("no validators available") + } + + var latestHeight int64 + val := n.Validators[0] + + for { + select { + case <-timeout: + ticker.Stop() + return latestHeight, errors.New("timeout exceeded waiting for block") + case <-ticker.C: + status, err := val.RPCClient.Status(context.Background()) + if err == nil && status != nil { + latestHeight = status.SyncInfo.LatestBlockHeight + if latestHeight >= h { + return latestHeight, nil + } + } + } + } +} + +// WaitForNextBlock waits for the next block to be committed, returning an error +// upon failure. +func (n *Network) WaitForNextBlock() error { + lastBlock, err := n.LatestHeight() + if err != nil { + return err + } + + _, err = n.WaitForHeight(lastBlock + 1) + if err != nil { + return err + } + + return err +} + +// Cleanup removes the root testing (temporary) directory and stops both the +// Tendermint and API services. It allows other callers to create and start +// test networks. This method must be called when a test is finished, typically +// in a defer. +func (n *Network) Cleanup() { + defer func() { + lock.Unlock() + n.T.Log("released test network lock") + }() + + n.T.Log("cleaning up test network...") + + for _, v := range n.Validators { + if v.tmNode != nil && v.tmNode.IsRunning() { + _ = v.tmNode.Stop() + } + + if v.api != nil { + _ = v.api.Close() + } + + if v.grpc != nil { + v.grpc.Stop() + if v.grpcWeb != nil { + _ = v.grpcWeb.Close() + } + } + } + + if n.Config.CleanupDir { + _ = os.RemoveAll(n.BaseDir) + } + + n.T.Log("finished cleaning up test network") +} diff --git a/testutil/network/util.go b/testutil/network/util.go new file mode 100644 index 0000000000..bdc6d72065 --- /dev/null +++ b/testutil/network/util.go @@ -0,0 +1,211 @@ +package network + +import ( + "encoding/json" + "path/filepath" + "time" + + tmos "github.com/tendermint/tendermint/libs/os" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/p2p" + pvm "github.com/tendermint/tendermint/privval" + "github.com/tendermint/tendermint/proxy" + "github.com/tendermint/tendermint/rpc/client/local" + "github.com/tendermint/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + "github.com/cosmos/cosmos-sdk/server/api" + servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + srvtypes "github.com/cosmos/cosmos-sdk/server/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +func startInProcess(cfg Config, val *Validator) error { + logger := val.Ctx.Logger + tmCfg := val.Ctx.Config + tmCfg.Instrumentation.Prometheus = false + + if err := val.AppConfig.ValidateBasic(); err != nil { + return err + } + + nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile()) + if err != nil { + return err + } + + app := cfg.AppConstructor(*val) + + genDocProvider := node.DefaultGenesisDocProviderFunc(tmCfg) + tmNode, err := node.NewNode( + tmCfg, + pvm.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()), + nodeKey, + proxy.NewLocalClientCreator(app), + genDocProvider, + node.DefaultDBProvider, + node.DefaultMetricsProvider(tmCfg.Instrumentation), + logger.With("module", val.Moniker), + ) + if err != nil { + return err + } + + if err := tmNode.Start(); err != nil { + return err + } + + val.tmNode = tmNode + + if val.RPCAddress != "" { + val.RPCClient = local.New(tmNode) + } + + // We'll need an RPC client if the validator exposes a gRPC or REST endpoint. + if val.APIAddress != "" || val.AppConfig.GRPC.Enable { + val.ClientCtx = val.ClientCtx. + WithClient(val.RPCClient) + + app.RegisterTxService(val.ClientCtx) + app.RegisterTendermintService(val.ClientCtx) + + if a, ok := app.(srvtypes.ApplicationQueryService); ok { + a.RegisterNodeService(val.ClientCtx) + } + } + + if val.APIAddress != "" { + apiSrv := api.New(val.ClientCtx, logger.With("module", "api-server")) + app.RegisterAPIRoutes(apiSrv, val.AppConfig.API) + + errCh := make(chan error) + + go func() { + if err := apiSrv.Start(*val.AppConfig); err != nil { + errCh <- err + } + }() + + select { + case err := <-errCh: + return err + case <-time.After(srvtypes.ServerStartTime): // assume server started successfully + } + + val.api = apiSrv + } + + if val.AppConfig.GRPC.Enable { + grpcSrv, err := servergrpc.StartGRPCServer(val.ClientCtx, app, val.AppConfig.GRPC.Address) + if err != nil { + return err + } + + val.grpc = grpcSrv + + if val.AppConfig.GRPCWeb.Enable { + val.grpcWeb, err = servergrpc.StartGRPCWeb(grpcSrv, *val.AppConfig) + if err != nil { + return err + } + } + } + + return nil +} + +func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error { + genTime := tmtime.Now() + + for i := 0; i < cfg.NumValidators; i++ { + tmCfg := vals[i].Ctx.Config + + nodeDir := filepath.Join(outputDir, vals[i].Moniker, "simd") + gentxsDir := filepath.Join(outputDir, "gentxs") + + tmCfg.Moniker = vals[i].Moniker + tmCfg.SetRoot(nodeDir) + + initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey) + + genFile := tmCfg.GenesisFile() + genDoc, err := types.GenesisDocFromFile(genFile) + if err != nil { + return err + } + + appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig, + tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}) + if err != nil { + return err + } + + // overwrite each validator's genesis file to have a canonical genesis time + if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil { + return err + } + } + + return nil +} + +func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error { + // set the accounts in the genesis state + var authGenState authtypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState) + + accounts, err := authtypes.PackAccounts(genAccounts) + if err != nil { + return err + } + + authGenState.Accounts = append(authGenState.Accounts, accounts...) + cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState) + + // set the balances in the genesis state + var bankGenState banktypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState) + + bankGenState.Balances = append(bankGenState.Balances, genBalances...) + cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState) + + appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ") + if err != nil { + return err + } + + genDoc := types.GenesisDoc{ + ChainID: cfg.ChainID, + AppState: appGenStateJSON, + Validators: nil, + } + + // generate empty genesis files for each validator and save + for i := 0; i < cfg.NumValidators; i++ { + if err := genDoc.SaveAs(genFiles[i]); err != nil { + return err + } + } + + return nil +} + +func writeFile(name string, dir string, contents []byte) error { + writePath := filepath.Join(dir) //nolint:gocritic + file := filepath.Join(writePath, name) + + err := tmos.EnsureDir(writePath, 0o755) + if err != nil { + return err + } + + err = tmos.WriteFile(file, contents, 0o644) + if err != nil { + return err + } + + return nil +} diff --git a/testutil/network_suite.go b/testutil/network_suite.go index 5182d3a80b..670af7bfe7 100644 --- a/testutil/network_suite.go +++ b/testutil/network_suite.go @@ -8,26 +8,28 @@ import ( "strings" "time" + "github.com/gogo/protobuf/jsonpb" + "github.com/spf13/pflag" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + sdkclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdknetworktest "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" cosmosauthtx "github.com/cosmos/cosmos-sdk/x/auth/tx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/gogo/protobuf/jsonpb" - "github.com/spf13/pflag" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" + + "github.com/akash-network/node/testutil/network" ) type NetworkTestSuite struct { *suite.Suite - cfg sdknetworktest.Config - network *sdknetworktest.Network + cfg network.Config + network *network.Network testIdx int kr keyring.Keyring @@ -37,7 +39,7 @@ type NetworkTestSuite struct { cancelTestCtx context.CancelFunc } -func NewNetworkTestSuite(cfg *sdknetworktest.Config, container interface{}) NetworkTestSuite { +func NewNetworkTestSuite(cfg *network.Config, container interface{}) NetworkTestSuite { nts := NetworkTestSuite{ Suite: &suite.Suite{}, container: container, @@ -74,7 +76,7 @@ func (nts *NetworkTestSuite) TearDownSuite() { func (nts *NetworkTestSuite) SetupSuite() { nts.kr = Keyring(nts.T()) - nts.network = sdknetworktest.New(nts.T(), nts.cfg) + nts.network = network.New(nts.T(), nts.cfg) _, err := nts.network.WaitForHeightWithTimeout(1, time.Second*30) require.NoError(nts.T(), err) @@ -145,7 +147,7 @@ func (nts *NetworkTestSuite) SetupSuite() { } -func (nts *NetworkTestSuite) Validator(idxT ...int) *sdknetworktest.Validator { +func (nts *NetworkTestSuite) Validator(idxT ...int) *network.Validator { idx := 0 if len(idxT) != 0 { if len(idxT) > 1 { @@ -181,7 +183,7 @@ func (nts *NetworkTestSuite) GoContextForTest() context.Context { return nts.testCtx } -func (nts *NetworkTestSuite) Network() *sdknetworktest.Network { +func (nts *NetworkTestSuite) Network() *network.Network { return nts.network } @@ -196,7 +198,7 @@ func (nts *NetworkTestSuite) Context(idxT ...int) sdkclient.Context { return result.WithFromAddress(validator.Address).WithFromName(fmt.Sprintf("node%d", idx)) } -func (nts *NetworkTestSuite) Config() sdknetworktest.Config { +func (nts *NetworkTestSuite) Config() network.Config { return nts.cfg } diff --git a/testutil/types.go b/testutil/types.go index 87bbe5004c..5199dec5cf 100644 --- a/testutil/types.go +++ b/testutil/types.go @@ -10,22 +10,39 @@ import ( "time" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp" storetypes "github.com/cosmos/cosmos-sdk/store/types" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + tmrand "github.com/tendermint/tendermint/libs/rand" dbm "github.com/tendermint/tm-db" types "github.com/akash-network/akash-api/go/node/types/v1beta3" "github.com/akash-network/node/app" + "github.com/akash-network/node/testutil/network" ) +type InterceptState func(codec.Codec, string, json.RawMessage) json.RawMessage + +type networkConfigOptions struct { + interceptState InterceptState +} + +type ConfigOption func(*networkConfigOptions) + +// WithInterceptState set custom name of the log object +func WithInterceptState(val InterceptState) ConfigOption { + return func(t *networkConfigOptions) { + t.interceptState = val + } +} + func RandRangeInt(min, max int) int { return rand.Intn(max-min) + min // nolint: gosec } @@ -75,7 +92,12 @@ func NewApp(val network.Validator) servertypes.Application { // DefaultConfig returns a default configuration suitable for nearly all // testing requirements. -func DefaultConfig() network.Config { +func DefaultConfig(opts ...ConfigOption) network.Config { + cfg := &networkConfigOptions{} + for _, opt := range opts { + opt(cfg) + } + encCfg := app.MakeEncodingConfig() origGenesisState := app.ModuleBasics().DefaultGenesis(encCfg.Marshaler) @@ -109,6 +131,15 @@ func DefaultConfig() network.Config { genesisState[k] = replacementV } + if cfg.interceptState != nil { + for k, v := range genesisState { + res := cfg.interceptState(encCfg.Marshaler, k, v) + if res != nil { + genesisState[k] = res + } + } + } + return network.Config{ Codec: encCfg.Marshaler, TxConfig: encCfg.TxConfig, @@ -121,13 +152,16 @@ func DefaultConfig() network.Config { ChainID: "chain-" + tmrand.NewRand().Str(6), NumValidators: 4, BondDenom: CoinDenom, - MinGasPrices: fmt.Sprintf("0.000006%s", CoinDenom), - AccountTokens: sdk.TokensFromConsensusPower(1000000000000, sdk.DefaultPowerReduction), - StakingTokens: sdk.TokensFromConsensusPower(100000, sdk.DefaultPowerReduction), - BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), - PruningStrategy: storetypes.PruningOptionNothing, - CleanupDir: true, - SigningAlgo: string(hd.Secp256k1Type), - KeyringOptions: []keyring.Option{}, + Denoms: []string{ + "ibc/12C6A0C374171B595A0A9E18B83FA09D295FB1F2D8C6DAA3AC28683471752D84", + }, + MinGasPrices: fmt.Sprintf("0.000006%s", CoinDenom), + AccountTokens: sdk.TokensFromConsensusPower(1000000000000, sdk.DefaultPowerReduction), + StakingTokens: sdk.TokensFromConsensusPower(100000, sdk.DefaultPowerReduction), + BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), + PruningStrategy: storetypes.PruningOptionNothing, + CleanupDir: true, + SigningAlgo: string(hd.Secp256k1Type), + KeyringOptions: []keyring.Option{}, } } diff --git a/x/cert/client/cli/grpc_rest_test.go b/x/cert/client/cli/grpc_rest_test.go index e7fdf5d374..2ad1f1aea2 100644 --- a/x/cert/client/cli/grpc_rest_test.go +++ b/x/cert/client/cli/grpc_rest_test.go @@ -5,16 +5,16 @@ import ( "fmt" "testing" - sdkrest "github.com/cosmos/cosmos-sdk/types/rest" "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" + sdkrest "github.com/cosmos/cosmos-sdk/types/rest" types "github.com/akash-network/akash-api/go/node/cert/v1beta3" "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" atypes "github.com/akash-network/node/types" ccli "github.com/akash-network/node/x/cert/client/cli" ) @@ -34,7 +34,7 @@ func (s *GRPCRestTestSuite) SetupSuite() { cfg.NumValidators = 1 s.cfg = cfg - s.network = network.New(s.T(), cfg) + s.network = network.New(s.T(), s.cfg) _, err := s.network.WaitForHeight(1) s.Require().NoError(err) diff --git a/x/deployment/client/cli/cli_test.go b/x/deployment/client/cli/cli_test.go index 8c3b557713..5707d537e0 100644 --- a/x/deployment/client/cli/cli_test.go +++ b/x/deployment/client/cli/cli_test.go @@ -6,22 +6,20 @@ import ( "path/filepath" "testing" - "github.com/cosmos/cosmos-sdk/crypto/hd" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - - clitestutil "github.com/akash-network/node/testutil/cli" - "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" + banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" types "github.com/akash-network/akash-api/go/node/deployment/v1beta3" "github.com/akash-network/node/testutil" + clitestutil "github.com/akash-network/node/testutil/cli" + "github.com/akash-network/node/testutil/network" ccli "github.com/akash-network/node/x/cert/client/cli" "github.com/akash-network/node/x/deployment/client/cli" ) diff --git a/x/deployment/client/cli/grpc_rest_test.go b/x/deployment/client/cli/grpc_rest_test.go index 274c38b174..4a23e0602f 100644 --- a/x/deployment/client/cli/grpc_rest_test.go +++ b/x/deployment/client/cli/grpc_rest_test.go @@ -9,12 +9,13 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" sdkrest "github.com/cosmos/cosmos-sdk/types/rest" types "github.com/akash-network/akash-api/go/node/deployment/v1beta3" + "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" atypes "github.com/akash-network/node/types" ccli "github.com/akash-network/node/x/cert/client/cli" "github.com/akash-network/node/x/deployment/client/cli" diff --git a/x/market/client/cli/cli_test.go b/x/market/client/cli/cli_test.go index f2fa7ce2e0..3ee4804bd1 100644 --- a/x/market/client/cli/cli_test.go +++ b/x/market/client/cli/cli_test.go @@ -11,17 +11,16 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" dtypes "github.com/akash-network/akash-api/go/node/deployment/v1beta3" types "github.com/akash-network/akash-api/go/node/market/v1beta3" - ptypes "github.com/akash-network/akash-api/go/node/provider/v1beta3" "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" ccli "github.com/akash-network/node/x/cert/client/cli" dcli "github.com/akash-network/node/x/deployment/client/cli" "github.com/akash-network/node/x/market/client/cli" diff --git a/x/market/client/cli/grpc_rest_test.go b/x/market/client/cli/grpc_rest_test.go index 5d8dc997a6..9c4dde3f29 100644 --- a/x/market/client/cli/grpc_rest_test.go +++ b/x/market/client/cli/grpc_rest_test.go @@ -11,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" sdkrest "github.com/cosmos/cosmos-sdk/types/rest" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" @@ -19,6 +18,7 @@ import ( types "github.com/akash-network/akash-api/go/node/market/v1beta3" "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" atypes "github.com/akash-network/node/types" ccli "github.com/akash-network/node/x/cert/client/cli" dcli "github.com/akash-network/node/x/deployment/client/cli" diff --git a/x/provider/client/cli/cli_test.go b/x/provider/client/cli/cli_test.go index 998cf9bda1..a6e8ceffab 100644 --- a/x/provider/client/cli/cli_test.go +++ b/x/provider/client/cli/cli_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" types "github.com/akash-network/akash-api/go/node/provider/v1beta3" "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" "github.com/akash-network/node/x/provider/client/cli" ) diff --git a/x/provider/client/cli/grpc_rest_test.go b/x/provider/client/cli/grpc_rest_test.go index fde7afc656..513405d458 100644 --- a/x/provider/client/cli/grpc_rest_test.go +++ b/x/provider/client/cli/grpc_rest_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/suite" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" sdkrest "github.com/cosmos/cosmos-sdk/types/rest" types "github.com/akash-network/akash-api/go/node/provider/v1beta3" "github.com/akash-network/node/testutil" + "github.com/akash-network/node/testutil/network" "github.com/akash-network/node/x/provider/client/cli" )