github.com/cosmos/cosmos-sdk@v0.50.10/testutil/network/util.go (about)

     1  package network
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	cmtcfg "github.com/cometbft/cometbft/config"
    12  	"github.com/cometbft/cometbft/node"
    13  	"github.com/cometbft/cometbft/p2p"
    14  	pvm "github.com/cometbft/cometbft/privval"
    15  	"github.com/cometbft/cometbft/proxy"
    16  	"github.com/cometbft/cometbft/rpc/client/local"
    17  	cmttypes "github.com/cometbft/cometbft/types"
    18  	cmttime "github.com/cometbft/cometbft/types/time"
    19  	"golang.org/x/sync/errgroup"
    20  
    21  	"cosmossdk.io/log"
    22  
    23  	"github.com/cosmos/cosmos-sdk/server"
    24  	"github.com/cosmos/cosmos-sdk/server/api"
    25  	servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
    26  	servercmtlog "github.com/cosmos/cosmos-sdk/server/log"
    27  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    28  	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
    29  	"github.com/cosmos/cosmos-sdk/x/genutil"
    30  	genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
    31  )
    32  
    33  func startInProcess(cfg Config, val *Validator) error {
    34  	logger := val.Ctx.Logger
    35  	cmtCfg := val.Ctx.Config
    36  	cmtCfg.Instrumentation.Prometheus = false
    37  
    38  	if err := val.AppConfig.ValidateBasic(); err != nil {
    39  		return err
    40  	}
    41  
    42  	nodeKey, err := p2p.LoadOrGenNodeKey(cmtCfg.NodeKeyFile())
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	app := cfg.AppConstructor(*val)
    48  	val.app = app
    49  
    50  	appGenesisProvider := func() (*cmttypes.GenesisDoc, error) {
    51  		appGenesis, err := genutiltypes.AppGenesisFromFile(cmtCfg.GenesisFile())
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		return appGenesis.ToGenesisDoc()
    57  	}
    58  
    59  	cmtApp := server.NewCometABCIWrapper(app)
    60  	tmNode, err := node.NewNode( //resleak:notresource
    61  		cmtCfg,
    62  		pvm.LoadOrGenFilePV(cmtCfg.PrivValidatorKeyFile(), cmtCfg.PrivValidatorStateFile()),
    63  		nodeKey,
    64  		proxy.NewLocalClientCreator(cmtApp),
    65  		appGenesisProvider,
    66  		cmtcfg.DefaultDBProvider,
    67  		node.DefaultMetricsProvider(cmtCfg.Instrumentation),
    68  		servercmtlog.CometLoggerWrapper{Logger: logger.With("module", val.Moniker)},
    69  	)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	if err := tmNode.Start(); err != nil {
    75  		return err
    76  	}
    77  	val.tmNode = tmNode
    78  
    79  	if val.RPCAddress != "" {
    80  		val.RPCClient = local.New(tmNode)
    81  	}
    82  
    83  	// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
    84  	if val.APIAddress != "" || val.AppConfig.GRPC.Enable {
    85  		val.ClientCtx = val.ClientCtx.
    86  			WithClient(val.RPCClient)
    87  
    88  		app.RegisterTxService(val.ClientCtx)
    89  		app.RegisterTendermintService(val.ClientCtx)
    90  		app.RegisterNodeService(val.ClientCtx, *val.AppConfig)
    91  	}
    92  
    93  	ctx := context.Background()
    94  	ctx, val.cancelFn = context.WithCancel(ctx)
    95  	val.errGroup, ctx = errgroup.WithContext(ctx)
    96  
    97  	grpcCfg := val.AppConfig.GRPC
    98  
    99  	if grpcCfg.Enable {
   100  		grpcSrv, err := servergrpc.NewGRPCServer(val.ClientCtx, app, grpcCfg)
   101  		if err != nil {
   102  			return err
   103  		}
   104  
   105  		// Start the gRPC server in a goroutine. Note, the provided ctx will ensure
   106  		// that the server is gracefully shut down.
   107  		val.errGroup.Go(func() error {
   108  			return servergrpc.StartGRPCServer(ctx, logger.With(log.ModuleKey, "grpc-server"), grpcCfg, grpcSrv)
   109  		})
   110  
   111  		val.grpc = grpcSrv
   112  	}
   113  
   114  	if val.APIAddress != "" {
   115  		apiSrv := api.New(val.ClientCtx, logger.With(log.ModuleKey, "api-server"), val.grpc)
   116  		app.RegisterAPIRoutes(apiSrv, val.AppConfig.API)
   117  
   118  		val.errGroup.Go(func() error {
   119  			return apiSrv.Start(ctx, *val.AppConfig)
   120  		})
   121  
   122  		val.api = apiSrv
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error {
   129  	genTime := cmttime.Now()
   130  
   131  	for i := 0; i < cfg.NumValidators; i++ {
   132  		cmtCfg := vals[i].Ctx.Config
   133  
   134  		nodeDir := filepath.Join(outputDir, vals[i].Moniker, "simd")
   135  		gentxsDir := filepath.Join(outputDir, "gentxs")
   136  
   137  		cmtCfg.Moniker = vals[i].Moniker
   138  		cmtCfg.SetRoot(nodeDir)
   139  
   140  		initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey)
   141  
   142  		genFile := cmtCfg.GenesisFile()
   143  		appGenesis, err := genutiltypes.AppGenesisFromFile(genFile)
   144  		if err != nil {
   145  			return err
   146  		}
   147  
   148  		appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig,
   149  			cmtCfg, initCfg, appGenesis, banktypes.GenesisBalancesIterator{}, genutiltypes.DefaultMessageValidator, cfg.TxConfig.SigningContext().ValidatorAddressCodec())
   150  		if err != nil {
   151  			return err
   152  		}
   153  
   154  		// overwrite each validator's genesis file to have a canonical genesis time
   155  		if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil {
   156  			return err
   157  		}
   158  	}
   159  
   160  	return nil
   161  }
   162  
   163  func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error {
   164  	// set the accounts in the genesis state
   165  	var authGenState authtypes.GenesisState
   166  	cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState)
   167  
   168  	accounts, err := authtypes.PackAccounts(genAccounts)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	authGenState.Accounts = append(authGenState.Accounts, accounts...)
   174  	cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState)
   175  
   176  	// set the balances in the genesis state
   177  	var bankGenState banktypes.GenesisState
   178  	cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState)
   179  
   180  	bankGenState.Balances = append(bankGenState.Balances, genBalances...)
   181  	cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState)
   182  
   183  	appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", "  ")
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	appGenesis := genutiltypes.AppGenesis{
   189  		ChainID:  cfg.ChainID,
   190  		AppState: appGenStateJSON,
   191  		Consensus: &genutiltypes.ConsensusGenesis{
   192  			Validators: nil,
   193  		},
   194  	}
   195  
   196  	// generate empty genesis files for each validator and save
   197  	for i := 0; i < cfg.NumValidators; i++ {
   198  		if err := appGenesis.SaveAs(genFiles[i]); err != nil {
   199  			return err
   200  		}
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func writeFile(name, dir string, contents []byte) error {
   207  	file := filepath.Join(dir, name)
   208  
   209  	if err := os.MkdirAll(dir, 0o755); err != nil {
   210  		return fmt.Errorf("could not create directory %q: %w", dir, err)
   211  	}
   212  
   213  	if err := os.WriteFile(file, contents, 0o600); err != nil {
   214  		return err
   215  	}
   216  
   217  	return nil
   218  }
   219  
   220  // Get a free address for a test CometBFT server
   221  // protocol is either tcp, http, etc
   222  func FreeTCPAddr() (addr, port string, closeFn func() error, err error) {
   223  	l, err := net.Listen("tcp", "127.0.0.1:0")
   224  	if err != nil {
   225  		return "", "", nil, err
   226  	}
   227  
   228  	closeFn = func() error {
   229  		return l.Close()
   230  	}
   231  
   232  	portI := l.Addr().(*net.TCPAddr).Port
   233  	port = fmt.Sprintf("%d", portI)
   234  	addr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
   235  	return
   236  }