cosmos-sdk/server/util.go
dependabot[bot] ea8b0f731d
build(deps): Bump github.com/tendermint/tendermint from 0.35.2 to 0.35.3 (#11599)
Bumps [github.com/tendermint/tendermint](https://github.com/tendermint/tendermint) from 0.35.2 to 0.35.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/tendermint/tendermint/releases">github.com/tendermint/tendermint's releases</a>.</em></p>
<blockquote>
<h2>0.35.3 (WARNING: BETA SOFTWARE)</h2>
<p><a href="https://github.com/tendermint/tendermint/blob/v0.35.3/CHANGELOG.md#v0.35.3">https://github.com/tendermint/tendermint/blob/v0.35.3/CHANGELOG.md#v0.35.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/tendermint/tendermint/blob/master/CHANGELOG.md">github.com/tendermint/tendermint's changelog</a>.</em></p>
<blockquote>
<h2>v0.35.3</h2>
<p>April 8, 2022</p>
<h3>FEATURES</h3>
<ul>
<li>[cli] <a href="https://github-redirect.dependabot.com/tendermint/tendermint/pull/8081">#8081</a> add a safer-to-use <code>reset-state</code> command. (<a href="https://github.com/marbar3778"><code>@​marbar3778</code></a>)</li>
</ul>
<h3>IMPROVEMENTS</h3>
<ul>
<li>[consensus] <a href="https://github-redirect.dependabot.com/tendermint/tendermint/pull/8138">#8138</a> change lock handling in reactor and handleMsg for RoundState. (<a href="https://github.com/williambanfield"><code>@​williambanfield</code></a>)</li>
</ul>
<h3>BUG FIXES</h3>
<ul>
<li>[cli] <a href="https://github-redirect.dependabot.com/tendermint/tendermint/pull/8276">#8276</a> scmigrate: ensure target key is correctly renamed. (<a href="https://github.com/creachadair"><code>@​creachadair</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="dfa001f5c7"><code>dfa001f</code></a> Prepare changelog for release v0.35.3. (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8289">#8289</a>)</li>
<li><a href="5f7031432d"><code>5f70314</code></a> build(deps): Bump github.com/lib/pq from 1.10.4 to 1.10.5 (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8282">#8282</a>)</li>
<li><a href="fb7ce48c15"><code>fb7ce48</code></a> scmigrate: ensure target key is correctly renamed (backport <a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8276">#8276</a>) (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8280">#8280</a>)</li>
<li><a href="308d283241"><code>308d283</code></a> cli: fix reset command for v0.35 (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8259">#8259</a>)</li>
<li><a href="530e81dea4"><code>530e81d</code></a> Fix broken links in the changelog. (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8268">#8268</a>)</li>
<li><a href="5051a1ce82"><code>5051a1c</code></a> build(deps): Bump github.com/BurntSushi/toml from 1.0.0 to 1.1.0 (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8253">#8253</a>)</li>
<li><a href="ac881db09a"><code>ac881db</code></a> build(deps): Bump github.com/vektra/mockery/v2 from 2.10.2 to 2.10.4 (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8254">#8254</a>)</li>
<li><a href="14461339f4"><code>1446133</code></a> Update golangci-lint-action and golang-ci versions. (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8256">#8256</a>)</li>
<li><a href="21da336656"><code>21da336</code></a> build(deps): Bump github.com/vektra/mockery/v2 from 2.10.1 to 2.10.2 (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8247">#8247</a>)</li>
<li><a href="524d3ceb88"><code>524d3ce</code></a> e2e: Fix hashing for app + Fix logic of TestApp_Hash (backport <a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8229">#8229</a>) (<a href="https://github-redirect.dependabot.com/tendermint/tendermint/issues/8236">#8236</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/tendermint/tendermint/compare/v0.35.2...v0.35.3">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/tendermint/tendermint&package-manager=go_modules&previous-version=0.35.2&new-version=0.35.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>
2022-04-12 05:19:38 +00:00

410 lines
11 KiB
Go

package server
import (
"errors"
"fmt"
"io"
"net"
"os"
"os/signal"
"path"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cast"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
tmcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmcfg "github.com/tendermint/tendermint/config"
tmlog "github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server/config"
"github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
)
// DONTCOVER
// ServerContextKey defines the context key used to retrieve a server.Context from
// a command's Context.
const ServerContextKey = sdk.ContextKey("server.context")
// server context
type Context struct {
Viper *viper.Viper
Config *tmcfg.Config
Logger tmlog.Logger
}
// ErrorCode contains the exit code for server exit.
type ErrorCode struct {
Code int
}
func (e ErrorCode) Error() string {
return strconv.Itoa(e.Code)
}
func NewDefaultContext() *Context {
return NewContext(
viper.New(),
tmcfg.DefaultConfig(),
ZeroLogWrapper{log.Logger},
)
}
func NewContext(v *viper.Viper, config *tmcfg.Config, logger tmlog.Logger) *Context {
return &Context{v, config, logger}
}
func bindFlags(basename string, cmd *cobra.Command, v *viper.Viper) (err error) {
defer func() {
recover()
}()
cmd.Flags().VisitAll(func(f *pflag.Flag) {
// Environment variables can't have dashes in them, so bind them to their equivalent
// keys with underscores, e.g. --favorite-color to STING_FAVORITE_COLOR
err = v.BindEnv(f.Name, fmt.Sprintf("%s_%s", basename, strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_"))))
if err != nil {
panic(err)
}
err = v.BindPFlag(f.Name, f)
if err != nil {
panic(err)
}
// Apply the viper config value to the flag when the flag is not set and viper has a value
if !f.Changed && v.IsSet(f.Name) {
val := v.Get(f.Name)
err = cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val))
if err != nil {
panic(err)
}
}
})
return
}
// InterceptConfigsPreRunHandler performs a pre-run function for the root daemon
// application command. It will create a Viper literal and a default server
// Context. The server Tendermint configuration will either be read and parsed
// or created and saved to disk, where the server Context is updated to reflect
// the Tendermint configuration. It takes custom app config template and config
// settings to create a custom Tendermint configuration. If the custom template
// is empty, it uses default-template provided by the server. The Viper literal
// is used to read and parse the application configuration. Command handlers can
// fetch the server Context to get the Tendermint configuration or to get access
// to Viper.
func InterceptConfigsPreRunHandler(cmd *cobra.Command, customAppConfigTemplate string, customAppConfig interface{}, tmConfig *tmcfg.Config) error {
serverCtx := NewDefaultContext()
// Get the executable name and configure the viper instance so that environmental
// variables are checked based off that name. The underscore character is used
// as a separator
executableName, err := os.Executable()
if err != nil {
return err
}
basename := path.Base(executableName)
// Configure the viper instance
serverCtx.Viper.BindPFlags(cmd.Flags())
serverCtx.Viper.BindPFlags(cmd.PersistentFlags())
serverCtx.Viper.SetEnvPrefix(basename)
serverCtx.Viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
serverCtx.Viper.AutomaticEnv()
// intercept configuration files, using both Viper instances separately
config, err := interceptConfigs(serverCtx.Viper, customAppConfigTemplate, customAppConfig, tmConfig)
if err != nil {
return err
}
// return value is a tendermint configuration object
serverCtx.Config = config
if err = bindFlags(basename, cmd, serverCtx.Viper); err != nil {
return err
}
var logWriter io.Writer
if strings.ToLower(serverCtx.Viper.GetString(flags.FlagLogFormat)) == tmlog.LogFormatPlain {
logWriter = zerolog.ConsoleWriter{Out: os.Stderr}
} else {
logWriter = os.Stderr
}
logLvlStr := serverCtx.Viper.GetString(flags.FlagLogLevel)
logLvl, err := zerolog.ParseLevel(logLvlStr)
if err != nil {
return fmt.Errorf("failed to parse log level (%s): %w", logLvlStr, err)
}
serverCtx.Logger = ZeroLogWrapper{zerolog.New(logWriter).Level(logLvl).With().Timestamp().Logger()}
return SetCmdServerContext(cmd, serverCtx)
}
// GetServerContextFromCmd returns a Context from a command or an empty Context
// if it has not been set.
func GetServerContextFromCmd(cmd *cobra.Command) *Context {
if v := cmd.Context().Value(ServerContextKey); v != nil {
serverCtxPtr := v.(*Context)
return serverCtxPtr
}
return NewDefaultContext()
}
// SetCmdServerContext sets a command's Context value to the provided argument.
func SetCmdServerContext(cmd *cobra.Command, serverCtx *Context) error {
v := cmd.Context().Value(ServerContextKey)
if v == nil {
return errors.New("server context not set")
}
serverCtxPtr := v.(*Context)
*serverCtxPtr = *serverCtx
return nil
}
// interceptConfigs parses and updates a Tendermint configuration file or
// creates a new one and saves it. It also parses and saves the application
// configuration file. The Tendermint configuration file is parsed given a root
// Viper object, whereas the application is parsed with the private package-aware
// viperCfg object.
func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customConfig interface{}, tmConfig *tmcfg.Config) (*tmcfg.Config, error) {
rootDir := rootViper.GetString(flags.FlagHome)
configPath := filepath.Join(rootDir, "config")
tmCfgFile := filepath.Join(configPath, "config.toml")
conf := tmConfig
switch _, err := os.Stat(tmCfgFile); {
case os.IsNotExist(err):
tmcfg.EnsureRoot(rootDir)
if err = conf.ValidateBasic(); err != nil {
return nil, fmt.Errorf("error in config file: %v", err)
}
conf.RPC.PprofListenAddress = "localhost:6060"
conf.P2P.RecvRate = 5120000
conf.P2P.SendRate = 5120000
conf.Consensus.TimeoutCommit = 5 * time.Second
tmcfg.WriteConfigFile(rootDir, conf)
case err != nil:
return nil, err
default:
rootViper.SetConfigType("toml")
rootViper.SetConfigName("config")
rootViper.AddConfigPath(configPath)
if err := rootViper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to read in %s: %w", tmCfgFile, err)
}
}
// Read into the configuration whatever data the viper instance has for it.
// This may come from the configuration file above but also any of the other
// sources viper uses.
if err := rootViper.Unmarshal(conf); err != nil {
return nil, err
}
conf.SetRoot(rootDir)
appCfgFilePath := filepath.Join(configPath, "app.toml")
if _, err := os.Stat(appCfgFilePath); os.IsNotExist(err) {
if customAppTemplate != "" {
config.SetConfigTemplate(customAppTemplate)
if err = rootViper.Unmarshal(&customConfig); err != nil {
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
}
config.WriteConfigFile(appCfgFilePath, customConfig)
} else {
appConf, err := config.ParseConfig(rootViper)
if err != nil {
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
}
config.WriteConfigFile(appCfgFilePath, appConf)
}
}
rootViper.SetConfigType("toml")
rootViper.SetConfigName("app")
rootViper.AddConfigPath(configPath)
if err := rootViper.MergeInConfig(); err != nil {
return nil, fmt.Errorf("failed to merge configuration: %w", err)
}
return conf, nil
}
// add 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",
}
tendermintCmd.AddCommand(
ShowNodeIDCmd(),
ShowValidatorCmd(),
ShowAddressCmd(),
VersionCmd(),
tmcmd.ResetAllCmd,
tmcmd.ResetStateCmd,
tmcmd.InspectCmd,
)
startCmd := StartCmd(appCreator, defaultNodeHome)
addStartFlags(startCmd)
rootCmd.AddCommand(
startCmd,
tendermintCmd,
ExportCmd(appExport, defaultNodeHome),
version.NewVersionCommand(),
NewRollbackCmd(defaultNodeHome),
)
}
// https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go
// TODO there must be a better way to get external IP
func ExternalIP() (string, error) {
ifaces, err := net.Interfaces()
if err != nil {
return "", err
}
for _, iface := range ifaces {
if skipInterface(iface) {
continue
}
addrs, err := iface.Addrs()
if err != nil {
return "", err
}
for _, addr := range addrs {
ip := addrToIP(addr)
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
return ip.String(), nil
}
}
return "", errors.New("are you connected to the network?")
}
// TrapSignal traps SIGINT and SIGTERM and terminates the server correctly.
func TrapSignal(cleanupFunc func()) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
if cleanupFunc != nil {
cleanupFunc()
}
exitCode := 128
switch sig {
case syscall.SIGINT:
exitCode += int(syscall.SIGINT)
case syscall.SIGTERM:
exitCode += int(syscall.SIGTERM)
}
os.Exit(exitCode)
}()
}
// WaitForQuitSignals waits for SIGINT and SIGTERM and returns.
func WaitForQuitSignals() ErrorCode {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigs
return ErrorCode{Code: int(sig.(syscall.Signal)) + 128}
}
// GetAppDBBackend gets the backend type to use for the application DBs.
func GetAppDBBackend(opts types.AppOptions) dbm.BackendType {
rv := cast.ToString(opts.Get("app-db-backend"))
if len(rv) == 0 {
rv = sdk.DBBackend
}
if len(rv) == 0 {
rv = cast.ToString(opts.Get("db-backend"))
}
if len(rv) != 0 {
return dbm.BackendType(rv)
}
return dbm.GoLevelDBBackend
}
func skipInterface(iface net.Interface) bool {
if iface.Flags&net.FlagUp == 0 {
return true // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
return true // loopback interface
}
return false
}
func addrToIP(addr net.Addr) net.IP {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
return ip
}
func openDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) {
dataDir := filepath.Join(rootDir, "data")
return dbm.NewDB("application", backendType, dataDir)
}
func openTraceWriter(traceWriterFile string) (w io.Writer, err error) {
if traceWriterFile == "" {
return
}
return os.OpenFile(
traceWriterFile,
os.O_WRONLY|os.O_APPEND|os.O_CREATE,
0666,
)
}