forked from cerc-io/laconicd-deprecated
update fork
This commit is contained in:
+45
-28
@@ -28,7 +28,7 @@ const (
|
||||
// DefaultEVMTracer is the default vm.Tracer type
|
||||
DefaultEVMTracer = ""
|
||||
|
||||
DefaultMaxTxGasWanted = 500000
|
||||
DefaultMaxTxGasWanted = 0
|
||||
|
||||
DefaultGasCap uint64 = 25000000
|
||||
|
||||
@@ -47,6 +47,10 @@ const (
|
||||
DefaultHTTPTimeout = 30 * time.Second
|
||||
|
||||
DefaultHTTPIdleTimeout = 120 * time.Second
|
||||
// DefaultAllowUnprotectedTxs value is false
|
||||
DefaultAllowUnprotectedTxs = false
|
||||
// DefaultMaxOpenConnections represents the amount of open connections (unlimited = 0)
|
||||
DefaultMaxOpenConnections = 0
|
||||
)
|
||||
|
||||
var evmTracers = []string{"json", "markdown", "struct", "access_list"}
|
||||
@@ -98,6 +102,14 @@ type JSONRPCConfig struct {
|
||||
HTTPTimeout time.Duration `mapstructure:"http-timeout"`
|
||||
// HTTPIdleTimeout is the idle timeout of http json-rpc server.
|
||||
HTTPIdleTimeout time.Duration `mapstructure:"http-idle-timeout"`
|
||||
// AllowUnprotectedTxs restricts unprotected (non EIP155 signed) transactions to be submitted via
|
||||
// the node's RPC when global parameter is disabled.
|
||||
AllowUnprotectedTxs bool `mapstructure:"allow-unprotected-txs"`
|
||||
// MaxOpenConnections sets the maximum number of simultaneous connections
|
||||
// for the server listener.
|
||||
MaxOpenConnections int `mapstructure:"max-open-connections"`
|
||||
// EnableIndexer defines if enable the custom indexer service.
|
||||
EnableIndexer bool `mapstructure:"enable-indexer"`
|
||||
}
|
||||
|
||||
// TLSConfig defines the certificate and matching private key for the server.
|
||||
@@ -183,19 +195,22 @@ func GetAPINamespaces() []string {
|
||||
// DefaultJSONRPCConfig returns an EVM config with the JSON-RPC API enabled by default
|
||||
func DefaultJSONRPCConfig() *JSONRPCConfig {
|
||||
return &JSONRPCConfig{
|
||||
Enable: true,
|
||||
API: GetDefaultAPINamespaces(),
|
||||
Address: DefaultJSONRPCAddress,
|
||||
WsAddress: DefaultJSONRPCWsAddress,
|
||||
GasCap: DefaultGasCap,
|
||||
EVMTimeout: DefaultEVMTimeout,
|
||||
TxFeeCap: DefaultTxFeeCap,
|
||||
FilterCap: DefaultFilterCap,
|
||||
FeeHistoryCap: DefaultFeeHistoryCap,
|
||||
BlockRangeCap: DefaultBlockRangeCap,
|
||||
LogsCap: DefaultLogsCap,
|
||||
HTTPTimeout: DefaultHTTPTimeout,
|
||||
HTTPIdleTimeout: DefaultHTTPIdleTimeout,
|
||||
Enable: true,
|
||||
API: GetDefaultAPINamespaces(),
|
||||
Address: DefaultJSONRPCAddress,
|
||||
WsAddress: DefaultJSONRPCWsAddress,
|
||||
GasCap: DefaultGasCap,
|
||||
EVMTimeout: DefaultEVMTimeout,
|
||||
TxFeeCap: DefaultTxFeeCap,
|
||||
FilterCap: DefaultFilterCap,
|
||||
FeeHistoryCap: DefaultFeeHistoryCap,
|
||||
BlockRangeCap: DefaultBlockRangeCap,
|
||||
LogsCap: DefaultLogsCap,
|
||||
HTTPTimeout: DefaultHTTPTimeout,
|
||||
HTTPIdleTimeout: DefaultHTTPIdleTimeout,
|
||||
AllowUnprotectedTxs: DefaultAllowUnprotectedTxs,
|
||||
MaxOpenConnections: DefaultMaxOpenConnections,
|
||||
EnableIndexer: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +252,7 @@ func (c JSONRPCConfig) Validate() error {
|
||||
return errors.New("JSON-RPC HTTP idle timeout duration cannot be negative")
|
||||
}
|
||||
|
||||
// TODO: validate APIs
|
||||
// check for duplicates
|
||||
seenAPIs := make(map[string]bool)
|
||||
for _, api := range c.API {
|
||||
if seenAPIs[api] {
|
||||
@@ -289,19 +304,21 @@ func GetConfig(v *viper.Viper) (Config, error) {
|
||||
MaxTxGasWanted: v.GetUint64("evm.max-tx-gas-wanted"),
|
||||
},
|
||||
JSONRPC: JSONRPCConfig{
|
||||
Enable: v.GetBool("json-rpc.enable"),
|
||||
API: v.GetStringSlice("json-rpc.api"),
|
||||
Address: v.GetString("json-rpc.address"),
|
||||
WsAddress: v.GetString("json-rpc.ws-address"),
|
||||
GasCap: v.GetUint64("json-rpc.gas-cap"),
|
||||
FilterCap: v.GetInt32("json-rpc.filter-cap"),
|
||||
FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"),
|
||||
TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"),
|
||||
EVMTimeout: v.GetDuration("json-rpc.evm-timeout"),
|
||||
LogsCap: v.GetInt32("json-rpc.logs-cap"),
|
||||
BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"),
|
||||
HTTPTimeout: v.GetDuration("json-rpc.http-timeout"),
|
||||
HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"),
|
||||
Enable: v.GetBool("json-rpc.enable"),
|
||||
API: v.GetStringSlice("json-rpc.api"),
|
||||
Address: v.GetString("json-rpc.address"),
|
||||
WsAddress: v.GetString("json-rpc.ws-address"),
|
||||
GasCap: v.GetUint64("json-rpc.gas-cap"),
|
||||
FilterCap: v.GetInt32("json-rpc.filter-cap"),
|
||||
FeeHistoryCap: v.GetInt32("json-rpc.feehistory-cap"),
|
||||
TxFeeCap: v.GetFloat64("json-rpc.txfee-cap"),
|
||||
EVMTimeout: v.GetDuration("json-rpc.evm-timeout"),
|
||||
LogsCap: v.GetInt32("json-rpc.logs-cap"),
|
||||
BlockRangeCap: v.GetInt32("json-rpc.block-range-cap"),
|
||||
HTTPTimeout: v.GetDuration("json-rpc.http-timeout"),
|
||||
HTTPIdleTimeout: v.GetDuration("json-rpc.http-idle-timeout"),
|
||||
MaxOpenConnections: v.GetInt("json-rpc.max-open-connections"),
|
||||
EnableIndexer: v.GetBool("json-rpc.enable-indexer"),
|
||||
},
|
||||
TLS: TLSConfig{
|
||||
CertificatePath: v.GetString("tls.certificate-path"),
|
||||
|
||||
@@ -62,6 +62,17 @@ http-timeout = "{{ .JSONRPC.HTTPTimeout }}"
|
||||
# HTTPIdleTimeout is the idle timeout of http json-rpc server.
|
||||
http-idle-timeout = "{{ .JSONRPC.HTTPIdleTimeout }}"
|
||||
|
||||
# AllowUnprotectedTxs restricts unprotected (non EIP155 signed) transactions to be submitted via
|
||||
# the node's RPC when the global parameter is disabled.
|
||||
allow-unprotected-txs = {{ .JSONRPC.AllowUnprotectedTxs }}
|
||||
|
||||
# MaxOpenConnections sets the maximum number of simultaneous connections
|
||||
# for the server listener.
|
||||
max-open-connections = {{ .JSONRPC.MaxOpenConnections }}
|
||||
|
||||
# EnableIndexer enables the custom transaction indexer for the EVM (ethereum transactions).
|
||||
enable-indexer = {{ .JSONRPC.EnableIndexer }}
|
||||
|
||||
###############################################################################
|
||||
### TLS Configuration ###
|
||||
###############################################################################
|
||||
|
||||
+20
-30
@@ -5,16 +5,17 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
)
|
||||
|
||||
// Tendermint full-node start flags
|
||||
// Tendermint/cosmos-sdk full-node start flags
|
||||
const (
|
||||
WithTendermint = "with-tendermint"
|
||||
Address = "address"
|
||||
Transport = "transport"
|
||||
TraceStore = "trace-store"
|
||||
CPUProfile = "cpu-profile"
|
||||
// The type of database for application and snapshots databases
|
||||
AppDBBackend = "app-db-backend"
|
||||
)
|
||||
|
||||
// GRPC-related flags.
|
||||
@@ -33,18 +34,21 @@ const (
|
||||
|
||||
// JSON-RPC flags
|
||||
const (
|
||||
JSONRPCEnable = "json-rpc.enable"
|
||||
JSONRPCAPI = "json-rpc.api"
|
||||
JSONRPCAddress = "json-rpc.address"
|
||||
JSONWsAddress = "json-rpc.ws-address"
|
||||
JSONRPCGasCap = "json-rpc.gas-cap"
|
||||
JSONRPCEVMTimeout = "json-rpc.evm-timeout"
|
||||
JSONRPCTxFeeCap = "json-rpc.txfee-cap"
|
||||
JSONRPCFilterCap = "json-rpc.filter-cap"
|
||||
JSONRPCLogsCap = "json-rpc.logs-cap"
|
||||
JSONRPCBlockRangeCap = "json-rpc.block-range-cap"
|
||||
JSONRPCHTTPTimeout = "json-rpc.http-timeout"
|
||||
JSONRPCHTTPIdleTimeout = "json-rpc.http-idle-timeout"
|
||||
JSONRPCEnable = "json-rpc.enable"
|
||||
JSONRPCAPI = "json-rpc.api"
|
||||
JSONRPCAddress = "json-rpc.address"
|
||||
JSONWsAddress = "json-rpc.ws-address"
|
||||
JSONRPCGasCap = "json-rpc.gas-cap"
|
||||
JSONRPCEVMTimeout = "json-rpc.evm-timeout"
|
||||
JSONRPCTxFeeCap = "json-rpc.txfee-cap"
|
||||
JSONRPCFilterCap = "json-rpc.filter-cap"
|
||||
JSONRPCLogsCap = "json-rpc.logs-cap"
|
||||
JSONRPCBlockRangeCap = "json-rpc.block-range-cap"
|
||||
JSONRPCHTTPTimeout = "json-rpc.http-timeout"
|
||||
JSONRPCHTTPIdleTimeout = "json-rpc.http-idle-timeout"
|
||||
JSONRPCAllowUnprotectedTxs = "json-rpc.allow-unprotected-txs"
|
||||
JSONRPCMaxOpenConnections = "json-rpc.max-open-connections"
|
||||
JSONRPCEnableIndexer = "json-rpc.enable-indexer"
|
||||
)
|
||||
|
||||
// EVM flags
|
||||
@@ -65,12 +69,10 @@ func AddTxFlags(cmd *cobra.Command) (*cobra.Command, error) {
|
||||
cmd.PersistentFlags().String(flags.FlagFrom, "", "Name or address of private key with which to sign")
|
||||
cmd.PersistentFlags().String(flags.FlagFees, "", "Fees to pay along with transaction; eg: 10aphoton")
|
||||
cmd.PersistentFlags().String(flags.FlagGasPrices, "", "Gas prices to determine the transaction fee (e.g. 10aphoton)")
|
||||
cmd.PersistentFlags().String(flags.FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
||||
cmd.PersistentFlags().Float64(flags.FlagGasAdjustment, flags.DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
|
||||
cmd.PersistentFlags().String(flags.FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain") //nolint:lll
|
||||
cmd.PersistentFlags().Float64(flags.FlagGasAdjustment, flags.DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ") //nolint:lll
|
||||
cmd.PersistentFlags().StringP(flags.FlagBroadcastMode, "b", flags.BroadcastSync, "Transaction broadcasting mode (sync|async|block)")
|
||||
cmd.PersistentFlags().String(flags.FlagKeyringBackend, keyring.BackendOS, "Select keyring's backend")
|
||||
cmd.PersistentFlags().BoolP(flags.FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
|
||||
cmd.Flags().StringP(tmcli.OutputFlag, "o", "text", "Output format (text|json)")
|
||||
|
||||
// --gas can accept integers and "simulate"
|
||||
// cmd.PersistentFlags().Var(&flags.GasFlagVar, "gas", fmt.Sprintf(
|
||||
@@ -87,15 +89,3 @@ func AddTxFlags(cmd *cobra.Command) (*cobra.Command, error) {
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
// AddGQLFlags adds gql flags for
|
||||
func AddGQLFlags(cmd *cobra.Command) *cobra.Command {
|
||||
// Add flags for GQL server.
|
||||
cmd.PersistentFlags().Bool("gql-server", false, "Start GQL server.")
|
||||
cmd.PersistentFlags().Bool("gql-playground", false, "Enable GQL playground.")
|
||||
cmd.PersistentFlags().String("gql-playground-api-base", "", "GQL API base path to use in GQL playground.")
|
||||
cmd.PersistentFlags().String("gql-port", "9473", "Port to use for the GQL server.")
|
||||
cmd.PersistentFlags().String("log-file", "", "File to tail for GQL 'getLogs' API.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cerc-io/laconicd/indexer"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
tmnode "github.com/tendermint/tendermint/node"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
tmstore "github.com/tendermint/tendermint/store"
|
||||
)
|
||||
|
||||
func NewIndexTxCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "index-eth-tx [backward|forward]",
|
||||
Short: "Index historical eth txs",
|
||||
Long: `Index historical eth txs, it only support two traverse direction to avoid creating gaps in the indexer db if using arbitrary block ranges:
|
||||
- backward: index the blocks from the first indexed block to the earliest block in the chain, if indexer db is empty, start from the latest block.
|
||||
- forward: index the blocks from the latest indexed block to latest block in the chain.
|
||||
|
||||
When start the node, the indexer start from the latest indexed block to avoid creating gap.
|
||||
Backward mode should be used most of the time, so the latest indexed block is always up-to-date.
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
serverCtx := server.GetServerContextFromCmd(cmd)
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
direction := args[0]
|
||||
if direction != "backward" && direction != "forward" {
|
||||
return fmt.Errorf("unknown index direction, expect: backward|forward, got: %s", direction)
|
||||
}
|
||||
|
||||
cfg := serverCtx.Config
|
||||
home := cfg.RootDir
|
||||
logger := serverCtx.Logger
|
||||
idxDB, err := OpenIndexerDB(home, server.GetAppDBBackend(serverCtx.Viper))
|
||||
if err != nil {
|
||||
logger.Error("failed to open evm indexer DB", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
idxer := indexer.NewKVIndexer(idxDB, logger.With("module", "evmindex"), clientCtx)
|
||||
|
||||
// open local tendermint db, because the local rpc won't be available.
|
||||
tmdb, err := tmnode.DefaultDBProvider(&tmnode.DBContext{ID: "blockstore", Config: cfg})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blockStore := tmstore.NewBlockStore(tmdb)
|
||||
|
||||
stateDB, err := tmnode.DefaultDBProvider(&tmnode.DBContext{ID: "state", Config: cfg})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
|
||||
DiscardABCIResponses: cfg.Storage.DiscardABCIResponses,
|
||||
})
|
||||
|
||||
indexBlock := func(height int64) error {
|
||||
blk := blockStore.LoadBlock(height)
|
||||
if blk == nil {
|
||||
return fmt.Errorf("block not found %d", height)
|
||||
}
|
||||
resBlk, err := stateStore.LoadABCIResponses(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := idxer.IndexBlock(blk, resBlk.DeliverTxs); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(height)
|
||||
return nil
|
||||
}
|
||||
|
||||
switch args[0] {
|
||||
case "backward":
|
||||
first, err := idxer.FirstIndexedBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if first == -1 {
|
||||
// start from the latest block if indexer db is empty
|
||||
first = blockStore.Height()
|
||||
}
|
||||
for i := first - 1; i > 0; i-- {
|
||||
if err := indexBlock(i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case "forward":
|
||||
latest, err := idxer.LastIndexedBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if latest == -1 {
|
||||
// start from genesis if empty
|
||||
latest = 0
|
||||
}
|
||||
for i := latest + 1; i <= blockStore.Height(); i++ {
|
||||
if err := indexBlock(i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown direction %s", args[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/service"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceName = "EVMIndexerService"
|
||||
|
||||
NewBlockWaitTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
// EVMIndexerService indexes transactions for json-rpc service.
|
||||
type EVMIndexerService struct {
|
||||
service.BaseService
|
||||
|
||||
txIdxr ethermint.EVMTxIndexer
|
||||
client rpcclient.Client
|
||||
}
|
||||
|
||||
// NewEVMIndexerService returns a new service instance.
|
||||
func NewEVMIndexerService(
|
||||
txIdxr ethermint.EVMTxIndexer,
|
||||
client rpcclient.Client,
|
||||
) *EVMIndexerService {
|
||||
is := &EVMIndexerService{txIdxr: txIdxr, client: client}
|
||||
is.BaseService = *service.NewBaseService(nil, ServiceName, is)
|
||||
return is
|
||||
}
|
||||
|
||||
// OnStart implements service.Service by subscribing for new blocks
|
||||
// and indexing them by events.
|
||||
func (eis *EVMIndexerService) OnStart() error {
|
||||
ctx := context.Background()
|
||||
status, err := eis.client.Status(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
latestBlock := status.SyncInfo.LatestBlockHeight
|
||||
newBlockSignal := make(chan struct{}, 1)
|
||||
|
||||
// Use SubscribeUnbuffered here to ensure both subscriptions does not get
|
||||
// canceled due to not pulling messages fast enough. Cause this might
|
||||
// sometimes happen when there are no other subscribers.
|
||||
blockHeadersChan, err := eis.client.Subscribe(
|
||||
ctx,
|
||||
ServiceName,
|
||||
types.QueryForEvent(types.EventNewBlockHeader).String(),
|
||||
0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
msg := <-blockHeadersChan
|
||||
eventDataHeader := msg.Data.(types.EventDataNewBlockHeader)
|
||||
if eventDataHeader.Header.Height > latestBlock {
|
||||
latestBlock = eventDataHeader.Header.Height
|
||||
// notify
|
||||
select {
|
||||
case newBlockSignal <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
lastBlock, err := eis.txIdxr.LastIndexedBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if lastBlock == -1 {
|
||||
lastBlock = latestBlock
|
||||
}
|
||||
for {
|
||||
if latestBlock <= lastBlock {
|
||||
// nothing to index. wait for signal of new block
|
||||
select {
|
||||
case <-newBlockSignal:
|
||||
case <-time.After(NewBlockWaitTimeout):
|
||||
}
|
||||
continue
|
||||
}
|
||||
for i := lastBlock + 1; i <= latestBlock; i++ {
|
||||
block, err := eis.client.Block(ctx, &i)
|
||||
if err != nil {
|
||||
eis.Logger.Error("failed to fetch block", "height", i, "err", err)
|
||||
break
|
||||
}
|
||||
blockResult, err := eis.client.BlockResults(ctx, &i)
|
||||
if err != nil {
|
||||
eis.Logger.Error("failed to fetch block result", "height", i, "err", err)
|
||||
break
|
||||
}
|
||||
if err := eis.txIdxr.IndexBlock(block.Block, blockResult.TxsResults); err != nil {
|
||||
eis.Logger.Error("failed to index block", "height", i, "err", err)
|
||||
}
|
||||
lastBlock = blockResult.Height
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
-8
@@ -15,10 +15,17 @@ import (
|
||||
ethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
)
|
||||
|
||||
// StartJSONRPC starts the JSON-RPC server
|
||||
func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEndpoint string, config config.Config) (*http.Server, chan struct{}, error) {
|
||||
func StartJSONRPC(ctx *server.Context,
|
||||
clientCtx client.Context,
|
||||
tmRPCAddr,
|
||||
tmEndpoint string,
|
||||
config *config.Config,
|
||||
indexer ethermint.EVMTxIndexer,
|
||||
) (*http.Server, chan struct{}, error) {
|
||||
tmWsClient := ConnectTmWS(tmRPCAddr, tmEndpoint, ctx.Logger)
|
||||
|
||||
logger := ctx.Logger.With("module", "geth")
|
||||
@@ -36,8 +43,10 @@ func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEn
|
||||
|
||||
rpcServer := ethrpc.NewServer()
|
||||
|
||||
allowUnprotectedTxs := config.JSONRPC.AllowUnprotectedTxs
|
||||
rpcAPIArr := config.JSONRPC.API
|
||||
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, rpcAPIArr)
|
||||
|
||||
apis := rpc.GetRPCAPIs(ctx, clientCtx, tmWsClient, allowUnprotectedTxs, indexer, rpcAPIArr)
|
||||
|
||||
for _, api := range apis {
|
||||
if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil {
|
||||
@@ -59,18 +68,24 @@ func StartJSONRPC(ctx *server.Context, clientCtx client.Context, tmRPCAddr, tmEn
|
||||
}
|
||||
|
||||
httpSrv := &http.Server{
|
||||
Addr: config.JSONRPC.Address,
|
||||
Handler: handlerWithCors.Handler(r),
|
||||
ReadTimeout: config.JSONRPC.HTTPTimeout,
|
||||
WriteTimeout: config.JSONRPC.HTTPTimeout,
|
||||
IdleTimeout: config.JSONRPC.HTTPIdleTimeout,
|
||||
Addr: config.JSONRPC.Address,
|
||||
Handler: handlerWithCors.Handler(r),
|
||||
ReadHeaderTimeout: config.JSONRPC.HTTPTimeout,
|
||||
ReadTimeout: config.JSONRPC.HTTPTimeout,
|
||||
WriteTimeout: config.JSONRPC.HTTPTimeout,
|
||||
IdleTimeout: config.JSONRPC.HTTPIdleTimeout,
|
||||
}
|
||||
httpSrvDone := make(chan struct{}, 1)
|
||||
|
||||
ln, err := Listen(httpSrv.Addr, config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
errCh := make(chan error)
|
||||
go func() {
|
||||
ctx.Logger.Info("Starting JSON-RPC server", "address", config.JSONRPC.Address)
|
||||
if err := httpSrv.ListenAndServe(); err != nil {
|
||||
if err := httpSrv.Serve(ln); err != nil {
|
||||
if err == http.ErrServerClosed {
|
||||
close(httpSrvDone)
|
||||
return
|
||||
|
||||
+113
-50
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -17,43 +18,36 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
pvm "github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/api"
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
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"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
pvm "github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
"github.com/tendermint/tendermint/rpc/client/local"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/gql"
|
||||
ethdebug "github.com/cerc-io/laconicd/rpc/ethereum/namespaces/debug"
|
||||
"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"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/api"
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/cerc-io/laconicd/indexer"
|
||||
ethdebug "github.com/cerc-io/laconicd/rpc/namespaces/ethereum/debug"
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
// gRPC-related flags
|
||||
flagGRPCOnly = "grpc-only"
|
||||
flagGRPCEnable = "grpc.enable"
|
||||
flagGRPCAddress = "grpc.address"
|
||||
flagGRPCWebEnable = "grpc-web.enable"
|
||||
flagGRPCWebAddress = "grpc-web.address"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
)
|
||||
|
||||
// StartCmd runs the service passed in, either stand-alone or in-process with
|
||||
@@ -140,7 +134,7 @@ which accepts a path for the resulting pprof file.
|
||||
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")
|
||||
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)")
|
||||
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
|
||||
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")
|
||||
@@ -149,9 +143,10 @@ which accepts a path for the resulting pprof file.
|
||||
cmd.Flags().Bool(server.FlagTrace, false, "Provide full stack traces for errors in ABCI Log")
|
||||
cmd.Flags().String(server.FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)")
|
||||
cmd.Flags().Uint64(server.FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')")
|
||||
cmd.Flags().Uint64(server.FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')")
|
||||
cmd.Flags().Uint64(server.FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") //nolint:lll
|
||||
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")
|
||||
cmd.Flags().String(srvflags.AppDBBackend, "", "The type of database for application and snapshots databases")
|
||||
|
||||
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")
|
||||
@@ -165,17 +160,20 @@ which accepts a path for the resulting pprof file.
|
||||
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")
|
||||
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)")
|
||||
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)")
|
||||
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
|
||||
cmd.Flags().Int32(srvflags.JSONRPCFilterCap, config.DefaultFilterCap, "Sets the global cap for total number of filters that can be created")
|
||||
cmd.Flags().Duration(srvflags.JSONRPCEVMTimeout, config.DefaultEVMTimeout, "Sets a timeout used for eth_call (0=infinite)")
|
||||
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)")
|
||||
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
|
||||
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")
|
||||
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")
|
||||
|
||||
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)")
|
||||
cmd.Flags().Uint64(srvflags.EVMMaxTxGasWanted, config.DefaultMaxTxGasWanted, "the gas wanted for each eth tx returned in ante handler in check tx mode")
|
||||
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
|
||||
|
||||
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")
|
||||
@@ -193,11 +191,10 @@ func startStandAlone(ctx *server.Context, appCreator types.AppCreator) error {
|
||||
transport := ctx.Viper.GetString(srvflags.Transport)
|
||||
home := ctx.Viper.GetString(flags.FlagHome)
|
||||
|
||||
db, err := openDB(home, server.GetAppDBBackend((ctx.Viper)))
|
||||
db, err := openDB(home, server.GetAppDBBackend(ctx.Viper))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := db.Close(); err != nil {
|
||||
ctx.Logger.With("error", err).Error("error closing db")
|
||||
@@ -271,6 +268,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore)
|
||||
db, err := openDB(home, server.GetAppDBBackend(ctx.Viper))
|
||||
if err != nil {
|
||||
logger.Error("failed to open DB", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
@@ -311,8 +309,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.Logger.Info("starting node with ABCI Tendermint in-process")
|
||||
|
||||
genDocProvider := node.DefaultGenesisDocProviderFunc(cfg)
|
||||
tmNode, err := node.NewNode(
|
||||
cfg,
|
||||
@@ -324,7 +320,6 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
node.DefaultMetricsProvider(cfg.Instrumentation),
|
||||
ctx.Logger.With("server", "node"),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("failed init node", "error", err.Error())
|
||||
return err
|
||||
@@ -338,25 +333,90 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
// Add the tx service to the gRPC router. We only need to register this
|
||||
// service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general
|
||||
// case, because it spawns a new local tendermint RPC client.
|
||||
if config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable {
|
||||
|
||||
if config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable || config.JSONRPC.EnableIndexer {
|
||||
clientCtx = clientCtx.WithClient(local.New(tmNode))
|
||||
|
||||
app.RegisterTxService(clientCtx)
|
||||
app.RegisterTendermintService(clientCtx)
|
||||
}
|
||||
|
||||
var apiSrv *api.Server
|
||||
if config.API.Enable {
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
|
||||
var idxer ethermint.EVMTxIndexer
|
||||
if config.JSONRPC.EnableIndexer {
|
||||
idxDB, err := OpenIndexerDB(home, server.GetAppDBBackend(ctx.Viper))
|
||||
if err != nil {
|
||||
logger.Error("failed to open evm indexer DB", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
idxLogger := ctx.Logger.With("module", "evmindex")
|
||||
idxer = indexer.NewKVIndexer(idxDB, idxLogger, clientCtx)
|
||||
indexerService := NewEVMIndexerService(idxer, clientCtx.Client)
|
||||
indexerService.SetLogger(idxLogger)
|
||||
|
||||
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.
|
||||
clientCtx = clientCtx.
|
||||
WithHomeDir(home).
|
||||
WithChainID(genDoc.ChainID)
|
||||
|
||||
// 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 {
|
||||
apiSrv = api.New(clientCtx, ctx.Logger.With("server", "api"))
|
||||
app.RegisterAPIRoutes(apiSrv, config.API)
|
||||
errCh := make(chan error)
|
||||
@@ -434,7 +494,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
)
|
||||
|
||||
if config.JSONRPC.Enable {
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
|
||||
genDoc, err := genDocProvider()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -443,15 +503,12 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
|
||||
|
||||
tmEndpoint := "/websocket"
|
||||
tmRPCAddr := cfg.RPC.ListenAddress
|
||||
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, config)
|
||||
httpSrv, httpSrvDone, err = StartJSONRPC(ctx, clientCtx, tmRPCAddr, tmEndpoint, &config, idxer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start the GQL Server
|
||||
go gql.Server(clientCtx)
|
||||
|
||||
defer func() {
|
||||
if tmNode.IsRunning() {
|
||||
_ = tmNode.Stop()
|
||||
@@ -501,6 +558,12 @@ func openDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) {
|
||||
return dbm.NewDB("application", backendType, dataDir)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
func openTraceWriter(traceWriterFile string) (w io.Writer, err error) {
|
||||
if traceWriterFile == "" {
|
||||
return
|
||||
|
||||
+32
-4
@@ -1,24 +1,33 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/improbable-eng/grpc-web/go/grpcweb"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/net/netutil"
|
||||
|
||||
sdkserver "github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
tmcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
|
||||
tmcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
|
||||
)
|
||||
|
||||
// add server commands
|
||||
func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, appExport types.AppExporter, addStartFlags types.ModuleInitFlags) {
|
||||
// AddCommands adds server commands
|
||||
func AddCommands(
|
||||
rootCmd *cobra.Command,
|
||||
defaultNodeHome string,
|
||||
appCreator types.AppCreator,
|
||||
appExport types.AppExporter,
|
||||
addStartFlags types.ModuleInitFlags,
|
||||
) {
|
||||
tendermintCmd := &cobra.Command{
|
||||
Use: "tendermint",
|
||||
Short: "Tendermint subcommands",
|
||||
@@ -41,6 +50,10 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type
|
||||
tendermintCmd,
|
||||
sdkserver.ExportCmd(appExport, defaultNodeHome),
|
||||
version.NewVersionCommand(),
|
||||
sdkserver.NewRollbackCmd(appCreator, defaultNodeHome),
|
||||
|
||||
// custom tx indexer command
|
||||
NewIndexTxCmd(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,7 +92,6 @@ func MountGRPCWebServices(
|
||||
logger tmlog.Logger,
|
||||
) {
|
||||
for _, res := range grpcResources {
|
||||
|
||||
logger.Info("[GRPC Web] HTTP POST mounted", "resource", res)
|
||||
|
||||
s := router.Methods("POST").Subrouter()
|
||||
@@ -96,3 +108,19 @@ func MountGRPCWebServices(
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Listen starts a net.Listener on the tcp network on the given address.
|
||||
// If there is a specified MaxOpenConnections in the config, it will also set the limitListener.
|
||||
func Listen(addr string, config *config.Config) (net.Listener, error) {
|
||||
if addr == "" {
|
||||
addr = ":http"
|
||||
}
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.JSONRPC.MaxOpenConnections > 0 {
|
||||
ln = netutil.LimitListener(ln, config.JSONRPC.MaxOpenConnections)
|
||||
}
|
||||
return ln, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user