Merge PR #6426: Migrate API Server

This commit is contained in:
Alexander Bezobchuk 2020-06-15 13:39:09 -04:00 committed by GitHub
parent 6336f95802
commit 6a05b83069
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 287 additions and 218 deletions

2
.gitattributes vendored
View File

@ -1 +1 @@
client/lcd/swagger-ui/* linguist-vendored client/docs/swagger-ui/* linguist-vendored

View File

@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Client Breaking ### Client Breaking
* (api) [\#6426](https://github.com/cosmos/cosmos-sdk/pull/6426) The ability to start an out-of-process API REST server has now been removed. Instead, the API server is now started in-process along with the application and Tendermint. Configuration options have been added to `app.toml` to enable/disable the API server along with additional HTTP server options.
* (baseapp) [\#6384](https://github.com/cosmos/cosmos-sdk/pull/6384) The `Result.Data` is now a Protocol Buffer encoded binary blob of type `TxData`. The `TxData` contains `Data` which contains a list of Protocol Buffer encoded message data and the corresponding message type. * (baseapp) [\#6384](https://github.com/cosmos/cosmos-sdk/pull/6384) The `Result.Data` is now a Protocol Buffer encoded binary blob of type `TxData`. The `TxData` contains `Data` which contains a list of Protocol Buffer encoded message data and the corresponding message type.
* (x/gov) [#6295](https://github.com/cosmos/cosmos-sdk/pull/6295) Fix typo in querying governance params. * (x/gov) [#6295](https://github.com/cosmos/cosmos-sdk/pull/6295) Fix typo in querying governance params.
* (x/auth) [\#6054](https://github.com/cosmos/cosmos-sdk/pull/6054) Remove custom JSON marshaling for base accounts as multsigs cannot be bech32 decoded. * (x/auth) [\#6054](https://github.com/cosmos/cosmos-sdk/pull/6054) Remove custom JSON marshaling for base accounts as multsigs cannot be bech32 decoded.

View File

@ -217,9 +217,9 @@ lint:
.PHONY: lint .PHONY: lint
format: format:
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs gofmt -w -s find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs gofmt -w -s
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs misspell -w find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs misspell -w
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk
.PHONY: format .PHONY: format
############################################################################### ###############################################################################

View File

@ -21,8 +21,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
// Context implements a typical context created in SDK modules for // Context implements a typical context created in SDK modules for transaction
// transaction handling and queries. // handling and queries.
type Context struct { type Context struct {
FromAddress sdk.AccAddress FromAddress sdk.AccAddress
Client rpcclient.Client Client rpcclient.Client
@ -34,10 +34,8 @@ type Context struct {
OutputFormat string OutputFormat string
Height int64 Height int64
HomeDir string HomeDir string
NodeURI string
From string From string
BroadcastMode string BroadcastMode string
Verifier tmlite.Verifier
FromName string FromName string
TrustNode bool TrustNode bool
UseLedger bool UseLedger bool
@ -49,6 +47,12 @@ type Context struct {
TxGenerator TxGenerator TxGenerator TxGenerator
AccountRetriever AccountRetriever AccountRetriever AccountRetriever
// TODO: API and CLI interfaces are migrating to a single binary (i.e be part of
// the same process of the application). We need to groom through these fields
// and remove any that no longer make sense.
NodeURI string
Verifier tmlite.Verifier
// TODO: Deprecated (remove). // TODO: Deprecated (remove).
Codec *codec.Codec Codec *codec.Codec
} }
@ -267,6 +271,12 @@ func (ctx Context) WithChainID(chainID string) Context {
return ctx return ctx
} }
// WithHomeDir returns a copy of the Context with HomeDir set.
func (ctx Context) WithHomeDir(dir string) Context {
ctx.HomeDir = dir
return ctx
}
// WithGenerateOnly returns a copy of the context with updated GenerateOnly value // WithGenerateOnly returns a copy of the context with updated GenerateOnly value
func (ctx Context) WithGenerateOnly(generateOnly bool) Context { func (ctx Context) WithGenerateOnly(generateOnly bool) Context {
ctx.GenerateOnly = generateOnly ctx.GenerateOnly = generateOnly

View File

@ -1,3 +1,3 @@
package statik package statik
//This just for fixing the error in importing empty github.com/cosmos/cosmos-sdk/client/lcd/statik //This just for fixing the error in importing empty github.com/cosmos/cosmos-sdk/client/docs/statik

View File

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 445 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -39,37 +39,31 @@ const (
// List of CLI flags // List of CLI flags
const ( const (
FlagHome = tmcli.HomeFlag FlagHome = tmcli.HomeFlag
FlagUseLedger = "ledger" FlagUseLedger = "ledger"
FlagChainID = "chain-id" FlagChainID = "chain-id"
FlagNode = "node" FlagNode = "node"
FlagHeight = "height" FlagHeight = "height"
FlagGasAdjustment = "gas-adjustment" FlagGasAdjustment = "gas-adjustment"
FlagTrustNode = "trust-node" FlagTrustNode = "trust-node"
FlagFrom = "from" FlagFrom = "from"
FlagName = "name" FlagName = "name"
FlagAccountNumber = "account-number" FlagAccountNumber = "account-number"
FlagSequence = "sequence" FlagSequence = "sequence"
FlagMemo = "memo" FlagMemo = "memo"
FlagFees = "fees" FlagFees = "fees"
FlagGasPrices = "gas-prices" FlagGasPrices = "gas-prices"
FlagBroadcastMode = "broadcast-mode" FlagBroadcastMode = "broadcast-mode"
FlagDryRun = "dry-run" FlagDryRun = "dry-run"
FlagGenerateOnly = "generate-only" FlagGenerateOnly = "generate-only"
FlagOffline = "offline" FlagOffline = "offline"
FlagIndentResponse = "indent" FlagIndentResponse = "indent"
FlagListenAddr = "laddr" FlagOutputDocument = "output-document" // inspired by wget -O
FlagMaxOpenConnections = "max-open" FlagSkipConfirmation = "yes"
FlagRPCReadTimeout = "read-timeout" FlagProve = "prove"
FlagRPCWriteTimeout = "write-timeout" FlagKeyringBackend = "keyring-backend"
FlagRPCMaxBodyBytes = "max-body-bytes" FlagPage = "page"
FlagOutputDocument = "output-document" // inspired by wget -O FlagLimit = "limit"
FlagSkipConfirmation = "yes"
FlagProve = "prove"
FlagKeyringBackend = "keyring-backend"
FlagPage = "page"
FlagLimit = "limit"
FlagUnsafeCORS = "unsafe-cors"
) )
// LineBreak can be included in a command list to provide a blank line // LineBreak can be included in a command list to provide a blank line
@ -141,19 +135,6 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
return cmds return cmds
} }
// RegisterRestServerFlags registers the flags required for rest server
func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command {
cmd = GetCommands(cmd)[0]
cmd.Flags().String(FlagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
cmd.Flags().Uint(FlagMaxOpenConnections, 1000, "The number of maximum open connections")
cmd.Flags().Uint(FlagRPCReadTimeout, 10, "The RPC read timeout (in seconds)")
cmd.Flags().Uint(FlagRPCWriteTimeout, 10, "The RPC write timeout (in seconds)")
cmd.Flags().Uint(FlagRPCMaxBodyBytes, 1000000, "The RPC max body bytes")
cmd.Flags().Bool(FlagUnsafeCORS, false, "Allows CORS requests from all domains. For development purposes only, use it at your own risk.")
return cmd
}
// Gas flag parsing functions // Gas flag parsing functions
// GasSetting encapsulates the possible values passed through the --gas flag. // GasSetting encapsulates the possible values passed through the --gas flag.

View File

@ -1,128 +0,0 @@
package lcd
import (
"fmt"
"net"
"net/http"
"os"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/rakyll/statik/fs"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmrpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
// unnamed import of statik for swagger UI support
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
)
// RestServer represents the Light Client Rest server
type RestServer struct {
Mux *mux.Router
ClientCtx client.Context
log log.Logger
listener net.Listener
}
// NewRestServer creates a new rest server instance
func NewRestServer(cdc *codec.Codec) *RestServer {
r := mux.NewRouter()
clientCtx := client.NewContext().WithCodec(cdc)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
return &RestServer{
Mux: r,
ClientCtx: clientCtx,
log: logger,
}
}
// StartWithConfig starts the REST server that listens on the provided listenAddr.
// It will use the provided RPC configuration.
func (rs *RestServer) StartWithConfig(listenAddr string, cors bool, cfg *tmrpcserver.Config) error {
server.TrapSignal(func() {
err := rs.listener.Close()
rs.log.Error("error closing listener", "err", err)
})
listener, err := tmrpcserver.Listen(listenAddr, cfg)
if err != nil {
return err
}
rs.listener = listener
rs.log.Info(
fmt.Sprintf("Starting application REST service (chain-id: %q)...", viper.GetString(flags.FlagChainID)),
)
var h http.Handler = rs.Mux
if cors {
return tmrpcserver.Serve(rs.listener, handlers.CORS()(h), rs.log, cfg)
}
return tmrpcserver.Serve(rs.listener, rs.Mux, rs.log, cfg)
}
// Start starts the REST server that listens on the provided listenAddr. The REST
// service will use Tendermint's default RPC configuration, where the R/W timeout
// and max open connections are overridden.
func (rs *RestServer) Start(listenAddr string, maxOpen int, readTimeout, writeTimeout uint, cors bool) error {
cfg := tmrpcserver.DefaultConfig()
cfg.MaxOpenConnections = maxOpen
cfg.ReadTimeout = time.Duration(readTimeout) * time.Second
cfg.WriteTimeout = time.Duration(writeTimeout) * time.Second
return rs.StartWithConfig(listenAddr, cors, cfg)
}
// ServeCommand will start the application REST service as a blocking process. It
// takes a codec to create a RestServer object and a function to register all
// necessary routes.
func ServeCommand(cdc *codec.Codec, registerRoutesFn func(*RestServer)) *cobra.Command {
cmd := &cobra.Command{
Use: "rest-server",
Short: "Start LCD (light-client daemon), a local REST server",
RunE: func(cmd *cobra.Command, args []string) (err error) {
rs := NewRestServer(cdc)
registerRoutesFn(rs)
rs.registerSwaggerUI()
cfg := tmrpcserver.DefaultConfig()
cfg.MaxOpenConnections = viper.GetInt(flags.FlagMaxOpenConnections)
cfg.ReadTimeout = time.Duration(viper.GetInt64(flags.FlagRPCReadTimeout)) * time.Second
cfg.WriteTimeout = time.Duration(viper.GetInt64(flags.FlagRPCWriteTimeout)) * time.Second
cfg.MaxBodyBytes = viper.GetInt64(flags.FlagRPCMaxBodyBytes)
// start the rest server and return error if one exists
return rs.StartWithConfig(
viper.GetString(flags.FlagListenAddr),
viper.GetBool(flags.FlagUnsafeCORS),
cfg,
)
},
}
return flags.RegisterRestServerFlags(cmd)
}
func (rs *RestServer) registerSwaggerUI() {
statikFS, err := fs.New()
if err != nil {
panic(err)
}
staticServer := http.FileServer(statikFS)
rs.Mux.PathPrefix("/").Handler(staticServer)
}

View File

@ -6,6 +6,7 @@ services:
image: "cosmos-sdk/simappnode" image: "cosmos-sdk/simappnode"
ports: ports:
- "26656-26657:26656-26657" - "26656-26657:26656-26657"
- "1317:1317"
environment: environment:
- ID=0 - ID=0
- LOG=${LOG:-simd.log} - LOG=${LOG:-simd.log}
@ -20,6 +21,7 @@ services:
image: "cosmos-sdk/simappnode" image: "cosmos-sdk/simappnode"
ports: ports:
- "26659-26660:26656-26657" - "26659-26660:26656-26657"
- "1318:1317"
environment: environment:
- ID=1 - ID=1
- LOG=${LOG:-simd.log} - LOG=${LOG:-simd.log}
@ -37,6 +39,7 @@ services:
- LOG=${LOG:-simd.log} - LOG=${LOG:-simd.log}
ports: ports:
- "26661-26662:26656-26657" - "26661-26662:26656-26657"
- "1319:1317"
volumes: volumes:
- ./build:/simd:Z - ./build:/simd:Z
networks: networks:
@ -51,6 +54,7 @@ services:
- LOG=${LOG:-simd.log} - LOG=${LOG:-simd.log}
ports: ports:
- "26663-26664:26656-26657" - "26663-26664:26656-26657"
- "1320:1317"
volumes: volumes:
- ./build:/simd:Z - ./build:/simd:Z
networks: networks:

View File

@ -15,7 +15,7 @@ RUN apt-get update && \
VOLUME [ /simd ] VOLUME [ /simd ]
WORKDIR /simd WORKDIR /simd
EXPOSE 26656 26657 EXPOSE 26656 26657 1317
ENTRYPOINT ["/usr/bin/wrapper.sh"] ENTRYPOINT ["/usr/bin/wrapper.sh"]
CMD ["start"] CMD ["start"]
STOPSIGNAL SIGTERM STOPSIGNAL SIGTERM

77
server/api/server.go Normal file
View File

@ -0,0 +1,77 @@
package api
import (
"net"
"net/http"
"os"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/rakyll/statik/fs"
"github.com/tendermint/tendermint/libs/log"
tmrpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server/config"
// unnamed import of statik for swagger UI support
_ "github.com/cosmos/cosmos-sdk/client/docs/statik"
)
// Server defines the server's API interface.
type Server struct {
Router *mux.Router
ClientCtx client.Context
logger log.Logger
listener net.Listener
}
func New(clientCtx client.Context) *Server {
return &Server{
Router: mux.NewRouter(),
ClientCtx: clientCtx,
logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "api-server"),
}
}
// Start starts the API server. Internally, the API server leverages Tendermint's
// JSON RPC server. Configuration options are provided via config.APIConfig
// and are delegated to the Tendermint JSON RPC server. The process is
// non-blocking, so an external signal handler must be used.
func (s *Server) Start(cfg config.APIConfig) error {
if cfg.Swagger {
s.registerSwaggerUI()
}
tmCfg := tmrpcserver.DefaultConfig()
tmCfg.MaxOpenConnections = int(cfg.MaxOpenConnections)
tmCfg.ReadTimeout = time.Duration(cfg.RPCReadTimeout) * time.Second
tmCfg.WriteTimeout = time.Duration(cfg.RPCWriteTimeout) * time.Second
tmCfg.MaxBodyBytes = int64(cfg.RPCMaxBodyBytes)
listener, err := tmrpcserver.Listen(cfg.Address, tmCfg)
if err != nil {
return err
}
s.listener = listener
var h http.Handler = s.Router
if cfg.EnableUnsafeCORS {
return tmrpcserver.Serve(s.listener, handlers.CORS()(h), s.logger, tmCfg)
}
return tmrpcserver.Serve(s.listener, s.Router, s.logger, tmCfg)
}
func (s *Server) registerSwaggerUI() {
statikFS, err := fs.New()
if err != nil {
panic(err)
}
staticServer := http.FileServer(statikFS)
s.Router.PathPrefix("/").Handler(staticServer)
}

View File

@ -19,6 +19,10 @@ type BaseConfig struct {
// specified in this config (e.g. 0.25token1;0.0001token2). // specified in this config (e.g. 0.25token1;0.0001token2).
MinGasPrices string `mapstructure:"minimum-gas-prices"` MinGasPrices string `mapstructure:"minimum-gas-prices"`
Pruning string `mapstructure:"pruning"`
PruningKeepEvery string `mapstructure:"pruning-keep-every"`
PruningSnapshotEvery string `mapstructure:"pruning-snapshot-every"`
// HaltHeight contains a non-zero block height at which a node will gracefully // HaltHeight contains a non-zero block height at which a node will gracefully
// halt and shutdown that can be used to assist upgrades and testing. // halt and shutdown that can be used to assist upgrades and testing.
// //
@ -34,15 +38,44 @@ type BaseConfig struct {
// InterBlockCache enables inter-block caching. // InterBlockCache enables inter-block caching.
InterBlockCache bool `mapstructure:"inter-block-cache"` InterBlockCache bool `mapstructure:"inter-block-cache"`
}
Pruning string `mapstructure:"pruning"` // APIConfig defines the API listener configuration.
PruningKeepEvery string `mapstructure:"pruning-keep-every"` type APIConfig struct {
PruningSnapshotEvery string `mapstructure:"pruning-snapshot-every"` // Enable defines if the API server should be enabled.
Enable bool `mapstructure:"enable"`
// Swagger defines if swagger documentation should automatically be registered.
Swagger bool `mapstructure:"swagger"`
// EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
EnableUnsafeCORS bool `mapstructure:"enabled-unsafe-cors"`
// Address defines the API server to listen on
Address string `mapstructure:"address"`
// MaxOpenConnections defines the number of maximum open connections
MaxOpenConnections uint `mapstructure:"max-open-connections"`
// RPCReadTimeout defines the Tendermint RPC read timeout (in seconds)
RPCReadTimeout uint `mapstructure:"rpc-read-timeout"`
// RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds)
RPCWriteTimeout uint `mapstructure:"rpc-write-timeout"`
// RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes)
RPCMaxBodyBytes uint `mapstructure:"rpc-max-body-bytes"`
// TODO: TLS/Proxy configuration.
//
// Ref: https://github.com/cosmos/cosmos-sdk/issues/6420
} }
// Config defines the server's top level configuration // Config defines the server's top level configuration
type Config struct { type Config struct {
BaseConfig `mapstructure:",squash"` BaseConfig `mapstructure:",squash"`
API APIConfig `mapstructure:"api"`
} }
// SetMinGasPrices sets the validator's minimum gas prices. // SetMinGasPrices sets the validator's minimum gas prices.
@ -75,12 +108,20 @@ func (c *Config) GetMinGasPrices() sdk.DecCoins {
// DefaultConfig returns server's default configuration. // DefaultConfig returns server's default configuration.
func DefaultConfig() *Config { func DefaultConfig() *Config {
return &Config{ return &Config{
BaseConfig{ BaseConfig: BaseConfig{
MinGasPrices: defaultMinGasPrices, MinGasPrices: defaultMinGasPrices,
InterBlockCache: true, InterBlockCache: true,
Pruning: store.PruningStrategySyncable, Pruning: store.PruningStrategySyncable,
PruningKeepEvery: "0", PruningKeepEvery: "0",
PruningSnapshotEvery: "0", PruningSnapshotEvery: "0",
}, },
API: APIConfig{
Enable: false,
Swagger: false,
Address: "tcp://0.0.0.0:1317",
MaxOpenConnections: 1000,
RPCReadTimeout: 10,
RPCMaxBodyBytes: 1000000,
},
} }
} }

View File

@ -11,13 +11,26 @@ import (
const defaultConfigTemplate = `# This is a TOML config file. const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml # For more information, see https://github.com/toml-lang/toml
##### main base config options ##### ###############################################################################
### Base Configuration ###
###############################################################################
# The minimum gas prices a validator is willing to accept for processing a # The minimum gas prices a validator is willing to accept for processing a
# transaction. A transaction's fees must meet the minimum of any denomination # transaction. A transaction's fees must meet the minimum of any denomination
# specified in this config (e.g. 0.25token1;0.0001token2). # specified in this config (e.g. 0.25token1;0.0001token2).
minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}" minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}"
# Pruning sets the pruning strategy: syncable, nothing, everything, custom
# syncable: only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th)
# 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
# custom: allows fine-grained control through the pruning-keep-every and pruning-snapshot-every options.
pruning = "{{ .BaseConfig.Pruning }}"
# These are applied if and only if the pruning strategy is custom.
pruning-keep-every = "{{ .BaseConfig.PruningKeepEvery }}"
pruning-snapshot-every = "{{ .BaseConfig.PruningSnapshotEvery }}"
# HaltHeight contains a non-zero block height at which a node will gracefully # HaltHeight contains a non-zero block height at which a node will gracefully
# halt and shutdown that can be used to assist upgrades and testing. # halt and shutdown that can be used to assist upgrades and testing.
# #
@ -34,16 +47,35 @@ halt-time = {{ .BaseConfig.HaltTime }}
# InterBlockCache enables inter-block caching. # InterBlockCache enables inter-block caching.
inter-block-cache = {{ .BaseConfig.InterBlockCache }} inter-block-cache = {{ .BaseConfig.InterBlockCache }}
# Pruning sets the pruning strategy: syncable, nothing, everything, custom ###############################################################################
# syncable: only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th) ### API Configuration ###
# 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
# custom: allows fine-grained control through the pruning-keep-every and pruning-snapshot-every options.
pruning = "{{ .BaseConfig.Pruning }}"
# These are applied if and only if the pruning strategy is custom. [api]
pruning-keep-every = "{{ .BaseConfig.PruningKeepEvery }}"
pruning-snapshot-every = "{{ .BaseConfig.PruningSnapshotEvery }}" # Enable defines if the API server should be enabled.
enable = {{ .API.Enable }}
# Swagger defines if swagger documentation should automatically be registered.
swagger = {{ .API.Swagger }}
# Address defines the API server to listen on
address = "{{ .API.Address }}"
# MaxOpenConnections defines the number of maximum open connections
max-open-connections = {{ .API.MaxOpenConnections }}
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds)
rpc-read-timeout = {{ .API.RPCReadTimeout }}
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds)
rpc-write-timeout = {{ .API.RPCWriteTimeout }}
# RPCMaxBodyBytes defines the Tendermint maximum response body (in bytes)
rpc-max-body-bytes = {{ .API.RPCMaxBodyBytes }}
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk)
enabled-unsafe-cors = {{ .API.EnableUnsafeCORS }}
` `
var configTemplate *template.Template var configTemplate *template.Template

View File

@ -11,13 +11,23 @@ import (
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/server/api"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
type ( type (
// Application defines an application interface that wraps abci.Application.
// The interface defines the necessary contracts to be implemented in order
// to fully bootstrap and start an application.
Application interface {
abci.Application
RegisterAPIRoutes(*api.Server)
}
// AppCreator is a function that allows us to lazily initialize an // AppCreator is a function that allows us to lazily initialize an
// application using various configurations. // application using various configurations.
AppCreator func(log.Logger, dbm.DB, io.Writer) abci.Application AppCreator func(log.Logger, dbm.DB, io.Writer) Application
// AppExporter is a function that dumps all app state to // AppExporter is a function that dumps all app state to
// JSON-serializable structure and returns the current validator set. // JSON-serializable structure and returns the current validator set.

View File

@ -16,6 +16,12 @@ import (
"github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval" pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/rpc/client/local"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
) )
// Tendermint full-node start flags // Tendermint full-node start flags
@ -36,7 +42,7 @@ const (
// StartCmd runs the service passed in, either stand-alone or in-process with // StartCmd runs the service passed in, either stand-alone or in-process with
// Tendermint. // Tendermint.
func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { func StartCmd(ctx *Context, cdc codec.JSONMarshaler, appCreator AppCreator) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "start", Use: "start",
Short: "Run the full node", Short: "Run the full node",
@ -72,7 +78,7 @@ which accepts a path for the resulting pprof file.
ctx.Logger.Info("starting ABCI with Tendermint") ctx.Logger.Info("starting ABCI with Tendermint")
err := startInProcess(ctx, appCreator) err := startInProcess(ctx, cdc, appCreator)
return err return err
}, },
} }
@ -143,7 +149,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
select {} select {}
} }
func startInProcess(ctx *Context, appCreator AppCreator) error { func startInProcess(ctx *Context, cdc codec.JSONMarshaler, appCreator AppCreator) error {
cfg := ctx.Config cfg := ctx.Config
home := cfg.RootDir home := cfg.RootDir
@ -165,13 +171,15 @@ func startInProcess(ctx *Context, appCreator AppCreator) error {
return err return err
} }
genDocProvider := node.DefaultGenesisDocProviderFunc(cfg)
// create & start tendermint node // create & start tendermint node
tmNode, err := node.NewNode( tmNode, err := node.NewNode(
cfg, cfg,
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()), pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
nodeKey, nodeKey,
proxy.NewLocalClientCreator(app), proxy.NewLocalClientCreator(app),
node.DefaultGenesisDocProviderFunc(cfg), genDocProvider,
node.DefaultDBProvider, node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation), node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("module", "node"), ctx.Logger.With("module", "node"),
@ -184,6 +192,39 @@ func startInProcess(ctx *Context, appCreator AppCreator) error {
return err return err
} }
if viper.GetBool("api.enable") {
genDoc, err := genDocProvider()
if err != nil {
return err
}
// TODO: Since this is running in process, do we need to provide a verifier
// and set TrustNode=false? If so, we need to add additional logic that
// waits for a block to be committed first before starting the API server.
ctx := client.Context{}.
WithHomeDir(home).
WithChainID(genDoc.ChainID).
WithJSONMarshaler(cdc).
WithClient(local.New(tmNode)).
WithTrustNode(true)
apiSrv := api.New(ctx)
apiCfg := config.APIConfig{
Address: viper.GetString("api.address"),
MaxOpenConnections: viper.GetUint("api.max-open-connections"),
RPCReadTimeout: viper.GetUint("api.rpc-read-timeout"),
RPCWriteTimeout: viper.GetUint("api.rpc-write-timeout"),
RPCMaxBodyBytes: viper.GetUint("api.rpc-max-body-bytes"),
EnableUnsafeCORS: viper.GetBool("api.enabled-unsafe-cors"),
}
app.RegisterAPIRoutes(apiSrv)
if err := apiSrv.Start(apiCfg); err != nil {
return err
}
}
var cpuProfileCleanup func() var cpuProfileCleanup func()
if cpuProfile := viper.GetString(flagCPUProfile); cpuProfile != "" { if cpuProfile := viper.GetString(flagCPUProfile); cpuProfile != "" {

View File

@ -71,7 +71,7 @@ func TestPruningOptions(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
viper.Reset() viper.Reset()
viper.SetDefault(flagPruning, "syncable") viper.SetDefault(flagPruning, "syncable")
startCommand := StartCmd(nil, nil) startCommand := StartCmd(nil, nil, nil)
tt.paramInit() tt.paramInit()
err := startCommand.PreRunE(startCommand, nil) err := startCommand.PreRunE(startCommand, nil)

View File

@ -122,9 +122,8 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
// add server commands // add server commands
func AddCommands( func AddCommands(
ctx *Context, cdc codec.JSONMarshaler, ctx *Context, cdc codec.JSONMarshaler, rootCmd *cobra.Command, appCreator AppCreator, appExport AppExporter,
rootCmd *cobra.Command, ) {
appCreator AppCreator, appExport AppExporter) {
rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level")
@ -141,7 +140,7 @@ func AddCommands(
) )
rootCmd.AddCommand( rootCmd.AddCommand(
StartCmd(ctx, appCreator), StartCmd(ctx, cdc, appCreator),
UnsafeResetAllCmd(ctx), UnsafeResetAllCmd(ctx),
flags.LineBreak, flags.LineBreak,
tendermintCmd, tendermintCmd,

View File

@ -10,15 +10,18 @@ import (
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/testdata" "github.com/cosmos/cosmos-sdk/codec/testdata"
"github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/ante"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
@ -499,6 +502,14 @@ func (app *SimApp) SimulationManager() *module.SimulationManager {
return app.sm return app.sm
} }
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server) {
rpc.RegisterRoutes(apiSvr.ClientCtx, apiSvr.Router)
authrest.RegisterTxRoutes(apiSvr.ClientCtx, apiSvr.Router)
ModuleBasics.RegisterRESTRoutes(apiSvr.ClientCtx, apiSvr.Router)
}
// GetMaccPerms returns a copy of the module account permissions // GetMaccPerms returns a copy of the module account permissions
func GetMaccPerms() map[string][]string { func GetMaccPerms() map[string][]string {
dupMaccPerms := make(map[string][]string) dupMaccPerms := make(map[string][]string)

View File

@ -12,14 +12,12 @@ import (
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/lcd"
"github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/types"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
) )
@ -65,7 +63,6 @@ func main() {
queryCmd(cdc), queryCmd(cdc),
txCmd(cdc), txCmd(cdc),
flags.LineBreak, flags.LineBreak,
lcd.ServeCommand(cdc, registerRoutes),
flags.LineBreak, flags.LineBreak,
keys.Commands(), keys.Commands(),
flags.LineBreak, flags.LineBreak,
@ -148,14 +145,6 @@ func txCmd(cdc *codec.Codec) *cobra.Command {
return txCmd return txCmd
} }
// registerRoutes registers the routes from the different modules for the REST client.
// NOTE: details on the routes added for each module are in the module documentation
func registerRoutes(rs *lcd.RestServer) {
rpc.RegisterRoutes(rs.ClientCtx, rs.Mux)
authrest.RegisterTxRoutes(rs.ClientCtx, rs.Mux)
simapp.ModuleBasics.RegisterRESTRoutes(rs.ClientCtx, rs.Mux)
}
func initConfig(cmd *cobra.Command) error { func initConfig(cmd *cobra.Command) error {
home, err := cmd.PersistentFlags().GetString(cli.HomeFlag) home, err := cmd.PersistentFlags().GetString(cli.HomeFlag)
if err != nil { if err != nil {

View File

@ -71,7 +71,7 @@ func main() {
} }
} }
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application { func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) server.Application {
var cache sdk.MultiStorePersistentCache var cache sdk.MultiStorePersistentCache
if viper.GetBool(server.FlagInterBlockCache) { if viper.GetBool(server.FlagInterBlockCache) {

View File

@ -121,6 +121,7 @@ func InitTestnet(
simappConfig := srvconfig.DefaultConfig() simappConfig := srvconfig.DefaultConfig()
simappConfig.MinGasPrices = minGasPrices simappConfig.MinGasPrices = minGasPrices
simappConfig.API.Enable = true
var ( var (
genAccounts []authtypes.GenesisAccount genAccounts []authtypes.GenesisAccount