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 }