Skip to content

Commit

Permalink
feat(testutil): implement custom testnet config
Browse files Browse the repository at this point in the history
Signed-off-by: Artur Troian <[email protected]>
  • Loading branch information
troian committed Aug 9, 2023
1 parent b2816ca commit 1b02811
Show file tree
Hide file tree
Showing 11 changed files with 751 additions and 39 deletions.
467 changes: 467 additions & 0 deletions testutil/network/network.go

Large diffs are not rendered by default.

211 changes: 211 additions & 0 deletions testutil/network/util.go
Original file line number Diff line number Diff line change
@@ -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
}
26 changes: 14 additions & 12 deletions testutil/network_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}

Expand All @@ -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
}

Expand Down
54 changes: 44 additions & 10 deletions testutil/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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,
Expand All @@ -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{},
}
}
Loading

0 comments on commit 1b02811

Please sign in to comment.