263 lines
7.4 KiB
Go
263 lines
7.4 KiB
Go
package network
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
|
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"
|
|
crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
|
|
"github.com/cosmos/cosmos-sdk/x/genutil"
|
|
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
|
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
|
mintypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
|
|
|
"github.com/evmos/ethermint/server"
|
|
evmtypes "github.com/evmos/ethermint/x/evm/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.AppConfig.API.Enable && 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.Config); 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.Config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
if val.AppConfig.JSONRPC.Enable && val.AppConfig.JSONRPC.Address != "" {
|
|
if val.Ctx == nil || val.Ctx.Viper == nil {
|
|
return fmt.Errorf("validator %s context is nil", val.Moniker)
|
|
}
|
|
|
|
tmEndpoint := "/websocket"
|
|
tmRPCAddr := val.RPCAddress
|
|
|
|
val.jsonrpc, val.jsonrpcDone, err = server.StartJSONRPC(val.Ctx, val.ClientCtx, tmRPCAddr, tmEndpoint, *val.AppConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
address := fmt.Sprintf("http://%s", val.AppConfig.JSONRPC.Address)
|
|
|
|
val.JSONRPCClient, err = ethclient.Dial(address)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to dial JSON-RPC at %s: %w", val.AppConfig.JSONRPC.Address, 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, "evmosd")
|
|
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
|
|
bankGenState.Balances = genBalances
|
|
cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState)
|
|
|
|
var stakingGenState stakingtypes.GenesisState
|
|
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[stakingtypes.ModuleName], &stakingGenState)
|
|
|
|
stakingGenState.Params.BondDenom = cfg.BondDenom
|
|
cfg.GenesisState[stakingtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&stakingGenState)
|
|
|
|
var govGenState govtypes.GenesisState
|
|
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[govtypes.ModuleName], &govGenState)
|
|
|
|
govGenState.DepositParams.MinDeposit[0].Denom = cfg.BondDenom
|
|
cfg.GenesisState[govtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&govGenState)
|
|
|
|
var mintGenState mintypes.GenesisState
|
|
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[mintypes.ModuleName], &mintGenState)
|
|
|
|
mintGenState.Params.MintDenom = cfg.BondDenom
|
|
cfg.GenesisState[mintypes.ModuleName] = cfg.Codec.MustMarshalJSON(&mintGenState)
|
|
|
|
var crisisGenState crisistypes.GenesisState
|
|
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[crisistypes.ModuleName], &crisisGenState)
|
|
|
|
crisisGenState.ConstantFee.Denom = cfg.BondDenom
|
|
cfg.GenesisState[crisistypes.ModuleName] = cfg.Codec.MustMarshalJSON(&crisisGenState)
|
|
|
|
var evmGenState evmtypes.GenesisState
|
|
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[evmtypes.ModuleName], &evmGenState)
|
|
|
|
evmGenState.Params.EvmDenom = cfg.BondDenom
|
|
cfg.GenesisState[evmtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&evmGenState)
|
|
|
|
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 {
|
|
file := filepath.Join(dir, name)
|
|
|
|
err := tmos.EnsureDir(dir, 0o755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return tmos.WriteFile(file, contents, 0o644)
|
|
}
|