diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 831523bc6a69..96311595e2d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: .mod .sum - name: Run cosmovisor tests - run: cd cosmovisor; go test . + run: cd cosmovisor; make if: "env.GIT_DIFF != ''" split-test-files: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index 2e219c862cef..03dbff1e84a7 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,10 @@ build-simd: go.sum build-simd-linux: go.sum LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build-simd -.PHONY: build build-simd build-simd-linux +cosmovisor: + $(MAKE) -C cosmovisor cosmovisor + +.PHONY: build build-simd build-simd-linux cosmovisor mocks: $(MOCKS_DIR) mockgen -source=client/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go diff --git a/baseapp/abci.go b/baseapp/abci.go index 4a5b6335028e..5e8f6f760e38 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -1,6 +1,7 @@ package baseapp import ( + "crypto/sha256" "errors" "fmt" "os" @@ -81,9 +82,25 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } } + // In the case of a new chain, AppHash will be the hash of an empty string. + // During an upgrade, it'll be the hash of the last committed block. + var appHash []byte + if !app.LastCommitID().IsZero() { + appHash = app.LastCommitID().Hash + } else { + // $ echo -n '' | sha256sum + // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + emptyHash := sha256.Sum256([]byte{}) + appHash = emptyHash[:] + } + // NOTE: We don't commit, but BeginBlock for block `initial_height` starts from this // deliverState. - return res + return abci.ResponseInitChain{ + ConsensusParams: res.ConsensusParams, + Validators: res.Validators, + AppHash: appHash, + } } // Info implements the ABCI interface. diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index efe2b1528bb8..089277ccac07 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -564,7 +564,16 @@ func TestInitChainer(t *testing.T) { require.Nil(t, err) require.Equal(t, int64(0), app.LastBlockHeight()) - app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty + initChainRes := app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty + + // The AppHash returned by a new chain is the sha256 hash of "". + // $ echo -n '' | sha256sum + // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + require.Equal( + t, + []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + initChainRes.AppHash, + ) // assert that chainID is set correctly in InitChain chainID := app.deliverState.ctx.ChainID() diff --git a/client/grpc/simulate/simulate_test.go b/client/grpc/simulate/simulate_test.go index 390b5b52e433..1a5c32306fd0 100644 --- a/client/grpc/simulate/simulate_test.go +++ b/client/grpc/simulate/simulate_test.go @@ -11,10 +11,12 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/simulate" "github.com/cosmos/cosmos-sdk/client/tx" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -98,9 +100,14 @@ func (s IntegrationTestSuite) TestSimulateService() { ) txBuilder.SetSignatures(sigV2) + any, ok := txBuilder.(codectypes.IntoAny) + s.Require().True(ok) + cached := any.AsAny().GetCachedValue() + txTx, ok := cached.(*txtypes.Tx) + s.Require().True(ok) res, err := s.queryClient.Simulate( context.Background(), - &simulate.SimulateRequest{Tx: txBuilder.GetProtoTx()}, + &simulate.SimulateRequest{Tx: txTx}, ) s.Require().NoError(err) diff --git a/client/rpc/validators.go b/client/rpc/validators.go index 572f2005a568..26f9aae27b0b 100644 --- a/client/rpc/validators.go +++ b/client/rpc/validators.go @@ -56,7 +56,7 @@ func ValidatorCommand() *cobra.Command { cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)") - cmd.Flags().Int(flags.FlagPage, 0, "Query a specific page of paginated results") + cmd.Flags().Int(flags.FlagPage, rest.DefaultPage, "Query a specific page of paginated results") cmd.Flags().Int(flags.FlagLimit, 100, "Query number of results returned per page") return cmd diff --git a/client/tx/legacy.go b/client/tx/legacy.go index 80f9e4ef8cb0..2648a520cfdd 100644 --- a/client/tx/legacy.go +++ b/client/tx/legacy.go @@ -12,7 +12,6 @@ import ( // ConvertTxToStdTx converts a transaction to the legacy StdTx format func ConvertTxToStdTx(codec *codec.LegacyAmino, tx signing.Tx) (types.StdTx, error) { - if stdTx, ok := tx.(types.StdTx); ok { return stdTx, nil } diff --git a/client/tx/legacy_test.go b/client/tx/legacy_test.go index 86e506a9eab8..191da4c629e7 100644 --- a/client/tx/legacy_test.go +++ b/client/tx/legacy_test.go @@ -3,26 +3,21 @@ package tx_test import ( "testing" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/simapp/params" - - "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "github.com/cosmos/cosmos-sdk/client" tx2 "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/std" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - types3 "github.com/cosmos/cosmos-sdk/x/auth/types" - - signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing" - - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/testutil/testdata" "github.com/cosmos/cosmos-sdk/types" + signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + types3 "github.com/cosmos/cosmos-sdk/x/auth/types" types2 "github.com/cosmos/cosmos-sdk/x/bank/types" ) diff --git a/client/tx/tx.go b/client/tx/tx.go index 2babbf625edc..b5f9e2900cd0 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -14,9 +14,11 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sim "github.com/cosmos/cosmos-sdk/client/grpc/simulate" "github.com/cosmos/cosmos-sdk/client/input" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) @@ -265,7 +267,17 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { return nil, err } - simReq := sim.SimulateRequest{Tx: txb.GetProtoTx()} + any, ok := txb.(codectypes.IntoAny) + if !ok { + return nil, fmt.Errorf("cannot simulate tx that cannot be wrapped into any") + } + cached := any.AsAny().GetCachedValue() + protoTx, ok := cached.(*tx.Tx) + if !ok { + return nil, fmt.Errorf("cannot simulate amino tx") + } + + simReq := sim.SimulateRequest{Tx: protoTx} return simReq.Marshal() } diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index a2834f08dd59..825b158c1430 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -15,13 +15,12 @@ import ( "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/signing" - "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) func NewTestTxConfig() client.TxConfig { - _, cdc := simapp.MakeCodecs() - return types.StdTxConfig{Cdc: cdc} + cfg := simapp.MakeEncodingConfig() + return cfg.TxConfig } func TestCalculateGas(t *testing.T) { diff --git a/client/tx_config.go b/client/tx_config.go index 65e3899c4511..6992a7a2402d 100644 --- a/client/tx_config.go +++ b/client/tx_config.go @@ -2,7 +2,6 @@ package client import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/tx" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/signing" ) @@ -36,8 +35,6 @@ type ( // also know how to encode itself. TxBuilder interface { GetTx() signing.Tx - // GetProtoTx returns the tx as a proto.Message. - GetProtoTx() *tx.Tx SetMsgs(msgs ...sdk.Msg) error SetSignatures(signatures ...signingtypes.SignatureV2) error diff --git a/codec/types/any.go b/codec/types/any.go index 60bfef1cade6..b879180481db 100644 --- a/codec/types/any.go +++ b/codec/types/any.go @@ -91,7 +91,7 @@ func (any *Any) Pack(x proto.Message) error { func UnsafePackAny(x interface{}) *Any { if msg, ok := x.(proto.Message); ok { any, err := NewAnyWithValue(msg) - if err != nil { + if err == nil { return any } } @@ -107,3 +107,8 @@ func (any *Any) GetCachedValue() interface{} { func (any *Any) ClearCachedValue() { any.cachedValue = nil } + +// IntoAny represents a type that can be wrapped into an Any. +type IntoAny interface { + AsAny() *Any +} diff --git a/codec/types/compat.go b/codec/types/compat.go index 3e42067763e4..3aa024126000 100644 --- a/codec/types/compat.go +++ b/codec/types/compat.go @@ -50,7 +50,7 @@ func (any *Any) UnmarshalAmino(bz []byte) error { return nil } -func (any Any) MarshalJSON() ([]byte, error) { +func (any *Any) MarshalJSON() ([]byte, error) { ac := any.compat if ac == nil { return nil, anyCompatError("JSON marshal", any) diff --git a/cosmovisor/Makefile b/cosmovisor/Makefile new file mode 100644 index 000000000000..bd5b5c5430da --- /dev/null +++ b/cosmovisor/Makefile @@ -0,0 +1,12 @@ +#!/usr/bin/make -f + + +all: cosmovisor test + +cosmovisor: + go build -mod=readonly ./cmd/cosmovisor + +test: + go test -mod=readonly -race ./... + +.PHONY: all cosmovisor test diff --git a/cosmovisor/args.go b/cosmovisor/args.go index 7e0ac2f54809..33fb62e0180f 100644 --- a/cosmovisor/args.go +++ b/cosmovisor/args.go @@ -1,11 +1,11 @@ package cosmovisor import ( + "errors" + "fmt" "net/url" "os" "path/filepath" - - "github.com/pkg/errors" ) const ( @@ -80,8 +80,7 @@ func (cfg *Config) CurrentBin() (string, error) { } // and return the binary - dest = filepath.Join(dest, "bin", cfg.Name) - return dest, nil + return filepath.Join(dest, "bin", cfg.Name), nil } // GetConfigFromEnv will read the environmental variables into a config @@ -91,15 +90,19 @@ func GetConfigFromEnv() (*Config, error) { Home: os.Getenv("DAEMON_HOME"), Name: os.Getenv("DAEMON_NAME"), } + if os.Getenv("DAEMON_ALLOW_DOWNLOAD_BINARIES") == "true" { cfg.AllowDownloadBinaries = true } + if os.Getenv("DAEMON_RESTART_AFTER_UPGRADE") == "true" { cfg.RestartAfterUpgrade = true } + if err := cfg.validate(); err != nil { return nil, err } + return cfg, nil } @@ -110,6 +113,7 @@ func (cfg *Config) validate() error { if cfg.Name == "" { return errors.New("DAEMON_NAME is not set") } + if cfg.Home == "" { return errors.New("DAEMON_HOME is not set") } @@ -121,10 +125,11 @@ func (cfg *Config) validate() error { // ensure the root directory exists info, err := os.Stat(cfg.Root()) if err != nil { - return errors.Wrap(err, "cannot stat home dir") + return fmt.Errorf("cannot stat home dir: %w", err) } + if !info.IsDir() { - return errors.Errorf("%s is not a directory", info.Name()) + return fmt.Errorf("%s is not a directory", info.Name()) } return nil diff --git a/cosmovisor/cmd/main.go b/cosmovisor/cmd/cosmovisor/main.go similarity index 82% rename from cosmovisor/cmd/main.go rename to cosmovisor/cmd/cosmovisor/main.go index 9a5cd7e0ad03..a165acab38f6 100644 --- a/cosmovisor/cmd/main.go +++ b/cosmovisor/cmd/cosmovisor/main.go @@ -4,13 +4,12 @@ import ( "fmt" "os" - cosmovisor "github.com/cosmos/cosmos-sdk/cosmovisor" + "github.com/cosmos/cosmos-sdk/cosmovisor" ) func main() { - err := Run(os.Args[1:]) - if err != nil { - fmt.Printf("%+v\n", err) + if err := Run(os.Args[1:]); err != nil { + fmt.Fprintf(os.Stderr, "%+v\n", err) os.Exit(1) } } @@ -21,8 +20,8 @@ func Run(args []string) error { if err != nil { return err } - doUpgrade, err := cosmovisor.LaunchProcess(cfg, args, os.Stdout, os.Stderr) + doUpgrade, err := cosmovisor.LaunchProcess(cfg, args, os.Stdout, os.Stderr) // if RestartAfterUpgrade, we launch after a successful upgrade (only condition LaunchProcess returns nil) for cfg.RestartAfterUpgrade && err == nil && doUpgrade { doUpgrade, err = cosmovisor.LaunchProcess(cfg, args, os.Stdout, os.Stderr) diff --git a/cosmovisor/go.mod b/cosmovisor/go.mod index d9f4fdfaecc1..fe6be0cdd4e0 100644 --- a/cosmovisor/go.mod +++ b/cosmovisor/go.mod @@ -5,6 +5,5 @@ go 1.14 require ( github.com/hashicorp/go-getter v1.4.1 github.com/otiai10/copy v1.2.0 - github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.6.1 ) diff --git a/cosmovisor/go.sum b/cosmovisor/go.sum index f9861359c9ac..4506c2a5a19d 100644 --- a/cosmovisor/go.sum +++ b/cosmovisor/go.sum @@ -69,8 +69,6 @@ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6 github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/cosmovisor/process.go b/cosmovisor/process.go index 87acd8b7b4e5..055c4ebfc657 100644 --- a/cosmovisor/process.go +++ b/cosmovisor/process.go @@ -2,12 +2,11 @@ package cosmovisor import ( "bufio" + "fmt" "io" "os/exec" "strings" "sync" - - "github.com/pkg/errors" ) // LaunchProcess runs a subprocess and returns when the subprocess exits, @@ -15,11 +14,11 @@ import ( func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, error) { bin, err := cfg.CurrentBin() if err != nil { - return false, errors.Wrap(err, "error creating symlink to genesis") + return false, fmt.Errorf("error creating symlink to genesis: %w", err) } - err = EnsureBinary(bin) - if err != nil { - return false, errors.Wrap(err, "current binary invalid") + + if err := EnsureBinary(bin); err != nil { + return false, fmt.Errorf("current binary invalid: %w", err) } cmd := exec.Command(bin, args...) @@ -27,16 +26,17 @@ func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, if err != nil { return false, err } + errpipe, err := cmd.StderrPipe() if err != nil { return false, err } + scanOut := bufio.NewScanner(io.TeeReader(outpipe, stdout)) scanErr := bufio.NewScanner(io.TeeReader(errpipe, stderr)) - err = cmd.Start() - if err != nil { - return false, errors.Wrapf(err, "launching process %s %s", bin, strings.Join(args, " ")) + if err := cmd.Start(); err != nil { + return false, fmt.Errorf("launching process %s %s: %w", bin, strings.Join(args, " "), err) } // three ways to exit - command ends, find regexp in scanOut, find regexp in scanErr @@ -44,6 +44,7 @@ func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, if err != nil { return false, err } + if upgradeInfo != nil { return true, DoUpgrade(cfg, upgradeInfo) } diff --git a/cosmovisor/upgrade.go b/cosmovisor/upgrade.go index 12eadf010477..9c1cae8dae72 100644 --- a/cosmovisor/upgrade.go +++ b/cosmovisor/upgrade.go @@ -2,6 +2,7 @@ package cosmovisor import ( "encoding/json" + "errors" "fmt" "io/ioutil" "net/url" @@ -11,41 +12,38 @@ import ( "strings" "github.com/hashicorp/go-getter" - "github.com/pkg/errors" ) // DoUpgrade will be called after the log message has been parsed and the process has terminated. // We can now make any changes to the underlying directory without interference and leave it // in a state, so we can make a proper restart func DoUpgrade(cfg *Config, info *UpgradeInfo) error { - err := EnsureBinary(cfg.UpgradeBin(info.Name)) - // Simplest case is to switch the link + err := EnsureBinary(cfg.UpgradeBin(info.Name)) if err == nil { // we have the binary - do it return cfg.SetCurrentUpgrade(info.Name) } - // if auto-download is disabled, we fail if !cfg.AllowDownloadBinaries { - return errors.Wrap(err, "binary not present, downloading disabled") + return fmt.Errorf("binary not present, downloading disabled: %w", err) } + // if the dir is there already, don't download either - _, err = os.Stat(cfg.UpgradeDir(info.Name)) - if !os.IsNotExist(err) { - return errors.Errorf("upgrade dir already exists, won't overwrite") + if _, err := os.Stat(cfg.UpgradeDir(info.Name)); !os.IsNotExist(err) { + return errors.New("upgrade dir already exists, won't overwrite") } // If not there, then we try to download it... maybe if err := DownloadBinary(cfg, info); err != nil { - return errors.Wrap(err, "cannot download binary") + return fmt.Errorf("cannot download binary: %w", err) } // and then set the binary again - err = EnsureBinary(cfg.UpgradeBin(info.Name)) - if err != nil { - return errors.Wrap(err, "downloaded binary doesn't check out") + if err := EnsureBinary(cfg.UpgradeBin(info.Name)); err != nil { + return fmt.Errorf("downloaded binary doesn't check out: %w", err) } + return cfg.SetCurrentUpgrade(info.Name) } @@ -77,7 +75,7 @@ func DownloadBinary(cfg *Config, info *UpgradeInfo) error { func MarkExecutable(path string) error { info, err := os.Stat(path) if err != nil { - return errors.Wrap(err, "stating binary") + return fmt.Errorf("stating binary: %w", err) } // end early if world exec already set if info.Mode()&0001 == 1 { @@ -100,17 +98,18 @@ func GetDownloadURL(info *UpgradeInfo) (string, error) { if _, err := url.Parse(doc); err == nil { tmpDir, err := ioutil.TempDir("", "upgrade-manager-reference") if err != nil { - return "", errors.Wrap(err, "create tempdir for reference file") + return "", fmt.Errorf("create tempdir for reference file: %w", err) } defer os.RemoveAll(tmpDir) + refPath := filepath.Join(tmpDir, "ref") - err = getter.GetFile(refPath, doc) - if err != nil { - return "", errors.Wrapf(err, "downloading reference link %s", doc) + if err := getter.GetFile(refPath, doc); err != nil { + return "", fmt.Errorf("downloading reference link %s: %w", doc, err) } + refBytes, err := ioutil.ReadFile(refPath) if err != nil { - return "", errors.Wrap(err, "reading downloaded reference") + return "", fmt.Errorf("reading downloaded reference: %w", err) } // if download worked properly, then we use this new file as the binary map to parse doc = string(refBytes) @@ -118,12 +117,13 @@ func GetDownloadURL(info *UpgradeInfo) (string, error) { // check if it is the upgrade config var config UpgradeConfig - err := json.Unmarshal([]byte(doc), &config) - if err == nil { + + if err := json.Unmarshal([]byte(doc), &config); err == nil { url, ok := config.Binaries[osArch()] if !ok { - return "", errors.Errorf("cannot find binary for os/arch: %s", osArch()) + return "", fmt.Errorf("cannot find binary for os/arch: %s", osArch()) } + return url, nil } @@ -138,6 +138,7 @@ func osArch() string { func (cfg *Config) SetCurrentUpgrade(upgradeName string) error { // ensure named upgrade exists bin := cfg.UpgradeBin(upgradeName) + if err := EnsureBinary(bin); err != nil { return err } @@ -154,8 +155,9 @@ func (cfg *Config) SetCurrentUpgrade(upgradeName string) error { // point to the new directory if err := os.Symlink(upgrade, link); err != nil { - return errors.Wrap(err, "creating current symlink") + return fmt.Errorf("creating current symlink: %w", err) } + return nil } @@ -163,15 +165,18 @@ func (cfg *Config) SetCurrentUpgrade(upgradeName string) error { func EnsureBinary(path string) error { info, err := os.Stat(path) if err != nil { - return errors.Wrap(err, "cannot stat home dir") + return fmt.Errorf("cannot stat dir %s: %w", path, err) } + if !info.Mode().IsRegular() { - return errors.Errorf("%s is not a regular file", info.Name()) + return fmt.Errorf("%s is not a regular file", info.Name()) } + // this checks if the world-executable bit is set (we cannot check owner easily) exec := info.Mode().Perm() & 0001 if exec == 0 { - return errors.Errorf("%s is not world executable", info.Name()) + return fmt.Errorf("%s is not world executable", info.Name()) } + return nil } diff --git a/cosmovisor/upgrade_test.go b/cosmovisor/upgrade_test.go index cf84b6f6621a..c954f270f8ff 100644 --- a/cosmovisor/upgrade_test.go +++ b/cosmovisor/upgrade_test.go @@ -12,7 +12,6 @@ import ( copy2 "github.com/otiai10/copy" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -270,7 +269,7 @@ func TestDownloadBinary(t *testing.T) { func copyTestData(subdir string) (string, error) { tmpdir, err := ioutil.TempDir("", "upgrade-manager-test") if err != nil { - return "", errors.Wrap(err, "create temp dir") + return "", fmt.Errorf("couldn't create temporary directory: %w", err) } src := filepath.Join("testdata", subdir) @@ -278,7 +277,8 @@ func copyTestData(subdir string) (string, error) { err = copy2.Copy(src, tmpdir) if err != nil { os.RemoveAll(tmpdir) - return "", errors.Wrap(err, "copying files") + return "", fmt.Errorf("couldn't copy files: %w", err) } + return tmpdir, nil } diff --git a/proto/cosmos/base/abci/v1beta1/abci.proto b/proto/cosmos/base/abci/v1beta1/abci.proto index 98345987f643..78ec72594608 100644 --- a/proto/cosmos/base/abci/v1beta1/abci.proto +++ b/proto/cosmos/base/abci/v1beta1/abci.proto @@ -114,3 +114,30 @@ message TxMsgData { repeated MsgData data = 1; } + +// SearchTxsResult defines a structure for querying txs pageable +message SearchTxsResult { + option (gogoproto.stringer) = true; + + // Count of all txs + uint64 total_count = 1 [ + (gogoproto.moretags) = "yaml:\"total_count\"", + (gogoproto.jsontag) = "total_count" + ]; + // Count of txs in current page + uint64 count = 2; + // Index of current page, start from 1 + uint64 page_number = 3 [ + (gogoproto.moretags) = "yaml:\"page_number\"", + (gogoproto.jsontag) = "page_number" + ]; + // Count of total pages + uint64 page_total = 4 [ + (gogoproto.moretags) = "yaml:\"page_total\"", + (gogoproto.jsontag) = "page_total" + ]; + // Max count txs per page + uint64 limit = 5; + // List of txs in current page + repeated TxResponse txs = 6; +} diff --git a/std/codec.go b/std/codec.go index 4563e955b09c..22a5db408d60 100644 --- a/std/codec.go +++ b/std/codec.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + txtypes "github.com/cosmos/cosmos-sdk/types/tx" vesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" ) @@ -17,5 +18,6 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces registers Interfaces from sdk/types and vesting func RegisterInterfaces(interfaceRegistry types.InterfaceRegistry) { sdk.RegisterInterfaces(interfaceRegistry) + txtypes.RegisterInterfaces(interfaceRegistry) vesting.RegisterInterfaces(interfaceRegistry) } diff --git a/types/abci.pb.go b/types/abci.pb.go index 1b130f5cceb1..b410a36f80b1 100644 --- a/types/abci.pb.go +++ b/types/abci.pb.go @@ -498,6 +498,96 @@ func (m *TxMsgData) GetData() []*MsgData { return nil } +// SearchTxsResult defines a structure for querying txs pageable +type SearchTxsResult struct { + // Count of all txs + TotalCount uint64 `protobuf:"varint,1,opt,name=total_count,json=totalCount,proto3" json:"total_count" yaml:"total_count"` + // Count of txs in current page + Count uint64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"` + // Index of current page, start from 1 + PageNumber uint64 `protobuf:"varint,3,opt,name=page_number,json=pageNumber,proto3" json:"page_number" yaml:"page_number"` + // Count of total pages + PageTotal uint64 `protobuf:"varint,4,opt,name=page_total,json=pageTotal,proto3" json:"page_total" yaml:"page_total",json:"page_total"` + // Max count txs per page + Limit uint64 `protobuf:"varint,5,opt,name=limit,proto3" json:"limit,omitempty"` + // List of txs in current page + Txs []*TxResponse `protobuf:"bytes,6,rep,name=txs,proto3" json:"txs,omitempty"` +} + +func (m *SearchTxsResult) Reset() { *m = SearchTxsResult{} } +func (*SearchTxsResult) ProtoMessage() {} +func (*SearchTxsResult) Descriptor() ([]byte, []int) { + return fileDescriptor_4e37629bc7eb0df8, []int{9} +} +func (m *SearchTxsResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SearchTxsResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SearchTxsResult.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SearchTxsResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_SearchTxsResult.Merge(m, src) +} +func (m *SearchTxsResult) XXX_Size() int { + return m.Size() +} +func (m *SearchTxsResult) XXX_DiscardUnknown() { + xxx_messageInfo_SearchTxsResult.DiscardUnknown(m) +} + +var xxx_messageInfo_SearchTxsResult proto.InternalMessageInfo + +func (m *SearchTxsResult) GetTotalCount() uint64 { + if m != nil { + return m.TotalCount + } + return 0 +} + +func (m *SearchTxsResult) GetCount() uint64 { + if m != nil { + return m.Count + } + return 0 +} + +func (m *SearchTxsResult) GetPageNumber() uint64 { + if m != nil { + return m.PageNumber + } + return 0 +} + +func (m *SearchTxsResult) GetPageTotal() uint64 { + if m != nil { + return m.PageTotal + } + return 0 +} + +func (m *SearchTxsResult) GetLimit() uint64 { + if m != nil { + return m.Limit + } + return 0 +} + +func (m *SearchTxsResult) GetTxs() []*TxResponse { + if m != nil { + return m.Txs + } + return nil +} + func init() { proto.RegisterType((*TxResponse)(nil), "cosmos.base.abci.v1beta1.TxResponse") proto.RegisterType((*ABCIMessageLog)(nil), "cosmos.base.abci.v1beta1.ABCIMessageLog") @@ -508,6 +598,7 @@ func init() { proto.RegisterType((*SimulationResponse)(nil), "cosmos.base.abci.v1beta1.SimulationResponse") proto.RegisterType((*MsgData)(nil), "cosmos.base.abci.v1beta1.MsgData") proto.RegisterType((*TxMsgData)(nil), "cosmos.base.abci.v1beta1.TxMsgData") + proto.RegisterType((*SearchTxsResult)(nil), "cosmos.base.abci.v1beta1.SearchTxsResult") } func init() { @@ -515,57 +606,66 @@ func init() { } var fileDescriptor_4e37629bc7eb0df8 = []byte{ - // 786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x4b, 0x6f, 0xdb, 0x46, - 0x10, 0x16, 0x25, 0x99, 0x12, 0x47, 0x76, 0xdd, 0x6e, 0x55, 0x9b, 0xb6, 0x5b, 0x49, 0xa5, 0x5b, - 0x40, 0x97, 0x52, 0xf0, 0xa3, 0x40, 0xe1, 0x43, 0x51, 0xb3, 0x2f, 0x0b, 0xb0, 0x2f, 0xb4, 0x8c, - 0x00, 0xb9, 0x08, 0x2b, 0x71, 0xbd, 0x62, 0x2c, 0x72, 0x05, 0xee, 0xca, 0x96, 0x6e, 0x39, 0xe6, - 0x98, 0x93, 0x0f, 0x39, 0xe5, 0x9c, 0x5f, 0xe2, 0xa3, 0x8f, 0x3e, 0x04, 0x4a, 0x22, 0xff, 0x03, - 0xff, 0x82, 0x60, 0x97, 0xd4, 0xc3, 0x09, 0xe4, 0x13, 0xe7, 0xf1, 0xed, 0xec, 0xcc, 0xf7, 0xcd, - 0x12, 0xb6, 0xdb, 0x8c, 0x07, 0x8c, 0xd7, 0x5a, 0x98, 0x93, 0x1a, 0x6e, 0xb5, 0xfd, 0xda, 0xe5, - 0x4e, 0x8b, 0x08, 0xbc, 0xa3, 0x1c, 0xbb, 0x17, 0x31, 0xc1, 0x90, 0x19, 0x83, 0x6c, 0x09, 0xb2, - 0x55, 0x3c, 0x01, 0x6d, 0x16, 0x29, 0xa3, 0x4c, 0x81, 0x6a, 0xd2, 0x8a, 0xf1, 0x9b, 0x5b, 0x82, - 0x84, 0x1e, 0x89, 0x02, 0x3f, 0x14, 0x71, 0x4d, 0x31, 0xec, 0x11, 0x9e, 0x24, 0x37, 0x28, 0x63, - 0xb4, 0x4b, 0x6a, 0xca, 0x6b, 0xf5, 0xcf, 0x6b, 0x38, 0x1c, 0xc6, 0x29, 0xeb, 0x3a, 0x03, 0xd0, - 0x18, 0xb8, 0x84, 0xf7, 0x58, 0xc8, 0x09, 0x5a, 0x03, 0xbd, 0x43, 0x7c, 0xda, 0x11, 0xa6, 0x56, - 0xd1, 0xaa, 0x19, 0x37, 0xf1, 0x90, 0x05, 0xba, 0x18, 0x74, 0x30, 0xef, 0x98, 0xe9, 0x8a, 0x56, - 0x35, 0x1c, 0x18, 0x8f, 0xca, 0x7a, 0x63, 0x70, 0x84, 0x79, 0xc7, 0x4d, 0x32, 0xe8, 0x47, 0x30, - 0xda, 0xcc, 0x23, 0xbc, 0x87, 0xdb, 0xc4, 0xcc, 0x48, 0x98, 0x3b, 0x0b, 0x20, 0x04, 0x59, 0xe9, - 0x98, 0xd9, 0x8a, 0x56, 0x5d, 0x71, 0x95, 0x2d, 0x63, 0x1e, 0x16, 0xd8, 0x5c, 0x52, 0x60, 0x65, - 0xa3, 0x75, 0xc8, 0x45, 0xf8, 0xaa, 0xd9, 0x65, 0xd4, 0xd4, 0x55, 0x58, 0x8f, 0xf0, 0xd5, 0x31, - 0xa3, 0xe8, 0x0c, 0xb2, 0x5d, 0x46, 0xb9, 0x99, 0xab, 0x64, 0xaa, 0x85, 0xdd, 0xaa, 0xbd, 0x88, - 0x20, 0xfb, 0xd0, 0xf9, 0xbb, 0x7e, 0x42, 0x38, 0xc7, 0x94, 0x1c, 0x33, 0xea, 0xac, 0xdf, 0x8c, - 0xca, 0xa9, 0x77, 0x1f, 0xca, 0xab, 0x8f, 0xe3, 0xdc, 0x55, 0xe5, 0x64, 0x0f, 0x7e, 0x78, 0xce, - 0xcc, 0x7c, 0xdc, 0x83, 0xb4, 0xd1, 0x4f, 0x00, 0x14, 0xf3, 0xe6, 0x15, 0x0e, 0x05, 0xf1, 0x4c, - 0x43, 0x31, 0x61, 0x50, 0xcc, 0x9f, 0xa9, 0x00, 0xda, 0x80, 0xbc, 0x4c, 0xf7, 0x39, 0xf1, 0x4c, - 0x50, 0xc9, 0x1c, 0xc5, 0xfc, 0x8c, 0x13, 0x0f, 0xfd, 0x02, 0x69, 0x31, 0x30, 0x0b, 0x15, 0xad, - 0x5a, 0xd8, 0x2d, 0xda, 0x31, 0xed, 0xf6, 0x84, 0x76, 0xfb, 0x30, 0x1c, 0xba, 0x69, 0x31, 0x90, - 0x4c, 0x09, 0x3f, 0x20, 0x5c, 0xe0, 0xa0, 0x67, 0x2e, 0xc7, 0x4c, 0x4d, 0x03, 0x07, 0xd9, 0x57, - 0x6f, 0xcb, 0x29, 0xeb, 0x8d, 0x06, 0xdf, 0x3c, 0xee, 0x18, 0x6d, 0x81, 0x11, 0x70, 0xda, 0xf4, - 0x43, 0x8f, 0x0c, 0x94, 0x3e, 0x2b, 0x6e, 0x3e, 0xe0, 0xb4, 0x2e, 0x7d, 0xf4, 0x2d, 0x64, 0x24, - 0x67, 0x4a, 0x1e, 0x57, 0x9a, 0xe8, 0x14, 0x74, 0x72, 0x49, 0x42, 0xc1, 0xcd, 0x8c, 0xa2, 0xec, - 0xd7, 0xc5, 0x94, 0x9d, 0x8a, 0xc8, 0x0f, 0xe9, 0xbf, 0x12, 0xed, 0x14, 0x13, 0xbe, 0x96, 0xe7, - 0x82, 0xdc, 0x4d, 0x4a, 0x1d, 0x64, 0x5f, 0xbe, 0xaf, 0x68, 0x56, 0x04, 0x85, 0xb9, 0xac, 0xe4, - 0x50, 0xae, 0x9b, 0xea, 0xc9, 0x70, 0x95, 0x8d, 0xea, 0x00, 0x58, 0x88, 0xc8, 0x6f, 0xf5, 0x05, - 0xe1, 0x66, 0x5a, 0x75, 0xb0, 0xfd, 0x84, 0x68, 0x13, 0xac, 0x93, 0x95, 0xf7, 0xbb, 0x73, 0x87, - 0x93, 0x3b, 0xf7, 0xc0, 0x98, 0x82, 0xe4, 0xb4, 0x17, 0x64, 0x98, 0x5c, 0x28, 0x4d, 0x54, 0x84, - 0xa5, 0x4b, 0xdc, 0xed, 0x93, 0x84, 0x81, 0xd8, 0xb1, 0x18, 0xe4, 0xfe, 0xc7, 0xbc, 0x2e, 0x45, - 0xdd, 0x7f, 0x24, 0xaa, 0x3c, 0x99, 0x75, 0x7e, 0x78, 0x18, 0x95, 0xbf, 0x1b, 0xe2, 0xa0, 0x7b, - 0x60, 0xcd, 0x72, 0xd6, 0xbc, 0xd6, 0xf6, 0x9c, 0xd6, 0x69, 0x75, 0xe6, 0xfb, 0x87, 0x51, 0x79, - 0x75, 0x76, 0x46, 0x66, 0xac, 0xe9, 0x02, 0x58, 0x2f, 0x40, 0x77, 0x09, 0xef, 0x77, 0xc5, 0x74, - 0xb9, 0xe5, 0x4d, 0xcb, 0xc9, 0x72, 0x7f, 0x2d, 0xd2, 0xfe, 0x17, 0x22, 0xad, 0xd9, 0xb3, 0x87, - 0x1c, 0x33, 0x14, 0xab, 0x12, 0xb3, 0x32, 0x55, 0x41, 0xad, 0xc8, 0xb5, 0x06, 0xe8, 0xd4, 0x0f, - 0xfa, 0x5d, 0x2c, 0x7c, 0x16, 0x4e, 0xdf, 0xf0, 0x7f, 0x71, 0xcb, 0x6a, 0xab, 0x35, 0xb5, 0x89, - 0x3f, 0x2f, 0xe6, 0x3d, 0x61, 0xc7, 0xc9, 0xcb, 0xfa, 0xb7, 0xa3, 0xb2, 0xa6, 0x46, 0x51, 0x84, - 0xfd, 0x01, 0x7a, 0xa4, 0x46, 0x51, 0xfd, 0x16, 0x76, 0x2b, 0x8b, 0xab, 0xc4, 0x23, 0xbb, 0x09, - 0xde, 0xfa, 0x13, 0x72, 0x27, 0x9c, 0xfe, 0x23, 0x27, 0xde, 0x00, 0xb9, 0xa2, 0xcd, 0xb9, 0xf5, - 0xc8, 0x05, 0x9c, 0x36, 0xe4, 0x86, 0x4c, 0x08, 0x4a, 0xcf, 0x08, 0x4a, 0xa4, 0x3e, 0x02, 0xa3, - 0x31, 0x98, 0x54, 0xf8, 0x7d, 0xca, 0x63, 0xe6, 0xe9, 0x51, 0x92, 0x03, 0xf3, 0x95, 0x9c, 0xbf, - 0xee, 0x3e, 0x95, 0x52, 0x37, 0xe3, 0x92, 0x76, 0x3b, 0x2e, 0x69, 0x1f, 0xc7, 0x25, 0xed, 0xf5, - 0x7d, 0x29, 0x75, 0x7b, 0x5f, 0x4a, 0xdd, 0xdd, 0x97, 0x52, 0xcf, 0x2d, 0xea, 0x8b, 0x4e, 0xbf, - 0x65, 0xb7, 0x59, 0x50, 0x4b, 0x7e, 0xca, 0xf1, 0xe7, 0x37, 0xee, 0x5d, 0xc4, 0x7f, 0xd0, 0x96, - 0xae, 0x5e, 0xef, 0xde, 0xe7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x2c, 0x53, 0x4a, 0xb6, 0x05, - 0x00, 0x00, + // 932 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0x31, 0x73, 0x1b, 0x45, + 0x14, 0xd6, 0x49, 0xca, 0xc9, 0x7a, 0x72, 0x30, 0x2c, 0x26, 0x39, 0x27, 0xa0, 0x13, 0xe7, 0x64, + 0x46, 0x05, 0x9c, 0x26, 0x4e, 0xc2, 0x30, 0x2e, 0x18, 0xa2, 0x40, 0x88, 0x67, 0x12, 0x8a, 0xb5, + 0x32, 0xcc, 0xd0, 0x68, 0x56, 0xd2, 0x66, 0x75, 0x89, 0xee, 0x56, 0x73, 0xbb, 0xb2, 0xe5, 0x8e, + 0x92, 0x92, 0x2a, 0x05, 0x15, 0x35, 0xbf, 0x24, 0xa5, 0xcb, 0x14, 0xcc, 0x41, 0xec, 0x2e, 0xa5, + 0x7f, 0x01, 0xb3, 0x6f, 0xcf, 0xd2, 0x09, 0x46, 0xa9, 0xb4, 0xdf, 0xf7, 0xde, 0xbe, 0x7d, 0xfb, + 0x7d, 0x4f, 0x7b, 0xb0, 0x3b, 0x94, 0x2a, 0x96, 0xaa, 0x33, 0x60, 0x8a, 0x77, 0xd8, 0x60, 0x18, + 0x75, 0x8e, 0xee, 0x0c, 0xb8, 0x66, 0x77, 0x10, 0x84, 0xd3, 0x54, 0x6a, 0x49, 0x3c, 0x9b, 0x14, + 0x9a, 0xa4, 0x10, 0xf9, 0x3c, 0xe9, 0xc6, 0xb6, 0x90, 0x42, 0x62, 0x52, 0xc7, 0xac, 0x6c, 0xfe, + 0x8d, 0x9b, 0x9a, 0x27, 0x23, 0x9e, 0xc6, 0x51, 0xa2, 0x6d, 0x4d, 0x7d, 0x32, 0xe5, 0x2a, 0x0f, + 0xee, 0x08, 0x29, 0xc5, 0x84, 0x77, 0x10, 0x0d, 0x66, 0xcf, 0x3b, 0x2c, 0x39, 0xb1, 0xa1, 0xe0, + 0x55, 0x05, 0xa0, 0x37, 0xa7, 0x5c, 0x4d, 0x65, 0xa2, 0x38, 0xb9, 0x06, 0xee, 0x98, 0x47, 0x62, + 0xac, 0x3d, 0xa7, 0xe5, 0xb4, 0x2b, 0x34, 0x47, 0x24, 0x00, 0x57, 0xcf, 0xc7, 0x4c, 0x8d, 0xbd, + 0x72, 0xcb, 0x69, 0xd7, 0xbb, 0x70, 0x96, 0xf9, 0x6e, 0x6f, 0xfe, 0x98, 0xa9, 0x31, 0xcd, 0x23, + 0xe4, 0x53, 0xa8, 0x0f, 0xe5, 0x88, 0xab, 0x29, 0x1b, 0x72, 0xaf, 0x62, 0xd2, 0xe8, 0x92, 0x20, + 0x04, 0xaa, 0x06, 0x78, 0xd5, 0x96, 0xd3, 0xbe, 0x4a, 0x71, 0x6d, 0xb8, 0x11, 0xd3, 0xcc, 0xbb, + 0x82, 0xc9, 0xb8, 0x26, 0xd7, 0xa1, 0x96, 0xb2, 0xe3, 0xfe, 0x44, 0x0a, 0xcf, 0x45, 0xda, 0x4d, + 0xd9, 0xf1, 0x13, 0x29, 0xc8, 0x33, 0xa8, 0x4e, 0xa4, 0x50, 0x5e, 0xad, 0x55, 0x69, 0x37, 0xf6, + 0xda, 0xe1, 0x3a, 0x81, 0xc2, 0x07, 0xdd, 0x87, 0x07, 0x4f, 0xb9, 0x52, 0x4c, 0xf0, 0x27, 0x52, + 0x74, 0xaf, 0xbf, 0xce, 0xfc, 0xd2, 0x9f, 0x7f, 0xfb, 0x5b, 0xab, 0xbc, 0xa2, 0x58, 0xce, 0xf4, + 0x10, 0x25, 0xcf, 0xa5, 0xb7, 0x61, 0x7b, 0x30, 0x6b, 0xf2, 0x19, 0x80, 0x60, 0xaa, 0x7f, 0xcc, + 0x12, 0xcd, 0x47, 0x5e, 0x1d, 0x95, 0xa8, 0x0b, 0xa6, 0x7e, 0x42, 0x82, 0xec, 0xc0, 0x86, 0x09, + 0xcf, 0x14, 0x1f, 0x79, 0x80, 0xc1, 0x9a, 0x60, 0xea, 0x99, 0xe2, 0x23, 0x72, 0x0b, 0xca, 0x7a, + 0xee, 0x35, 0x5a, 0x4e, 0xbb, 0xb1, 0xb7, 0x1d, 0x5a, 0xd9, 0xc3, 0x4b, 0xd9, 0xc3, 0x07, 0xc9, + 0x09, 0x2d, 0xeb, 0xb9, 0x51, 0x4a, 0x47, 0x31, 0x57, 0x9a, 0xc5, 0x53, 0x6f, 0xd3, 0x2a, 0xb5, + 0x20, 0xf6, 0xab, 0xbf, 0xfe, 0xe1, 0x97, 0x82, 0xdf, 0x1d, 0xf8, 0x60, 0xb5, 0x63, 0x72, 0x13, + 0xea, 0xb1, 0x12, 0xfd, 0x28, 0x19, 0xf1, 0x39, 0xfa, 0x73, 0x95, 0x6e, 0xc4, 0x4a, 0x1c, 0x18, + 0x4c, 0x3e, 0x84, 0x8a, 0xd1, 0x0c, 0xed, 0xa1, 0x66, 0x49, 0x0e, 0xc1, 0xe5, 0x47, 0x3c, 0xd1, + 0xca, 0xab, 0xa0, 0x64, 0xb7, 0xd7, 0x4b, 0x76, 0xa8, 0xd3, 0x28, 0x11, 0xdf, 0x9b, 0xec, 0xee, + 0x76, 0xae, 0xd7, 0x66, 0x81, 0x54, 0x34, 0x2f, 0xb5, 0x5f, 0xfd, 0xe5, 0xaf, 0x96, 0x13, 0xa4, + 0xd0, 0x28, 0x44, 0x8d, 0x86, 0x66, 0xdc, 0xb0, 0xa7, 0x3a, 0xc5, 0x35, 0x39, 0x00, 0x60, 0x5a, + 0xa7, 0xd1, 0x60, 0xa6, 0xb9, 0xf2, 0xca, 0xd8, 0xc1, 0xee, 0x7b, 0x4c, 0xbb, 0xcc, 0xed, 0x56, + 0xcd, 0xf9, 0xb4, 0xb0, 0x39, 0x3f, 0xf3, 0x2e, 0xd4, 0x17, 0x49, 0xe6, 0xb6, 0x2f, 0xf9, 0x49, + 0x7e, 0xa0, 0x59, 0x92, 0x6d, 0xb8, 0x72, 0xc4, 0x26, 0x33, 0x9e, 0x2b, 0x60, 0x41, 0x20, 0xa1, + 0xf6, 0x03, 0x53, 0x07, 0xc6, 0xd4, 0x7b, 0x2b, 0xa6, 0x9a, 0x9d, 0xd5, 0xee, 0x27, 0x17, 0x99, + 0xff, 0xd1, 0x09, 0x8b, 0x27, 0xfb, 0xc1, 0x32, 0x16, 0x14, 0xbd, 0x0e, 0x0b, 0x5e, 0x97, 0x71, + 0xcf, 0xc7, 0x17, 0x99, 0xbf, 0xb5, 0xdc, 0x63, 0x22, 0xc1, 0x62, 0x00, 0x82, 0x17, 0xe0, 0x52, + 0xae, 0x66, 0x13, 0xbd, 0x18, 0x6e, 0x73, 0xd2, 0x66, 0x3e, 0xdc, 0xff, 0x37, 0xe9, 0xde, 0x7f, + 0x4c, 0xba, 0x16, 0x2e, 0xff, 0xc8, 0x56, 0x21, 0xeb, 0x8a, 0x55, 0x65, 0xe1, 0x02, 0x8e, 0xc8, + 0x2b, 0x07, 0xc8, 0x61, 0x14, 0xcf, 0x26, 0x4c, 0x47, 0x32, 0x59, 0xfc, 0x87, 0x1f, 0xd9, 0x96, + 0x71, 0xaa, 0x1d, 0x9c, 0xc4, 0xcf, 0xd7, 0xeb, 0x9e, 0xab, 0xd3, 0xdd, 0x30, 0xf5, 0x4f, 0x33, + 0xdf, 0xc1, 0xab, 0xa0, 0x60, 0x5f, 0x83, 0x9b, 0xe2, 0x55, 0xb0, 0xdf, 0xc6, 0x5e, 0x6b, 0x7d, + 0x15, 0x7b, 0x65, 0x9a, 0xe7, 0x07, 0xdf, 0x40, 0xed, 0xa9, 0x12, 0xdf, 0x99, 0x1b, 0xef, 0x80, + 0x19, 0xd1, 0x7e, 0x61, 0x3c, 0x6a, 0xb1, 0x12, 0x3d, 0x33, 0x21, 0x97, 0x02, 0x95, 0x97, 0x02, + 0xe5, 0x56, 0x3f, 0x86, 0x7a, 0x6f, 0x7e, 0x59, 0xe1, 0xfe, 0x42, 0xc7, 0xca, 0xfb, 0xaf, 0x92, + 0x6f, 0x58, 0xa9, 0xf4, 0xb6, 0x0c, 0x5b, 0x87, 0x9c, 0xa5, 0xc3, 0x71, 0x6f, 0xae, 0x72, 0x63, + 0x1e, 0x41, 0x43, 0x4b, 0xcd, 0x26, 0xfd, 0xa1, 0x9c, 0x25, 0x3a, 0x9f, 0x84, 0xdb, 0xef, 0x32, + 0xbf, 0x48, 0x5f, 0x64, 0x3e, 0xb1, 0x26, 0x17, 0xc8, 0x80, 0x02, 0xa2, 0x87, 0x06, 0x98, 0x89, + 0xb3, 0x15, 0x70, 0x2e, 0xa8, 0x05, 0xa6, 0xfa, 0x94, 0x09, 0xde, 0x4f, 0x66, 0xf1, 0x80, 0xa7, + 0xf8, 0x0e, 0xe6, 0xd5, 0x0b, 0xf4, 0xb2, 0x7a, 0x81, 0x0c, 0x28, 0x18, 0xf4, 0x23, 0x02, 0xd2, + 0x03, 0x44, 0x7d, 0x3c, 0x10, 0x5f, 0xcd, 0x6a, 0xf7, 0xfe, 0xbb, 0xcc, 0x2f, 0xb0, 0x17, 0x99, + 0xbf, 0x5b, 0xa8, 0x82, 0x5c, 0xf0, 0xc5, 0x0b, 0x25, 0x93, 0x15, 0x86, 0xd6, 0x0d, 0xe8, 0x99, + 0xb5, 0xe9, 0x79, 0x12, 0xc5, 0x91, 0xc6, 0x27, 0xb7, 0x4a, 0x2d, 0x20, 0x5f, 0x41, 0x45, 0xcf, + 0x95, 0xe7, 0xa2, 0xc2, 0xb7, 0xd6, 0x2b, 0xbc, 0xfc, 0x50, 0x50, 0xb3, 0xc1, 0x6a, 0xdc, 0xfd, + 0xf6, 0xcd, 0xdb, 0x66, 0xe9, 0xf5, 0x59, 0xd3, 0x39, 0x3d, 0x6b, 0x3a, 0xff, 0x9c, 0x35, 0x9d, + 0xdf, 0xce, 0x9b, 0xa5, 0xd3, 0xf3, 0x66, 0xe9, 0xcd, 0x79, 0xb3, 0xf4, 0x73, 0x20, 0x22, 0x3d, + 0x9e, 0x0d, 0xc2, 0xa1, 0x8c, 0x3b, 0xf9, 0x87, 0xcf, 0xfe, 0x7c, 0xa9, 0x46, 0x2f, 0xed, 0x57, + 0x6a, 0xe0, 0xe2, 0x0b, 0x79, 0xf7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7c, 0x3e, 0xa1, 0x0e, + 0x1a, 0x07, 0x00, 0x00, } func (m *TxResponse) Marshal() (dAtA []byte, err error) { @@ -1012,6 +1112,68 @@ func (m *TxMsgData) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SearchTxsResult) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SearchTxsResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SearchTxsResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Txs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAbci(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if m.Limit != 0 { + i = encodeVarintAbci(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x28 + } + if m.PageTotal != 0 { + i = encodeVarintAbci(dAtA, i, uint64(m.PageTotal)) + i-- + dAtA[i] = 0x20 + } + if m.PageNumber != 0 { + i = encodeVarintAbci(dAtA, i, uint64(m.PageNumber)) + i-- + dAtA[i] = 0x18 + } + if m.Count != 0 { + i = encodeVarintAbci(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x10 + } + if m.TotalCount != 0 { + i = encodeVarintAbci(dAtA, i, uint64(m.TotalCount)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintAbci(dAtA []byte, offset int, v uint64) int { offset -= sovAbci(v) base := offset @@ -1221,6 +1383,36 @@ func (m *TxMsgData) Size() (n int) { return n } +func (m *SearchTxsResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TotalCount != 0 { + n += 1 + sovAbci(uint64(m.TotalCount)) + } + if m.Count != 0 { + n += 1 + sovAbci(uint64(m.Count)) + } + if m.PageNumber != 0 { + n += 1 + sovAbci(uint64(m.PageNumber)) + } + if m.PageTotal != 0 { + n += 1 + sovAbci(uint64(m.PageTotal)) + } + if m.Limit != 0 { + n += 1 + sovAbci(uint64(m.Limit)) + } + if len(m.Txs) > 0 { + for _, e := range m.Txs { + l = e.Size() + n += 1 + l + sovAbci(uint64(l)) + } + } + return n +} + func sovAbci(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1286,6 +1478,26 @@ func (this *TxMsgData) String() string { }, "") return s } +func (this *SearchTxsResult) String() string { + if this == nil { + return "nil" + } + repeatedStringForTxs := "[]*TxResponse{" + for _, f := range this.Txs { + repeatedStringForTxs += strings.Replace(fmt.Sprintf("%v", f), "TxResponse", "TxResponse", 1) + "," + } + repeatedStringForTxs += "}" + s := strings.Join([]string{`&SearchTxsResult{`, + `TotalCount:` + fmt.Sprintf("%v", this.TotalCount) + `,`, + `Count:` + fmt.Sprintf("%v", this.Count) + `,`, + `PageNumber:` + fmt.Sprintf("%v", this.PageNumber) + `,`, + `PageTotal:` + fmt.Sprintf("%v", this.PageTotal) + `,`, + `Limit:` + fmt.Sprintf("%v", this.Limit) + `,`, + `Txs:` + repeatedStringForTxs + `,`, + `}`, + }, "") + return s +} func valueToStringAbci(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -2631,6 +2843,188 @@ func (m *TxMsgData) Unmarshal(dAtA []byte) error { } return nil } +func (m *SearchTxsResult) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SearchTxsResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SearchTxsResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalCount", wireType) + } + m.TotalCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalCount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Count |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PageNumber", wireType) + } + m.PageNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PageNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PageTotal", wireType) + } + m.PageTotal = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PageTotal |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAbci + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAbci + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAbci + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Txs = append(m.Txs, &TxResponse{}) + if err := m.Txs[len(m.Txs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAbci(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAbci + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthAbci + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipAbci(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/types/codec.go b/types/codec.go index c654508b4c49..2735c2f02100 100644 --- a/types/codec.go +++ b/types/codec.go @@ -1,9 +1,8 @@ package types import ( - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" ) // RegisterLegacyAminoCodec registers the sdk message type. diff --git a/types/result.go b/types/result.go index 56d4482dcd9d..02467e0a309e 100644 --- a/types/result.go +++ b/types/result.go @@ -12,7 +12,7 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" ) var cdc = codec.NewLegacyAmino() @@ -60,7 +60,7 @@ func (logs ABCIMessageLogs) String() (str string) { } // NewResponseResultTx returns a TxResponse given a ResultTx from tendermint -func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) *TxResponse { +func NewResponseResultTx(res *ctypes.ResultTx, anyTx *codectypes.Any, timestamp string) *TxResponse { if res == nil { return nil } @@ -78,7 +78,7 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) *TxRespo Info: res.TxResult.Info, GasWanted: res.TxResult.GasWanted, GasUsed: res.TxResult.GasUsed, - Tx: types.UnsafePackAny(tx), + Tx: anyTx, Timestamp: timestamp, } } @@ -213,22 +213,12 @@ func (r TxResponse) Empty() bool { return r.TxHash == "" && r.Logs == nil } -// SearchTxsResult defines a structure for querying txs pageable -type SearchTxsResult struct { - TotalCount int `json:"total_count"` // Count of all txs - Count int `json:"count"` // Count of txs in current page - PageNumber int `json:"page_number"` // Index of current page, start from 1 - PageTotal int `json:"page_total"` // Count of total pages - Limit int `json:"limit"` // Max count txs per page - Txs []*TxResponse `json:"txs"` // List of txs in current page -} - -func NewSearchTxsResult(totalCount, count, page, limit int, txs []*TxResponse) SearchTxsResult { - return SearchTxsResult{ +func NewSearchTxsResult(totalCount, count, page, limit uint64, txs []*TxResponse) *SearchTxsResult { + return &SearchTxsResult{ TotalCount: totalCount, Count: count, PageNumber: page, - PageTotal: int(math.Ceil(float64(totalCount) / float64(limit))), + PageTotal: uint64(math.Ceil(float64(totalCount) / float64(limit))), Limit: limit, Txs: txs, } @@ -241,15 +231,15 @@ func ParseABCILogs(logs string) (res ABCIMessageLogs, err error) { return res, err } -var _, _ types.UnpackInterfacesMessage = SearchTxsResult{}, TxResponse{} +var _, _ codectypes.UnpackInterfacesMessage = SearchTxsResult{}, TxResponse{} // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces // // types.UnpackInterfaces needs to be called for each nested Tx because // there are generally interfaces to unpack in Tx's -func (s SearchTxsResult) UnpackInterfaces(unpacker types.AnyUnpacker) error { +func (s SearchTxsResult) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { for _, tx := range s.Txs { - err := types.UnpackInterfaces(tx, unpacker) + err := codectypes.UnpackInterfaces(tx, unpacker) if err != nil { return err } @@ -258,7 +248,7 @@ func (s SearchTxsResult) UnpackInterfaces(unpacker types.AnyUnpacker) error { } // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces -func (r TxResponse) UnpackInterfaces(unpacker types.AnyUnpacker) error { +func (r TxResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { if r.Tx != nil { var tx Tx return unpacker.UnpackAny(r.Tx, &tx) diff --git a/types/result_test.go b/types/result_test.go index 3d0283a31f50..faed16c86969 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -11,7 +11,6 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -41,7 +40,7 @@ func TestABCIMessageLog(t *testing.T) { func TestNewSearchTxsResult(t *testing.T) { t.Parallel() got := sdk.NewSearchTxsResult(150, 20, 2, 20, []*sdk.TxResponse{}) - require.Equal(t, sdk.SearchTxsResult{ + require.Equal(t, &sdk.SearchTxsResult{ TotalCount: 150, Count: 20, PageNumber: 2, @@ -93,12 +92,12 @@ func TestResponseResultTx(t *testing.T) { Info: "info", GasWanted: 100, GasUsed: 90, - Tx: &types.Any{}, + Tx: nil, Timestamp: "timestamp", } - require.Equal(t, want, sdk.NewResponseResultTx(resultTx, sdk.Tx(nil), "timestamp")) - require.Equal(t, (*sdk.TxResponse)(nil), sdk.NewResponseResultTx(nil, sdk.Tx(nil), "timestamp")) + require.Equal(t, want, sdk.NewResponseResultTx(resultTx, nil, "timestamp")) + require.Equal(t, (*sdk.TxResponse)(nil), sdk.NewResponseResultTx(nil, nil, "timestamp")) require.Equal(t, `Response: Height: 10 TxHash: 74657374 @@ -110,7 +109,7 @@ func TestResponseResultTx(t *testing.T) { GasWanted: 100 GasUsed: 90 Codespace: codespace - Timestamp: timestamp`, sdk.NewResponseResultTx(resultTx, sdk.Tx(nil), "timestamp").String()) + Timestamp: timestamp`, sdk.NewResponseResultTx(resultTx, nil, "timestamp").String()) require.True(t, sdk.TxResponse{}.Empty()) require.False(t, want.Empty()) diff --git a/types/tx/types.go b/types/tx/types.go index ed56de13e4bc..437b6cedb5f7 100644 --- a/types/tx/types.go +++ b/types/tx/types.go @@ -1,16 +1,106 @@ package tx import ( + fmt "fmt" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +// MaxGasWanted defines the max gas allowed. +const MaxGasWanted = uint64((1 << 63) - 1) + var _, _ codectypes.UnpackInterfacesMessage = &Tx{}, &TxBody{} +var _ sdk.Tx = &Tx{} + +// GetMsgs implements the GetMsgs method on sdk.Tx. +func (t *Tx) GetMsgs() []sdk.Msg { + if t == nil || t.Body == nil { + return nil + } + + anys := t.Body.Messages + res := make([]sdk.Msg, len(anys)) + for i, any := range anys { + msg := any.GetCachedValue().(sdk.Msg) + res[i] = msg + } + return res +} + +// ValidateBasic implements the ValidateBasic method on sdk.Tx. +func (t *Tx) ValidateBasic() error { + if t == nil { + return fmt.Errorf("bad Tx") + } + + body := t.Body + if body == nil { + return fmt.Errorf("missing TxBody") + } + + authInfo := t.AuthInfo + if authInfo == nil { + return fmt.Errorf("missing AuthInfo") + } + + fee := authInfo.Fee + if fee == nil { + return fmt.Errorf("missing fee") + } + + if fee.GasLimit > MaxGasWanted { + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid gas supplied; %d > %d", fee.GasLimit, MaxGasWanted, + ) + } + + if fee.Amount.IsAnyNegative() { + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFee, + "invalid fee provided: %s", fee.Amount, + ) + } + + sigs := t.Signatures + + if len(sigs) == 0 { + return sdkerrors.ErrNoSignatures + } + + if len(sigs) != len(t.GetSigners()) { + return sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, + "wrong number of signers; expected %d, got %d", t.GetSigners(), len(sigs), + ) + } + + return nil +} + +// GetSigners retrieves all the signers of a tx. +func (t *Tx) GetSigners() []sdk.AccAddress { + var signers []sdk.AccAddress + seen := map[string]bool{} + + for _, msg := range t.GetMsgs() { + for _, addr := range msg.GetSigners() { + if !seen[addr.String()] { + signers = append(signers, addr) + seen[addr.String()] = true + } + } + } + + return signers +} // UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method -func (m *Tx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { - if m.Body != nil { - return m.Body.UnpackInterfaces(unpacker) +func (t *Tx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + if t.Body != nil { + return t.Body.UnpackInterfaces(unpacker) } return nil } @@ -26,3 +116,9 @@ func (m *TxBody) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { } return nil } + +// RegisterInterfaces registers the sdk.Tx interface. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterInterface("cosmos.tx.v1beta1.Tx", (*sdk.Tx)(nil)) + registry.RegisterImplementations((*sdk.Tx)(nil), &Tx{}) +} diff --git a/x/auth/client/cli/cli_test.go b/x/auth/client/cli/cli_test.go index 6b0f29c917b7..05f8f77cf303 100644 --- a/x/auth/client/cli/cli_test.go +++ b/x/auth/client/cli/cli_test.go @@ -8,8 +8,6 @@ import ( "strings" "testing" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" tmcrypto "github.com/tendermint/tendermint/crypto" @@ -18,6 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" codec2 "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" @@ -165,6 +164,46 @@ func (s *IntegrationTestSuite) TestCLISignBatch() { s.Require().Error(err) } +func (s *IntegrationTestSuite) TestCLITxQueryCmd() { + val := s.network.Validators[0] + var txHash string + + s.Run("bank send tx", func() { + clientCtx := val.ClientCtx + + bz, err := bankcli.MsgSendExec(clientCtx, val.Address, val.Address, sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), + ), []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + }...) + + var txRes sdk.TxResponse + s.Require().NoError(err) + s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), &txRes), bz.String()) + + txHash = txRes.TxHash + s.Require().Equal(uint32(0), txRes.Code) + }) + + s.network.WaitForNextBlock() + + s.Run("test QueryTxCmd", func() { + cmd := authcli.QueryTxCmd() + args := []string{ + txHash, + } + + out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) + s.Require().NoError(err) + + var tx sdk.TxResponse + s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &tx)) + }) +} + func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { val1 := s.network.Validators[0] diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 3706a3a4720f..534bce3ae22f 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -167,13 +167,7 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator return err } - output, err := clientCtx.LegacyAmino.MarshalJSON(txs) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil + return clientCtx.PrintOutput(txs) }, } diff --git a/x/auth/client/query.go b/x/auth/client/query.go index 74a75bf24933..a77f58c7b10f 100644 --- a/x/auth/client/query.go +++ b/x/auth/client/query.go @@ -3,15 +3,15 @@ package client import ( "encoding/hex" "errors" + "fmt" "strings" "time" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" ) // QueryTxsByEvents performs a search for transactions for a given set of events @@ -53,14 +53,14 @@ func QueryTxsByEvents(clientCtx client.Context, events []string, page, limit int return nil, err } - txs, err := formatTxResults(clientCtx.LegacyAmino, resTxs.Txs, resBlocks) + txs, err := formatTxResults(clientCtx.TxConfig, resTxs.Txs, resBlocks) if err != nil { return nil, err } - result := sdk.NewSearchTxsResult(resTxs.TotalCount, len(txs), page, limit, txs) + result := sdk.NewSearchTxsResult(uint64(resTxs.TotalCount), uint64(len(txs)), uint64(page), uint64(limit), txs) - return &result, nil + return result, nil } // QueryTx queries for a single transaction by a hash string in hex format. An @@ -88,7 +88,7 @@ func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, erro return nil, err } - out, err := formatTxResult(clientCtx.LegacyAmino, resTx, resBlocks[resTx.Height]) + out, err := formatTxResult(clientCtx.TxConfig, resTx, resBlocks[resTx.Height]) if err != nil { return out, err } @@ -97,11 +97,11 @@ func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, erro } // formatTxResults parses the indexed txs into a slice of TxResponse objects. -func formatTxResults(cdc *codec.LegacyAmino, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]*sdk.TxResponse, error) { +func formatTxResults(txConfig client.TxConfig, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]*sdk.TxResponse, error) { var err error out := make([]*sdk.TxResponse, len(resTxs)) for i := range resTxs { - out[i], err = formatTxResult(cdc, resTxs[i], resBlocks[resTxs[i].Height]) + out[i], err = formatTxResult(txConfig, resTxs[i], resBlocks[resTxs[i].Height]) if err != nil { return nil, err } @@ -132,22 +132,27 @@ func getBlocksForTxResults(clientCtx client.Context, resTxs []*ctypes.ResultTx) return resBlocks, nil } -func formatTxResult(cdc *codec.LegacyAmino, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (*sdk.TxResponse, error) { - tx, err := parseTx(cdc, resTx.Tx) +func formatTxResult(txConfig client.TxConfig, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (*sdk.TxResponse, error) { + anyTx, err := parseTx(txConfig, resTx.Tx) if err != nil { return nil, err } - return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil + return sdk.NewResponseResultTx(resTx, anyTx.AsAny(), resBlock.Block.Time.Format(time.RFC3339)), nil } -func parseTx(cdc *codec.LegacyAmino, txBytes []byte) (sdk.Tx, error) { - var tx types.StdTx +func parseTx(txConfig client.TxConfig, txBytes []byte) (codectypes.IntoAny, error) { + var tx sdk.Tx - err := cdc.UnmarshalBinaryBare(txBytes, &tx) + tx, err := txConfig.TxDecoder()(txBytes) if err != nil { return nil, err } - return tx, nil + anyTx, ok := tx.(codectypes.IntoAny) + if !ok { + return nil, fmt.Errorf("tx cannot be packed into Any") + } + + return anyTx, nil } diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index cfb4bc925179..78be2731bf84 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -1,8 +1,6 @@ package tx import ( - "fmt" - "github.com/gogo/protobuf/proto" "github.com/tendermint/tendermint/crypto" @@ -10,7 +8,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -44,6 +41,7 @@ var ( _ client.TxBuilder = &wrapper{} _ ante.HasExtensionOptionsTx = &wrapper{} _ ExtensionOptionsTxBuilder = &wrapper{} + _ codectypes.IntoAny = &wrapper{} ) // ExtensionOptionsTxBuilder defines a TxBuilder that can also set extensions. @@ -67,71 +65,11 @@ func newBuilder(pubkeyCodec types.PublicKeyCodec) *wrapper { } func (w *wrapper) GetMsgs() []sdk.Msg { - if w.tx == nil || w.tx.Body == nil { - return nil - } - - anys := w.tx.Body.Messages - res := make([]sdk.Msg, len(anys)) - for i, any := range anys { - msg := any.GetCachedValue().(sdk.Msg) - res[i] = msg - } - return res + return w.tx.GetMsgs() } -// MaxGasWanted defines the max gas allowed. -const MaxGasWanted = uint64((1 << 63) - 1) - func (w *wrapper) ValidateBasic() error { - theTx := w.tx - if theTx == nil { - return fmt.Errorf("bad Tx") - } - - body := w.tx.Body - if body == nil { - return fmt.Errorf("missing TxBody") - } - - authInfo := w.tx.AuthInfo - if authInfo == nil { - return fmt.Errorf("missing AuthInfo") - } - - fee := authInfo.Fee - if fee == nil { - return fmt.Errorf("missing fee") - } - - if fee.GasLimit > MaxGasWanted { - return sdkerrors.Wrapf( - sdkerrors.ErrInvalidRequest, - "invalid gas supplied; %d > %d", fee.GasLimit, MaxGasWanted, - ) - } - - if fee.Amount.IsAnyNegative() { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFee, - "invalid fee provided: %s", fee.Amount, - ) - } - - sigs := theTx.Signatures - - if len(sigs) == 0 { - return sdkerrors.ErrNoSignatures - } - - if len(sigs) != len(w.GetSigners()) { - return sdkerrors.Wrapf( - sdkerrors.ErrUnauthorized, - "wrong number of signers; expected %d, got %d", w.GetSigners(), len(sigs), - ) - } - - return nil + return w.tx.ValidateBasic() } func (w *wrapper) getBodyBytes() []byte { @@ -167,19 +105,7 @@ func (w *wrapper) getAuthInfoBytes() []byte { } func (w *wrapper) GetSigners() []sdk.AccAddress { - var signers []sdk.AccAddress - seen := map[string]bool{} - - for _, msg := range w.GetMsgs() { - for _, addr := range msg.GetSigners() { - if !seen[addr.String()] { - signers = append(signers, addr) - seen[addr.String()] = true - } - } - } - - return signers + return w.tx.GetSigners() } func (w *wrapper) GetPubKeys() []crypto.PubKey { @@ -358,8 +284,10 @@ func (w *wrapper) GetTx() authsigning.Tx { } // GetProtoTx returns the tx as a proto.Message. -func (w *wrapper) GetProtoTx() *tx.Tx { - return w.tx +func (w *wrapper) AsAny() *codectypes.Any { + // We're sure here that w.tx is a proto.Message, so this will call + // codectypes.NewAnyWithValue under the hood. + return codectypes.UnsafePackAny(w.tx) } // WrapTx creates a TxBuilder wrapper around a tx.Tx proto message. diff --git a/x/auth/tx/builder_test.go b/x/auth/tx/builder_test.go index 42f4e7627813..3bd8d37a33c6 100644 --- a/x/auth/tx/builder_test.go +++ b/x/auth/tx/builder_test.go @@ -201,10 +201,10 @@ func TestBuilderValidateBasic(t *testing.T) { require.NoError(t, err) // gas limit too high - txBuilder.SetGasLimit(MaxGasWanted + 1) + txBuilder.SetGasLimit(txtypes.MaxGasWanted + 1) err = txBuilder.ValidateBasic() require.Error(t, err) - txBuilder.SetGasLimit(MaxGasWanted - 1) + txBuilder.SetGasLimit(txtypes.MaxGasWanted - 1) err = txBuilder.ValidateBasic() require.NoError(t, err) diff --git a/x/auth/tx/encoder.go b/x/auth/tx/encoder.go index 557ddae9efdb..f8889cb62fab 100644 --- a/x/auth/tx/encoder.go +++ b/x/auth/tx/encoder.go @@ -6,13 +6,13 @@ import ( "github.com/gogo/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" txtypes "github.com/cosmos/cosmos-sdk/types/tx" ) // DefaultTxEncoder returns a default protobuf TxEncoder using the provided Marshaler -func DefaultTxEncoder() types.TxEncoder { - return func(tx types.Tx) ([]byte, error) { +func DefaultTxEncoder() sdk.TxEncoder { + return func(tx sdk.Tx) ([]byte, error) { txWrapper, ok := tx.(*wrapper) if !ok { return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx) @@ -28,14 +28,20 @@ func DefaultTxEncoder() types.TxEncoder { } } -// DefaultTxEncoder returns a default protobuf JSON TxEncoder using the provided Marshaler -func DefaultJSONTxEncoder() types.TxEncoder { - return func(tx types.Tx) ([]byte, error) { +// DefaultJSONTxEncoder returns a default protobuf JSON TxEncoder using the provided Marshaler. +func DefaultJSONTxEncoder() sdk.TxEncoder { + return func(tx sdk.Tx) ([]byte, error) { txWrapper, ok := tx.(*wrapper) - if !ok { - return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx) + if ok { + return codec.ProtoMarshalJSON(txWrapper.tx) } - return codec.ProtoMarshalJSON(txWrapper.tx) + protoTx, ok := tx.(*txtypes.Tx) + if ok { + return codec.ProtoMarshalJSON(protoTx) + } + + return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx) + } } diff --git a/x/auth/types/client_tx.go b/x/auth/types/client_tx.go index 9c583e17363e..04b28937638d 100644 --- a/x/auth/types/client_tx.go +++ b/x/auth/types/client_tx.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - txtypes "github.com/cosmos/cosmos-sdk/types/tx" "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) @@ -26,12 +25,6 @@ func (s *StdTxBuilder) GetTx() authsigning.Tx { return s.StdTx } -// GetProtoTx implements TxBuilder.GetProtoTx -func (s *StdTxBuilder) GetProtoTx() *txtypes.Tx { - // Stdtx isn't a proto.Message - return nil -} - // SetMsgs implements TxBuilder.SetMsgs func (s *StdTxBuilder) SetMsgs(msgs ...sdk.Msg) error { s.Msgs = msgs diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index 1ba33bc0e56c..004406966091 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -133,7 +133,10 @@ func CountSubKeys(pub crypto.PubKey) int { // DEPRECATED // --------------------------------------------------------------------------- -var _ sdk.Tx = (*StdTx)(nil) +var ( + _ sdk.Tx = (*StdTx)(nil) + _ codectypes.IntoAny = (*StdTx)(nil) +) // StdTx is the legacy transaction format for wrapping a Msg with Fee and Signatures. // It only works with Amino, please prefer the new protobuf Tx in types/tx. @@ -189,6 +192,11 @@ func (tx StdTx) ValidateBasic() error { return nil } +// AsAny implements IntoAny.AsAny. +func (tx *StdTx) AsAny() *codectypes.Any { + return codectypes.UnsafePackAny(tx) +} + // GetSigners returns the addresses that must sign the transaction. // Addresses are returned in a deterministic order. // They are accumulated from the GetSigners method for each Msg diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index c576eacd493e..6ddf1287326a 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -1,6 +1,8 @@ -package utils +package utils_test import ( + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/gov/client/utils" "testing" "github.com/stretchr/testify/require" @@ -59,7 +61,7 @@ func TestGetPaginatedVotes(t *testing.T) { type testCase struct { description string page, limit int - txs []authtypes.StdTx + msgs [][]sdk.Msg votes []types.Vote } acc1 := make(sdk.AccAddress, 20) @@ -79,22 +81,21 @@ func TestGetPaginatedVotes(t *testing.T) { description: "1MsgPerTxAll", page: 1, limit: 2, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs[:1]}, - {Msgs: acc2Msgs[:1]}, + msgs: [][]sdk.Msg{ + acc1Msgs[:1], + acc2Msgs[:1], }, votes: []types.Vote{ types.NewVote(0, acc1, types.OptionYes), types.NewVote(0, acc2, types.OptionYes)}, }, - { description: "2MsgPerTx1Chunk", page: 1, limit: 2, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs}, - {Msgs: acc2Msgs}, + msgs: [][]sdk.Msg{ + acc1Msgs, + acc2Msgs, }, votes: []types.Vote{ types.NewVote(0, acc1, types.OptionYes), @@ -104,9 +105,9 @@ func TestGetPaginatedVotes(t *testing.T) { description: "2MsgPerTx2Chunk", page: 2, limit: 2, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs}, - {Msgs: acc2Msgs}, + msgs: [][]sdk.Msg{ + acc1Msgs, + acc2Msgs, }, votes: []types.Vote{ types.NewVote(0, acc2, types.OptionYes), @@ -116,49 +117,54 @@ func TestGetPaginatedVotes(t *testing.T) { description: "IncompleteSearchTx", page: 1, limit: 2, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs[:1]}, + msgs: [][]sdk.Msg{ + acc1Msgs[:1], }, votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, }, { description: "InvalidPage", page: -1, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs[:1]}, + msgs: [][]sdk.Msg{ + acc1Msgs[:1], }, }, { description: "OutOfBounds", page: 2, limit: 10, - txs: []authtypes.StdTx{ - {Msgs: acc1Msgs[:1]}, + msgs: [][]sdk.Msg{ + acc1Msgs[:1], }, }, } { - tc := tc t.Run(tc.description, func(t *testing.T) { var ( - marshalled = make([]tmtypes.Tx, len(tc.txs)) + marshalled = make([]tmtypes.Tx, len(tc.msgs)) cdc = newTestCodec() ) - for i := range tc.txs { - tx, err := cdc.MarshalBinaryBare(&tc.txs[i]) - require.NoError(t, err) - marshalled[i] = tx - } - + encodingConfig := simapp.MakeEncodingConfig() cli := TxSearchMock{txs: marshalled} clientCtx := client.Context{}. WithLegacyAmino(cdc). - WithClient(cli) + WithClient(cli). + WithTxConfig(encodingConfig.TxConfig) + + for i := range tc.msgs { + txBuilder := clientCtx.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs(tc.msgs[i]...) + require.NoError(t, err) + + tx, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx()) + require.NoError(t, err) + marshalled[i] = tx + } params := types.NewQueryProposalVotesParams(0, tc.page, tc.limit) - votesData, err := QueryVotesByTxQuery(clientCtx, params) + votesData, err := utils.QueryVotesByTxQuery(clientCtx, params) require.NoError(t, err) votes := []types.Vote{} require.NoError(t, clientCtx.LegacyAmino.UnmarshalJSON(votesData, &votes)) diff --git a/x/ibc/02-client/client/cli/query.go b/x/ibc/02-client/client/cli/query.go index 66b903e914c6..42e39f392434 100644 --- a/x/ibc/02-client/client/cli/query.go +++ b/x/ibc/02-client/client/cli/query.go @@ -211,7 +211,7 @@ func GetCmdQueryHeader() *cobra.Command { } clientCtx = clientCtx.WithHeight(height) - return clientCtx.PrintOutputLegacy(header) + return clientCtx.PrintOutput(&header) }, } diff --git a/x/ibc/04-channel/client/cli/query.go b/x/ibc/04-channel/client/cli/query.go index be0941ae8ac6..aa9e5dfe9c74 100644 --- a/x/ibc/04-channel/client/cli/query.go +++ b/x/ibc/04-channel/client/cli/query.go @@ -161,7 +161,7 @@ func GetCmdQueryChannelClientState() *cobra.Command { return err } - return clientCtx.PrintOutputLegacy(res.IdentifiedClientState) + return clientCtx.PrintOutput(res.IdentifiedClientState) }, }