Skip to content

Commit

Permalink
Merge branch 'master' into am/amino-tipper
Browse files Browse the repository at this point in the history
  • Loading branch information
amaury1093 authored Oct 22, 2021
2 parents 7602d4d + 994219a commit 6b9abab
Show file tree
Hide file tree
Showing 64 changed files with 4,001 additions and 286 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* (client) [#10226](https://github.com/cosmos/cosmos-sdk/pull/10226) Fix --home flag parsing.
* (rosetta) [\#10340](https://github.com/cosmos/cosmos-sdk/pull/10340) Use `GenesisChunked(ctx)` instead `Genesis(ctx)` to get genesis block height
* (client) [#10226](https://github.com/cosmos/cosmos-sdk/pull/10226) Fix --home flag parsing.
* [#10180](https://github.com/cosmos/cosmos-sdk/issues/10180) Documentation: make references to Cosmos SDK consistent
* (x/genutil) [#10104](https://github.com/cosmos/cosmos-sdk/pull/10104) Ensure the `init` command reads the `--home` flag value correctly.
* [\#9651](https://github.com/cosmos/cosmos-sdk/pull/9651) Change inconsistent limit of `0` to `MaxUint64` on InfiniteGasMeter and add GasRemaining func to GasMeter.
Expand All @@ -157,6 +158,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#10184](https://github.com/cosmos/cosmos-sdk/pull/10184) Fixed CLI tx commands to no longer explicitly require the chain-id flag as this value can come from a user config.
* [\#10239](https://github.com/cosmos/cosmos-sdk/pull/10239) Fixed x/bank/044 migrateDenomMetadata.
* (x/upgrade) [\#10189](https://github.com/cosmos/cosmos-sdk/issues/10189) Removed potential sources of non-determinism in upgrades
* [\#10258](https://github.com/cosmos/cosmos-sdk/issues/10258) Fixes issue related to segmentaiton fault on mac m1 arm64

### State Machine Breaking

Expand Down Expand Up @@ -201,6 +203,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#9848](https://github.com/cosmos/cosmos-sdk/pull/9848) ADR-040: Implement BadgerDB backend
* [\#9851](https://github.com/cosmos/cosmos-sdk/pull/9851) ADR-040: Implement RocksDB backend
* [\#10308](https://github.com/cosmos/cosmos-sdk/pull/10308) ADR-040: Implement DBConnection.Revert
* [\#9892](https://github.com/cosmos/cosmos-sdk/pull/9892) ADR-040: KV Store with decoupled storage and state commitment


### Client Breaking Changes
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ BUILD_TARGETS := build install

build: BUILD_ARGS=-o $(BUILDDIR)/
build-linux:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build
GOOS=linux GOARCH=$(if $(findstring aarch64,$(shell uname -m)) || $(findstring arm64,$(shell uname -m)),arm64,amd64) LEDGER_ENABLED=false $(MAKE) build

$(BUILD_TARGETS): go.sum $(BUILDDIR)/
go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...
Expand Down
8 changes: 8 additions & 0 deletions cosmovisor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

### Features

+ [\#10285](https://github.com/cosmos/cosmos-sdk/pull/10316) Added `run` action.

### Deprecated

+ [\#10285](https://github.com/cosmos/cosmos-sdk/pull/10316) Running `cosmovisor` without the `run` argument.

## v1.0.0 2021-09-30

### Features
Expand Down
38 changes: 14 additions & 24 deletions cosmovisor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#### Design

Cosmovisor is designed to be used as a wrapper for an `Cosmos SDK` app:
* it will pass all arguments to the associated app (configured by `DAEMON_NAME` env variable).
Running `cosmovisor arg1 arg2 ....` will run `app arg1 arg2 ...`;
Cosmovisor is designed to be used as a wrapper for a `Cosmos SDK` app:
* it will pass arguments to the associated app (configured by `DAEMON_NAME` env variable).
Running `cosmovisor run arg1 arg2 ....` will run `app arg1 arg2 ...`;
* it will manage an app by restarting and upgrading if needed;
* it is configured using environment variables, not positional arguments.

Expand Down Expand Up @@ -34,19 +34,25 @@ go install github.com/cosmos/cosmos-sdk/cosmovisor/cmd/cosmovisor@latest

### Command Line Arguments And Environment Variables

All arguments passed to `cosmovisor` will be passed to the application binary (as a subprocess). `cosmovisor` will return `/dev/stdout` and `/dev/stderr` of the subprocess as its own. For this reason, `cosmovisor` cannot accept any command-line arguments other than those available to the application binary, nor will it print anything to output other than what is printed by the application binary.
The first argument passed to `cosmovisor` is the action for `cosmovisor` to take. Options are:
* `help`, `--help`, or `-h` - Output `cosmovisor` help information and check your `cosmovisor` configuration.
* `run` - Run the configured binary using the rest of the provided arguments.
* `version`, or `--version` - Output the `cosmovisor` version and also run the binary with the `version` argument.

All arguments passed to `cosmovisor run` will be passed to the application binary (as a subprocess). `cosmovisor` will return `/dev/stdout` and `/dev/stderr` of the subprocess as its own. For this reason, `cosmovisor run` cannot accept any command-line arguments other than those available to the application binary.

*Note: Use of `cosmovisor` without one of the action arguments is deprecated. For backwards compatability, if the first argument is not an action argument, `run` is assumed. However, this fallback might be removed in future versions, so it is recommended that you always provide `run`.

`cosmovisor` reads its configuration from environment variables:

* `DAEMON_HOME` is the location where the `cosmovisor/` directory is kept that contains the genesis binary, the upgrade binaries, and any additional auxiliary files associated with each binary (e.g. `$HOME/.gaiad`, `$HOME/.regend`, `$HOME/.simd`, etc.).
* `DAEMON_NAME` is the name of the binary itself (e.g. `gaiad`, `regend`, `simd`, etc.).
* `DAEMON_ALLOW_DOWNLOAD_BINARIES` (*optional*), if set to `true`, will enable auto-downloading of new binaries (for security reasons, this is intended for full nodes rather than validators). By default, `cosmovisor` will not auto-download new binaries.
* `DAEMON_RESTART_AFTER_UPGRADE` (*optional*, default = `true`), if `true`, restarts the subprocess with the same command-line arguments and flags (but with the new binary) after a successful upgrade. Otherwise (`false`), `cosmovisor` stops running after an upgrade and requires the system administrator to manually restart it. Note restart is only after the upgrade and does not auto-restart the subprocess after an error occurs.
* `DAEMON_POLL_INTERVAL` is the interval length in milliseconds for polling the upgrade plan file. Default: 300.
* `UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `false`, backs up the data before trying the upgrade. Otherwise (`true`), upgrades directly without performing a backup. The default value of false is useful and recommended in case of failures and when a backup needed to rollback. We recommend using the default backup option `UNSAFE_SKIP_BACKUP=false`.
* `DAEMON_POLL_INTERVAL` is the interval length for polling the upgrade plan file. The value can either be a number (in milliseconds) or a duration (e.g. `1s`). Default: 300 milliseconds.
* `UNSAFE_SKIP_BACKUP` (defaults to `false`), if set to `true`, upgrades directly without performing a backup. Otherwise (`false`, default) backs up the data before trying the upgrade. The default value of false is useful and recommended in case of failures and when a backup needed to rollback. We recommend using the default backup option `UNSAFE_SKIP_BACKUP=false`.
* `DAEMON_PREUPGRADE_MAX_RETRIES` (defaults to `0`). The maximum number of times to call `pre-upgrade` in the application after exit status of `31`. After the maximum number of retries, cosmovisor fails the upgrade.


### Folder Layout

`$DAEMON_HOME/cosmovisor` is expected to belong completely to `cosmovisor` and the subprocesses that are controlled by it. The folder content is organized as follows:
Expand Down Expand Up @@ -91,22 +97,6 @@ In order to support downloadable binaries, a tarball for each upgrade binary wil

The `DAEMON` specific code and operations (e.g. tendermint config, the application db, syncing blocks, etc.) all work as expected. The application binaries' directives such as command-line flags and environment variables also work as expected.

### Commands

Because Cosmovisor is meant to be used as a wrapper for a Cosmos SDK application, it does not require many commands.

To determine the version of Cosmovisor, run the following command:
```
cosmovisor version
```
The output of the `cosmovisor version` command shows the version of the Cosmos SDK application and the version of Cosmovisor:

```
Cosmovisor Version: v0.1.0-85-g65baacac0
0.43.0-beta1-319-ge3aec1840
```


### Detecting Upgrades

`cosmovisor` is polling the `$DAEMON_HOME/data/upgrade-info.json` file for new upgrade instructions. The file is created by the x/upgrade module in `BeginBlocker` when an upgrade is detected and the blockchain reaches the upgrade height.
Expand Down Expand Up @@ -278,7 +268,7 @@ cp ./build/simd $DAEMON_HOME/cosmovisor/upgrades/test1/bin
Start `cosmosvisor`:

```
cosmovisor start
cosmovisor run start
```

Open a new terminal window and submit an upgrade proposal along with a deposit and a vote (these commands must be run within 20 seconds of each other):
Expand Down
39 changes: 32 additions & 7 deletions cosmovisor/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"strings"
"time"

"github.com/rs/zerolog"

cverrors "github.com/cosmos/cosmos-sdk/cosmovisor/errors"
)

Expand Down Expand Up @@ -143,13 +145,18 @@ func GetConfigFromEnv() (*Config, error) {

interval := os.Getenv(EnvInterval)
if interval != "" {
switch i, e := strconv.ParseUint(interval, 10, 32); {
case e != nil:
errs = append(errs, fmt.Errorf("invalid %s: %w", EnvInterval, err))
case i == 0:
errs = append(errs, fmt.Errorf("invalid %s: cannot be 0", EnvInterval))
default:
cfg.PollInterval = time.Millisecond * time.Duration(i)
var intervalUInt uint64
intervalUInt, err = strconv.ParseUint(interval, 10, 32)
if err == nil {
cfg.PollInterval = time.Millisecond * time.Duration(intervalUInt)
} else {
cfg.PollInterval, err = time.ParseDuration(interval)
}
switch {
case err != nil:
errs = append(errs, fmt.Errorf("invalid %s: could not parse \"%s\" into either a duration or uint (milliseconds)", EnvInterval, interval))
case cfg.PollInterval <= 0:
errs = append(errs, fmt.Errorf("invalid %s: must be greater than 0", EnvInterval))
}
} else {
cfg.PollInterval = 300 * time.Millisecond
Expand All @@ -168,6 +175,24 @@ func GetConfigFromEnv() (*Config, error) {
return cfg, nil
}

// LogConfigOrError logs either the config details or the error.
func LogConfigOrError(logger zerolog.Logger, cfg *Config, cerr error) {
switch {
case cerr != nil:
switch err := cerr.(type) {
case *cverrors.MultiError:
logger.Error().Msg("multiple configuration errors found:")
for i, e := range err.GetErrors() {
logger.Error().Err(e).Msg(fmt.Sprintf(" %d:", i+1))
}
default:
logger.Error().Err(cerr).Msg("configuration error:")
}
case cfg != nil:
logger.Info().Msg("Configuration is valid:\n" + cfg.DetailString())
}
}

// validate returns an error if this config is invalid.
// it enforces Home/cosmovisor is a valid directory and exists,
// and that Name is set
Expand Down
98 changes: 98 additions & 0 deletions cosmovisor/args_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package cosmovisor

import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"testing"
"time"

"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -451,6 +454,18 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
expectedCfg: newConfig(absPath, "testname", false, false, false, 987, 1),
expectedErrCount: 0,
},
{
name: "poll interval 1s",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "false", "1s", "1"},
expectedCfg: newConfig(absPath, "testname", false, false, false, 1000, 1),
expectedErrCount: 0,
},
{
name: "poll interval -3m",
envVals: cosmovisorEnv{absPath, "testname", "false", "false", "false", "-3m", "1"},
expectedCfg: nil,
expectedErrCount: 1,
},
// EnvHome, EnvName, EnvDownloadBin, EnvRestartUpgrade, EnvSkipBackup, EnvInterval, EnvPreupgradeMaxRetries
{
name: "prepupgrade max retries bad",
Expand Down Expand Up @@ -497,3 +512,86 @@ func (s *argsTestSuite) TestGetConfigFromEnv() {
})
}
}

func (s *argsTestSuite) TestLogConfigOrError() {
cfg := &Config{
Home: "/no/place/like/it",
Name: "cosmotestvisor",
AllowDownloadBinaries: true,
RestartAfterUpgrade: true,
PollInterval: 999,
UnsafeSkipBackup: false,
PreupgradeMaxRetries: 20,
}
errNormal := fmt.Errorf("this is a single error")
errs := []error{
fmt.Errorf("multi-error error 1"),
fmt.Errorf("multi-error error 2"),
fmt.Errorf("multi-error error 3"),
}
errMulti := errors.FlattenErrors(errs...)

makeTestLogger := func(testName string, out io.Writer) zerolog.Logger {
output := zerolog.ConsoleWriter{Out: out, TimeFormat: time.Kitchen, NoColor: true}
return zerolog.New(output).With().Str("test", testName).Timestamp().Logger()
}

tests := []struct {
name string
cfg *Config
err error
contains []string
notcontains []string
}{
{
name: "normal error",
cfg: nil,
err: errNormal,
contains: []string{"configuration error", errNormal.Error()}, // TODO: Fix this.
notcontains: nil,
},
{
name: "multi error",
cfg: nil,
err: errMulti,
contains: []string{"multiple configuration errors found", errs[0].Error(), errs[1].Error(), errs[2].Error()},
notcontains: nil,
},
{
name: "config",
cfg: cfg,
err: nil,
contains: []string{"Configuration is valid", cfg.DetailString()},
notcontains: nil,
},
{
name: "error and config - no config details",
cfg: cfg,
err: errNormal,
contains: []string{"error"},
notcontains: []string{"Configuration is valid", EnvName, cfg.Home}, // Just some spot checks.
},
{
name: "nil nil - no output",
cfg: nil,
err: nil,
contains: nil,
notcontains: []string{" "},
},
}

for _, tc := range tests {
s.T().Run(tc.name, func(t *testing.T) {
var b bytes.Buffer
logger := makeTestLogger(tc.name, &b)
LogConfigOrError(logger, tc.cfg, tc.err)
output := b.String()
for _, expected := range tc.contains {
assert.Contains(t, output, expected)
}
for _, unexpected := range tc.notcontains {
assert.NotContains(t, output, unexpected)
}
})
}
}
34 changes: 19 additions & 15 deletions cosmovisor/cmd/cosmovisor/cmd/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,34 @@ package cmd
import (
"fmt"
"os"
"strings"
"time"

"github.com/rs/zerolog"

"github.com/cosmos/cosmos-sdk/cosmovisor"
)

// HelpArgs are the strings that indicate a cosmovisor help command.
var HelpArgs = []string{"help", "--help", "-h"}

// ShouldGiveHelp checks the env and provided args to see if help is needed or being requested.
// Help is needed if either cosmovisor.EnvName and/or cosmovisor.EnvHome env vars aren't set.
// Help is requested if any args are "help", "--help", or "-h".
func ShouldGiveHelp(args []string) bool {
if len(os.Getenv(cosmovisor.EnvName)) == 0 || len(os.Getenv(cosmovisor.EnvHome)) == 0 {
return true
}
if len(args) == 0 {
return false
}
for _, arg := range args {
if strings.EqualFold(arg, "help") || strings.EqualFold(arg, "--help") || strings.EqualFold(arg, "-h") {
return true
}
}
return false
// Help is requested if the first arg is "help", "--help", or "-h".
func ShouldGiveHelp(arg string) bool {
return isOneOf(arg, HelpArgs) || len(os.Getenv(cosmovisor.EnvName)) == 0 || len(os.Getenv(cosmovisor.EnvHome)) == 0
}

// DoHelp outputs help text
func DoHelp() {
// Not using the logger for this output because the header and footer look weird for help text.
fmt.Println(GetHelpText())
// Check the config and output details or any errors.
// Not using the cosmovisor.Logger in order to ignore any level it might have set,
// and also to not have any of the extra parameters in the output.
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.Kitchen}
logger := zerolog.New(output).With().Timestamp().Logger()
cfg, err := cosmovisor.GetConfigFromEnv()
cosmovisor.LogConfigOrError(logger, cfg, err)
}

// GetHelpText creates the help text multi-line string.
Expand All @@ -45,5 +46,8 @@ and restart the App.
Configuration of Cosmovisor is done through environment variables, which are
documented in: https://github.com/cosmos/cosmos-sdk/tree/master/cosmovisor/README.md
To get help for the configured binary:
cosmovisor run help
`, cosmovisor.EnvName, cosmovisor.EnvHome)
}
Loading

0 comments on commit 6b9abab

Please sign in to comment.