<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺ v ✰ Thanks for creating a PR! ✰ v Before smashing the submit button please review the checkboxes. v If a checkbox is n/a - please still include it but + a little note why ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> ## Description <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> closes: #9106 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x/<module>/spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes
222 lines
5.5 KiB
Go
222 lines
5.5 KiB
Go
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"
|
|
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 a 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)
|
|
|
|
// Add the tx service in the gRPC router.
|
|
app.RegisterTxService(val.ClientCtx)
|
|
|
|
// Add the tendermint queries service in the gRPC router.
|
|
app.RegisterTendermintService(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(5 * time.Second): // 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 {
|
|
errCh1 := make(chan error)
|
|
go func() {
|
|
grpcWeb, err := servergrpc.StartGRPCWeb(grpcSrv, *val.AppConfig)
|
|
if err != nil {
|
|
errCh1 <- err
|
|
}
|
|
|
|
val.grpcWeb = grpcWeb
|
|
}()
|
|
select {
|
|
case err := <-errCh1:
|
|
return err
|
|
case <-time.After(5 * time.Second): // assume server started successfully
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
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)
|
|
file := filepath.Join(writePath, name)
|
|
|
|
err := tmos.EnsureDir(writePath, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = tmos.WriteFile(file, contents, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|