Merge branch 'master' into gov_split_vote_weighted_vote

This commit is contained in:
Sunny Aggarwal 2021-01-10 00:27:20 -05:00
commit 81bc4479c0
193 changed files with 5962 additions and 1895 deletions

View File

@ -37,12 +37,21 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
### Improvements
* (logging) [\#8072](https://github.com/cosmos/cosmos-sdk/pull/8072) Refactor logging:
* Use [zerolog](https://github.com/rs/zerolog) over Tendermint's go-kit logging wrapper.
* Introduce Tendermint's `--log_format=plain|json` flag. Using format `json` allows for emitting structured JSON
logs which can be consumed by an external logging facility (e.g. Loggly). Both formats log to STDERR.
* The existing `--log_level` flag and it's default value now solely relates to the global logging
level (e.g. `info`, `debug`, etc...) instead of `<module>:<level>`.
* (crypto) [\#7987](https://github.com/cosmos/cosmos-sdk/pull/7987) Fix the inconsistency of CryptoCdc, only use `codec/legacy.Cdc`.
* (SDK) [\#7925](https://github.com/cosmos/cosmos-sdk/pull/7925) Updated dependencies to use gRPC v1.33.2
* Updated gRPC dependency to v1.33.2
* Updated iavl dependency to v0.15-rc2
* (version) [\#7848](https://github.com/cosmos/cosmos-sdk/pull/7848) [\#7941](https://github.com/cosmos/cosmos-sdk/pull/7941) `version --long` output now shows the list of build dependencies and replaced build dependencies.
### State Machine Breaking Changes
* (x/upgrade) [\#7979](https://github.com/cosmos/cosmos-sdk/pull/7979) keeper pubkey storage serialization migration from bech32 to protobuf.
### Bug Fixes
@ -53,9 +62,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Client Breaking
* (crypto) [\#7419](https://github.com/cosmos/cosmos-sdk/pull/7419) The SDK doesn't use Tendermint's `crypto.PubKey` interface anymore, and uses instead it's own `PubKey` interface, defined in `crypto/types`. Replace all instances of `crypto.PubKey` by `cryptotypes.Pubkey`.
* (x/staking) [\#7419](https://github.com/cosmos/cosmos-sdk/pull/7419) The `TmConsPubKey` method on ValidatorI has been removed and replaced instead by `ConsPubKey` (which returns a SDK `cryptotypes.PubKey`) and `TmConsPublicKey` (which returns a Tendermint proto PublicKey).
### Improvements
* (tendermint) [\#7828](https://github.com/cosmos/cosmos-sdk/pull/7828) Update tendermint dependency to v0.34.0-rc6
## [v0.40.0-rc2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc2) - 2020-11-02
@ -88,18 +99,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
* __Modules__
* `x/crisis` has a new function: `AddModuleInitFlags`, which will register optional crisis module flags for the start command.
### Bug Fixes
* (client) [\#7699](https://github.com/cosmos/cosmos-sdk/pull/7699) Fix panic in context when setting invalid nodeURI. `WithNodeURI` does not set the `Client` in the context.
* (x/gov) [#7641](https://github.com/cosmos/cosmos-sdk/pull/7641) Fix tally calculation precision error.
### Improvements
### Improvements
* (rest) [#7649](https://github.com/cosmos/cosmos-sdk/pull/7649) Return an unsigned tx in legacy GET /tx endpoint when signature conversion fails
* (cli) [#7764](https://github.com/cosmos/cosmos-sdk/pull/7764) Update x/banking and x/crisis InitChain to improve node startup time
## [v0.40.0-rc1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc1) - 2020-10-19
### Client Breaking Changes

View File

@ -357,7 +357,7 @@ devdoc-update:
### Protobuf ###
###############################################################################
proto-all: proto-format proto-lint proto-check-breaking proto-gen
proto-all: proto-format proto-lint proto-gen
proto-gen:
@echo "Generating Protobuf files"

View File

@ -291,7 +291,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {
// MultiStore (app.cms) so when Commit() is called is persists those values.
app.deliverState.ms.Write()
commitID := app.cms.Commit()
app.logger.Debug("Commit synced", "commit", fmt.Sprintf("%X", commitID))
app.logger.Info("commit synced", "commit", fmt.Sprintf("%X", commitID))
// Reset the Check state to the latest committed.
//
@ -358,30 +358,43 @@ func (app *BaseApp) snapshot(height int64) {
app.logger.Info("snapshot manager not configured")
return
}
app.logger.Info("Creating state snapshot", "height", height)
app.logger.Info("creating state snapshot", "height", height)
snapshot, err := app.snapshotManager.Create(uint64(height))
if err != nil {
app.logger.Error("Failed to create state snapshot", "height", height, "err", err)
app.logger.Error("failed to create state snapshot", "height", height, "err", err)
return
}
app.logger.Info("Completed state snapshot", "height", height, "format", snapshot.Format)
app.logger.Info("completed state snapshot", "height", height, "format", snapshot.Format)
if app.snapshotKeepRecent > 0 {
app.logger.Debug("Pruning state snapshots")
app.logger.Debug("pruning state snapshots")
pruned, err := app.snapshotManager.Prune(app.snapshotKeepRecent)
if err != nil {
app.logger.Error("Failed to prune state snapshots", "err", err)
return
}
app.logger.Debug("Pruned state snapshots", "pruned", pruned)
app.logger.Debug("pruned state snapshots", "pruned", pruned)
}
}
// Query implements the ABCI interface. It delegates to CommitMultiStore if it
// implements Queryable.
func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery {
func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
defer telemetry.MeasureSince(time.Now(), "abci", "query")
// Add panic recovery for all queries.
// ref: https://github.com/cosmos/cosmos-sdk/pull/8039
defer func() {
if r := recover(); r != nil {
res = sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r))
}
}()
// when a client did not provide a query height, manually inject the latest
if req.Height == 0 {
req.Height = app.LastBlockHeight()
@ -425,13 +438,14 @@ func (app *BaseApp) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseLi
snapshots, err := app.snapshotManager.List()
if err != nil {
app.logger.Error("Failed to list snapshots", "err", err)
app.logger.Error("failed to list snapshots", "err", err)
return resp
}
for _, snapshot := range snapshots {
abciSnapshot, err := snapshot.ToABCI()
if err != nil {
app.logger.Error("Failed to list snapshots", "err", err)
app.logger.Error("failed to list snapshots", "err", err)
return resp
}
resp.Snapshots = append(resp.Snapshots, &abciSnapshot)
@ -447,8 +461,13 @@ func (app *BaseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.Re
}
chunk, err := app.snapshotManager.LoadChunk(req.Height, req.Format, req.Chunk)
if err != nil {
app.logger.Error("Failed to load snapshot chunk", "height", req.Height, "format", req.Format,
"chunk", req.Chunk, "err")
app.logger.Error(
"failed to load snapshot chunk",
"height", req.Height,
"format", req.Format,
"chunk", req.Chunk,
"err", err,
)
return abci.ResponseLoadSnapshotChunk{}
}
return abci.ResponseLoadSnapshotChunk{Chunk: chunk}
@ -462,15 +481,16 @@ func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOf
}
if req.Snapshot == nil {
app.logger.Error("Received nil snapshot")
app.logger.Error("received nil snapshot")
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
}
snapshot, err := snapshottypes.SnapshotFromABCI(req.Snapshot)
if err != nil {
app.logger.Error("Failed to decode snapshot metadata", "err", err)
app.logger.Error("failed to decode snapshot metadata", "err", err)
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
}
err = app.snapshotManager.Restore(snapshot)
switch {
case err == nil:
@ -480,13 +500,22 @@ func (app *BaseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOf
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT_FORMAT}
case errors.Is(err, snapshottypes.ErrInvalidMetadata):
app.logger.Error("Rejecting invalid snapshot", "height", req.Snapshot.Height,
"format", req.Snapshot.Format, "err", err)
app.logger.Error(
"rejecting invalid snapshot",
"height", req.Snapshot.Height,
"format", req.Snapshot.Format,
"err", err,
)
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
default:
app.logger.Error("Failed to restore snapshot", "height", req.Snapshot.Height,
"format", req.Snapshot.Format, "err", err)
app.logger.Error(
"failed to restore snapshot",
"height", req.Snapshot.Height,
"format", req.Snapshot.Format,
"err", err,
)
// We currently don't support resetting the IAVL stores and retrying a different snapshot,
// so we ask Tendermint to abort all snapshot restoration.
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}
@ -506,8 +535,12 @@ func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.
return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}
case errors.Is(err, snapshottypes.ErrChunkHashMismatch):
app.logger.Error("Chunk checksum mismatch, rejecting sender and requesting refetch",
"chunk", req.Index, "sender", req.Sender, "err", err)
app.logger.Error(
"chunk checksum mismatch; rejecting sender and requesting refetch",
"chunk", req.Index,
"sender", req.Sender,
"err", err,
)
return abci.ResponseApplySnapshotChunk{
Result: abci.ResponseApplySnapshotChunk_RETRY,
RefetchChunks: []uint32{req.Index},
@ -515,7 +548,7 @@ func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.
}
default:
app.logger.Error("Failed to restore snapshot", "err", err)
app.logger.Error("failed to restore snapshot", "err", err)
return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ABORT}
}
}

View File

@ -16,7 +16,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestGRPCRouter(t *testing.T) {
func TestGRPCGatewayRouter(t *testing.T) {
qr := baseapp.NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)

View File

@ -5,6 +5,8 @@ import (
"strconv"
gogogrpc "github.com/gogo/protobuf/grpc"
grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
@ -74,7 +76,10 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) {
newMethods[i] = grpc.MethodDesc{
MethodName: method.MethodName,
Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, _ grpc.UnaryServerInterceptor) (interface{}, error) {
return methodHandler(srv, ctx, dec, interceptor)
return methodHandler(srv, ctx, dec, grpcmiddleware.ChainUnaryServer(
grpcrecovery.UnaryServerInterceptor(),
interceptor,
))
},
}
}

View File

@ -7,10 +7,13 @@ import (
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/mempool"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
)
// BroadcastTx broadcasts a transactions either synchronously or asynchronously
@ -142,3 +145,36 @@ func (ctx Context) BroadcastTxAsync(txBytes []byte) (*sdk.TxResponse, error) {
return sdk.NewResponseFormatBroadcastTx(res), err
}
// TxServiceBroadcast is a helper function to broadcast a Tx with the correct gRPC types
// from the tx service. Calls `clientCtx.BroadcastTx` under the hood.
func TxServiceBroadcast(grpcCtx context.Context, clientCtx Context, req *tx.BroadcastTxRequest) (*tx.BroadcastTxResponse, error) {
if req == nil || req.TxBytes == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
clientCtx = clientCtx.WithBroadcastMode(normalizeBroadcastMode(req.Mode))
resp, err := clientCtx.BroadcastTx(req.TxBytes)
if err != nil {
return nil, err
}
return &tx.BroadcastTxResponse{
TxResponse: resp,
}, nil
}
// normalizeBroadcastMode converts a broadcast mode into a normalized string
// to be passed into the clientCtx.
func normalizeBroadcastMode(mode tx.BroadcastMode) string {
switch mode {
case tx.BroadcastMode_BROADCAST_MODE_ASYNC:
return "async"
case tx.BroadcastMode_BROADCAST_MODE_BLOCK:
return "block"
case tx.BroadcastMode_BROADCAST_MODE_SYNC:
return "sync"
default:
return "unspecified"
}
}

View File

@ -65,6 +65,10 @@ const (
FlagCountTotal = "count-total"
FlagTimeoutHeight = "timeout-height"
FlagKeyAlgorithm = "algo"
// Tendermint logging flags
FlagLogLevel = "log_level"
FlagLogFormat = "log_format"
)
// LineBreak can be included in a command list to provide a blank line

View File

@ -1,16 +1,18 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: cosmos/base/tendermint/v1beta1/query.proto
package query
package tmservice
import (
context "context"
fmt "fmt"
types "github.com/cosmos/cosmos-sdk/codec/types"
query "github.com/cosmos/cosmos-sdk/types/query"
_ "github.com/gogo/protobuf/gogoproto"
grpc1 "github.com/gogo/protobuf/grpc"
proto "github.com/gogo/protobuf/proto"
p2p "github.com/tendermint/tendermint/proto/tendermint/p2p"
types "github.com/tendermint/tendermint/proto/tendermint/types"
types1 "github.com/tendermint/tendermint/proto/tendermint/types"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
@ -35,7 +37,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type GetValidatorSetByHeightRequest struct {
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
// pagination defines an pagination for the request.
Pagination *PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"`
Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"`
}
func (m *GetValidatorSetByHeightRequest) Reset() { *m = GetValidatorSetByHeightRequest{} }
@ -78,7 +80,7 @@ func (m *GetValidatorSetByHeightRequest) GetHeight() int64 {
return 0
}
func (m *GetValidatorSetByHeightRequest) GetPagination() *PageRequest {
func (m *GetValidatorSetByHeightRequest) GetPagination() *query.PageRequest {
if m != nil {
return m.Pagination
}
@ -90,7 +92,7 @@ type GetValidatorSetByHeightResponse struct {
BlockHeight int64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
Validators []*Validator `protobuf:"bytes,2,rep,name=validators,proto3" json:"validators,omitempty"`
// pagination defines an pagination for the response.
Pagination *PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"`
Pagination *query.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"`
}
func (m *GetValidatorSetByHeightResponse) Reset() { *m = GetValidatorSetByHeightResponse{} }
@ -140,7 +142,7 @@ func (m *GetValidatorSetByHeightResponse) GetValidators() []*Validator {
return nil
}
func (m *GetValidatorSetByHeightResponse) GetPagination() *PageResponse {
func (m *GetValidatorSetByHeightResponse) GetPagination() *query.PageResponse {
if m != nil {
return m.Pagination
}
@ -150,7 +152,7 @@ func (m *GetValidatorSetByHeightResponse) GetPagination() *PageResponse {
// GetLatestValidatorSetRequest is the request type for the Query/GetValidatorSetByHeight RPC method.
type GetLatestValidatorSetRequest struct {
// pagination defines an pagination for the request.
Pagination *PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"`
Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"`
}
func (m *GetLatestValidatorSetRequest) Reset() { *m = GetLatestValidatorSetRequest{} }
@ -186,7 +188,7 @@ func (m *GetLatestValidatorSetRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_GetLatestValidatorSetRequest proto.InternalMessageInfo
func (m *GetLatestValidatorSetRequest) GetPagination() *PageRequest {
func (m *GetLatestValidatorSetRequest) GetPagination() *query.PageRequest {
if m != nil {
return m.Pagination
}
@ -198,7 +200,7 @@ type GetLatestValidatorSetResponse struct {
BlockHeight int64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
Validators []*Validator `protobuf:"bytes,2,rep,name=validators,proto3" json:"validators,omitempty"`
// pagination defines an pagination for the response.
Pagination *PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"`
Pagination *query.PageResponse `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"`
}
func (m *GetLatestValidatorSetResponse) Reset() { *m = GetLatestValidatorSetResponse{} }
@ -248,7 +250,7 @@ func (m *GetLatestValidatorSetResponse) GetValidators() []*Validator {
return nil
}
func (m *GetLatestValidatorSetResponse) GetPagination() *PageResponse {
func (m *GetLatestValidatorSetResponse) GetPagination() *query.PageResponse {
if m != nil {
return m.Pagination
}
@ -257,10 +259,10 @@ func (m *GetLatestValidatorSetResponse) GetPagination() *PageResponse {
// Validator is the type for the validator-set.
type Validator struct {
Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
PubKey string `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
VotingPower int64 `protobuf:"varint,3,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
ProposerPriority int64 `protobuf:"varint,4,opt,name=proposer_priority,json=proposerPriority,proto3" json:"proposer_priority,omitempty"`
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
PubKey *types.Any `protobuf:"bytes,2,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
VotingPower int64 `protobuf:"varint,3,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"`
ProposerPriority int64 `protobuf:"varint,4,opt,name=proposer_priority,json=proposerPriority,proto3" json:"proposer_priority,omitempty"`
}
func (m *Validator) Reset() { *m = Validator{} }
@ -296,18 +298,18 @@ func (m *Validator) XXX_DiscardUnknown() {
var xxx_messageInfo_Validator proto.InternalMessageInfo
func (m *Validator) GetAddress() []byte {
func (m *Validator) GetAddress() string {
if m != nil {
return m.Address
}
return nil
return ""
}
func (m *Validator) GetPubKey() string {
func (m *Validator) GetPubKey() *types.Any {
if m != nil {
return m.PubKey
}
return ""
return nil
}
func (m *Validator) GetVotingPower() int64 {
@ -371,8 +373,8 @@ func (m *GetBlockByHeightRequest) GetHeight() int64 {
// GetBlockByHeightResponse is the response type for the Query/GetBlockByHeight RPC method.
type GetBlockByHeightResponse struct {
BlockId *types.BlockID `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
Block *types.Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
BlockId *types1.BlockID `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
Block *types1.Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
}
func (m *GetBlockByHeightResponse) Reset() { *m = GetBlockByHeightResponse{} }
@ -408,14 +410,14 @@ func (m *GetBlockByHeightResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_GetBlockByHeightResponse proto.InternalMessageInfo
func (m *GetBlockByHeightResponse) GetBlockId() *types.BlockID {
func (m *GetBlockByHeightResponse) GetBlockId() *types1.BlockID {
if m != nil {
return m.BlockId
}
return nil
}
func (m *GetBlockByHeightResponse) GetBlock() *types.Block {
func (m *GetBlockByHeightResponse) GetBlock() *types1.Block {
if m != nil {
return m.Block
}
@ -461,8 +463,8 @@ var xxx_messageInfo_GetLatestBlockRequest proto.InternalMessageInfo
// GetLatestBlockResponse is the response type for the Query/GetLatestBlock RPC method.
type GetLatestBlockResponse struct {
BlockId *types.BlockID `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
Block *types.Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
BlockId *types1.BlockID `protobuf:"bytes,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
Block *types1.Block `protobuf:"bytes,2,opt,name=block,proto3" json:"block,omitempty"`
}
func (m *GetLatestBlockResponse) Reset() { *m = GetLatestBlockResponse{} }
@ -498,14 +500,14 @@ func (m *GetLatestBlockResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_GetLatestBlockResponse proto.InternalMessageInfo
func (m *GetLatestBlockResponse) GetBlockId() *types.BlockID {
func (m *GetLatestBlockResponse) GetBlockId() *types1.BlockID {
if m != nil {
return m.BlockId
}
return nil
}
func (m *GetLatestBlockResponse) GetBlock() *types.Block {
func (m *GetLatestBlockResponse) GetBlock() *types1.Block {
if m != nil {
return m.Block
}
@ -783,7 +785,7 @@ type Module struct {
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
// module version
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
//checksum
// checksum
Sum string `protobuf:"bytes,3,opt,name=sum,proto3" json:"sum,omitempty"`
}
@ -864,72 +866,74 @@ func init() {
}
var fileDescriptor_40c93fb3ef485c5d = []byte{
// 1031 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
0x14, 0xcf, 0xc6, 0x6d, 0x1c, 0x3f, 0x57, 0x90, 0x4c, 0x4a, 0xb3, 0xb5, 0x52, 0x37, 0xec, 0xa1,
0x4d, 0x88, 0xb2, 0x2b, 0x3b, 0x84, 0x82, 0xf8, 0x27, 0x85, 0x40, 0x1a, 0x15, 0xaa, 0x68, 0x83,
0x38, 0x20, 0xa4, 0xd5, 0xd8, 0x3b, 0xd9, 0x8c, 0x62, 0xef, 0x4c, 0x77, 0xc6, 0x41, 0x16, 0xaa,
0x40, 0xfd, 0x00, 0x08, 0x89, 0xaf, 0xc0, 0x85, 0x2f, 0xc0, 0x11, 0x71, 0xe4, 0x46, 0x25, 0x24,
0xe8, 0x11, 0x25, 0x7c, 0x0a, 0x4e, 0x68, 0x67, 0x66, 0xed, 0xdd, 0x26, 0xa9, 0xed, 0x1c, 0x90,
0x38, 0x79, 0xf6, 0xbd, 0xf7, 0x7b, 0xf3, 0xfb, 0xbd, 0x79, 0x33, 0x7e, 0xf0, 0x5a, 0x9b, 0x89,
0x2e, 0x13, 0x5e, 0x0b, 0x0b, 0xe2, 0x49, 0x12, 0x87, 0x24, 0xe9, 0xd2, 0x58, 0x7a, 0xc7, 0x8d,
0x16, 0x91, 0xb8, 0xe1, 0x3d, 0xea, 0x91, 0xa4, 0xef, 0xf2, 0x84, 0x49, 0x86, 0xea, 0x3a, 0xd6,
0x4d, 0x63, 0xdd, 0x61, 0xac, 0x6b, 0x62, 0x6b, 0xd7, 0x23, 0x16, 0x31, 0x15, 0xea, 0xa5, 0x2b,
0x8d, 0xaa, 0x2d, 0x45, 0x8c, 0x45, 0x1d, 0xe2, 0x61, 0x4e, 0x3d, 0x1c, 0xc7, 0x4c, 0x62, 0x49,
0x59, 0x2c, 0x8c, 0xb7, 0x96, 0xdb, 0x93, 0x37, 0xb9, 0x27, 0xfb, 0x9c, 0x64, 0xbe, 0xa5, 0x9c,
0x4f, 0xd9, 0xbd, 0x56, 0x87, 0xb5, 0x8f, 0x2e, 0xf4, 0xe6, 0xb1, 0x05, 0x5d, 0x4a, 0xc4, 0x40,
0x12, 0xc7, 0x11, 0x8d, 0x15, 0x09, 0x1d, 0xeb, 0x7c, 0x63, 0x41, 0x7d, 0x87, 0xc8, 0xcf, 0x70,
0x87, 0x86, 0x58, 0xb2, 0x64, 0x9f, 0xc8, 0xad, 0xfe, 0x7d, 0x42, 0xa3, 0x43, 0xe9, 0x93, 0x47,
0x3d, 0x22, 0x24, 0xba, 0x01, 0x33, 0x87, 0xca, 0x60, 0x5b, 0xcb, 0xd6, 0x4a, 0xc9, 0x37, 0x5f,
0xe8, 0x23, 0x80, 0x61, 0x3a, 0x7b, 0x7a, 0xd9, 0x5a, 0xa9, 0x36, 0xef, 0xb8, 0xf9, 0x3a, 0xe9,
0x02, 0x9a, 0xbd, 0xdd, 0x3d, 0x1c, 0x11, 0x93, 0xd3, 0xcf, 0x21, 0x9d, 0x67, 0x16, 0xdc, 0xbe,
0x90, 0x82, 0xe0, 0x2c, 0x16, 0x04, 0xbd, 0x0a, 0xd7, 0x94, 0xfe, 0xa0, 0xc0, 0xa4, 0xaa, 0x6c,
0x3a, 0x14, 0xed, 0x02, 0x1c, 0x67, 0x29, 0x84, 0x3d, 0xbd, 0x5c, 0x5a, 0xa9, 0x36, 0x57, 0xdd,
0x17, 0x1f, 0x9b, 0x3b, 0xd8, 0xd4, 0xcf, 0x81, 0xd1, 0x4e, 0x41, 0x59, 0x49, 0x29, 0xbb, 0x3b,
0x52, 0x99, 0xa6, 0x5a, 0x90, 0x76, 0x00, 0x4b, 0x3b, 0x44, 0x7e, 0x8c, 0x25, 0x11, 0x05, 0x7d,
0x59, 0x69, 0x8b, 0x25, 0xb4, 0x2e, 0x5d, 0xc2, 0x3f, 0x2c, 0xb8, 0x75, 0xc1, 0x46, 0xff, 0xef,
0x02, 0x7e, 0x6b, 0x41, 0x65, 0xb0, 0x05, 0xb2, 0xa1, 0x8c, 0xc3, 0x30, 0x21, 0x42, 0x28, 0xfe,
0xd7, 0xfc, 0xec, 0x13, 0x2d, 0x42, 0x99, 0xf7, 0x5a, 0xc1, 0x11, 0xe9, 0xab, 0x46, 0xac, 0xf8,
0x33, 0xbc, 0xd7, 0x7a, 0x40, 0xfa, 0xa9, 0xee, 0x63, 0x26, 0x69, 0x1c, 0x05, 0x9c, 0x7d, 0x49,
0x12, 0xc5, 0xa5, 0xe4, 0x57, 0xb5, 0x6d, 0x2f, 0x35, 0xa1, 0x35, 0x98, 0xe7, 0x09, 0xe3, 0x4c,
0x90, 0x24, 0xe0, 0x09, 0x65, 0x09, 0x95, 0x7d, 0xfb, 0x8a, 0x8a, 0x9b, 0xcb, 0x1c, 0x7b, 0xc6,
0xee, 0x34, 0x60, 0x71, 0x87, 0xc8, 0xad, 0xb4, 0x6c, 0x63, 0xde, 0x13, 0xe7, 0x6b, 0xb0, 0xcf,
0x42, 0xcc, 0xb1, 0xbc, 0x0e, 0xb3, 0xfa, 0x58, 0x68, 0x68, 0x8e, 0xff, 0x66, 0xbe, 0xca, 0xfa,
0x56, 0x2b, 0xe8, 0xee, 0xb6, 0x5f, 0x56, 0xa1, 0xbb, 0x21, 0x5a, 0x87, 0xab, 0x6a, 0x69, 0x2e,
0xdd, 0xe2, 0x05, 0x10, 0x5f, 0x47, 0x39, 0x8b, 0xf0, 0xca, 0xa0, 0x39, 0xb4, 0x43, 0x33, 0x76,
0x1e, 0xc3, 0x8d, 0xe7, 0x1d, 0xff, 0x25, 0xaf, 0x05, 0x98, 0xdf, 0x21, 0x72, 0xbf, 0x1f, 0xb7,
0x69, 0x1c, 0x65, 0x9c, 0x5c, 0x40, 0x79, 0xa3, 0xe1, 0x63, 0x43, 0x59, 0x68, 0x93, 0xa2, 0x33,
0xeb, 0x67, 0x9f, 0xce, 0x75, 0x15, 0xff, 0x90, 0x85, 0x64, 0x37, 0x3e, 0x60, 0x59, 0x96, 0x5f,
0x2c, 0x58, 0x28, 0x98, 0x4d, 0x9e, 0x07, 0x30, 0x1f, 0x92, 0x03, 0xdc, 0xeb, 0xc8, 0x20, 0x66,
0x21, 0x09, 0x68, 0x7c, 0xc0, 0x8c, 0xc0, 0xdb, 0x79, 0xb6, 0xbc, 0xc9, 0xdd, 0x6d, 0x1d, 0x38,
0xc8, 0xf1, 0x72, 0x58, 0x34, 0xa0, 0x2f, 0x60, 0x01, 0x73, 0xde, 0xa1, 0x6d, 0xd5, 0xab, 0xc1,
0x31, 0x49, 0xc4, 0xf0, 0x25, 0x5c, 0x1b, 0x79, 0x73, 0x74, 0xb8, 0x4a, 0x8d, 0x72, 0x79, 0x8c,
0xdd, 0xf9, 0xc7, 0x82, 0x6a, 0x2e, 0x06, 0x21, 0xb8, 0x12, 0xe3, 0x2e, 0x51, 0x6c, 0x2b, 0xbe,
0x5a, 0xa3, 0x9b, 0x30, 0x8b, 0x39, 0x0f, 0x94, 0x5d, 0xf7, 0x7d, 0x19, 0x73, 0xfe, 0x30, 0x75,
0xd9, 0x50, 0xce, 0x08, 0x95, 0xb4, 0xc7, 0x7c, 0xa2, 0x5b, 0x00, 0x11, 0x95, 0x41, 0x9b, 0x75,
0xbb, 0x54, 0xaa, 0x46, 0xaf, 0xf8, 0x95, 0x88, 0xca, 0x0f, 0x94, 0x21, 0x75, 0xb7, 0x7a, 0xb4,
0x13, 0x06, 0x12, 0x47, 0xc2, 0xbe, 0xaa, 0xdd, 0xca, 0xf2, 0x29, 0x8e, 0x84, 0x42, 0xb3, 0x81,
0xd6, 0x19, 0x83, 0x66, 0x86, 0x29, 0xfa, 0x30, 0x43, 0x87, 0x84, 0x0b, 0xbb, 0xac, 0x1e, 0x91,
0x3b, 0xa3, 0x4a, 0xf1, 0x09, 0x0b, 0x7b, 0x1d, 0x62, 0x76, 0xd9, 0x26, 0x5c, 0x38, 0xf7, 0x61,
0x46, 0x1b, 0x53, 0xd9, 0x1c, 0xcb, 0xc3, 0x4c, 0x76, 0xba, 0xce, 0x6b, 0x9b, 0x2e, 0x6a, 0x9b,
0x83, 0x92, 0xe8, 0x75, 0x8d, 0xe2, 0x74, 0xd9, 0x7c, 0x52, 0x81, 0xf2, 0x3e, 0x49, 0x8e, 0x69,
0x9b, 0xa0, 0x1f, 0x2d, 0xa8, 0xe6, 0xba, 0x02, 0x35, 0x47, 0x11, 0x3b, 0xdb, 0x59, 0xb5, 0x8d,
0x89, 0x30, 0xba, 0xed, 0x9c, 0xc6, 0x93, 0xdf, 0xff, 0xfe, 0x7e, 0x7a, 0x0d, 0xad, 0x7a, 0x23,
0x46, 0x8e, 0x41, 0x53, 0xa2, 0x1f, 0x2c, 0x80, 0xe1, 0x45, 0x40, 0x8d, 0x31, 0xb6, 0x2d, 0xde,
0xa4, 0x5a, 0x73, 0x12, 0x88, 0x21, 0xea, 0x29, 0xa2, 0xab, 0xe8, 0xee, 0x28, 0xa2, 0xe6, 0xfa,
0xa1, 0x9f, 0x2c, 0x78, 0xa9, 0xf8, 0x86, 0xa0, 0xcd, 0x31, 0xf6, 0x3d, 0xfb, 0x18, 0xd5, 0xde,
0x98, 0x14, 0x66, 0x28, 0x6f, 0x2a, 0xca, 0x1e, 0x5a, 0x1f, 0x45, 0x59, 0x3d, 0x3a, 0xc2, 0xeb,
0xa8, 0x1c, 0xe8, 0x67, 0x0b, 0xe6, 0x9e, 0x7f, 0x96, 0xd1, 0xbd, 0x31, 0x38, 0x9c, 0xf7, 0xf6,
0xd7, 0xde, 0x9c, 0x1c, 0x68, 0xe8, 0xdf, 0x53, 0xf4, 0x1b, 0xc8, 0x1b, 0x93, 0xfe, 0x57, 0xfa,
0x5f, 0xe5, 0x31, 0xfa, 0xcd, 0xca, 0x3d, 0xeb, 0xf9, 0xff, 0x7c, 0xf4, 0xce, 0xd8, 0x95, 0x3c,
0x67, 0x26, 0xa9, 0xbd, 0x7b, 0x49, 0xb4, 0xd1, 0xf3, 0x96, 0xd2, 0xb3, 0x81, 0x1a, 0xa3, 0xf4,
0x0c, 0xc7, 0x85, 0xec, 0x48, 0xfe, 0xb4, 0xd4, 0x9f, 0xeb, 0x79, 0x83, 0x20, 0x7a, 0x6f, 0x0c,
0x56, 0x2f, 0x18, 0x62, 0x6b, 0xef, 0x5f, 0x1a, 0x6f, 0x74, 0xbd, 0xad, 0x74, 0x6d, 0xa2, 0x8d,
0x09, 0x74, 0x65, 0x67, 0xb5, 0xb5, 0xf5, 0xeb, 0x49, 0xdd, 0x7a, 0x7a, 0x52, 0xb7, 0xfe, 0x3a,
0xa9, 0x5b, 0xdf, 0x9d, 0xd6, 0xa7, 0x9e, 0x9e, 0xd6, 0xa7, 0x9e, 0x9d, 0xd6, 0xa7, 0x3e, 0x5f,
0x89, 0xa8, 0x3c, 0xec, 0xb5, 0xdc, 0x36, 0xeb, 0x66, 0x89, 0xf5, 0xcf, 0xba, 0x08, 0x8f, 0xcc,
0x6c, 0xaf, 0x66, 0xa5, 0xd6, 0x8c, 0x1a, 0xd8, 0x37, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x20,
0x61, 0xbc, 0x54, 0xb6, 0x0c, 0x00, 0x00,
// 1059 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x56, 0xcf, 0x6f, 0xdc, 0xc4,
0x17, 0x8f, 0xb3, 0x6d, 0x36, 0x79, 0xfb, 0xd5, 0x97, 0x64, 0x12, 0x1a, 0xc7, 0x4a, 0xb7, 0xc1,
0x87, 0x36, 0x21, 0x8a, 0xad, 0xdd, 0x10, 0x0a, 0xe2, 0x97, 0x08, 0x81, 0x34, 0x6a, 0xa9, 0x22,
0x07, 0x71, 0x40, 0x48, 0x96, 0x77, 0x3d, 0x71, 0x46, 0xd9, 0xf5, 0x4c, 0x3d, 0xe3, 0xa0, 0x15,
0xaa, 0x40, 0xfd, 0x0b, 0x90, 0xf8, 0x17, 0x7a, 0xe1, 0x1f, 0xe0, 0x88, 0x38, 0x72, 0xa3, 0x12,
0x12, 0xf4, 0x88, 0x12, 0xfe, 0x0a, 0x4e, 0xc8, 0x33, 0xe3, 0x5d, 0xbb, 0x49, 0xba, 0xbb, 0x39,
0x20, 0x71, 0xf2, 0xcc, 0xfb, 0x35, 0x9f, 0xcf, 0x9b, 0xf7, 0x9e, 0x07, 0x5e, 0x6f, 0x53, 0xde,
0xa5, 0xdc, 0x6d, 0x05, 0x1c, 0xbb, 0x02, 0xc7, 0x21, 0x4e, 0xba, 0x24, 0x16, 0xee, 0x49, 0xa3,
0x85, 0x45, 0xd0, 0x70, 0x1f, 0xa5, 0x38, 0xe9, 0x39, 0x2c, 0xa1, 0x82, 0xa2, 0xba, 0xb2, 0x75,
0x32, 0x5b, 0x67, 0x60, 0xeb, 0x68, 0x5b, 0x6b, 0x21, 0xa2, 0x11, 0x95, 0xa6, 0x6e, 0xb6, 0x52,
0x5e, 0xd6, 0x52, 0x44, 0x69, 0xd4, 0xc1, 0xae, 0xdc, 0xb5, 0xd2, 0x43, 0x37, 0x88, 0x75, 0x40,
0x6b, 0x59, 0xab, 0x02, 0x46, 0xdc, 0x20, 0x8e, 0xa9, 0x08, 0x04, 0xa1, 0x31, 0xd7, 0x5a, 0xab,
0x00, 0x87, 0x35, 0x99, 0x2b, 0x7a, 0x0c, 0xe7, 0xba, 0xe5, 0x82, 0x4e, 0xca, 0xdd, 0x56, 0x87,
0xb6, 0x8f, 0x2f, 0xd5, 0x16, 0x7d, 0x4b, 0x94, 0x25, 0xbf, 0x3e, 0x5b, 0x16, 0x44, 0x24, 0x96,
0x20, 0x94, 0xad, 0xfd, 0xad, 0x01, 0xf5, 0x5d, 0x2c, 0x3e, 0x0f, 0x3a, 0x24, 0x0c, 0x04, 0x4d,
0x0e, 0xb0, 0xd8, 0xee, 0xdd, 0xc3, 0x24, 0x3a, 0x12, 0x1e, 0x7e, 0x94, 0x62, 0x2e, 0xd0, 0x0d,
0x98, 0x3a, 0x92, 0x02, 0xd3, 0x58, 0x31, 0x56, 0x2b, 0x9e, 0xde, 0xa1, 0x4f, 0x00, 0x06, 0xe1,
0xcc, 0xc9, 0x15, 0x63, 0xb5, 0xd6, 0xbc, 0xed, 0x14, 0x53, 0xa8, 0x72, 0xab, 0xcf, 0x76, 0xf6,
0x83, 0x08, 0xeb, 0x98, 0x5e, 0xc1, 0xd3, 0x7e, 0x6e, 0xc0, 0xad, 0x4b, 0x21, 0x70, 0x46, 0x63,
0x8e, 0xd1, 0x6b, 0xf0, 0x3f, 0xc9, 0xdf, 0x2f, 0x21, 0xa9, 0x49, 0x99, 0x32, 0x45, 0x7b, 0x00,
0x27, 0x79, 0x08, 0x6e, 0x4e, 0xae, 0x54, 0x56, 0x6b, 0xcd, 0x35, 0xe7, 0xe5, 0x37, 0xea, 0xf4,
0x0f, 0xf5, 0x0a, 0xce, 0x68, 0xb7, 0xc4, 0xac, 0x22, 0x99, 0xdd, 0x19, 0xca, 0x4c, 0x41, 0x2d,
0x51, 0x3b, 0x84, 0xe5, 0x5d, 0x2c, 0x1e, 0x04, 0x02, 0xf3, 0x12, 0xbf, 0x3c, 0xb5, 0xe5, 0x14,
0x1a, 0x57, 0x4e, 0xe1, 0xef, 0x06, 0xdc, 0xbc, 0xe4, 0xa0, 0xff, 0x76, 0x02, 0x9f, 0x1a, 0x30,
0xd3, 0x3f, 0x02, 0x99, 0x50, 0x0d, 0xc2, 0x30, 0xc1, 0x9c, 0x4b, 0xfc, 0x33, 0x5e, 0xbe, 0x45,
0x1b, 0x50, 0x65, 0x69, 0xcb, 0x3f, 0xc6, 0x3d, 0x5d, 0x88, 0x0b, 0x8e, 0x6a, 0x3d, 0x27, 0xef,
0x4a, 0xe7, 0xc3, 0xb8, 0xe7, 0x4d, 0xb1, 0xb4, 0x75, 0x1f, 0xf7, 0xb2, 0x6c, 0x9c, 0x50, 0x41,
0xe2, 0xc8, 0x67, 0xf4, 0x2b, 0x9c, 0x48, 0x84, 0x15, 0xaf, 0xa6, 0x64, 0xfb, 0x99, 0x08, 0xad,
0xc3, 0x1c, 0x4b, 0x28, 0xa3, 0x1c, 0x27, 0x3e, 0x4b, 0x08, 0x4d, 0x88, 0xe8, 0x99, 0xd7, 0xa4,
0xdd, 0x6c, 0xae, 0xd8, 0xd7, 0x72, 0xbb, 0x01, 0x8b, 0xbb, 0x58, 0x6c, 0x67, 0xc9, 0x1c, 0xb1,
0x7b, 0xec, 0x6f, 0xc0, 0x3c, 0xef, 0xa2, 0x2f, 0xeb, 0x0d, 0x98, 0x56, 0x97, 0x45, 0x42, 0x5d,
0x14, 0x4b, 0xc5, 0xdc, 0xab, 0x5e, 0x97, 0xae, 0x7b, 0x3b, 0x5e, 0x55, 0x9a, 0xee, 0x85, 0x68,
0x03, 0xae, 0xcb, 0xa5, 0xce, 0xc0, 0xe2, 0x25, 0x2e, 0x9e, 0xb2, 0xb2, 0x17, 0xe1, 0xd5, 0x7e,
0xc9, 0x28, 0x85, 0x42, 0x6c, 0x3f, 0x86, 0x1b, 0x2f, 0x2a, 0xfe, 0x4d, 0x5c, 0xf3, 0x30, 0xb7,
0x8b, 0xc5, 0x41, 0x2f, 0x6e, 0x93, 0x38, 0xca, 0x31, 0x39, 0x80, 0x8a, 0x42, 0x8d, 0xc7, 0x84,
0x2a, 0x57, 0x22, 0x09, 0x67, 0xda, 0xcb, 0xb7, 0xf6, 0x82, 0xb4, 0x7f, 0x48, 0x43, 0xbc, 0x17,
0x1f, 0xd2, 0x3c, 0xca, 0xcf, 0x06, 0xcc, 0x97, 0xc4, 0x3a, 0xce, 0x7d, 0x98, 0x0b, 0xf1, 0x61,
0x90, 0x76, 0x84, 0x1f, 0xd3, 0x10, 0xfb, 0x24, 0x3e, 0xa4, 0x9a, 0xe0, 0xad, 0x22, 0x5a, 0xd6,
0x64, 0xce, 0x8e, 0x32, 0xec, 0xc7, 0x78, 0x25, 0x2c, 0x0b, 0xd0, 0x97, 0x30, 0x1f, 0x30, 0xd6,
0x21, 0x6d, 0x59, 0xc1, 0xfe, 0x09, 0x4e, 0xf8, 0x60, 0x3e, 0xae, 0x0f, 0xed, 0x27, 0x65, 0x2e,
0x43, 0xa3, 0x42, 0x1c, 0x2d, 0xb7, 0xff, 0x36, 0xa0, 0x56, 0xb0, 0x41, 0x08, 0xae, 0xc5, 0x41,
0x17, 0xeb, 0x7e, 0x90, 0x6b, 0xb4, 0x04, 0xd3, 0x01, 0x63, 0xbe, 0x94, 0x4f, 0xea, 0x3e, 0x61,
0xec, 0x61, 0xa6, 0x32, 0xa1, 0x9a, 0x03, 0xaa, 0x28, 0x8d, 0xde, 0xa2, 0x9b, 0x00, 0x11, 0x11,
0x7e, 0x9b, 0x76, 0xbb, 0x44, 0xc8, 0x42, 0x9f, 0xf1, 0x66, 0x22, 0x22, 0x3e, 0x92, 0x82, 0x4c,
0xdd, 0x4a, 0x49, 0x27, 0xf4, 0x45, 0x10, 0x71, 0xf3, 0xba, 0x52, 0x4b, 0xc9, 0x67, 0x41, 0xc4,
0xa5, 0x37, 0xed, 0x73, 0x9d, 0xd2, 0xde, 0x54, 0x23, 0x45, 0x1f, 0xe7, 0xde, 0x21, 0x66, 0xdc,
0xac, 0xca, 0xd1, 0x72, 0x7b, 0x58, 0x2a, 0x3e, 0xa5, 0x61, 0xda, 0xc1, 0xfa, 0x94, 0x1d, 0xcc,
0xb8, 0x7d, 0x0f, 0xa6, 0x94, 0x30, 0xa3, 0xcd, 0x02, 0x71, 0x94, 0xd3, 0xce, 0xd6, 0x45, 0x6e,
0x93, 0x65, 0x6e, 0xb3, 0x50, 0xe1, 0x69, 0x57, 0x33, 0xce, 0x96, 0xcd, 0x27, 0x33, 0x50, 0x3d,
0xc0, 0xc9, 0x09, 0x69, 0x63, 0xf4, 0x83, 0x01, 0xb5, 0x42, 0x55, 0xa0, 0xe6, 0x30, 0x60, 0xe7,
0x2b, 0xcb, 0xda, 0x1c, 0xcb, 0x47, 0x95, 0x9d, 0xdd, 0x78, 0xf2, 0xdb, 0x5f, 0xdf, 0x4f, 0xae,
0xa3, 0x35, 0x77, 0xc8, 0x1b, 0xa5, 0x5f, 0x94, 0xe8, 0xa9, 0x01, 0x30, 0x68, 0x04, 0xd4, 0x18,
0xe1, 0xd8, 0x72, 0x27, 0x59, 0xcd, 0x71, 0x5c, 0x34, 0x50, 0x57, 0x02, 0x5d, 0x43, 0x77, 0x86,
0x01, 0xd5, 0xed, 0x87, 0x7e, 0x34, 0xe0, 0xff, 0xe5, 0x19, 0x82, 0xb6, 0x46, 0x38, 0xf7, 0xfc,
0x30, 0xb2, 0xde, 0x1c, 0xd7, 0x4d, 0x43, 0xde, 0x92, 0x90, 0x5d, 0xb4, 0x31, 0x0c, 0xb2, 0x1c,
0x3a, 0xdc, 0xed, 0xc8, 0x18, 0xe8, 0x27, 0x03, 0x66, 0x5f, 0x1c, 0xcb, 0xe8, 0xee, 0x08, 0x18,
0x2e, 0x9a, 0xfd, 0xd6, 0x5b, 0xe3, 0x3b, 0x6a, 0xf8, 0x77, 0x25, 0xfc, 0x06, 0x72, 0x47, 0x84,
0xff, 0xb5, 0xfa, 0xab, 0x3c, 0x46, 0xbf, 0x1a, 0x85, 0xb1, 0x5e, 0x7c, 0x09, 0xa0, 0x77, 0x47,
0xce, 0xe4, 0x05, 0x2f, 0x15, 0xeb, 0xbd, 0x2b, 0x7a, 0x6b, 0x3e, 0x6f, 0x4b, 0x3e, 0x9b, 0xa8,
0x31, 0x8c, 0xcf, 0xe0, 0x11, 0x91, 0x5f, 0xc9, 0x1f, 0x86, 0xfc, 0xb9, 0x5e, 0xf4, 0x3c, 0x44,
0xef, 0x8f, 0x80, 0xea, 0x25, 0x4f, 0x5b, 0xeb, 0x83, 0x2b, 0xfb, 0x6b, 0x5e, 0xef, 0x48, 0x5e,
0x5b, 0x68, 0x73, 0x0c, 0x5e, 0xf9, 0x5d, 0x6d, 0x3f, 0xf8, 0xe5, 0xb4, 0x6e, 0x3c, 0x3b, 0xad,
0x1b, 0x7f, 0x9e, 0xd6, 0x8d, 0xef, 0xce, 0xea, 0x13, 0xcf, 0xce, 0xea, 0x13, 0xcf, 0xcf, 0xea,
0x13, 0x5f, 0x34, 0x23, 0x22, 0x8e, 0xd2, 0x96, 0xd3, 0xa6, 0xdd, 0x3c, 0xb0, 0xfa, 0x6c, 0xf0,
0xf0, 0xd8, 0x6d, 0x77, 0x08, 0x8e, 0x85, 0x1b, 0x25, 0xac, 0xed, 0x8a, 0x2e, 0x57, 0x63, 0xac,
0x35, 0x25, 0x5f, 0x3a, 0x9b, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf6, 0xf3, 0x0e, 0x76, 0xf1,
0x0c, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -1417,10 +1421,15 @@ func (m *Validator) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x18
}
if len(m.PubKey) > 0 {
i -= len(m.PubKey)
copy(dAtA[i:], m.PubKey)
i = encodeVarintQuery(dAtA, i, uint64(len(m.PubKey)))
if m.PubKey != nil {
{
size, err := m.PubKey.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintQuery(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
@ -1922,8 +1931,8 @@ func (m *Validator) Size() (n int) {
if l > 0 {
n += 1 + l + sovQuery(uint64(l))
}
l = len(m.PubKey)
if l > 0 {
if m.PubKey != nil {
l = m.PubKey.Size()
n += 1 + l + sovQuery(uint64(l))
}
if m.VotingPower != 0 {
@ -2181,7 +2190,7 @@ func (m *GetValidatorSetByHeightRequest) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Pagination == nil {
m.Pagination = &PageRequest{}
m.Pagination = &query.PageRequest{}
}
if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -2323,7 +2332,7 @@ func (m *GetValidatorSetByHeightResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Pagination == nil {
m.Pagination = &PageResponse{}
m.Pagination = &query.PageResponse{}
}
if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -2412,7 +2421,7 @@ func (m *GetLatestValidatorSetRequest) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Pagination == nil {
m.Pagination = &PageRequest{}
m.Pagination = &query.PageRequest{}
}
if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -2554,7 +2563,7 @@ func (m *GetLatestValidatorSetResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Pagination == nil {
m.Pagination = &PageResponse{}
m.Pagination = &query.PageResponse{}
}
if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -2617,40 +2626,6 @@ func (m *Validator) Unmarshal(dAtA []byte) error {
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthQuery
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthQuery
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...)
if m.Address == nil {
m.Address = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
@ -2677,7 +2652,43 @@ func (m *Validator) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.PubKey = string(dAtA[iNdEx:postIndex])
m.Address = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthQuery
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthQuery
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.PubKey == nil {
m.PubKey = &types.Any{}
}
if err := m.PubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 3:
if wireType != 0 {
@ -2872,7 +2883,7 @@ func (m *GetBlockByHeightResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.BlockId == nil {
m.BlockId = &types.BlockID{}
m.BlockId = &types1.BlockID{}
}
if err := m.BlockId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -2908,7 +2919,7 @@ func (m *GetBlockByHeightResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Block == nil {
m.Block = &types.Block{}
m.Block = &types1.Block{}
}
if err := m.Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -3050,7 +3061,7 @@ func (m *GetLatestBlockResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.BlockId == nil {
m.BlockId = &types.BlockID{}
m.BlockId = &types1.BlockID{}
}
if err := m.BlockId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
@ -3086,7 +3097,7 @@ func (m *GetLatestBlockResponse) Unmarshal(dAtA []byte) error {
return io.ErrUnexpectedEOF
}
if m.Block == nil {
m.Block = &types.Block{}
m.Block = &types1.Block{}
}
if err := m.Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err

View File

@ -2,11 +2,11 @@
// source: cosmos/base/tendermint/v1beta1/query.proto
/*
Package query is a reverse proxy.
Package tmservice is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package query
package tmservice
import (
"context"

View File

@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/rpc"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
qtypes "github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/version"
)
@ -21,10 +22,11 @@ type queryServer struct {
interfaceRegistry codectypes.InterfaceRegistry
}
var _ qtypes.ServiceServer = queryServer{}
var _ ServiceServer = queryServer{}
var _ codectypes.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{}
// NewQueryServer creates a new tendermint query server.
func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) qtypes.ServiceServer {
func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) ServiceServer {
return queryServer{
clientCtx: clientCtx,
interfaceRegistry: interfaceRegistry,
@ -32,18 +34,18 @@ func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.Inter
}
// GetSyncing implements ServiceServer.GetSyncing
func (s queryServer) GetSyncing(_ context.Context, _ *qtypes.GetSyncingRequest) (*qtypes.GetSyncingResponse, error) {
func (s queryServer) GetSyncing(_ context.Context, _ *GetSyncingRequest) (*GetSyncingResponse, error) {
status, err := getNodeStatus(s.clientCtx)
if err != nil {
return nil, err
}
return &qtypes.GetSyncingResponse{
return &GetSyncingResponse{
Syncing: status.SyncInfo.CatchingUp,
}, nil
}
// GetLatestBlock implements ServiceServer.GetLatestBlock
func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockRequest) (*qtypes.GetLatestBlockResponse, error) {
func (s queryServer) GetLatestBlock(context.Context, *GetLatestBlockRequest) (*GetLatestBlockResponse, error) {
status, err := getBlock(s.clientCtx, nil)
if err != nil {
return nil, err
@ -55,14 +57,14 @@ func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockReque
return nil, err
}
return &qtypes.GetLatestBlockResponse{
return &GetLatestBlockResponse{
BlockId: &protoBlockID,
Block: protoBlock,
}, nil
}
// GetBlockByHeight implements ServiceServer.GetBlockByHeight
func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByHeightRequest) (*qtypes.GetBlockByHeightResponse, error) {
func (s queryServer) GetBlockByHeight(_ context.Context, req *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error) {
chainHeight, err := rpc.GetChainHeight(s.clientCtx)
if err != nil {
return nil, err
@ -81,14 +83,14 @@ func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByH
if err != nil {
return nil, err
}
return &qtypes.GetBlockByHeightResponse{
return &GetBlockByHeightResponse{
BlockId: &protoBlockID,
Block: protoBlock,
}, nil
}
// GetLatestValidatorSet implements ServiceServer.GetLatestValidatorSet
func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetLatestValidatorSetRequest) (*qtypes.GetLatestValidatorSetResponse, error) {
func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestValidatorSetRequest) (*GetLatestValidatorSetResponse, error) {
page, limit, err := qtypes.ParsePagination(req.Pagination)
if err != nil {
return nil, err
@ -99,24 +101,39 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetL
return nil, err
}
outputValidatorsRes := &qtypes.GetLatestValidatorSetResponse{
outputValidatorsRes := &GetLatestValidatorSetResponse{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)),
Validators: make([]*Validator, len(validatorsRes.Validators)),
}
for i, validator := range validatorsRes.Validators {
outputValidatorsRes.Validators[i] = &qtypes.Validator{
Address: validator.Address,
anyPub, err := codectypes.NewAnyWithValue(validator.PubKey)
if err != nil {
return nil, err
}
outputValidatorsRes.Validators[i] = &Validator{
Address: validator.Address.String(),
ProposerPriority: validator.ProposerPriority,
PubKey: validator.PubKey,
PubKey: anyPub,
VotingPower: validator.VotingPower,
}
}
return outputValidatorsRes, nil
}
func (m *GetLatestValidatorSetResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
var pubKey cryptotypes.PubKey
for _, val := range m.Validators {
err := unpacker.UnpackAny(val.PubKey, &pubKey)
if err != nil {
return err
}
}
return nil
}
// GetValidatorSetByHeight implements ServiceServer.GetValidatorSetByHeight
func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.GetValidatorSetByHeightRequest) (*qtypes.GetValidatorSetByHeightResponse, error) {
func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error) {
page, limit, err := qtypes.ParsePagination(req.Pagination)
if err != nil {
return nil, err
@ -136,16 +153,20 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.Ge
return nil, err
}
outputValidatorsRes := &qtypes.GetValidatorSetByHeightResponse{
outputValidatorsRes := &GetValidatorSetByHeightResponse{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)),
Validators: make([]*Validator, len(validatorsRes.Validators)),
}
for i, validator := range validatorsRes.Validators {
outputValidatorsRes.Validators[i] = &qtypes.Validator{
Address: validator.Address,
anyPub, err := codectypes.NewAnyWithValue(validator.PubKey)
if err != nil {
return nil, err
}
outputValidatorsRes.Validators[i] = &Validator{
Address: validator.Address.String(),
ProposerPriority: validator.ProposerPriority,
PubKey: validator.PubKey,
PubKey: anyPub,
VotingPower: validator.VotingPower,
}
}
@ -153,7 +174,7 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.Ge
}
// GetNodeInfo implements ServiceServer.GetNodeInfo
func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoRequest) (*qtypes.GetNodeInfoResponse, error) {
func (s queryServer) GetNodeInfo(ctx context.Context, req *GetNodeInfoRequest) (*GetNodeInfoResponse, error) {
status, err := getNodeStatus(s.clientCtx)
if err != nil {
return nil, err
@ -162,19 +183,19 @@ func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoReq
protoNodeInfo := status.NodeInfo.ToProto()
nodeInfo := version.NewInfo()
deps := make([]*qtypes.Module, len(nodeInfo.BuildDeps))
deps := make([]*Module, len(nodeInfo.BuildDeps))
for i, dep := range nodeInfo.BuildDeps {
deps[i] = &qtypes.Module{
deps[i] = &Module{
Path: dep.Path,
Sum: dep.Sum,
Version: dep.Version,
}
}
resp := qtypes.GetNodeInfoResponse{
resp := GetNodeInfoResponse{
DefaultNodeInfo: protoNodeInfo,
ApplicationVersion: &qtypes.VersionInfo{
ApplicationVersion: &VersionInfo{
AppName: nodeInfo.AppName,
Name: nodeInfo.Name,
GitCommit: nodeInfo.GitCommit,
@ -193,7 +214,7 @@ func RegisterTendermintService(
clientCtx client.Context,
interfaceRegistry codectypes.InterfaceRegistry,
) {
qtypes.RegisterServiceServer(
RegisterServiceServer(
qrt,
NewQueryServer(clientCtx, interfaceRegistry),
)
@ -202,5 +223,5 @@ func RegisterTendermintService(
// RegisterGRPCGatewayRoutes mounts the tendermint service's GRPC-gateway routes on the
// given Mux.
func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) {
qtypes.RegisterServiceHandlerClient(context.Background(), mux, qtypes.NewServiceClient(clientConn))
RegisterServiceHandlerClient(context.Background(), mux, NewServiceClient(clientConn))
}

View File

@ -7,6 +7,9 @@ import (
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/network"
qtypes "github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/types/rest"
@ -19,7 +22,7 @@ type IntegrationTestSuite struct {
cfg network.Config
network *network.Network
queryClient qtypes.ServiceClient
queryClient tmservice.ServiceClient
}
func (s *IntegrationTestSuite) SetupSuite() {
@ -36,7 +39,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
s.queryClient = qtypes.NewServiceClient(s.network.Validators[0].ClientCtx)
s.queryClient = tmservice.NewServiceClient(s.network.Validators[0].ClientCtx)
}
func (s *IntegrationTestSuite) TearDownSuite() {
@ -47,13 +50,13 @@ func (s *IntegrationTestSuite) TearDownSuite() {
func (s IntegrationTestSuite) TestQueryNodeInfo() {
val := s.network.Validators[0]
res, err := s.queryClient.GetNodeInfo(context.Background(), &qtypes.GetNodeInfoRequest{})
res, err := s.queryClient.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
s.Require().NoError(err)
s.Require().Equal(res.ApplicationVersion.AppName, version.NewInfo().AppName)
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/node_info", val.APIAddress))
s.Require().NoError(err)
var getInfoRes qtypes.GetNodeInfoResponse
var getInfoRes tmservice.GetNodeInfoResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getInfoRes))
s.Require().Equal(getInfoRes.ApplicationVersion.AppName, version.NewInfo().AppName)
}
@ -61,35 +64,35 @@ func (s IntegrationTestSuite) TestQueryNodeInfo() {
func (s IntegrationTestSuite) TestQuerySyncing() {
val := s.network.Validators[0]
_, err := s.queryClient.GetSyncing(context.Background(), &qtypes.GetSyncingRequest{})
_, err := s.queryClient.GetSyncing(context.Background(), &tmservice.GetSyncingRequest{})
s.Require().NoError(err)
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/syncing", val.APIAddress))
s.Require().NoError(err)
var syncingRes qtypes.GetSyncingResponse
var syncingRes tmservice.GetSyncingResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &syncingRes))
}
func (s IntegrationTestSuite) TestQueryLatestBlock() {
val := s.network.Validators[0]
_, err := s.queryClient.GetLatestBlock(context.Background(), &qtypes.GetLatestBlockRequest{})
_, err := s.queryClient.GetLatestBlock(context.Background(), &tmservice.GetLatestBlockRequest{})
s.Require().NoError(err)
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/latest", val.APIAddress))
s.Require().NoError(err)
var blockInfoRes qtypes.GetLatestBlockResponse
var blockInfoRes tmservice.GetLatestBlockResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes))
}
func (s IntegrationTestSuite) TestQueryBlockByHeight() {
val := s.network.Validators[0]
_, err := s.queryClient.GetBlockByHeight(context.Background(), &qtypes.GetBlockByHeightRequest{Height: 1})
_, err := s.queryClient.GetBlockByHeight(context.Background(), &tmservice.GetBlockByHeightRequest{Height: 1})
s.Require().NoError(err)
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/%d", val.APIAddress, 1))
s.Require().NoError(err)
var blockInfoRes qtypes.GetBlockByHeightResponse
var blockInfoRes tmservice.GetBlockByHeightResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes))
}
@ -97,13 +100,17 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() {
val := s.network.Validators[0]
// nil pagination
_, err := s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{
res, err := s.queryClient.GetLatestValidatorSet(context.Background(), &tmservice.GetLatestValidatorSetRequest{
Pagination: nil,
})
s.Require().NoError(err)
s.Require().Equal(1, len(res.Validators))
content, ok := res.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
s.Require().Equal(true, ok)
s.Require().Equal(content, val.PubKey)
//with pagination
_, err = s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{
_, err = s.queryClient.GetLatestValidatorSet(context.Background(), &tmservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{
Offset: 0,
Limit: 10,
}})
@ -116,21 +123,25 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() {
// rest request with pagination
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/latest?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 0, 1))
s.Require().NoError(err)
var validatorSetRes qtypes.GetLatestValidatorSetResponse
var validatorSetRes tmservice.GetLatestValidatorSetResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes))
s.Require().Equal(1, len(validatorSetRes.Validators))
anyPub, err := codectypes.NewAnyWithValue(val.PubKey)
s.Require().NoError(err)
s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub)
}
func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() {
val := s.network.Validators[0]
// nil pagination
_, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{
_, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{
Height: 1,
Pagination: nil,
})
s.Require().NoError(err)
_, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{
_, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{
Height: 1,
Pagination: &qtypes.PageRequest{
Offset: 0,
@ -144,7 +155,7 @@ func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() {
// rest query with pagination
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/%d?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 1, 0, 1))
var validatorSetRes qtypes.GetValidatorSetByHeightResponse
var validatorSetRes tmservice.GetValidatorSetByHeightResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes))
}

View File

@ -3,6 +3,7 @@ package client
import (
gocontext "context"
"fmt"
"reflect"
"strconv"
gogogrpc "github.com/gogo/protobuf/grpc"
@ -12,10 +13,10 @@ import (
"google.golang.org/grpc/encoding/proto"
"google.golang.org/grpc/metadata"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/codec/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/types/tx"
)
var _ gogogrpc.ClientConn = Context{}
@ -23,7 +24,37 @@ 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) error {
func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, 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() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "request cannot be nil")
}
// Case 1. Broadcasting a Tx.
if isBroadcast(method) {
req, ok := args.(*tx.BroadcastTxRequest)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxRequest)(nil), args)
}
res, ok := reply.(*tx.BroadcastTxResponse)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected %T, got %T", (*tx.BroadcastTxResponse)(nil), args)
}
broadcastRes, err := TxServiceBroadcast(grpcCtx, ctx, req)
if err != nil {
return err
}
*res = *broadcastRes
return err
}
// Case 2. Querying state.
reqBz, err := protoCodec.Marshal(args)
if err != nil {
return err
@ -86,3 +117,7 @@ func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, args, reply
func (Context) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) {
return nil, fmt.Errorf("streaming rpc not supported")
}
func isBroadcast(method string) bool {
return method == "/cosmos.tx.v1beta1.Service/BroadcastTx"
}

View File

@ -2,23 +2,45 @@ package keys
import (
"bufio"
"fmt"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)
const (
flagUnarmoredHex = "unarmored-hex"
flagUnsafe = "unsafe"
)
// ExportKeyCommand exports private keys from the key store.
func ExportKeyCommand() *cobra.Command {
return &cobra.Command{
cmd := &cobra.Command{
Use: "export <name>",
Short: "Export private keys",
Long: `Export a private key from the local keybase in ASCII-armored encrypted format.`,
Args: cobra.ExactArgs(1),
Long: `Export a private key from the local keyring in ASCII-armored encrypted format.
When both the --unarmored-hex and --unsafe flags are selected, cryptographic
private key material is exported in an INSECURE fashion that is designed to
allow users to import their keys in hot wallets. This feature is for advanced
users only that are confident about how to handle private keys work and are
FULLY AWARE OF THE RISKS. If you are unsure, you may want to do some research
and export your keys in ASCII-armored encrypted format.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
buf := bufio.NewReader(cmd.InOrStdin())
clientCtx := client.GetClientContextFromCmd(cmd)
unarmored, _ := cmd.Flags().GetBool(flagUnarmoredHex)
unsafe, _ := cmd.Flags().GetBool(flagUnsafe)
if unarmored && unsafe {
return exportUnsafeUnarmored(cmd, args[0], buf, clientCtx.Keyring)
} else if unarmored || unsafe {
return fmt.Errorf("the flags %s and %s must be used together", flagUnsafe, flagUnarmoredHex)
}
encryptPassword, err := input.GetPassword("Enter passphrase to encrypt the exported key:", buf)
if err != nil {
@ -31,7 +53,31 @@ func ExportKeyCommand() *cobra.Command {
}
cmd.Println(armored)
return nil
},
}
cmd.Flags().Bool(flagUnarmoredHex, false, "Export unarmored hex privkey. Requires --unsafe.")
cmd.Flags().Bool(flagUnsafe, false, "Enable unsafe operations. This flag must be switched on along with all unsafe operation-specific options.")
return cmd
}
func exportUnsafeUnarmored(cmd *cobra.Command, uid string, buf *bufio.Reader, kr keyring.Keyring) error {
// confirm deletion, unless -y is passed
if yes, err := input.GetConfirmation("WARNING: The private key will be exported as an unarmored hexadecimal string. USE AT YOUR OWN RISK. Continue?", buf, cmd.ErrOrStderr()); err != nil {
return err
} else if !yes {
return nil
}
hexPrivKey, err := keyring.NewUnsafe(kr).UnsafeExportPrivKeyHex(uid)
if err != nil {
return err
}
cmd.Println(hexPrivKey)
return nil
}

View File

@ -36,15 +36,34 @@ func Test_runExportCmd(t *testing.T) {
require.NoError(t, err)
// Now enter password
mockIn.Reset("123456789\n123456789\n")
cmd.SetArgs([]string{
args := []string{
"keyname1",
fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome),
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
})
}
mockIn.Reset("123456789\n123456789\n")
cmd.SetArgs(args)
clientCtx := client.Context{}.WithKeyring(kb)
ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx)
require.NoError(t, cmd.ExecuteContext(ctx))
argsUnsafeOnly := append(args, "--unsafe")
cmd.SetArgs(argsUnsafeOnly)
require.Error(t, cmd.ExecuteContext(ctx))
argsUnarmoredHexOnly := append(args, "--unarmored-hex")
cmd.SetArgs(argsUnarmoredHexOnly)
require.Error(t, cmd.ExecuteContext(ctx))
argsUnsafeUnarmoredHex := append(args, "--unsafe", "--unarmored-hex")
cmd.SetArgs(argsUnsafeUnarmoredHex)
require.Error(t, cmd.ExecuteContext(ctx))
mockIn, mockOut := testutil.ApplyMockIO(cmd)
mockIn.Reset("y\n")
require.NoError(t, cmd.ExecuteContext(ctx))
require.Equal(t, "2485e33678db4175dc0ecef2d6e1fc493d4a0d7f7ce83324b6ed70afe77f3485\n", mockOut.String())
}

View File

@ -15,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
)
@ -66,10 +67,10 @@ func ValidatorCommand() *cobra.Command {
// Validator output in bech32 format
type ValidatorOutput struct {
Address sdk.ConsAddress `json:"address"`
PubKey string `json:"pub_key"`
ProposerPriority int64 `json:"proposer_priority"`
VotingPower int64 `json:"voting_power"`
Address sdk.ConsAddress `json:"address"`
PubKey cryptotypes.PubKey `json:"pub_key"`
ProposerPriority int64 `json:"proposer_priority"`
VotingPower int64 `json:"voting_power"`
}
// Validators at a certain height output in bech32 format
@ -99,19 +100,15 @@ func (rvo ResultValidatorsOutput) String() string {
return b.String()
}
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
func validatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
pk, err := cryptocodec.FromTmPubKeyInterface(validator.PubKey)
if err != nil {
return ValidatorOutput{}, err
}
bechValPubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pk)
if err != nil {
return ValidatorOutput{}, err
}
return ValidatorOutput{
Address: sdk.ConsAddress(validator.Address),
PubKey: bechValPubkey,
PubKey: pk,
ProposerPriority: validator.ProposerPriority,
VotingPower: validator.VotingPower,
}, nil
@ -136,7 +133,7 @@ func GetValidators(clientCtx client.Context, height *int64, page, limit *int) (R
}
for i := 0; i < len(validatorsRes.Validators); i++ {
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
outputValidatorsRes.Validators[i], err = validatorOutput(validatorsRes.Validators[i])
if err != nil {
return ResultValidatorsOutput{}, err
}

View File

@ -3,6 +3,7 @@ package legacy
import (
"github.com/cosmos/cosmos-sdk/codec"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
// Cdc defines a global generic sealed Amino codec to be used throughout sdk. It
@ -15,5 +16,16 @@ func init() {
Cdc = codec.NewLegacyAmino()
cryptocodec.RegisterCrypto(Cdc)
codec.RegisterEvidences(Cdc)
Cdc.Seal()
}
// PrivKeyFromBytes unmarshals private key bytes and returns a PrivKey
func PrivKeyFromBytes(privKeyBytes []byte) (privKey cryptotypes.PrivKey, err error) {
err = Cdc.UnmarshalBinaryBare(privKeyBytes, &privKey)
return
}
// PubKeyFromBytes unmarshals public key bytes and returns a PubKey
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey cryptotypes.PubKey, err error) {
err = Cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
return
}

View File

@ -1,8 +1,9 @@
package types
import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
type Any struct {

View File

@ -12,7 +12,7 @@ VOLUME [ /simd ]
WORKDIR /simd
EXPOSE 26656 26657
ENTRYPOINT ["/usr/bin/wrapper.sh"]
CMD ["start"]
CMD ["start", "--log_format", "plain"]
STOPSIGNAL SIGTERM
COPY wrapper.sh /usr/bin/wrapper.sh

View File

@ -10,7 +10,6 @@ import (
"github.com/tendermint/tendermint/crypto/xsalsa20symmetric"
"github.com/cosmos/cosmos-sdk/codec/legacy"
cryptoAmino "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
@ -153,7 +152,7 @@ func encryptPrivKey(privKey cryptotypes.PrivKey, passphrase string) (saltBytes [
}
key = crypto.Sha256(key) // get 32 bytes
privKeyBytes := legacy.Cdc.Amino.MustMarshalBinaryBare(privKey)
privKeyBytes := legacy.Cdc.MustMarshalBinaryBare(privKey)
return saltBytes, xsalsa20symmetric.EncryptSymmetric(privKeyBytes, key)
}
@ -206,5 +205,5 @@ func decryptPrivKey(saltBytes []byte, encBytes []byte, passphrase string) (privK
return privKey, err
}
return cryptoAmino.PrivKeyFromBytes(privKeyBytes)
return legacy.PrivKeyFromBytes(privKeyBytes)
}

View File

@ -15,7 +15,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto"
cryptoAmino "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
@ -79,7 +78,7 @@ func TestArmorUnarmorPubKey(t *testing.T) {
armored := crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "")
pubBytes, algo, err := crypto.UnarmorPubKeyBytes(armored)
require.NoError(t, err)
pub, err := cryptoAmino.PubKeyFromBytes(pubBytes)
pub, err := legacy.PubKeyFromBytes(pubBytes)
require.NoError(t, err)
require.Equal(t, string(hd.Secp256k1Type), algo)
require.True(t, pub.Equals(info.GetPubKey()))
@ -87,7 +86,7 @@ func TestArmorUnarmorPubKey(t *testing.T) {
armored = crypto.ArmorPubKeyBytes(legacy.Cdc.Amino.MustMarshalBinaryBare(info.GetPubKey()), "unknown")
pubBytes, algo, err = crypto.UnarmorPubKeyBytes(armored)
require.NoError(t, err)
pub, err = cryptoAmino.PubKeyFromBytes(pubBytes)
pub, err = legacy.PubKeyFromBytes(pubBytes)
require.NoError(t, err)
require.Equal(t, "unknown", algo)
require.True(t, pub.Equals(info.GetPubKey()))

View File

@ -10,13 +10,6 @@ import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
var amino *codec.LegacyAmino
func init() {
amino = codec.NewLegacyAmino()
RegisterCrypto(amino)
}
// RegisterCrypto registers all crypto dependency types with the provided Amino
// codec.
func RegisterCrypto(cdc *codec.LegacyAmino) {
@ -38,15 +31,3 @@ func RegisterCrypto(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&secp256k1.PrivKey{},
secp256k1.PrivKeyName, nil)
}
// PrivKeyFromBytes unmarshals private key bytes and returns a PrivKey
func PrivKeyFromBytes(privKeyBytes []byte) (privKey cryptotypes.PrivKey, err error) {
err = amino.UnmarshalBinaryBare(privKeyBytes, &privKey)
return
}
// PubKeyFromBytes unmarshals public key bytes and returns a PubKey
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey cryptotypes.PubKey, err error) {
err = amino.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
return
}

View File

@ -2,18 +2,12 @@ package keyring
import (
"github.com/cosmos/cosmos-sdk/codec"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto/hd"
)
// CryptoCdc defines the codec required for keys and info
var CryptoCdc *codec.LegacyAmino
func init() {
CryptoCdc = codec.NewLegacyAmino()
cryptocodec.RegisterCrypto(CryptoCdc)
RegisterLegacyAminoCodec(CryptoCdc)
CryptoCdc.Seal()
RegisterLegacyAminoCodec(legacy.Cdc)
}
// RegisterLegacyAminoCodec registers concrete types and interfaces on the given codec.

View File

@ -3,6 +3,7 @@ package keyring
import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec/legacy"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
@ -246,12 +247,12 @@ func (i multiInfo) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
// encoding info
func marshalInfo(i Info) []byte {
return CryptoCdc.MustMarshalBinaryLengthPrefixed(i)
return legacy.Cdc.MustMarshalBinaryLengthPrefixed(i)
}
// decoding info
func unmarshalInfo(bz []byte) (info Info, err error) {
err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &info)
err = legacy.Cdc.UnmarshalBinaryLengthPrefixed(bz, &info)
if err != nil {
return nil, err
}
@ -266,7 +267,7 @@ func unmarshalInfo(bz []byte) (info Info, err error) {
_, ok := info.(multiInfo)
if ok {
var multi multiInfo
err = CryptoCdc.UnmarshalBinaryLengthPrefixed(bz, &multi)
err = legacy.Cdc.UnmarshalBinaryLengthPrefixed(bz, &multi)
return multi, err
}

View File

@ -18,8 +18,8 @@ import (
tmcrypto "github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto"
cryptoamino "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/ledger"
"github.com/cosmos/cosmos-sdk/crypto/types"
@ -88,6 +88,13 @@ type Keyring interface {
Exporter
}
// UnsafeKeyring exposes unsafe operations such as unsafe unarmored export in
// addition to those that are made available by the Keyring interface.
type UnsafeKeyring interface {
Keyring
UnsafeExporter
}
// Signer is implemented by key stores that want to provide signing capabilities.
type Signer interface {
// Sign sign byte messages with a user key.
@ -110,12 +117,20 @@ type Exporter interface {
// Export public key
ExportPubKeyArmor(uid string) (string, error)
ExportPubKeyArmorByAddress(address sdk.Address) (string, error)
// ExportPrivKey returns a private key in ASCII armored format.
// It returns an error if the key does not exist or a wrong encryption passphrase is supplied.
ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error)
ExportPrivKeyArmorByAddress(address sdk.Address, encryptPassphrase string) (armor string, err error)
}
// UnsafeExporter is implemented by key stores that support unsafe export
// of private keys' material.
type UnsafeExporter interface {
// UnsafeExportPrivKeyHex returns a private key in unarmored hex format
UnsafeExportPrivKeyHex(uid string) (string, error)
}
// Option overrides keyring configuration options.
type Option func(options *Options)
@ -198,7 +213,7 @@ func (ks keystore) ExportPubKeyArmor(uid string) (string, error) {
return "", fmt.Errorf("no key to export with name: %s", uid)
}
return crypto.ArmorPubKeyBytes(CryptoCdc.MustMarshalBinaryBare(bz.GetPubKey()), string(bz.GetAlgo())), nil
return crypto.ArmorPubKeyBytes(legacy.Cdc.MustMarshalBinaryBare(bz.GetPubKey()), string(bz.GetAlgo())), nil
}
func (ks keystore) ExportPubKeyArmorByAddress(address sdk.Address) (string, error) {
@ -240,7 +255,7 @@ func (ks keystore) ExportPrivateKeyObject(uid string) (types.PrivKey, error) {
return nil, err
}
priv, err = cryptoamino.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor))
priv, err = legacy.PrivKeyFromBytes([]byte(linfo.PrivKeyArmor))
if err != nil {
return nil, err
}
@ -289,7 +304,7 @@ func (ks keystore) ImportPubKey(uid string, armor string) error {
return err
}
pubKey, err := cryptoamino.PubKeyFromBytes(pubBytes)
pubKey, err := legacy.PubKeyFromBytes(pubBytes)
if err != nil {
return err
}
@ -316,7 +331,7 @@ func (ks keystore) Sign(uid string, msg []byte) ([]byte, types.PubKey, error) {
return nil, nil, fmt.Errorf("private key not available")
}
priv, err = cryptoamino.PrivKeyFromBytes([]byte(i.PrivKeyArmor))
priv, err = legacy.PrivKeyFromBytes([]byte(i.PrivKeyArmor))
if err != nil {
return nil, nil, err
}
@ -696,7 +711,7 @@ func (ks keystore) writeLocalKey(name string, priv types.PrivKey, algo hd.PubKey
// encrypt private key using keyring
pub := priv.PubKey()
info := newLocalInfo(name, pub, string(CryptoCdc.MustMarshalBinaryBare(priv)), algo)
info := newLocalInfo(name, pub, string(legacy.Cdc.MustMarshalBinaryBare(priv)), algo)
if err := ks.writeInfo(info); err != nil {
return nil, err
}
@ -774,6 +789,29 @@ func (ks keystore) writeMultisigKey(name string, pub types.PubKey) (Info, error)
return info, nil
}
type unsafeKeystore struct {
keystore
}
// NewUnsafe returns a new keyring that provides support for unsafe operations.
func NewUnsafe(kr Keyring) UnsafeKeyring {
// The type assertion is against the only keystore
// implementation that is currently provided.
ks := kr.(keystore)
return unsafeKeystore{ks}
}
// UnsafeExportPrivKeyHex exports private keys in unarmored hexadecimal format.
func (ks unsafeKeystore) UnsafeExportPrivKeyHex(uid string) (privkey string, err error) {
priv, err := ks.ExportPrivateKeyObject(uid)
if err != nil {
return "", err
}
return hex.EncodeToString(priv.Bytes()), nil
}
func addrHexKeyAsString(address sdk.Address) string {
return fmt.Sprintf("%s.%s", hex.EncodeToString(address.Bytes()), addressSuffix)
}

View File

@ -1,6 +1,7 @@
package keyring
import (
"encoding/hex"
"fmt"
"strings"
"testing"
@ -1092,6 +1093,29 @@ func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) {
require.EqualError(t, err, fmt.Sprintf("cannot overwrite key: %s", newUID))
}
func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) {
keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil)
require.NoError(t, err)
uid := theID
_, _, err = keyring.NewMnemonic(uid, English, sdk.FullFundraiserPath, hd.Secp256k1)
require.NoError(t, err)
unsafeKeyring := NewUnsafe(keyring)
privKey, err := unsafeKeyring.UnsafeExportPrivKeyHex(uid)
require.NoError(t, err)
require.Equal(t, 64, len(privKey))
_, err = hex.DecodeString(privKey)
require.NoError(t, err)
// test error on non existing key
_, err = unsafeKeyring.UnsafeExportPrivKeyHex("non-existing")
require.Error(t, err)
}
func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) {
keyring, err := New(t.Name(), BackendTest, t.TempDir(), nil)
require.NoError(t, err)

View File

@ -4,10 +4,11 @@ import (
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func Test_writeReadLedgerInfo(t *testing.T) {

View File

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require"
cryptoAmino "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil"
@ -238,7 +238,7 @@ func TestRealDeviceSecp256k1(t *testing.T) {
// now, let's serialize the public key and make sure it still works
bs := cdc.Amino.MustMarshalBinaryBare(priv.PubKey())
pub2, err := cryptoAmino.PubKeyFromBytes(bs)
pub2, err := legacy.PubKeyFromBytes(bs)
require.Nil(t, err, "%+v", err)
// make sure we get the same pubkey when we load from disk
@ -251,8 +251,8 @@ func TestRealDeviceSecp256k1(t *testing.T) {
require.True(t, valid)
// make sure pubkeys serialize properly as well
bs = cdc.Amino.MustMarshalBinaryBare(pub)
bpub, err := cryptoAmino.PubKeyFromBytes(bs)
bs = legacy.Cdc.MustMarshalBinaryBare(pub)
bpub, err := legacy.PubKeyFromBytes(bs)
require.NoError(t, err)
require.Equal(t, pub, bpub)
}

View File

@ -5,7 +5,7 @@ If you want to open a PR on the Cosmos SDK to update the documentation, please f
## Translating
- Docs translations live in a `docs/country-code/` folder, where `country-code` stands for the country code of the language used (`cn` for Chinese, `kr` for Korea, `fr` for France, ...).
- Always translate content living on `master`.
- Always translate content living on `master`.
- Only content under `/docs/intro/`, `/docs/basics/`, `/docs/core/`, `/docs/building-modules/` and `docs/interfaces` needs to be translated, as well as `docs/README.md`. It is also nice (but not mandatory) to translate `/docs/spec/`.
- Specify the release/tag of the translation in the README of your translation folder. Update the release/tag each time you update the translation.
@ -103,7 +103,7 @@ We are using [Algolia](https://www.algolia.com) to power full-text search. This
## Consistency
Because the build processes are identical (as is the information contained herein), this file should be kept in sync as
much as possible with its [counterpart in the Tendermint Core repo](https://github.com/tendermint/tendermint/blob/master/docs/DOCS_README.md).
much as possible with its [counterpart in the Tendermint Core repo](https://github.com/tendermint/tendermint/blob/v0.34.0/docs/DOCS_README.md).
### Update and Build the RPC docs

View File

@ -0,0 +1,81 @@
# ADR 034: Account Rekeying
## Changelog
- 30-09-2020: Initial Draft
## Status
PROPOSED
## Abstract
Account rekeying is a process hat allows an account to replace its authentication pubkey with a new one.
## Context
Currently, in the Cosmos SDK, the address of an auth `BaseAccount` is based on the hash of the public key. Once an account is created, the public key for the account is set in stone, and cannot be changed. This can be a problem for users, as key rotation is a useful security practice, but is not possible currently. Furthermore, as multisigs are a type of pubkey, once a multisig for an account is set, it can not be updated. This is problematic, as multisigs are often used by organizations or companies, who may need to change their set of multisig signers for internal reasons.
Transferring all the assets of an account to a new account with the updated pubkey is not sufficient, because some "engagements" of an account are not easily transferable. For example, in staking, to transfer bonded Atoms, an account would have to unbond all delegations and wait the three week unbonding period. Even more significantly, for validator operators, ownership over a validator is not transferrable at all, meaning that the operator key for a validator can never be updated, leading to poor operational security for validators.
## Decision
We propose the addition of a new feature to `x/auth` that allows accounts to update the public key associated with their account, while keeping the address the same.
This is possible because the Cosmos SDK `BaseAccount` stores the public key for an account in state, instead of making the assumption that the public key is included in the transaction (whether explicitly or implicitly through the signature) as in other blockchains such as Bitcoin and Ethereum. Because the public key is stored on chain, it is okay for the public key to not hash to the address of an account, as the address is not pertinent to the signature checking process.
To build this system, we design a new Msg type as follows:
```protobuf
service Msg {
rpc ChangePubKey(MsgChangePubKey) returns (MsgChangePubKeyResponse);
}
message MsgChangePubKey {
string address = 1;
google.protobuf.Any pub_key = 2;
}
message MsgChangePubKeyResponse {}
```
The MsgChangePubKey transaction needs to be signed by the existing pubkey in state.
Once, approved, the handler for this message type, which takes in the AccountKeeper, will update the in-state pubkey for the account and replace it with the pubkey from the Msg.
An account that has had its pubkey changed cannot be automatically pruned from state. This is because if pruned, the original pubkey of the account would be needed to recreate the same address, but the owner of the address may not have the original pubkey anymore. Currently, we do not automatically prune any accounts anyways, but we would like to keep this option open the road (this is the purpose of account numbers). To resolve this, we charge an additional gas fee for this operation to compensate for this this externality (this bound gas amount is configured as parameter `PubKeyChangeCost`). The bonus gas is charged inside the handler, using the `ConsumeGas` function. Furthermore, in the future, we can allow accounts that have rekeyed manually prune themselves using a new Msg type such as `MsgDeleteAccount`. Manually pruning accounts can give a gas refund as an incentive for performing the action.
```go
amount := ak.GetParams(ctx).PubKeyChangeCost
ctx.GasMeter().ConsumeGas(amount, "pubkey change fee")
```
Everytime a key for an address is changed, we will store a log of this change in the state of the chain, thus creating a stack of all previous keys for an address and the time intervals for which they were active. This allows dapps and clients to easily query past keys for an account which may be useful for features such as verifying timestamped off-chain signed messages.
## Consequences
### Positive
* Will allow users and validator operators to employ better operational security practices with key rotation.
* Will allow organizations or groups to easily change and add/remove multisig signers.
### Negative
Breaks the current assumed relationship between address and pubkeys as H(pubkey) = address. This has a couple of consequences.
* This makes wallets that support this feature more complicated. For example, if an address on chain was updated, the corresponding key in the CLI wallet also needs to be updated.
* Cannot automatically prune accounts with 0 balance that have had their pubkey changed.
### Neutral
* While the purpose of this is intended to allow the owner of an account to update to a new pubkey they own, this could technically also be used to transfer ownership of an account to a new owner. For example, this could be use used to sell a staked position without unbonding or an account that has vesting tokens. However, the friction of this is very high as this would essentially have to be done as a very specific OTC trade. Furthermore, additional constraints could be added to prevent accouns with Vesting tokens to use this feature.
* Will require that PubKeys for an account are included in the genesis exports.
## References
+ https://www.algorand.com/resources/blog/announcing-rekeying

View File

@ -62,17 +62,20 @@ In the Cosmos SDK, accounts are stored and managed via an object called a [`Keyr
A `Keyring` is an object that stores and manages accounts. In the Cosmos SDK, a `Keyring` implementation follows the `Keyring` interface:
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keyring/keyring.go#L50-L88
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keyring/keyring.go#L50-L88
The default implementation of `Keyring` comes from the third-party [`99designs/keyring`](https://github.com/99designs/keyring) library.
A few notes on the `Keyring` methods:
- `Sign(uid string, msg []byte) ([]byte, tmcrypto.PubKey, error)` strictly deals with the signature of the `message` bytes. Some preliminary work should be done beforehand to prepare and encode the `message` into a canonical `[]byte` form, and this is done in the `GetSignBytes` method. See an example of `message` preparation from the `x/bank` module. Note that signature verification is not implemented in the SDK by default. It is deferred to the [`anteHandler`](#antehandler).
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/x/bank/types/msgs.go#L51-L54
- `NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error)` creates a new account based on the [`bip44 path`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) and persists it on disk (note that the `PrivKey` is [encrypted with a passphrase before being persisted](https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keys/mintkey/mintkey.go), it is **never stored unencrypted**). In the context of this method, the `account` and `address` parameters refer to the segment of the BIP44 derivation path (e.g. `0`, `1`, `2`, ...) used to derive the `PrivKey` and `PubKey` from the mnemonic (note that given the same mnemonic and `account`, the same `PrivKey` will be generated, and given the same `account` and `address`, the same `PubKey` and `Address` will be generated). Finally, note that the `NewAccount` method derives keys and addresses using the algorithm specified in the last argument `algo`. Currently, the SDK supports two public key algorithms:
- `secp256k1`, as implemented in the [SDK's `crypto/keys/secp256k1` package](https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keys/secp256k1/secp256k1.go),
- `ed25519`, as implemented in the [SDK's `crypto/keys/ed25519` package](https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keys/ed25519/ed25519.go).
- `Sign(uid string, payload []byte) ([]byte, tmcrypto.PubKey, error)` strictly deals with the signature of the `payload` bytes. Some preliminary work should be done beforehand to prepare and encode the transaction into a canonical `[]byte` form. Protobuf being not deterministic, it has been decided in [ADR-020](../architecture/adr-020-protobuf-transaction-encoding.md) that the canonical `payload` to sign is the `SignDoc` struct, deterministically encoded using [ADR-027](adr-027-deterministic-protobuf-serialization.md). Note that signature verification is not implemented in the SDK by default, it is deferred to the [`anteHandler`](../core/baseapp.md#antehandler).
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/proto/cosmos/tx/v1beta1/tx.proto#L47-L64
- `NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error)` creates a new account based on the [`bip44 path`](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) and persists it on disk (note that the `PrivKey` is [encrypted with a passphrase before being persisted](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/armor.go), it is **never stored unencrypted**). In the context of this method, the `account` and `address` parameters refer to the segment of the BIP44 derivation path (e.g. `0`, `1`, `2`, ...) used to derive the `PrivKey` and `PubKey` from the mnemonic (note that given the same mnemonic and `account`, the same `PrivKey` will be generated, and given the same `account` and `address`, the same `PubKey` and `Address` will be generated). Finally, note that the `NewAccount` method derives keys and addresses using the algorithm specified in the last argument `algo`. Currently, the SDK supports two public key algorithms:
- `secp256k1`, as implemented in the [SDK's `crypto/keys/secp256k1` package](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/secp256k1/secp256k1.go),
- `ed25519`, as implemented in the [SDK's `crypto/keys/ed25519` package](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/ed25519/ed25519.go).
- `ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error)` exports a private key in ASCII-armored encrypted format, using the given passphrase. You can then either import it again into the keyring using the `ImportPrivKey(uid, armor, passphrase string)` function, or decrypt it into a raw private key using the `UnarmorDecryptPrivKey(armorStr string, passphrase string)` function.
Also see the [`Addresses`](#addresses) section for more information.
@ -93,20 +96,18 @@ Also see the [`Addresses`](#addresses) section for more information.
### PubKeys
`PubKey`s used in the Cosmos SDK are Protobuf messages and extend the `Pubkey` interface defined in tendermint's `crypto` package:
`PubKey`s used in the Cosmos SDK are Protobuf messages and have the following methods:
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/types/types.go#L8-L13
+++ https://github.com/cosmos/cosmos-sdk/blob/master/crypto/types/types.go#L8-L17
+++ https://github.com/tendermint/tendermint/blob/01c32c62e8840d812359c9e87e9c575aa67acb09/crypto/crypto.go#L22-L28
- For `secp256k1` keys, the actual implementation can be found [here](https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keys/secp256k1/secp256k1.go).
- For `ed25519` keys, it can be found [here](https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/crypto/keys/ed25519/ed25519.go).
- For `secp256k1` keys, the actual implementation can be found [here](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/secp256k1/secp256k1.go).
- For `ed25519` keys, it can be found [here](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/ed25519/ed25519.go).
In both case, the actual key (as raw bytes) is the compressed form of the pubkey. The first byte 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.
Note that in the Cosmos SDK, `Pubkeys` are not manipulated in their raw bytes form. Instead, they are encoded to string using [`Amino`](../core/encoding.md#amino) and [`bech32`](https://en.bitcoin.it/wiki/Bech32). In the SDK, it is done by first calling the `Bytes()` method on the raw `Pubkey` (which applies amino encoding), and then the `ConvertAndEncode` method of `bech32`.
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/types/address.go#L579-L729
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/address.go#L579-L729
### Addresses
@ -124,11 +125,11 @@ aa := sdk.AccAddress(pub.Address().Bytes())
These addresses implement the `Address` interface:
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/types/address.go#L73-L82
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/address.go#L73-L82
Of note, the `Marshal()` and `Bytes()` method both return the same raw `[]byte` form of the address, the former being needed for Protobuf compatibility. Also, the `String()` method is used to return the `bech32` encoded form of the address, which should be the only address format with which end-user interract. Here is an example:
+++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/types/address.go#L232-L246
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/address.go#L232-L246
## Next {hide}

View File

@ -49,17 +49,17 @@ The first thing defined in `app.go` is the `type` of the application. It is gene
- **A list of module's `keeper`s.** Each module defines an abstraction called [`keeper`](../building-modules/keeper.md), which handles reads and writes for this module's store(s). The `keeper`'s methods of one module can be called from other modules (if authorized), which is why they are declared in the application's type and exported as interfaces to other modules so that the latter can only access the authorized functions.
- **A reference to an [`appCodec`](../core/encoding.md).** The application's `appCodec` is used to serialize and deserialize data structures in order to store them, as stores can only persist `[]bytes`. The default codec is [Protocol Buffers](../core/encoding.md).
- **A reference to a [`legacyAmino`](../core/encoding.md) codec.** Some parts of the SDK have not been migrated to use the `appCodec` above, and are still hardcoded to use Amino. Other parts explicity use Amino for backwards compatibility. For these reasons, the application still holds a reference to the legacy Amino codec. Please note that the Amino codec will be removed from the SDK in the upcoming releases.
- **A reference to a [module manager](../building-modules/module-manager.md#manager)** and a [basic module manager](../building-modules/module-manager.md#basicmanager). The module manager is an object that contains a list of the application's module. It facilitates operations related to these modules, like registering their [`Msg` services](../core/baseapp.md#msg-services) and [gRPC `Query` services](../core/baseapp.md#grpc-query-services), or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker). For backwards-compatibility reasons, all modules expose [legacy `Msg`s routes](../core/baseapp.md#routing) and [legacy query routes](../core/baseapp.md#legacy-query-routing), which are also registered by the module manager..
- **A reference to a [module manager](../building-modules/module-manager.md#manager)** and a [basic module manager](../building-modules/module-manager.md#basicmanager). The module manager is an object that contains a list of the application's module. It facilitates operations related to these modules, like registering their [`Msg` service](../core/baseapp.md#msg-services) and [gRPC `Query` service](../core/baseapp.md#grpc-query-services), or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker).
See an example of application type definition from `simapp`, the SDK's own app used for demo and testing purposes:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/app.go#L139-L181
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/app.go#L139-L181
### Constructor Function
This function constructs a new application of the type defined in the section above. It must fulfill the `AppCreator` signature in order to be used in the [`start` command](../core/node.md#start-command) of the application's daemon command.
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/server/types/app.go#L42-L44
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/server/types/app.go#L42-L44
Here are the main actions performed by this function:
@ -81,7 +81,7 @@ Note that this function only creates an instance of the app, while the actual st
See an example of application constructor from `simapp`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/app.go#L192-L429
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/app.go#L192-L429
### InitChainer
@ -91,7 +91,7 @@ In general, the `InitChainer` is mostly composed of the [`InitGenesis`](../build
See an example of an `InitChainer` from `simapp`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/app.go#L452-L459
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/app.go#L452-L459
### BeginBlocker and EndBlocker
@ -103,13 +103,13 @@ As a sidenote, it is important to remember that application-specific blockchains
See an example of `BeginBlocker` and `EndBlocker` functions from `simapp`
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/app.go#L442-L450
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/app.go#L442-L450
### Register Codec
The `EncodingConfig` structure is the last important part of the `app.go` file. The goal of this structure is to define the codecs that will be used throughout the app.
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/params/encoding.go#L9-L16
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/params/encoding.go#L9-L16
Here are descriptions of what each of the four fields means:
@ -123,7 +123,7 @@ The SDK exposes a `MakeCodecs` function used to create a `EncodingConfig`. It us
See an example of a `MakeCodecs` from `simapp`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/simapp/app.go#L429-L435
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/simapp/app.go#L429-L435
## Modules
@ -143,33 +143,19 @@ When a valid block of transactions is received by the full-node, Tendermint rela
1. Upon receiving the transaction, the application first unmarshalls it from `[]bytes`.
2. Then, it verifies a few things about the transaction like [fee payment and signatures](#gas-fees.md#antehandler) before extracting the `Msg`(s) contained in the transaction.
3. `Msg`s are encoded as Protobuf [`Any`s](#register-codec) via the `sdk.ServiceMsg` struct. By analyzing each `Any`'s `type_url`, the application routes the `Msg` to the corresponding module's `Msg` service.
3. `Msg`s are encoded as Protobuf [`Any`s](#register-codec) via the `sdk.ServiceMsg` struct. By analyzing each `Any`'s `type_url`, baseapp's `msgServiceRouter` routes the `Msg` to the corresponding module's `Msg` service.
4. If the message is successfully processed, the state is updated.
For a more detailed look at a transaction lifecycle, click [here](./tx-lifecycle.md).
Module developers create custom `Msg`s when they build their own module. The general practice is to define all `Msg`s in a Protobuf service called `service Msg {}`, and define each `Msg` as a Protobuf service method, using the `rpc` keyword. These definitions usually reside in a `tx.proto` file. For example, the `x/bank` module defines two `Msg`s to allows users to transfer tokens:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
These two `Msg`s are processed by the `Msg` service of the `x/bank` module, which ultimately calls the `keeper` of the `x/auth` module in order to update the state.
Each module should also implement the `RegisterServices` method as part of the [`AppModule` interface](#application-module-interface). This method should call the `RegisterMsgServer` function provided by the generated Protobuf code.
#### Handlers
The [handler](../building-modules/msg-services.md#handler-type) refers to the part of the module responsible for processing the `Msg` after it is routed by `baseapp`. Handler functions of modules are only executed if the transaction is relayed from Tendermint by the `DeliverTx` ABCI message. If the transaction is relayed by `CheckTx`, only stateless checks and fee-related stateful checks are performed. To better understand the difference between `DeliverTx`and `CheckTx`, as well as the difference between stateful and stateless checks, click [here](./tx-lifecycle.md).
The `handler` of a module is generally defined in a file called `handler.go` and consists of:
- A **switch function** `NewHandler` to route the message to the appropriate `handler` function. This function returns a `handler` function, and is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the [application's router](../core/baseapp.md#routing). Next is an example from `x/bank`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/x/bank/handler.go#L10-L30
- **One handler function for each message type defined by the module**. Developers write the message processing logic in these functions. This generally involves doing stateful checks to ensure the message is valid and calling [`keeper`](#keeper)'s methods to update the state.
Handler functions return a result of type `sdk.Result`, which informs the application on whether the message was successfully processed:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/types/result.go#L15-L40
### gRPC `Query` Services
gRPC `Query` services are introduced in the v0.40 Stargate release. They allow users to query the state using [gRPC](https://grpc.io). They are enabled by default, and can be configued under the `grpc.enable` and `grpc.address` fields inside `app.toml`.
@ -180,35 +166,6 @@ Protobuf generates a `QueryServer` interface for each module, containing all the
Finally, each module should also implement the `RegisterServices` method as part of the [`AppModule` interface](#application-module-interface). This method should call the `RegisterQueryServer` function provided by the generated Protobuf code.
### Legacy `Msg`s
While the [`Msg` service](#msg-services) introduced in v0.40 is the official way to define `Msg`s, the SDK still handles legacy `Msg`s defined with previous versions of the SDK.
[Legacy `Msg`s](../building-modules/messages-and-queries.md#messages) are objects defined by each module that implement the [`sdk.Msg`](../building-modules/messages-and-queries.md#messages) interface. Each [`transaction`](../core/transactions.md) contains one or multiple legacy `Msg`s, and can also contain both legacy and non-legacy `Msg`s.
The application handles the transaction almost like with `Msg` service `Msg`s, only the third step (routing) differs:
1. Upon receiving the transaction, the application first unmarshalls it from `[]bytes`.
2. Then, it verifies a few things about the transaction like [fee payment and signatures](#gas-fees.md#antehandler) before extracting the message(s) contained in the transaction.
3. With the `Type()` method of the legacy `Msg`, `baseapp` is able to route it to the appropriate module's [legacy `Msg` handler](#handler) in order for it to be processed.
4. If the message is successfully processed, the state is updated.
New `Msg` services are compatible with legacy `Msg`s in terms of how `Msg`s are handled, please refer to the [handler](#handlers) section for more information.
### Legacy Query Routes
Legacy queriers were queriers used before the introduction of Protobuf and gRPC in the SDK. They are present for existing modules, but will be deprecated in a future release of the SDK. If you are developing new modules, gRPC `Query` services should be preferred, and you only need to implement the `LegacyQuerierHandler` interface if you wish to use legacy queriers.
[`Legacy queriers`](../building-modules/query-services.md#legacy-queriers) are very similar to `handlers`, except they serve user queries to the state as opposed to processing transactions. A [query](../building-modules/messages-and-queries.md#queries) is initiated from an [interface](#application-interface) by an end-user who provides a `queryRoute` and some `data`. The query is then routed to the correct application's `querier` by `baseapp`'s `handleQueryCustom` method using `queryRoute`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/baseapp/abci.go#L388-L418
The `Querier` of a module is defined in a file called `keeper/querier.go`, and consists of:
- A **switch function** `NewQuerier` to route the query to the appropriate `querier` function. This function returns a `querier` function, and is is registered in the [`AppModule`](#application-module-interface) to be used in the application's module manager to initialize the [application's query router](../core/baseapp.md#query-routing). See an example of such a switch from the [nameservice tutorial](https://github.com/cosmos/sdk-tutorials/tree/master/nameservice):
+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/querier.go#L19-L32
- **One querier function for each data type defined by the module that needs to be queryable**. Developers write the query processing logic in these functions. This generally involves calling [`keeper`](#keeper)'s methods to query the state and marshalling it to JSON.
### Keeper
[`Keepers`](../building-modules/keeper.md) are the gatekeepers of their module's store(s). To read or write in a module's store, it is mandatory to go through one of its `keeper`'s methods. This is ensured by the [object-capabilities](../core/ocap.md) model of the Cosmos SDK. Only objects that hold the key to a store can access it, and only the module's `keeper` should hold the key(s) to the module's store(s).
@ -257,7 +214,7 @@ The [module's Legacy REST interface](../building-modules/module-interfaces.md#le
- A `RegisterRoutes` function, which registers each route defined in the file. This function is called from the [main application's interface](#application-interfaces) for each module used within the application. The router used in the SDK is [Gorilla's mux](https://github.com/gorilla/mux).
- Custom request type definitions for each query or transaction creation function that needs to be exposed. These custom request types build on the base `request` type of the Cosmos SDK:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/types/rest/rest.go#L62-L76
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/rest/rest.go#L62-L76
- One handler function for each request that can be routed to the given module. These functions implement the core logic necessary to serve the request.
These Legacy API endpoints are present in the SDK for backward compatibility purposes and will be removed in the next release.

View File

@ -2,7 +2,7 @@
order: 4
-->
# Gas and Fees
# Gas and Fees
This document describes the default strategies to handle gas and fees within a Cosmos SDK application. {synopsis}
@ -15,21 +15,21 @@ This document describes the default strategies to handle gas and fees within a C
In the Cosmos SDK, `gas` is a special unit that is used to track the consumption of resources during execution. `gas` is typically consumed whenever read and writes are made to the store, but it can also be consumed if expensive computation needs to be done. It serves two main purposes:
- Make sure blocks are not consuming too many resources and will be finalized. This is implemented by default in the SDK via the [block gas meter](#block-gas-meter).
- Prevent spam and abuse from end-user. To this end, `gas` consumed during [`message`](../building-modules/messages-and-queries.md#messages) execution is typically priced, resulting in a `fee` (`fees = gas * gas-prices`). `fees` generally have to be paid by the sender of the `message`. Note that the SDK does not enforce `gas` pricing by default, as there may be other ways to prevent spam (e.g. bandwidth schemes). Still, most applications will implement `fee` mechanisms to prevent spam. This is done via the [`AnteHandler`](#antehandler).
- Prevent spam and abuse from end-user. To this end, `gas` consumed during [`message`](../building-modules/messages-and-queries.md#messages) execution is typically priced, resulting in a `fee` (`fees = gas * gas-prices`). `fees` generally have to be paid by the sender of the `message`. Note that the SDK does not enforce `gas` pricing by default, as there may be other ways to prevent spam (e.g. bandwidth schemes). Still, most applications will implement `fee` mechanisms to prevent spam. This is done via the [`AnteHandler`](#antehandler).
## Gas Meter
In the Cosmos SDK, `gas` is a simple alias for `uint64`, and is managed by an object called a *gas meter*. Gas meters implement the `GasMeter` interface
In the Cosmos SDK, `gas` is a simple alias for `uint64`, and is managed by an object called a _gas meter_. Gas meters implement the `GasMeter` interface
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/store/types/gas.go#L31-L39
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/store/types/gas.go#L34-L43
where:
- `GasConsumed()` returns the amount of gas that was consumed by the gas meter instance.
- `GasConsumedToLimit()` returns the amount of gas that was consumed by gas meter instance, or the limit if it is reached.
- `Limit()` returns the limit of the gas meter instance. `0` if the gas meter is infinite.
- `ConsumeGas(amount Gas, descriptor string)` consumes the amount of `gas` provided. If the `gas` overflows, it panics with the `descriptor` message. If the gas meter is not infinite, it panics if `gas` consumed goes above the limit.
- `IsPastLimit()` returns `true` if the amount of gas consumed by the gas meter instance is strictly above the limit, `false` otherwise.
- `Limit()` returns the limit of the gas meter instance. `0` if the gas meter is infinite.
- `ConsumeGas(amount Gas, descriptor string)` consumes the amount of `gas` provided. If the `gas` overflows, it panics with the `descriptor` message. If the gas meter is not infinite, it panics if `gas` consumed goes above the limit.
- `IsPastLimit()` returns `true` if the amount of gas consumed by the gas meter instance is strictly above the limit, `false` otherwise.
- `IsOutOfGas()` returns `true` if the amount of gas consumed by the gas meter instance is above or equal to the limit, `false` otherwise.
The gas meter is generally held in [`ctx`](../core/context.md), and consuming gas is done with the following pattern:
@ -38,19 +38,19 @@ The gas meter is generally held in [`ctx`](../core/context.md), and consuming ga
ctx.GasMeter().ConsumeGas(amount, "description")
```
By default, the Cosmos SDK makes use of two different gas meters, the [main gas meter](#main-gas-metter[) and the [block gas meter](#block-gas-meter).
By default, the Cosmos SDK makes use of two different gas meters, the [main gas meter](#main-gas-metter[) and the [block gas meter](#block-gas-meter).
### Main Gas Meter
`ctx.GasMeter()` is the main gas meter of the application. The main gas meter is initialized in `BeginBlock` via `setDeliverState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`BeginBlock`](../core/baseapp.md#beginblock), [`DeliverTx`](../core/baseapp.md#delivertx) and [`EndBlock`](../core/baseapp.md#endblock). At the beginning of each `DeliverTx`, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction.
`ctx.GasMeter()` is the main gas meter of the application. The main gas meter is initialized in `BeginBlock` via `setDeliverState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`BeginBlock`](../core/baseapp.md#beginblock), [`DeliverTx`](../core/baseapp.md#delivertx) and [`EndBlock`](../core/baseapp.md#endblock). At the beginning of each `DeliverTx`, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction.
Gas consumption can be done manually, generally by the module developer in the [`BeginBlocker`, `EndBlocker`](../building-modules/beginblock-endblock.md) or [`Msg` service](../building-modules/msg-services.md), but most of the time it is done automatically whenever there is a read or write to the store. This automatic gas consumption logic is implemented in a special store called [`GasKv`](../core/store.md#gaskv-store).
Gas consumption can be done manually, generally by the module developer in the [`BeginBlocker`, `EndBlocker`](../building-modules/beginblock-endblock.md) or [`Msg` service](../building-modules/msg-services.md), but most of the time it is done automatically whenever there is a read or write to the store. This automatic gas consumption logic is implemented in a special store called [`GasKv`](../core/store.md#gaskv-store).
### Block Gas Meter
`ctx.BlockGasMeter()` is the gas meter used to track gas consumption per block and make sure it does not go above a certain limit. A new instance of the `BlockGasMeter` is created each time [`BeginBlock`](../core/baseapp.md#beginblock) is called. The `BlockGasMeter` is finite, and the limit of gas per block is defined in the application's consensus parameters. By default Cosmos SDK applications use the default consensus parameters provided by Tendermint:
+++ https://github.com/tendermint/tendermint/blob/f323c80cb3b78e123ea6238c8e136a30ff749ccc/types/params.go#L65-L72
+++ https://github.com/tendermint/tendermint/blob/v0.34.0-rc6/types/params.go#L34-L41
When a new [transaction](../core/transactions.md) is being processed via `DeliverTx`, the current value of `BlockGasMeter` is checked to see if it is above the limit. If it is, `DeliverTx` returns immediately. This can happen even with the first transaction in a block, as `BeginBlock` itself can consume gas. If not, the transaction is processed normally. At the end of `DeliverTx`, the gas tracked by `ctx.BlockGasMeter()` is increased by the amount consumed to process the transaction:
@ -63,7 +63,7 @@ ctx.BlockGasMeter().ConsumeGas(
## AnteHandler
The `AnteHandler` is a special `handler` that is run for every transaction during `CheckTx` and `DeliverTx`, before the `handler` of each `message` in the transaction. `AnteHandler`s have a different signature than `handler`s:
The `AnteHandler` is run for every transaction during `CheckTx` and `DeliverTx`, before the `Msg` service of each `Msg` in the transaction. `AnteHandler`s have the following signature:
```go
// AnteHandler authenticates transactions, before their internal messages are handled.
@ -71,18 +71,18 @@ The `AnteHandler` is a special `handler` that is run for every transaction durin
type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, result Result, abort bool)
```
The `anteHandler` is not implemented in the core SDK but in a module. This gives the possibility to developers to choose which version of `AnteHandler` fits their application's needs. That said, most applications today use the default implementation defined in the [`auth` module](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth). Here is what the `anteHandler` is intended to do in a normal Cosmos SDK application:
The `anteHandler` is not implemented in the core SDK but in a module. This gives the possibility to developers to choose which version of `AnteHandler` fits their application's needs. That said, most applications today use the default implementation defined in the [`auth` module](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth). Here is what the `anteHandler` is intended to do in a normal Cosmos SDK application:
- Verify that the transaction are of the correct type. Transaction types are defined in the module that implements the `anteHandler`, and they follow the transaction interface:
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L33-L41
This enables developers to play with various types for the transaction of their application. In the default `auth` module, the standard transaction type is `StdTx`:
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L22-L29
- Verify signatures for each [`message`](../building-modules/messages-and-queries.md#messages) contained in the transaction. Each `message` should be signed by one or multiple sender(s), and these signatures must be verified in the `anteHandler`.
- During `CheckTx`, verify that the gas prices provided with the transaction is greater than the local `min-gas-prices` (as a reminder, gas-prices can be deducted from the following equation: `fees = gas * gas-prices`). `min-gas-prices` is a parameter local to each full-node and used during `CheckTx` to discard transactions that do not provide a minimum amount of fees. This ensure that the mempool cannot be spammed with garbage transactions.
- Verify that the sender of the transaction has enough funds to cover for the `fees`. When the end-user generates a transaction, they must indicate 2 of the 3 following parameters (the third one being implicit): `fees`, `gas` and `gas-prices`. This signals how much they are willing to pay for nodes to execute their transaction. The provided `gas` value is stored in a parameter called `GasWanted` for later use.
- Set `newCtx.GasMeter` to 0, with a limit of `GasWanted`. **This step is extremely important**, as it not only makes sure the transaction cannot consume infinite gas, but also that `ctx.GasMeter` is reset in-between each `DeliverTx` (`ctx` is set to `newCtx` after `anteHandler` is run, and the `anteHandler` is run each time `DeliverTx` is called).
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/tx_msg.go#L49-L57
This enables developers to play with various types for the transaction of their application. In the default `auth` module, the default transaction type is `Tx`:
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/proto/cosmos/tx/v1beta1/tx.proto#L12-L25
- Verify signatures for each [`message`](../building-modules/messages-and-queries.md#messages) contained in the transaction. Each `message` should be signed by one or multiple sender(s), and these signatures must be verified in the `anteHandler`.
- During `CheckTx`, verify that the gas prices provided with the transaction is greater than the local `min-gas-prices` (as a reminder, gas-prices can be deducted from the following equation: `fees = gas * gas-prices`). `min-gas-prices` is a parameter local to each full-node and used during `CheckTx` to discard transactions that do not provide a minimum amount of fees. This ensure that the mempool cannot be spammed with garbage transactions.
- Verify that the sender of the transaction has enough funds to cover for the `fees`. When the end-user generates a transaction, they must indicate 2 of the 3 following parameters (the third one being implicit): `fees`, `gas` and `gas-prices`. This signals how much they are willing to pay for nodes to execute their transaction. The provided `gas` value is stored in a parameter called `GasWanted` for later use.
- Set `newCtx.GasMeter` to 0, with a limit of `GasWanted`. **This step is extremely important**, as it not only makes sure the transaction cannot consume infinite gas, but also that `ctx.GasMeter` is reset in-between each `DeliverTx` (`ctx` is set to `newCtx` after `anteHandler` is run, and the `anteHandler` is run each time `DeliverTx` is called).
As explained above, the `anteHandler` returns a maximum limit of `gas` the transaction can consume during execution called `GasWanted`. The actual amount consumed in the end is denominated `GasUsed`, and we must therefore have `GasUsed =< GasWanted`. Both `GasWanted` and `GasUsed` are relayed to the underlying consensus engine when [`DeliverTx`](../core/baseapp.md#delivertx) returns.
As explained above, the `anteHandler` returns a maximum limit of `gas` the transaction can consume during execution called `GasWanted`. The actual amount consumed in the end is denominated `GasUsed`, and we must therefore have `GasUsed =< GasWanted`. Both `GasWanted` and `GasUsed` are relayed to the underlying consensus engine when [`DeliverTx`](../core/baseapp.md#delivertx) returns.
## Next {hide}

View File

@ -83,11 +83,13 @@ When `Tx` is received by the application from the underlying consensus engine (e
### ValidateBasic
[`Message`s](../core/transactions.md#messages) are extracted from `Tx` and `ValidateBasic`, a method of the `Msg` interface implemented by the module developer, is run for each one. It should include basic **stateless** sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as account balance of an address.
[`Msg`s](../core/transactions.md#messages) are extracted from `Tx` and `ValidateBasic`, a method of the `Msg` interface implemented by the module developer, is run for each one. It should include basic **stateless** sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as account balance of an address.
### AnteHandler
The [`AnteHandler`](../basics/gas-fees.md#antehandler), which is technically optional but should be defined for each application, is run. A deep copy of the internal state, `checkState`, is made and the defined `AnteHandler` performs limited checks specified for the transaction type. Using a copy allows the handler to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails.
After the ValidateBasic checks, the `AnteHandler`s are run. Technically, they are optional, but in practice, they are very often present to perform signature verification, gas calculation, fee deduction and other core operations related to blockchain transactions.
A copy of the cached context is provided to the `AnteHandler`, which performs limited checks specified for the transaction type. Using a copy allows the AnteHandler to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails.
For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`.
@ -198,7 +200,7 @@ Instead of using their `checkState`, full-nodes use `deliverState`:
[`runMsgs`](../core/baseapp.md#runtx-and-runmsgs) to fully execute each `Msg` within the transaction.
Since the transaction may have messages from different modules, `BaseApp` needs to know which module
to find the appropriate handler. This is achieved using `BaseApp`'s `MsgServiceRouter` so that it can be processed by the module's [`Msg` service](../building-modules/msg-services.md).
For legacy `Msg` routing, the `Route` function is called via the [module manager](../building-modules/module-manager.md) to retrieve the route name and find the legacy [`Handler`](../building-modules/msg-services.md#handler-type) within the module.
For legacy `Msg` routing, the `Route` function is called via the [module manager](../building-modules/module-manager.md) to retrieve the route name and find the legacy [`Handler`](../building-modules/msg-services.md#handler-type) within the module.
- **`Msg` service:** The `Msg` service, a step up from `AnteHandler`, is responsible for executing each
message in the `Tx` and causes state transitions to persist in `deliverTxState`. It is defined

View File

@ -14,12 +14,15 @@ Some important information concerning all legacy REST endpoints:
## Breaking Changes in Legacy REST Endpoints
| Legacy REST Endpoint | Description | Breaking Change |
| ------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST /txs` | Query tx by hash | Endpoint will error when trying to broadcast transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs/{hash}` | Query tx by hash | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs` | Query tx by events | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /staking/validators` | Get all validators | BondStatus is now a protobuf enum instead of an int32, and JSON serialized using its protobuf name, so expect query parameters like `?status=BOND_STATUS_{BONDED,UNBONDED,UNBONDING}` as opposed to `?status={bonded,unbonded,unbonding}`. |
| Legacy REST Endpoint | Description | Breaking Change |
| ------------------------------------------------------------------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /txs` | Broadcast tx | Endpoint will error when trying to broadcast transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `POST /txs/encode`, `POST /txs/decode` | Encode/decode Amino txs from JSON to binary | Endpoint will error when trying to encode/decode transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs/{hash}` | Query tx by hash | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs` | Query tx by events | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /gov/proposals/{id}/votes`, `GET /gov/proposals/{id}/votes/{voter}` | Gov endpoints for querying votes | All gov endpoints which return votes return int32 in the `option` field instead of string: `1=VOTE_OPTION_YES, 2=VOTE_OPTION_ABSTAIN, 3=VOTE_OPTION_NO, 4=VOTE_OPTION_NO_WITH_VETO`. |
| `GET /staking/*` | Staking query endpoints | All staking endpoints which return validators have two breaking changes. First, the validator's `consensus_pubkey` field returns an Amino-encoded struct representing an `Any` instead of a bech32-encoded string representing the pubkey. The `value` field of the `Any` is the pubkey's raw key as base64-encoded bytes. Second, the validator's `status` field now returns an int32 instead of string: `1=BOND_STATUS_UNBONDED`, `2=BOND_STATUS_UNBONDING`, `3=BOND_STATUS_BONDED`. |
| `GET /staking/validators` | Get all validators | BondStatus is now a protobuf enum instead of an int32, and JSON serialized using its protobuf name, so expect query parameters like `?status=BOND_STATUS_{BONDED,UNBONDED,UNBONDING}` as opposed to `?status={bonded,unbonded,unbonding}`. |
<sup>1</sup>: Transactions that don't support Amino serialization are the ones that contain one or more `Msg`s that are not registered with the Amino codec. Currently in the SDK, only IBC `Msg`s fall into this case.
@ -31,7 +34,7 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
| Legacy REST Endpoint | Description | New gGPC-gateway REST Endpoint |
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `GET /txs/{hash}` | Query tx by hash | `GET /cosmos/tx/v1beta1/tx/{hash}` |
| `GET /txs/{hash}` | Query tx by hash | `GET /cosmos/tx/v1beta1/txs/{hash}` |
| `GET /txs` | Query tx by events | `GET /cosmos/tx/v1beta1/txs` |
| `POST /txs` | Broadcast tx | `POST /cosmos/tx/v1beta1/txs` |
| `POST /txs/encode` | Encodes an Amino JSON tx to an Amino binary tx | N/A, use Protobuf directly |

1065
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"vuepress-theme-cosmos": "^1.0.175"
"vuepress-theme-cosmos": "^1.0.178"
}
}

2
go.mod
View File

@ -23,6 +23,7 @@ require (
github.com/golang/snappy v0.0.2 // indirect
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/hashicorp/golang-lru v0.5.4
github.com/magiconair/properties v1.8.4
@ -34,6 +35,7 @@ require (
github.com/prometheus/common v0.15.0
github.com/rakyll/statik v0.1.7
github.com/regen-network/cosmos-proto v0.3.0
github.com/rs/zerolog v1.20.0
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1
github.com/spf13/cobra v1.1.1

5
go.sum
View File

@ -247,6 +247,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.1/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@ -480,6 +481,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.20.0 h1:38k9hgtUBdxFwE34yS8rTHmHBa4eN16E4DJlv177LNs=
github.com/rs/zerolog v1.20.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -725,6 +729,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=

View File

@ -2,13 +2,14 @@ syntax = "proto3";
package cosmos.base.tendermint.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "tendermint/p2p/types.proto";
import "tendermint/types/block.proto";
import "tendermint/types/types.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types/query";
option go_package = "github.com/cosmos/cosmos-sdk/client/grpc/tmservice";
// Service defines the gRPC querier service for tendermint queries.
service Service {
@ -70,10 +71,10 @@ message GetLatestValidatorSetResponse {
// Validator is the type for the validator-set.
message Validator {
bytes address = 1;
string pub_key = 2;
int64 voting_power = 3;
int64 proposer_priority = 4;
string address = 1;
google.protobuf.Any pub_key = 2;
int64 voting_power = 3;
int64 proposer_priority = 4;
}
// GetBlockByHeightRequest is the request type for the Query/GetBlockByHeight RPC method.

View File

@ -4,6 +4,7 @@ package cosmos.tx.v1beta1;
import "google/api/annotations.proto";
import "cosmos/base/abci/v1beta1/abci.proto";
import "cosmos/tx/v1beta1/tx.proto";
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types/tx";
@ -12,13 +13,22 @@ option go_package = "github.com/cosmos/cosmos-sdk/types/tx";
service Service {
// Simulate simulates executing a transaction for estimating gas usage.
rpc Simulate(SimulateRequest) returns (SimulateResponse) {
option (google.api.http).post = "/cosmos/tx/v1beta1/simulate";
option (google.api.http) = {
post: "/cosmos/tx/v1beta1/simulate"
body: "*"
};
}
// GetTx fetches a tx by hash.
rpc GetTx(GetTxRequest) returns (GetTxResponse) {
option (google.api.http).get = "/cosmos/tx/v1beta1/tx/{hash}";
option (google.api.http).get = "/cosmos/tx/v1beta1/txs/{hash}";
}
// BroadcastTx broadcast transaction.
rpc BroadcastTx(BroadcastTxRequest) returns (BroadcastTxResponse) {
option (google.api.http) = {
post: "/cosmos/tx/v1beta1/txs"
body: "*"
};
}
// GetTxsEvent fetches txs by event.
rpc GetTxsEvent(GetTxsEventRequest) returns (GetTxsEventResponse) {
option (google.api.http).get = "/cosmos/tx/v1beta1/txs";
@ -28,8 +38,8 @@ service Service {
// GetTxsEventRequest is the request type for the Service.TxsByEvents
// RPC method.
message GetTxsEventRequest {
// event is the transaction event type.
string event = 1;
// events is the list of transaction event type.
repeated string events = 1;
// pagination defines an pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
@ -45,6 +55,36 @@ message GetTxsEventResponse {
cosmos.base.query.v1beta1.PageResponse pagination = 3;
}
// BroadcastTxRequest is the request type for the Service.BroadcastTxRequest
// RPC method.
message BroadcastTxRequest {
// tx_bytes is the raw transaction.
bytes tx_bytes = 1;
BroadcastMode mode = 2;
}
// BroadcastMode specifies the broadcast mode for the TxService.Broadcast RPC method.
enum BroadcastMode {
// zero-value for mode ordering
BROADCAST_MODE_UNSPECIFIED = 0;
// BROADCAST_MODE_BLOCK defines a tx broadcasting mode where the client waits for
// the tx to be committed in a block.
BROADCAST_MODE_BLOCK = 1;
// BROADCAST_MODE_SYNC defines a tx broadcasting mode where the client waits for
// a CheckTx execution response only.
BROADCAST_MODE_SYNC = 2;
// BROADCAST_MODE_ASYNC defines a tx broadcasting mode where the client returns
// immediately.
BROADCAST_MODE_ASYNC = 3;
}
// BroadcastTxResponse is the response type for the
// Service.BroadcastTx method.
message BroadcastTxResponse {
// tx_response is the queried TxResponses.
cosmos.base.abci.v1beta1.TxResponse tx_response = 1;
}
// SimulateRequest is the request type for the Service.Simulate
// RPC method.
message SimulateRequest {

View File

@ -17,7 +17,30 @@ message GenesisState {
(gogoproto.castrepeated) = "ClientsConsensusStates",
(gogoproto.moretags) = "yaml:\"clients_consensus\""
];
Params params = 3 [(gogoproto.nullable) = false];
// metadata from each client
repeated IdentifiedGenesisMetadata clients_metadata = 3
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clients_metadata\""];
Params params = 4 [(gogoproto.nullable) = false];
// create localhost on initialization
bool create_localhost = 4 [(gogoproto.moretags) = "yaml:\"create_localhost\""];
bool create_localhost = 5 [(gogoproto.moretags) = "yaml:\"create_localhost\""];
// the sequence for the next generated client identifier
uint64 next_client_sequence = 6 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""];
}
// GenesisMetadata defines the genesis type for metadata that clients may return
// with ExportMetadata
message GenesisMetadata {
option (gogoproto.goproto_getters) = false;
// store key of metadata without clientID-prefix
bytes key = 1;
// metadata value
bytes value = 2;
}
// IdentifiedGenesisMetadata has the client metadata with the corresponding client id.
message IdentifiedGenesisMetadata {
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
repeated GenesisMetadata client_metadata = 2
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_metadata\""];
}

View File

@ -27,15 +27,13 @@ message MsgCreateClient {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// client unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// light client state
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""];
// consensus state associated with the client that corresponds to a given
// height.
google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
// signer address
string signer = 4;
string signer = 3;
}
// MsgCreateClientResponse defines the Msg/CreateClient response type.

View File

@ -10,19 +10,23 @@ import "ibc/core/commitment/v1/commitment.proto";
// https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures
// ConnectionEnd defines a stateful object on a chain connected to another
// separate one. NOTE: there must only be 2 defined ConnectionEnds to establish
// separate one.
// NOTE: there must only be 2 defined ConnectionEnds to establish
// a connection between two chains.
message ConnectionEnd {
option (gogoproto.goproto_getters) = false;
// client associated with this connection.
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// IBC version which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection
// channels or packets utilising this connection.
repeated Version versions = 2;
// current state of the connection end.
State state = 3;
// counterparty chain associated with this connection.
Counterparty counterparty = 4 [(gogoproto.nullable) = false];
// delay period that must pass before a consensus state can be used for packet-verification
// NOTE: delay period logic is only implemented by some clients.
uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""];
}
// IdentifiedConnection defines a connection with additional connection
@ -40,6 +44,8 @@ message IdentifiedConnection {
State state = 4;
// counterparty chain associated with this connection.
Counterparty counterparty = 5 [(gogoproto.nullable) = false];
// delay period associated with this connection.
uint64 delay_period = 6 [(gogoproto.moretags) = "yaml:\"delay_period\""];
}
// State defines if a connection is in one of the following states:
@ -68,7 +74,7 @@ message Counterparty {
// identifies the connection end on the counterparty chain associated with a
// given connection.
string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""];
// commitment merkle prefix of the counterparty chain
// commitment merkle prefix of the counterparty chain.
ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false];
}

View File

@ -32,7 +32,8 @@ message MsgConnectionOpenInit {
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
Counterparty counterparty = 2 [(gogoproto.nullable) = false];
Version version = 3;
string signer = 4;
uint64 delay_period = 4 [(gogoproto.moretags) = "yaml:\"delay_period\""];
string signer = 5;
}
// MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response type.
@ -50,19 +51,20 @@ message MsgConnectionOpenTry {
string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""];
google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""];
Counterparty counterparty = 4 [(gogoproto.nullable) = false];
repeated Version counterparty_versions = 5 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
ibc.core.client.v1.Height proof_height = 6
uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""];
repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
ibc.core.client.v1.Height proof_height = 7
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
// proof of the initialization the connection on Chain A: `UNITIALIZED ->
// INIT`
bytes proof_init = 7 [(gogoproto.moretags) = "yaml:\"proof_init\""];
bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""];
// proof of client state included in message
bytes proof_client = 8 [(gogoproto.moretags) = "yaml:\"proof_client\""];
bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""];
// proof of client consensus state
bytes proof_consensus = 9 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 10
bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 11
[(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false];
string signer = 11;
string signer = 12;
}
// MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type.

View File

@ -26,9 +26,9 @@ import (
// Server defines the server's API interface.
type Server struct {
Router *mux.Router
GRPCRouter *runtime.ServeMux
ClientCtx client.Context
Router *mux.Router
GRPCGatewayRouter *runtime.ServeMux
ClientCtx client.Context
logger log.Logger
metrics *telemetry.Metrics
@ -63,7 +63,7 @@ func New(clientCtx client.Context, logger log.Logger) *Server {
Router: mux.NewRouter(),
ClientCtx: clientCtx,
logger: logger,
GRPCRouter: runtime.NewServeMux(
GRPCGatewayRouter: runtime.NewServeMux(
// Custom marshaler option is required for gogo proto
runtime.WithMarshalerOption(runtime.MIMEWildcard, marshalerOption),
@ -124,7 +124,7 @@ func (s *Server) Close() error {
}
func (s *Server) registerGRPCGatewayRoutes() {
s.Router.PathPrefix("/").Handler(s.GRPCRouter)
s.Router.PathPrefix("/").Handler(s.GRPCGatewayRouter)
}
func (s *Server) registerMetrics() {

View File

@ -11,55 +11,66 @@ import (
"github.com/stretchr/testify/suite"
"google.golang.org/grpc"
"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"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
conn *grpc.ClientConn
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
s.network = network.New(s.T(), network.DefaultConfig())
s.cfg = network.DefaultConfig()
s.network = network.New(s.T(), s.cfg)
s.Require().NotNil(s.network)
_, err := s.network.WaitForHeight(2)
s.Require().NoError(err)
val0 := s.network.Validators[0]
s.conn, err = grpc.Dial(
val0.AppConfig.GRPC.Address,
grpc.WithInsecure(), // Or else we get "no transport security set"
)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.conn.Close()
s.network.Cleanup()
}
func (s *IntegrationTestSuite) TestGRPCServer() {
val0 := s.network.Validators[0]
conn, err := grpc.Dial(
val0.AppConfig.GRPC.Address,
grpc.WithInsecure(), // Or else we get "no transport security set"
)
s.Require().NoError(err)
defer conn.Close()
func (s *IntegrationTestSuite) TestGRPCServer_TestService() {
// gRPC query to test service should work
testClient := testdata.NewQueryClient(conn)
testClient := testdata.NewQueryClient(s.conn)
testRes, err := testClient.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
s.Require().NoError(err)
s.Require().Equal("hello", testRes.Message)
}
func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() {
val0 := s.network.Validators[0]
// gRPC query to bank service should work
denom := fmt.Sprintf("%stoken", val0.Moniker)
bankClient := banktypes.NewQueryClient(conn)
bankClient := banktypes.NewQueryClient(s.conn)
var header metadata.MD
bankRes, err := bankClient.Balance(
context.Background(),
@ -82,9 +93,11 @@ func (s *IntegrationTestSuite) TestGRPCServer() {
)
blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader)
s.Require().Equal([]string{"1"}, blockHeight)
}
func (s *IntegrationTestSuite) TestGRPCServer_Reflection() {
// Test server reflection
reflectClient := rpb.NewServerReflectionClient(conn)
reflectClient := rpb.NewServerReflectionClient(s.conn)
stream, err := reflectClient.ServerReflectionInfo(context.Background(), grpc.WaitForReady(true))
s.Require().NoError(err)
s.Require().NoError(stream.Send(&rpb.ServerReflectionRequest{
@ -101,6 +114,65 @@ func (s *IntegrationTestSuite) TestGRPCServer() {
s.Require().True(servicesMap["cosmos.bank.v1beta1.Query"])
}
func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() {
// Query the tx via gRPC without pagination. This used to panic, see
// https://github.com/cosmos/cosmos-sdk/issues/8038.
txServiceClient := txtypes.NewServiceClient(s.conn)
_, err := txServiceClient.GetTxsEvent(
context.Background(),
&tx.GetTxsEventRequest{
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)
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,
},
)
s.Require().NoError(err)
s.Require().Equal(uint32(0), grpcRes.TxResponse.Code)
}
// Test and enforce that we upfront reject any connections to baseapp containing
// invalid initial x-cosmos-block-height that aren't positive and in the range [0, max(int64)]
// See issue https://github.com/cosmos/cosmos-sdk/issues/7662.

55
server/logger.go Normal file
View File

@ -0,0 +1,55 @@
package server
import (
"github.com/rs/zerolog"
tmlog "github.com/tendermint/tendermint/libs/log"
)
var _ tmlog.Logger = (*ZeroLogWrapper)(nil)
// ZeroLogWrapper provides a wrapper around a zerolog.Logger instance. It implements
// Tendermint's Logger interface.
type ZeroLogWrapper struct {
zerolog.Logger
}
// Info implements Tendermint's Logger interface and logs with level INFO. A set
// of key/value tuples may be provided to add context to the log. The number of
// tuples must be even and the key of the tuple must be a string.
func (z ZeroLogWrapper) Info(msg string, keyVals ...interface{}) {
z.Logger.Info().Fields(getLogFields(keyVals...)).Msg(msg)
}
// Error implements Tendermint's Logger interface and logs with level ERR. A set
// of key/value tuples may be provided to add context to the log. The number of
// tuples must be even and the key of the tuple must be a string.
func (z ZeroLogWrapper) Error(msg string, keyVals ...interface{}) {
z.Logger.Error().Fields(getLogFields(keyVals...)).Msg(msg)
}
// Debug implements Tendermint's Logger interface and logs with level DEBUG. A set
// of key/value tuples may be provided to add context to the log. The number of
// tuples must be even and the key of the tuple must be a string.
func (z ZeroLogWrapper) Debug(msg string, keyVals ...interface{}) {
z.Logger.Debug().Fields(getLogFields(keyVals...)).Msg(msg)
}
// With returns a new wrapped logger with additional context provided by a set
// of key/value tuples. The number of tuples must be even and the key of the
// tuple must be a string.
func (z ZeroLogWrapper) With(keyVals ...interface{}) tmlog.Logger {
return ZeroLogWrapper{z.Logger.With().Fields(getLogFields(keyVals...)).Logger()}
}
func getLogFields(keyVals ...interface{}) map[string]interface{} {
if len(keyVals)%2 != 0 {
return nil
}
fields := make(map[string]interface{})
for i := 0; i < len(keyVals); i += 2 {
fields[keyVals[i].(string)] = keyVals[i+1]
}
return fields
}

View File

@ -240,17 +240,17 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("module", "node"),
ctx.Logger,
)
if err != nil {
return err
}
ctx.Logger.Debug("Initialization: tmNode created")
ctx.Logger.Debug("initialization: tmNode created")
if err := tmNode.Start(); err != nil {
return err
}
ctx.Logger.Debug("Initialization: tmNode started")
ctx.Logger.Debug("initialization: tmNode started")
config := config.GetConfig(ctx.Viper)

View File

@ -14,12 +14,12 @@ import (
"syscall"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmcfg "github.com/tendermint/tendermint/config"
tmcli "github.com/tendermint/tendermint/libs/cli"
tmflags "github.com/tendermint/tendermint/libs/cli/flags"
"github.com/tendermint/tendermint/libs/log"
tmlog "github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client/flags"
@ -39,7 +39,7 @@ const ServerContextKey = sdk.ContextKey("server.context")
type Context struct {
Viper *viper.Viper
Config *tmcfg.Config
Logger log.Logger
Logger tmlog.Logger
}
// ErrorCode contains the exit code for server exit.
@ -52,10 +52,14 @@ func (e ErrorCode) Error() string {
}
func NewDefaultContext() *Context {
return NewContext(viper.New(), tmcfg.DefaultConfig(), log.NewTMLogger(log.NewSyncWriter(os.Stdout)))
return NewContext(
viper.New(),
tmcfg.DefaultConfig(),
ZeroLogWrapper{log.Logger},
)
}
func NewContext(v *viper.Viper, config *tmcfg.Config, logger log.Logger) *Context {
func NewContext(v *viper.Viper, config *tmcfg.Config, logger tmlog.Logger) *Context {
return &Context{v, config, logger}
}
@ -86,27 +90,29 @@ func InterceptConfigsPreRunHandler(cmd *cobra.Command) error {
serverCtx.Viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
serverCtx.Viper.AutomaticEnv()
// Intercept configuration files, using both Viper instances separately
// intercept configuration files, using both Viper instances separately
config, err := interceptConfigs(serverCtx.Viper)
if err != nil {
return err
}
// Return value is a tendermint configuration object
// return value is a tendermint configuration object
serverCtx.Config = config
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, tmcfg.DefaultLogLevel())
var logWriter io.Writer
if strings.ToLower(serverCtx.Viper.GetString(flags.FlagLogFormat)) == tmcfg.LogFormatPlain {
logWriter = zerolog.ConsoleWriter{Out: os.Stderr}
} else {
logWriter = os.Stderr
}
logLvlStr := serverCtx.Viper.GetString(flags.FlagLogLevel)
logLvl, err := zerolog.ParseLevel(logLvlStr)
if err != nil {
return err
return fmt.Errorf("failed to parse log level (%s): %w", logLvlStr, err)
}
// Check if the tendermint flag for trace logging is set
// if it is then setup a tracing logger in this app as well
if serverCtx.Viper.GetBool(tmcli.TraceFlag) {
logger = log.NewTracingLogger(logger)
}
serverCtx.Logger = logger.With("module", "main")
serverCtx.Logger = ZeroLogWrapper{zerolog.New(logWriter).Level(logLvl).With().Timestamp().Logger()}
return SetCmdServerContext(cmd, serverCtx)
}

View File

@ -10,8 +10,9 @@ import (
"strings"
"testing"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/flags"
)
var CancelledInPreRun = errors.New("Canelled in prerun")

View File

@ -560,13 +560,13 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon
// Register legacy tx routes.
authrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
// Register new tx routes from grpc-gateway.
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register new tendermint queries routes from grpc-gateway.
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register legacy and grpc-gateway routes for all modules.
ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router)
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// register swagger API from root so that other applications can override easily
if apiConfig.Swagger {

View File

@ -6,8 +6,10 @@ import (
"os"
"path/filepath"
"github.com/rs/zerolog"
"github.com/spf13/cast"
"github.com/spf13/cobra"
tmcfg "github.com/tendermint/tendermint/config"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
@ -79,7 +81,8 @@ func Execute(rootCmd *cobra.Command) error {
ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{})
ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx)
rootCmd.PersistentFlags().String("log_level", srvCtx.Config.LogLevel, "The logging level in the format of <module>:<level>,...")
rootCmd.PersistentFlags().String(flags.FlagLogLevel, zerolog.InfoLevel.String(), "The logging level (trace|debug|info|warn|error|fatal|panic)")
rootCmd.PersistentFlags().String(flags.FlagLogFormat, tmcfg.LogFormatJSON, "The logging format (json|plain)")
executor := tmcli.PrepareBaseCmd(rootCmd, "", simapp.DefaultNodeHome)
return executor.ExecuteContext(ctx)

View File

@ -549,9 +549,12 @@ func (rs *Store) SetInitialVersion(version int64) error {
// Loop through all the stores, if it's an IAVL store, then set initial
// version on it.
for _, commitKVStore := range rs.stores {
if storeWithVersion, ok := commitKVStore.(types.StoreWithInitialVersion); ok {
storeWithVersion.SetInitialVersion(version)
for key, store := range rs.stores {
if store.GetStoreType() == types.StoreTypeIAVL {
// If the store is wrapped with an inter-block cache, we must first unwrap
// it to get the underlying IAVL store.
store = rs.GetCommitKVStore(key)
store.(*iavl.Store).SetInitialVersion(version)
}
}

View File

@ -657,11 +657,18 @@ func TestSetInitialVersion(t *testing.T) {
db := dbm.NewMemDB()
multi := newMultiStoreWithMounts(db, types.PruneNothing)
require.NoError(t, multi.LoadLatestVersion())
multi.SetInitialVersion(5)
require.Equal(t, int64(5), multi.initialVersion)
multi.Commit()
require.Equal(t, int64(5), multi.LastCommitID().Version)
ckvs := multi.GetCommitKVStore(multi.keysByName["store1"])
iavlStore, ok := ckvs.(*iavl.Store)
require.True(t, ok)
require.True(t, iavlStore.VersionExists(5))
}
func BenchmarkMultistoreSnapshot100K(b *testing.B) {

View File

@ -5,11 +5,11 @@ import (
"io"
abci "github.com/tendermint/tendermint/abci/types"
tmstrings "github.com/tendermint/tendermint/libs/strings"
dbm "github.com/tendermint/tm-db"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/types/kv"
tmstrings "github.com/tendermint/tendermint/libs/strings"
)
type Store interface {

View File

@ -11,7 +11,6 @@ import (
yaml "gopkg.in/yaml.v2"
"github.com/cosmos/cosmos-sdk/codec/legacy"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
)
@ -663,7 +662,7 @@ func GetPubKeyFromBech32(pkt Bech32PubKeyType, pubkeyStr string) (cryptotypes.Pu
return nil, err
}
return cryptocodec.PubKeyFromBytes(bz)
return legacy.PubKeyFromBytes(bz)
}
// MustGetPubKeyFromBech32 calls GetPubKeyFromBech32 except it panics on error.

View File

@ -151,12 +151,14 @@ func errIsNil(err error) bool {
return false
}
var errPanicWithMsg = Wrapf(ErrPanic, "panic message redacted to hide potentially sensitive system info")
// Redact replaces an error that is not initialized as an ABCI Error with a
// generic internal error instance. If the error is an ABCI Error, that error is
// simply returned.
func Redact(err error) error {
if ErrPanic.Is(err) {
return ErrPanic
return errPanicWithMsg
}
if abciCode(err) == internalABCICode {
return errInternal

View File

@ -171,7 +171,7 @@ func (s *abciTestSuite) TestRedact() {
}{
"panic looses message": {
err: Wrap(ErrPanic, "some secret stack trace"),
changed: ErrPanic,
changed: errPanicWithMsg,
},
"sdk errors untouched": {
err: Wrap(ErrUnauthorized, "cannot drop db"),
@ -233,7 +233,7 @@ func (s *abciTestSuite) TestABCIInfoSerializeErr() {
},
"redact in default encoder": {
src: myPanic,
exp: "panic",
exp: "panic message redacted to hide potentially sensitive system info: panic",
},
"do not redact in debug encoder": {
src: myPanic,

View File

@ -7,10 +7,11 @@ import (
"sort"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/gogo/protobuf/jsonpb"
proto "github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
)
// ----------------------------------------------------------------------------

View File

@ -159,7 +159,7 @@ func (s *paginationTestSuite) TestPagination() {
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().Error(err)
s.Require().Equal(err.Error(), "invalid request, either offset or key is expected, got both")
s.Require().Equal("rpc error: code = InvalidArgument desc = paginate: invalid request, either offset or key is expected, got both", err.Error())
s.T().Log("verify paginate with offset greater than total results")
pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false}

View File

@ -8,6 +8,7 @@ import (
fmt "fmt"
types "github.com/cosmos/cosmos-sdk/types"
query "github.com/cosmos/cosmos-sdk/types/query"
_ "github.com/gogo/protobuf/gogoproto"
grpc1 "github.com/gogo/protobuf/grpc"
proto "github.com/gogo/protobuf/proto"
_ "google.golang.org/genproto/googleapis/api/annotations"
@ -30,11 +31,50 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// BroadcastMode specifies the broadcast mode for the TxService.Broadcast RPC method.
type BroadcastMode int32
const (
// zero-value for mode ordering
BroadcastMode_BROADCAST_MODE_UNSPECIFIED BroadcastMode = 0
// BROADCAST_MODE_BLOCK defines a tx broadcasting mode where the client waits for
// the tx to be committed in a block.
BroadcastMode_BROADCAST_MODE_BLOCK BroadcastMode = 1
// BROADCAST_MODE_SYNC defines a tx broadcasting mode where the client waits for
// a CheckTx execution response only.
BroadcastMode_BROADCAST_MODE_SYNC BroadcastMode = 2
// BROADCAST_MODE_ASYNC defines a tx broadcasting mode where the client returns
// immediately.
BroadcastMode_BROADCAST_MODE_ASYNC BroadcastMode = 3
)
var BroadcastMode_name = map[int32]string{
0: "BROADCAST_MODE_UNSPECIFIED",
1: "BROADCAST_MODE_BLOCK",
2: "BROADCAST_MODE_SYNC",
3: "BROADCAST_MODE_ASYNC",
}
var BroadcastMode_value = map[string]int32{
"BROADCAST_MODE_UNSPECIFIED": 0,
"BROADCAST_MODE_BLOCK": 1,
"BROADCAST_MODE_SYNC": 2,
"BROADCAST_MODE_ASYNC": 3,
}
func (x BroadcastMode) String() string {
return proto.EnumName(BroadcastMode_name, int32(x))
}
func (BroadcastMode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{0}
}
// GetTxsEventRequest is the request type for the Service.TxsByEvents
// RPC method.
type GetTxsEventRequest struct {
// event is the transaction event type.
Event string `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"`
// events is the list of transaction event type.
Events []string `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"`
// pagination defines an pagination for the request.
Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"`
}
@ -72,11 +112,11 @@ func (m *GetTxsEventRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_GetTxsEventRequest proto.InternalMessageInfo
func (m *GetTxsEventRequest) GetEvent() string {
func (m *GetTxsEventRequest) GetEvents() []string {
if m != nil {
return m.Event
return m.Events
}
return ""
return nil
}
func (m *GetTxsEventRequest) GetPagination() *query.PageRequest {
@ -151,6 +191,108 @@ func (m *GetTxsEventResponse) GetPagination() *query.PageResponse {
return nil
}
// BroadcastTxRequest is the request type for the Service.BroadcastTxRequest
// RPC method.
type BroadcastTxRequest struct {
// tx_bytes is the raw transaction.
TxBytes []byte `protobuf:"bytes,1,opt,name=tx_bytes,json=txBytes,proto3" json:"tx_bytes,omitempty"`
Mode BroadcastMode `protobuf:"varint,2,opt,name=mode,proto3,enum=cosmos.tx.v1beta1.BroadcastMode" json:"mode,omitempty"`
}
func (m *BroadcastTxRequest) Reset() { *m = BroadcastTxRequest{} }
func (m *BroadcastTxRequest) String() string { return proto.CompactTextString(m) }
func (*BroadcastTxRequest) ProtoMessage() {}
func (*BroadcastTxRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{2}
}
func (m *BroadcastTxRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *BroadcastTxRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_BroadcastTxRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *BroadcastTxRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_BroadcastTxRequest.Merge(m, src)
}
func (m *BroadcastTxRequest) XXX_Size() int {
return m.Size()
}
func (m *BroadcastTxRequest) XXX_DiscardUnknown() {
xxx_messageInfo_BroadcastTxRequest.DiscardUnknown(m)
}
var xxx_messageInfo_BroadcastTxRequest proto.InternalMessageInfo
func (m *BroadcastTxRequest) GetTxBytes() []byte {
if m != nil {
return m.TxBytes
}
return nil
}
func (m *BroadcastTxRequest) GetMode() BroadcastMode {
if m != nil {
return m.Mode
}
return BroadcastMode_BROADCAST_MODE_UNSPECIFIED
}
// BroadcastTxResponse is the response type for the
// Service.BroadcastTx method.
type BroadcastTxResponse struct {
// tx_response is the queried TxResponses.
TxResponse *types.TxResponse `protobuf:"bytes,1,opt,name=tx_response,json=txResponse,proto3" json:"tx_response,omitempty"`
}
func (m *BroadcastTxResponse) Reset() { *m = BroadcastTxResponse{} }
func (m *BroadcastTxResponse) String() string { return proto.CompactTextString(m) }
func (*BroadcastTxResponse) ProtoMessage() {}
func (*BroadcastTxResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{3}
}
func (m *BroadcastTxResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *BroadcastTxResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_BroadcastTxResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *BroadcastTxResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_BroadcastTxResponse.Merge(m, src)
}
func (m *BroadcastTxResponse) XXX_Size() int {
return m.Size()
}
func (m *BroadcastTxResponse) XXX_DiscardUnknown() {
xxx_messageInfo_BroadcastTxResponse.DiscardUnknown(m)
}
var xxx_messageInfo_BroadcastTxResponse proto.InternalMessageInfo
func (m *BroadcastTxResponse) GetTxResponse() *types.TxResponse {
if m != nil {
return m.TxResponse
}
return nil
}
// SimulateRequest is the request type for the Service.Simulate
// RPC method.
type SimulateRequest struct {
@ -162,7 +304,7 @@ func (m *SimulateRequest) Reset() { *m = SimulateRequest{} }
func (m *SimulateRequest) String() string { return proto.CompactTextString(m) }
func (*SimulateRequest) ProtoMessage() {}
func (*SimulateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{2}
return fileDescriptor_e0b00a618705eca7, []int{4}
}
func (m *SimulateRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -211,7 +353,7 @@ func (m *SimulateResponse) Reset() { *m = SimulateResponse{} }
func (m *SimulateResponse) String() string { return proto.CompactTextString(m) }
func (*SimulateResponse) ProtoMessage() {}
func (*SimulateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{3}
return fileDescriptor_e0b00a618705eca7, []int{5}
}
func (m *SimulateResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -265,7 +407,7 @@ func (m *GetTxRequest) Reset() { *m = GetTxRequest{} }
func (m *GetTxRequest) String() string { return proto.CompactTextString(m) }
func (*GetTxRequest) ProtoMessage() {}
func (*GetTxRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{4}
return fileDescriptor_e0b00a618705eca7, []int{6}
}
func (m *GetTxRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -313,7 +455,7 @@ func (m *GetTxResponse) Reset() { *m = GetTxResponse{} }
func (m *GetTxResponse) String() string { return proto.CompactTextString(m) }
func (*GetTxResponse) ProtoMessage() {}
func (*GetTxResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_e0b00a618705eca7, []int{5}
return fileDescriptor_e0b00a618705eca7, []int{7}
}
func (m *GetTxResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -357,8 +499,11 @@ func (m *GetTxResponse) GetTxResponse() *types.TxResponse {
}
func init() {
proto.RegisterEnum("cosmos.tx.v1beta1.BroadcastMode", BroadcastMode_name, BroadcastMode_value)
proto.RegisterType((*GetTxsEventRequest)(nil), "cosmos.tx.v1beta1.GetTxsEventRequest")
proto.RegisterType((*GetTxsEventResponse)(nil), "cosmos.tx.v1beta1.GetTxsEventResponse")
proto.RegisterType((*BroadcastTxRequest)(nil), "cosmos.tx.v1beta1.BroadcastTxRequest")
proto.RegisterType((*BroadcastTxResponse)(nil), "cosmos.tx.v1beta1.BroadcastTxResponse")
proto.RegisterType((*SimulateRequest)(nil), "cosmos.tx.v1beta1.SimulateRequest")
proto.RegisterType((*SimulateResponse)(nil), "cosmos.tx.v1beta1.SimulateResponse")
proto.RegisterType((*GetTxRequest)(nil), "cosmos.tx.v1beta1.GetTxRequest")
@ -368,43 +513,54 @@ func init() {
func init() { proto.RegisterFile("cosmos/tx/v1beta1/service.proto", fileDescriptor_e0b00a618705eca7) }
var fileDescriptor_e0b00a618705eca7 = []byte{
// 563 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0xae, 0x1d, 0xfa, 0xc3, 0xa4, 0x08, 0x58, 0x7e, 0x14, 0x99, 0xe2, 0x06, 0xa7, 0x69, 0x23,
0x24, 0xbc, 0x6a, 0xb8, 0xf4, 0x80, 0x84, 0x84, 0x54, 0x22, 0x6e, 0xc8, 0xed, 0x89, 0x4b, 0xb5,
0x09, 0x5b, 0xc7, 0x22, 0xf1, 0xba, 0xde, 0x4d, 0xb4, 0x15, 0xf4, 0xc2, 0x91, 0x13, 0x12, 0x2f,
0xc5, 0x31, 0x12, 0x17, 0x8e, 0x28, 0xe1, 0x0d, 0x78, 0x01, 0xe4, 0xf5, 0x3a, 0x71, 0xa8, 0x4d,
0x7b, 0xf2, 0xae, 0xfc, 0xfd, 0xcc, 0x37, 0xe3, 0x31, 0x6c, 0xf7, 0x18, 0x1f, 0x32, 0x8e, 0x85,
0xc4, 0xe3, 0xfd, 0x2e, 0x15, 0x64, 0x1f, 0x73, 0x1a, 0x8f, 0x83, 0x1e, 0x75, 0xa3, 0x98, 0x09,
0x86, 0xee, 0xa6, 0x00, 0x57, 0x48, 0x57, 0x03, 0xac, 0x2d, 0x9f, 0x31, 0x7f, 0x40, 0x31, 0x89,
0x02, 0x4c, 0xc2, 0x90, 0x09, 0x22, 0x02, 0x16, 0xf2, 0x94, 0x60, 0x35, 0xb4, 0x62, 0x97, 0x70,
0x8a, 0x49, 0xb7, 0x17, 0xcc, 0x85, 0x93, 0x8b, 0x06, 0x59, 0x97, 0x6d, 0x85, 0xd4, 0xef, 0x9e,
0xe6, 0x05, 0xce, 0x46, 0x34, 0x3e, 0x9f, 0x63, 0x22, 0xe2, 0x07, 0xa1, 0x72, 0x4b, 0xb1, 0x4e,
0x0c, 0xa8, 0x43, 0xc5, 0xb1, 0xe4, 0x87, 0x63, 0x1a, 0x0a, 0x8f, 0x9e, 0x8d, 0x28, 0x17, 0xe8,
0x3e, 0xac, 0xd2, 0xe4, 0x5e, 0x33, 0xea, 0x46, 0xeb, 0xa6, 0x97, 0x5e, 0xd0, 0x6b, 0x80, 0x05,
0xbf, 0x66, 0xd6, 0x8d, 0x56, 0xb5, 0xbd, 0xeb, 0xea, 0x78, 0x89, 0x99, 0xab, 0xcc, 0xb2, 0x98,
0xee, 0x5b, 0xe2, 0x53, 0xad, 0xe8, 0xe5, 0x98, 0xce, 0xc4, 0x80, 0x7b, 0x4b, 0xa6, 0x3c, 0x62,
0x21, 0xa7, 0x68, 0x0f, 0x2a, 0x42, 0xf2, 0x9a, 0x51, 0xaf, 0xb4, 0xaa, 0xed, 0x07, 0xee, 0xa5,
0xbe, 0xb9, 0xc7, 0xd2, 0x4b, 0x10, 0xa8, 0x03, 0x9b, 0x42, 0x9e, 0xc4, 0x9a, 0xc7, 0x6b, 0xa6,
0x62, 0xec, 0x2c, 0x95, 0xa2, 0x7a, 0x95, 0x23, 0x6a, 0xb0, 0x57, 0x15, 0xf3, 0x73, 0x22, 0x94,
0x4f, 0x54, 0x51, 0x89, 0xf6, 0xae, 0x4c, 0xa4, 0x95, 0xf2, 0x91, 0x0e, 0xe0, 0xf6, 0x51, 0x30,
0x1c, 0x0d, 0x88, 0xc8, 0x12, 0xa3, 0x26, 0x98, 0x42, 0xaa, 0x06, 0x96, 0x86, 0x31, 0x85, 0x74,
0xbe, 0x18, 0x70, 0x67, 0x41, 0xd5, 0x9d, 0x78, 0x01, 0x1b, 0x3e, 0xe1, 0x27, 0x41, 0x78, 0xca,
0xb4, 0xc2, 0x93, 0xf2, 0x70, 0x1d, 0xc2, 0xdf, 0x84, 0xa7, 0xcc, 0x5b, 0xf7, 0xd3, 0x03, 0x3a,
0x80, 0xb5, 0x98, 0xf2, 0xd1, 0x40, 0xe8, 0x19, 0xd5, 0xcb, 0xb9, 0x9e, 0xc2, 0x79, 0x1a, 0xef,
0x38, 0xb0, 0xa9, 0x06, 0x93, 0x65, 0x40, 0x70, 0xa3, 0x4f, 0x78, 0x5f, 0x7f, 0x06, 0xea, 0xec,
0x5c, 0xc0, 0x2d, 0x8d, 0xd1, 0xc5, 0x5e, 0x2f, 0x28, 0x3a, 0x84, 0x6a, 0x6e, 0x68, 0xba, 0xb4,
0xeb, 0xcd, 0x0c, 0x16, 0x33, 0x6b, 0xff, 0x31, 0x61, 0xfd, 0x28, 0x5d, 0x30, 0x24, 0x61, 0x23,
0x6b, 0x1d, 0x72, 0x0a, 0x9c, 0xff, 0x19, 0x89, 0xd5, 0xf8, 0x2f, 0x26, 0x35, 0x70, 0x1a, 0x9f,
0x7f, 0xfc, 0xfe, 0x66, 0x3e, 0x76, 0x1e, 0xe1, 0x82, 0xcd, 0xce, 0xdc, 0x22, 0x58, 0x55, 0x4d,
0x40, 0xdb, 0x05, 0x92, 0xf9, 0x16, 0x5a, 0xf5, 0x72, 0x80, 0x36, 0xdc, 0x51, 0x86, 0x36, 0xda,
0xc2, 0x45, 0x3b, 0x8d, 0x3f, 0x26, 0x5d, 0xbf, 0x40, 0x9f, 0xa0, 0x9a, 0xdb, 0x19, 0xd4, 0x2c,
0x93, 0x5d, 0x5a, 0x64, 0x6b, 0xf7, 0x2a, 0x98, 0xae, 0xc1, 0x56, 0x35, 0xd4, 0xd0, 0xc3, 0xc2,
0x1a, 0xf8, 0xab, 0x97, 0xdf, 0xa7, 0xb6, 0x31, 0x99, 0xda, 0xc6, 0xaf, 0xa9, 0x6d, 0x7c, 0x9d,
0xd9, 0x2b, 0x93, 0x99, 0xbd, 0xf2, 0x73, 0x66, 0xaf, 0xbc, 0x6b, 0xfa, 0x81, 0xe8, 0x8f, 0xba,
0x6e, 0x8f, 0x0d, 0x33, 0x6e, 0xfa, 0x78, 0xc6, 0xdf, 0x7f, 0xc0, 0xe2, 0x3c, 0xa2, 0x89, 0x58,
0x77, 0x4d, 0xfd, 0x6e, 0x9e, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xae, 0x63, 0xf9, 0x38, 0x2f,
0x05, 0x00, 0x00,
// 737 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4f, 0x13, 0x41,
0x14, 0xef, 0xb6, 0xc8, 0xc7, 0x2b, 0x68, 0x1d, 0x10, 0x6b, 0xd1, 0xa5, 0x2c, 0x16, 0x08, 0x89,
0xbb, 0xa1, 0x7a, 0x20, 0xc6, 0xc4, 0xd0, 0x52, 0x08, 0x51, 0x3e, 0xb2, 0xc5, 0x83, 0xc6, 0xa4,
0x99, 0xb6, 0xc3, 0xb2, 0x91, 0xee, 0x94, 0xce, 0x94, 0x2c, 0x01, 0x62, 0xe2, 0xd1, 0x93, 0x89,
0xff, 0x94, 0x47, 0x12, 0x2f, 0x1e, 0x0d, 0xf8, 0x47, 0x78, 0x34, 0x3b, 0x3b, 0x6d, 0xb7, 0x65,
0x0b, 0xc4, 0x13, 0x33, 0xcc, 0xef, 0xfd, 0x3e, 0xde, 0x9b, 0x9d, 0xc2, 0x74, 0x85, 0xb2, 0x1a,
0x65, 0x06, 0x77, 0x8d, 0xa3, 0xa5, 0x32, 0xe1, 0x78, 0xc9, 0x60, 0xa4, 0x71, 0x64, 0x57, 0x88,
0x5e, 0x6f, 0x50, 0x4e, 0xd1, 0x7d, 0x1f, 0xa0, 0x73, 0x57, 0x97, 0x80, 0xd4, 0x63, 0x8b, 0x52,
0xeb, 0x80, 0x18, 0xb8, 0x6e, 0x1b, 0xd8, 0x71, 0x28, 0xc7, 0xdc, 0xa6, 0x0e, 0xf3, 0x0b, 0x52,
0xb3, 0x92, 0xb1, 0x8c, 0x19, 0x31, 0x70, 0xb9, 0x62, 0xb7, 0x89, 0xbd, 0x8d, 0x04, 0xa5, 0xae,
0xca, 0x72, 0x57, 0x9e, 0x4d, 0x58, 0xd4, 0xa2, 0x62, 0x69, 0x78, 0x2b, 0xf9, 0xdf, 0xc5, 0x20,
0xed, 0x61, 0x93, 0x34, 0x8e, 0xdb, 0x95, 0x75, 0x6c, 0xd9, 0x8e, 0xf0, 0xe0, 0x63, 0x35, 0x0e,
0x68, 0x9d, 0xf0, 0x5d, 0x97, 0x15, 0x8e, 0x88, 0xc3, 0x4d, 0x72, 0xd8, 0x24, 0x8c, 0xa3, 0x49,
0x18, 0x24, 0xde, 0x9e, 0x25, 0x95, 0x74, 0x6c, 0x61, 0xc4, 0x94, 0x3b, 0xb4, 0x06, 0xd0, 0x61,
0x48, 0x46, 0xd3, 0xca, 0x42, 0x3c, 0x3b, 0xa7, 0xcb, 0xd8, 0x9e, 0x9c, 0x2e, 0xe4, 0x5a, 0xf1,
0xf5, 0x1d, 0x6c, 0x11, 0xc9, 0x69, 0x06, 0x2a, 0xb5, 0x73, 0x05, 0xc6, 0xbb, 0x64, 0x59, 0x9d,
0x3a, 0x8c, 0xa0, 0x79, 0x88, 0x71, 0xd7, 0x17, 0x8d, 0x67, 0x1f, 0xe8, 0x57, 0xfa, 0xa9, 0xef,
0xba, 0xa6, 0x87, 0x40, 0xeb, 0x30, 0xca, 0xdd, 0x52, 0x43, 0xd6, 0xb1, 0x64, 0x54, 0x54, 0x3c,
0xed, 0xb2, 0x22, 0x7a, 0x18, 0x28, 0x94, 0x60, 0x33, 0xce, 0xdb, 0x6b, 0x8f, 0x28, 0x98, 0x28,
0x26, 0x12, 0xcd, 0xdf, 0x98, 0x48, 0x32, 0x05, 0x23, 0x11, 0x40, 0xb9, 0x06, 0xc5, 0xd5, 0x0a,
0x66, 0xdc, 0x13, 0xf3, 0x1b, 0xf9, 0x08, 0x86, 0xb9, 0x5b, 0x2a, 0x1f, 0x73, 0xe2, 0xa5, 0x52,
0x16, 0x46, 0xcd, 0x21, 0xee, 0xe6, 0xbc, 0x2d, 0x7a, 0x01, 0x03, 0x35, 0x5a, 0x25, 0xa2, 0x8b,
0x77, 0xb3, 0xe9, 0x90, 0xb0, 0x6d, 0xbe, 0x4d, 0x5a, 0x25, 0xa6, 0x40, 0x6b, 0x1f, 0x61, 0xbc,
0x4b, 0x46, 0x36, 0xae, 0x00, 0xf1, 0x40, 0x3f, 0x84, 0xd4, 0x6d, 0xdb, 0x01, 0x9d, 0x76, 0x68,
0xcb, 0x70, 0xaf, 0x68, 0xd7, 0x9a, 0x07, 0x98, 0xb7, 0xc6, 0x86, 0x32, 0x10, 0xe5, 0xae, 0x24,
0xec, 0x33, 0x91, 0x28, 0x77, 0xb5, 0xaf, 0x0a, 0x24, 0x3a, 0xa5, 0xd2, 0xd5, 0x2b, 0x18, 0xb6,
0x30, 0x2b, 0xd9, 0xce, 0x1e, 0x95, 0x0c, 0x33, 0xfd, 0x2d, 0xad, 0x63, 0xb6, 0xe1, 0xec, 0x51,
0x73, 0xc8, 0xf2, 0x17, 0x68, 0x19, 0x06, 0x1b, 0x84, 0x35, 0x0f, 0xb8, 0xbc, 0x68, 0xe9, 0xfe,
0xb5, 0xa6, 0xc0, 0x99, 0x12, 0xaf, 0x69, 0x30, 0x2a, 0x6e, 0x57, 0x2b, 0x03, 0x82, 0x81, 0x7d,
0xcc, 0xf6, 0x85, 0x87, 0x11, 0x53, 0xac, 0xb5, 0x33, 0x18, 0x93, 0x18, 0x69, 0xf6, 0x76, 0x41,
0x7b, 0x3b, 0x1d, 0xfd, 0xbf, 0x4e, 0x2f, 0x9e, 0xc2, 0x58, 0xd7, 0x78, 0x91, 0x0a, 0xa9, 0x9c,
0xb9, 0xbd, 0xb2, 0x9a, 0x5f, 0x29, 0xee, 0x96, 0x36, 0xb7, 0x57, 0x0b, 0xa5, 0x77, 0x5b, 0xc5,
0x9d, 0x42, 0x7e, 0x63, 0x6d, 0xa3, 0xb0, 0x9a, 0x88, 0xa0, 0x24, 0x4c, 0xf4, 0x9c, 0xe7, 0xde,
0x6e, 0xe7, 0xdf, 0x24, 0x14, 0xf4, 0x10, 0xc6, 0x7b, 0x4e, 0x8a, 0xef, 0xb7, 0xf2, 0x89, 0x68,
0x48, 0xc9, 0x8a, 0x38, 0x89, 0x65, 0xff, 0xc6, 0x60, 0xa8, 0xe8, 0xbf, 0x5d, 0xe8, 0x04, 0x86,
0x5b, 0x83, 0x43, 0x5a, 0x48, 0xee, 0x9e, 0x0b, 0x91, 0x9a, 0xbd, 0x16, 0x23, 0x2f, 0xd2, 0xdc,
0x97, 0x9f, 0x7f, 0xbe, 0x47, 0xd3, 0xda, 0x94, 0x11, 0xf2, 0x68, 0x4a, 0xf0, 0x4b, 0x65, 0x11,
0x1d, 0xc2, 0x1d, 0x31, 0x05, 0x34, 0x1d, 0xc2, 0x1a, 0x9c, 0x61, 0x2a, 0xdd, 0x1f, 0x20, 0x35,
0x33, 0x42, 0x73, 0x1a, 0x3d, 0x31, 0xc2, 0x5e, 0x4c, 0x66, 0x9c, 0x78, 0x73, 0x3f, 0x43, 0x9f,
0x21, 0x1e, 0xf8, 0x82, 0x50, 0xe6, 0xba, 0x0f, 0xaf, 0x23, 0x3f, 0x77, 0x13, 0x4c, 0x9a, 0x98,
0x11, 0x26, 0xa6, 0xb4, 0xc9, 0x70, 0x13, 0x5e, 0xe6, 0x53, 0x88, 0x07, 0xde, 0xbe, 0x50, 0x03,
0x57, 0x9f, 0xe4, 0x50, 0x03, 0x21, 0x4f, 0xa8, 0xa6, 0x0a, 0x03, 0x49, 0xd4, 0xc7, 0x40, 0xee,
0xf5, 0x8f, 0x0b, 0x55, 0x39, 0xbf, 0x50, 0x95, 0xdf, 0x17, 0xaa, 0xf2, 0xed, 0x52, 0x8d, 0x9c,
0x5f, 0xaa, 0x91, 0x5f, 0x97, 0x6a, 0xe4, 0x43, 0xc6, 0xb2, 0xf9, 0x7e, 0xb3, 0xac, 0x57, 0x68,
0xad, 0x55, 0xeb, 0xff, 0x79, 0xc6, 0xaa, 0x9f, 0x0c, 0x7e, 0x5c, 0x27, 0x1e, 0x59, 0x79, 0x50,
0xfc, 0x70, 0x3c, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x96, 0xba, 0xfb, 0xcb, 0x0f, 0x07, 0x00,
0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -423,6 +579,8 @@ type ServiceClient interface {
Simulate(ctx context.Context, in *SimulateRequest, opts ...grpc.CallOption) (*SimulateResponse, error)
// GetTx fetches a tx by hash.
GetTx(ctx context.Context, in *GetTxRequest, opts ...grpc.CallOption) (*GetTxResponse, error)
// BroadcastTx broadcast transaction.
BroadcastTx(ctx context.Context, in *BroadcastTxRequest, opts ...grpc.CallOption) (*BroadcastTxResponse, error)
// GetTxsEvent fetches txs by event.
GetTxsEvent(ctx context.Context, in *GetTxsEventRequest, opts ...grpc.CallOption) (*GetTxsEventResponse, error)
}
@ -453,6 +611,15 @@ func (c *serviceClient) GetTx(ctx context.Context, in *GetTxRequest, opts ...grp
return out, nil
}
func (c *serviceClient) BroadcastTx(ctx context.Context, in *BroadcastTxRequest, opts ...grpc.CallOption) (*BroadcastTxResponse, error) {
out := new(BroadcastTxResponse)
err := c.cc.Invoke(ctx, "/cosmos.tx.v1beta1.Service/BroadcastTx", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *serviceClient) GetTxsEvent(ctx context.Context, in *GetTxsEventRequest, opts ...grpc.CallOption) (*GetTxsEventResponse, error) {
out := new(GetTxsEventResponse)
err := c.cc.Invoke(ctx, "/cosmos.tx.v1beta1.Service/GetTxsEvent", in, out, opts...)
@ -468,6 +635,8 @@ type ServiceServer interface {
Simulate(context.Context, *SimulateRequest) (*SimulateResponse, error)
// GetTx fetches a tx by hash.
GetTx(context.Context, *GetTxRequest) (*GetTxResponse, error)
// BroadcastTx broadcast transaction.
BroadcastTx(context.Context, *BroadcastTxRequest) (*BroadcastTxResponse, error)
// GetTxsEvent fetches txs by event.
GetTxsEvent(context.Context, *GetTxsEventRequest) (*GetTxsEventResponse, error)
}
@ -482,6 +651,9 @@ func (*UnimplementedServiceServer) Simulate(ctx context.Context, req *SimulateRe
func (*UnimplementedServiceServer) GetTx(ctx context.Context, req *GetTxRequest) (*GetTxResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetTx not implemented")
}
func (*UnimplementedServiceServer) BroadcastTx(ctx context.Context, req *BroadcastTxRequest) (*BroadcastTxResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BroadcastTx not implemented")
}
func (*UnimplementedServiceServer) GetTxsEvent(ctx context.Context, req *GetTxsEventRequest) (*GetTxsEventResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetTxsEvent not implemented")
}
@ -526,6 +698,24 @@ func _Service_GetTx_Handler(srv interface{}, ctx context.Context, dec func(inter
return interceptor(ctx, in, info, handler)
}
func _Service_BroadcastTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BroadcastTxRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).BroadcastTx(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cosmos.tx.v1beta1.Service/BroadcastTx",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).BroadcastTx(ctx, req.(*BroadcastTxRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Service_GetTxsEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetTxsEventRequest)
if err := dec(in); err != nil {
@ -556,6 +746,10 @@ var _Service_serviceDesc = grpc.ServiceDesc{
MethodName: "GetTx",
Handler: _Service_GetTx_Handler,
},
{
MethodName: "BroadcastTx",
Handler: _Service_BroadcastTx_Handler,
},
{
MethodName: "GetTxsEvent",
Handler: _Service_GetTxsEvent_Handler,
@ -597,12 +791,14 @@ func (m *GetTxsEventRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x12
}
if len(m.Event) > 0 {
i -= len(m.Event)
copy(dAtA[i:], m.Event)
i = encodeVarintService(dAtA, i, uint64(len(m.Event)))
i--
dAtA[i] = 0xa
if len(m.Events) > 0 {
for iNdEx := len(m.Events) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Events[iNdEx])
copy(dAtA[i:], m.Events[iNdEx])
i = encodeVarintService(dAtA, i, uint64(len(m.Events[iNdEx])))
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
@ -670,6 +866,76 @@ func (m *GetTxsEventResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *BroadcastTxRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *BroadcastTxRequest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *BroadcastTxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Mode != 0 {
i = encodeVarintService(dAtA, i, uint64(m.Mode))
i--
dAtA[i] = 0x10
}
if len(m.TxBytes) > 0 {
i -= len(m.TxBytes)
copy(dAtA[i:], m.TxBytes)
i = encodeVarintService(dAtA, i, uint64(len(m.TxBytes)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *BroadcastTxResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *BroadcastTxResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *BroadcastTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.TxResponse != nil {
{
size, err := m.TxResponse.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintService(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *SimulateRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -846,9 +1112,11 @@ func (m *GetTxsEventRequest) Size() (n int) {
}
var l int
_ = l
l = len(m.Event)
if l > 0 {
n += 1 + l + sovService(uint64(l))
if len(m.Events) > 0 {
for _, s := range m.Events {
l = len(s)
n += 1 + l + sovService(uint64(l))
}
}
if m.Pagination != nil {
l = m.Pagination.Size()
@ -882,6 +1150,35 @@ func (m *GetTxsEventResponse) Size() (n int) {
return n
}
func (m *BroadcastTxRequest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.TxBytes)
if l > 0 {
n += 1 + l + sovService(uint64(l))
}
if m.Mode != 0 {
n += 1 + sovService(uint64(m.Mode))
}
return n
}
func (m *BroadcastTxResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.TxResponse != nil {
l = m.TxResponse.Size()
n += 1 + l + sovService(uint64(l))
}
return n
}
func (m *SimulateRequest) Size() (n int) {
if m == nil {
return 0
@ -979,7 +1276,7 @@ func (m *GetTxsEventRequest) Unmarshal(dAtA []byte) error {
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Event", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@ -1007,7 +1304,7 @@ func (m *GetTxsEventRequest) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Event = string(dAtA[iNdEx:postIndex])
m.Events = append(m.Events, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
case 2:
if wireType != 2 {
@ -1226,6 +1523,201 @@ func (m *GetTxsEventResponse) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *BroadcastTxRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowService
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: BroadcastTxRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: BroadcastTxRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field TxBytes", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowService
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthService
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthService
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.TxBytes = append(m.TxBytes[:0], dAtA[iNdEx:postIndex]...)
if m.TxBytes == nil {
m.TxBytes = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType)
}
m.Mode = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowService
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mode |= BroadcastMode(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipService(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthService
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthService
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *BroadcastTxResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowService
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: BroadcastTxResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: BroadcastTxResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field TxResponse", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowService
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthService
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthService
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.TxResponse == nil {
m.TxResponse = &types.TxResponse{}
}
if err := m.TxResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipService(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthService
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthService
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *SimulateRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0

View File

@ -31,18 +31,15 @@ var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var (
filter_Service_Simulate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Service_Simulate_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_Simulate_0); err != nil {
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@ -55,10 +52,11 @@ func local_request_Service_Simulate_0(ctx context.Context, marshaler runtime.Mar
var protoReq SimulateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_Simulate_0); err != nil {
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@ -121,6 +119,40 @@ func local_request_Service_GetTx_0(ctx context.Context, marshaler runtime.Marsha
}
func request_Service_BroadcastTx_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BroadcastTxRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BroadcastTx(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Service_BroadcastTx_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BroadcastTxRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.BroadcastTx(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Service_GetTxsEvent_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
@ -203,6 +235,26 @@ func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, se
})
mux.Handle("POST", pattern_Service_BroadcastTx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Service_BroadcastTx_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_BroadcastTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Service_GetTxsEvent_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -304,6 +356,26 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
})
mux.Handle("POST", pattern_Service_BroadcastTx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Service_BroadcastTx_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_BroadcastTx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Service_GetTxsEvent_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -330,7 +402,9 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
var (
pattern_Service_Simulate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "simulate"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1, 1, 0, 4, 1, 5, 3}, []string{"cosmos", "tx", "v1beta1", "hash"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "tx", "v1beta1", "txs", "hash"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_BroadcastTx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "txs"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Service_GetTxsEvent_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "tx", "v1beta1", "txs"}, "", runtime.AssumeColonVerbOpt(true)))
)
@ -340,5 +414,7 @@ var (
forward_Service_GetTx_0 = runtime.ForwardResponseMessage
forward_Service_BroadcastTx_0 = runtime.ForwardResponseMessage
forward_Service_GetTxsEvent_0 = runtime.ForwardResponseMessage
)

View File

@ -1,8 +1,9 @@
package types
import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/gogo/protobuf/proto"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
type (

View File

@ -735,6 +735,71 @@ func (s *IntegrationTestSuite) TestCLIMultisign() {
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *IntegrationTestSuite) TestSignBatchMultisig() {
val := s.network.Validators[0]
// Fetch 2 accounts and a multisig.
account1, err := val.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err)
account2, err := val.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err)
multisigInfo, err := val.ClientCtx.Keyring.Key("multi")
// Send coins from validator to multisig.
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
_, err = bankcli.MsgSendExec(
val.ClientCtx,
val.Address,
multisigInfo.GetAddress(),
sdk.NewCoins(sendTokens),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
generatedStd, err := bankcli.MsgSendExec(
val.ClientCtx,
multisigInfo.GetAddress(),
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
)
s.Require().NoError(err)
// Write the output to disk
filename, cleanup1 := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 1))
defer cleanup1()
val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)
// sign-batch file
res, err := authtest.TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
s.Require().NoError(err)
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file
file1, cleanup2 := testutil.WriteToNewTempFile(s.T(), res.String())
defer cleanup2()
// sign-batch file with account2
res, err = authtest.TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().String())
s.Require().NoError(err)
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file2
file2, cleanup3 := testutil.WriteToNewTempFile(s.T(), res.String())
defer cleanup3()
res, err = authtest.TxMultiSignExec(val.ClientCtx, multisigInfo.GetName(), filename.Name(), file1.Name(), file2.Name())
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TestGetAccountCmd() {
val := s.network.Validators[0]
_, _, addr1 := testdata.KeyTestPubAddr()

View File

@ -119,7 +119,10 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return err
}
} else {
err = authclient.SignTxWithSignerAddress(txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, true)
if txFactory.SignMode() == signing.SignMode_SIGN_MODE_UNSPECIFIED {
txFactory = txFactory.WithSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
err = authclient.SignTxWithSignerAddress(txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline)
}
if err != nil {

View File

@ -1,9 +1,11 @@
package rest
import (
"fmt"
"io/ioutil"
"net/http"
clientrest "github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/client"
@ -30,8 +32,15 @@ func BroadcastTxRequest(clientCtx client.Context) http.HandlerFunc {
}
// NOTE: amino is used intentionally here, don't migrate it!
if err := clientCtx.LegacyAmino.UnmarshalJSON(body, &req); rest.CheckBadRequestError(w, err) {
return
err = clientCtx.LegacyAmino.UnmarshalJSON(body, &req)
if err != nil {
err := fmt.Errorf("this transaction cannot be broadcasted via legacy REST endpoints, because it does not support"+
" Amino serialization. Please either use CLI, gRPC, gRPC-gateway, or directly query the Tendermint RPC"+
" endpoint to broadcast this transaction. The new REST endpoint (via gRPC-gateway) is POST /cosmos/tx/v1beta1/txs."+
" Please also see the REST endpoints migration guide at %s for more info", clientrest.DeprecationURL)
if rest.CheckBadRequestError(w, err) {
return
}
}
txBytes, err := tx.ConvertAndEncodeStdTx(clientCtx.TxConfig, req.Tx)

View File

@ -55,7 +55,7 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
response := DecodeResp(stdTx)
err = checkSignModeError(clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
err = checkAminoMarshalError(clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

View File

@ -2,12 +2,13 @@ package rest
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/client"
clientrest "github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
)
@ -17,6 +18,12 @@ type EncodeResp struct {
Tx string `json:"tx" yaml:"tx"`
}
// ErrEncodeDecode is the error to show when encoding/decoding txs that are not
// amino-serializable (e.g. IBC txs).
var ErrEncodeDecode error = fmt.Errorf("this endpoint does not support txs that are not serializable"+
" via Amino, such as txs that contain IBC `Msg`s. For more info, please refer to our"+
" REST migration guide at %s", clientrest.DeprecationURL)
// EncodeTxRequestHandlerFn returns the encode tx REST handler. In particular,
// it takes a json-formatted transaction, encodes it to the Amino wire protocol,
// and responds with base64-encoded bytes.
@ -31,8 +38,12 @@ func EncodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
// NOTE: amino is used intentionally here, don't migrate it
err = clientCtx.LegacyAmino.UnmarshalJSON(body, &req)
if rest.CheckBadRequestError(w, err) {
return
// If there's an unmarshalling error, we assume that it's because we're
// using amino to unmarshal a non-amino tx.
if err != nil {
if rest.CheckBadRequestError(w, ErrEncodeDecode) {
return
}
}
// re-encode it in the chain's native binary format

View File

@ -108,7 +108,7 @@ func QueryTxsRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
packStdTxResponse(w, clientCtx, txRes)
}
err = checkSignModeError(clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
err = checkAminoMarshalError(clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -151,7 +151,7 @@ func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
rest.WriteErrorResponse(w, http.StatusNotFound, fmt.Sprintf("no transaction found with hash %s", hashHexStr))
}
err = checkSignModeError(clientCtx, output, "/cosmos/tx/v1beta1/tx/{txhash}")
err = checkAminoMarshalError(clientCtx, output, "/cosmos/tx/v1beta1/txs/{txhash}")
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
@ -198,9 +198,9 @@ func packStdTxResponse(w http.ResponseWriter, clientCtx client.Context, txRes *s
return nil
}
// checkSignModeError checks if there are errors with marshalling non-amino
// checkAminoMarshalError checks if there are errors with marshalling non-amino
// txs with amino.
func checkSignModeError(ctx client.Context, resp interface{}, grpcEndPoint string) error {
func checkAminoMarshalError(ctx client.Context, resp interface{}, grpcEndPoint string) error {
// LegacyAmino used intentionally here to handle the SignMode errors
marshaler := ctx.LegacyAmino

View File

@ -21,7 +21,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
rest2 "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/x/bank/types"
@ -72,7 +72,7 @@ func (s *IntegrationTestSuite) TearDownSuite() {
s.network.Cleanup()
}
func mkTx() legacytx.StdTx {
func mkStdTx() legacytx.StdTx {
// NOTE: this uses StdTx explicitly, don't migrate it!
return legacytx.StdTx{
Msgs: []sdk.Msg{&types.MsgSend{}},
@ -84,10 +84,49 @@ func mkTx() legacytx.StdTx {
}
}
// Create an IBC tx that's encoded as amino-JSON. Since we can't amino-marshal
// a tx with "cosmos-sdk/MsgTransfer" using the SDK, we just hardcode the tx
// here. But external clients might, see https://github.com/cosmos/cosmos-sdk/issues/8022.
func mkIBCStdTx() []byte {
ibcTx := `{
"account_number": "68",
"chain_id": "stargate-4",
"fee": {
"amount": [
{
"amount": "3500",
"denom": "umuon"
}
],
"gas": "350000"
},
"memo": "",
"msg": [
{
"type": "cosmos-sdk/MsgTransfer",
"value": {
"receiver": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z",
"sender": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z",
"source_channel": "THEslipperCHANNEL",
"source_port": "transfer",
"token": {
"amount": "1000000",
"denom": "umuon"
}
}
}
],
"sequence": "24"
}`
req := fmt.Sprintf(`{"tx":%s,"mode":"async"}`, ibcTx)
return []byte(req)
}
func (s *IntegrationTestSuite) TestEncodeDecode() {
var require = s.Require()
val := s.network.Validators[0]
stdTx := mkTx()
stdTx := mkStdTx()
// NOTE: this uses amino explicitly, don't migrate it!
cdc := val.ClientCtx.LegacyAmino
@ -98,11 +137,11 @@ func (s *IntegrationTestSuite) TestEncodeDecode() {
res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", bz)
require.NoError(err)
var encodeResp rest2.EncodeResp
var encodeResp authrest.EncodeResp
err = cdc.UnmarshalJSON(res, &encodeResp)
require.NoError(err)
bz, err = cdc.MarshalJSON(rest2.DecodeReq{Tx: encodeResp.Tx})
bz, err = cdc.MarshalJSON(authrest.DecodeReq{Tx: encodeResp.Tx})
require.NoError(err)
res, err = rest.PostRequest(fmt.Sprintf("%s/txs/decode", val.APIAddress), "application/json", bz)
@ -111,14 +150,24 @@ func (s *IntegrationTestSuite) TestEncodeDecode() {
var respWithHeight rest.ResponseWithHeight
err = cdc.UnmarshalJSON(res, &respWithHeight)
require.NoError(err)
var decodeResp rest2.DecodeResp
var decodeResp authrest.DecodeResp
err = cdc.UnmarshalJSON(respWithHeight.Result, &decodeResp)
require.NoError(err)
require.Equal(stdTx, legacytx.StdTx(decodeResp))
}
func (s *IntegrationTestSuite) TestEncodeIBCTx() {
val := s.network.Validators[0]
req := mkIBCStdTx()
res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", []byte(req))
s.Require().NoError(err)
s.Require().Contains(string(res), authrest.ErrEncodeDecode.Error())
}
func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
stdTx := mkTx()
stdTx := mkStdTx()
// we just test with async mode because this tx will fail - all we care about is that it got encoded and broadcast correctly
res, err := s.broadcastReq(stdTx, "async")
@ -130,6 +179,17 @@ func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
s.Require().NotEmpty(txRes.TxHash)
}
func (s *IntegrationTestSuite) TestBroadcastIBCTxRequest() {
val := s.network.Validators[0]
req := mkIBCStdTx()
res, err := rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", []byte(req))
s.Require().NoError(err)
// Make sure the error message is correct.
s.Require().Contains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints")
}
// Helper function to test querying txs. We will use it to query StdTx and service `Msg`s.
func (s *IntegrationTestSuite) testQueryTx(txHeight int64, txHash, txRecipient string) {
val0 := s.network.Validators[0]
@ -332,7 +392,7 @@ func (s *IntegrationTestSuite) broadcastReq(stdTx legacytx.StdTx, mode string) (
// NOTE: this uses amino explicitly, don't migrate it!
cdc := val.ClientCtx.LegacyAmino
req := rest2.BroadcastReq{
req := authrest.BroadcastReq{
Tx: stdTx,
Mode: mode,
}
@ -345,7 +405,7 @@ func (s *IntegrationTestSuite) broadcastReq(stdTx legacytx.StdTx, mode string) (
// testQueryIBCTx is a helper function to test querying txs which:
// - show an error message on legacy REST endpoints
// - succeed using gRPC
// In practise, we call this function on IBC txs.
// In practice, we call this function on IBC txs.
func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.Command, args []string) {
val := s.network.Validators[0]
@ -381,7 +441,7 @@ func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.C
}
// try fetching the txn using gRPC req, it will fetch info since it has proto codec.
grpcJSON, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/tx/%s", val.APIAddress, txRes.TxHash))
grpcJSON, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, txRes.TxHash))
s.Require().NoError(err)
var getTxRes txtypes.GetTxResponse
@ -401,7 +461,7 @@ func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.C
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.GetEncodeCommand(), []string{txFileName})
s.Require().NoError(err)
bz, err := val.ClientCtx.LegacyAmino.MarshalJSON(rest2.DecodeReq{Tx: string(out.Bytes())})
bz, err := val.ClientCtx.LegacyAmino.MarshalJSON(authrest.DecodeReq{Tx: string(out.Bytes())})
s.Require().NoError(err)
// try to decode the txn using legacy rest, it fails.
@ -453,7 +513,6 @@ func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
"Successful IBC message",
ibcsolomachinecli.NewCreateClientCmd(),
[]string{
"21212121212", // dummy client-id
"1", // dummy sequence
consensusJSON.Name(), // path to consensus json,
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),

View File

@ -86,7 +86,7 @@ func NewAccountKeeper(
// Logger returns a module-specific logger.
func (ak AccountKeeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// GetPubKey Returns the PubKey of the account at address

View File

@ -49,32 +49,21 @@ const (
// TxsByEvents implements the ServiceServer.TxsByEvents RPC method.
func (s txServer) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventRequest) (*txtypes.GetTxsEventResponse, error) {
offset := int(req.Pagination.Offset)
limit := int(req.Pagination.Limit)
if offset < 0 {
return nil, status.Error(codes.InvalidArgument, "offset must greater than 0")
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}
if len(req.Event) == 0 {
page, limit, err := pagination.ParsePagination(req.Pagination)
if err != nil {
return nil, err
}
if len(req.Events) == 0 {
return nil, status.Error(codes.InvalidArgument, "must declare at least one event to search")
}
if limit < 0 {
return nil, status.Error(codes.InvalidArgument, "limit must greater than 0")
} else if limit == 0 {
limit = pagination.DefaultLimit
}
page := offset/limit + 1
var events []string
if strings.Contains(req.Event, "&") {
events = strings.Split(req.Event, "&")
} else {
events = append(events, req.Event)
}
tmEvents := make([]string, len(events))
for i, event := range events {
tmEvents := make([]string, len(req.Events))
for i, event := range req.Events {
if !strings.Contains(event, "=") {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid event; event %s should be of the format: %s", event, eventFormat))
} else if strings.Count(event, "=") > 1 {
@ -128,7 +117,7 @@ func (s txServer) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventReque
// Simulate implements the ServiceServer.Simulate RPC method.
func (s txServer) Simulate(ctx context.Context, req *txtypes.SimulateRequest) (*txtypes.SimulateResponse, error) {
if req.Tx == nil {
if req == nil || req.Tx == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
@ -154,6 +143,10 @@ func (s txServer) Simulate(ctx context.Context, req *txtypes.SimulateRequest) (*
// GetTx implements the ServiceServer.GetTx RPC method.
func (s txServer) GetTx(ctx context.Context, req *txtypes.GetTxRequest) (*txtypes.GetTxResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}
// We get hash as a hex string in the request, convert it to bytes.
hash, err := hex.DecodeString(req.Hash)
if err != nil {
@ -185,6 +178,10 @@ func (s txServer) GetTx(ctx context.Context, req *txtypes.GetTxRequest) (*txtype
}, nil
}
func (s txServer) BroadcastTx(ctx context.Context, req *txtypes.BroadcastTxRequest) (*txtypes.BroadcastTxResponse, error) {
return client.TxServiceBroadcast(ctx, s.clientCtx, req)
}
// RegisterTxService registers the tx service on the gRPC router.
func RegisterTxService(
qrt gogogrpc.Server,

View File

@ -31,6 +31,7 @@ type IntegrationTestSuite struct {
network *network.Network
queryClient tx.ServiceClient
txRes sdk.TxResponse
}
func (s *IntegrationTestSuite) SetupSuite() {
@ -41,13 +42,34 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.cfg = cfg
s.network = network.New(s.T(), cfg)
s.Require().NotNil(s.network)
val := s.network.Validators[0]
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
s.queryClient = tx.NewServiceClient(s.network.Validators[0].ClientCtx)
s.queryClient = tx.NewServiceClient(val.ClientCtx)
// Create a new MsgSend tx from val to itself.
out, err := bankcli.MsgSendExec(
val.ClientCtx,
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
)
s.Require().NoError(err)
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &s.txRes))
s.Require().Equal(uint32(0), s.txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
}
func (s *IntegrationTestSuite) TearDownSuite() {
@ -55,8 +77,354 @@ func (s *IntegrationTestSuite) TearDownSuite() {
s.network.Cleanup()
}
func (s IntegrationTestSuite) TestSimulate() {
func (s IntegrationTestSuite) TestSimulateTx_GRPC() {
txBuilder := s.mkTxBuilder()
// Convert the txBuilder to a tx.Tx.
protoTx, err := txBuilderToProtoTx(txBuilder)
s.Require().NoError(err)
testCases := []struct {
name string
req *tx.SimulateRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "request cannot be nil"},
{"empty request", &tx.SimulateRequest{}, true, "invalid empty tx"},
{"valid request", &tx.SimulateRequest{Tx: protoTx}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
// Broadcast the tx via gRPC via the validator's clientCtx (which goes
// through Tendermint).
res, err := s.queryClient.Simulate(context.Background(), tc.req)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)
// Check the result and gas used are correct.
s.Require().Equal(len(res.GetResult().GetEvents()), 4) // 1 transfer, 3 messages.
s.Require().True(res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty.
}
})
}
}
func (s IntegrationTestSuite) TestSimulateTx_GRPCGateway() {
val := s.network.Validators[0]
txBuilder := s.mkTxBuilder()
// Convert the txBuilder to a tx.Tx.
protoTx, err := txBuilderToProtoTx(txBuilder)
s.Require().NoError(err)
testCases := []struct {
name string
req *tx.SimulateRequest
expErr bool
expErrMsg string
}{
{"empty request", &tx.SimulateRequest{}, true, "invalid empty tx"},
{"valid request", &tx.SimulateRequest{Tx: protoTx}, false, ""},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
req, err := val.ClientCtx.JSONMarshaler.MarshalJSON(tc.req)
s.Require().NoError(err)
res, err := rest.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/simulate", val.APIAddress), "application/json", req)
s.Require().NoError(err)
if tc.expErr {
s.Require().Contains(string(res), tc.expErrMsg)
} else {
var result tx.SimulateResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
// Check the result and gas used are correct.
s.Require().Equal(len(result.GetResult().GetEvents()), 4) // 1 transfer, 3 messages.
s.Require().True(result.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty.
}
})
}
}
func (s IntegrationTestSuite) TestGetTxEvents_GRPC() {
testCases := []struct {
name string
req *tx.GetTxsEventRequest
expErr bool
expErrMsg string
}{
{
"nil request",
nil,
true, "request cannot be nil",
},
{
"empty request",
&tx.GetTxsEventRequest{},
true, "must declare at least one event to search",
},
{
"request with dummy event",
&tx.GetTxsEventRequest{Events: []string{"foobar"}},
true, "event foobar should be of the format: {eventType}.{eventAttribute}={value}",
},
{
"without pagination",
&tx.GetTxsEventRequest{
Events: []string{"message.action=send"},
},
false, "",
},
{
"with pagination",
&tx.GetTxsEventRequest{
Events: []string{"message.action=send"},
Pagination: &query.PageRequest{
CountTotal: false,
Offset: 0,
Limit: 1,
},
},
false, "",
},
{
"with multi events",
&tx.GetTxsEventRequest{
Events: []string{"message.action=send", "message.module=bank"},
},
false, "",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
// Query the tx via gRPC.
grpcRes, err := s.queryClient.GetTxsEvent(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().GreaterOrEqual(len(grpcRes.Txs), 1)
s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo)
}
})
}
}
func (s IntegrationTestSuite) TestGetTxEvents_GRPCGateway() {
val := s.network.Validators[0]
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{
"empty params",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.APIAddress),
true,
"must declare at least one event to search",
},
{
"without pagination",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action=send"),
false,
"",
},
{
"with pagination",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action=send", 0, 10),
false,
"",
},
{
"expect pass with multiple-events",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s", val.APIAddress, "message.action=send", "message.module=bank"),
false,
"",
},
{
"expect pass with escape event",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action%3Dsend"),
false,
"",
},
}
for _, tc := range testCases {
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 tx.GetTxsEventResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().GreaterOrEqual(len(result.Txs), 1)
s.Require().Equal("foobar", result.Txs[0].Body.Memo)
s.Require().NotZero(result.TxResponses[0].Height)
}
})
}
}
func (s IntegrationTestSuite) TestGetTx_GRPC() {
testCases := []struct {
name string
req *tx.GetTxRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "request cannot be nil"},
{"empty request", &tx.GetTxRequest{}, true, "transaction hash cannot be empty"},
{"request with dummy hash", &tx.GetTxRequest{Hash: "deadbeef"}, true, "tx (DEADBEEF) not found"},
{"good request", &tx.GetTxRequest{Hash: s.txRes.TxHash}, false, ""},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
// Query the tx via gRPC.
grpcRes, err := s.queryClient.GetTx(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().Equal("foobar", grpcRes.Tx.Body.Memo)
}
})
}
}
func (s IntegrationTestSuite) TestGetTx_GRPCGateway() {
val := s.network.Validators[0]
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{
"empty params",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/", val.APIAddress),
true, "transaction hash cannot be empty",
},
{
"dummy hash",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, "deadbeef"),
true, "tx (DEADBEEF) not found",
},
{
"good hash",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.APIAddress, s.txRes.TxHash),
false, "",
},
}
for _, tc := range testCases {
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 tx.GetTxResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().Equal("foobar", result.Tx.Body.Memo)
s.Require().NotZero(result.TxResponse.Height)
}
})
}
}
func (s IntegrationTestSuite) TestBroadcastTx_GRPC() {
val := s.network.Validators[0]
txBuilder := s.mkTxBuilder()
txBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
testCases := []struct {
name string
req *tx.BroadcastTxRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "request cannot be nil"},
{"empty request", &tx.BroadcastTxRequest{}, true, "invalid empty tx"},
{"no mode", &tx.BroadcastTxRequest{
TxBytes: txBytes,
}, true, "supported types: sync, async, block"},
{"valid request", &tx.BroadcastTxRequest{
Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
// Broadcast the tx via gRPC via the validator's clientCtx (which goes
// through Tendermint).
grpcRes, err := s.queryClient.BroadcastTx(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().Equal(uint32(0), grpcRes.TxResponse.Code)
}
})
}
}
func (s IntegrationTestSuite) TestBroadcastTx_GRPCGateway() {
val := s.network.Validators[0]
txBuilder := s.mkTxBuilder()
txBytes, err := val.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
testCases := []struct {
name string
req *tx.BroadcastTxRequest
expErr bool
expErrMsg string
}{
{"empty request", &tx.BroadcastTxRequest{}, true, "invalid empty tx"},
{"no mode", &tx.BroadcastTxRequest{TxBytes: txBytes}, true, "supported types: sync, async, block"},
{"valid request", &tx.BroadcastTxRequest{
Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
}, false, ""},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
req, err := val.ClientCtx.JSONMarshaler.MarshalJSON(tc.req)
s.Require().NoError(err)
res, err := rest.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.APIAddress), "application/json", req)
s.Require().NoError(err)
if tc.expErr {
s.Require().Contains(string(res), tc.expErrMsg)
} else {
var result tx.BroadcastTxResponse
err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().Equal(uint32(0), result.TxResponse.Code)
}
})
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder {
val := s.network.Validators[0]
s.Require().NoError(s.network.WaitForNextBlock())
// prepare txBuilder with msg
txBuilder := val.ClientCtx.TxConfig.NewTxBuilder()
@ -71,7 +439,6 @@ func (s IntegrationTestSuite) TestSimulate() {
)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo("foobar")
// setup txFactory
txFactory := clienttx.Factory{}.
@ -84,115 +451,7 @@ func (s IntegrationTestSuite) TestSimulate() {
err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false)
s.Require().NoError(err)
// Convert the txBuilder to a tx.Tx.
protoTx, err := txBuilderToProtoTx(txBuilder)
s.Require().NoError(err)
// Run the simulate gRPC query.
res, err := s.queryClient.Simulate(
context.Background(),
&tx.SimulateRequest{Tx: protoTx},
)
s.Require().NoError(err)
// Check the result and gas used are correct.
s.Require().Equal(len(res.GetResult().GetEvents()), 4) // 1 transfer, 3 messages.
s.Require().True(res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty.
}
func (s IntegrationTestSuite) TestGetTxEvents() {
val := s.network.Validators[0]
// Create a new MsgSend tx from val to itself.
out, err := bankcli.MsgSendExec(
val.ClientCtx,
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
)
s.Require().NoError(err)
var txRes sdk.TxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
// Query the tx via gRPC.
grpcRes, err := s.queryClient.GetTxsEvent(
context.Background(),
&tx.GetTxsEventRequest{Event: "message.action=send",
Pagination: &query.PageRequest{
CountTotal: false,
Offset: 0,
Limit: 1,
},
},
)
s.Require().NoError(err)
s.Require().Equal(len(grpcRes.Txs), 1)
s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo)
// Query the tx via grpc-gateway.
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?event=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action=send", 0, 1))
s.Require().NoError(err)
var getTxRes tx.GetTxsEventResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getTxRes))
s.Require().Equal(len(grpcRes.Txs), 1)
s.Require().Equal("foobar", getTxRes.Txs[0].Body.Memo)
s.Require().NotZero(grpcRes.TxResponses[0].Height)
}
func (s IntegrationTestSuite) TestGetTx() {
val := s.network.Validators[0]
// Create a new MsgSend tx from val to itself.
out, err := bankcli.MsgSendExec(
val.ClientCtx,
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
)
s.Require().NoError(err)
var txRes sdk.TxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(uint32(0), txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
// Query the tx via gRPC.
grpcRes, err := s.queryClient.GetTx(
context.Background(),
&tx.GetTxRequest{Hash: txRes.TxHash},
)
s.Require().NoError(err)
s.Require().Equal("foobar", grpcRes.Tx.Body.Memo)
s.Require().NotZero(grpcRes.TxResponse.Height)
// Query the tx via grpc-gateway.
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/tx/%s", val.APIAddress, txRes.TxHash))
s.Require().NoError(err)
var getTxRes tx.GetTxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getTxRes))
s.Require().Equal("foobar", grpcRes.Tx.Body.Memo)
s.Require().NotZero(grpcRes.TxResponse.Height)
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
return txBuilder
}
// txBuilderToProtoTx converts a txBuilder into a proto tx.Tx.

View File

@ -1,9 +1,10 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/client/rest"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/client"
)

View File

@ -8,7 +8,7 @@ import (
)
// InitGenesis initializes the bank module's state from a given genesis state.
func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {
func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
k.SetParams(ctx, genState.Params)
var totalSupply sdk.Coins
@ -32,6 +32,10 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {
}
k.SetSupply(ctx, types.NewSupply(genState.Supply))
for _, meta := range genState.DenomMetadata {
k.SetDenomMetaData(ctx, meta)
}
}
// ExportGenesis returns the bank module's genesis state.

View File

@ -37,8 +37,20 @@ func (suite *IntegrationTestSuite) getTestBalances() []types.Balance {
addr2, _ := sdk.AccAddressFromBech32("cosmos1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0556gh0")
addr1, _ := sdk.AccAddressFromBech32("cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh")
return []types.Balance{
{addr2.String(), sdk.Coins{sdk.NewInt64Coin("testcoin1", 32), sdk.NewInt64Coin("testcoin2", 34)}},
{addr1.String(), sdk.Coins{sdk.NewInt64Coin("testcoin3", 10)}},
{Address: addr2.String(), Coins: sdk.Coins{sdk.NewInt64Coin("testcoin1", 32), sdk.NewInt64Coin("testcoin2", 34)}},
{Address: addr1.String(), Coins: sdk.Coins{sdk.NewInt64Coin("testcoin3", 10)}},
}
}
func (suite *IntegrationTestSuite) TestInitGenesis() {
require := suite.Require()
m := types.Metadata{Description: sdk.DefaultBondDenom, Base: sdk.DefaultBondDenom, Display: sdk.DefaultBondDenom}
g := types.DefaultGenesisState()
g.DenomMetadata = []types.Metadata{m}
bk := suite.app.BankKeeper
bk.InitGenesis(suite.ctx, g)
m2 := bk.GetDenomMetaData(suite.ctx, m.Base)
require.Equal(m, m2)
}

View File

@ -31,7 +31,7 @@ func (k BaseKeeper) Balance(ctx context.Context, req *types.QueryBalanceRequest)
sdkCtx := sdk.UnwrapSDKContext(ctx)
address, err := sdk.AccAddressFromBech32(req.Address)
if err != nil {
return nil, err
return nil, status.Errorf(codes.InvalidArgument, "invalid address: %s", err.Error())
}
balance := k.GetBalance(sdkCtx, address, req.Denom)
@ -45,9 +45,13 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if req.Address == "" {
return nil, status.Error(codes.InvalidArgument, "address cannot be empty")
}
addr, err := sdk.AccAddressFromBech32(req.Address)
if err != nil {
return nil, err
return nil, status.Errorf(codes.InvalidArgument, "invalid address: %s", err.Error())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
@ -68,7 +72,7 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances
})
if err != nil {
return &types.QueryAllBalancesResponse{}, err
return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err)
}
return &types.QueryAllBalancesResponse{Balances: balances, Pagination: pageRes}, nil

View File

@ -1,7 +1,6 @@
package keeper
import (
"fmt"
"time"
"github.com/cosmos/cosmos-sdk/codec"
@ -22,7 +21,7 @@ var _ Keeper = (*BaseKeeper)(nil)
type Keeper interface {
SendKeeper
InitGenesis(sdk.Context, types.GenesisState)
InitGenesis(sdk.Context, *types.GenesisState)
ExportGenesis(sdk.Context) *types.GenesisState
GetSupply(ctx sdk.Context) exported.SupplyI
@ -186,7 +185,6 @@ func (k BaseKeeper) GetDenomMetaData(ctx sdk.Context, denom string) types.Metada
store = prefix.NewStore(store, types.DenomMetadataKey(denom))
bz := store.Get([]byte(denom))
var metadata types.Metadata
k.cdc.MustUnmarshalBinaryBare(bz, &metadata)
@ -342,7 +340,7 @@ func (k BaseKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins)
k.SetSupply(ctx, supply)
logger := k.Logger(ctx)
logger.Info(fmt.Sprintf("minted %s from %s module account", amt.String(), moduleName))
logger.Info("minted coins from module account", "amount", amt.String(), "from", moduleName)
return nil
}
@ -370,7 +368,7 @@ func (k BaseKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins)
k.SetSupply(ctx, supply)
logger := k.Logger(ctx)
logger.Info(fmt.Sprintf("burned %s from %s module account", amt.String(), moduleName))
logger.Info("burned tokens from module account", "amount", amt.String(), "from", moduleName)
return nil
}

View File

@ -49,7 +49,7 @@ func NewBaseViewKeeper(cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, ak type
// Logger returns a module-specific logger.
func (k BaseViewKeeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// HasBalance returns whether or not an account has at least amt balance.

View File

@ -52,7 +52,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage {
}
// ValidateGenesis performs genesis state validation for the bank module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error {
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, _ client.TxEncodingConfig, bz json.RawMessage) error {
var data types.GenesisState
if err := cdc.UnmarshalJSON(bz, &data); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
@ -140,7 +140,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j
cdc.MustUnmarshalJSON(data, &genesisState)
telemetry.MeasureSince(start, "InitGenesis", "crisis", "unmarshal")
am.keeper.InitGenesis(ctx, genesisState)
am.keeper.InitGenesis(ctx, &genesisState)
return []abci.ValidatorUpdate{}
}
@ -170,7 +170,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent {
return nil
}

View File

@ -44,7 +44,7 @@ func NewKeeper(
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// RegisterRoute register the routes for each of the invariants
@ -76,7 +76,7 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) {
invarRoutes := k.Routes()
n := len(invarRoutes)
for i, ir := range invarRoutes {
logger.Debug("Asserting cirisis invariants", "inv", fmt.Sprint(i, "/", n))
logger.Info("asserting crisis invariants", "inv", fmt.Sprint(i, "/", n))
if res, stop := ir.Invar(ctx); stop {
// TODO: Include app name as part of context to allow for this to be
// variable.

View File

@ -152,9 +152,13 @@ func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val stakingtypes.Vali
rewards := rewardsRaw.Intersect(outstanding)
if !rewards.IsEqual(rewardsRaw) {
logger := k.Logger(ctx)
logger.Info(fmt.Sprintf("missing rewards rounding error, delegator %v"+
"withdrawing rewards from validator %v, should have received %v, got %v",
val.GetOperator(), del.GetDelegatorAddr(), rewardsRaw, rewards))
logger.Info(
"rounding error withdrawing rewards from validator",
"delegator", del.GetDelegatorAddr().String(),
"validator", val.GetOperator().String(),
"got", rewards.String(),
"expected", rewardsRaw.String(),
)
}
// truncate coins, return remainder to community pool

View File

@ -57,7 +57,7 @@ func NewKeeper(
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// SetWithdrawAddr sets a new address that will receive the rewards upon withdrawal

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/distribution/types"

View File

@ -1,8 +1,6 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
@ -13,16 +11,19 @@ func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p *types.Commun
if k.blockedAddrs[p.Recipient] {
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive external funds", p.Recipient)
}
recipient, addrErr := sdk.AccAddressFromBech32(p.Recipient)
if addrErr != nil {
return addrErr
}
err := k.DistributeFromFeePool(ctx, p.Amount, recipient)
if err != nil {
return err
}
logger := k.Logger(ctx)
logger.Info(fmt.Sprintf("transferred %s from the community pool to recipient %s", p.Amount, p.Recipient))
logger.Info("transferred from the community pool to recipient", "amount", p.Amount.String(), "recipient", p.Recipient)
return nil
}

View File

@ -0,0 +1,80 @@
package cli_test
import (
"strings"
"testing"
"github.com/stretchr/testify/suite"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
testnet "github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/x/evidence/client/cli"
)
type IntegrationTestSuite struct {
suite.Suite
cfg testnet.Config
network *testnet.Network
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
cfg := testnet.DefaultConfig()
cfg.NumValidators = 1
s.cfg = cfg
s.network = testnet.New(s.T(), cfg)
_, err := s.network.WaitForHeight(1)
s.Require().NoError(err)
}
func (s *IntegrationTestSuite) TearDownSuite() {
s.T().Log("tearing down integration test suite")
s.network.Cleanup()
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
func (s *IntegrationTestSuite) TestGetQueryCmd() {
val := s.network.Validators[0]
testCases := map[string]struct {
args []string
expectedOutput string
expectErr bool
}{
"non-existent evidence": {
[]string{"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"},
"evidence DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660 not found",
true,
},
"all evidence (default pagination)": {
[]string{},
"evidence: []\npagination:\n next_key: null\n total: \"0\"",
false,
},
}
for name, tc := range testCases {
tc := tc
s.Run(name, func() {
cmd := cli.GetQueryCmd()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
s.Require().Contains(strings.TrimSpace(out.String()), tc.expectedOutput)
})
}
}

View File

@ -47,18 +47,14 @@ $ %s query %s --page=2 --limit=50
// can be queried for by hash or paginated evidence can be returned.
func QueryEvidenceCmd() func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
if err := client.ValidateCmd(cmd, args); err != nil {
return err
}
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
if hash := args[0]; hash != "" {
return queryEvidence(clientCtx, hash)
if len(args) > 0 {
return queryEvidence(clientCtx, args[0])
}
pageReq, err := client.ReadPageRequest(cmd.Flags())

View File

@ -40,7 +40,7 @@ func NewKeeper(
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// SetRouter sets the Evidence Handler router for the x/evidence module. Note,

View File

@ -30,13 +30,13 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
)
logger.Info(
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
proposal.ProposalId,
proposal.GetTitle(),
keeper.GetDepositParams(ctx).MinDeposit,
proposal.TotalDeposit,
),
"proposal did not meet minimum deposit; deleted",
"proposal", proposal.ProposalId,
"title", proposal.GetTitle(),
"min_deposit", keeper.GetDepositParams(ctx).MinDeposit.String(),
"total_deposit", proposal.TotalDeposit.String(),
)
return false
})
@ -90,10 +90,10 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)
logger.Info(
fmt.Sprintf(
"proposal %d (%s) tallied; result: %s",
proposal.ProposalId, proposal.GetTitle(), logMsg,
),
"proposal tallied",
"proposal", proposal.ProposalId,
"title", proposal.GetTitle(),
"result", logMsg,
)
ctx.EventManager().EmitEvent(

View File

@ -162,7 +162,7 @@ func (s *IntegrationTestSuite) TestGetProposalsGRPC() {
func (s *IntegrationTestSuite) TestGetProposalVoteGRPC() {
val := s.network.Validators[0]
voterAddressBase64 := val.Address.String()
voterAddressBech32 := val.Address.String()
testCases := []struct {
name string
@ -172,13 +172,13 @@ func (s *IntegrationTestSuite) TestGetProposalVoteGRPC() {
}{
{
"empty proposal",
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "", voterAddressBase64),
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "", voterAddressBech32),
true,
types.NewNonSplitVoteOption(types.OptionYes),
},
{
"get non existing proposal",
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "10", voterAddressBase64),
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "10", voterAddressBech32),
true,
types.NewNonSplitVoteOption(types.OptionYes),
},
@ -190,7 +190,7 @@ func (s *IntegrationTestSuite) TestGetProposalVoteGRPC() {
},
{
"get proposal with id",
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "1", voterAddressBase64),
fmt.Sprintf("%s/cosmos/gov/v1beta1/proposals/%s/votes/%s", val.APIAddress, "1", voterAddressBech32),
false,
types.NewNonSplitVoteOption(types.OptionYes),
},

View File

@ -0,0 +1,110 @@
// +build norace
package rest_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
func (s *IntegrationTestSuite) TestLegacyGetVote() {
val := s.network.Validators[0]
voterAddressBech32 := val.Address.String()
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{
"get non existing proposal",
fmt.Sprintf("%s/gov/proposals/%s/votes/%s", val.APIAddress, "10", voterAddressBech32),
true, "proposalID 10 does not exist",
},
{
"get proposal with wrong voter address",
fmt.Sprintf("%s/gov/proposals/%s/votes/%s", val.APIAddress, "1", "wrongVoterAddress"),
true, "decoding bech32 failed: string not all lowercase or all uppercase",
},
{
"get proposal with id",
fmt.Sprintf("%s/gov/proposals/%s/votes/%s", val.APIAddress, "1", voterAddressBech32),
false, "",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
respJSON, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
if tc.expErr {
var errResp rest.ErrorResponse
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(respJSON, &errResp))
s.Require().Equal(errResp.Error, tc.expErrMsg)
} else {
var resp = rest.ResponseWithHeight{}
err = val.ClientCtx.LegacyAmino.UnmarshalJSON(respJSON, &resp)
s.Require().NoError(err)
// Check result is not empty.
var vote types.Vote
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(resp.Result, &vote))
s.Require().Equal(val.Address.String(), vote.Voter)
// Note that option is now an int.
s.Require().Equal(types.VoteOption(1), vote.Option)
}
})
}
}
func (s *IntegrationTestSuite) TestLegacyGetVotes() {
val := s.network.Validators[0]
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{
"votes with empty proposal id",
fmt.Sprintf("%s/gov/proposals/%s/votes", val.APIAddress, ""),
true, "'votes' is not a valid uint64",
},
{
"get votes with valid id",
fmt.Sprintf("%s/gov/proposals/%s/votes", val.APIAddress, "1"),
false, "",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
respJSON, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
if tc.expErr {
var errResp rest.ErrorResponse
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(respJSON, &errResp))
s.Require().Equal(errResp.Error, tc.expErrMsg)
} else {
var resp = rest.ResponseWithHeight{}
err = val.ClientCtx.LegacyAmino.UnmarshalJSON(respJSON, &resp)
s.Require().NoError(err)
// Check result is not empty.
var votes []types.Vote
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(resp.Result, &votes))
s.Require().Greater(len(votes), 0)
}
})
}
}

View File

@ -3,13 +3,14 @@ package keeper_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
)
var (

View File

@ -68,7 +68,7 @@ func NewKeeper(
// Logger returns a module-specific logger.
func (keeper Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// Router returns the gov Keeper's Router

View File

@ -6,6 +6,7 @@ import (
"strconv"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"

View File

@ -1,8 +1,6 @@
package keeper
import (
"fmt"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
@ -63,7 +61,7 @@ func NewKeeper(
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName))
return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName)
}
// GetTransferAccount returns the ICS20 - transfers ModuleAccount

View File

@ -7,7 +7,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/09-localhost/types"
)
// InitGenesis initializes the ibc client submodule's state from a provided genesis
@ -15,6 +14,12 @@ import (
func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) {
k.SetParams(ctx, gs.Params)
// Set all client metadata first. This will allow client keeper to overwrite client and consensus state keys
// if clients accidentally write to ClientKeeper reserved keys.
if len(gs.ClientsMetadata) != 0 {
k.SetAllClientMetadata(ctx, gs.ClientsMetadata)
}
for _, client := range gs.Clients {
cs, ok := client.ClientState.GetCachedValue().(exported.ClientState)
if !ok {
@ -39,37 +44,24 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) {
}
}
if !gs.CreateLocalhost {
return
}
k.SetNextClientSequence(ctx, gs.NextClientSequence)
// NOTE: return if the localhost client was already imported. The chain-id and
// block height will be overwriten to the correct values during BeginBlock.
if _, found := k.GetClientState(ctx, exported.Localhost); found {
return
}
// client id is always "localhost"
revision := types.ParseChainID(ctx.ChainID())
clientState := localhosttypes.NewClientState(
ctx.ChainID(), types.NewHeight(revision, uint64(ctx.BlockHeight())),
)
if err := clientState.Validate(); err != nil {
panic(err)
}
if err := k.CreateClient(ctx, exported.Localhost, clientState, nil); err != nil {
panic(err)
}
// NOTE: localhost creation is specifically disallowed for the time being.
// Issue: https://github.com/cosmos/cosmos-sdk/issues/7871
}
// ExportGenesis returns the ibc client submodule's exported genesis.
// NOTE: CreateLocalhost should always be false on export since a
// created localhost will be included in the exported clients.
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState {
genClients := k.GetAllGenesisClients(ctx)
clientsMetadata, err := k.GetAllClientMetadata(ctx, genClients)
if err != nil {
panic(err)
}
return types.GenesisState{
Clients: k.GetAllGenesisClients(ctx),
Clients: genClients,
ClientsMetadata: clientsMetadata,
ClientsConsensus: k.GetAllConsensusStates(ctx),
Params: k.GetParams(ctx),
CreateLocalhost: false,

View File

@ -12,22 +12,26 @@ import (
// CreateClient creates a new client state and populates it with a given consensus
// state as defined in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
//
// CONTRACT: ClientState was constructed correctly from given initial consensusState
func (k Keeper) CreateClient(
ctx sdk.Context, clientID string, clientState exported.ClientState, consensusState exported.ConsensusState,
) error {
ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState,
) (string, error) {
params := k.GetParams(ctx)
if !params.IsAllowedClient(clientState.ClientType()) {
return sdkerrors.Wrapf(
return "", sdkerrors.Wrapf(
types.ErrInvalidClientType,
"client state type %s is not registered in the allowlist", clientState.ClientType(),
)
}
_, found := k.GetClientState(ctx, clientID)
if found {
return sdkerrors.Wrapf(types.ErrClientExists, "cannot create client with ID %s", clientID)
clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType())
k.SetClientState(ctx, clientID, clientState)
k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String())
// verifies initial consensus state against client state and initializes client store with any client-specific metadata
// e.g. set ProcessedTime in Tendermint clients
if err := clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, clientID), consensusState); err != nil {
return "", err
}
// check if consensus state is nil in case the created client is Localhost
@ -35,7 +39,6 @@ func (k Keeper) CreateClient(
k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState)
}
k.SetClientState(ctx, clientID, clientState)
k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String())
defer func() {
@ -46,7 +49,7 @@ func (k Keeper) CreateClient(
)
}()
return nil
return clientID, nil
}
// UpdateClient updates the consensus state and the state root from a provided header.

View File

@ -19,36 +19,23 @@ import (
func (suite *KeeperTestSuite) TestCreateClient() {
cases := []struct {
msg string
clientID string
expPass bool
expPanic bool
msg string
clientState exported.ClientState
expPass bool
}{
{"success", testClientID, true, false},
{"client ID exists", testClientID, false, false},
{"success", ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true},
{"client type not supported", localhosttypes.NewClientState(testChainID, clienttypes.NewHeight(0, 1)), false},
}
for i, tc := range cases {
tc := tc
i := i
if tc.expPanic {
suite.Require().Panics(func() {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
suite.keeper.CreateClient(suite.ctx, tc.clientID, clientState, suite.consensusState)
}, "Msg %d didn't panic: %s", i, tc.msg)
} else {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
if tc.expPass {
suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg)
}
// If we were able to NewClientState clientstate successfully, try persisting it to state
err := suite.keeper.CreateClient(suite.ctx, tc.clientID, clientState, suite.consensusState)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
}
clientID, err := suite.keeper.CreateClient(suite.ctx, tc.clientState, suite.consensusState)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
suite.Require().NotNil(clientID, "valid test case %d failed: %s", i, tc.msg)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
suite.Require().Equal("", clientID, "invalid test case %d passed: %s", i, tc.msg)
}
}
}
@ -72,6 +59,8 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
var (
updateHeader *ibctmtypes.Header
clientState *ibctmtypes.ClientState
clientID string
err error
)
cases := []struct {
@ -81,7 +70,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
}{
{"valid update", func() error {
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
incrementedClientHeight := testClientHeight.Increment()
@ -89,17 +78,17 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, incrementedClientHeight, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, incrementedClientHeight, intermediateConsState)
clientState.LatestHeight = incrementedClientHeight
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
suite.keeper.SetClientState(suite.ctx, clientID, clientState)
updateHeader = createFutureUpdateFn(suite)
return err
}, true},
{"valid past update", func() error {
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
suite.Require().NoError(err)
height1 := types.NewHeight(0, 1)
@ -109,7 +98,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
Timestamp: suite.past,
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height1, prevConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, height1, prevConsState)
height2 := types.NewHeight(0, 2)
@ -118,7 +107,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
Timestamp: suite.past.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height2, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, height2, intermediateConsState)
// updateHeader will fill in consensus state between prevConsState and suite.consState
// clientState should not be updated
@ -147,7 +136,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
{"valid past update before client was frozen", func() error {
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
clientState.FrozenHeight = types.NewHeight(0, testClientHeight.RevisionHeight-1)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
suite.Require().NoError(err)
height1 := types.NewHeight(0, 1)
@ -157,7 +146,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
Timestamp: suite.past,
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height1, prevConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, height1, prevConsState)
// updateHeader will fill in consensus state between prevConsState and suite.consState
// clientState should not be updated
@ -166,7 +155,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
}, true},
{"invalid header", func() error {
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
_, err := suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
suite.Require().NoError(err)
updateHeader = createPastUpdateFn(suite)
@ -179,13 +168,14 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
i := i
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
clientID = testClientID // must be explicitly changed
err := tc.malleate()
suite.Require().NoError(err)
suite.ctx = suite.ctx.WithBlockTime(updateHeader.Header.Time.Add(time.Minute))
err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader)
err = suite.keeper.UpdateClient(suite.ctx, clientID, updateHeader)
if tc.expPass {
suite.Require().NoError(err, err)
@ -196,10 +186,10 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
NextValidatorsHash: updateHeader.Header.NextValidatorsHash,
}
newClientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
newClientState, found := suite.keeper.GetClientState(suite.ctx, clientID)
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, updateHeader.GetHeight())
consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, clientID, updateHeader.GetHeight())
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
// Determine if clientState should be updated or not
@ -399,6 +389,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {
}
func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
var (
clientID string
err error
)
altPrivVal := ibctestingmock.NewPV()
altPubKey, err := altPrivVal.GetPubKey()
suite.Require().NoError(err)
@ -437,12 +432,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = bothValsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
return err
},
@ -453,22 +448,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = valsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
intermediateConsState := &ibctmtypes.ConsensusState{
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, heightPlus3, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState)
clientState.LatestHeight = heightPlus3
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
suite.keeper.SetClientState(suite.ctx, clientID, clientState)
return err
},
@ -479,22 +474,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = valsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
// store trusted consensus state for Header2
intermediateConsState := &ibctmtypes.ConsensusState{
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: bothValsHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, heightPlus3, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState)
clientState.LatestHeight = heightPlus3
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
suite.keeper.SetClientState(suite.ctx, clientID, clientState)
return err
},
@ -505,12 +500,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, altTime, bothValSet, bothValSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = valsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
// intermediate consensus state at height + 3 is not created
return err
},
@ -521,12 +516,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = valsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
// intermediate consensus state at height + 3 is not created
return err
},
@ -543,15 +538,15 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
suite.consensusState.NextValidatorsHash = bothValsHash
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
clientState.FrozenHeight = types.NewHeight(0, 1)
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
suite.keeper.SetClientState(suite.ctx, clientID, clientState)
return err
},
@ -562,14 +557,14 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
&ibctmtypes.Misbehaviour{
Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
ClientId: testClientID,
ClientId: clientID,
},
func() error {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
if err != nil {
return err
}
err = suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
return err
},
@ -580,18 +575,22 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
for i, tc := range testCases {
tc := tc
i := i
suite.Run(tc.name, func() {
suite.SetupTest() // reset
suite.SetupTest() // reset
clientID = testClientID // must be explicitly changed
err := tc.malleate()
suite.Require().NoError(err)
tc.misbehaviour.ClientId = clientID
err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.misbehaviour)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
clientState, found := suite.keeper.GetClientState(suite.ctx, clientID)
suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
suite.Require().True(clientState.IsFrozen(), "valid test case %d failed: %s", i, tc.name)
suite.Require().Equal(tc.misbehaviour.GetHeight(), clientState.GetFrozenHeight(),

View File

@ -43,7 +43,7 @@ func (suite *KeeperTestSuite) TestQueryClientState() {
{
"success",
func() {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
var err error
@ -183,10 +183,10 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() {
"invalid height",
func() {
req = &types.QueryConsensusStateRequest{
ClientId: testClientID,
ClientId: testClientID,
RevisionNumber: 0,
RevisionHeight: 0,
LatestHeight: false,
LatestHeight: false,
}
},
false,
@ -204,7 +204,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() {
{
"success latest height",
func() {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
cs := ibctmtypes.NewConsensusState(
suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash1")), nil,
)
@ -235,7 +235,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() {
suite.Require().NoError(err)
req = &types.QueryConsensusStateRequest{
ClientId: testClientID,
ClientId: testClientID,
RevisionNumber: 0,
RevisionHeight: height,
}

View File

@ -47,7 +47,17 @@ func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace paramtype
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", host.ModuleName, types.SubModuleName))
return ctx.Logger().With("module", "x/"+host.ModuleName+"/"+types.SubModuleName)
}
// GenerateClientIdentifier returns the next client identifier.
func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) string {
nextClientSeq := k.GetNextClientSequence(ctx)
clientID := types.FormatClientIdentifier(clientType, nextClientSeq)
nextClientSeq++
k.SetNextClientSequence(ctx, nextClientSeq)
return clientID
}
// GetClientState gets a particular client from the store
@ -87,6 +97,24 @@ func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height
store.Set(host.ConsensusStateKey(height), k.MustMarshalConsensusState(consensusState))
}
// GetNextClientSequence gets the next client sequence from the store.
func (k Keeper) GetNextClientSequence(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get([]byte(types.KeyNextClientSequence))
if bz == nil {
panic("next client sequence is nil")
}
return sdk.BigEndianToUint64(bz)
}
// SetNextClientSequence sets the next client sequence to the store.
func (k Keeper) SetNextClientSequence(ctx sdk.Context, sequence uint64) {
store := ctx.KVStore(k.storeKey)
bz := sdk.Uint64ToBigEndian(sequence)
store.Set([]byte(types.KeyNextClientSequence), bz)
}
// IterateConsensusStates provides an iterator over all stored consensus states.
// objects. For each State object, cb will be called. If the cb returns true,
// the iterator will close and stop.
@ -124,6 +152,49 @@ func (k Keeper) GetAllGenesisClients(ctx sdk.Context) types.IdentifiedClientStat
return genClients.Sort()
}
// GetAllClientMetadata will take a list of IdentifiedClientState and return a list
// of IdentifiedGenesisMetadata necessary for exporting and importing client metadata
// into the client store.
func (k Keeper) GetAllClientMetadata(ctx sdk.Context, genClients []types.IdentifiedClientState) ([]types.IdentifiedGenesisMetadata, error) {
genMetadata := make([]types.IdentifiedGenesisMetadata, 0)
for _, ic := range genClients {
cs, err := types.UnpackClientState(ic.ClientState)
if err != nil {
return nil, err
}
gms := cs.ExportMetadata(k.ClientStore(ctx, ic.ClientId))
if len(gms) == 0 {
continue
}
clientMetadata := make([]types.GenesisMetadata, len(gms))
for i, metadata := range gms {
cmd, ok := metadata.(types.GenesisMetadata)
if !ok {
return nil, sdkerrors.Wrapf(types.ErrInvalidClientMetadata, "expected metadata type: %T, got: %T",
types.GenesisMetadata{}, cmd)
}
clientMetadata[i] = cmd
}
genMetadata = append(genMetadata, types.NewIdentifiedGenesisMetadata(
ic.ClientId,
clientMetadata,
))
}
return genMetadata, nil
}
// SetAllClientMetadata takes a list of IdentifiedGenesisMetadata and stores all of the metadata in the client store at the appropriate paths.
func (k Keeper) SetAllClientMetadata(ctx sdk.Context, genMetadata []types.IdentifiedGenesisMetadata) {
for _, igm := range genMetadata {
// create client store
store := k.ClientStore(ctx, igm.ClientId)
// set all metadata kv pairs in client store
for _, md := range igm.ClientMetadata {
store.Set(md.GetKey(), md.GetValue())
}
}
}
// GetAllConsensusStates returns all stored client consensus states.
func (k Keeper) GetAllConsensusStates(ctx sdk.Context) types.ClientsConsensusStates {
clientConsStates := make(types.ClientsConsensusStates, 0)

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