2021-06-29 17:02:21 +00:00
package server
2021-04-18 16:39:15 +00:00
import (
"context"
2021-07-23 12:31:59 +00:00
"fmt"
2021-04-18 16:39:15 +00:00
"io"
2022-10-10 10:38:33 +00:00
"net"
2021-04-18 16:39:15 +00:00
"net/http"
"os"
"path/filepath"
"runtime/pprof"
2021-08-16 09:45:10 +00:00
"strings"
2021-04-18 16:39:15 +00:00
"time"
2021-07-23 12:31:59 +00:00
"github.com/cosmos/cosmos-sdk/codec"
2021-10-06 11:41:42 +00:00
"github.com/cosmos/cosmos-sdk/crypto/keyring"
2021-07-23 12:31:59 +00:00
2021-04-18 16:39:15 +00:00
"github.com/spf13/cobra"
2021-08-19 16:55:13 +00:00
2021-04-18 16:39:15 +00:00
"google.golang.org/grpc"
2022-10-10 10:38:33 +00:00
"google.golang.org/grpc/credentials/insecure"
2021-04-18 16:39:15 +00:00
2022-10-10 10:38:33 +00:00
abciserver "github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/tendermint/tendermint/node"
2022-09-30 06:41:39 +00:00
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
2022-10-10 10:38:33 +00:00
"github.com/tendermint/tendermint/rpc/client/local"
2022-09-30 06:41:39 +00:00
dbm "github.com/tendermint/tm-db"
2022-10-10 10:38:33 +00:00
"github.com/cosmos/cosmos-sdk/server/rosetta"
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
2021-04-18 16:39:15 +00:00
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
2021-07-23 12:31:59 +00:00
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
2021-04-18 16:39:15 +00:00
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
"github.com/cosmos/cosmos-sdk/server/types"
2022-10-10 10:38:33 +00:00
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
2021-04-18 16:39:15 +00:00
2022-10-12 07:34:44 +00:00
"github.com/cerc-io/laconicd/gql"
2022-10-10 10:38:33 +00:00
"github.com/cerc-io/laconicd/indexer"
ethdebug "github.com/cerc-io/laconicd/rpc/namespaces/ethereum/debug"
2022-09-07 06:36:11 +00:00
"github.com/cerc-io/laconicd/server/config"
srvflags "github.com/cerc-io/laconicd/server/flags"
2022-10-10 10:38:33 +00:00
ethermint "github.com/cerc-io/laconicd/types"
2022-04-11 08:09:39 +00:00
)
2021-04-18 16:39:15 +00:00
// StartCmd runs the service passed in, either stand-alone or in-process with
// Tendermint.
func StartCmd ( appCreator types . AppCreator , defaultNodeHome string ) * cobra . Command {
cmd := & cobra . Command {
Use : "start" ,
Short : "Run the full node" ,
Long : ` Run the full node application with Tendermint in or out of process . By
default , the application will run with Tendermint in process .
Pruning options can be provided via the ' -- pruning ' flag or alternatively with ' -- pruning - keep - recent ' ,
' pruning - keep - every ' , and ' pruning - interval ' together .
For ' -- pruning ' the options are as follows :
default : the last 100 states are kept in addition to every 500 th state ; pruning at 10 block intervals
nothing : all historic states will be saved , nothing will be deleted ( i . e . archiving node )
everything : all saved states will be deleted , storing only the current state ; pruning at 10 block intervals
custom : allow pruning options to be manually specified through ' pruning - keep - recent ' , ' pruning - keep - every ' , and ' pruning - interval '
Node halting configurations exist in the form of two flags : ' -- halt - height ' and ' -- halt - time ' . During
the ABCI Commit phase , the node will check if the current block height is greater than or equal to
the halt - height or if the current block time is greater than or equal to the halt - time . If so , the
node will attempt to gracefully shutdown and the block will not be committed . In addition , the node
will not be able to commit subsequent blocks .
For profiling and benchmarking purposes , CPU profiling can be enabled via the ' -- cpu - profile ' flag
which accepts a path for the resulting pprof file .
` ,
PreRunE : func ( cmd * cobra . Command , _ [ ] string ) error {
serverCtx := server . GetServerContextFromCmd ( cmd )
// Bind flags to the Context's Viper so the app construction can set
// options accordingly.
2021-06-08 07:07:11 +00:00
err := serverCtx . Viper . BindPFlags ( cmd . Flags ( ) )
if err != nil {
return err
}
2021-04-18 16:39:15 +00:00
2021-06-08 07:07:11 +00:00
_ , err = server . GetPruningOptionsFromFlags ( serverCtx . Viper )
2021-04-18 16:39:15 +00:00
return err
} ,
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
serverCtx := server . GetServerContextFromCmd ( cmd )
2021-07-23 12:31:59 +00:00
clientCtx , err := client . GetClientQueryContext ( cmd )
if err != nil {
return err
}
2021-08-16 09:45:10 +00:00
withTM , _ := cmd . Flags ( ) . GetBool ( srvflags . WithTendermint )
2021-07-23 12:31:59 +00:00
if ! withTM {
serverCtx . Logger . Info ( "starting ABCI without Tendermint" )
return startStandAlone ( serverCtx , appCreator )
}
2021-04-18 16:39:15 +00:00
2021-10-06 11:41:42 +00:00
serverCtx . Logger . Info ( "Unlocking keyring" )
// fire unlock precess for keyring
keyringBackend , _ := cmd . Flags ( ) . GetString ( flags . FlagKeyringBackend )
if keyringBackend == keyring . BackendFile {
_ , err = clientCtx . Keyring . List ( )
if err != nil {
return err
}
}
2021-04-18 16:39:15 +00:00
serverCtx . Logger . Info ( "starting ABCI with Tendermint" )
// amino is needed here for backwards compatibility of REST routes
2021-07-23 12:31:59 +00:00
err = startInProcess ( serverCtx , clientCtx , appCreator )
errCode , ok := err . ( server . ErrorCode )
if ! ok {
return err
}
serverCtx . Logger . Debug ( fmt . Sprintf ( "received quit signal: %d" , errCode . Code ) )
return nil
2021-04-18 16:39:15 +00:00
} ,
}
cmd . Flags ( ) . String ( flags . FlagHome , defaultNodeHome , "The application home directory" )
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Bool ( srvflags . WithTendermint , true , "Run abci app embedded in-process with tendermint" )
cmd . Flags ( ) . String ( srvflags . Address , "tcp://0.0.0.0:26658" , "Listen address" )
cmd . Flags ( ) . String ( srvflags . Transport , "socket" , "Transport protocol: socket, grpc" )
cmd . Flags ( ) . String ( srvflags . TraceStore , "" , "Enable KVStore tracing to an output file" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . String ( server . FlagMinGasPrices , "" , "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photon;0.0001stake)" ) //nolint:lll
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . IntSlice ( server . FlagUnsafeSkipUpgrades , [ ] int { } , "Skip a set of upgrade heights to continue the old binary" )
cmd . Flags ( ) . Uint64 ( server . FlagHaltHeight , 0 , "Block height at which to gracefully halt the chain and shutdown the node" )
cmd . Flags ( ) . Uint64 ( server . FlagHaltTime , 0 , "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node" )
cmd . Flags ( ) . Bool ( server . FlagInterBlockCache , true , "Enable inter-block caching" )
cmd . Flags ( ) . String ( srvflags . CPUProfile , "" , "Enable CPU profiling and write to the provided file" )
cmd . Flags ( ) . Bool ( server . FlagTrace , false , "Provide full stack traces for errors in ABCI Log" )
2022-06-06 12:37:13 +00:00
cmd . Flags ( ) . String ( server . FlagPruning , pruningtypes . PruningOptionDefault , "Pruning strategy (default|nothing|everything|custom)" )
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Uint64 ( server . FlagPruningKeepRecent , 0 , "Number of recent heights to keep on disk (ignored if pruning is not 'custom')" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . Uint64 ( server . FlagPruningInterval , 0 , "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')" ) //nolint:lll
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Uint ( server . FlagInvCheckPeriod , 0 , "Assert registered invariants every N blocks" )
cmd . Flags ( ) . Uint64 ( server . FlagMinRetainBlocks , 0 , "Minimum block height offset during ABCI commit to prune Tendermint blocks" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . String ( srvflags . AppDBBackend , "" , "The type of database for application and snapshots databases" )
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Bool ( srvflags . GRPCEnable , true , "Define if the gRPC server should be enabled" )
cmd . Flags ( ) . String ( srvflags . GRPCAddress , serverconfig . DefaultGRPCAddress , "the gRPC server address to listen on" )
cmd . Flags ( ) . Bool ( srvflags . GRPCWebEnable , true , "Define if the gRPC-Web server should be enabled. (Note: gRPC must also be enabled.)" )
cmd . Flags ( ) . String ( srvflags . GRPCWebAddress , serverconfig . DefaultGRPCWebAddress , "The gRPC-Web server address to listen on" )
2022-01-17 18:08:02 +00:00
cmd . Flags ( ) . Bool ( srvflags . RPCEnable , false , "Defines if Cosmos-sdk REST server should be enabled" )
2022-03-15 19:59:31 +00:00
cmd . Flags ( ) . Bool ( srvflags . EnabledUnsafeCors , false , "Defines if CORS should be enabled (unsafe - use it at your own risk)" )
2022-01-17 18:08:02 +00:00
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Bool ( srvflags . JSONRPCEnable , true , "Define if the gRPC server should be enabled" )
cmd . Flags ( ) . StringSlice ( srvflags . JSONRPCAPI , config . GetDefaultAPINamespaces ( ) , "Defines a list of JSON-RPC namespaces that should be enabled" )
cmd . Flags ( ) . String ( srvflags . JSONRPCAddress , config . DefaultJSONRPCAddress , "the JSON-RPC server address to listen on" )
cmd . Flags ( ) . String ( srvflags . JSONWsAddress , config . DefaultJSONRPCWsAddress , "the JSON-RPC WS server address to listen on" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . Uint64 ( srvflags . JSONRPCGasCap , config . DefaultGasCap , "Sets a cap on gas that can be used in eth_call/estimateGas unit is aphoton (0=infinite)" ) //nolint:lll
cmd . Flags ( ) . Float64 ( srvflags . JSONRPCTxFeeCap , config . DefaultTxFeeCap , "Sets a cap on transaction fee that can be sent via the RPC APIs (1 = default 1 photon)" ) //nolint:lll
2021-10-13 11:03:49 +00:00
cmd . Flags ( ) . Int32 ( srvflags . JSONRPCFilterCap , config . DefaultFilterCap , "Sets the global cap for total number of filters that can be created" )
2021-10-25 15:01:04 +00:00
cmd . Flags ( ) . Duration ( srvflags . JSONRPCEVMTimeout , config . DefaultEVMTimeout , "Sets a timeout used for eth_call (0=infinite)" )
2022-03-09 07:31:51 +00:00
cmd . Flags ( ) . Duration ( srvflags . JSONRPCHTTPTimeout , config . DefaultHTTPTimeout , "Sets a read/write timeout for json-rpc http server (0=infinite)" )
cmd . Flags ( ) . Duration ( srvflags . JSONRPCHTTPIdleTimeout , config . DefaultHTTPIdleTimeout , "Sets a idle timeout for json-rpc http server (0=infinite)" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . Bool ( srvflags . JSONRPCAllowUnprotectedTxs , config . DefaultAllowUnprotectedTxs , "Allow for unprotected (non EIP155 signed) transactions to be submitted via the node's RPC when the global parameter is disabled" ) //nolint:lll
2021-12-29 21:47:25 +00:00
cmd . Flags ( ) . Int32 ( srvflags . JSONRPCLogsCap , config . DefaultLogsCap , "Sets the max number of results can be returned from single `eth_getLogs` query" )
cmd . Flags ( ) . Int32 ( srvflags . JSONRPCBlockRangeCap , config . DefaultBlockRangeCap , "Sets the max block range allowed for `eth_getLogs` query" )
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . Int ( srvflags . JSONRPCMaxOpenConnections , config . DefaultMaxOpenConnections , "Sets the maximum number of simultaneous connections for the server listener" ) //nolint:lll
cmd . Flags ( ) . Bool ( srvflags . JSONRPCEnableIndexer , false , "Enable the custom tx indexer for json-rpc" )
2021-08-16 09:45:10 +00:00
2022-10-10 10:38:33 +00:00
cmd . Flags ( ) . String ( srvflags . EVMTracer , config . DefaultEVMTracer , "the EVM tracer type to collect execution traces from the EVM transaction execution (json|struct|access_list|markdown)" ) //nolint:lll
cmd . Flags ( ) . Uint64 ( srvflags . EVMMaxTxGasWanted , config . DefaultMaxTxGasWanted , "the gas wanted for each eth tx returned in ante handler in check tx mode" ) //nolint:lll
2021-08-16 09:45:10 +00:00
2021-09-28 11:33:54 +00:00
cmd . Flags ( ) . String ( srvflags . TLSCertPath , "" , "the cert.pem file path for the server TLS configuration" )
cmd . Flags ( ) . String ( srvflags . TLSKeyPath , "" , "the key.pem file path for the server TLS configuration" )
2021-08-16 09:45:10 +00:00
cmd . Flags ( ) . Uint64 ( server . FlagStateSyncSnapshotInterval , 0 , "State sync snapshot interval" )
cmd . Flags ( ) . Uint32 ( server . FlagStateSyncSnapshotKeepRecent , 2 , "State sync snapshot to keep" )
2021-04-18 16:39:15 +00:00
// add support for all Tendermint-specific command line options
tcmd . AddNodeFlags ( cmd )
return cmd
}
2021-07-23 12:31:59 +00:00
func startStandAlone ( ctx * server . Context , appCreator types . AppCreator ) error {
2021-08-16 09:45:10 +00:00
addr := ctx . Viper . GetString ( srvflags . Address )
transport := ctx . Viper . GetString ( srvflags . Transport )
2021-07-23 12:31:59 +00:00
home := ctx . Viper . GetString ( flags . FlagHome )
2022-10-10 10:38:33 +00:00
db , err := openDB ( home , server . GetAppDBBackend ( ctx . Viper ) )
2021-07-23 12:31:59 +00:00
if err != nil {
return err
}
2021-09-09 08:05:26 +00:00
defer func ( ) {
if err := db . Close ( ) ; err != nil {
ctx . Logger . With ( "error" , err ) . Error ( "error closing db" )
}
} ( )
2021-07-23 12:31:59 +00:00
2021-08-16 09:45:10 +00:00
traceWriterFile := ctx . Viper . GetString ( srvflags . TraceStore )
2021-07-23 12:31:59 +00:00
traceWriter , err := openTraceWriter ( traceWriterFile )
if err != nil {
return err
}
app := appCreator ( ctx . Logger , db , traceWriter , ctx . Viper )
svr , err := abciserver . NewServer ( addr , transport , app )
if err != nil {
return fmt . Errorf ( "error creating listener: %v" , err )
}
svr . SetLogger ( ctx . Logger . With ( "server" , "abci" ) )
err = svr . Start ( )
if err != nil {
tmos . Exit ( err . Error ( ) )
}
defer func ( ) {
if err = svr . Stop ( ) ; err != nil {
tmos . Exit ( err . Error ( ) )
}
} ( )
// Wait for SIGINT or SIGTERM signal
return server . WaitForQuitSignals ( )
}
// legacyAminoCdc is used for the legacy REST API
2021-11-25 15:12:57 +00:00
func startInProcess ( ctx * server . Context , clientCtx client . Context , appCreator types . AppCreator ) ( err error ) {
2021-04-18 16:39:15 +00:00
cfg := ctx . Config
home := cfg . RootDir
2021-07-12 18:39:35 +00:00
logger := ctx . Logger
2021-11-25 15:12:57 +00:00
var cpuProfileCleanup func ( ) error
2021-07-23 12:31:59 +00:00
2021-08-16 09:45:10 +00:00
if cpuProfile := ctx . Viper . GetString ( srvflags . CPUProfile ) ; cpuProfile != "" {
2021-10-13 10:52:05 +00:00
fp , err := ethdebug . ExpandHome ( cpuProfile )
if err != nil {
ctx . Logger . Debug ( "failed to get filepath for the CPU profile file" , "error" , err . Error ( ) )
return err
}
f , err := os . Create ( fp )
2021-07-23 12:31:59 +00:00
if err != nil {
return err
}
ctx . Logger . Info ( "starting CPU profiler" , "profile" , cpuProfile )
if err := pprof . StartCPUProfile ( f ) ; err != nil {
return err
}
2021-11-25 15:12:57 +00:00
cpuProfileCleanup = func ( ) error {
2021-07-23 12:31:59 +00:00
ctx . Logger . Info ( "stopping CPU profiler" , "profile" , cpuProfile )
pprof . StopCPUProfile ( )
2021-11-25 15:12:57 +00:00
if err := f . Close ( ) ; err != nil {
logger . Error ( "failed to close CPU profiler file" , "error" , err . Error ( ) )
return err
}
return nil
2021-07-23 12:31:59 +00:00
}
}
2021-04-18 16:39:15 +00:00
2021-08-16 09:45:10 +00:00
traceWriterFile := ctx . Viper . GetString ( srvflags . TraceStore )
2022-04-11 08:09:39 +00:00
db , err := openDB ( home , server . GetAppDBBackend ( ctx . Viper ) )
2021-04-18 16:39:15 +00:00
if err != nil {
2022-10-10 10:38:33 +00:00
logger . Error ( "failed to open DB" , "error" , err . Error ( ) )
2021-04-18 16:39:15 +00:00
return err
}
2021-09-09 08:05:26 +00:00
defer func ( ) {
if err := db . Close ( ) ; err != nil {
ctx . Logger . With ( "error" , err ) . Error ( "error closing db" )
}
} ( )
2021-04-18 16:39:15 +00:00
traceWriter , err := openTraceWriter ( traceWriterFile )
if err != nil {
2021-07-12 18:39:35 +00:00
logger . Error ( "failed to open trace writer" , "error" , err . Error ( ) )
2021-04-18 16:39:15 +00:00
return err
}
2022-09-30 06:41:39 +00:00
config , err := config . GetConfig ( ctx . Viper )
if err != nil {
logger . Error ( "failed to get server config" , "error" , err . Error ( ) )
return err
}
2021-08-16 09:45:10 +00:00
2021-07-23 12:31:59 +00:00
if err := config . ValidateBasic ( ) ; err != nil {
2021-08-16 09:45:10 +00:00
if strings . Contains ( err . Error ( ) , "set min gas price in app.toml or flag or env variable" ) {
ctx . Logger . Error (
"WARNING: The minimum-gas-prices config in app.toml is set to the empty string. " +
"This defaults to 0 in the current version, but will error in the next version " +
"(SDK v0.44). Please explicitly put the desired minimum-gas-prices in your app.toml." ,
)
} else {
return err
}
2021-07-23 12:31:59 +00:00
}
2021-04-18 16:39:15 +00:00
app := appCreator ( ctx . Logger , db , traceWriter , ctx . Viper )
2022-09-30 06:41:39 +00:00
nodeKey , err := p2p . LoadOrGenNodeKey ( cfg . NodeKeyFile ( ) )
2021-04-18 16:39:15 +00:00
if err != nil {
2022-09-30 06:41:39 +00:00
logger . Error ( "failed load or gen node key" , "error" , err . Error ( ) )
2021-04-18 16:39:15 +00:00
return err
}
2022-09-30 06:41:39 +00:00
genDocProvider := node . DefaultGenesisDocProviderFunc ( cfg )
tmNode , err := node . NewNode (
cfg ,
pvm . LoadOrGenFilePV ( cfg . PrivValidatorKeyFile ( ) , cfg . PrivValidatorStateFile ( ) ) ,
nodeKey ,
proxy . NewLocalClientCreator ( app ) ,
genDocProvider ,
node . DefaultDBProvider ,
node . DefaultMetricsProvider ( cfg . Instrumentation ) ,
ctx . Logger . With ( "server" , "node" ) ,
2021-04-18 16:39:15 +00:00
)
2022-09-30 06:41:39 +00:00
if err != nil {
logger . Error ( "failed init node" , "error" , err . Error ( ) )
return err
}
2022-04-11 08:09:39 +00:00
2022-09-30 06:41:39 +00:00
if err := tmNode . Start ( ) ; err != nil {
logger . Error ( "failed start tendermint server" , "error" , err . Error ( ) )
return err
2021-04-18 16:39:15 +00:00
}
2021-07-23 12:31:59 +00:00
// Add the tx service to the gRPC router. We only need to register this
2022-03-15 10:28:14 +00:00
// service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general
2021-07-23 12:31:59 +00:00
// case, because it spawns a new local tendermint RPC client.
2022-10-10 10:38:33 +00:00
if config . API . Enable || config . GRPC . Enable || config . JSONRPC . Enable || config . JSONRPC . EnableIndexer {
2022-09-30 06:41:39 +00:00
clientCtx = clientCtx . WithClient ( local . New ( tmNode ) )
2021-04-18 16:39:15 +00:00
2021-07-23 12:31:59 +00:00
app . RegisterTxService ( clientCtx )
app . RegisterTendermintService ( clientCtx )
}
2021-04-18 16:39:15 +00:00
2022-10-10 10:38:33 +00:00
var idxer ethermint . EVMTxIndexer
if config . JSONRPC . EnableIndexer {
idxDB , err := OpenIndexerDB ( home , server . GetAppDBBackend ( ctx . Viper ) )
2021-04-18 16:39:15 +00:00
if err != nil {
2022-10-10 10:38:33 +00:00
logger . Error ( "failed to open evm indexer DB" , "error" , err . Error ( ) )
2021-06-25 09:18:37 +00:00
return err
2021-04-18 16:39:15 +00:00
}
2022-10-10 10:38:33 +00:00
idxLogger := ctx . Logger . With ( "module" , "evmindex" )
idxer = indexer . NewKVIndexer ( idxDB , idxLogger , clientCtx )
indexerService := NewEVMIndexerService ( idxer , clientCtx . Client )
indexerService . SetLogger ( idxLogger )
2021-04-18 16:39:15 +00:00
2022-10-10 10:38:33 +00:00
errCh := make ( chan error )
go func ( ) {
if err := indexerService . Start ( ) ; err != nil {
errCh <- err
}
} ( )
select {
case err := <- errCh :
return err
case <- time . After ( types . ServerStartTime ) : // assume server started successfully
}
}
if config . API . Enable || config . JSONRPC . Enable {
genDoc , err := genDocProvider ( )
if err != nil {
return err
}
clientCtx = clientCtx .
2021-07-23 12:31:59 +00:00
WithHomeDir ( home ) .
WithChainID ( genDoc . ChainID )
2021-04-18 16:39:15 +00:00
2022-10-10 10:38:33 +00:00
// Set `GRPCClient` to `clientCtx` to enjoy concurrent grpc query.
// only use it if gRPC server is enabled.
if config . GRPC . Enable {
_ , port , err := net . SplitHostPort ( config . GRPC . Address )
if err != nil {
return sdkerrors . Wrapf ( err , "invalid grpc address %s" , config . GRPC . Address )
}
maxSendMsgSize := config . GRPC . MaxSendMsgSize
if maxSendMsgSize == 0 {
maxSendMsgSize = serverconfig . DefaultGRPCMaxSendMsgSize
}
maxRecvMsgSize := config . GRPC . MaxRecvMsgSize
if maxRecvMsgSize == 0 {
maxRecvMsgSize = serverconfig . DefaultGRPCMaxRecvMsgSize
}
grpcAddress := fmt . Sprintf ( "127.0.0.1:%s" , port )
// If grpc is enabled, configure grpc client for grpc gateway and json-rpc.
grpcClient , err := grpc . Dial (
grpcAddress ,
grpc . WithTransportCredentials ( insecure . NewCredentials ( ) ) ,
grpc . WithDefaultCallOptions (
grpc . ForceCodec ( codec . NewProtoCodec ( clientCtx . InterfaceRegistry ) . GRPCCodec ( ) ) ,
grpc . MaxCallRecvMsgSize ( maxRecvMsgSize ) ,
grpc . MaxCallSendMsgSize ( maxSendMsgSize ) ,
) ,
)
if err != nil {
return err
}
clientCtx = clientCtx . WithGRPCClient ( grpcClient )
ctx . Logger . Debug ( "gRPC client assigned to client context" , "address" , grpcAddress )
}
}
var apiSrv * api . Server
if config . API . Enable {
2021-07-23 12:31:59 +00:00
apiSrv = api . New ( clientCtx , ctx . Logger . With ( "server" , "api" ) )
app . RegisterAPIRoutes ( apiSrv , config . API )
2021-04-18 16:39:15 +00:00
errCh := make ( chan error )
2021-07-23 12:31:59 +00:00
go func ( ) {
if err := apiSrv . Start ( config . Config ) ; err != nil {
2021-04-18 16:39:15 +00:00
errCh <- err
}
} ( )
select {
case err := <- errCh :
return err
2021-07-23 12:31:59 +00:00
case <- time . After ( types . ServerStartTime ) : // assume server started successfully
2021-04-18 16:39:15 +00:00
}
2021-07-23 12:31:59 +00:00
}
2021-04-18 16:39:15 +00:00
2021-07-23 12:31:59 +00:00
var (
grpcSrv * grpc . Server
grpcWebSrv * http . Server
)
if config . GRPC . Enable {
2022-06-06 12:37:13 +00:00
grpcSrv , err = servergrpc . StartGRPCServer ( clientCtx , app , config . GRPC )
2021-07-23 12:31:59 +00:00
if err != nil {
return err
}
if config . GRPCWeb . Enable {
grpcWebSrv , err = servergrpc . StartGRPCWeb ( grpcSrv , config . Config )
if err != nil {
2021-11-25 15:12:57 +00:00
ctx . Logger . Error ( "failed to start grpc-web http server" , "error" , err )
2021-07-23 12:31:59 +00:00
return err
}
}
2021-04-18 16:39:15 +00:00
}
2021-07-23 12:31:59 +00:00
var rosettaSrv crgserver . Server
if config . Rosetta . Enable {
offlineMode := config . Rosetta . Offline
if ! config . GRPC . Enable { // If GRPC is not enabled rosetta cannot work in online mode, so it works in offline mode.
offlineMode = true
}
conf := & rosetta . Config {
Blockchain : config . Rosetta . Blockchain ,
Network : config . Rosetta . Network ,
TendermintRPC : ctx . Config . RPC . ListenAddress ,
GRPCEndpoint : config . GRPC . Address ,
Addr : config . Rosetta . Address ,
Retries : config . Rosetta . Retries ,
Offline : offlineMode ,
}
conf . WithCodec ( clientCtx . InterfaceRegistry , clientCtx . Codec . ( * codec . ProtoCodec ) )
2021-04-18 16:39:15 +00:00
2021-07-23 12:31:59 +00:00
rosettaSrv , err = rosetta . ServerFromConfig ( conf )
if err != nil {
return err
}
errCh := make ( chan error )
2021-04-18 16:39:15 +00:00
go func ( ) {
2021-07-23 12:31:59 +00:00
if err := rosettaSrv . Start ( ) ; err != nil {
2021-04-18 16:39:15 +00:00
errCh <- err
}
} ( )
select {
case err := <- errCh :
return err
2021-07-23 12:31:59 +00:00
case <- time . After ( types . ServerStartTime ) : // assume server started successfully
2021-04-18 16:39:15 +00:00
}
}
2021-07-23 12:31:59 +00:00
var (
httpSrv * http . Server
httpSrvDone chan struct { }
)
2021-12-13 23:51:36 +00:00
2021-08-16 09:45:10 +00:00
if config . JSONRPC . Enable {
2022-10-10 10:38:33 +00:00
genDoc , err := genDocProvider ( )
2021-04-18 16:39:15 +00:00
if err != nil {
return err
}
2021-07-23 12:31:59 +00:00
clientCtx := clientCtx . WithChainID ( genDoc . ChainID )
2021-04-18 16:39:15 +00:00
2021-07-23 12:31:59 +00:00
tmEndpoint := "/websocket"
tmRPCAddr := cfg . RPC . ListenAddress
2022-10-10 10:38:33 +00:00
httpSrv , httpSrvDone , err = StartJSONRPC ( ctx , clientCtx , tmRPCAddr , tmEndpoint , & config , idxer )
2021-07-23 12:31:59 +00:00
if err != nil {
return err
2021-04-18 16:39:15 +00:00
}
}
2022-10-12 07:34:44 +00:00
// Start the GQL Server
go gql . Server ( clientCtx )
2021-07-23 12:31:59 +00:00
defer func ( ) {
2021-04-18 16:39:15 +00:00
if tmNode . IsRunning ( ) {
_ = tmNode . Stop ( )
}
if cpuProfileCleanup != nil {
2021-11-25 15:12:57 +00:00
_ = cpuProfileCleanup ( )
2021-04-18 16:39:15 +00:00
}
2021-07-23 12:31:59 +00:00
if apiSrv != nil {
_ = apiSrv . Close ( )
}
if grpcSrv != nil {
grpcSrv . Stop ( )
if grpcWebSrv != nil {
2021-11-25 15:12:57 +00:00
if err := grpcWebSrv . Close ( ) ; err != nil {
logger . Error ( "failed to close the grpcWebSrc" , "error" , err . Error ( ) )
}
2021-07-23 12:31:59 +00:00
}
}
2021-04-18 16:39:15 +00:00
if httpSrv != nil {
shutdownCtx , cancelFn := context . WithTimeout ( context . Background ( ) , 10 * time . Second )
defer cancelFn ( )
if err := httpSrv . Shutdown ( shutdownCtx ) ; err != nil {
2021-07-12 18:39:35 +00:00
logger . Error ( "HTTP server shutdown produced a warning" , "error" , err . Error ( ) )
2021-04-18 16:39:15 +00:00
} else {
2021-07-12 18:39:35 +00:00
logger . Info ( "HTTP server shut down, waiting 5 sec" )
2021-04-18 16:39:15 +00:00
select {
case <- time . Tick ( 5 * time . Second ) :
case <- httpSrvDone :
}
}
}
2021-07-12 18:39:35 +00:00
logger . Info ( "Bye!" )
2021-07-23 12:31:59 +00:00
} ( )
2021-04-18 16:39:15 +00:00
2021-07-23 12:31:59 +00:00
// Wait for SIGINT or SIGTERM signal
return server . WaitForQuitSignals ( )
2021-04-18 16:39:15 +00:00
}
2022-09-30 06:41:39 +00:00
func openDB ( rootDir string , backendType dbm . BackendType ) ( dbm . DB , error ) {
2021-04-18 16:39:15 +00:00
dataDir := filepath . Join ( rootDir , "data" )
2022-04-11 08:09:39 +00:00
return dbm . NewDB ( "application" , backendType , dataDir )
2021-04-18 16:39:15 +00:00
}
2022-10-10 10:38:33 +00:00
// OpenIndexerDB opens the custom eth indexer db, using the same db backend as the main app
func OpenIndexerDB ( rootDir string , backendType dbm . BackendType ) ( dbm . DB , error ) {
dataDir := filepath . Join ( rootDir , "data" )
return dbm . NewDB ( "evmindexer" , backendType , dataDir )
}
2021-04-18 16:39:15 +00:00
func openTraceWriter ( traceWriterFile string ) ( w io . Writer , err error ) {
if traceWriterFile == "" {
return
}
2021-11-25 15:12:57 +00:00
filePath := filepath . Clean ( traceWriterFile )
2021-04-18 16:39:15 +00:00
return os . OpenFile (
2021-11-25 15:12:57 +00:00
filePath ,
2021-04-18 16:39:15 +00:00
os . O_WRONLY | os . O_APPEND | os . O_CREATE ,
2021-11-25 15:12:57 +00:00
0 o600 ,
2021-04-18 16:39:15 +00:00
)
}