Merge branch 'master' into adr-epoched-staking

This commit is contained in:
Dev Ojha 2021-02-25 21:48:57 -06:00 committed by GitHub
commit c0fd863ef1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
404 changed files with 12764 additions and 4349 deletions

58
.github/workflows/atlas.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: Atlas
# Atlas checks if a modules atlas manifest has been touched, if so it publishes the updated version
on:
push:
branches:
- master
paths:
- "x/**/atlas/*"
pull_request:
paths:
- "x/**/atlas/*"
jobs:
auth:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
id: git_diff
with:
PATTERNS: |
x/auth/atlas/**
- uses: marbar3778/atlas_action@main
with:
token: ${{ secrets.ATLAS_TOKEN }}
path: ./x/auth/atlas/atlas.toml
dry-run: ${{ github.event_name != 'pull_request' }}
if: env.GIT_DIFF
bank:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
id: git_diff
with:
PATTERNS: |
x/bank/atlas/**
- uses: marbar3778/atlas_action@main
with:
token: ${{ secrets.ATLAS_TOKEN }}
path: ./x/bank/atlas/atlas.toml
dry-run: ${{ github.event_name != 'pull_request' }}
if: env.GIT_DIFF
evidence:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: technote-space/get-diff-action@v4
id: git_diff
with:
PATTERNS: |
x/evidence/atlas/**
- uses: marbar3778/atlas_action@main
with:
token: ${{ secrets.ATLAS_TOKEN }}
path: ./x/evidence/atlas/manifest.toml
dry-run: ${{ github.event_name != 'pull_request' }}
if: env.GIT_DIFF

View File

@ -23,7 +23,7 @@ jobs:
- uses: golangci/golangci-lint-action@master
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.28
version: v1.37
args: --timeout 10m
github-token: ${{ secrets.github_token }}
if: env.GIT_DIFF

View File

@ -8,3 +8,19 @@ pull_request_rules:
merge:
method: squash
strict: true
- name: backport patches to v0.41.x branch
conditions:
- base=master
- label=backport/0.41.x (Stargate)
actions:
backport:
branches:
- release/v0.41.x
- name: backport patches to v0.39.x branch
conditions:
- base=master
- label=backport/0.39.x (Launchpad)
actions:
backport:
branches:
- launchpad/backports

View File

@ -38,35 +38,85 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Client Breaking Changes
* [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address.
* [\#8363](https://github.com/cosmos/cosmos-sdk/pull/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address.
* [\#8346](https://github.com/cosmos/cosmos-sdk/pull/8346) All CLI `tx` commands generate ServiceMsgs by default. Graceful Amino support has been added to ServiceMsgs to support signing legacy Msgs.
### API Breaking Changes
* (keyring) [#\8662](https://github.com/cosmos/cosmos-sdk/pull/8662) `NewMnemonic` now receives an additional `passphrase` argument to secure the key generated by the bip39 mnemonic.
* (x/bank) [\#8473](https://github.com/cosmos/cosmos-sdk/pull/8473) Bank keeper does not expose unsafe balance changing methods such as `SetBalance`, `SetSupply` etc.
* (x/staking) [\#8473](https://github.com/cosmos/cosmos-sdk/pull/8473) On genesis init, if non bonded pool and bonded pool balance, coming from the bank module, does not match what is saved in the staking state, the initialization will panic.
* (x/gov) [\#8473](https://github.com/cosmos/cosmos-sdk/pull/8473) On genesis init, if the gov module account balance, coming from bank module state, does not match the one in gov module state, the initialization will panic.
* (x/distribution) [\#8473](https://github.com/cosmos/cosmos-sdk/pull/8473) On genesis init, if the distribution module account balance, coming from bank module state, does not match the one in distribution module state, the initialization will panic.
* (client/keys) [\#8500](https://github.com/cosmos/cosmos-sdk/pull/8500) `InfoImporter` interface is removed from legacy keybase.
* [\#8629](https://github.com/cosmos/cosmos-sdk/pull/8629) Deprecated `SetFullFundraiserPath` from `Config` in favor of `SetPurpose` and `SetCoinType`.
### State Machine Breaking
* (x/{bank,distrib,gov,slashing,staking}) [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Store keys have been modified to allow for variable-length addresses.
* (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON for IBC messages in order to support Ledger text signing.
* (x/ibc) [\#8405](https://github.com/cosmos/cosmos-sdk/pull/8405) Refactor IBC client update governance proposals to use a substitute client to update a frozen or expired client.
* (x/evidence) [\#8502](https://github.com/cosmos/cosmos-sdk/pull/8502) `HandleEquivocationEvidence` persists the evidence to state.
* (x/gov) [\#7733](https://github.com/cosmos/cosmos-sdk/pull/7733) ADR 037 Implementation: Governance Split Votes
* (x/bank) [\#8656](https://github.com/cosmos/cosmos-sdk/pull/8656) balance and supply are now correctly tracked via `coin_spent`, `coin_received`, `coinbase` and `burn` events.
### Improvements
* (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata
* (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts
* (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method.
### Bug Fixes
* (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic`
* (x/evidence) [#8461](https://github.com/cosmos/cosmos-sdk/pull/8461) Fix bech32 prefix in evidence validator address conversion
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
* (server) [\#8399](https://github.com/cosmos/cosmos-sdk/pull/8399) fix gRPC-web flag default value
* (server) [\#8641](https://github.com/cosmos/cosmos-sdk/pull/8641) Fix Tendermint and application configuration reading from file
## [v0.41.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.3) - 2021-02-18
**IMPORTANT:** Due to a bug in the `v0.41.x` series with how evidence handles validator consensus addresses [\#8461](https://github.com/cosmos/cosmos-sdk/issues/8461), SDK based chains that are not using the default bech32 prefix (`cosmos`, aka all chains except for the Cosmos Hub) **should not** use this release or any release in the `v0.41.x` series. Please see [\#8668](https://github.com/cosmos/cosmos-sdk/issues/8668) for tracking & timeline for the v0.42.0 release, which will include a fix for this issue.
### Bug Fixes
* [\#8617](https://github.com/cosmos/cosmos-sdk/pull/8617) Fix build failures caused by a small API breakage introduced in tendermint v0.34.7.
## [v0.41.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.2) - 2021-02-18
### Improvements
* Bump tendermint dependency to v0.34.7.
## [v0.41.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.1) - 2021-02-17
### Bug Fixes
* (grpc) [\#8549](https://github.com/cosmos/cosmos-sdk/pull/8549) Make gRPC requests go through ABCI and disallow concurrency.
* (x/staking) [\#8546](https://github.com/cosmos/cosmos-sdk/pull/8546) Fix caching bug where concurrent calls to GetValidator could cause a node to crash
* (server) [\#8481](https://github.com/cosmos/cosmos-sdk/pull/8481) Don't create files when running `{appd} tendermint show-*` subcommands.
* (client/keys) [\#8436](https://github.com/cosmos/cosmos-sdk/pull/8436) Fix keybase->keyring keys migration.
* (crypto/hd) [\#8607](https://github.com/cosmos/cosmos-sdk/pull/8607) Make DerivePrivateKeyForPath error and not panic on trailing slashes.
### Improvements
* (x/ibc) [\#8458](https://github.com/cosmos/cosmos-sdk/pull/8458) Add `packet_connection` attribute to ibc events to enable relayer filtering
* (x/bank) [\#8479](https://github.com/cosmos/cosmos-sdk/pull/8479) Adittional client denom metadata validation for `base` and `display` denoms.
* (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks.
* [\#8396](https://github.com/cosmos/cosmos-sdk/pull/8396) Add support for ARM platform
* (x/bank) [\#8479](https://github.com/cosmos/cosmos-sdk/pull/8479) Aditional client denom metadata validation for `base` and `display` denoms.
* (codec/types) [\#8605](https://github.com/cosmos/cosmos-sdk/pull/8605) Avoid unnecessary allocations for NewAnyWithCustomTypeURL on error.
## [v0.41.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.41.0) - 2021-01-26
### State Machine Breaking
* (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON support for IBC MsgTransfer in order to support Ledger text signing transfer transactions.
* (x/ibc) [\#8404](https://github.com/cosmos/cosmos-sdk/pull/8404) Reorder IBC `ChanOpenAck` and `ChanOpenConfirm` handler execution to perform core handler first, followed by application callbacks.
### Bug Fixes
* (x/evidence) [#8461](https://github.com/cosmos/cosmos-sdk/pull/8461) Fix bech32 prefix in evidence validator address conversion
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
* (simapp) [\#8418](https://github.com/cosmos/cosmos-sdk/pull/8418) Add balance coin to supply when adding a new genesis account
* (x/bank) [\#8417](https://github.com/cosmos/cosmos-sdk/pull/8417) Validate balances and coin denom metadata on genesis
* (server) [\#8399](https://github.com/cosmos/cosmos-sdk/pull/8399) fix gRPC-web flag default value
* (client/keys) [\#8436](https://github.com/cosmos/cosmos-sdk/pull/8436) Fix key migration issue
* (server) [\#8481](https://github.com/cosmos/cosmos-sdk/pull/8481) Don't create
files when running `{appd} tendermint show-*` subcommands
## [v0.40.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.1) - 2021-01-19

View File

@ -3,6 +3,7 @@
PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation')
PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation')
VERSION := $(shell echo $(shell git describe --always) | sed 's/^v//')
TMVERSION := $(shell go list -m github.com/tendermint/tendermint | sed 's:.* ::')
COMMIT := $(shell git log -1 --format='%H')
LEDGER_ENABLED ?= true
BINDIR ?= $(GOPATH)/bin
@ -58,7 +59,8 @@ ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=sim \
-X github.com/cosmos/cosmos-sdk/version.AppName=simd \
-X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)"
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" \
-X github.com/tendermint/tendermint/version.TMCoreSemVer=$(TMVERSION)
# DB backend selection
ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS)))

View File

@ -2,6 +2,7 @@ package baseapp
import (
"fmt"
"reflect"
gogogrpc "github.com/gogo/protobuf/grpc"
abci "github.com/tendermint/tendermint/abci/types"
@ -12,13 +13,19 @@ import (
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
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
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
interfaceRegistry codectypes.InterfaceRegistry
serviceData []serviceData
}
@ -34,7 +41,8 @@ var _ gogogrpc.Server = &GRPCQueryRouter{}
// NewGRPCQueryRouter creates a new GRPCQueryRouter
func NewGRPCQueryRouter() *GRPCQueryRouter {
return &GRPCQueryRouter{
routes: map[string]GRPCQueryHandler{},
returnTypes: map[string]reflect.Type{},
routes: map[string]GRPCQueryHandler{},
}
}
@ -89,8 +97,17 @@ 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
}
@ -127,3 +144,16 @@ 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
}

View File

@ -2,67 +2,78 @@ package baseapp
import (
"context"
"strconv"
"reflect"
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"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/client"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/types/tx"
)
// 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(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")
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.
// 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)
}
return client.TxServiceBroadcast(grpcCtx, clientCtx, reqProto)
}
// Get height header from the request context, if present.
var height int64
if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) > 0 {
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
}
}
// 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)
// Case 2. Querying state.
inMd, _ := metadata.FromIncomingContext(grpcCtx)
abciRes, outMd, err := client.RunGRPCQuery(clientCtx, grpcCtx, info.FullMethod, req, inMd)
if err != nil {
return nil, err
}
// Attach the sdk.Context into the gRPC's context.Context.
grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx)
// Add relevant gRPC headers
if height == 0 {
height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest
// 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
}
md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10))
grpc.SetHeader(grpcCtx, md)
return handler(grpcCtx, req)
// 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
}
// Send the metadata header back. The metadata currently includes:
// - block height.
err = grpc.SendHeader(grpcCtx, outMd)
if err != nil {
return nil, err
}
return res, nil
}
// Loop through all services and methods, add the interceptor, and register

View File

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

View File

@ -234,9 +234,9 @@ func RegisterReflectionServiceHandlerClient(ctx context.Context, mux *runtime.Se
}
var (
pattern_ReflectionService_ListAllInterfaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ReflectionService_ListAllInterfaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces", "interface_name", "implementations"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ReflectionService_ListImplementations_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"cosmos", "base", "reflection", "v1beta1", "interfaces", "interface_name", "implementations"}, "", runtime.AssumeColonVerbOpt(false)))
)
var (

View File

@ -538,17 +538,17 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
}
var (
pattern_Service_GetNodeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "node_info"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetNodeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "node_info"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetSyncing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "syncing"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetSyncing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "syncing"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetLatestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "latest"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetLatestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "latest"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetBlockByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "height"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetBlockByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "height"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "latest"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "latest"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "height"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "height"}, "", runtime.AssumeColonVerbOpt(false)))
)
var (

View File

@ -104,6 +104,9 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestVa
outputValidatorsRes := &GetLatestValidatorSetResponse{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*Validator, len(validatorsRes.Validators)),
Pagination: &qtypes.PageResponse{
Total: validatorsRes.Total,
},
}
for i, validator := range validatorsRes.Validators {
@ -156,6 +159,7 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValida
outputValidatorsRes := &GetValidatorSetByHeightResponse{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*Validator, len(validatorsRes.Validators)),
Pagination: &qtypes.PageResponse{Total: validatorsRes.Total},
}
for i, validator := range validatorsRes.Validators {

View File

@ -131,32 +131,126 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() {
s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub)
}
func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() {
val := s.network.Validators[0]
func (s IntegrationTestSuite) TestLatestValidatorSet_GRPC() {
vals := s.network.Validators
testCases := []struct {
name string
req *tmservice.GetLatestValidatorSetRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "cannot be nil"},
{"no pagination", &tmservice.GetLatestValidatorSetRequest{}, false, ""},
{"with pagination", &tmservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
grpcRes, err := s.queryClient.GetLatestValidatorSet(context.Background(), tc.req)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)
s.Require().Len(grpcRes.Validators, len(vals))
s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals)))
content, ok := grpcRes.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
s.Require().Equal(true, ok)
s.Require().Equal(content, vals[0].PubKey)
}
})
}
}
// nil pagination
_, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{
Height: 1,
Pagination: nil,
})
s.Require().NoError(err)
func (s IntegrationTestSuite) TestLatestValidatorSet_GRPCGateway() {
vals := s.network.Validators
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest", vals[0].APIAddress), false, ""},
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress), true, "strconv.ParseUint"},
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=0&pagination.limit=2", vals[0].APIAddress), false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
res, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
if tc.expErr {
s.Require().Contains(string(res), tc.expErrMsg)
} else {
var result tmservice.GetLatestValidatorSetResponse
err = vals[0].ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
anyPub, err := codectypes.NewAnyWithValue(vals[0].PubKey)
s.Require().NoError(err)
s.Require().Equal(result.Validators[0].PubKey, anyPub)
}
})
}
}
_, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{
Height: 1,
Pagination: &qtypes.PageRequest{
Offset: 0,
Limit: 10,
}})
s.Require().NoError(err)
func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPC() {
vals := s.network.Validators
testCases := []struct {
name string
req *tmservice.GetValidatorSetByHeightRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "request cannot be nil"},
{"empty request", &tmservice.GetValidatorSetByHeightRequest{}, true, "height must be greater than 0"},
{"no pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1}, false, ""},
{"with pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1, Pagination: &qtypes.PageRequest{Offset: 0, Limit: 1}}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
grpcRes, err := s.queryClient.GetValidatorSetByHeight(context.Background(), tc.req)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)
s.Require().Len(grpcRes.Validators, len(vals))
s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals)))
}
})
}
}
// no pagination rest
_, err = rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", val.APIAddress, 1))
s.Require().NoError(err)
// rest query with pagination
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 1, 0, 1))
var validatorSetRes tmservice.GetValidatorSetByHeightResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes))
func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPCGateway() {
vals := s.network.Validators
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{"invalid height", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].APIAddress, -1), true, "height must be greater than 0"},
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].APIAddress, 1), false, ""},
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress, 1), true, "strconv.ParseUint"},
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=0&pagination.limit=2", vals[0].APIAddress, 1), false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
res, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
if tc.expErr {
s.Require().Contains(string(res), tc.expErrMsg)
} else {
var result tmservice.GetValidatorSetByHeightResponse
err = vals[0].ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
}
})
}
}
func TestIntegrationTestSuite(t *testing.T) {

View File

@ -24,86 +24,54 @@ var _ gogogrpc.ClientConn = Context{}
var protoCodec = encoding.GetCodec(proto.Name)
// Invoke implements the grpc ClientConn.Invoke method
func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, reply interface{}, opts ...grpc.CallOption) (err error) {
func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply interface{}, opts ...grpc.CallOption) (err error) {
// Two things can happen here:
// 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 args (it will panic unexpectedly).
if reflect.ValueOf(args).IsNil() {
// In both cases, we don't allow empty request req (it will panic unexpectedly).
if reflect.ValueOf(req).IsNil() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "request cannot be nil")
}
// Case 1. Broadcasting a Tx.
if isBroadcast(method) {
req, ok := args.(*tx.BroadcastTxRequest)
if reqProto, ok := req.(*tx.BroadcastTxRequest); ok {
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), args)
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), req)
}
res, ok := reply.(*tx.BroadcastTxResponse)
resProto, ok := reply.(*tx.BroadcastTxResponse)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), args)
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), req)
}
broadcastRes, err := TxServiceBroadcast(grpcCtx, ctx, req)
broadcastRes, err := TxServiceBroadcast(grpcCtx, ctx, reqProto)
if err != nil {
return err
}
*res = *broadcastRes
*resProto = *broadcastRes
return err
}
// Case 2. Querying state.
reqBz, err := protoCodec.Marshal(args)
inMd, _ := metadata.FromOutgoingContext(grpcCtx)
abciRes, outMd, err := RunGRPCQuery(ctx, grpcCtx, method, req, inMd)
if err != nil {
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 err
}
if height < 0 {
return sdkerrors.Wrapf(
sdkerrors.ErrInvalidRequest,
"client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader)
}
ctx = ctx.WithHeight(height)
}
req := abci.RequestQuery{
Path: method,
Data: reqBz,
}
res, err := ctx.QueryABCI(req)
err = protoCodec.Unmarshal(abciRes.Value, reply)
if err != nil {
return err
}
err = protoCodec.Unmarshal(res.Value, reply)
if err != nil {
return err
}
// Create header metadata. For now the headers contain:
// - block height
// 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(res.Height, 10))
for _, callOpt := range opts {
header, ok := callOpt.(grpc.HeaderCallOption)
if !ok {
continue
}
*header.HeaderAddr = md
*header.HeaderAddr = outMd
}
if ctx.InterfaceRegistry != nil {
@ -118,6 +86,47 @@ func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.Ca
return nil, fmt.Errorf("streaming rpc not supported")
}
func isBroadcast(method string) bool {
return method == "/cosmos.tx.v1beta1.Service/BroadcastTx"
// 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
}
// parse height header
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
}
if height < 0 {
return abci.ResponseQuery{}, nil, sdkerrors.Wrapf(
sdkerrors.ErrInvalidRequest,
"client.Context.Invoke: height (%d) from %q must be >= 0", height, grpctypes.GRPCBlockHeightHeader)
}
ctx = ctx.WithHeight(height)
}
abciReq := abci.RequestQuery{
Path: method,
Data: reqBz,
}
abciRes, err := ctx.QueryABCI(abciReq)
if err != nil {
return abci.ResponseQuery{}, nil, err
}
// Create header metadata. For now the headers contain:
// - block height
// 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))
return abciRes, md, nil
}

View File

@ -29,8 +29,8 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
bech32PrefixConsAddr := "terravalcons"
bech32PrefixConsPub := "terravalconspub"
config.SetPurpose(44)
config.SetCoinType(330)
config.SetFullFundraiserPath("44'/330'/0'/0/0")
config.SetBech32PrefixForAccount(bech32PrefixAccAddr, bech32PrefixAccPub)
config.SetBech32PrefixForValidator(bech32PrefixValAddr, bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(bech32PrefixConsAddr, bech32PrefixConsPub)
@ -77,8 +77,8 @@ func Test_runAddCmdLedgerWithCustomCoinType(t *testing.T) {
"terrapub1addwnpepqvpg7r26nl2pvqqern00m6s9uaax3hauu2rzg8qpjzq9hy6xve7sw0d84m6",
sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, key1.GetPubKey()))
config.SetPurpose(44)
config.SetCoinType(118)
config.SetFullFundraiserPath("44'/118'/0'/0/0")
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)

View File

@ -31,7 +31,7 @@ func Test_runDeleteCmd(t *testing.T) {
fakeKeyName1 := "runDeleteCmd_Key1"
fakeKeyName2 := "runDeleteCmd_Key2"
path := sdk.GetConfig().GetFullFundraiserPath()
path := sdk.GetConfig().GetFullBIP44Path()
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn)
require.NoError(t, err)
@ -39,7 +39,7 @@ func Test_runDeleteCmd(t *testing.T) {
_, err = kb.NewAccount(fakeKeyName1, testutil.TestMnemonic, "", path, hd.Secp256k1)
require.NoError(t, err)
_, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = kb.NewMnemonic(fakeKeyName2, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
cmd.SetArgs([]string{"blah", fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome)})

View File

@ -31,7 +31,7 @@ func Test_runExportCmd(t *testing.T) {
kb.Delete("keyname1") // nolint:errcheck
})
path := sdk.GetConfig().GetFullFundraiserPath()
path := sdk.GetConfig().GetFullBIP44Path()
_, err = kb.NewAccount("keyname1", testutil.TestMnemonic, "", path, hd.Secp256k1)
require.NoError(t, err)

View File

@ -30,7 +30,7 @@ func Test_runListCmd(t *testing.T) {
clientCtx := client.Context{}.WithKeyring(kb)
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
path := "" //sdk.GetConfig().GetFullFundraiserPath()
path := "" //sdk.GetConfig().GetFullBIP44Path()
_, err = kb.NewAccount("something", testutil.TestMnemonic, "", path, hd.Secp256k1)
require.NoError(t, err)

View File

@ -25,6 +25,7 @@ func addHTTPDeprecationHeaders(h http.Handler) http.Handler {
// WithHTTPDeprecationHeaders returns a new *mux.Router, identical to its input
// but with the addition of HTTP Deprecation headers. This is used to mark legacy
// amino REST endpoints as deprecated in the REST API.
// nolint: gocritic
func WithHTTPDeprecationHeaders(r *mux.Router) *mux.Router {
subRouter := r.NewRoute().Subrouter()
subRouter.Use(addHTTPDeprecationHeaders)

View File

@ -15,7 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/rest"
)
//BlockCommand returns the verified block data for a given heights
// BlockCommand returns the verified block data for a given heights
func BlockCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "block [height]",

View File

@ -22,7 +22,7 @@ import (
// TODO these next two functions feel kinda hacky based on their placement
//ValidatorCommand returns the validator set for a given height
// ValidatorCommand returns the validator set for a given height
func ValidatorCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "tendermint-validator-set [height]",
@ -79,12 +79,14 @@ type ValidatorOutput struct {
type ResultValidatorsOutput struct {
BlockHeight int64 `json:"block_height"`
Validators []ValidatorOutput `json:"validators"`
Total uint64 `json:"total"`
}
func (rvo ResultValidatorsOutput) String() string {
var b strings.Builder
b.WriteString(fmt.Sprintf("block height: %d\n", rvo.BlockHeight))
b.WriteString(fmt.Sprintf("total count: %d\n", rvo.Total))
for _, val := range rvo.Validators {
b.WriteString(
@ -129,9 +131,15 @@ func GetValidators(ctx context.Context, clientCtx client.Context, height *int64,
return ResultValidatorsOutput{}, err
}
total := validatorsRes.Total
if validatorsRes.Total < 0 {
total = 0
}
outputValidatorsRes := ResultValidatorsOutput{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
Total: uint64(total),
}
for i := 0; i < len(validatorsRes.Validators); i++ {

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
@ -23,14 +24,13 @@ import (
const (
memo = "waboom"
gas = uint64(10000)
timeoutHeight = 5
timeoutHeight = uint64(5)
)
var (
fee = types.NewCoins(types.NewInt64Coin("bam", 100))
_, pub1, addr1 = testdata.KeyTestPubAddr()
_, _, addr2 = testdata.KeyTestPubAddr()
msg = banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 10000)))
sig = signing2.SignatureV2{
PubKey: pub1,
Data: &signing2.SingleSignatureData{
@ -38,13 +38,18 @@ var (
Signature: []byte("dummy"),
},
}
msg0 = banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 1)))
msg1 = sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 2))),
}
)
func buildTestTx(t *testing.T, builder client.TxBuilder) {
builder.SetMemo(memo)
builder.SetGasLimit(gas)
builder.SetFeeAmount(fee)
err := builder.SetMsgs(msg)
err := builder.SetMsgs(msg0, msg1)
require.NoError(t, err)
err = builder.SetSignatures(sig)
require.NoError(t, err)
@ -75,11 +80,15 @@ func (s *TestSuite) TestCopyTx() {
protoBuilder2 := s.protoCfg.NewTxBuilder()
err = tx2.CopyTx(aminoBuilder.GetTx(), protoBuilder2, false)
s.Require().NoError(err)
bz, err := s.protoCfg.TxEncoder()(protoBuilder.GetTx())
// Check sigs, signers and msgs.
sigsV2_1, err := protoBuilder.GetTx().GetSignaturesV2()
s.Require().NoError(err)
bz2, err := s.protoCfg.TxEncoder()(protoBuilder2.GetTx())
sigsV2_2, err := protoBuilder2.GetTx().GetSignaturesV2()
s.Require().NoError(err)
s.Require().Equal(bz, bz2)
s.Require().Equal(sigsV2_1, sigsV2_2)
s.Require().Equal(protoBuilder.GetTx().GetSigners(), protoBuilder2.GetTx().GetSigners())
s.Require().Equal(protoBuilder.GetTx().GetMsgs()[0], protoBuilder2.GetTx().GetMsgs()[0])
s.Require().Equal(protoBuilder.GetTx().GetMsgs()[1].(sdk.ServiceMsg).Request, protoBuilder2.GetTx().GetMsgs()[1]) // We lose the "ServiceMsg" information
// amino -> proto -> amino
aminoBuilder = s.aminoCfg.NewTxBuilder()
@ -90,11 +99,15 @@ func (s *TestSuite) TestCopyTx() {
aminoBuilder2 := s.aminoCfg.NewTxBuilder()
err = tx2.CopyTx(protoBuilder.GetTx(), aminoBuilder2, false)
s.Require().NoError(err)
bz, err = s.aminoCfg.TxEncoder()(aminoBuilder.GetTx())
// Check sigs, signers, and msgs
sigsV2_1, err = aminoBuilder.GetTx().GetSignaturesV2()
s.Require().NoError(err)
bz2, err = s.aminoCfg.TxEncoder()(aminoBuilder2.GetTx())
sigsV2_2, err = aminoBuilder2.GetTx().GetSignaturesV2()
s.Require().NoError(err)
s.Require().Equal(bz, bz2)
s.Require().Equal(sigsV2_1, sigsV2_2)
s.Require().Equal(aminoBuilder.GetTx().GetSigners(), aminoBuilder2.GetTx().GetSigners())
s.Require().Equal(aminoBuilder.GetTx().GetMsgs()[0], aminoBuilder2.GetTx().GetMsgs()[0])
s.Require().Equal(aminoBuilder.GetTx().GetMsgs()[1], aminoBuilder2.GetTx().GetMsgs()[1]) // We lose the "ServiceMsg" information
}
func (s *TestSuite) TestConvertTxToStdTx() {
@ -106,7 +119,8 @@ func (s *TestSuite) TestConvertTxToStdTx() {
s.Require().Equal(memo, stdTx.Memo)
s.Require().Equal(gas, stdTx.Fee.Gas)
s.Require().Equal(fee, stdTx.Fee.Amount)
s.Require().Equal(msg, stdTx.Msgs[0])
s.Require().Equal(msg0, stdTx.Msgs[0])
s.Require().Equal(msg1.Request, stdTx.Msgs[1])
s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight)
s.Require().Equal(sig.PubKey, stdTx.Signatures[0].PubKey)
s.Require().Equal(sig.Data.(*signing2.SingleSignatureData).Signature, stdTx.Signatures[0].Signature)
@ -125,7 +139,8 @@ func (s *TestSuite) TestConvertTxToStdTx() {
s.Require().Equal(memo, stdTx.Memo)
s.Require().Equal(gas, stdTx.Fee.Gas)
s.Require().Equal(fee, stdTx.Fee.Amount)
s.Require().Equal(msg, stdTx.Msgs[0])
s.Require().Equal(msg0, stdTx.Msgs[0])
s.Require().Equal(msg1.Request, stdTx.Msgs[1])
s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight)
s.Require().Empty(stdTx.Signatures)
@ -158,3 +173,7 @@ func (s *TestSuite) TestConvertAndEncodeStdTx() {
s.Require().NoError(err)
s.Require().Equal(stdTx, decodedTx)
}
func TestTestSuite(t *testing.T) {
suite.Run(t, new(TestSuite))
}

View File

@ -132,10 +132,10 @@ func TestSign(t *testing.T) {
var from2 = "test_key2"
// create a new key using a mnemonic generator and test if we can reuse seed to recreate that account
_, seed, err := kr.NewMnemonic(from1, keyring.English, path, hd.Secp256k1)
_, seed, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
requireT.NoError(err)
requireT.NoError(kr.Delete(from1))
info1, _, err := kr.NewMnemonic(from1, keyring.English, path, hd.Secp256k1)
info1, _, err := kr.NewMnemonic(from1, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
requireT.NoError(err)
info2, err := kr.NewAccount(from2, seed, "", path, hd.Secp256k1)

View File

@ -13,8 +13,8 @@ import (
"github.com/cosmos/cosmos-sdk/codec/types"
)
// deprecated: LegacyAmino defines a wrapper for an Amino codec that properly handles protobuf
// types with Any's
// LegacyAmino defines a wrapper for an Amino codec that properly
// handles protobuf types with Any's. Deprecated.
type LegacyAmino struct {
Amino *amino.Codec
}

View File

@ -71,11 +71,14 @@ func NewAnyWithValue(v proto.Message) (*Any, error) {
// into the protobuf Any serialization. For simple marshaling you should use NewAnyWithValue.
func NewAnyWithCustomTypeURL(v proto.Message, typeURL string) (*Any, error) {
bz, err := proto.Marshal(v)
if err != nil {
return nil, err
}
return &Any{
TypeUrl: typeURL,
Value: bz,
cachedValue: v,
}, err
}, nil
}
// UnsafePackAny packs the value x in the Any and instead of returning the error

68
codec/types/any_test.go Normal file
View File

@ -0,0 +1,68 @@
package types_test
import (
"fmt"
"runtime"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
)
type errOnMarshal struct {
testdata.Dog
}
var _ proto.Message = (*errOnMarshal)(nil)
var errAlways = fmt.Errorf("always erroring")
func (eom *errOnMarshal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return nil, errAlways
}
const fauxURL = "/anyhere"
var eom = &errOnMarshal{}
// Ensure that returning an error doesn't suddenly allocate and waste bytes.
// See https://github.com/cosmos/cosmos-sdk/issues/8537
func TestNewAnyWithCustomTypeURLWithErrorNoAllocation(t *testing.T) {
var ms1, ms2 runtime.MemStats
runtime.ReadMemStats(&ms1)
any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL)
runtime.ReadMemStats(&ms2)
// Ensure that no fresh allocation was made.
if diff := ms2.HeapAlloc - ms1.HeapAlloc; diff > 0 {
t.Errorf("Unexpected allocation of %d bytes", diff)
}
if err == nil {
t.Fatal("err wasn't returned")
}
if any != nil {
t.Fatalf("Unexpectedly got a non-nil Any value: %v", any)
}
}
var sink interface{}
func BenchmarkNewAnyWithCustomTypeURLWithErrorReturned(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL)
if err == nil {
b.Fatal("err wasn't returned")
}
if any != nil {
b.Fatalf("Unexpectedly got a non-nil Any value: %v", any)
}
sink = any
}
if sink == nil {
b.Fatal("benchmark didn't run")
}
sink = (interface{})(nil)
}

View File

@ -73,7 +73,7 @@ func TestArmorUnarmorPubKey(t *testing.T) {
cstore := keyring.NewInMemory()
// Add keys and see they return in alphabetical order
info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, hd.Secp256k1)
info, _, err := cstore.NewMnemonic("Bob", keyring.English, types.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "")
pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored)

View File

@ -26,7 +26,7 @@ func RegisterCrypto(cdc *codec.LegacyAmino) {
cdc.RegisterInterface((*cryptotypes.PrivKey)(nil), nil)
cdc.RegisterConcrete(sr25519.PrivKey{},
sr25519.PrivKeyName, nil)
cdc.RegisterConcrete(&ed25519.PrivKey{},
cdc.RegisterConcrete(&ed25519.PrivKey{}, //nolint:staticcheck
ed25519.PrivKeyName, nil)
cdc.RegisterConcrete(&secp256k1.PrivKey{},
secp256k1.PrivKeyName, nil)

View File

@ -6,6 +6,7 @@ import (
"encoding/binary"
"fmt"
"math/big"
"path/filepath"
"strconv"
"strings"
@ -177,6 +178,9 @@ func ComputeMastersFromSeed(seed []byte) (secret [32]byte, chainCode [32]byte) {
// DerivePrivateKeyForPath derives the private key by following the BIP 32/44 path from privKeyBytes,
// using the given chainCode.
func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]byte, error) {
// First step is to trim the right end path separator lest we panic.
// See issue https://github.com/cosmos/cosmos-sdk/issues/8557
path = strings.TrimRightFunc(path, func(r rune) bool { return r == filepath.Separator })
data := privKeyBytes
parts := strings.Split(path, "/")
@ -187,7 +191,10 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
parts = parts[1:]
}
for _, part := range parts {
for i, part := range parts {
if part == "" {
return nil, fmt.Errorf("path %q with split element #%d is an empty string", part, i)
}
// do we have an apostrophe?
harden := part[len(part)-1:] == "'"
// harden == private derivation, else public derivation:

View File

@ -281,3 +281,26 @@ func ExampleSomeBIP32TestVecs() {
//
// c4c11d8c03625515905d7e89d25dfc66126fbc629ecca6db489a1a72fc4bda78
}
// Ensuring that we don't crash if values have trailing slashes
// See issue https://github.com/cosmos/cosmos-sdk/issues/8557.
func TestDerivePrivateKeyForPathDoNotCrash(t *testing.T) {
paths := []string{
"m/5/",
"m/5",
"/44",
"m//5",
"m/0/7",
"/",
"m /0/7", // Test case from fuzzer
" / ", // Test case from fuzzer
"m///7//////",
}
for _, path := range paths {
path := path
t.Run(path, func(t *testing.T) {
hd.DerivePrivateKeyForPath([32]byte{}, [32]byte{}, path)
})
}
}

View File

@ -64,14 +64,17 @@ type Keyring interface {
Delete(uid string) error
DeleteByAddress(address sdk.Address) error
// NewMnemonic generates a new mnemonic, derives a hierarchical deterministic
// key from that, and persists it to the storage. Returns the generated mnemonic and the key
// Info. It returns an error if it fails to generate a key for the given algo type, or if
// another key is already stored under the same name.
NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error)
// NewMnemonic generates a new mnemonic, derives a hierarchical deterministic key from it, and
// persists the key to storage. Returns the generated mnemonic and the key Info.
// It returns an error if it fails to generate a key for the given algo type, or if
// another key is already stored under the same name or address.
//
// A passphrase set to the empty string will set the passphrase to the DefaultBIP39Passphrase value.
NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error)
// NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it.
NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error)
// It fails if there is an existing key Info with the same address.
NewAccount(uid, mnemonic, bip39Passphrase, hdPath string, algo SignatureAlgo) (Info, error)
// SaveLedgerKey retrieves a public key reference from a Ledger device and persists it.
SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error)
@ -477,7 +480,7 @@ func (ks keystore) List() ([]Info, error) {
return res, nil
}
func (ks keystore) NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) {
func (ks keystore) NewMnemonic(uid string, language Language, hdPath, bip39Passphrase string, algo SignatureAlgo) (Info, string, error) {
if language != English {
return nil, "", ErrUnsupportedLanguage
}
@ -498,12 +501,16 @@ func (ks keystore) NewMnemonic(uid string, language Language, hdPath string, alg
return nil, "", err
}
info, err := ks.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, hdPath, algo)
if bip39Passphrase == "" {
bip39Passphrase = DefaultBIP39Passphrase
}
info, err := ks.NewAccount(uid, mnemonic, bip39Passphrase, hdPath, algo)
if err != nil {
return nil, "", err
}
return info, mnemonic, err
return info, mnemonic, nil
}
func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase string, hdPath string, algo SignatureAlgo) (Info, error) {
@ -519,6 +526,13 @@ func (ks keystore) NewAccount(uid string, mnemonic string, bip39Passphrase strin
privKey := algo.Generate()(derivedPriv)
// check if the a key already exists with the same address and return an error
// if found
address := sdk.AccAddress(privKey.PubKey().Address())
if _, err := ks.KeyByAddress(address); err == nil {
return nil, fmt.Errorf("account with address %s already exists in keyring, delete the key first if you want to recreate it", address)
}
return ks.writeLocalKey(uid, privKey, algo.Name())
}

View File

@ -80,7 +80,7 @@ func TestSignVerifyKeyRingWithLedger(t *testing.T) {
require.True(t, i1.GetPubKey().VerifySignature(d1, s1))
require.True(t, bytes.Equal(s1, s2))
localInfo, _, err := kb.NewMnemonic("test", English, types.FullFundraiserPath, hd.Secp256k1)
localInfo, _, err := kb.NewMnemonic("test", English, types.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
_, _, err = SignWithLedger(localInfo, d1)
require.Error(t, err)

View File

@ -42,7 +42,7 @@ func TestNewKeyring(t *testing.T) {
require.Equal(t, "unknown keyring backend fuzzy", err.Error())
mockIn.Reset("password\npassword\n")
info, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, hd.Secp256k1)
info, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
require.Equal(t, "foo", info.GetName())
}
@ -59,17 +59,17 @@ func TestKeyManagementKeyRing(t *testing.T) {
require.Nil(t, err)
require.Empty(t, l)
_, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, notSupportedAlgo{})
_, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
require.Error(t, err, "ed25519 keys are currently not supported by keybase")
// create some keys
_, err = kb.Key(n1)
require.Error(t, err)
i, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
i, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.NoError(t, err)
require.Equal(t, n1, i.GetName())
_, _, err = kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo)
_, _, err = kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.NoError(t, err)
// we can get these keys
@ -137,10 +137,10 @@ func TestSignVerifyKeyRing(t *testing.T) {
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
// create two users and get their info
i1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
i1, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err)
i2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo)
i2, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err)
// let's try to sign some messages
@ -209,7 +209,7 @@ func TestExportImportKeyRing(t *testing.T) {
kb, err := New("keybasename", "test", t.TempDir(), nil)
require.NoError(t, err)
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1)
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
require.Equal(t, info.GetName(), "john")
@ -243,7 +243,7 @@ func TestExportImportPubKeyKeyRing(t *testing.T) {
algo := hd.Secp256k1
// CreateMnemonic a private-public key pair and ensure consistency
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, algo)
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err)
require.NotEqual(t, info, "")
require.Equal(t, info.GetName(), "john")
@ -285,7 +285,7 @@ func TestAdvancedKeyManagementKeyRing(t *testing.T) {
n1, n2 := "old-name", "new name"
// make sure key works with initial password
_, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
_, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err, "%+v", err)
_, err = kb.ExportPubKeyArmor(n1 + ".notreal")
@ -320,7 +320,7 @@ func TestSeedPhraseKeyRing(t *testing.T) {
n1, n2 := "lost-key", "found-again"
// make sure key works with initial password
info, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
info, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err, "%+v", err)
require.Equal(t, n1, info.GetName())
require.NotEmpty(t, mnemonic)
@ -345,7 +345,7 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) {
kb, err := New("keybasename", "test", t.TempDir(), nil)
require.NoError(t, err)
_, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
keystr, err := kb.ExportPrivKeyArmor("john", "somepassword")
@ -372,7 +372,7 @@ func TestKeyringKeybaseExportImportPrivKey(t *testing.T) {
func TestInMemoryLanguage(t *testing.T) {
kb := NewInMemory()
_, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.Error(t, err)
require.Equal(t, "unsupported language: only english is supported", err.Error())
}
@ -412,17 +412,17 @@ func TestInMemoryKeyManagement(t *testing.T) {
require.Nil(t, err)
require.Empty(t, l)
_, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, notSupportedAlgo{})
_, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
require.Error(t, err, "ed25519 keys are currently not supported by keybase")
// create some keys
_, err = cstore.Key(n1)
require.Error(t, err)
i, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
i, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.NoError(t, err)
require.Equal(t, n1, i.GetName())
_, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo)
_, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.NoError(t, err)
// we can get these keys
@ -492,10 +492,10 @@ func TestInMemorySignVerify(t *testing.T) {
n1, n2, n3 := "some dude", "a dudette", "dude-ish"
// create two users and get their info
i1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
i1, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err)
i2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, algo)
i2, _, err := cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err)
// let's try to sign some messages
@ -566,7 +566,7 @@ func TestInMemoryExportImport(t *testing.T) {
// make the storage with reasonable defaults
cstore := NewInMemory()
info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1)
info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
require.Equal(t, info.GetName(), "john")
@ -596,7 +596,7 @@ func TestInMemoryExportImport(t *testing.T) {
func TestInMemoryExportImportPrivKey(t *testing.T) {
kb := NewInMemory()
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1)
info, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
require.Equal(t, info.GetName(), "john")
priv1, err := kb.Key("john")
@ -624,7 +624,7 @@ func TestInMemoryExportImportPubKey(t *testing.T) {
cstore := NewInMemory()
// CreateMnemonic a private-public key pair and ensure consistency
info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, hd.Secp256k1)
info, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.Nil(t, err)
require.NotEqual(t, info, "")
require.Equal(t, info.GetName(), "john")
@ -663,7 +663,7 @@ func TestInMemoryAdvancedKeyManagement(t *testing.T) {
n1, n2 := "old-name", "new name"
// make sure key works with initial password
_, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
_, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err, "%+v", err)
// exporting requires the proper name and passphrase
@ -698,7 +698,7 @@ func TestInMemorySeedPhrase(t *testing.T) {
n1, n2 := "lost-key", "found-again"
// make sure key works with initial password
info, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, algo)
info, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo)
require.Nil(t, err, "%+v", err)
require.Equal(t, n1, info.GetName())
require.NotEmpty(t, mnemonic)
@ -724,7 +724,7 @@ func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) {
require.NoError(t, err)
// Given we create a mnemonic
_, seed, err := kr.NewMnemonic("test", English, "", hd.Secp256k1)
_, seed, err := kr.NewMnemonic("test", English, "", DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
require.NoError(t, kr.Delete("test"))
@ -745,7 +745,7 @@ func ExampleNew() {
sec := hd.Secp256k1
// Add keys and see they return in alphabetical order
bob, _, err := cstore.NewMnemonic("Bob", English, sdk.FullFundraiserPath, sec)
bob, _, err := cstore.NewMnemonic("Bob", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
if err != nil {
// this should never happen
fmt.Println(err)
@ -753,8 +753,8 @@ func ExampleNew() {
// return info here just like in List
fmt.Println(bob.GetName())
}
_, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, sec)
_, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, sec)
_, _, _ = cstore.NewMnemonic("Alice", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
_, _, _ = cstore.NewMnemonic("Carl", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, sec)
info, _ := cstore.List()
for _, i := range info {
fmt.Println(i.GetName())
@ -799,16 +799,16 @@ func TestAltKeyring_List(t *testing.T) {
require.Empty(t, list)
// Fails on creating unsupported pubKeyType
_, _, err = keyring.NewMnemonic("failing", English, sdk.FullFundraiserPath, notSupportedAlgo{})
_, _, err = keyring.NewMnemonic("failing", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error())
// Create 3 keys
uid1, uid2, uid3 := "Zkey", "Bkey", "Rkey"
_, _, err = keyring.NewMnemonic(uid1, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
_, _, err = keyring.NewMnemonic(uid2, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
_, _, err = keyring.NewMnemonic(uid3, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid3, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
list, err = keyring.List()
@ -852,7 +852,7 @@ func TestAltKeyring_Get(t *testing.T) {
require.NoError(t, err)
uid := someKey
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
key, err := keyring.Key(uid)
@ -865,7 +865,7 @@ func TestAltKeyring_KeyByAddress(t *testing.T) {
require.NoError(t, err)
uid := someKey
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
key, err := keyring.KeyByAddress(mnemonic.GetAddress())
@ -878,7 +878,7 @@ func TestAltKeyring_Delete(t *testing.T) {
require.NoError(t, err)
uid := someKey
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
list, err := keyring.List()
@ -898,7 +898,7 @@ func TestAltKeyring_DeleteByAddress(t *testing.T) {
require.NoError(t, err)
uid := someKey
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
list, err := keyring.List()
@ -940,9 +940,9 @@ func TestAltKeyring_SaveMultisig(t *testing.T) {
keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil)
require.NoError(t, err)
mnemonic1, _, err := keyring.NewMnemonic("key1", English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic1, _, err := keyring.NewMnemonic("key1", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
mnemonic2, _, err := keyring.NewMnemonic("key2", English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic2, _, err := keyring.NewMnemonic("key2", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
key := "multi"
@ -969,7 +969,7 @@ func TestAltKeyring_Sign(t *testing.T) {
require.NoError(t, err)
uid := "jack"
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
msg := []byte("some message")
@ -985,7 +985,7 @@ func TestAltKeyring_SignByAddress(t *testing.T) {
require.NoError(t, err)
uid := "jack"
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
msg := []byte("some message")
@ -1001,7 +1001,7 @@ func TestAltKeyring_ImportExportPrivKey(t *testing.T) {
require.NoError(t, err)
uid := theID
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
passphrase := "somePass"
@ -1027,7 +1027,7 @@ func TestAltKeyring_ImportExportPrivKey_ByAddress(t *testing.T) {
require.NoError(t, err)
uid := theID
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
passphrase := "somePass"
@ -1054,7 +1054,7 @@ func TestAltKeyring_ImportExportPubKey(t *testing.T) {
require.NoError(t, err)
uid := theID
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
armor, err := keyring.ExportPubKeyArmor(uid)
@ -1076,7 +1076,7 @@ func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) {
require.NoError(t, err)
uid := theID
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
mnemonic, _, err := keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
armor, err := keyring.ExportPubKeyArmorByAddress(mnemonic.GetAddress())
@ -1099,7 +1099,7 @@ func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) {
uid := theID
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
unsafeKeyring := NewUnsafe(keyring)
@ -1121,11 +1121,11 @@ func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) {
require.NoError(t, err)
// should fail when using unsupported signing algorythm.
_, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, notSupportedAlgo{})
_, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
require.EqualError(t, err, "unsupported signing algo")
// but works with default signing algo.
_, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, hd.Secp256k1)
_, _, err = keyring.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)
// but we can create a new keybase with our provided algos.
@ -1137,7 +1137,7 @@ func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) {
require.NoError(t, err)
// now this new keyring does not fail when signing with provided algo
_, _, err = keyring2.NewMnemonic("test", English, sdk.FullFundraiserPath, notSupportedAlgo{})
_, _, err = keyring2.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{})
require.NoError(t, err)
}

View File

@ -42,7 +42,7 @@ var _ LegacyKeybase = dbKeybase{}
// dbKeybase combines encryption and storage implementation to provide a
// full-featured key manager.
//
// NOTE: dbKeybase will be deprecated in favor of keyringKeybase.
// Deprecated: dbKeybase will be removed in favor of keyringKeybase.
type dbKeybase struct {
db dbm.DB
}

View File

@ -116,7 +116,8 @@ func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error {
return privKey.UnmarshalAmino(bz)
}
// GenPrivKey generates a new ed25519 private key.
// GenPrivKey generates a new ed25519 private key. These ed25519 keys must not
// be used in SDK apps except in a tendermint validator context.
// It uses OS randomness in conjunction with the current global random seed
// in tendermint/libs/common to generate the private key.
func GenPrivKey() *PrivKey {
@ -137,6 +138,7 @@ func genPrivKey(rand io.Reader) *PrivKey {
// GenPrivKeyFromSecret hashes the secret with SHA2, and uses
// that 32 byte output to create the private key.
// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context.
// NOTE: secret should be the output of a KDF like bcrypt,
// if it's derived from user input.
func GenPrivKeyFromSecret(secret []byte) *PrivKey {
@ -151,10 +153,14 @@ var _ cryptotypes.PubKey = &PubKey{}
var _ codec.AminoMarshaler = &PubKey{}
// Address is the SHA256-20 of the raw pubkey bytes.
// It doesn't implement ADR-28 addresses and it must not be used
// in SDK except in a tendermint validator context.
func (pubKey *PubKey) Address() crypto.Address {
if len(pubKey.Key) != PubKeySize {
panic("pubkey is incorrect size")
}
// For ADR-28 compatible address we would need to
// return address.Hash(proto.MessageName(pubKey), pubKey.Key)
return crypto.Address(tmhash.SumTruncated(pubKey.Key))
}

View File

@ -84,6 +84,12 @@ func TestPubKeyEquals(t *testing.T) {
}
}
func TestAddressEd25519(t *testing.T) {
pk := ed25519.PubKey{[]byte{125, 80, 29, 208, 159, 53, 119, 198, 73, 53, 187, 33, 199, 144, 62, 255, 1, 235, 117, 96, 128, 211, 17, 45, 34, 64, 189, 165, 33, 182, 54, 206}}
addr := pk.Address()
require.Len(t, addr, 20, "Address must be 20 bytes long")
}
func TestPrivKeyEquals(t *testing.T) {
ed25519PrivKey := ed25519.GenPrivKey()

View File

@ -24,11 +24,11 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// PubKey defines a ed25519 public key
// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte
// if the y-coordinate is the lexicographically largest of the two associated with
// the x-coordinate. Otherwise the first byte is a 0x03.
// This prefix is followed with the x-coordinate.
// PubKey is an ed25519 public key for handling Tendermint keys in SDK.
// It's needed for Any serialization and SDK compatibility.
// It must not be used in a non Tendermint key context because it doesn't implement
// ADR-28. Nevertheless, you will like to use ed25519 in app user level
// then you must create a new proto message and follow ADR-28 for Address construction.
type PubKey struct {
Key crypto_ed25519.PublicKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/ed25519.PublicKey" json:"key,omitempty"`
}
@ -72,7 +72,8 @@ func (m *PubKey) GetKey() crypto_ed25519.PublicKey {
return nil
}
// PrivKey defines a ed25519 private key.
// Deprecated: PrivKey defines a ed25519 private key.
// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context.
type PrivKey struct {
Key crypto_ed25519.PrivateKey `protobuf:"bytes,1,opt,name=key,proto3,casttype=crypto/ed25519.PrivateKey" json:"key,omitempty"`
}

View File

@ -15,6 +15,8 @@ var _ multisigtypes.PubKey = &LegacyAminoPubKey{}
var _ types.UnpackInterfacesMessage = &LegacyAminoPubKey{}
// NewLegacyAminoPubKey returns a new LegacyAminoPubKey.
// Multisig can be constructed with multiple same keys - it will increase the power of
// the owner of that key (he will still need to add multiple signatures in the right order).
// Panics if len(pubKeys) < k or 0 >= k.
func NewLegacyAminoPubKey(k int, pubKeys []cryptotypes.PubKey) *LegacyAminoPubKey {
if k <= 0 {
@ -40,7 +42,11 @@ func (m *LegacyAminoPubKey) Bytes() []byte {
return AminoCdc.MustMarshalBinaryBare(m)
}
// VerifyMultisignature implements the multisigtypes.PubKey VerifyMultisignature method
// VerifyMultisignature implements the multisigtypes.PubKey VerifyMultisignature method.
// The signatures must be added in an order corresponding to the public keys order in
// LegacyAminoPubKey. It's OK to have multiple same keys in the multisig - it will increase
// the power of the owner of that key - in that case the signer will still need to append
// multiple same signatures in the right order.
func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetSignBytesFunc, sig *signing.MultiSignatureData) error {
bitarray := sig.BitArray
sigs := sig.Signatures
@ -48,7 +54,7 @@ func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetS
pubKeys := m.GetPubKeys()
// ensure bit array is the correct size
if len(pubKeys) != size {
return fmt.Errorf("bit array size is incorrect %d", len(pubKeys))
return fmt.Errorf("bit array size is incorrect, expecting: %d", len(pubKeys))
}
// ensure size of signature list
if len(sigs) < int(m.Threshold) || len(sigs) > size {
@ -56,7 +62,7 @@ func (m *LegacyAminoPubKey) VerifyMultisignature(getSignBytes multisigtypes.GetS
}
// ensure at least k signatures are set
if bitarray.NumTrueBitsBefore(size) < int(m.Threshold) {
return fmt.Errorf("minimum number of signatures not set, have %d, expected %d", bitarray.NumTrueBitsBefore(size), int(m.Threshold))
return fmt.Errorf("not enough signatures set, have %d, expected %d", bitarray.NumTrueBitsBefore(size), int(m.Threshold))
}
// index in the list of signatures which we are concerned with.
sigIndex := 0

View File

@ -15,6 +15,15 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
)
func TestNewMultiSig(t *testing.T) {
require := require.New(t)
pk1 := secp256k1.GenPrivKey().PubKey()
pks := []cryptotypes.PubKey{pk1, pk1}
require.NotNil(kmultisig.NewLegacyAminoPubKey(1, pks),
"Should support not unique public keys")
}
func TestAddress(t *testing.T) {
msg := []byte{1, 2, 3, 4}
pubKeys, _ := generatePubKeysAndSignatures(5, msg)
@ -85,21 +94,20 @@ func TestVerifyMultisignature(t *testing.T) {
testCases := []struct {
msg string
malleate func()
malleate func(*require.Assertions)
expectPass bool
}{
{
"nested multisignature",
func() {
func(require *require.Assertions) {
genPk, genSig := generateNestedMultiSignature(3, msg)
sig = genSig
pk = genPk
},
true,
},
{
}, {
"wrong size for sig bit array",
func() {
func(require *require.Assertions) {
pubKeys, _ := generatePubKeysAndSignatures(3, msg)
pk = kmultisig.NewLegacyAminoPubKey(3, pubKeys)
sig = multisig.NewMultisig(1)
@ -108,7 +116,7 @@ func TestVerifyMultisignature(t *testing.T) {
},
{
"single signature data, expects the first k signatures to be valid",
func() {
func(require *require.Assertions) {
k := 2
signingIndices := []int{0, 3, 1}
pubKeys, sigs := generatePubKeysAndSignatures(5, msg)
@ -119,32 +127,26 @@ func TestVerifyMultisignature(t *testing.T) {
for i := 0; i < k-1; i++ {
signingIndex := signingIndices[i]
require.NoError(
t,
multisig.AddSignatureFromPubKey(sig, sigs[signingIndex], pubKeys[signingIndex], pubKeys),
)
require.Error(
t,
pk.VerifyMultisignature(signBytesFn, sig),
"multisig passed when i < k, i %d", i,
)
require.NoError(
t,
multisig.AddSignatureFromPubKey(sig, sigs[signingIndex], pubKeys[signingIndex], pubKeys),
)
require.Equal(
t,
i+1,
len(sig.Signatures),
"adding a signature for the same pubkey twice increased signature count by 2, index %d", i,
)
}
require.Error(
t,
pk.VerifyMultisignature(signBytesFn, sig),
"multisig passed with k - 1 sigs",
)
require.NoError(
t,
multisig.AddSignatureFromPubKey(
sig,
sigs[signingIndices[k]],
@ -153,30 +155,50 @@ func TestVerifyMultisignature(t *testing.T) {
),
)
require.NoError(
t,
pk.VerifyMultisignature(signBytesFn, sig),
"multisig failed after k good signatures",
)
},
true,
},
{
}, {
"duplicate signatures",
func() {
func(require *require.Assertions) {
pubKeys, sigs := generatePubKeysAndSignatures(5, msg)
pk = kmultisig.NewLegacyAminoPubKey(2, pubKeys)
sig = multisig.NewMultisig(5)
require.Error(t, pk.VerifyMultisignature(signBytesFn, sig))
require.Error(pk.VerifyMultisignature(signBytesFn, sig))
multisig.AddSignatureFromPubKey(sig, sigs[0], pubKeys[0], pubKeys)
// Add second signature manually
sig.Signatures = append(sig.Signatures, sigs[0])
},
false,
},
{
}, {
"duplicated key",
func(require *require.Assertions) {
// here we test an edge case where we create a multi sig with two same
// keys. It should work.
pubkeys, sigs := generatePubKeysAndSignatures(3, msg)
pubkeys[1] = pubkeys[0]
pk = kmultisig.NewLegacyAminoPubKey(2, pubkeys)
sig = multisig.NewMultisig(len(pubkeys))
multisig.AddSignature(sig, sigs[0], 0)
multisig.AddSignature(sig, sigs[0], 1)
},
true,
}, {
"same key used twice",
func(require *require.Assertions) {
pubkeys, sigs := generatePubKeysAndSignatures(3, msg)
pk = kmultisig.NewLegacyAminoPubKey(2, pubkeys)
sig = multisig.NewMultisig(len(pubkeys))
multisig.AddSignature(sig, sigs[0], 0)
multisig.AddSignature(sig, sigs[0], 1)
},
false,
}, {
"unable to verify signature",
func() {
func(require *require.Assertions) {
pubKeys, _ := generatePubKeysAndSignatures(2, msg)
_, sigs := generatePubKeysAndSignatures(2, msg)
pk = kmultisig.NewLegacyAminoPubKey(2, pubKeys)
@ -190,7 +212,7 @@ func TestVerifyMultisignature(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.msg, func(t *testing.T) {
tc.malleate()
tc.malleate(require.New(t))
err := pk.VerifyMultisignature(signBytesFn, sig)
if tc.expectPass {
require.NoError(t, err)

View File

@ -151,12 +151,9 @@ func (pubKey *PubKey) Address() crypto.Address {
panic("length of pubkey is incorrect")
}
hasherSHA256 := sha256.New()
hasherSHA256.Write(pubKey.Key) // does not error
sha := hasherSHA256.Sum(nil)
sha := sha256.Sum256(pubKey.Key)
hasherRIPEMD160 := ripemd160.New()
hasherRIPEMD160.Write(sha) // does not error
hasherRIPEMD160.Write(sha[:]) // does not error
return crypto.Address(hasherRIPEMD160.Sum(nil))
}

View File

@ -30,14 +30,14 @@ func NewCompactBitArray(bits int) *CompactBitArray {
func (bA *CompactBitArray) Count() int {
if bA == nil {
return 0
} else if bA.ExtraBitsStored == uint32(0) {
} else if bA.ExtraBitsStored == 0 {
return len(bA.Elems) * 8
}
return (len(bA.Elems)-1)*8 + int(bA.ExtraBitsStored)
}
// GetIndex returns the bit at index i within the bit array.
// GetIndex returns true if the bit at index i is set; returns false otherwise.
// The behavior is undefined if i >= bA.Count()
func (bA *CompactBitArray) GetIndex(i int) bool {
if bA == nil {
@ -47,11 +47,11 @@ func (bA *CompactBitArray) GetIndex(i int) bool {
return false
}
return bA.Elems[i>>3]&(uint8(1)<<uint8(7-(i%8))) > 0
return bA.Elems[i>>3]&(1<<uint8(7-(i%8))) > 0
}
// SetIndex sets the bit at index i within the bit array.
// The behavior is undefined if i >= bA.Count()
// SetIndex sets the bit at index i within the bit array. Returns true if and only if the
// operation succeeded. The behavior is undefined if i >= bA.Count()
func (bA *CompactBitArray) SetIndex(i int, v bool) bool {
if bA == nil {
return false
@ -62,9 +62,9 @@ func (bA *CompactBitArray) SetIndex(i int, v bool) bool {
}
if v {
bA.Elems[i>>3] |= (uint8(1) << uint8(7-(i%8)))
bA.Elems[i>>3] |= (1 << uint8(7-(i%8)))
} else {
bA.Elems[i>>3] &= ^(uint8(1) << uint8(7-(i%8)))
bA.Elems[i>>3] &= ^(1 << uint8(7-(i%8)))
}
return true
@ -75,13 +75,23 @@ func (bA *CompactBitArray) SetIndex(i int, v bool) bool {
// there are two bits set to true before index 4.
func (bA *CompactBitArray) NumTrueBitsBefore(index int) int {
numTrueValues := 0
for i := 0; i < index; i++ {
if bA.GetIndex(i) {
numTrueValues++
max := bA.Count()
if index > max {
index = max
}
// below we iterate over the bytes then over bits (in low endian) and count bits set to 1
var i = 0
for elem := 0; ; elem++ {
for b := 7; b >= 0; b-- {
if i >= index {
return numTrueValues
}
i++
if (bA.Elems[elem]>>b)&1 == 1 {
numTrueValues++
}
}
}
return numTrueValues
}
// Copy returns a copy of the provided bit array.
@ -99,6 +109,18 @@ func (bA *CompactBitArray) Copy() *CompactBitArray {
}
}
// Equal checks if both bit arrays are equal. If both arrays are nil then it returns true.
func (bA *CompactBitArray) Equal(other *CompactBitArray) bool {
if bA == other {
return true
}
if bA == nil || other == nil {
return false
}
return bA.ExtraBitsStored == other.ExtraBitsStored &&
bytes.Equal(bA.Elems, other.Elems)
}
// String returns a string representation of CompactBitArray: BA{<bit-string>},
// where <bit-string> is a sequence of 'x' (1) and '_' (0).
// The <bit-string> includes spaces and newlines to help people.

View File

@ -36,6 +36,34 @@ func TestNewBitArrayNeverCrashesOnNegatives(t *testing.T) {
}
}
func TestBitArrayEqual(t *testing.T) {
empty := new(CompactBitArray)
big1, _ := randCompactBitArray(1000)
big1Cpy := *big1
big2, _ := randCompactBitArray(1000)
big2.SetIndex(500, !big1.GetIndex(500)) // ensure they are different
cases := []struct {
name string
b1 *CompactBitArray
b2 *CompactBitArray
eq bool
}{
{name: "both nil are equal", b1: nil, b2: nil, eq: true},
{name: "if one is nil then not equal", b1: nil, b2: empty, eq: false},
{name: "nil and empty not equal", b1: empty, b2: nil, eq: false},
{name: "empty and empty equal", b1: empty, b2: new(CompactBitArray), eq: true},
{name: "same bits should be equal", b1: big1, b2: &big1Cpy, eq: true},
{name: "different should not be equal", b1: big1, b2: big2, eq: false},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
eq := tc.b1.Equal(tc.b2)
require.Equal(t, tc.eq, eq)
})
}
}
func TestJSONMarshalUnmarshal(t *testing.T) {
bA1 := NewCompactBitArray(0)
@ -200,3 +228,13 @@ func TestCompactBitArrayGetSetIndex(t *testing.T) {
}
}
}
func BenchmarkNumTrueBitsBefore(b *testing.B) {
ba, _ := randCompactBitArray(100)
b.Run("new", func(b *testing.B) {
for i := 0; i < b.N; i++ {
ba.NumTrueBitsBefore(90)
}
})
}

View File

@ -34,7 +34,8 @@ func getIndex(pk types.PubKey, keys []types.PubKey) int {
return -1
}
// AddSignature adds a signature to the multisig, at the corresponding index.
// AddSignature adds a signature to the multisig, at the corresponding index. The index must
// represent the pubkey index in the LegacyAmingPubKey structure, which verifies this signature.
// If the signature already exists, replace it.
func AddSignature(mSig *signing.MultiSignatureData, sig signing.SignatureData, index int) {
newSigIndex := mSig.BitArray.NumTrueBitsBefore(index)

View File

@ -42,6 +42,10 @@ module.exports = {
"label": "v0.39",
"key": "v0.39"
},
{
"label": "v0.41",
"key": "v0.41"
},
{
"label": "master",
"key": "master"

View File

@ -72,6 +72,7 @@ Read about the [PROCESS](./PROCESS.md).
- [ADR 027: Deterministic Protobuf Serialization](./adr-027-deterministic-protobuf-serialization.md)
- [ADR 028: Public Key Addresses](./adr-028-public-key-addresses.md)
- [ADR 032: Typed Events](./adr-032-typed-events.md)
- [ADR 033: Inter-module RPC](./adr-033-protobuf-inter-module-comm.md)
- [ADR 035: Rosetta API Support](./adr-035-rosetta-api-support.md)
- [ADR 037: Governance Split Votes](./adr-037-gov-split-vote.md)
- [ADR 038: State Listening](./adr-038-state-listening.md)

View File

@ -7,6 +7,7 @@
- 2020 Apr 27: Convert usages of `oneof` for interfaces to `Any`
- 2020 May 15: Describe `cosmos_proto` extensions and amino compatibility
- 2020 Dec 4: Move and rename `MarshalAny` and `UnmarshalAny` into the `codec.Marshaler` interface.
- 2021 Feb 24: Remove mentions of `HybridCodec`, which has been abandoned in [#6843](https://github.com/cosmos/cosmos-sdk/pull/6843).
## Status
@ -59,24 +60,26 @@ We will adopt [Protocol Buffers](https://developers.google.com/protocol-buffers)
persisted structured data in the Cosmos SDK while providing a clean mechanism and developer UX for
applications wishing to continue to use Amino. We will provide this mechanism by updating modules to
accept a codec interface, `Marshaler`, instead of a concrete Amino codec. Furthermore, the Cosmos SDK
will provide three concrete implementations of the `Marshaler` interface: `AminoCodec`, `ProtoCodec`,
and `HybridCodec`.
will provide two concrete implementations of the `Marshaler` interface: `AminoCodec` and `ProtoCodec`.
- `AminoCodec`: Uses Amino for both binary and JSON encoding.
- `ProtoCodec`: Uses Protobuf for or both binary and JSON encoding.
- `HybridCodec`: Uses Amino for JSON encoding and Protobuf for binary encoding.
- `ProtoCodec`: Uses Protobuf for both binary and JSON encoding.
Until the client migration landscape is fully understood and designed, modules will use a `HybridCodec`
as the concrete codec it accepts and/or extends. This means that all client JSON encoding, including
genesis state, will still use Amino. The ultimate goal will be to replace Amino JSON encoding with
Protbuf encoding and thus have modules accept and/or extend `ProtoCodec`.
Modules will use whichever codec that is instantiated in the app. By default, the SDK's `simapp`
instantiates a `ProtoCodec` as the concrete implementation of `Marshaler`, inside the `MakeTestEncodingConfig`
function. This can be easily overwritten by app developers if they so desire.
The ultimate goal will be to replace Amino JSON encoding with Protobuf encoding and thus have
modules accept and/or extend `ProtoCodec`. Until then, Amino JSON is still provided for legacy use-cases.
A handful of places in the SDK still have Amino JSON hardcoded, such as the Legacy API REST endpoints
and the `x/params` store. They are planned to be converted to Protobuf in a gradual manner.
### Module Codecs
Modules that do not require the ability to work with and serialize interfaces, the path to Protobuf
migration is pretty straightforward. These modules are to simply migrate any existing types that
are encoded and persisted via their concrete Amino codec to Protobuf and have their keeper accept a
`Marshaler` that will be a `HybridCodec`. This migration is simple as things will just work as-is.
`Marshaler` that will be a `ProtoCodec`. This migration is simple as things will just work as-is.
Note, any business logic that needs to encode primitive types like `bool` or `int64` should use
[gogoprotobuf](https://github.com/gogo/protobuf) Value types.
@ -207,7 +210,7 @@ Note that `InterfaceRegistry` usage does not deviate from standard protobuf
usage of `Any`, it just introduces a security and introspection layer for
golang usage.
`InterfaceRegistry` will be a member of `ProtoCodec` and `HybridCodec` as
`InterfaceRegistry` will be a member of `ProtoCodec`
described above. In order for modules to register interface types, app modules
can optionally implement the following interface:

View File

@ -12,6 +12,7 @@
- 2020 August 19: Move sequence field from `SignDoc` to `SignerInfo`, as discussed in [#6966](https://github.com/cosmos/cosmos-sdk/issues/6966).
- 2020 September 25: Remove `PublicKey` type in favor of `secp256k1.PubKey`, `ed25519.PubKey` and `multisig.LegacyAminoPubKey`.
- 2020 October 15: Add `GetAccount` and `GetAccountWithHeight` methods to the `AccountRetriever` interface.
- 2021 Feb 24: The SDK does not use Tendermint's `PubKey` interface anymore, but its own `cryptotypes.PubKey`. Updates to reflect this.
## Status
@ -286,7 +287,7 @@ and `FileDescriptor`s and returns a boolean result.
### Public Key Encoding
Public keys in the Cosmos SDK implement Tendermint's `crypto.PubKey` interface.
Public keys in the Cosmos SDK implement the `cryptotypes.PubKey` interface.
We propose to use `Any` for protobuf encoding as we are doing with other interfaces (e.g. in `BaseAccount` `PubKey` or `SignerInfo` `PublicKey`).
Following public keys are implemented: secp256k1, ed25519 and multisignature.

View File

@ -44,7 +44,7 @@ We elect not to deal with chains which have actually halted, which is necessaril
1. Add a new governance proposal type, `ClientUpdateProposal`, in the `x/ibc` module
1. Extend the base `Proposal` with two client identifiers (`string`) and an initial height ('exported.Height').
1. The first client identifier is the proposed client to be updated. This client must be either frozen or expired.
1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height and frozen height). It should be continually updated during the voting period.
1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain-id). It should be continually updated during the voting period.
1. The initial height represents the starting height consensus states which will be copied from the substitute client to the frozen/expired client.
1. If this governance proposal passes, the client on trial will be updated with all the state of the substitute, if and only if:
1. `allow_governance_override_after_expiry` is true and the client has expired (`Expired()` returns true)

View File

@ -4,7 +4,7 @@
- 2019-11-06: Initial Draft
- 2020-10-12: Updated Draft
- 2021-11-13: Accepted
- 2020-11-13: Accepted
## Status
@ -55,7 +55,7 @@ type Authorization interface {
MethodName() string
// Accept determines whether this grant permits the provided sdk.ServiceMsg to be performed, and if
// so provides an upgraded authorization instance.
// so provides an upgraded authorization instance.
// Returns:
// + allow: true if msg is authorized
// + updated: new Authorization instance which should overwrite the current one with new state
@ -146,7 +146,7 @@ to the router based on `Authorization` grants:
```go
type Keeper interface {
// DispatchActions routes the provided msgs to their respective handlers if the grantee was granted an authorization
// to send those messages by the first (and only) signer of each msg.
// to send those messages by the first (and only) signer of each msg.
DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, msgs []sdk.ServiceMsg) sdk.Result`
}
```
@ -216,7 +216,7 @@ message GenericAuthorization {
- Users will be able to authorize arbitrary actions on behalf of their accounts to other
users, improving key management for many use cases
- The solution is more generic than previously considered approaches and the
`Authorization` interface approach can be extended to cover other use cases by
`Authorization` interface approach can be extended to cover other use cases by
SDK users
### Negative

View File

@ -0,0 +1,395 @@
# ADR 033: Protobuf-based Inter-Module Communication
## Changelog
- 2020-10-05: Initial Draft
## Status
Proposed
## Abstract
This ADR introduces a system for permissioned inter-module communication leveraging the protobuf `Query` and `Msg`
service definitions defined in [ADR 021](./adr-021-protobuf-query-encoding.md) and
[ADR 031](./adr-031-msg-service.md) which provides:
- stable protobuf based module interfaces to potentially later replace the keeper paradigm
- stronger inter-module object capabilities (OCAPs) guarantees
- module accounts and sub-account authorization
## Context
In the current Cosmos SDK documentation on the [Object-Capability Model](../docs/core/ocap.md), it is stated that:
> We assume that a thriving ecosystem of Cosmos-SDK modules that are easy to compose into a blockchain application will contain faulty or malicious modules.
There is currently not a thriving ecosystem of Cosmos SDK modules. We hypothesize that this is in part due to:
1. lack of a stable v1.0 Cosmos SDK to build modules off of. Module interfaces are changing, sometimes dramatically, from
point release to point release, often for good reasons, but this does not create a stable foundation to build on.
2. lack of a properly implemented object capability or even object-oriented encapsulation system which makes refactors
of module keeper interfaces inevitable because the current interfaces are poorly constrained.
### `x/bank` Case Study
Currently the `x/bank` keeper gives pretty much unrestricted access to any module which references it. For instance, the
`SetBalance` method allows the caller to set the balance of any account to anything, bypassing even proper tracking of supply.
There appears to have been some later attempts to implement some semblance of OCAPs using module-level minting, staking
and burning permissions. These permissions allow a module to mint, burn or delegate tokens with reference to the modules
own account. These permissions are actually stored as a `[]string` array on the `ModuleAccount` type in state.
However, these permissions dont really do much. They control what modules can be referenced in the `MintCoins`,
`BurnCoins` and `DelegateCoins***` methods, but for one there is no unique object capability token that controls access —
just a simple string. So the `x/upgrade` module could mint tokens for the `x/staking` module simple by calling
`MintCoins(“staking”)`. Furthermore, all modules which have access to these keeper methods, also have access to
`SetBalance` negating any other attempt at OCAPs and breaking even basic object-oriented encapsulation.
## Decision
Based on [ADR-021](./adr-021-protobuf-query-encoding.md) and [ADR-031](./adr-031-msg-service.md), we introduce the
Inter-Module Communication framework for secure module authorization and OCAPs.
When implemented, this could also serve as an alternative to the existing paradigm of passing keepers between
modules. The approach outlined here-in is intended to form the basis of a Cosmos SDK v1.0 that provides the necessary
stability and encapsulation guarantees that allow a thriving module ecosystem to emerge.
Of particular note — the decision is to _enable_ this functionality for modules to adopt at their own discretion.
Proposals to migrate existing modules to this new paradigm will have to be a separate conversation, potentially
addressed as amendments to this ADR.
### New "Keeper" Paradigm
In [ADR 021](./adr-021-protobuf-query-encoding.md), a mechanism for using protobuf service definitions to define queriers
was introduced and in [ADR 31](./adr-031-msg-service.md), a mechanism for using protobuf service to define `Msg`s was added.
Protobuf service definitions generate two golang interfaces representing the client and server sides of a service plus
some helper code. Here is a minimal example for the bank `cosmos.bank.Msg/Send` message type:
```go
package bank
type MsgClient interface {
Send(context.Context, *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error)
}
type MsgServer interface {
Send(context.Context, *MsgSend) (*MsgSendResponse, error)
}
```
[ADR 021](./adr-021-protobuf-query-encoding.md) and [ADR 31](./adr-031-msg-service.md) specifies how modules can implement the generated `QueryServer`
and `MsgServer` interfaces as replacements for the legacy queriers and `Msg` handlers respectively.
In this ADR we explain how modules can make queries and send `Msg`s to other modules using the generated `QueryClient`
and `MsgClient` interfaces and propose this mechanism as a replacement for the existing `Keeper` paradigm. To be clear,
this ADR does not necessitate the creation of new protobuf definitions or services. Rather, it leverages the same proto
based service interfaces already used by clients for inter-module communication.
Using this `QueryClient`/`MsgClient` approach has the following key benefits over exposing keepers to external modules:
1. Protobuf types are checked for breaking changes using [buf](https://buf.build/docs/breaking-overview) and because of
the way protobuf is designed this will give us strong backwards compatibility guarantees while allowing for forward
evolution.
2. The separation between the client and server interfaces will allow us to insert permission checking code in between
the two which checks if one module is authorized to send the specified `Msg` to the other module providing a proper
object capability system (see below).
3. The router for inter-module communication gives us a convenient place to handle rollback of transactions,
enabling atomicy of operations ([currently a problem](https://github.com/cosmos/cosmos-sdk/issues/8030)). Any failure within a module-to-module call would result in a failure of the entire
transaction
This mechanism has the added benefits of:
- reducing boilerplate through code generation, and
- allowing for modules in other languages either via a VM like CosmWasm or sub-processes using gRPC
### Inter-module Communication
To use the `Client` generated by the protobuf compiler we need a `grpc.ClientConn` [interface](https://github.com/regen-network/protobuf/blob/cosmos/grpc/types.go#L12)
implementation. For this we introduce
a new type, `ModuleKey`, which implements the `grpc.ClientConn` interface. `ModuleKey` can be thought of as the "private
key" corresponding to a module account, where authentication is provided through use of a special `Invoker()` function,
described in more detail below.
Blockchain users (external clients) use their account's private key to sign transactions containing `Msg`s where they are listed as signers (each
message specifies required signers with `Msg.GetSigner`). The authentication checks is performed by `AnteHandler`.
Here, we extend this process, by allowing modules to be identified in `Msg.GetSigners`. When a module wants to trigger the execution a `Msg` in another module,
its `ModuleKey` acts as the sender (through the `ClientConn` interface we describe below) and is set as a sole "signer". It's worth to note
that we don't use any cryptographic signature in this case.
For example, module `A` could use its `A.ModuleKey` to create `MsgSend` object for `/cosmos.bank.Msg/Send` transaction. `MsgSend` validation
will assure that the `from` account (`A.ModuleKey` in this case) is the signer.
Here's an example of a hypothetical module `foo` interacting with `x/bank`:
```go
package foo
type FooMsgServer {
// ...
bankQuery bank.QueryClient
bankMsg bank.MsgClient
}
func NewFooMsgServer(moduleKey RootModuleKey, ...) FooMsgServer {
// ...
return FooMsgServer {
// ...
modouleKey: moduleKey,
bankQuery: bank.NewQueryClient(moduleKey),
bankMsg: bank.NewMsgClient(moduleKey),
}
}
func (foo *FooMsgServer) Bar(ctx context.Context, req *MsgBarRequest) (*MsgBarResponse, error) {
balance, err := foo.bankQuery.Balance(&bank.QueryBalanceRequest{Address: fooMsgServer.moduleKey.Address(), Denom: "foo"})
...
res, err := foo.bankMsg.Send(ctx, &bank.MsgSendRequest{FromAddress: fooMsgServer.moduleKey.Address(), ...})
...
}
```
This design is also intended to be extensible to cover use cases of more fine grained permissioning like minting by
denom prefix being restricted to certain modules (as discussed in
[#7459](https://github.com/cosmos/cosmos-sdk/pull/7459#discussion_r529545528)).
### `ModuleKey`s and `ModuleID`s
A `ModuleKey` can be thought of as a "private key" for a module account and a `ModuleID` can be thought of as the
corresponding "public key". From the [ADR 028](./adr-028-public-key-addresses.md), modules can have both a root module account and any number of sub-accounts
or derived accounts that can be used for different pools (ex. staking pools) or managed accounts (ex. group
accounts). We can also think of module sub-accounts as similar to derived keys - there is a root key and then some
derivation path. `ModuleID` is a simple struct which contains the module name and optional "derivation" path,
and forms its address based on the `AddressHash` method from [the ADR-028](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md):
```go
type ModuleID struct {
ModuleName string
Path []byte
}
func (key ModuleID) Address() []byte {
return AddressHash(key.ModuleName, key.Path)
}
```
In addition to being able to generate a `ModuleID` and address, a `ModuleKey` contains a special function called
`Invoker` which is the key to safe inter-module access. The `Invoker` creates an `InvokeFn` closure which is used as an `Invoke` method in
the `grpc.ClientConn` interface and under the hood is able to route messages to the appropriate `Msg` and `Query` handlers
performing appropriate security checks on `Msg`s. This allows for even safer inter-module access than keeper's whose
private member variables could be manipulated through reflection. Golang does not support reflection on a function
closure's captured variables and direct manipulation of memory would be needed for a truly malicious module to bypass
the `ModuleKey` security.
The two `ModuleKey` types are `RootModuleKey` and `DerivedModuleKey`:
```go
type Invoker func(callInfo CallInfo) func(ctx context.Context, request, response interface{}, opts ...interface{}) error
type CallInfo {
Method string
Caller ModuleID
}
type RootModuleKey struct {
moduleName string
invoker Invoker
}
func (rm RootModuleKey) Derive(path []byte) DerivedModuleKey { /* ... */}
type DerivedModuleKey struct {
moduleName string
path []byte
invoker Invoker
}
```
A module can get access to a `DerivedModuleKey`, using the `Derive(path []byte)` method on `RootModuleKey` and then
would use this key to authenticate `Msg`s from a sub-account. Ex:
```go
package foo
func (fooMsgServer *MsgServer) Bar(ctx context.Context, req *MsgBar) (*MsgBarResponse, error) {
derivedKey := fooMsgServer.moduleKey.Derive(req.SomePath)
bankMsgClient := bank.NewMsgClient(derivedKey)
res, err := bankMsgClient.Balance(ctx, &bank.MsgSend{FromAddress: derivedKey.Address(), ...})
...
}
```
In this way, a module can gain permissioned access to a root account and any number of sub-accounts and send
authenticated `Msg`s from these accounts. The `Invoker` `callInfo.Caller` parameter is used under the hood to
distinguish between different module accounts, but either way the function returned by `Invoker` only allows `Msg`s
from either the root or a derived module account to pass through.
Note that `Invoker` itself returns a function closure based on the `CallInfo` passed in. This will allow client implementations
in the future that cache the invoke function for each method type avoiding the overhead of hash table lookup.
This would reduce the performance overhead of this inter-module communication method to the bare minimum required for
checking permissions.
To re-iterate, the closure only allows access to authorized calls. There is no access to anything else regardless of any
name impersonation.
Below is a rough sketch of the implementation of `grpc.ClientConn.Invoke` for `RootModuleKey`:
```go
func (key RootModuleKey) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...grpc.CallOption) error {
f := key.invoker(CallInfo {Method: method, Caller: ModuleID {ModuleName: key.moduleName}})
return f(ctx, args, reply)
}
```
### `AppModule` Wiring and Requirements
In [ADR 031](./adr-031-msg-service.md), the `AppModule.RegisterService(Configurator)` method was introduced. To support
inter-module communication, we extend the `Configurator` interface to pass in the `ModuleKey` and to allow modules to
specify their dependencies on other modules using `RequireServer()`:
```go
type Configurator interface {
MsgServer() grpc.Server
QueryServer() grpc.Server
ModuleKey() ModuleKey
RequireServer(msgServer interface{})
}
```
The `ModuleKey` is passed to modules in the `RegisterService` method itself so that `RegisterServices` serves as a single
entry point for configuring module services. This is intended to also have the side-effect of greatly reducing boilerplate in
`app.go`. For now, `ModuleKey`s will be created based on `AppModuleBasic.Name()`, but a more flexible system may be
introduced in the future. The `ModuleManager` will handle creation of module accounts behind the scenes.
Because modules do not get direct access to each other anymore, modules may have unfulfilled dependencies. To make sure
that module dependencies are resolved at startup, the `Configurator.RequireServer` method should be added. The `ModuleManager`
will make sure that all dependencies declared with `RequireServer` can be resolved before the app starts. An example
module `foo` could declare it's dependency on `x/bank` like this:
```go
package foo
func (am AppModule) RegisterServices(cfg Configurator) {
cfg.RequireServer((*bank.QueryServer)(nil))
cfg.RequireServer((*bank.MsgServer)(nil))
}
```
### Security Considerations
In addition to checking for `ModuleKey` permissions, a few additional security precautions will need to be taken by
the underlying router infrastructure.
#### Recursion and Re-entry
Recursive or re-entrant method invocations pose a potential security threat. This can be a problem if Module A
calls Module B and Module B calls module A again in the same call.
One basic way for the router system to deal with this is to maintain a call stack which prevents a module from
being referenced more than once in the call stack so that there is no re-entry. A `map[string]interface{}` table
in the router could be used to perform this security check.
#### Queries
Queries in Cosmos SDK are generally un-permissioned so allowing one module to query another module should not pose
any major security threats assuming basic precautions are taken. The basic precaution that the router system will
need to take is making sure that the `sdk.Context` passed to query methods does not allow writing to the store. This
can be done for now with a `CacheMultiStore` as is currently done for `BaseApp` queries.
### Internal Methods
In many cases, we may wish for modules to call methods on other modules which are not exposed to clients at all. For this
purpose, we add the `InternalServer` method to `Configurator`:
```go
type Configurator interface {
MsgServer() grpc.Server
QueryServer() grpc.Server
InternalServer() grpc.Server
}
```
As an example, x/slashing's Slash must call x/staking's Slash, but we don't want to expose x/staking's Slash to end users
and clients.
Internal protobuf services will be defined in a corresponding `internal.proto` file in the given module's
proto package.
Services registered against `InternalServer` will be callable from other modules but not by external clients.
An alternative solution to internal-only methods could involve hooks / plugins as discussed [here](https://github.com/cosmos/cosmos-sdk/pull/7459#issuecomment-733807753).
A more detailed evaluation of a hooks / plugin system will be addressed later in follow-ups to this ADR or as a separate
ADR.
### Authorization
By default, the inter-module router requires that messages are sent by the first signer returned by `GetSigners`. The
inter-module router should also accept authorization middleware such as that provided by [ADR 030](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-030-authz-module.md).
This middleware will allow accounts to otherwise specific module accounts to perform actions on their behalf.
Authorization middleware should take into account the need to grant certain modules effectively "admin" privileges to
other modules. This will be addressed in separate ADRs or updates to this ADR.
### Future Work
Other future improvements may include:
* custom code generation that:
* simplifies interfaces (ex. generates code with `sdk.Context` instead of `context.Context`)
* optimizes inter-module calls - for instance caching resolved methods after first invocation
* combining `StoreKey`s and `ModuleKey`s into a single interface so that modules have a single OCAPs handle
* code generation which makes inter-module communication more performant
* decoupling `ModuleKey` creation from `AppModuleBasic.Name()` so that app's can override root module account names
* inter-module hooks and plugins
## Alternatives
### MsgServices vs `x/capability`
The `x/capability` module does provide a proper object-capability implementation that can be used by any module in the
SDK and could even be used for inter-module OCAPs as described in [\#5931](https://github.com/cosmos/cosmos-sdk/issues/5931).
The advantages of the approach described in this ADR are mostly around how it integrates with other parts of the SDK,
specifically:
* protobuf so that:
* code generation of interfaces can be leveraged for a better dev UX
* module interfaces are versioned and checked for breakage using [buf](https://docs.buf.build/breaking-overview)
* sub-module accounts as per ADR 028
* the general `Msg` passing paradigm and the way signers are specified by `GetSigners`
Also, this is a complete replacement for keepers and could be applied to _all_ inter-module communication whereas the
`x/capability` approach in #5931 would need to be applied method by method.
## Consequences
### Backwards Compatibility
This ADR is intended to provide a pathway to a scenario where there is greater long term compatibility between modules.
In the short-term, this will likely result in breaking certain `Keeper` interfaces which are too permissive and/or
replacing `Keeper` interfaces altogether.
### Positive
- an alternative to keepers which can more easily lead to stable inter-module interfaces
- proper inter-module OCAPs
- improved module developer DevX, as commented on by several particpants on
[Architecture Review Call, Dec 3](https://hackmd.io/E0wxxOvRQ5qVmTf6N_k84Q)
- lays the groundwork for what can be a greatly simplified `app.go`
- router can be setup to enforce atomic transactions for moule-to-module calls
### Negative
- modules which adopt this will need significant refactoring
### Neutral
## Test Cases [optional]
## References
- [ADR 021](./adr-021-protobuf-query-encoding.md)
- [ADR 031](./adr-031-msg-service.md)
- [ADR 028](./adr-028-public-key-addresses.md)
- [ADR 030 draft](https://github.com/cosmos/cosmos-sdk/pull/7105)
- [Object-Capability Model](../docs/core/ocap.md)

View File

@ -6,7 +6,7 @@
## Status
Proposed
Accepted
## Abstract
@ -35,7 +35,7 @@ type Vote struct {
}
```
And for backwards compatibility, we introduce `MsgWeightedVote` while keeping `MsgVote`.
And for backwards compatibility, we introduce `MsgVoteWeighted` while keeping `MsgVote`.
```
type MsgVote struct {
ProposalID int64
@ -43,14 +43,14 @@ type MsgVote struct {
Option Option
}
type MsgWeightedVote struct {
type MsgVoteWeighted struct {
ProposalID int64
Voter sdk.Address
Options []WeightedVoteOption
}
```
The `ValidateBasic` of a `MsgWeightedVote` struct would require that
The `ValidateBasic` of a `MsgVoteWeighted` struct would require that
1. The sum of all the Rates is equal to 1.0
2. No Option is repeated

View File

@ -33,7 +33,7 @@ The blockchain full-node presents itself as a binary, generally suffixed by `-d`
Once the main binary is built, the node can be started by running the [`start` command](../core/node.md#start-command). This command function primarily does three things:
1. Create an instance of the state-machine defined in [`app.go`](#core-application-file).
2. Initialize the state-machine with the latest known state, extracted from the `db` stored in the `~/.appd/data` folder. At this point, the state-machine is at height `appBlockHeight`.
2. Initialize the state-machine with the latest known state, extracted from the `db` stored in the `~/.app/data` folder. At this point, the state-machine is at height `appBlockHeight`.
3. Create and start a new Tendermint instance. Among other things, the node will perform a handshake with its peers. It will get the latest `blockHeight` from them, and replay blocks to sync to this height if it is greater than the local `appBlockHeight`. If `appBlockHeight` is `0`, the node is starting from genesis and Tendermint sends an `InitChain` message via the ABCI to the `app`, which triggers the [`InitChainer`](#initchainer).
## Core Application File
@ -77,7 +77,7 @@ Here are the main actions performed by this function:
- Mount the stores.
- Return the application.
Note that this function only creates an instance of the app, while the actual state is either carried over from the `~/.appd/data` folder if the node is restarted, or generated from the genesis file if the node is started for the first time.
Note that this function only creates an instance of the app, while the actual state is either carried over from the `~/.app/data` folder if the node is restarted, or generated from the genesis file if the node is started for the first time.
See an example of application constructor from `simapp`:
@ -237,6 +237,18 @@ See an example of an application's main command-line file from the [nameservice
## Dependencies and Makefile
::: warning
A patch introduced in `go-grpc v1.34.0` made gRPC incompatible with the `gogoproto` library, making some [gRPC queries](https://github.com/cosmos/cosmos-sdk/issues/8426) panic. As such, the SDK requires that `go-grpc <=v1.33.2` is installed in your `go.mod`.
To make sure that gRPC is working properly, it is **highly recommended** to add the following line in your application's `go.mod`:
```
replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
```
Please see [issue #8392](https://github.com/cosmos/cosmos-sdk/issues/8392) for more info.
:::
This section is optional, as developers are free to choose their dependency manager and project building method. That said, the current most used framework for versioning control is [`go.mod`](https://github.com/golang/go/wiki/Modules). It ensures each of the libraries used throughout the application are imported with the correct version. See an example from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice):
+++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/go.mod#L1-L18

View File

@ -38,6 +38,18 @@ The CLI understands a specific set of commands, defined in a hierarchical struct
### gRPC
::: warning
A patch introduced in `go-grpc v1.34.0` made gRPC incompatible with the `gogoproto` library, making some [gRPC queries](https://github.com/cosmos/cosmos-sdk/issues/8426) panic. As such, the SDK requires that `go-grpc <=v1.33.2` is installed in your `go.mod`.
To make sure that gRPC is working properly, it is **highly recommended** to add the following line in your application's `go.mod`:
```
replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
```
Please see [issue #8392](https://github.com/cosmos/cosmos-sdk/issues/8392) for more info.
:::
Another interface through which users can make queries, introduced in Cosmos SDK v0.40, is [gRPC](https://grpc.io) requests to a [gRPC server](../core/grpc_rest.md#grpc-server). The endpoints are defined as [Protocol Buffers](https://developers.google.com/protocol-buffers) service methods inside `.proto` files, written in Protobuf's own language-agnostic interface definition language (IDL). The Protobuf ecosystem developed tools for code-generation from `*.proto` files into various languages. These tools allow to build gRPC clients easily.
One such tool is [grpcurl](https://github.com/fullstorydev/grpcurl), and a gRPC request for `MyQuery` using this client looks like:

View File

@ -28,7 +28,7 @@ Blockchain Node | | Consensus | |
1. [`app.go`] 创建了一个状态机实例。
2. 用最新的已知状态初始化状态机,该状态机是从存储在 `~/.appd/data` 文件夹中的 db 中提取的。 此时,状态机的高度为:`appBlockHeight`。
2. 用最新的已知状态初始化状态机,该状态机是从存储在 `~/.app/data` 文件夹中的 db 中提取的。 此时,状态机的高度为:`appBlockHeight`。
3. 创建并启动一个新的 Tendermint 实例。 该节点将与对等节点进行连接交换信息。 它将从他们那里获取最新的 `blockHeight`,如果它大于本地的 `appBlockHeight`,则重播块以同步到该高度。 如果 `appBlockHeight``0`,则该节点从创世开始,并且 Tendermint 通过 ABCI 接口向 `app` 发送 `InitChain` 初始化链命令,从而触发 [`InitChainer`](https://docs.cosmos.network/master/basics/app-anatomy.html#initchainer)。
@ -73,7 +73,7 @@ Blockchain Node | | Consensus | |
- 挂载存储.
- 返回应用实例.
请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从 `〜/.appd/data` 文件夹中保留下来状态加载如果节点是第一次启动则从创世文件生成。See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia):
请注意,此函数仅创建该应用的一个实例,而如果重新启动节点,则状态将从 `〜/.app/data` 文件夹中保留下来状态加载如果节点是第一次启动则从创世文件生成。See an example of application constructor from [`gaia`](https://github.com/cosmos/gaia):
+++ https://github.com/cosmos/gaia/blob/f41a660cdd5bea173139965ade55bd25d1ee3429/app/app.go#L110-L222

View File

@ -286,7 +286,7 @@ Before the first transaction of a given block is processed, a [volatile state](#
1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose.
2. For each `Msg` in the transaction, route to the appropriate module's [`Msg` service](../building-modules/msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `deliverState` `CacheMultiStore`.
During step 5., each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation:
During the additional fifth step outlined in (2), each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/store/types/gas.go#L153-L162

View File

@ -96,7 +96,7 @@ This `queryCmd` function adds all the queries available to end-users for the app
Here is an example of a `queryCmd` aggregating subcommands from the `simapp` application:
+++ https://github.com/cosmos/cosmos-sdk/blob/0.40.0/simapp/simd/cmd/root.go#L99-L121
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/simapp/simd/cmd/root.go#L99-L121
## Flags

View File

@ -19,7 +19,7 @@ take the form of: `{eventType}.{eventAttribute}={value}`.
Events contain:
- A `type`, which is meant to categorize an event at a high-level (e.g. by module or action).
- A `type`, which is meant to categorize an event at a high-level (e.g. by module (e.g. `module=bank`) or action (e.g. `action=/cosmos.bank.v1beta1.Msg/Send`)).
- A list of `attributes`, which are key-value pairs that give more information about
the categorized `event`.
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L51-L56

View File

@ -20,16 +20,28 @@ The node also exposes some other endpoints, such as the Tendermint P2P endpoint,
## gRPC Server
::: warning
A patch introduced in `go-grpc v1.34.0` made gRPC incompatible with the `gogoproto` library, making some [gRPC queries](https://github.com/cosmos/cosmos-sdk/issues/8426) panic. As such, the SDK requires that `go-grpc <=v1.33.2` is installed in your `go.mod`.
To make sure that gRPC is working properly, it is **highly recommended** to add the following line in your application's `go.mod`:
```
replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
```
Please see [issue #8392](https://github.com/cosmos/cosmos-sdk/issues/8392) for more info.
:::
Cosmos SDK v0.40 introduced Protobuf as the main [encoding](./encoding) library, and this brings a wide range of Protobuf-based tools that can be plugged into the SDK. One such tool is [gRPC](https://grpc.io), a modern open source high performance RPC framework that has decent client support in several languages.
Each module exposes [`Msg` and `Query` Protobuf services](../building-modules/messages-and-queries.md) to define state transitions and state queries. These services are hooked up to gRPC via the following function inside the application:
https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/server/types/app.go#L39-L41
<https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/server/types/app.go#L39-L41>
The `grpc.Server` is a concrete gRPC server, which spawns and serves any gRPC requests. This server can be configured inside `~/.simapp/config/app.toml`:
- `grpc.enable = true|false` field defines if the gRPC server should be enabled. Defaults to `true`.
- `grpc.address = {string}` field defines the address (really, the port, since the host should be kept at `0.0.0.0`) the server should bind to. Defaults to `0.0.0.0:9000`.
- `grpc.address = {string}` field defines the address (really, the port, since the host should be kept at `0.0.0.0`) the server should bind to. Defaults to `0.0.0.0:9090`.
::tip
`~/.simapp` is the directory where the node's configuration and databases are stored. By default, it's set to `~/.{app_name}`.
@ -45,7 +57,7 @@ In Cosmos SDK v0.40, the node continues to serve a REST server. However, the exi
All routes are configured under the following fields in `~/.simapp/config/app.toml`:
- `api.enable = true|false` field defines if the REST server should be enabled. Defaults to `true`.
- `api.enable = true|false` field defines if the REST server should be enabled. Defaults to `false`.
- `api.address = {string}` field defines the address (really, the port, since the host should be kept at `0.0.0.0`) the server should bind to. Defaults to `tcp://0.0.0.0:1317`.
- some additional API configuration options are defined in `~/.simapp/config/app.toml`, along with comments, please refer to that file directly.
@ -55,7 +67,7 @@ If, for various reasons, you cannot use gRPC (for example, you are building a we
[gRPC-gateway](https://grpc-ecosystem.github.io/grpc-gateway/) is a tool to expose gRPC endpoints as REST endpoints. For each RPC endpoint defined in a Protobuf service, the SDK offers a REST equivalent. For instance, querying a balance could be done via the `/cosmos.bank.v1beta1.Query/AllBalances` gRPC endpoint, or alternatively via the gRPC-gateway `"/cosmos/bank/v1beta1/balances/{address}"` REST endpoint: both will return the same result. For each RPC method defined in a Protobuf service, the corresponding REST endpoint is defined as an option:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/proto/cosmos/bank/v1beta1/query.proto#L19-L22
+++ <https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/proto/cosmos/bank/v1beta1/query.proto#L19-L22>
For application developers, gRPC-gateway REST routes needs to be wired up to the REST server, this is done by calling the `RegisterGRPCGatewayRoutes` function on the ModuleManager.

View File

@ -12,24 +12,35 @@
- [cosmos/auth/v1beta1/genesis.proto](#cosmos/auth/v1beta1/genesis.proto)
- [GenesisState](#cosmos.auth.v1beta1.GenesisState)
- [cosmos/base/query/v1beta1/pagination.proto](#cosmos/base/query/v1beta1/pagination.proto)
- [PageRequest](#cosmos.base.query.v1beta1.PageRequest)
- [PageResponse](#cosmos.base.query.v1beta1.PageResponse)
- [cosmos/auth/v1beta1/query.proto](#cosmos/auth/v1beta1/query.proto)
- [QueryAccountRequest](#cosmos.auth.v1beta1.QueryAccountRequest)
- [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse)
- [QueryAccountsRequest](#cosmos.auth.v1beta1.QueryAccountsRequest)
- [QueryAccountsResponse](#cosmos.auth.v1beta1.QueryAccountsResponse)
- [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest)
- [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse)
- [Query](#cosmos.auth.v1beta1.Query)
- [cosmos/base/v1beta1/coin.proto](#cosmos/base/v1beta1/coin.proto)
- [Coin](#cosmos.base.v1beta1.Coin)
- [DecCoin](#cosmos.base.v1beta1.DecCoin)
- [DecProto](#cosmos.base.v1beta1.DecProto)
- [IntProto](#cosmos.base.v1beta1.IntProto)
- [cosmos/authz/v1beta1/authz.proto](#cosmos/authz/v1beta1/authz.proto)
- [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant)
- [GenericAuthorization](#cosmos.authz.v1beta1.GenericAuthorization)
- [SendAuthorization](#cosmos.authz.v1beta1.SendAuthorization)
- [cosmos/authz/v1beta1/genesis.proto](#cosmos/authz/v1beta1/genesis.proto)
- [GenesisState](#cosmos.authz.v1beta1.GenesisState)
- [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization)
- [cosmos/authz/v1beta1/query.proto](#cosmos/authz/v1beta1/query.proto)
- [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest)
- [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse)
- [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest)
- [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse)
- [Query](#cosmos.authz.v1beta1.Query)
- [cosmos/base/abci/v1beta1/abci.proto](#cosmos/base/abci/v1beta1/abci.proto)
- [ABCIMessageLog](#cosmos.base.abci.v1beta1.ABCIMessageLog)
@ -53,21 +64,14 @@
- [Msg](#cosmos.authz.v1beta1.Msg)
- [cosmos/authz/v1beta1/genesis.proto](#cosmos/authz/v1beta1/genesis.proto)
- [GenesisState](#cosmos.authz.v1beta1.GenesisState)
- [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization)
- [cosmos/base/v1beta1/coin.proto](#cosmos/base/v1beta1/coin.proto)
- [Coin](#cosmos.base.v1beta1.Coin)
- [DecCoin](#cosmos.base.v1beta1.DecCoin)
- [DecProto](#cosmos.base.v1beta1.DecProto)
- [IntProto](#cosmos.base.v1beta1.IntProto)
- [cosmos/base/query/v1beta1/pagination.proto](#cosmos/base/query/v1beta1/pagination.proto)
- [PageRequest](#cosmos.base.query.v1beta1.PageRequest)
- [PageResponse](#cosmos.base.query.v1beta1.PageResponse)
- [cosmos/authz/v1beta1/query.proto](#cosmos/authz/v1beta1/query.proto)
- [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest)
- [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse)
- [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest)
- [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse)
- [Query](#cosmos.authz.v1beta1.Query)
- [cosmos/bank/v1beta1/authz.proto](#cosmos/bank/v1beta1/authz.proto)
- [SendAuthorization](#cosmos.bank.v1beta1.SendAuthorization)
- [cosmos/bank/v1beta1/bank.proto](#cosmos/bank/v1beta1/bank.proto)
- [DenomUnit](#cosmos.bank.v1beta1.DenomUnit)
@ -302,6 +306,7 @@
- [TextProposal](#cosmos.gov.v1beta1.TextProposal)
- [Vote](#cosmos.gov.v1beta1.Vote)
- [VotingParams](#cosmos.gov.v1beta1.VotingParams)
- [WeightedVoteOption](#cosmos.gov.v1beta1.WeightedVoteOption)
- [ProposalStatus](#cosmos.gov.v1beta1.ProposalStatus)
- [VoteOption](#cosmos.gov.v1beta1.VoteOption)
@ -336,6 +341,8 @@
- [MsgSubmitProposalResponse](#cosmos.gov.v1beta1.MsgSubmitProposalResponse)
- [MsgVote](#cosmos.gov.v1beta1.MsgVote)
- [MsgVoteResponse](#cosmos.gov.v1beta1.MsgVoteResponse)
- [MsgVoteWeighted](#cosmos.gov.v1beta1.MsgVoteWeighted)
- [MsgVoteWeightedResponse](#cosmos.gov.v1beta1.MsgVoteWeightedResponse)
- [Msg](#cosmos.gov.v1beta1.Msg)
@ -392,6 +399,12 @@
- [Msg](#cosmos.slashing.v1beta1.Msg)
- [cosmos/staking/v1beta1/authz.proto](#cosmos/staking/v1beta1/authz.proto)
- [StakeAuthorization](#cosmos.staking.v1beta1.StakeAuthorization)
- [StakeAuthorization.Validators](#cosmos.staking.v1beta1.StakeAuthorization.Validators)
- [AuthorizationType](#cosmos.staking.v1beta1.AuthorizationType)
- [cosmos/staking/v1beta1/staking.proto](#cosmos/staking/v1beta1/staking.proto)
- [Commission](#cosmos.staking.v1beta1.Commission)
- [CommissionRates](#cosmos.staking.v1beta1.CommissionRates)
@ -837,6 +850,68 @@ GenesisState defines the auth module's genesis state.
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/base/query/v1beta1/pagination.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/query/v1beta1/pagination.proto
<a name="cosmos.base.query.v1beta1.PageRequest"></a>
### PageRequest
PageRequest is to be embedded in gRPC request messages for efficient
pagination. Ex:
message SomeRequest {
Foo some_parameter = 1;
PageRequest pagination = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [bytes](#bytes) | | key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. |
| `offset` | [uint64](#uint64) | | offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. |
| `limit` | [uint64](#uint64) | | limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. |
| `count_total` | [bool](#bool) | | count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. |
<a name="cosmos.base.query.v1beta1.PageResponse"></a>
### PageResponse
PageResponse is to be embedded in gRPC response messages where the
corresponding request message has used PageRequest.
message SomeResponse {
repeated Bar results = 1;
PageResponse page = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `next_key` | [bytes](#bytes) | | next_key is the key to be passed to PageRequest.key to query the next page most efficiently |
| `total` | [uint64](#uint64) | | total is total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
<!-- end messages -->
<!-- end enums -->
@ -884,6 +959,37 @@ QueryAccountResponse is the response type for the Query/Account RPC method.
<a name="cosmos.auth.v1beta1.QueryAccountsRequest"></a>
### QueryAccountsRequest
QueryAccountsRequest is the request type for the Query/Accounts RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. |
<a name="cosmos.auth.v1beta1.QueryAccountsResponse"></a>
### QueryAccountsResponse
QueryAccountsResponse is the response type for the Query/Accounts RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `accounts` | [google.protobuf.Any](#google.protobuf.Any) | repeated | accounts are the existing accounts |
| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. |
<a name="cosmos.auth.v1beta1.QueryParamsRequest"></a>
### QueryParamsRequest
@ -922,6 +1028,7 @@ Query defines the gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Accounts` | [QueryAccountsRequest](#cosmos.auth.v1beta1.QueryAccountsRequest) | [QueryAccountsResponse](#cosmos.auth.v1beta1.QueryAccountsResponse) | Accounts returns all the existing accounts | GET|/cosmos/auth/v1beta1/accounts|
| `Account` | [QueryAccountRequest](#cosmos.auth.v1beta1.QueryAccountRequest) | [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse) | Account returns account details based on address. | GET|/cosmos/auth/v1beta1/accounts/{address}|
| `Params` | [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse) | Params queries all parameters. | GET|/cosmos/auth/v1beta1/params|
@ -929,90 +1036,6 @@ Query defines the gRPC querier service.
<a name="cosmos/base/v1beta1/coin.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/v1beta1/coin.proto
<a name="cosmos.base.v1beta1.Coin"></a>
### Coin
Coin defines a token with a denomination and an amount.
NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `denom` | [string](#string) | | |
| `amount` | [string](#string) | | |
<a name="cosmos.base.v1beta1.DecCoin"></a>
### DecCoin
DecCoin defines a token with a denomination and a decimal amount.
NOTE: The amount field is an Dec which implements the custom method
signatures required by gogoproto.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `denom` | [string](#string) | | |
| `amount` | [string](#string) | | |
<a name="cosmos.base.v1beta1.DecProto"></a>
### DecProto
DecProto defines a Protobuf wrapper around a Dec object.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `dec` | [string](#string) | | |
<a name="cosmos.base.v1beta1.IntProto"></a>
### IntProto
IntProto defines a Protobuf wrapper around an Int object.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `int` | [string](#string) | | |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/authz/v1beta1/authz.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -1052,17 +1075,50 @@ the provided method on behalf of the granter's account.
<!-- end messages -->
<a name="cosmos.authz.v1beta1.SendAuthorization"></a>
<!-- end enums -->
### SendAuthorization
SendAuthorization allows the grantee to spend up to spend_limit coins from
the granter's account.
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/authz/v1beta1/genesis.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/genesis.proto
<a name="cosmos.authz.v1beta1.GenesisState"></a>
### GenesisState
GenesisState defines the authz module's genesis state.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `authorization` | [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization) | repeated | |
<a name="cosmos.authz.v1beta1.GrantAuthorization"></a>
### GrantAuthorization
GrantAuthorization defines the GenesisState/GrantAuthorization type.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
@ -1078,6 +1134,98 @@ the granter's account.
<a name="cosmos/authz/v1beta1/query.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/query.proto
<a name="cosmos.authz.v1beta1.QueryAuthorizationRequest"></a>
### QueryAuthorizationRequest
QueryAuthorizationRequest is the request type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `method_name` | [string](#string) | | |
<a name="cosmos.authz.v1beta1.QueryAuthorizationResponse"></a>
### QueryAuthorizationResponse
QueryAuthorizationResponse is the response type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | | authorization is a authorization granted for grantee by granter. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsRequest"></a>
### QueryAuthorizationsRequest
QueryAuthorizationsRequest is the request type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an pagination for the request. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsResponse"></a>
### QueryAuthorizationsResponse
QueryAuthorizationsResponse is the response type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorizations` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | repeated | authorizations is a list of grants granted for grantee by granter. |
| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines an pagination for the response. |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<a name="cosmos.authz.v1beta1.Query"></a>
### Query
Query defines the gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Authorization` | [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest) | [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse) | Returns any `Authorization` (or `nil`), with the expiration time, granted to the grantee by the granter for the provided msg type. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grant|
| `Authorizations` | [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest) | [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse) | Returns list of `Authorization`, granted to the grantee by the granter. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grants|
<!-- end services -->
<a name="cosmos/base/abci/v1beta1/abci.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -1393,40 +1541,75 @@ Msg defines the authz Msg service.
<a name="cosmos/authz/v1beta1/genesis.proto"></a>
<a name="cosmos/base/v1beta1/coin.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/genesis.proto
## cosmos/base/v1beta1/coin.proto
<a name="cosmos.authz.v1beta1.GenesisState"></a>
<a name="cosmos.base.v1beta1.Coin"></a>
### GenesisState
GenesisState defines the authz module's genesis state.
### Coin
Coin defines a token with a denomination and an amount.
NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [GrantAuthorization](#cosmos.authz.v1beta1.GrantAuthorization) | repeated | |
| `denom` | [string](#string) | | |
| `amount` | [string](#string) | | |
<a name="cosmos.authz.v1beta1.GrantAuthorization"></a>
<a name="cosmos.base.v1beta1.DecCoin"></a>
### GrantAuthorization
GrantAuthorization defines the GenesisState/GrantAuthorization type.
### DecCoin
DecCoin defines a token with a denomination and a decimal amount.
NOTE: The amount field is an Dec which implements the custom method
signatures required by gogoproto.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `authorization` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `expiration` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
| `denom` | [string](#string) | | |
| `amount` | [string](#string) | | |
<a name="cosmos.base.v1beta1.DecProto"></a>
### DecProto
DecProto defines a Protobuf wrapper around a Dec object.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `dec` | [string](#string) | | |
<a name="cosmos.base.v1beta1.IntProto"></a>
### IntProto
IntProto defines a Protobuf wrapper around an Int object.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `int` | [string](#string) | | |
@ -1442,53 +1625,23 @@ GrantAuthorization defines the GenesisState/GrantAuthorization type.
<a name="cosmos/base/query/v1beta1/pagination.proto"></a>
<a name="cosmos/bank/v1beta1/authz.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/base/query/v1beta1/pagination.proto
## cosmos/bank/v1beta1/authz.proto
<a name="cosmos.base.query.v1beta1.PageRequest"></a>
<a name="cosmos.bank.v1beta1.SendAuthorization"></a>
### PageRequest
PageRequest is to be embedded in gRPC request messages for efficient
pagination. Ex:
message SomeRequest {
Foo some_parameter = 1;
PageRequest pagination = 2;
}
### SendAuthorization
SendAuthorization allows the grantee to spend up to spend_limit coins from
the granter's account.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `key` | [bytes](#bytes) | | key is a value returned in PageResponse.next_key to begin querying the next page most efficiently. Only one of offset or key should be set. |
| `offset` | [uint64](#uint64) | | offset is a numeric offset that can be used when key is unavailable. It is less efficient than using key. Only one of offset or key should be set. |
| `limit` | [uint64](#uint64) | | limit is the total number of results to be returned in the result page. If left empty it will default to a value to be set by each app. |
| `count_total` | [bool](#bool) | | count_total is set to true to indicate that the result set should include a count of the total number of items available for pagination in UIs. count_total is only respected when offset is used. It is ignored when key is set. |
<a name="cosmos.base.query.v1beta1.PageResponse"></a>
### PageResponse
PageResponse is to be embedded in gRPC response messages where the
corresponding request message has used PageRequest.
message SomeResponse {
repeated Bar results = 1;
PageResponse page = 2;
}
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `next_key` | [bytes](#bytes) | | next_key is the key to be passed to PageRequest.key to query the next page most efficiently |
| `total` | [uint64](#uint64) | | total is total number of results available if PageRequest.count_total was set, its value is undefined otherwise |
| `spend_limit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
@ -1504,98 +1657,6 @@ corresponding request message has used PageRequest.
<a name="cosmos/authz/v1beta1/query.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/authz/v1beta1/query.proto
<a name="cosmos.authz.v1beta1.QueryAuthorizationRequest"></a>
### QueryAuthorizationRequest
QueryAuthorizationRequest is the request type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `method_name` | [string](#string) | | |
<a name="cosmos.authz.v1beta1.QueryAuthorizationResponse"></a>
### QueryAuthorizationResponse
QueryAuthorizationResponse is the response type for the Query/Authorization RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorization` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | | authorization is a authorization granted for grantee by granter. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsRequest"></a>
### QueryAuthorizationsRequest
QueryAuthorizationsRequest is the request type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `granter` | [string](#string) | | |
| `grantee` | [string](#string) | | |
| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an pagination for the request. |
<a name="cosmos.authz.v1beta1.QueryAuthorizationsResponse"></a>
### QueryAuthorizationsResponse
QueryAuthorizationsResponse is the response type for the Query/Authorizations RPC method.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `authorizations` | [AuthorizationGrant](#cosmos.authz.v1beta1.AuthorizationGrant) | repeated | authorizations is a list of grants granted for grantee by granter. |
| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines an pagination for the response. |
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<a name="cosmos.authz.v1beta1.Query"></a>
### Query
Query defines the gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Authorization` | [QueryAuthorizationRequest](#cosmos.authz.v1beta1.QueryAuthorizationRequest) | [QueryAuthorizationResponse](#cosmos.authz.v1beta1.QueryAuthorizationResponse) | Returns any `Authorization` (or `nil`), with the expiration time, granted to the grantee by the granter for the provided msg type. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grant|
| `Authorizations` | [QueryAuthorizationsRequest](#cosmos.authz.v1beta1.QueryAuthorizationsRequest) | [QueryAuthorizationsResponse](#cosmos.authz.v1beta1.QueryAuthorizationsResponse) | Returns list of `Authorization`, granted to the grantee by the granter. | GET|/cosmos/authz/v1beta1/granters/{granter}/grantees/{grantee}/grants|
<!-- end services -->
<a name="cosmos/bank/v1beta1/bank.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -1650,6 +1711,8 @@ a basic token.
| `denom_units` | [DenomUnit](#cosmos.bank.v1beta1.DenomUnit) | repeated | denom_units represents the list of DenomUnit's for a given coin |
| `base` | [string](#string) | | base represents the base denom (should be the DenomUnit with exponent = 0). |
| `display` | [string](#string) | | display indicates the suggested denom that should be displayed in clients. |
| `name` | [string](#string) | | name defines the name of the token (eg: Cosmos Atom) |
| `symbol` | [string](#string) | | symbol is the token symbol usually shown on exchanges (eg: ATOM). This can be the same as the display. |
@ -2882,7 +2945,8 @@ Msg defines the bank Msg service.
<a name="cosmos.crypto.ed25519.PrivKey"></a>
### PrivKey
PrivKey defines a ed25519 private key.
Deprecated: PrivKey defines a ed25519 private key.
NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context.
| Field | Type | Label | Description |
@ -2897,11 +2961,11 @@ PrivKey defines a ed25519 private key.
<a name="cosmos.crypto.ed25519.PubKey"></a>
### PubKey
PubKey defines a ed25519 public key
Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte
if the y-coordinate is the lexicographically largest of the two associated with
the x-coordinate. Otherwise the first byte is a 0x03.
This prefix is followed with the x-coordinate.
PubKey is an ed25519 public key for handling Tendermint keys in SDK.
It's needed for Any serialization and SDK compatibility.
It must not be used in a non Tendermint key context because it doesn't implement
ADR-28. Nevertheless, you will like to use ed25519 in app user level
then you must create a new proto message and follow ADR-28 for Address construction.
| Field | Type | Label | Description |
@ -4587,7 +4651,7 @@ A Vote consists of a proposal ID, the voter, and the vote option.
| ----- | ---- | ----- | ----------- |
| `proposal_id` | [uint64](#uint64) | | |
| `voter` | [string](#string) | | |
| `option` | [VoteOption](#cosmos.gov.v1beta1.VoteOption) | | |
| `options` | [WeightedVoteOption](#cosmos.gov.v1beta1.WeightedVoteOption) | repeated | |
@ -4608,6 +4672,22 @@ VotingParams defines the params for voting on governance proposals.
<a name="cosmos.gov.v1beta1.WeightedVoteOption"></a>
### WeightedVoteOption
WeightedVoteOption defines a unit of vote for vote split.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `option` | [VoteOption](#cosmos.gov.v1beta1.VoteOption) | | |
| `weight` | [string](#string) | | |
<!-- end messages -->
@ -5065,6 +5145,33 @@ MsgVoteResponse defines the Msg/Vote response type.
<a name="cosmos.gov.v1beta1.MsgVoteWeighted"></a>
### MsgVoteWeighted
MsgVote defines a message to cast a vote.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `proposal_id` | [uint64](#uint64) | | |
| `voter` | [string](#string) | | |
| `options` | [WeightedVoteOption](#cosmos.gov.v1beta1.WeightedVoteOption) | repeated | |
<a name="cosmos.gov.v1beta1.MsgVoteWeightedResponse"></a>
### MsgVoteWeightedResponse
MsgVoteWeightedResponse defines the Msg/VoteWeighted response type.
<!-- end messages -->
<!-- end enums -->
@ -5081,6 +5188,7 @@ Msg defines the bank Msg service.
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `SubmitProposal` | [MsgSubmitProposal](#cosmos.gov.v1beta1.MsgSubmitProposal) | [MsgSubmitProposalResponse](#cosmos.gov.v1beta1.MsgSubmitProposalResponse) | SubmitProposal defines a method to create new proposal given a content. | |
| `Vote` | [MsgVote](#cosmos.gov.v1beta1.MsgVote) | [MsgVoteResponse](#cosmos.gov.v1beta1.MsgVoteResponse) | Vote defines a method to add a vote on a specific proposal. | |
| `VoteWeighted` | [MsgVoteWeighted](#cosmos.gov.v1beta1.MsgVoteWeighted) | [MsgVoteWeightedResponse](#cosmos.gov.v1beta1.MsgVoteWeightedResponse) | WeightedVote defines a method to add a weighted vote on a specific proposal. | |
| `Deposit` | [MsgDeposit](#cosmos.gov.v1beta1.MsgDeposit) | [MsgDepositResponse](#cosmos.gov.v1beta1.MsgDepositResponse) | Deposit defines a method to add deposit on a specific proposal. | |
<!-- end services -->
@ -5692,6 +5800,69 @@ Msg defines the slashing Msg service.
<a name="cosmos/staking/v1beta1/authz.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## cosmos/staking/v1beta1/authz.proto
<a name="cosmos.staking.v1beta1.StakeAuthorization"></a>
### StakeAuthorization
StakeAuthorization defines authorization for delegate/undelegate/redelegate.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `max_tokens` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is empty, there is no spend limit and any amount of coins can be delegated. |
| `allow_list` | [StakeAuthorization.Validators](#cosmos.staking.v1beta1.StakeAuthorization.Validators) | | allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's account. |
| `deny_list` | [StakeAuthorization.Validators](#cosmos.staking.v1beta1.StakeAuthorization.Validators) | | deny_list specifies list of validator addresses to whom grantee can not delegate tokens. |
| `authorization_type` | [AuthorizationType](#cosmos.staking.v1beta1.AuthorizationType) | | authorization_type defines one of AuthorizationType. |
<a name="cosmos.staking.v1beta1.StakeAuthorization.Validators"></a>
### StakeAuthorization.Validators
Validators defines list of validator addresses.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | repeated | |
<!-- end messages -->
<a name="cosmos.staking.v1beta1.AuthorizationType"></a>
### AuthorizationType
AuthorizationType defines the type of staking module authorization type
| Name | Number | Description |
| ---- | ------ | ----------- |
| AUTHORIZATION_TYPE_UNSPECIFIED | 0 | AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type |
| AUTHORIZATION_TYPE_DELEGATE | 1 | AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate |
| AUTHORIZATION_TYPE_UNDELEGATE | 2 | AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate |
| AUTHORIZATION_TYPE_REDELEGATE | 3 | AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate |
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="cosmos/staking/v1beta1/staking.proto"></a>
<p align="right"><a href="#top">Top</a></p>
@ -7901,17 +8072,20 @@ client.
<a name="ibc.core.client.v1.ClientUpdateProposal"></a>
### ClientUpdateProposal
ClientUpdateProposal is a governance proposal. If it passes, the client is
updated with the provided header. The update may fail if the header is not
valid given certain conditions specified by the client implementation.
ClientUpdateProposal is a governance proposal. If it passes, the substitute client's
consensus states starting from the 'initial height' are copied over to the subjects
client state. The proposal handler may fail if the subject and the substitute do not
match in client and chain parameters (with exception to latest height, frozen height, and chain-id).
The updated client must also be valid (cannot be expired).
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `title` | [string](#string) | | the title of the update proposal |
| `description` | [string](#string) | | the description of the proposal |
| `client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes |
| `header` | [google.protobuf.Any](#google.protobuf.Any) | | the header used to update the client if the proposal passes |
| `subject_client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes |
| `substitute_client_id` | [string](#string) | | the substitute client identifier for the client standing in for the subject client |
| `initial_height` | [Height](#ibc.core.client.v1.Height) | | the intital height to copy consensus states from the substitute to the subject |

View File

@ -12,6 +12,7 @@ This repository contains reference documentation for the IBC protocol integratio
2. [Integration](./integration.md)
3. [Customization](./custom.md)
4. [Relayer](./relayer.md)
5. [Governance Proposals](./proposals.md)
After reading about IBC, head on to the [Building Modules
documentation](../building-modules/README.md) to learn more about the process of building modules.

42
docs/ibc/proposals.md Normal file
View File

@ -0,0 +1,42 @@
<!--
order: 5
-->
# Governance Proposals
In uncommon situations, a highly valued client may become frozen due to uncontrollable
circumstances. A highly valued client might have hundreds of channels being actively used.
Some of those channels might have a significant amount of locked tokens used for ICS 20.
If the one third of the validator set of the chain the client represents decides to collude,
they can sign off on two valid but conflicting headers each signed by the other one third
of the honest validator set. The light client can now be updated with two valid, but conflicting
headers at the same height. The light client cannot know which header is trustworthy and therefore
evidence of such misbehaviour is likely to be submitted resulting in a frozen light client.
Frozen light clients cannot be updated under any circumstance except via a governance proposal.
Since a quorum of validators can sign arbitrary state roots which may not be valid executions
of the state machine, a governance proposal has been added to ease the complexity of unfreezing
or updating clients which have become "stuck". Without this mechanism, validator sets would need
to construct a state root to unfreeze the client. Unfreezing clients, re-enables all of the channels
built upon that client. This may result in recovery of otherwise lost funds.
Tendermint light clients may become expired if the trusting period has passed since their
last update. This may occur if relayers stop submitting headers to update the clients.
An unplanned upgrade by the counterparty chain may also result in expired clients. If the counterparty
chain undergoes an unplanned upgrade, there may be no commitment to that upgrade signed by the validator
set before the chain-id changes. In this situation, the validator set of the last valid update for the
light client is never expected to produce another valid header since the chain-id has changed, which will
ultimately lead the on-chain light client to become expired.
In the case that a highly valued light client is frozen, expired, or rendered non-updateable, a
governance proposal may be submitted to update this client, known as the subject client. The
proposal includes the client identifier for the subject, the client identifier for a substitute
client, and an initial height to reference the substitute client from. Light client implementations
may implement custom updating logic, but in most cases, the subject will be updated with information
from the substitute client, if the proposal passes. The substitute client is used as a "stand in"
while the subject is on trial. It is best practice to create a substitute client *after* the subject
has become frozen to avoid the substitute from also becoming frozen. An active substitute client
allows headers to be submitted during the voting period to prevent accidental expiry once the proposal
passes.

View File

@ -32,11 +32,11 @@ Some important information concerning all legacy REST endpoints:
## Migrating to New REST Endpoints
Thanks to the Protocol Buffers migration in v0.40, we are able to take advantage of a vast number of gRPC tools and solutions. For most of the legacy REST endpoints, Cosmos SDK v0.40 provides new REST endpoints generated from [gRPC `Query` services](../building-modules/query-services.md) using [grpc-gateway](https://grpc-ecosystem.github.io/grpc-gateway/). We usually call them _gGPC-gateway REST endpoints_.
Thanks to the Protocol Buffers migration in v0.40, we are able to take advantage of a vast number of gRPC tools and solutions. For most of the legacy REST endpoints, Cosmos SDK v0.40 provides new REST endpoints generated from [gRPC `Query` services](../building-modules/query-services.md) using [grpc-gateway](https://grpc-ecosystem.github.io/grpc-gateway/). We usually call them _gRPC-gateway REST endpoints_.
Some modules expose legacy `POST` endpoints to generate unsigned transactions for their `Msg`s. These `POST` endpoints have been removed. We recommend to use [service `Msg`s](../building-modules/msg-services.md) directly, and use Protobuf to do client-side transaction generation. A guide can be found [here](../run-node/txs.md).
| Legacy REST Endpoint | Description | New gGPC-gateway REST Endpoint |
| Legacy REST Endpoint | Description | New gRPC-gateway REST Endpoint |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `GET /txs/{hash}` | Query tx by hash | `GET /cosmos/tx/v1beta1/txs/{hash}` |
| `GET /txs` | Query tx by events | `GET /cosmos/tx/v1beta1/txs` |
@ -44,7 +44,7 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
| `POST /txs/encode` | Encodes an Amino JSON tx to an Amino binary tx | N/A, use Protobuf directly |
| `POST /txs/decode` | Decodes an Amino binary tx into an Amino JSON tx | N/A, use Protobuf directly |
| `POST /bank/*` | Create unsigned `Msg`s for bank tx | N/A, use Protobuf directly |
| `GET /bank/balances/{address}` | Get the balance of an address | `GET /cosmos/bank/v1beta1/balances/{address}/{denom}` |
| `GET /bank/balances/{address}` | Get the balance of an address | `GET /cosmos/bank/v1beta1/balances/{address}` |
| `GET /bank/total` | Get the total supply of all coins | `GET /cosmos/bank/v1beta1/supply` |
| `GET /bank/total/{denom}` | Get the total supply of one coin | `GET /cosmos/bank/v1beta1/supply/{denom}` |
| `POST /distribution/delegators/{delegatorAddr}/rewards` | Withdraw all delegator rewards | N/A, use Protobuf directly |
@ -52,8 +52,8 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
| `GET /distribution/delegators/{delegatorAddr}/rewards` | Get the total rewards balance from all delegations | `GET /cosmos/distribution/v1beta1/v1beta1/delegators/{delegator_address}/rewards` |
| `GET /distribution/delegators/{delegatorAddr}/rewards/{validatorAddr}` | Query a delegation reward | `GET /cosmos/distribution/v1beta1/delegators/{delegatorAddr}/rewards/{validatorAddr}` |
| `GET /distribution/delegators/{delegatorAddr}/withdraw_address` | Get the rewards withdrawal address | `GET /cosmos/distribution/v1beta1/delegators/{delegatorAddr}/withdraw_address` |
| `GET /distribution/validators/{validatorAddr}` | Validator distribution information | `GET /cosmos/distribution/v1beta1/validators/{validatorAddr}` |
| `GET /distribution/validators/{validatorAddr}/rewards` | Commission and self-delegation rewards of a single a validator | `GET /cosmos/distribution/v1beta1/validators/{validatorAddr}/rewards` |
| `GET /distribution/validators/{validatorAddr}` | Validator distribution information | N/A |
| `GET /distribution/validators/{validatorAddr}/rewards` | Commission and outstanding rewards of a single a validator | `GET /cosmos/distribution/v1beta1/validators/{validatorAddr}/commission` <br> `GET /cosmos/distribution/v1beta1/validators/{validatorAddr}/outstanding_rewards` |
| `GET /distribution/validators/{validatorAddr}/outstanding_rewards` | Outstanding rewards of a single validator | `GET /cosmos/distribution/v1beta1/validators/{validatorAddr}/outstanding_rewards` |
| `GET /distribution/parameters` | Get the current distribution parameter values | `GET /cosmos/distribution/v1beta1/params` |
| `GET /distribution/community_pool` | Get the amount held in the community pool | `GET /cosmos/distribution/v1beta1/community_pool` |
@ -77,12 +77,12 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
| `GET /slashing/signing_infos` | Get all signing infos | `GET /cosmos/slashing/v1beta1/signing_infos` |
| `GET /slashing/parameters` | Get slashing parameters | `GET /cosmos/slashing/v1beta1/params` |
| `POST /staking/*` | Create unsigned `Msg`s for staking | N/A, use Protobuf directly |
| `GET /staking/delegators/{delegatorAddr}/delegations` | Get all delegations from a delegator | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/delegations` |
| `GET /staking/delegators/{delegatorAddr}/delegations` | Get all delegations from a delegator | `GET /cosmos/staking/v1beta1/delegations/{delegatorAddr}` |
| `GET /staking/delegators/{delegatorAddr}/unbonding_delegations` | Get all unbonding delegations from a delegator | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/unbonding_delegations` |
| `GET /staking/delegators/{delegatorAddr}/txs` | Get all staking txs (i.e msgs) from a delegator | Removed |
| `GET /staking/delegators/{delegatorAddr}/validators` | Query all validators that a delegator is bonded to | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators` |
| `GET /staking/delegators/{delegatorAddr}/validators/{validatorAddr}` | Query a validator that a delegator is bonded to | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators/{validatorAddr}` |
| `GET /staking/delegators/{delegatorAddr}/delegations/{validatorAddr}` | Query a delegation between a delegator and a validator | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/delegations/{validatorAddr}` |
| `GET /staking/delegators/{delegatorAddr}/delegations/{validatorAddr}` | Query a delegation between a delegator and a validator | `GET /cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr}` |
| `GET /staking/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}` | Query all unbonding delegations between a delegator and a validator | `GET /cosmos/staking/v1beta1/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr}` |
| `GET /staking/redelegations` | Query redelegations | `GET /cosmos/staking/v1beta1/v1beta1/delegators/{delegator_addr}/redelegations` |
| `GET /staking/validators` | Get all validators | `GET /cosmos/staking/v1beta1/validators` |

214
docs/package-lock.json generated
View File

@ -5,118 +5,118 @@
"requires": true,
"dependencies": {
"@algolia/cache-browser-local-storage": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.8.3.tgz",
"integrity": "sha512-Cwc03hikHSUI+xvgUdN+H+f6jFyoDsC9fegzXzJ2nPn1YSN9EXzDMBnbrgl0sbl9iLGXe0EIGMYqR2giCv1wMQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.8.4.tgz",
"integrity": "sha512-qSS3VMP3oMhcLrYIFveRyt3F5XB6MqWogF4Vooj8KvOvqv6jBmYwkAueSXCF5pkJEaA72VL9+9NbBpfC8ez2ww==",
"requires": {
"@algolia/cache-common": "4.8.3"
"@algolia/cache-common": "4.8.4"
}
},
"@algolia/cache-common": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.8.3.tgz",
"integrity": "sha512-Cf7zZ2i6H+tLSBTkFePHhYvlgc9fnMPKsF9qTmiU38kFIGORy/TN2Fx5n1GBuRLIzaSXvcf+oHv1HvU0u1gE1g=="
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.8.4.tgz",
"integrity": "sha512-5+dLmj6qFy4WOtnNQuFRfWTIIDdpUigv+dXaKMFplNPBvZHGFy3hcRjWqYzGcqaeLqcXbN8cU5r75mvrlJIxcw=="
},
"@algolia/cache-in-memory": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.8.3.tgz",
"integrity": "sha512-+N7tkvmijXiDy2E7u1mM73AGEgGPWFmEmPeJS96oT46I98KXAwVPNYbcAqBE79YlixdXpkYJk41cFcORzNh+Iw==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.8.4.tgz",
"integrity": "sha512-PBN4YKxn/L+HjVKqUE5rtLiFKqzm4qnUoF7QvCFFmFAViCdYwZSMFVmDobstqWY3KULfsEqaeD4eU4jxZbKhEA==",
"requires": {
"@algolia/cache-common": "4.8.3"
"@algolia/cache-common": "4.8.4"
}
},
"@algolia/client-account": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.8.3.tgz",
"integrity": "sha512-Uku8LqnXBwfDCtsTCDYTUOz2/2oqcAQCKgaO0uGdIR8DTQENBXFQvzziambHdn9KuFuY+6Et9k1+cjpTPBDTBg==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.8.4.tgz",
"integrity": "sha512-mrsOnGV4O2b+t1CumUH72+Psw9d9qwngBEp2le7IMSceJQywQvNCyJ4B4qyoozHsIGapXfcVAOhRxqUsNQ6U6g==",
"requires": {
"@algolia/client-common": "4.8.3",
"@algolia/client-search": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/client-common": "4.8.4",
"@algolia/client-search": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"@algolia/client-analytics": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.8.3.tgz",
"integrity": "sha512-9ensIWmjYJprZ+YjAVSZdWUG05xEnbytENXp508X59tf34IMIX8BR2xl0RjAQODtxBdAteGxuKt5THX6U9tQLA==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.8.4.tgz",
"integrity": "sha512-Xy70njSUgG/QTv5+rPjsTIzBF/bjxseS5h9SawrQGzovTosbJbu9JBlg4YwVJnYvjovzpr7S39+gPIPc8M7+Rg==",
"requires": {
"@algolia/client-common": "4.8.3",
"@algolia/client-search": "4.8.3",
"@algolia/requester-common": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/client-common": "4.8.4",
"@algolia/client-search": "4.8.4",
"@algolia/requester-common": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"@algolia/client-common": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.8.3.tgz",
"integrity": "sha512-TU3623AEFAWUQlDTznkgAMSYo8lfS9pNs5QYDQzkvzWdqK0GBDWthwdRfo9iIsfxiR9qdCMHqwEu+AlZMVhNSA==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.8.4.tgz",
"integrity": "sha512-sQlRa+KWFn+D8AOEZb4kj6RE/i6DnPwVOF4AnNf9IjNB0mUUhLWw96cQN6GDx0KE4lhW67t+qR39ZuuDBgR9ww==",
"requires": {
"@algolia/requester-common": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/requester-common": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"@algolia/client-recommendation": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/client-recommendation/-/client-recommendation-4.8.3.tgz",
"integrity": "sha512-qysGbmkcc6Agt29E38KWJq9JuxjGsyEYoKuX9K+P5HyQh08yR/BlRYrA8mB7vT/OIUHRGFToGO6Vq/rcg0NIOQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/client-recommendation/-/client-recommendation-4.8.4.tgz",
"integrity": "sha512-CE0CVqLGWotVOaUXyU33FVD9FZ/7rqcbwFPH5MgSjVdE0B1YWVedhR0s2BNKodXLcIGVLVYfXR05CLdvOlTw+A==",
"requires": {
"@algolia/client-common": "4.8.3",
"@algolia/requester-common": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/client-common": "4.8.4",
"@algolia/requester-common": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"@algolia/client-search": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.8.3.tgz",
"integrity": "sha512-rAnvoy3GAhbzOQVniFcKVn1eM2NX77LearzYNCbtFrFYavG+hJI187bNVmajToiuGZ10FfJvK99X2OB1AzzezQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.8.4.tgz",
"integrity": "sha512-eH2tRPnDU3tqpp0BSqP6coRRQe8fceqsupuf/1ho+Mcs5DM13mEuFmNOyPywHRlYLVPmbbCPRhDr5rB8QoN7XQ==",
"requires": {
"@algolia/client-common": "4.8.3",
"@algolia/requester-common": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/client-common": "4.8.4",
"@algolia/requester-common": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"@algolia/logger-common": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.8.3.tgz",
"integrity": "sha512-03wksHRbhl2DouEKnqWuUb64s1lV6kDAAabMCQ2Du1fb8X/WhDmxHC4UXMzypeOGlH5BZBsgVwSB7vsZLP3MZg=="
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.8.4.tgz",
"integrity": "sha512-6hOaFG75Onmant9adcaeCZgvPYfnif7n0H1ycbixm6/WH3SmxqPMG+CMiW8mTNTRrrAEceQVrq6tDHD8jdnOOw=="
},
"@algolia/logger-console": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.8.3.tgz",
"integrity": "sha512-Npt+hI4UF8t3TLMluL5utr9Gc11BjL5kDnGZOhDOAz5jYiSO2nrHMFmnpLT4Cy/u7a5t7EB5dlypuC4/AGStkA==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.8.4.tgz",
"integrity": "sha512-+9T3t/eB9vseANFz9YbFHG0cHjzVP/DVfGqzTAkeSlvMHP69JzJga9Wb0Ai6J3xXE3d4k9K+k6t+kkjCQjzEqg==",
"requires": {
"@algolia/logger-common": "4.8.3"
"@algolia/logger-common": "4.8.4"
}
},
"@algolia/requester-browser-xhr": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.8.3.tgz",
"integrity": "sha512-/LTTIpgEmEwkyhn8yXxDdBWqXqzlgw5w2PtTpIwkSlP2/jDwdR/9w1TkFzhNbJ81ki6LAEQM5mSwoTTnbIIecg==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.8.4.tgz",
"integrity": "sha512-BYa8O/pht0UL2bcm0ZkLZiyC+5dHrbc6gvKIo+OgqxmDb/K4KrVo6RIof3BVpR8fgcfxQJohjNVHKXHxEUhBCQ==",
"requires": {
"@algolia/requester-common": "4.8.3"
"@algolia/requester-common": "4.8.4"
}
},
"@algolia/requester-common": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.8.3.tgz",
"integrity": "sha512-+Yo9vBkofoKR1SCqqtMnmnfq9yt/BiaDewY/6bYSMNxSYCnu2Fw1JKSIaf/4zos09PMSsxGpLohZwGas3+0GDQ=="
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.8.4.tgz",
"integrity": "sha512-br3LXb6srfAy7F04axwExmrkPOlXCDckgTFoLFv/RT9Oo28SpoyvHqktyBovQLdzdTs+Laglf+LtOHr0iUrZJg=="
},
"@algolia/requester-node-http": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.8.3.tgz",
"integrity": "sha512-k2fiKIeMIFqgC01FnzII6kqC2GQBAfbNaUX4k7QCPa6P8t4sp2xE6fImOUiztLnnL3C9X9ZX6Fw3L+cudi7jvQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.8.4.tgz",
"integrity": "sha512-o5Cc4UxYPn3IBHQSDBNFFhq1LQLv40eYvCvK0FPJ8xZkrnNXhjPvaLCu/lQTHpk/HX7DaE6fQ/KboU0OSPKevQ==",
"requires": {
"@algolia/requester-common": "4.8.3"
"@algolia/requester-common": "4.8.4"
}
},
"@algolia/transporter": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.8.3.tgz",
"integrity": "sha512-nU7fy2iU8snxATlsks0MjMyv97QJWQmOVwTjDc+KZ4+nue8CLcgm4LA4dsTBqvxeCQIoEtt3n72GwXcaqiJSjQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.8.4.tgz",
"integrity": "sha512-EvXFYICxrr9QEO6m6awUeNOBstOxePQ2Fy0jtYlS1v9TY2P5HqKRzkxmaZjeYRBsXOImpVjgQIzTzj1Au4br2w==",
"requires": {
"@algolia/cache-common": "4.8.3",
"@algolia/logger-common": "4.8.3",
"@algolia/requester-common": "4.8.3"
"@algolia/cache-common": "4.8.4",
"@algolia/logger-common": "4.8.4",
"@algolia/requester-common": "4.8.4"
}
},
"@babel/code-frame": {
@ -1241,9 +1241,9 @@
}
},
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw=="
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
"integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
},
"@types/minimatch": {
"version": "3.0.3",
@ -1251,9 +1251,9 @@
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
},
"@types/node": {
"version": "14.14.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz",
"integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A=="
"version": "14.14.22",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
"integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw=="
},
"@types/q": {
"version": "1.5.4",
@ -1337,9 +1337,9 @@
},
"dependencies": {
"core-js": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.2.tgz",
"integrity": "sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A=="
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
"integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q=="
}
}
},
@ -1510,9 +1510,9 @@
},
"dependencies": {
"core-js": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.2.tgz",
"integrity": "sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A=="
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
"integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q=="
}
}
},
@ -1861,24 +1861,24 @@
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
},
"algoliasearch": {
"version": "4.8.3",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.8.3.tgz",
"integrity": "sha512-pljX9jEE2TQ3i1JayhG8afNdE8UuJg3O9c7unW6QO67yRWCKr6b0t5aKC3hSVtjt7pA2TQXLKoAISb4SHx9ozQ==",
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.8.4.tgz",
"integrity": "sha512-QbXpFvBKj/QhKWE7xBoqaWOWyw7ni6W6THSuFJHOcADRrInhjFCBYjrv+YsIhv9huCepKXWpfV4UJup9BslVhQ==",
"requires": {
"@algolia/cache-browser-local-storage": "4.8.3",
"@algolia/cache-common": "4.8.3",
"@algolia/cache-in-memory": "4.8.3",
"@algolia/client-account": "4.8.3",
"@algolia/client-analytics": "4.8.3",
"@algolia/client-common": "4.8.3",
"@algolia/client-recommendation": "4.8.3",
"@algolia/client-search": "4.8.3",
"@algolia/logger-common": "4.8.3",
"@algolia/logger-console": "4.8.3",
"@algolia/requester-browser-xhr": "4.8.3",
"@algolia/requester-common": "4.8.3",
"@algolia/requester-node-http": "4.8.3",
"@algolia/transporter": "4.8.3"
"@algolia/cache-browser-local-storage": "4.8.4",
"@algolia/cache-common": "4.8.4",
"@algolia/cache-in-memory": "4.8.4",
"@algolia/client-account": "4.8.4",
"@algolia/client-analytics": "4.8.4",
"@algolia/client-common": "4.8.4",
"@algolia/client-recommendation": "4.8.4",
"@algolia/client-search": "4.8.4",
"@algolia/logger-common": "4.8.4",
"@algolia/logger-console": "4.8.4",
"@algolia/requester-browser-xhr": "4.8.4",
"@algolia/requester-common": "4.8.4",
"@algolia/requester-node-http": "4.8.4",
"@algolia/transporter": "4.8.4"
}
},
"align-text": {
@ -2864,9 +2864,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001178",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001178.tgz",
"integrity": "sha512-VtdZLC0vsXykKni8Uztx45xynytOi71Ufx9T8kHptSw9AL4dpqailUJJHavttuzUe1KYuBYtChiWv+BAb7mPmQ=="
"version": "1.0.30001179",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001179.tgz",
"integrity": "sha512-blMmO0QQujuUWZKyVrD1msR4WNDAqb/UPO1Sw2WWsQ7deoM5bJiicKnWJ1Y0NS/aGINSnKPIWBMw5luX+NDUCA=="
},
"caseless": {
"version": "0.12.0",
@ -3406,11 +3406,11 @@
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
},
"core-js-compat": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.2.tgz",
"integrity": "sha512-LO8uL9lOIyRRrQmZxHZFl1RV+ZbcsAkFWTktn5SmH40WgLtSNYN4m4W2v9ONT147PxBY/XrRhrWq8TlvObyUjQ==",
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz",
"integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==",
"requires": {
"browserslist": "^4.16.0",
"browserslist": "^4.16.1",
"semver": "7.0.0"
},
"dependencies": {
@ -4123,9 +4123,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"electron-to-chromium": {
"version": "1.3.641",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.641.tgz",
"integrity": "sha512-b0DLhsHSHESC1I+Nx6n4w4Lr61chMd3m/av1rZQhS2IXTzaS5BMM5N+ldWdMIlni9CITMRM09m8He4+YV/92TA=="
"version": "1.3.642",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.642.tgz",
"integrity": "sha512-cev+jOrz/Zm1i+Yh334Hed6lQVOkkemk2wRozfMF4MtTR7pxf3r3L5Rbd7uX1zMcEqVJ7alJBnJL7+JffkC6FQ=="
},
"elliptic": {
"version": "6.5.3",
@ -6515,9 +6515,9 @@
}
},
"node-releases": {
"version": "1.1.69",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz",
"integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA=="
"version": "1.1.70",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz",
"integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw=="
},
"nopt": {
"version": "1.0.10",

View File

@ -1,3 +1,3 @@
master master
launchpad/backports v0.39
release/v0.40.x v0.40
release/v0.41.x v0.41

12
go.mod
View File

@ -28,17 +28,17 @@ require (
github.com/improbable-eng/grpc-web v0.14.0
github.com/magiconair/properties v1.8.4
github.com/mattn/go-isatty v0.0.12
github.com/otiai10/copy v1.4.2
github.com/otiai10/copy v1.5.0
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.8.0
github.com/prometheus/common v0.15.0
github.com/prometheus/client_golang v1.9.0
github.com/prometheus/common v0.17.0
github.com/rakyll/statik v0.1.7
github.com/regen-network/cosmos-proto v0.3.1
github.com/rs/zerolog v1.20.0
github.com/spf13/afero v1.3.4 // indirect
github.com/spf13/cast v1.3.1
github.com/spf13/cobra v1.1.2
github.com/spf13/cobra v1.1.3
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.1
@ -47,11 +47,11 @@ require (
github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
github.com/tendermint/go-amino v0.16.0
github.com/tendermint/tendermint v0.34.3
github.com/tendermint/tendermint v0.34.8
github.com/tendermint/tm-db v0.6.4
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f
google.golang.org/grpc v1.35.0
google.golang.org/grpc v1.36.0
google.golang.org/protobuf v1.25.0
gopkg.in/ini.v1 v1.61.0 // indirect
gopkg.in/yaml.v2 v2.4.0

21
go.sum
View File

@ -505,8 +505,8 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/otiai10/copy v1.4.2 h1:RTiz2sol3eoXPLF4o+YWqEybwfUa/Q2Nkc4ZIUs3fwI=
github.com/otiai10/copy v1.4.2/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/copy v1.5.0 h1:SoXDGnlTUZoqB/wSuj/Y5L6T5i6iN4YRAcMCd+JnLNU=
github.com/otiai10/copy v1.5.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
@ -546,6 +546,8 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -561,8 +563,9 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.17.0 h1:kDIZLI74SS+3tedSvEkykgBkD7txMxaJAPj8DtJUKYA=
github.com/prometheus/common v0.17.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -599,6 +602,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y=
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4=
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -627,8 +632,8 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.1.2 h1:frHO75w/dH7kEc+e2KYZZKY4+PLrp39OqI77oB8m0KQ=
github.com/spf13/cobra v1.1.2/go.mod h1:ZjwqWkCg0LnXvLRIfTLdB4Y/MCO3gMHHJ2KFxQZy4xE=
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -675,8 +680,8 @@ github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoM
github.com/tendermint/tendermint v0.34.0-rc4/go.mod h1:yotsojf2C1QBOw4dZrTcxbyxmPUrT4hNuOQWX9XUwB4=
github.com/tendermint/tendermint v0.34.0-rc6/go.mod h1:ugzyZO5foutZImv0Iyx/gOFCX6mjJTgbLHTwi17VDVg=
github.com/tendermint/tendermint v0.34.0/go.mod h1:Aj3PIipBFSNO21r+Lq3TtzQ+uKESxkbA3yo/INM4QwQ=
github.com/tendermint/tendermint v0.34.3 h1:9yEsf3WO5VAwPVwrmM+RffDMiijmNfWaBwNttHm0q5w=
github.com/tendermint/tendermint v0.34.3/go.mod h1:h57vnXeOlrdvvNFCqPBSaOrpOivl+2swWEtlUAqStYE=
github.com/tendermint/tendermint v0.34.8 h1:PMWgUx47FrNTsfhxCWzoiIlVAC1SE9+WBlnsF9oQW0I=
github.com/tendermint/tendermint v0.34.8/go.mod h1:JVuu3V1ZexOaZG8VJMRl8lnfrGw6hEB2TVnoUwKRbss=
github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs+yAcLvGI=
github.com/tendermint/tm-db v0.6.3 h1:ZkhQcKnB8/2jr5EaZwGndN4owkPsGezW2fSisS9zGbg=
github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8=
@ -859,6 +864,8 @@ golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -1,6 +1,7 @@
syntax = "proto3";
package cosmos.auth.v1beta1;
import "cosmos/base/query/v1beta1/pagination.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
@ -11,6 +12,11 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types";
// Query defines the gRPC querier service.
service Query {
// Accounts returns all the existing accounts
rpc Accounts(QueryAccountsRequest) returns (QueryAccountsResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/accounts";
}
// Account returns account details based on address.
rpc Account(QueryAccountRequest) returns (QueryAccountResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/accounts/{address}";
@ -22,6 +28,21 @@ service Query {
}
}
// QueryAccountsRequest is the request type for the Query/Accounts RPC method.
message QueryAccountsRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryAccountsResponse is the response type for the Query/Accounts RPC method.
message QueryAccountsResponse {
// accounts are the existing accounts
repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "AccountI"];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryAccountRequest is the request type for the Query/Account RPC method.
message QueryAccountRequest {
option (gogoproto.equal) = false;

View File

@ -1,7 +1,6 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "cosmos/base/v1beta1/coin.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/timestamp.proto";
import "gogoproto/gogo.proto";
@ -9,15 +8,6 @@ import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";
// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
message SendAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}
// GenericAuthorization gives the grantee unrestricted permissions to execute
// the provided method on behalf of the granter's account.
message GenericAuthorization {

View File

@ -5,7 +5,6 @@ import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/authz/v1beta1/tx.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/authz/types";

View File

@ -1,10 +1,7 @@
syntax = "proto3";
package cosmos.authz.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/authz/v1beta1/authz.proto";

View File

@ -0,0 +1,17 @@
syntax = "proto3";
package cosmos.bank.v1beta1;
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/bank/types";
// SendAuthorization allows the grantee to spend up to spend_limit coins from
// the granter's account.
message SendAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

View File

@ -82,4 +82,9 @@ message Metadata {
// display indicates the suggested denom that should be
// displayed in clients.
string display = 4;
// name defines the name of the token (eg: Cosmos Atom)
string name = 5;
// symbol is the token symbol usually shown on exchanges (eg: ATOM). This can
// be the same as the display.
string symbol = 6;
}

View File

@ -5,18 +5,19 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519";
// PubKey defines a ed25519 public key
// Key is the compressed form of the pubkey. The first byte depends is a 0x02 byte
// if the y-coordinate is the lexicographically largest of the two associated with
// the x-coordinate. Otherwise the first byte is a 0x03.
// This prefix is followed with the x-coordinate.
// PubKey is an ed25519 public key for handling Tendermint keys in SDK.
// It's needed for Any serialization and SDK compatibility.
// It must not be used in a non Tendermint key context because it doesn't implement
// ADR-28. Nevertheless, you will like to use ed25519 in app user level
// then you must create a new proto message and follow ADR-28 for Address construction.
message PubKey {
option (gogoproto.goproto_stringer) = false;
bytes key = 1 [(gogoproto.casttype) = "crypto/ed25519.PublicKey"];
}
// PrivKey defines a ed25519 private key.
// Deprecated: PrivKey defines a ed25519 private key.
// NOTE: ed25519 keys must not be used in SDK apps except in a tendermint validator context.
message PrivKey {
bytes key = 1 [(gogoproto.casttype) = "crypto/ed25519.PrivateKey"];
}

View File

@ -29,6 +29,16 @@ enum VoteOption {
VOTE_OPTION_NO_WITH_VETO = 4 [(gogoproto.enumvalue_customname) = "OptionNoWithVeto"];
}
// WeightedVoteOption defines a unit of vote for vote split.
message WeightedVoteOption {
VoteOption option = 1;
string weight = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"weight\""
];
}
// TextProposal defines a standard text proposal whose changes need to be
// manually updated in case of approval.
message TextProposal {
@ -119,9 +129,11 @@ message Vote {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.equal) = false;
uint64 proposal_id = 1 [(gogoproto.moretags) = "yaml:\"proposal_id\""];
string voter = 2;
VoteOption option = 3;
uint64 proposal_id = 1 [(gogoproto.moretags) = "yaml:\"proposal_id\""];
string voter = 2;
reserved 3;
reserved "option";
repeated WeightedVoteOption options = 4 [(gogoproto.nullable) = false];
}
// DepositParams defines the params for deposits on governance proposals.

View File

@ -17,6 +17,9 @@ service Msg {
// Vote defines a method to add a vote on a specific proposal.
rpc Vote(MsgVote) returns (MsgVoteResponse);
// WeightedVote defines a method to add a weighted vote on a specific proposal.
rpc VoteWeighted(MsgVoteWeighted) returns (MsgVoteWeightedResponse);
// Deposit defines a method to add deposit on a specific proposal.
rpc Deposit(MsgDeposit) returns (MsgDepositResponse);
}
@ -55,9 +58,24 @@ message MsgVote {
VoteOption option = 3;
}
// MsgVote defines a message to cast a vote.
message MsgVoteWeighted {
option (gogoproto.equal) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.stringer) = false;
option (gogoproto.goproto_getters) = false;
uint64 proposal_id = 1 [(gogoproto.jsontag) = "proposal_id", (gogoproto.moretags) = "yaml:\"proposal_id\""];
string voter = 2;
repeated WeightedVoteOption options = 3 [(gogoproto.nullable) = false];
}
// MsgVoteResponse defines the Msg/Vote response type.
message MsgVoteResponse {}
// MsgVoteWeightedResponse defines the Msg/VoteWeighted response type.
message MsgVoteWeightedResponse {}
// MsgDeposit defines a message to submit a deposit to an existing proposal.
message MsgDeposit {
option (gogoproto.equal) = false;

View File

@ -0,0 +1,43 @@
syntax = "proto3";
package cosmos.staking.v1beta1;
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/v1beta1/coin.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/staking/types";
// StakeAuthorization defines authorization for delegate/undelegate/redelegate.
message StakeAuthorization {
option (cosmos_proto.implements_interface) = "Authorization";
// max_tokens specifies the maximum amount of tokens can be delegate to a validator. If it is
// empty, there is no spend limit and any amount of coins can be delegated.
cosmos.base.v1beta1.Coin max_tokens = 1 [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"];
// validators is the oneof that represents either allow_list or deny_list
oneof validators {
// allow_list specifies list of validator addresses to whom grantee can delegate tokens on behalf of granter's
// account.
Validators allow_list = 2;
// deny_list specifies list of validator addresses to whom grantee can not delegate tokens.
Validators deny_list = 3;
}
// Validators defines list of validator addresses.
message Validators {
repeated string address = 1;
}
// authorization_type defines one of AuthorizationType.
AuthorizationType authorization_type = 4;
}
// AuthorizationType defines the type of staking module authorization type
enum AuthorizationType {
// AUTHORIZATION_TYPE_UNSPECIFIED specifies an unknown authorization type
AUTHORIZATION_TYPE_UNSPECIFIED = 0;
// AUTHORIZATION_TYPE_DELEGATE defines an authorization type for Msg/Delegate
AUTHORIZATION_TYPE_DELEGATE = 1;
// AUTHORIZATION_TYPE_UNDELEGATE defines an authorization type for Msg/Undelegate
AUTHORIZATION_TYPE_UNDELEGATE = 2;
// AUTHORIZATION_TYPE_REDELEGATE defines an authorization type for Msg/BeginRedelegate
AUTHORIZATION_TYPE_REDELEGATE = 3;
}

View File

@ -28,7 +28,7 @@ message CommissionRates {
option (gogoproto.goproto_stringer) = false;
// rate is the commission rate charged to delegators, as a fraction.
string rate = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string rate = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
// max_rate defines the maximum commission rate which validator can ever charge, as a fraction.
string max_rate = 2 [
(gogoproto.moretags) = "yaml:\"max_rate\"",
@ -49,9 +49,9 @@ message Commission {
option (gogoproto.goproto_stringer) = false;
// commission_rates defines the initial commission rates to be used for creating a validator.
CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
// update_time is the last time the commission rate was changed.
google.protobuf.Timestamp update_time = 2
google.protobuf.Timestamp update_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"update_time\""];
}
@ -61,15 +61,15 @@ message Description {
option (gogoproto.goproto_stringer) = false;
// moniker defines a human-readable name for the validator.
string moniker = 1;
string moniker = 1;
// identity defines an optional identity signature (ex. UPort or Keybase).
string identity = 2;
string identity = 2;
// website defines an optional website link.
string website = 3;
string website = 3;
// security_contact defines an optional email for security contact.
string security_contact = 4 [(gogoproto.moretags) = "yaml:\"security_contact\""];
// details define other optional details.
string details = 5;
string details = 5;
}
// Validator defines a validator, together with the total amount of the
@ -86,12 +86,12 @@ message Validator {
option (gogoproto.goproto_getters) = false;
// operator_address defines the address of the validator's operator; bech encoded in JSON.
string operator_address = 1 [(gogoproto.moretags) = "yaml:\"operator_address\""];
string operator_address = 1 [(gogoproto.moretags) = "yaml:\"operator_address\""];
// consensus_pubkey is the consensus public key of the validator, as a Protobuf Any.
google.protobuf.Any consensus_pubkey = 2
[(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\""];
// jailed defined whether the validator has been jailed from bonded status or not.
bool jailed = 3;
bool jailed = 3;
// status is the validator status (bonded/unbonding/unbonded).
BondStatus status = 4;
// tokens define the delegated tokens (incl. self-delegation).
@ -103,16 +103,16 @@ message Validator {
(gogoproto.nullable) = false
];
// description defines the description terms for the validator.
Description description = 7 [(gogoproto.nullable) = false];
Description description = 7 [(gogoproto.nullable) = false];
// unbonding_height defines, if unbonding, the height at which this validator has begun unbonding.
int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""];
int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""];
// unbonding_time defines, if unbonding, the min time for the validator to complete unbonding.
google.protobuf.Timestamp unbonding_time = 9
google.protobuf.Timestamp unbonding_time = 9
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""];
// commission defines the commission parameters.
Commission commission = 10 [(gogoproto.nullable) = false];
Commission commission = 10 [(gogoproto.nullable) = false];
// min_self_delegation is the validator's self declared minimum self delegation.
string min_self_delegation = 11 [
string min_self_delegation = 11 [
(gogoproto.moretags) = "yaml:\"min_self_delegation\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
@ -201,9 +201,9 @@ message UnbondingDelegation {
option (gogoproto.goproto_stringer) = false;
// delegator_address is the bech32-encoded address of the delegator.
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
// validator_address is the bech32-encoded address of the validator.
string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""];
string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""];
// entries are the unbonding delegation entries.
repeated UnbondingDelegationEntry entries = 3 [(gogoproto.nullable) = false]; // unbonding delegation entries
}
@ -214,7 +214,7 @@ message UnbondingDelegationEntry {
option (gogoproto.goproto_stringer) = false;
// creation_height is the height which the unbonding took place.
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
// completion_time is the unix time for unbonding completion.
google.protobuf.Timestamp completion_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""];
@ -234,7 +234,7 @@ message RedelegationEntry {
option (gogoproto.goproto_stringer) = false;
// creation_height defines the height which the redelegation took place.
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
// completion_time defines the unix time for redelegation completion.
google.protobuf.Timestamp completion_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""];
@ -257,13 +257,13 @@ message Redelegation {
option (gogoproto.goproto_stringer) = false;
// delegator_address is the bech32-encoded address of the delegator.
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
// validator_src_address is the validator redelegation source operator address.
string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""];
string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""];
// validator_dst_address is the validator redelegation destination operator address.
string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""];
string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""];
// entries are the redelegation entries.
repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries
repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries
}
// Params defines the parameters for the staking module.
@ -275,13 +275,13 @@ message Params {
google.protobuf.Duration unbonding_time = 1
[(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""];
// max_validators is the maximum number of validators.
uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""];
uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""];
// max_entries is the max entries for either unbonding delegation or redelegation (per pair/trio).
uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""];
uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""];
// historical_entries is the number of historical entries to persist.
uint32 historical_entries = 4 [(gogoproto.moretags) = "yaml:\"historical_entries\""];
// bond_denom defines the bondable coin denomination.
string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""];
string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""];
}
// DelegationResponse is equivalent to Delegation except that it contains a

View File

@ -33,9 +33,11 @@ message ClientConsensusStates {
[(gogoproto.moretags) = "yaml:\"consensus_states\"", (gogoproto.nullable) = false];
}
// ClientUpdateProposal is a governance proposal. If it passes, the client is
// updated with the provided header. The update may fail if the header is not
// valid given certain conditions specified by the client implementation.
// ClientUpdateProposal is a governance proposal. If it passes, the substitute client's
// consensus states starting from the 'initial height' are copied over to the subjects
// client state. The proposal handler may fail if the subject and the substitute do not
// match in client and chain parameters (with exception to latest height, frozen height, and chain-id).
// The updated client must also be valid (cannot be expired).
message ClientUpdateProposal {
option (gogoproto.goproto_getters) = false;
// the title of the update proposal
@ -43,9 +45,11 @@ message ClientUpdateProposal {
// the description of the proposal
string description = 2;
// the client identifier for the client to be updated if the proposal passes
string client_id = 3 [(gogoproto.moretags) = "yaml:\"client_id\""];
// the header used to update the client if the proposal passes
google.protobuf.Any header = 4;
string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""];
// the substitute client identifier for the client standing in for the subject client
string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"susbtitute_client_id\""];
// the intital height to copy consensus states from the substitute to the subject
Height initial_height = 5 [(gogoproto.moretags) = "yaml:\"initial_height\"", (gogoproto.nullable) = false];
}
// Height is a monotonically increasing data type

View File

@ -10,11 +10,11 @@ for dir in $proto_dirs; do
query_file=$(find "${dir}" -maxdepth 1 \( -name 'query.proto' -o -name 'service.proto' \))
if [[ ! -z "$query_file" ]]; then
buf protoc \
-I "proto" \
-I "third_party/proto" \
"$query_file" \
--swagger_out=./tmp-swagger-gen \
--swagger_opt=logtostderr=true --swagger_opt=fqn_for_swagger_name=true --swagger_opt=simple_operation_ids=true
-I "proto" \
-I "third_party/proto" \
"$query_file" \
--swagger_out=./tmp-swagger-gen \
--swagger_opt=logtostderr=true --swagger_opt=fqn_for_swagger_name=true --swagger_opt=simple_operation_ids=true
fi
done

View File

@ -16,22 +16,22 @@ protoc_gen_gocosmos
proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq)
for dir in $proto_dirs; do
buf protoc \
-I "proto" \
-I "third_party/proto" \
--gocosmos_out=plugins=interfacetype+grpc,\
-I "proto" \
-I "third_party/proto" \
--gocosmos_out=plugins=interfacetype+grpc,\
Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. \
--grpc-gateway_out=logtostderr=true:. \
--grpc-gateway_out=logtostderr=true,allow_colon_final_segments=true:. \
$(find "${dir}" -maxdepth 1 -name '*.proto')
done
# command to generate docs using protoc-gen-doc
buf protoc \
-I "proto" \
-I "third_party/proto" \
--doc_out=./docs/core \
--doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \
$(find "$(pwd)/proto" -maxdepth 5 -name '*.proto')
-I "proto" \
-I "third_party/proto" \
--doc_out=./docs/core \
--doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \
$(find "$(pwd)/proto" -maxdepth 5 -name '*.proto')
go mod tidy
# generate codec/testdata proto code

View File

@ -8,13 +8,14 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server/types"
)
// StartGRPCServer starts a gRPC server on the given address.
func StartGRPCServer(app types.Application, address string) (*grpc.Server, error) {
func StartGRPCServer(clientCtx client.Context, app types.Application, address string) (*grpc.Server, error) {
grpcSrv := grpc.NewServer()
app.RegisterGRPCServer(grpcSrv)
app.RegisterGRPCServer(clientCtx, grpcSrv)
// Reflection allows external clients to see what services and methods
// the gRPC server exposes.

View File

@ -13,15 +13,13 @@ import (
"google.golang.org/grpc/metadata"
rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/types/tx"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
@ -37,6 +35,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
s.cfg = network.DefaultConfig()
s.cfg.NumValidators = 1
s.network = network.New(s.T(), s.cfg)
s.Require().NotNil(s.network)
@ -92,7 +91,7 @@ func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() {
grpc.Header(&header),
)
blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader)
s.Require().Equal([]string{"1"}, blockHeight)
s.Require().NotEmpty(blockHeight[0]) // blockHeight is []string, first element is block height.
}
func (s *IntegrationTestSuite) TestGRPCServer_Reflection() {
@ -124,50 +123,15 @@ func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() {
Events: []string{"message.action=send"},
},
)
// TODO Once https://github.com/cosmos/cosmos-sdk/pull/8029 is merged, this
// should not error anymore.
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TestGRPCServer_BroadcastTx() {
val0 := s.network.Validators[0]
// prepare txBuilder with msg
txBuilder := val0.ClientCtx.TxConfig.NewTxBuilder()
feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}
gasLimit := testdata.NewTestGasLimit()
s.Require().NoError(
txBuilder.SetMsgs(&banktypes.MsgSend{
FromAddress: val0.Address.String(),
ToAddress: val0.Address.String(),
Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)},
}),
)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
// setup txFactory
txFactory := clienttx.Factory{}.
WithChainID(val0.ClientCtx.ChainID).
WithKeybase(val0.ClientCtx.Keyring).
WithTxConfig(val0.ClientCtx.TxConfig).
WithSignMode(signing.SignMode_SIGN_MODE_DIRECT)
// Sign Tx.
err := authclient.SignTx(txFactory, val0.ClientCtx, val0.Moniker, txBuilder, false, true)
s.Require().NoError(err)
txBytes, err := val0.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
// Broadcast the tx via gRPC.
queryClient := tx.NewServiceClient(s.conn)
grpcRes, err := queryClient.BroadcastTx(
context.Background(),
&tx.BroadcastTxRequest{
Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
},
grpcRes, err := banktestutil.LegacyGRPCProtoMsgSend(val0.ClientCtx,
val0.Moniker, val0.Address, val0.Address,
sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}, sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)},
)
s.Require().NoError(err)
s.Require().Equal(uint32(0), grpcRes.TxResponse.Code)
@ -185,9 +149,9 @@ func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() {
value string
wantErr string
}{
{"-1", "height < 0"},
{"-1", "\"x-cosmos-block-height\" must be >= 0"},
{"9223372036854775808", "value out of range"}, // > max(int64) by 1
{"-10", "height < 0"},
{"-10", "\"x-cosmos-block-height\" must be >= 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
}

View File

@ -12,7 +12,7 @@ import (
// phrase to recover the private key.
func GenerateCoinKey(algo keyring.SignatureAlgo) (sdk.AccAddress, string, error) {
// generate a private key, with recovery phrase
info, secret, err := keyring.NewInMemory().NewMnemonic("name", keyring.English, sdk.FullFundraiserPath, algo)
info, secret, err := keyring.NewInMemory().NewMnemonic("name", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
if err != nil {
return sdk.AccAddress([]byte{}), "", err
}
@ -43,7 +43,7 @@ func GenerateSaveCoinKey(keybase keyring.Keyring, keyName string, overwrite bool
}
}
info, secret, err := keybase.NewMnemonic(keyName, keyring.English, sdk.FullFundraiserPath, algo)
info, secret, err := keybase.NewMnemonic(keyName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, algo)
if err != nil {
return sdk.AccAddress([]byte{}), "", err
}

View File

@ -318,7 +318,7 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
grpcWebSrv *http.Server
)
if config.GRPC.Enable {
grpcSrv, err = servergrpc.StartGRPCServer(app, config.GRPC.Address)
grpcSrv, err = servergrpc.StartGRPCServer(clientCtx, app, config.GRPC.Address)
if err != nil {
return err
}

View File

@ -38,7 +38,7 @@ type (
// RegisterGRPCServer registers gRPC services directly with the gRPC
// server.
RegisterGRPCServer(grpc.Server)
RegisterGRPCServer(client.Context, grpc.Server)
// RegisterTxService registers the gRPC Query service for tx (such as tx
// simulation, fetching txs by hash...).

View File

@ -184,11 +184,11 @@ func SetCmdServerContext(cmd *cobra.Command, serverCtx *Context) error {
func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
rootDir := rootViper.GetString(flags.FlagHome)
configPath := filepath.Join(rootDir, "config")
configFile := filepath.Join(configPath, "config.toml")
tmCfgFile := filepath.Join(configPath, "config.toml")
conf := tmcfg.DefaultConfig()
switch _, err := os.Stat(configFile); {
switch _, err := os.Stat(tmCfgFile); {
case os.IsNotExist(err):
tmcfg.EnsureRoot(rootDir)
@ -200,7 +200,7 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
conf.P2P.RecvRate = 5120000
conf.P2P.SendRate = 5120000
conf.Consensus.TimeoutCommit = 5 * time.Second
tmcfg.WriteConfigFile(configFile, conf)
tmcfg.WriteConfigFile(tmCfgFile, conf)
case err != nil:
return nil, err
@ -209,34 +209,37 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
rootViper.SetConfigType("toml")
rootViper.SetConfigName("config")
rootViper.AddConfigPath(configPath)
if err := rootViper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to read in app.toml: %w", err)
return nil, fmt.Errorf("failed to read in %s: %w", tmCfgFile, err)
}
}
// Read into the configuration whatever data the viper instance has for it
// This may come from the configuration file above but also any of the other sources
// viper uses
// Read into the configuration whatever data the viper instance has for it.
// This may come from the configuration file above but also any of the other
// sources viper uses.
if err := rootViper.Unmarshal(conf); err != nil {
return nil, err
}
conf.SetRoot(rootDir)
appConfigFilePath := filepath.Join(configPath, "app.toml")
if _, err := os.Stat(appConfigFilePath); os.IsNotExist(err) {
appCfgFilePath := filepath.Join(configPath, "app.toml")
if _, err := os.Stat(appCfgFilePath); os.IsNotExist(err) {
appConf, err := config.ParseConfig(rootViper)
if err != nil {
return nil, fmt.Errorf("failed to parse app.toml: %w", err)
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
}
config.WriteConfigFile(appConfigFilePath, appConf)
config.WriteConfigFile(appCfgFilePath, appConf)
}
rootViper.SetConfigType("toml")
rootViper.SetConfigName("app")
rootViper.AddConfigPath(configPath)
if err := rootViper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to read in app.toml: %w", err)
if err := rootViper.MergeInConfig(); err != nil {
return nil, fmt.Errorf("failed to merge configuration: %w", err)
}
return conf, nil

View File

@ -162,76 +162,6 @@ func TestInterceptConfigsPreRunHandlerReadsAppToml(t *testing.T) {
}
}
func TestInterceptConfigsPreRunHandlerDoesNotMixConfigFiles(t *testing.T) {
// The goal of this test is to make sure that app.toml and config.toml
// are separate files and that mixing values does not work
const testDbBackend = "awesome_test_db"
const testHaltTime = 1337
const testHaltHeight = 2001
tempDir := t.TempDir()
err := os.Mkdir(path.Join(tempDir, "config"), os.ModePerm)
if err != nil {
t.Fatalf("creating config dir failed: %v", err)
}
configTomlPath := path.Join(tempDir, "config", "config.toml")
writer, err := os.Create(configTomlPath)
if err != nil {
t.Fatalf("creating config.toml file failed: %v", err)
}
// Put a value in config.toml that should be in app.toml
_, err = writer.WriteString(fmt.Sprintf("halt-time = %d\ndb_backend = \"%s\"\n", testHaltTime, testDbBackend))
if err != nil {
t.Fatalf("Failed writing string to config.toml: %v", err)
}
if err := writer.Close(); err != nil {
t.Fatalf("Failed closing config.toml: %v", err)
}
appTomlPath := path.Join(tempDir, "config", "app.toml")
writer, err = os.Create(appTomlPath)
if err != nil {
t.Fatalf("creating app.toml file failed %v", err)
}
// Put a different value in app.toml
_, err = writer.WriteString(fmt.Sprintf("halt-height = %d\n", testHaltHeight))
if err != nil {
t.Fatalf("Failed writing string to app.toml: %v", err)
}
if err := writer.Close(); err != nil {
t.Fatalf("Failed closing app.toml: %v", err)
}
cmd := StartCmd(nil, tempDir)
cmd.PreRunE = preRunETestImpl
serverCtx := &Context{}
ctx := context.WithValue(context.Background(), ServerContextKey, serverCtx)
if err := cmd.ExecuteContext(ctx); err != CancelledInPreRun {
t.Fatalf("function failed with [%T] %v", err, err)
}
// check that the intended value from config.toml is used
if testDbBackend != serverCtx.Config.DBBackend {
t.Error("DBPath was not set from config.toml")
}
// The value from app.toml should be used for this
if testHaltHeight != serverCtx.Viper.GetInt("halt-height") {
t.Error("Halt height is not using provided value")
}
// The value from config.toml should not be used, default is used instead
if 0 != serverCtx.Viper.GetInt("halt-time") {
t.Error("Halt time is not using default")
}
}
func TestInterceptConfigsPreRunHandlerReadsFlags(t *testing.T) {
const testAddr = "tcp://127.1.2.3:12345"
tempDir := t.TempDir()

View File

@ -1,6 +1,7 @@
package simapp
import (
"encoding/json"
"io"
"net/http"
"os"
@ -10,7 +11,6 @@ import (
"github.com/rakyll/statik/fs"
"github.com/spf13/cast"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -69,6 +69,7 @@ import (
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
ibc "github.com/cosmos/cosmos-sdk/x/ibc/core"
ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client"
ibcclienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
porttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/05-port/types"
ibchost "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/core/keeper"
@ -309,7 +310,7 @@ func NewSimApp(
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
AddRoute(ibchost.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper))
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientUpdateProposalHandler(app.IBCKeeper.ClientKeeper))
app.GovKeeper = govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, govRouter,
@ -483,7 +484,7 @@ func (app *SimApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.Re
// InitChainer application update at chain initialization
func (app *SimApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
var genesisState GenesisState
if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
panic(err)
}
return app.mm.InitGenesis(ctx, app.appCodec, genesisState)

View File

@ -11,8 +11,27 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/crisis"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
feegrant "github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
transfer "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer"
ibc "github.com/cosmos/cosmos-sdk/x/ibc/core"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/upgrade"
)
func TestSimAppExportAndBlockedAddrs(t *testing.T) {
@ -52,11 +71,33 @@ func TestGetMaccPerms(t *testing.T) {
func TestRunMigrations(t *testing.T) {
db := dbm.NewMemDB()
encCfg := MakeTestEncodingConfig()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
// Create a new configurator for the purpose of this test.
// Create a new baseapp and configurator for the purpose of this test.
bApp := baseapp.NewBaseApp(appName, logger, db, encCfg.TxConfig.TxDecoder())
bApp.SetCommitMultiStoreTracer(nil)
bApp.SetInterfaceRegistry(encCfg.InterfaceRegistry)
app.BaseApp = bApp
app.configurator = module.NewConfigurator(app.MsgServiceRouter(), app.GRPCQueryRouter())
// We register all modules on the Configurator, except x/bank. x/bank will
// serve as the test subject on which we run the migration tests.
//
// The loop below is the same as calling `RegisterServices` on
// ModuleManager, except that we skip x/bank.
for _, module := range app.mm.Modules {
if module.Name() == banktypes.ModuleName {
continue
}
module.RegisterServices(app.configurator)
}
// Initialize the chain
app.InitChain(abci.RequestInitChain{})
app.Commit()
testCases := []struct {
name string
moduleName string
@ -94,7 +135,7 @@ func TestRunMigrations(t *testing.T) {
var err error
// Since it's very hard to test actual in-place store migrations in
// tests (due to the difficulty of maintaing multiple versions of a
// tests (due to the difficulty of maintaining multiple versions of a
// module), we're just testing here that the migration logic is
// called.
called := 0
@ -115,12 +156,30 @@ func TestRunMigrations(t *testing.T) {
}
require.NoError(t, err)
// Run migrations only for bank. That's why we put the initial
// version for bank as 1, and for all other modules, we put as
// their latest ConsensusVersion.
err = app.RunMigrations(
app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}),
module.MigrationMap{
"auth": 1, "authz": 1, "bank": 1, "staking": 1, "mint": 1, "distribution": 1,
"slashing": 1, "gov": 1, "params": 1, "ibc": 1, "upgrade": 1, "vesting": 1,
"feegrant": 1, "transfer": 1, "evidence": 1, "crisis": 1, "genutil": 1, "capability": 1,
"bank": 1,
"auth": auth.AppModule{}.ConsensusVersion(),
"authz": authz.AppModule{}.ConsensusVersion(),
"staking": staking.AppModule{}.ConsensusVersion(),
"mint": mint.AppModule{}.ConsensusVersion(),
"distribution": distribution.AppModule{}.ConsensusVersion(),
"slashing": slashing.AppModule{}.ConsensusVersion(),
"gov": gov.AppModule{}.ConsensusVersion(),
"params": params.AppModule{}.ConsensusVersion(),
"ibc": ibc.AppModule{}.ConsensusVersion(),
"upgrade": upgrade.AppModule{}.ConsensusVersion(),
"vesting": vesting.AppModule{}.ConsensusVersion(),
"feegrant": feegrant.AppModule{}.ConsensusVersion(),
"transfer": transfer.AppModule{}.ConsensusVersion(),
"evidence": evidence.AppModule{}.ConsensusVersion(),
"crisis": crisis.AppModule{}.ConsensusVersion(),
"genutil": genutil.AppModule{}.ConsensusVersion(),
"capability": capability.AppModule{}.ConsensusVersion(),
},
)
if tc.expRunErr {

View File

@ -10,6 +10,7 @@ const (
DefaultWeightMsgFundCommunityPool int = 50
DefaultWeightMsgDeposit int = 100
DefaultWeightMsgVote int = 67
DefaultWeightMsgVoteWeighted int = 33
DefaultWeightMsgUnjail int = 100
DefaultWeightMsgCreateValidator int = 100
DefaultWeightMsgEditValidator int = 5

View File

@ -136,6 +136,7 @@ func txCommand() *cobra.Command {
authcmd.GetSignCommand(),
authcmd.GetSignBatchCommand(),
authcmd.GetMultiSignCommand(),
authcmd.GetMultiSignBatchCmd(),
authcmd.GetValidateSignaturesCommand(),
flags.LineBreak,
authcmd.GetBroadcastCommand(),

View File

@ -14,9 +14,12 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// AppStateFn returns the initial application state using a genesis or the simulation parameters.
@ -68,6 +71,57 @@ func AppStateFn(cdc codec.JSONMarshaler, simManager *module.SimulationManager) s
appState, simAccs = AppStateRandomizedFn(simManager, r, cdc, accs, genesisTimestamp, appParams)
}
rawState := make(map[string]json.RawMessage)
err := json.Unmarshal(appState, &rawState)
if err != nil {
panic(err)
}
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
if !ok {
panic("staking genesis state is missing")
}
stakingState := new(stakingtypes.GenesisState)
err = cdc.UnmarshalJSON(stakingStateBz, stakingState)
if err != nil {
panic(err)
}
// compute not bonded balance
notBondedTokens := sdk.ZeroInt()
for _, val := range stakingState.Validators {
if val.Status != stakingtypes.Unbonded {
continue
}
notBondedTokens = notBondedTokens.Add(val.GetTokens())
}
notBondedCoins := sdk.NewCoin(stakingState.Params.BondDenom, notBondedTokens)
// edit bank state to make it have the not bonded pool tokens
bankStateBz, ok := rawState[banktypes.ModuleName]
// TODO(fdymylja/jonathan): should we panic in this case
if !ok {
panic("bank genesis state is missing")
}
bankState := new(banktypes.GenesisState)
err = cdc.UnmarshalJSON(bankStateBz, bankState)
if err != nil {
panic(err)
}
bankState.Balances = append(bankState.Balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String(),
Coins: sdk.NewCoins(notBondedCoins),
})
// change appState back
rawState[stakingtypes.ModuleName] = cdc.MustMarshalJSON(stakingState)
rawState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankState)
// replace appstate
appState, err = json.Marshal(rawState)
if err != nil {
panic(err)
}
return appState, simAccs, chainID, genesisTimestamp
}
}

View File

@ -27,6 +27,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
@ -119,7 +120,6 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
}
// set validators and delegations
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis)
@ -130,6 +130,12 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...)
}
// add bonded amount to bonded pool module account
balances = append(balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
})
// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
@ -213,9 +219,9 @@ func createIncrementalAccounts(accNum int) []sdk.AccAddress {
// start at 100 so we can make up to 999 test addresses with valid test addresses
for i := 100; i < (accNum + 100); i++ {
numString := strconv.Itoa(i)
buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string
buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") // base address string
buffer.WriteString(numString) //adding on final two digits to make addresses unique
buffer.WriteString(numString) // adding on final two digits to make addresses unique
res, _ := sdk.AccAddressFromHex(buffer.String())
bech := res.String()
addr, _ := TestAddr(buffer.String(), bech)
@ -231,21 +237,11 @@ func createIncrementalAccounts(accNum int) []sdk.AccAddress {
func AddTestAddrsFromPubKeys(app *SimApp, ctx sdk.Context, pubKeys []cryptotypes.PubKey, accAmt sdk.Int) {
initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt))
setTotalSupply(app, ctx, accAmt, len(pubKeys))
// fill all the addresses with some coins, set the loose pool tokens simultaneously
for _, pubKey := range pubKeys {
saveAccount(app, ctx, sdk.AccAddress(pubKey.Address()), initCoins)
for _, pk := range pubKeys {
initAccountWithCoins(app, ctx, sdk.AccAddress(pk.Address()), initCoins)
}
}
// setTotalSupply provides the total supply based on accAmt * totalAccounts.
func setTotalSupply(app *SimApp, ctx sdk.Context, accAmt sdk.Int, totalAccounts int) {
totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt.MulRaw(int64(totalAccounts))))
prevSupply := app.BankKeeper.GetSupply(ctx)
app.BankKeeper.SetSupply(ctx, banktypes.NewSupply(prevSupply.GetTotal().Add(totalSupply...)))
}
// AddTestAddrs constructs and returns accNum amount of accounts with an
// initial balance of accAmt in random order
func AddTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int) []sdk.AccAddress {
@ -262,21 +258,21 @@ func addTestAddrs(app *SimApp, ctx sdk.Context, accNum int, accAmt sdk.Int, stra
testAddrs := strategy(accNum)
initCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), accAmt))
setTotalSupply(app, ctx, accAmt, accNum)
// fill all the addresses with some coins, set the loose pool tokens simultaneously
for _, addr := range testAddrs {
saveAccount(app, ctx, addr, initCoins)
initAccountWithCoins(app, ctx, addr, initCoins)
}
return testAddrs
}
// saveAccount saves the provided account into the simapp with balance based on initCoins.
func saveAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, initCoins sdk.Coins) {
acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr)
app.AccountKeeper.SetAccount(ctx, acc)
err := app.BankKeeper.AddCoins(ctx, addr, initCoins)
func initAccountWithCoins(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, coins sdk.Coins) {
err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, coins)
if err != nil {
panic(err)
}
err = app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, coins)
if err != nil {
panic(err)
}
@ -440,3 +436,13 @@ type EmptyAppOptions struct{}
func (ao EmptyAppOptions) Get(o string) interface{} {
return nil
}
// FundAccount is a utility function that funds an account by minting and sending the coins to the address
// TODO(fdymylja): instead of using the mint module account, which has the permission of minting, create a "faucet" account
func FundAccount(app *SimApp, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error {
err := app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts)
if err != nil {
return err
}
return app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts)
}

View File

@ -19,7 +19,6 @@ type Store struct {
}
// NewStore returns a reference to a new GasKVStore.
// nolint
func NewStore(parent types.KVStore, gasMeter types.GasMeter, gasConfig types.GasConfig) *Store {
kvs := &Store{
gasMeter: gasMeter,

View File

@ -242,7 +242,7 @@ func New(t *testing.T, cfg Config) *Network {
logger := log.NewNopLogger()
if cfg.EnableLogging {
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger, _ = tmflags.ParseLogLevel("info", logger, tmcfg.DefaultLogLevel())
logger, _ = tmflags.ParseLogLevel("info", logger, tmcfg.DefaultLogLevel)
}
ctx.Logger = logger

View File

@ -93,7 +93,7 @@ func startInProcess(cfg Config, val *Validator) error {
}
if val.AppConfig.GRPC.Enable {
grpcSrv, err := servergrpc.StartGRPCServer(app, val.AppConfig.GRPC.Address)
grpcSrv, err := servergrpc.StartGRPCServer(val.ClientCtx, app, val.AppConfig.GRPC.Address)
if err != nil {
return err
}

View File

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"strings"
"sync"
yaml "gopkg.in/yaml.v2"
@ -26,13 +27,16 @@ const (
// config.SetBech32PrefixForAccount(yourBech32PrefixAccAddr, yourBech32PrefixAccPub)
// config.SetBech32PrefixForValidator(yourBech32PrefixValAddr, yourBech32PrefixValPub)
// config.SetBech32PrefixForConsensusNode(yourBech32PrefixConsAddr, yourBech32PrefixConsPub)
// config.SetPurpose(yourPurpose)
// config.SetCoinType(yourCoinType)
// config.SetFullFundraiserPath(yourFullFundraiserPath)
// config.Seal()
// Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address
Bech32MainPrefix = "cosmos"
// Purpose is the ATOM purpose as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
Purpose = 44
// CoinType is the ATOM coin type as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
CoinType = 118
@ -233,8 +237,28 @@ func (aa AccAddress) Bytes() []byte {
return aa
}
// AccAddress.String() is expensive and if unoptimized dominantly showed up in profiles,
// yet has no mechanisms to trivially cache the result given that AccAddress is a []byte type.
// With the string interning below, we are able to achieve zero cost allocations for string->[]byte
// because the Go compiler recognizes the special case of map[string([]byte)] when used exactly
// in that pattern. See https://github.com/cosmos/cosmos-sdk/issues/8693.
var addMu sync.Mutex
var addrStrMemoize = make(map[string]string)
// String implements the Stringer interface.
func (aa AccAddress) String() string {
func (aa AccAddress) String() (str string) {
addMu.Lock()
defer addMu.Unlock()
if str, ok := addrStrMemoize[string(aa)]; ok {
return str
}
// Otherwise cache it for later memoization.
defer func() {
addrStrMemoize[string(aa)] = str
}()
if aa.Empty() {
return ""
}

7
types/address/README.md Normal file
View File

@ -0,0 +1,7 @@
# Account
This package defines Cosmos SDK address related functions.
## References
+ [ADR-028](../../docs/architecture/adr-028-public-key-addresses.md)

73
types/address/hash.go Normal file
View File

@ -0,0 +1,73 @@
package address
import (
"bytes"
"crypto/sha256"
"fmt"
"reflect"
"sort"
"unsafe"
"github.com/cosmos/cosmos-sdk/types/errors"
)
// Len is the length of base addresses
const Len = sha256.Size
type Addressable interface {
Address() []byte
}
// Hash creates a new address from address type and key
func Hash(typ string, key []byte) []byte {
hasher := sha256.New()
hasher.Write(unsafeStrToByteArray(typ))
th := hasher.Sum(nil)
hasher.Reset()
_, err := hasher.Write(th)
// the error always nil, it's here only to satisfy the io.Writer interface
errors.AssertNil(err)
_, err = hasher.Write(key)
errors.AssertNil(err)
return hasher.Sum(nil)
}
// NewComposed creates a new address based on sub addresses.
func NewComposed(typ string, subAddresses []Addressable) ([]byte, error) {
as := make([][]byte, len(subAddresses))
totalLen := 0
var err error
for i := range subAddresses {
a := subAddresses[i].Address()
as[i], err = LengthPrefix(a)
if err != nil {
return nil, fmt.Errorf("not compatible sub-adddress=%v at index=%d [%w]", a, i, err)
}
totalLen += len(as[i])
}
sort.Slice(as, func(i, j int) bool { return bytes.Compare(as[i], as[j]) <= 0 })
key := make([]byte, totalLen)
offset := 0
for i := range as {
copy(key[offset:], as[i])
offset += len(as[i])
}
return Hash(typ, key), nil
}
// Module is a specialized version of a composed address for modules. Each module account
// is constructed from a module name and module account key.
func Module(moduleName string, key []byte) []byte {
mKey := append([]byte(moduleName), 0)
return Hash("module", append(mKey, key...))
}
// unsafeStrToByteArray uses unsafe to convert string into byte array. Returned bytes
// must not be altered after this function is called as it will cause a segmentation fault.
func unsafeStrToByteArray(s string) []byte {
var buf = *(*[]byte)(unsafe.Pointer(&s))
(*reflect.SliceHeader)(unsafe.Pointer(&buf)).Cap = len(s)
return buf
}

109
types/address/hash_test.go Normal file
View File

@ -0,0 +1,109 @@
package address
import (
"crypto/sha256"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)
func TestAddressSuite(t *testing.T) {
suite.Run(t, new(AddressSuite))
}
type AddressSuite struct{ suite.Suite }
func (suite *AddressSuite) TestHash() {
assert := suite.Assert()
typ := "1"
key := []byte{1}
part1 := sha256.Sum256([]byte(typ))
expected := sha256.Sum256(append(part1[:], key...))
received := Hash(typ, key)
assert.Equal(expected[:], received, "must create a correct address")
received = Hash("other", key)
assert.NotEqual(expected[:], received, "must create a correct address")
assert.Len(received, Len, "must have correct length")
}
func (suite *AddressSuite) TestComposed() {
assert := suite.Assert()
a1 := addrMock{[]byte{11, 12}}
a2 := addrMock{[]byte{21, 22}}
typ := "multisig"
ac, err := NewComposed(typ, []Addressable{a1, a2})
assert.NoError(err)
assert.Len(ac, Len)
// check if optimizations work
checkingKey := append([]byte{}, a1.AddressWithLen(suite.T())...)
checkingKey = append(checkingKey, a2.AddressWithLen(suite.T())...)
ac2 := Hash(typ, checkingKey)
assert.Equal(ac, ac2, "NewComposed works correctly")
// changing order of addresses shouldn't impact a composed address
ac2, err = NewComposed(typ, []Addressable{a2, a1})
assert.NoError(err)
assert.Len(ac2, Len)
assert.Equal(ac, ac2, "NewComposed is not sensitive for order")
// changing a type should change composed address
ac2, err = NewComposed(typ+"other", []Addressable{a2, a1})
assert.NoError(err)
assert.NotEqual(ac, ac2, "NewComposed must be sensitive to type")
// changing order of addresses shouldn't impact a composed address
ac2, err = NewComposed(typ, []Addressable{a1, addrMock{make([]byte, 300, 300)}})
assert.Error(err)
assert.Contains(err.Error(), "should be max 255 bytes, got 300")
}
func (suite *AddressSuite) TestModule() {
assert := suite.Assert()
var modName, key = "myModule", []byte{1, 2}
addr := Module(modName, key)
assert.Len(addr, Len, "must have address length")
addr2 := Module("myModule2", key)
assert.NotEqual(addr, addr2, "changing module name must change address")
addr3 := Module(modName, []byte{1, 2, 3})
assert.NotEqual(addr, addr3, "changing key must change address")
assert.NotEqual(addr2, addr3, "changing key must change address")
}
func unsafeConvertABC() []byte {
return unsafeStrToByteArray("abc")
}
func (suite *AddressSuite) TestUnsafeStrToBytes() {
// we convert in other function to trigger GC. We want to check that
// the underlying array in []bytes is accessible after GC will finish swapping.
for i := 0; i < 5; i++ {
b := unsafeConvertABC()
runtime.GC()
<-time.NewTimer(2 * time.Millisecond).C
b2 := append(b, 'd')
suite.Equal("abc", string(b))
suite.Equal("abcd", string(b2))
}
}
type addrMock struct {
Addr []byte
}
func (a addrMock) Address() []byte {
return a.Addr
}
func (a addrMock) AddressWithLen(t *testing.T) []byte {
addr, err := LengthPrefix(a.Addr)
assert.NoError(t, err)
return addr
}

View File

@ -3,12 +3,19 @@ package address_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/types/address"
)
func TestLengthPrefixedAddressStoreKey(t *testing.T) {
func TestStoreKeySuite(t *testing.T) {
suite.Run(t, new(StoreKeySuite))
}
type StoreKeySuite struct{ suite.Suite }
func (suite *StoreKeySuite) TestLengthPrefix() {
require := suite.Require()
addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
addr256byte := make([]byte, 256)
@ -23,15 +30,16 @@ func TestLengthPrefixedAddressStoreKey(t *testing.T) {
{"20-byte address", addr20byte, append([]byte{byte(20)}, addr20byte...), false},
{"256-byte address (too long)", addr256byte, nil, true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
suite.Run(tt.name, func() {
storeKey, err := address.LengthPrefix(tt.addr)
if tt.expErr {
require.Error(t, err)
require.Error(err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expStoreKey, storeKey)
require.NoError(err)
require.Equal(tt.expStoreKey, storeKey)
}
})
}

Some files were not shown because too many files have changed in this diff Show More