diff --git a/CHANGELOG.md b/CHANGELOG.md index 58bd34e82b98..c01a3a52aa8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9533](https://github.com/cosmos/cosmos-sdk/pull/9533) Added a new gRPC method, `DenomOwners`, in `x/bank` to query for all account holders of a specific denomination. * (bank) [\#9618](https://github.com/cosmos/cosmos-sdk/pull/9618) Update bank.Metadata: add URI and URIHash attributes. * [\#9837](https://github.com/cosmos/cosmos-sdk/issues/9837) `--generate-only` flag will accept the keyname now. +* [\#10045](https://github.com/cosmos/cosmos-sdk/pull/10045) Revert [#8549](https://github.com/cosmos/cosmos-sdk/pull/8549). Do not route grpc queries through Tendermint. ### API Breaking Changes @@ -120,8 +121,11 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (types) [\#10021](https://github.com/cosmos/cosmos-sdk/pull/10021) Speedup coins.AmountOf(), by removing many intermittent regex calls. * (rosetta) [\#10001](https://github.com/cosmos/cosmos-sdk/issues/10001) Add documentation for rosetta-cli dockerfile and rename folder for the rosetta-ci dockerfile * [\#9699](https://github.com/cosmos/cosmos-sdk/pull/9699) Add `:`, `.`, `-`, and `_` as allowed characters in the default denom regular expression. +* [\#10262](https://github.com/cosmos/cosmos-sdk/pull/10262) Remove unnecessary logging in `x/feegrant` simulation. ### Bug Fixes + +* (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 * (store) [#10218](https://github.com/cosmos/cosmos-sdk/pull/10218) Charge gas even when there are no entries while seeking. * (x/genutil) [#10104](https://github.com/cosmos/cosmos-sdk/pull/10104) Ensure the `init` command reads the `--home` flag value correctly. diff --git a/README.md b/README.md index b26942f868d1..883f0748c9cf 100644 --- a/README.md +++ b/README.md @@ -40,34 +40,33 @@ parent: Lint Satus -The Cosmos-SDK is a framework for building blockchain applications in Golang. -It is being used to build [`Gaia`](https://github.com/cosmos/gaia), the first implementation of the Cosmos Hub. +The Cosmos SDK is a framework for building blockchain applications. [Tendermint Core (BFT Consensus)](https://github.com/tendermint/tendermint) and the Cosmos SDK are written in the Golang programming language. Cosmos SDK is used to build [Gaia](https://github.com/cosmos/gaia), the first implementation of the Cosmos Hub. -**WARNING**: The SDK has mostly stabilized, but we are still making some +**WARNING**: The Cosmos SDK has mostly stabilized, but we are still making some breaking changes. **Note**: Requires [Go 1.17+](https://golang.org/dl/) ## Quick Start -To learn how the SDK works from a high-level perspective, go to the [SDK Intro](./docs/intro/overview.md). +To learn how the Cosmos SDK works from a high-level perspective, see the Cosmos SDK [High-Level Intro](./docs/intro/overview.md). -If you want to get started quickly and learn how to build on top of the SDK, please visit the [tutorials website](https://tutorials.cosmos.network). You can also fork the tutorial's repository to get started building your own Cosmos SDK application. +If you want to get started quickly and learn how to build on top of Cosmos SDK, visit [Cosmos SDK Tutorials](https://tutorials.cosmos.network). You can also fork the tutorial's repository to get started building your own Cosmos SDK application. -For more, please go to the [Cosmos SDK Docs](./docs/). +For more information, see the [Cosmos SDK Documentation](./docs/). ## Cosmos Hub Mainnet -The Cosmos Hub application, `gaia`, has moved to its [own repository](https://github.com/cosmos/gaia). Go there to join the Cosmos Hub mainnet and more. +The Cosmos Hub application, `gaia`, has moved to its own [cosmos/gaia repository](https://github.com/cosmos/gaia). Go there to join the Cosmos Hub mainnet and more. -## Interblockchain Communication (IBC) +## Inter-Blockchain Communication (IBC) -The IBC module for the SDK has moved to its [own repository](https://github.com/cosmos/ibc-go). Go there to build and integrate with the IBC module. +The IBC module for the Cosmos SDK has moved to its own [cosmos/ibc-go repository](https://github.com/cosmos/ibc-go). Go there to build and integrate with the IBC module. ## Starport -If you are starting a new app or a new module you can use [Starport](https://github.com/tendermint/starport) to help you get started and speed up development. If you have any questions or find a bug, feel free to open an issue in the repo. +Starport is the all-in-one platform to build, launch, and maintain any crypto application on a sovereign and secured blockchain. If you are building a new app or a new module, use [Starport](https://github.com/tendermint/starport) to get started and speed up development. ## Disambiguation -This Cosmos-SDK project is not related to the [React-Cosmos](https://github.com/react-cosmos/react-cosmos) project (yet). Many thanks to Evan Coury and Ovidiu (@skidding) for this Github organization name. As per our agreement, this disambiguation notice will stay here. +This Cosmos SDK project is not related to the [React-Cosmos](https://github.com/react-cosmos/react-cosmos) project (yet). Many thanks to Evan Coury and Ovidiu (@skidding) for this Github organization name. As per our agreement, this disambiguation notice will stay here. diff --git a/baseapp/grpcrouter.go b/baseapp/grpcrouter.go index 3570648d48ab..9c15b695176c 100644 --- a/baseapp/grpcrouter.go +++ b/baseapp/grpcrouter.go @@ -2,7 +2,6 @@ package baseapp import ( "fmt" - "reflect" "github.com/cosmos/cosmos-sdk/client/grpc/reflection" @@ -14,19 +13,13 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var protoCodec = encoding.GetCodec(proto.Name) // GRPCQueryRouter routes ABCI Query requests to GRPC handlers type GRPCQueryRouter struct { - routes map[string]GRPCQueryHandler - // returnTypes is a map of FQ method name => its return type. It is used - // for cache purposes: the first time a method handler is run, we save its - // return type in this map. Then, on subsequent method handler calls, we - // decode the ABCI response bytes using the cached return type. - returnTypes map[string]reflect.Type + routes map[string]GRPCQueryHandler interfaceRegistry codectypes.InterfaceRegistry serviceData []serviceData } @@ -42,8 +35,7 @@ var _ gogogrpc.Server = &GRPCQueryRouter{} // NewGRPCQueryRouter creates a new GRPCQueryRouter func NewGRPCQueryRouter() *GRPCQueryRouter { return &GRPCQueryRouter{ - returnTypes: map[string]reflect.Type{}, - routes: map[string]GRPCQueryHandler{}, + routes: map[string]GRPCQueryHandler{}, } } @@ -98,17 +90,8 @@ func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interf if qrt.interfaceRegistry != nil { return codectypes.UnpackInterfaces(i, qrt.interfaceRegistry) } - return nil }, nil) - - // If it's the first time we call this handler, then we save - // the return type of the handler in the `returnTypes` map. - // The return type will be used for decoding subsequent requests. - if _, found := qrt.returnTypes[fqName]; !found { - qrt.returnTypes[fqName] = reflect.TypeOf(res) - } - if err != nil { return abci.ResponseQuery{}, err } @@ -144,16 +127,3 @@ func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.In reflection.NewReflectionServiceServer(interfaceRegistry), ) } - -// returnTypeOf returns the return type of a gRPC method handler. With the way the -// `returnTypes` cache map is set up, the return type of a method handler is -// guaranteed to be found if it's retrieved **after** the method handler ran at -// least once. If not, then a logic error is return. -func (qrt *GRPCQueryRouter) returnTypeOf(method string) (reflect.Type, error) { - returnType, found := qrt.returnTypes[method] - if !found { - return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "cannot find %s return type", method) - } - - return returnType, nil -} diff --git a/baseapp/grpcserver.go b/baseapp/grpcserver.go index c1db08a555aa..68cc14e66545 100644 --- a/baseapp/grpcserver.go +++ b/baseapp/grpcserver.go @@ -2,78 +2,68 @@ package baseapp import ( "context" - "reflect" + "strconv" gogogrpc "github.com/gogo/protobuf/grpc" grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" - "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/types/tx" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" ) // GRPCQueryRouter returns the GRPCQueryRouter of a BaseApp. func (app *BaseApp) GRPCQueryRouter() *GRPCQueryRouter { return app.grpcQueryRouter } // RegisterGRPCServer registers gRPC services directly with the gRPC server. -func (app *BaseApp) RegisterGRPCServer(clientCtx client.Context, server gogogrpc.Server) { - // Define an interceptor for all gRPC queries: this interceptor will route - // the query through the `clientCtx`, which itself queries Tendermint. - interceptor := func(grpcCtx context.Context, req interface{}, info *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) { - // Two things can happen here: - // 1. either we're broadcasting a Tx, in which case we call Tendermint's broadcast endpoint directly, - // 2. or we are querying for state, in which case we call ABCI's Query. +func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { + // Define an interceptor for all gRPC queries: this interceptor will create + // a new sdk.Context, and pass it into the query handler. + interceptor := func(grpcCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + // If there's some metadata in the context, retrieve it. + md, ok := metadata.FromIncomingContext(grpcCtx) + if !ok { + return nil, status.Error(codes.Internal, "unable to retrieve metadata") + } - // Case 1. Broadcasting a Tx. - if reqProto, ok := req.(*tx.BroadcastTxRequest); ok { - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req) + // Get height header from the request context, if present. + var height int64 + if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) == 1 { + height, err = strconv.ParseInt(heightHeaders[0], 10, 64) + if err != nil { + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err) + } + if err := checkNegativeHeight(height); err != nil { + return nil, err } - - return client.TxServiceBroadcast(grpcCtx, clientCtx, reqProto) } - // Case 2. Querying state. - inMd, _ := metadata.FromIncomingContext(grpcCtx) - abciRes, outMd, err := client.RunGRPCQuery(clientCtx, grpcCtx, info.FullMethod, req, inMd) + // Create the sdk.Context. Passing false as 2nd arg, as we can't + // actually support proofs with gRPC right now. + sdkCtx, err := app.createQueryContext(height, false) if err != nil { return nil, err } - // We need to know the return type of the grpc method for - // unmarshalling abciRes.Value. - // - // When we call each method handler for the first time, we save its - // return type in the `returnTypes` map (see the method handler in - // `grpcrouter.go`). By this time, the method handler has already run - // at least once (in the RunGRPCQuery call), so we're sure the - // returnType maps is populated for this method. We're retrieving it - // for decoding. - returnType, err := app.GRPCQueryRouter().returnTypeOf(info.FullMethod) - if err != nil { - return nil, err + // Add relevant gRPC headers + if height == 0 { + height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest } - // returnType is a pointer to a struct. Here, we're creating res which - // is a new pointer to the underlying struct. - res := reflect.New(returnType.Elem()).Interface() - - err = protoCodec.Unmarshal(abciRes.Value, res) - if err != nil { - return nil, err - } + // Attach the sdk.Context into the gRPC's context.Context. + grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx) - // Send the metadata header back. The metadata currently includes: - // - block height. - err = grpc.SendHeader(grpcCtx, outMd) - if err != nil { - return nil, err - } + md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10)) + grpc.SetHeader(grpcCtx, md) - return res, nil + return handler(grpcCtx, req) } // Loop through all services and methods, add the interceptor, and register diff --git a/client/cmd.go b/client/cmd.go index c2e3ff8a4726..0e401a9250f6 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -93,6 +93,11 @@ func ReadPersistentCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Cont clientCtx = clientCtx.WithOutputFormat(output) } + if clientCtx.HomeDir == "" || flagSet.Changed(flags.FlagHome) { + homeDir, _ := flagSet.GetString(flags.FlagHome) + clientCtx = clientCtx.WithHomeDir(homeDir) + } + if !clientCtx.Simulate || flagSet.Changed(flags.FlagDryRun) { dryRun, _ := flagSet.GetBool(flags.FlagDryRun) clientCtx = clientCtx.WithSimulation(dryRun) @@ -249,17 +254,6 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err return clientCtx, nil } -// ReadHomeFlag checks if home flag is changed. If this is a case, we update -// HomeDir field of Client Context. -func ReadHomeFlag(clientCtx Context, cmd *cobra.Command) Context { - if cmd.Flags().Changed(flags.FlagHome) { - rootDir, _ := cmd.Flags().GetString(flags.FlagHome) - clientCtx = clientCtx.WithHomeDir(rootDir) - } - - return clientCtx -} - // GetClientQueryContext returns a Context from a command with fields set based on flags // defined in AddQueryFlagsToCmd. An error is returned if any flag query fails. // diff --git a/client/grpc_query.go b/client/grpc_query.go index cbaba73caa2a..597b82985c22 100644 --- a/client/grpc_query.go +++ b/client/grpc_query.go @@ -29,17 +29,14 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply i // 1. either we're broadcasting a Tx, in which call we call Tendermint's broadcast endpoint directly, // 2. or we are querying for state, in which case we call ABCI's Query. - // In both cases, we don't allow empty request req (it will panic unexpectedly). + // In both cases, we don't allow empty request args (it will panic unexpectedly). if reflect.ValueOf(req).IsNil() { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "request cannot be nil") } // Case 1. Broadcasting a Tx. if reqProto, ok := req.(*tx.BroadcastTxRequest); ok { - if !ok { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req) - } - resProto, ok := reply.(*tx.BroadcastTxResponse) + res, ok := reply.(*tx.BroadcastTxResponse) if !ok { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), req) } @@ -48,62 +45,26 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply i if err != nil { return err } - *resProto = *broadcastRes + *res = *broadcastRes return err } // Case 2. Querying state. - inMd, _ := metadata.FromOutgoingContext(grpcCtx) - abciRes, outMd, err := RunGRPCQuery(ctx, grpcCtx, method, req, inMd) - if err != nil { - return err - } - - err = protoCodec.Unmarshal(abciRes.Value, reply) - if err != nil { - return err - } - - for _, callOpt := range opts { - header, ok := callOpt.(grpc.HeaderCallOption) - if !ok { - continue - } - - *header.HeaderAddr = outMd - } - - if ctx.InterfaceRegistry != nil { - return types.UnpackInterfaces(reply, ctx.InterfaceRegistry) - } - - return nil -} - -// NewStream implements the grpc ClientConn.NewStream method -func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { - return nil, fmt.Errorf("streaming rpc not supported") -} - -// RunGRPCQuery runs a gRPC query from the clientCtx, given all necessary -// arguments for the gRPC method, and returns the ABCI response. It is used -// to factorize code between client (Invoke) and server (RegisterGRPCServer) -// gRPC handlers. -func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req interface{}, md metadata.MD) (abci.ResponseQuery, metadata.MD, error) { reqBz, err := protoCodec.Marshal(req) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } // parse height header + md, _ := metadata.FromOutgoingContext(grpcCtx) if heights := md.Get(grpctypes.GRPCBlockHeightHeader); len(heights) > 0 { height, err := strconv.ParseInt(heights[0], 10, 64) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } if height < 0 { - return abci.ResponseQuery{}, nil, sdkerrors.Wrapf( + return sdkerrors.Wrapf( sdkerrors.ErrInvalidRequest, "client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader) } @@ -117,9 +78,14 @@ func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req int Height: ctx.Height, } - abciRes, err := ctx.QueryABCI(abciReq) + res, err := ctx.QueryABCI(abciReq) + if err != nil { + return err + } + + err = protoCodec.Unmarshal(res.Value, reply) if err != nil { - return abci.ResponseQuery{}, nil, err + return err } // Create header metadata. For now the headers contain: @@ -127,7 +93,24 @@ func RunGRPCQuery(ctx Context, grpcCtx gocontext.Context, method string, req int // We then parse all the call options, if the call option is a // HeaderCallOption, then we manually set the value of that header to the // metadata. - md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(abciRes.Height, 10)) + md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(res.Height, 10)) + for _, callOpt := range opts { + header, ok := callOpt.(grpc.HeaderCallOption) + if !ok { + continue + } + + *header.HeaderAddr = md + } + + if ctx.InterfaceRegistry != nil { + return types.UnpackInterfaces(reply, ctx.InterfaceRegistry) + } - return abciRes, md, nil + return nil +} + +// NewStream implements the grpc ClientConn.NewStream method +func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) { + return nil, fmt.Errorf("streaming rpc not supported") } diff --git a/client/keys/list_test.go b/client/keys/list_test.go index 5d4ddb50d31f..2d728dbfd1b9 100644 --- a/client/keys/list_test.go +++ b/client/keys/list_test.go @@ -59,7 +59,6 @@ func Test_runListCmd(t *testing.T) { cmd.SetArgs([]string{ fmt.Sprintf("--%s=%s", flags.FlagHome, tt.kbDir), fmt.Sprintf("--%s=false", flagListNames), - fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), }) if err := cmd.ExecuteContext(ctx); (err != nil) != tt.wantErr { @@ -69,7 +68,6 @@ func Test_runListCmd(t *testing.T) { cmd.SetArgs([]string{ fmt.Sprintf("--%s=%s", flags.FlagHome, tt.kbDir), fmt.Sprintf("--%s=true", flagListNames), - fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), }) if err := cmd.ExecuteContext(ctx); (err != nil) != tt.wantErr { diff --git a/cosmovisor/CHANGELOG.md b/cosmovisor/CHANGELOG.md index 52c4747040fe..a5b298b1b904 100644 --- a/cosmovisor/CHANGELOG.md +++ b/cosmovisor/CHANGELOG.md @@ -29,7 +29,6 @@ Types of changes (Stanzas): "Client Breaking" for breaking Protobuf, gRPC and REST routes used by end-users. "CLI Breaking" for breaking CLI commands. "API Breaking" for breaking exported APIs used by developers building on SDK. -"State Machine Breaking" for any changes that result in a different AppState given same genesisState and txList. Ref: https://keepachangelog.com/en/1.0.0/ --> @@ -37,10 +36,11 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +## v1.0.0 2021-09-30 + ### Features + [\#8590](https://github.com/cosmos/cosmos-sdk/pull/8590) File watcher for cosmovisor. Instead of parsing logs from stdin and stderr, we watch the `/data/upgrade-info.json` file updates using polling mechanism. -+ [\#10128](https://github.com/cosmos/cosmos-sdk/pull/10128) Change default value of `DAEMON_RESTART_AFTER_UPGRADE` to `true`. + [\#9999](https://github.com/cosmos/cosmos-sdk/pull/10103) Added `version` command that returns the cosmovisor version and the application version. + [\#9973](https://github.com/cosmos/cosmos-sdk/pull/10056) Added support for pre-upgrade command in Cosmovisor to be called before the binary is upgraded. Added new environmental variable `DAEMON_PREUPGRADE_MAX_RETRIES` that holds the maximum number of times to reattempt pre-upgrade before failing. + [\#10126](https://github.com/cosmos/cosmos-sdk/pull/10229) Added `help`. @@ -51,6 +51,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ + [\#10036](https://github.com/cosmos/cosmos-sdk/pull/10036) Improve logs when downloading the binary. + [\#10217](https://github.com/cosmos/cosmos-sdk/pull/10217) Replacing logging to use zerolog. +### CLI Breaking ++ [\#10128](https://github.com/cosmos/cosmos-sdk/pull/10128) Change default value of `DAEMON_RESTART_AFTER_UPGRADE` to `true`. + ## v0.1 2021-08-06 This is the first release and we started this changelog on 2021-07-01. See the (README)[https://github.com/cosmos/cosmos-sdk/blob/release/cosmovisor/v0.1.x/cosmovisor/CHANGELOG.md] file for the full list of features. diff --git a/cosmovisor/README.md b/cosmovisor/README.md index 1d3eb2b00f7e..afb7f0fe2ef8 100644 --- a/cosmovisor/README.md +++ b/cosmovisor/README.md @@ -5,13 +5,14 @@ #### Design Cosmovisor is designed to be used as a wrapper for an `Cosmos SDK` app: -* it will pass all arguments to the app. Running `cosmovisor arg1 arg2 ....` will run `app arg1 arg2 ...`; +* it will pass all arguments to the associated app (configured by `DAEMON_NAME` env variable). + Running `cosmovisor 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. *Note: If new versions of the application are not set up to run in-place store migrations, migrations will need to be run manually before restarting `cosmovisor` with the new binary. For this reason, we recommend applications adopt in-place store migrations.* -*Note: If validators would like to enable the auto-download option, and they are currently running an application using Cosmos SDK `v0.42`, they will need to use Cosmovisor [`v0.1`](https://github.com/cosmos/cosmos-sdk/releases/tag/cosmovisor%2Fv0.1.0). Later versions of Cosmovisor do not support Cosmos SDK `v0.42` or earlier if the auto-download option is enabled.* +*Note: If validators would like to enable the auto-download option (which [we don't recommend](#auto-download)), and they are currently running an application using Cosmos SDK `v0.42`, they will need to use Cosmovisor [`v0.1`](https://github.com/cosmos/cosmos-sdk/releases/tag/cosmovisor%2Fv0.1.0). Later versions of Cosmovisor do not support Cosmos SDK `v0.42` or earlier if the auto-download option is enabled.* ## Contributing @@ -43,7 +44,7 @@ All arguments passed to `cosmovisor` will be passed to the application binary (a * `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_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. +* `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 @@ -92,12 +93,12 @@ The `DAEMON` specific code and operations (e.g. tendermint config, the applicati ### Commands -Because Cosmovisor is meant to be used as a wrapper for a Cosmos SDK application, it does not require many 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: ``` @@ -115,13 +116,17 @@ The following heuristic is applied to detect the upgrade: + If `cosmovisor/current/upgrade-info.json` doesn't exist but `data/upgrade-info.json` exists, then `cosmovisor` assumes that whatever is in `data/upgrade-info.json` is a valid upgrade request. In this case `cosmovisor` tries immediately to make an upgrade according to the `name` attribute in `data/upgrade-info.json`. + Otherwise, `cosmovisor` waits for changes in `upgrade-info.json`. As soon as a new upgrade name is recorded in the file, `cosmovisor` will trigger an upgrade mechanism. -When the upgrade mechanism is triggered, `cosmovisor` will start by auto-downloading a new binary (if `DAEMON_ALLOW_DOWNLOAD_BINARIES` is enabled) into `cosmovisor//bin` (where `` is the `upgrade-info.json:name` attribute). `cosmovisor` will then update the `current` symbolic link to point to the new directory and save `data/upgrade-info.json` to `cosmovisor/current/upgrade-info.json`. +When the upgrade mechanism is triggered, `cosmovisor` will: +1. if `DAEMON_ALLOW_DOWNLOAD_BINARIES` is enabled, start by auto-downloading a new binary into `cosmovisor//bin` (where `` is the `upgrade-info.json:name` attribute); +2. update the `current` symbolic link to point to the new directory and save `data/upgrade-info.json` to `cosmovisor/current/upgrade-info.json`. ### Auto-Download -Generally, `cosmovisor` requires that the system administrator place all relevant binaries on disk before the upgrade happens. However, for people who don't need such control and want an easier setup (maybe they are syncing a non-validating fullnode and want to do little maintenance), there is another option. +Generally, `cosmovisor` requires that the system administrator place all relevant binaries on disk before the upgrade happens. However, for people who don't need such control and want an automated setup (maybe they are syncing a non-validating fullnode and want to do little maintenance), there is another option. + +**NOTE: we don't recommend using auto-download** because it doesn't verify in advance if a binary is available. If there will be any issue with downloading a binary, the cosmovisor will stop and won't restart an App (which could lead to a chain halt). -If `DAEMON_ALLOW_DOWNLOAD_BINARIES` is set to `true`, and no local binary can be found when an upgrade is triggered, `cosmovisor` will attempt to download and install the binary itself. The plan stored in the upgrade module has an info field for arbitrary JSON. This info is expected to be outputed on the halt log message. There are two valid formats to specify a download in such a message: +If `DAEMON_ALLOW_DOWNLOAD_BINARIES` is set to `true`, and no local binary can be found when an upgrade is triggered, `cosmovisor` will attempt to download and install the binary itself based on the instructions in the `info` attribute in the `data/upgrade-info.json` file. The files is constructed by the x/upgrade module and contains data from the upgrade `Plan` object. The `Plan` has an info field that is expected to have one of the following two valid formats to specify a download: 1. Store an os/architecture -> binary URI map in the upgrade plan info field as JSON under the `"binaries"` key. For example: diff --git a/cosmovisor/RELEASE_NOTES.md b/cosmovisor/RELEASE_NOTES.md index e59981ee7ba4..c32d17870dce 100644 --- a/cosmovisor/RELEASE_NOTES.md +++ b/cosmovisor/RELEASE_NOTES.md @@ -1,8 +1,33 @@ -# Cosmovisor v0.1.0 Release Notes +# Cosmovisor v1.0.0 Release Notes -This is the first tracked release of Cosmovisor. It contains the original behavior of scanning app stdin and stdout. -Since the original design, this release contains one important feature: state backup. Since v0.1, by default, cosmovisor will make a state backup (`/data` directory). Backup will be skipped if `UNSAFE_SKIP_BACKUP=true` is set. +This is the first major release of Cosmovisor. +It changes the way Cosmovisor is searching for an upgrade event from an app. +Instead of scanning standard input and standard output logs, the Cosmovisor +observes the `$DAEMON_HOME/upgrade-info.json` file, that is produced by the +`x/upgrade` module. The `upgrade-info.json` files is created by the `x/upgrade` +module and contains information from the on-chain upgrade Plan record. +Using the file based approach solved many outstanding problems: freezing when +logs are too long, race condition with the `x/upgrade` handler, and potential +exploit (if a chain would allow to log an arbitrary message, then an attacker +could produce a fake upgrade signal and halt a chain or instrument a download +of modified, hacked binary when the auto download option is enabled). -Updates to this release will be pushed to `release/cosmovisor/v0.1.x` branch. +## Auto downloads -Please see the [CHANGELOG](https://github.com/cosmos/cosmos-sdk/blob/release/cosmovisor/v0.1.x/cosmovisor/CHANGELOG.md) for more details. +Cosmovisor v1.0 supports auto downloads based on the information in the +`data/upgrade-info.json`. In the Cosmos SDK `< v0.44`, that file doesn't contain +`upgrade.Plan.Info`, that is needed for doing auto download. Hence Cosmovisor `v1.0` +auto download won't work with Apps updating from `v0.43` and earlier. + +NOTE: we **don't recommend using auto download** functionality. It can lead to potential +chain halt when the upgrade Plan contains a bad link or the resource with the +binary will be temporarily unavailable. We are planning on adding a upgrade +verification command which can potentially solve this issue. + +## Other updates + ++ Changed default value of `DAEMON_RESTART_AFTER_UPGRADE` to `true`. ++ Added `version` command, which prints both the Cosmovisor and the associated app version. ++ Added `help` command, which prints the Cosmovisor help without passing it to the associated version. This is an exception, because normally, Cosmovisor passes all arguments to the associated app. + +For more details, please see the [CHANGELOG](https://github.com/cosmos/cosmos-sdk/blob/cosmovisor/v1.0.0/cosmovisor/CHANGELOG.md). diff --git a/server/grpc/server.go b/server/grpc/server.go index 40a3c7716d97..0b41a57cd323 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -17,7 +17,7 @@ import ( // StartGRPCServer starts a gRPC server on the given address. func StartGRPCServer(clientCtx client.Context, app types.Application, address string) (*grpc.Server, error) { grpcSrv := grpc.NewServer() - app.RegisterGRPCServer(clientCtx, grpcSrv) + app.RegisterGRPCServer(grpcSrv) // reflection allows consumers to build dynamic clients that can write // to any cosmos-sdk application without relying on application packages at compile time err := reflection.Register(grpcSrv, reflection.Config{ diff --git a/server/grpc/server_test.go b/server/grpc/server_test.go index 3a4afd45b238..8ea293a9169c 100644 --- a/server/grpc/server_test.go +++ b/server/grpc/server_test.go @@ -106,7 +106,7 @@ func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() { ) s.Require().NoError(err) blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader) - s.Require().NotEmpty(blockHeight[0]) // blockHeight is []string, first element is block height. + s.Require().Equal([]string{"1"}, blockHeight) } func (s *IntegrationTestSuite) TestGRPCServer_Reflection() { @@ -201,9 +201,9 @@ func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() { value string wantErr string }{ - {"-1", "\"x-cosmos-block-height\" must be >= 0"}, + {"-1", "height < 0"}, {"9223372036854775808", "value out of range"}, // > max(int64) by 1 - {"-10", "\"x-cosmos-block-height\" must be >= 0"}, + {"-10", "height < 0"}, {"18446744073709551615", "value out of range"}, // max uint64, which is > max(int64) {"-9223372036854775809", "value out of range"}, // Out of the range of for negative int64 } diff --git a/server/types/app.go b/server/types/app.go index cf6b6ad9a1ff..467f627c605f 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -43,7 +43,7 @@ type ( // RegisterGRPCServer registers gRPC services directly with the gRPC // server. - RegisterGRPCServer(client.Context, grpc.Server) + RegisterGRPCServer(grpc.Server) // RegisterTxService registers the gRPC Query service for tx (such as tx // simulation, fetching txs by hash...). diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 8d467eedb907..d93615b8cd90 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -56,9 +56,12 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { cmd.SetOut(cmd.OutOrStdout()) cmd.SetErr(cmd.ErrOrStderr()) - initClientCtx = client.ReadHomeFlag(initClientCtx, cmd) + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } - initClientCtx, err := config.ReadFromClientConfig(initClientCtx) + initClientCtx, err = config.ReadFromClientConfig(initClientCtx) if err != nil { return err } diff --git a/x/auth/spec/01_concepts.md b/x/auth/spec/01_concepts.md index 9f8c9b8d8f2d..57393d6ed561 100644 --- a/x/auth/spec/01_concepts.md +++ b/x/auth/spec/01_concepts.md @@ -4,6 +4,12 @@ order: 1 # Concepts +**Note:** The auth module is different from the [authz module](../modules/authz/). + +The differences are: +* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types. +* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter. + ## Gas & Fees Fees serve two purposes for an operator of the network. diff --git a/x/auth/spec/03_antehandlers.md b/x/auth/spec/03_antehandlers.md index 851005162d78..ce1dc85c50f1 100644 --- a/x/auth/spec/03_antehandlers.md +++ b/x/auth/spec/03_antehandlers.md @@ -27,7 +27,7 @@ The auth module provides `AnteDecorator`s that are recursively chained together - `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters. -- `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it will deduct fees from the fee granter account. +- `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it deducts fees from the fee granter account. - `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context. diff --git a/x/auth/spec/05_vesting.md b/x/auth/spec/05_vesting.md index 858579b6f12c..b085cc4c5d03 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/spec/05_vesting.md @@ -34,8 +34,8 @@ the Cosmos Hub. The requirements for this vesting account is that it should be initialized during genesis with a starting balance `X` and a vesting end time `ET`. A vesting account may be initialized with a vesting start time `ST` and a number of vesting periods `P`. If a vesting start time is included, the -vesting period will not begin until start time is reached. If vesting periods -are included, the vesting will occur over the specified number of periods. +vesting period does not begin until start time is reached. If vesting periods +are included, the vesting occurs over the specified number of periods. For all vesting accounts, the owner of the vesting account is able to delegate and undelegate from validators, however they cannot transfer coins to another @@ -378,7 +378,7 @@ func (cva ContinuousVestingAccount) TrackUndelegation(amount Coins) { **Note** `TrackUnDelegation` only modifies the `DelegatedVesting` and `DelegatedFree` fields, so upstream callers MUST modify the `Coins` field by adding `amount`. -**Note**: If a delegation is slashed, the continuous vesting account will end up +**Note**: If a delegation is slashed, the continuous vesting account ends up with an excess `DV` amount, even after all its coins have vested. This is because undelegating free coins are prioritized. @@ -419,11 +419,11 @@ See the above specification for full implementation details. ## Genesis Initialization -To initialize both vesting and non-vesting accounts, the `GenesisAccount` struct will -include new fields: `Vesting`, `StartTime`, and `EndTime`. Accounts meant to be -of type `BaseAccount` or any non-vesting type will have `Vesting = false`. The -genesis initialization logic (e.g. `initFromGenesisState`) will have to parse -and return the correct accounts accordingly based off of these new fields. +To initialize both vesting and non-vesting accounts, the `GenesisAccount` struct +includes new fields: `Vesting`, `StartTime`, and `EndTime`. Accounts meant to be +of type `BaseAccount` or any non-vesting type have `Vesting = false`. The +genesis initialization logic (e.g. `initFromGenesisState`) must parse +and return the correct accounts accordingly based off of these fields. ```go type GenesisAccount struct { diff --git a/x/auth/spec/README.md b/x/auth/spec/README.md index f666e0923b2e..b8a96aaa7ce1 100644 --- a/x/auth/spec/README.md +++ b/x/auth/spec/README.md @@ -16,7 +16,7 @@ for an application, since the SDK itself is agnostic to these particulars. It co the ante handler, where all basic transaction validity checks (signatures, nonces, auxiliary fields) are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts. -This module will be used in the Cosmos Hub. +This module is used in the Cosmos Hub. ## Contents diff --git a/x/authz/spec/01_concepts.md b/x/authz/spec/01_concepts.md index 20ec9a7b6abb..7855ff5fc579 100644 --- a/x/authz/spec/01_concepts.md +++ b/x/authz/spec/01_concepts.md @@ -6,19 +6,19 @@ order: 1 ## Authorization and Grant -`x/authz` module defines interfaces and messages grant authorizations to perform actions +The `x/authz` module defines interfaces and messages grant authorizations to perform actions on behalf of one account to other accounts. The design is defined in the [ADR 030](../../../architecture/adr-030-authz-module.md). -Grant is an allowance to execute a Msg by the grantee on behalf of the granter. +A *grant* is an allowance to execute a Msg by the grantee on behalf of the granter. Authorization is an interface that must be implemented by a concrete authorization logic to validate and execute grants. Authorizations are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details. -**Note:** The authz module is different from the [auth](../modules/auth/) (authentication) module that is responsible for specifying the base transaction and account types. +**Note:** The authz module is different from the [auth (authentication)](../modules/auth/) module that is responsible for specifying the base transaction and account types. +++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/x/authz/authorizations.go#L11-L25 ## Built-in Authorizations -The Cosmos SDK `x/authz` module comes with following authorization types. +The Cosmos SDK `x/authz` module comes with following authorization types: ### SendAuthorization @@ -42,4 +42,4 @@ The Cosmos SDK `x/authz` module comes with following authorization types. ## Gas -In order to prevent DoS attacks, granting `StakeAuthorizaiton`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK will iterate over these lists and charge 10 gas for each validator in both of the lists. +In order to prevent DoS attacks, granting `StakeAuthorizaiton`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK iterates over these lists and charge 10 gas for each validator in both of the lists. diff --git a/x/authz/spec/03_messages.md b/x/authz/spec/03_messages.md index 736c5761b96f..7ff1b7548aca 100644 --- a/x/authz/spec/03_messages.md +++ b/x/authz/spec/03_messages.md @@ -9,7 +9,7 @@ In this section we describe the processing of messages for the authz module. ## MsgGrant An authorization grant is created using the `MsgGrant` message. -If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant will overwrite the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created. +If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant overwrites the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created. +++ https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-beta1/proto/cosmos/authz/v1beta1/tx.proto#L32-L37 diff --git a/x/authz/spec/05_client.md b/x/authz/spec/05_client.md index 2c40a6029ff7..a67007e59467 100644 --- a/x/authz/spec/05_client.md +++ b/x/authz/spec/05_client.md @@ -18,7 +18,7 @@ simd query authz --help #### grants -The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it will select grants only for that message type. +The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. ```bash simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags] @@ -99,7 +99,7 @@ A user can query the `authz` module using gRPC endpoints. ### Grants -The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it will select grants only for that message type. +The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. ```bash cosmos.authz.v1beta1.Query/Grants diff --git a/x/feegrant/simulation/genesis.go b/x/feegrant/simulation/genesis.go index 21e4e7079dea..d01e42b2b663 100644 --- a/x/feegrant/simulation/genesis.go +++ b/x/feegrant/simulation/genesis.go @@ -1,7 +1,6 @@ package simulation import ( - "fmt" "math/rand" "time" @@ -74,6 +73,5 @@ func RandomizedGenState(simState *module.SimulationState) { panic(err) } - fmt.Printf("Selected randomly generated %s parameters:\n%s\n", feegrant.ModuleName, bz) simState.GenState[feegrant.ModuleName] = bz } diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index df5b20c006c3..7931e2634c59 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -80,8 +80,6 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config - - clientCtx = client.ReadHomeFlag(clientCtx, cmd) config.SetRoot(clientCtx.HomeDir) chainID, _ := cmd.Flags().GetString(flags.FlagChainID)