Merge branch 'master' into sunny/change-pubkey-adr
This commit is contained in:
commit
a77eb251f1
48
Makefile
48
Makefile
|
@ -10,7 +10,8 @@ BUILDDIR ?= $(CURDIR)/build
|
|||
SIMAPP = ./simapp
|
||||
MOCKS_DIR = $(CURDIR)/tests/mocks
|
||||
HTTPS_GIT := https://github.com/cosmos/cosmos-sdk.git
|
||||
DOCKER_BUF := docker run -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
|
||||
DOCKER := $(shell which docker)
|
||||
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
|
||||
|
||||
export GO111MODULE = on
|
||||
|
||||
|
@ -112,26 +113,26 @@ $(BUILDDIR)/:
|
|||
mkdir -p $(BUILDDIR)/
|
||||
|
||||
build-simd-all: go.sum
|
||||
docker rm latest-build || true
|
||||
docker run --volume=$(CURDIR):/sources:ro \
|
||||
$(DOCKER) rm latest-build || true
|
||||
$(DOCKER) run --volume=$(CURDIR):/sources:ro \
|
||||
--env TARGET_PLATFORMS='linux/amd64 darwin/amd64 linux/arm64 windows/amd64' \
|
||||
--env APP=simd \
|
||||
--env VERSION=$(VERSION) \
|
||||
--env COMMIT=$(COMMIT) \
|
||||
--env LEDGER_ENABLED=$(LEDGER_ENABLED) \
|
||||
--name latest-build cosmossdk/rbuilder:latest
|
||||
docker cp -a latest-build:/home/builder/artifacts/ $(CURDIR)/
|
||||
$(DOCKER) cp -a latest-build:/home/builder/artifacts/ $(CURDIR)/
|
||||
|
||||
build-simd-linux: go.sum $(BUILDDIR)/
|
||||
docker rm latest-build || true
|
||||
docker run --volume=$(CURDIR):/sources:ro \
|
||||
$(DOCKER) rm latest-build || true
|
||||
$(DOCKER) run --volume=$(CURDIR):/sources:ro \
|
||||
--env TARGET_PLATFORMS='linux/amd64' \
|
||||
--env APP=simd \
|
||||
--env VERSION=$(VERSION) \
|
||||
--env COMMIT=$(COMMIT) \
|
||||
--env LEDGER_ENABLED=false \
|
||||
--name latest-build cosmossdk/rbuilder:latest
|
||||
docker cp -a latest-build:/home/builder/artifacts/ $(CURDIR)/
|
||||
$(DOCKER) cp -a latest-build:/home/builder/artifacts/ $(CURDIR)/
|
||||
cp artifacts/simd-*-linux-amd64 $(BUILDDIR)/simd
|
||||
|
||||
cosmovisor:
|
||||
|
@ -333,12 +334,12 @@ format:
|
|||
DEVDOC_SAVE = docker commit `docker ps -a -n 1 -q` devdoc:local
|
||||
|
||||
devdoc-init:
|
||||
docker run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" tendermint/devdoc echo
|
||||
$(DOCKER) run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" tendermint/devdoc echo
|
||||
# TODO make this safer
|
||||
$(call DEVDOC_SAVE)
|
||||
|
||||
devdoc:
|
||||
docker run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" devdoc:local bash
|
||||
$(DOCKER) run -it -v "$(CURDIR):/go/src/github.com/cosmos/cosmos-sdk" -w "/go/src/github.com/cosmos/cosmos-sdk" devdoc:local bash
|
||||
|
||||
devdoc-save:
|
||||
# TODO make this safer
|
||||
|
@ -360,17 +361,17 @@ proto-all: proto-format proto-lint proto-check-breaking proto-gen
|
|||
|
||||
proto-gen:
|
||||
@echo "Generating Protobuf files"
|
||||
docker run -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen.sh
|
||||
$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen.sh
|
||||
|
||||
proto-format:
|
||||
@echo "Formatting Protobuf files"
|
||||
docker run -v $(CURDIR):/workspace \
|
||||
$(DOCKER) run --rm -v $(CURDIR):/workspace \
|
||||
--workdir /workspace tendermintdev/docker-build-proto \
|
||||
find ./ -not -path "./third_party/*" -name *.proto -exec clang-format -i {} \;
|
||||
|
||||
# This generates the SDK's custom wrapper for google.protobuf.Any. It should only be run manually when needed
|
||||
proto-gen-any:
|
||||
docker run -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen-any.sh
|
||||
$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen-any.sh
|
||||
|
||||
proto-swagger-gen:
|
||||
@./scripts/protoc-swagger-gen.sh
|
||||
|
@ -381,16 +382,17 @@ proto-lint:
|
|||
proto-check-breaking:
|
||||
@$(DOCKER_BUF) check breaking --against-input $(HTTPS_GIT)#branch=master
|
||||
|
||||
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.0-rc6/proto/tendermint
|
||||
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
|
||||
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
|
||||
CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.6.3
|
||||
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.0-rc6/proto/tendermint
|
||||
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
|
||||
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
|
||||
CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.6.3
|
||||
|
||||
TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto
|
||||
TM_ABCI_TYPES = third_party/proto/tendermint/abci
|
||||
TM_TYPES = third_party/proto/tendermint/types
|
||||
TM_VERSION = third_party/proto/tendermint/version
|
||||
TM_LIBS = third_party/proto/tendermint/libs/bits
|
||||
TM_TYPES = third_party/proto/tendermint/types
|
||||
TM_VERSION = third_party/proto/tendermint/version
|
||||
TM_LIBS = third_party/proto/tendermint/libs/bits
|
||||
TM_P2P = third_party/proto/tendermint/p2p
|
||||
|
||||
GOGO_PROTO_TYPES = third_party/proto/gogoproto
|
||||
COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto
|
||||
|
@ -418,6 +420,7 @@ proto-update-deps:
|
|||
@curl -sSL $(TM_URL)/types/evidence.proto > $(TM_TYPES)/evidence.proto
|
||||
@curl -sSL $(TM_URL)/types/params.proto > $(TM_TYPES)/params.proto
|
||||
@curl -sSL $(TM_URL)/types/validator.proto > $(TM_TYPES)/validator.proto
|
||||
@curl -sSL $(TM_URL)/types/block.proto > $(TM_TYPES)/block.proto
|
||||
|
||||
@mkdir -p $(TM_CRYPTO_TYPES)
|
||||
@curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto
|
||||
|
@ -426,6 +429,9 @@ proto-update-deps:
|
|||
@mkdir -p $(TM_LIBS)
|
||||
@curl -sSL $(TM_URL)/libs/bits/types.proto > $(TM_LIBS)/types.proto
|
||||
|
||||
@mkdir -p $(TM_P2P)
|
||||
@curl -sSL $(TM_URL)/p2p/types.proto > $(TM_P2P)/types.proto
|
||||
|
||||
@mkdir -p $(CONFIO_TYPES)
|
||||
@curl -sSL $(CONFIO_URL)/proofs.proto > $(CONFIO_TYPES)/proofs.proto
|
||||
## insert go package option into proofs.proto file
|
||||
|
@ -440,8 +446,8 @@ proto-update-deps:
|
|||
|
||||
# Run a 4-node testnet locally
|
||||
localnet-start: build-linux localnet-stop
|
||||
$(if $(shell docker inspect -f '{{ .Id }}' cosmossdk/simd-env 2>/dev/null),$(info found image cosmossdk/simd-env),$(MAKE) -C contrib/images simd-env)
|
||||
if ! [ -f build/node0/simd/config/genesis.json ]; then docker run --rm \
|
||||
$(if $(shell $(DOCKER) inspect -f '{{ .Id }}' cosmossdk/simd-env 2>/dev/null),$(info found image cosmossdk/simd-env),$(MAKE) -C contrib/images simd-env)
|
||||
if ! [ -f build/node0/simd/config/genesis.json ]; then $(DOCKER) run --rm \
|
||||
--user $(shell id -u):$(shell id -g) \
|
||||
-v $(BUILDDIR):/simd:Z \
|
||||
-v /etc/group:/etc/group:ro \
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package tmservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
|
||||
func getBlock(clientCtx client.Context, height *int64) (*ctypes.ResultBlock, error) {
|
||||
// get the node
|
||||
node, err := clientCtx.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return node.Block(context.Background(), height)
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
package tmservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
gogogrpc "github.com/gogo/protobuf/grpc"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
qtypes "github.com/cosmos/cosmos-sdk/types/query"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
// This is the struct that we will implement all the handlers on.
|
||||
type queryServer struct {
|
||||
clientCtx client.Context
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
}
|
||||
|
||||
var _ qtypes.ServiceServer = queryServer{}
|
||||
|
||||
// NewQueryServer creates a new tendermint query server.
|
||||
func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) qtypes.ServiceServer {
|
||||
return queryServer{
|
||||
clientCtx: clientCtx,
|
||||
interfaceRegistry: interfaceRegistry,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSyncing implements ServiceServer.GetSyncing
|
||||
func (s queryServer) GetSyncing(_ context.Context, _ *qtypes.GetSyncingRequest) (*qtypes.GetSyncingResponse, error) {
|
||||
status, err := getNodeStatus(s.clientCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &qtypes.GetSyncingResponse{
|
||||
Syncing: status.SyncInfo.CatchingUp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetLatestBlock implements ServiceServer.GetLatestBlock
|
||||
func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockRequest) (*qtypes.GetLatestBlockResponse, error) {
|
||||
status, err := getBlock(s.clientCtx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoBlockID := status.BlockID.ToProto()
|
||||
protoBlock, err := status.Block.ToProto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &qtypes.GetLatestBlockResponse{
|
||||
BlockId: &protoBlockID,
|
||||
Block: protoBlock,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetBlockByHeight implements ServiceServer.GetBlockByHeight
|
||||
func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByHeightRequest) (*qtypes.GetBlockByHeightResponse, error) {
|
||||
chainHeight, err := rpc.GetChainHeight(s.clientCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.Height > chainHeight {
|
||||
return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length")
|
||||
}
|
||||
|
||||
res, err := getBlock(s.clientCtx, &req.Height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
protoBlockID := res.BlockID.ToProto()
|
||||
protoBlock, err := res.Block.ToProto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &qtypes.GetBlockByHeightResponse{
|
||||
BlockId: &protoBlockID,
|
||||
Block: protoBlock,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetLatestValidatorSet implements ServiceServer.GetLatestValidatorSet
|
||||
func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetLatestValidatorSetRequest) (*qtypes.GetLatestValidatorSetResponse, error) {
|
||||
page, limit, err := qtypes.ParsePagination(req.Pagination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
validatorsRes, err := rpc.GetValidators(s.clientCtx, nil, &page, &limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputValidatorsRes := &qtypes.GetLatestValidatorSetResponse{
|
||||
BlockHeight: validatorsRes.BlockHeight,
|
||||
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)),
|
||||
}
|
||||
|
||||
for i, validator := range validatorsRes.Validators {
|
||||
outputValidatorsRes.Validators[i] = &qtypes.Validator{
|
||||
Address: validator.Address,
|
||||
ProposerPriority: validator.ProposerPriority,
|
||||
PubKey: validator.PubKey,
|
||||
VotingPower: validator.VotingPower,
|
||||
}
|
||||
}
|
||||
return outputValidatorsRes, nil
|
||||
}
|
||||
|
||||
// GetValidatorSetByHeight implements ServiceServer.GetValidatorSetByHeight
|
||||
func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.GetValidatorSetByHeightRequest) (*qtypes.GetValidatorSetByHeightResponse, error) {
|
||||
page, limit, err := qtypes.ParsePagination(req.Pagination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chainHeight, err := rpc.GetChainHeight(s.clientCtx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "failed to parse chain height")
|
||||
}
|
||||
if req.Height > chainHeight {
|
||||
return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length")
|
||||
}
|
||||
|
||||
validatorsRes, err := rpc.GetValidators(s.clientCtx, &req.Height, &page, &limit)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outputValidatorsRes := &qtypes.GetValidatorSetByHeightResponse{
|
||||
BlockHeight: validatorsRes.BlockHeight,
|
||||
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)),
|
||||
}
|
||||
|
||||
for i, validator := range validatorsRes.Validators {
|
||||
outputValidatorsRes.Validators[i] = &qtypes.Validator{
|
||||
Address: validator.Address,
|
||||
ProposerPriority: validator.ProposerPriority,
|
||||
PubKey: validator.PubKey,
|
||||
VotingPower: validator.VotingPower,
|
||||
}
|
||||
}
|
||||
return outputValidatorsRes, nil
|
||||
}
|
||||
|
||||
// GetNodeInfo implements ServiceServer.GetNodeInfo
|
||||
func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoRequest) (*qtypes.GetNodeInfoResponse, error) {
|
||||
status, err := getNodeStatus(s.clientCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoNodeInfo := status.NodeInfo.ToProto()
|
||||
nodeInfo := version.NewInfo()
|
||||
|
||||
deps := make([]*qtypes.Module, len(nodeInfo.BuildDeps))
|
||||
|
||||
for i, dep := range nodeInfo.BuildDeps {
|
||||
deps[i] = &qtypes.Module{
|
||||
Path: dep.Path,
|
||||
Sum: dep.Sum,
|
||||
Version: dep.Version,
|
||||
}
|
||||
}
|
||||
|
||||
resp := qtypes.GetNodeInfoResponse{
|
||||
DefaultNodeInfo: protoNodeInfo,
|
||||
ApplicationVersion: &qtypes.VersionInfo{
|
||||
AppName: nodeInfo.AppName,
|
||||
Name: nodeInfo.Name,
|
||||
GitCommit: nodeInfo.GitCommit,
|
||||
GoVersion: nodeInfo.GoVersion,
|
||||
Version: nodeInfo.Version,
|
||||
BuildTags: nodeInfo.BuildTags,
|
||||
BuildDeps: deps,
|
||||
},
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// RegisterTendermintService registers the tendermint queries on the gRPC router.
|
||||
func RegisterTendermintService(
|
||||
qrt gogogrpc.Server,
|
||||
clientCtx client.Context,
|
||||
interfaceRegistry codectypes.InterfaceRegistry,
|
||||
) {
|
||||
qtypes.RegisterServiceServer(
|
||||
qrt,
|
||||
NewQueryServer(clientCtx, interfaceRegistry),
|
||||
)
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package tmservice_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
qtypes "github.com/cosmos/cosmos-sdk/types/query"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
type IntegrationTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
cfg network.Config
|
||||
network *network.Network
|
||||
|
||||
queryClient qtypes.ServiceClient
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) SetupSuite() {
|
||||
s.T().Log("setting up integration test suite")
|
||||
|
||||
cfg := network.DefaultConfig()
|
||||
cfg.NumValidators = 1
|
||||
|
||||
s.cfg = cfg
|
||||
s.network = network.New(s.T(), cfg)
|
||||
|
||||
s.Require().NotNil(s.network)
|
||||
|
||||
_, err := s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.queryClient = qtypes.NewServiceClient(s.network.Validators[0].ClientCtx)
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TearDownSuite() {
|
||||
s.T().Log("tearing down integration test suite")
|
||||
s.network.Cleanup()
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestQueryNodeInfo() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
res, err := s.queryClient.GetNodeInfo(context.Background(), &qtypes.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
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &getInfoRes))
|
||||
s.Require().Equal(getInfoRes.ApplicationVersion.AppName, version.NewInfo().AppName)
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestQuerySyncing() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
_, err := s.queryClient.GetSyncing(context.Background(), &qtypes.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
|
||||
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{})
|
||||
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
|
||||
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})
|
||||
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
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &blockInfoRes))
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestQueryLatestValidatorSet() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
// nil pagination
|
||||
_, err := s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{
|
||||
Pagination: nil,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
|
||||
//with pagination
|
||||
_, err = s.queryClient.GetLatestValidatorSet(context.Background(), &qtypes.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
}})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// rest request without pagination
|
||||
_, err = rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/latest", val.APIAddress))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// 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
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes))
|
||||
}
|
||||
|
||||
func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
// nil pagination
|
||||
_, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{
|
||||
Height: 1,
|
||||
Pagination: nil,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
|
||||
_, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &qtypes.GetValidatorSetByHeightRequest{
|
||||
Height: 1,
|
||||
Pagination: &qtypes.PageRequest{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
}})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// no pagination rest
|
||||
_, err = rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validators/%d", val.APIAddress, 1))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// 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
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes))
|
||||
}
|
||||
|
||||
func TestIntegrationTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(IntegrationTestSuite))
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package tmservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
|
||||
func getNodeStatus(clientCtx client.Context) (*ctypes.ResultStatus, error) {
|
||||
node, err := clientCtx.GetNode()
|
||||
if err != nil {
|
||||
return &ctypes.ResultStatus{}, err
|
||||
}
|
||||
return node.Status(context.Background())
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -16,6 +16,7 @@ Some important information concerning all 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}`. |
|
||||
|
@ -87,3 +88,7 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
|
|||
| `POST /upgrade/*` | Create unsigned `Msg`s for upgrade | N/A, use Protobuf directly |
|
||||
| `GET /upgrade/current` | Get the current plan | `GET /cosmos/upgrade/v1beta1/current_plan` |
|
||||
| `GET /upgrade/applied_plan/{name}` | Get a previously applied plan | `GET /cosmos/upgrade/v1beta1/applied/{name}` |
|
||||
|
||||
## Migrating to gRPC
|
||||
|
||||
Instead of hitting REST endpoints as described in the previous paragraph, the SDK also exposes a gRPC server. Any client can use gRPC instead of REST to interact with the node. An overview of different ways to communicate with a node can be found [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657), and a concrete tutorial for setting up a gRPC client [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657).
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
syntax = "proto3";
|
||||
package cosmos.base.tendermint.v1beta1;
|
||||
|
||||
import "gogoproto/gogo.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";
|
||||
|
||||
// Service defines the gRPC querier service for tendermint queries.
|
||||
service Service {
|
||||
// GetNodeInfo queries the current node info.
|
||||
rpc GetNodeInfo(GetNodeInfoRequest) returns (GetNodeInfoResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/node_info";
|
||||
}
|
||||
// GetSyncing queries node syncing.
|
||||
rpc GetSyncing(GetSyncingRequest) returns (GetSyncingResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/syncing";
|
||||
}
|
||||
// GetLatestBlock returns the latest block.
|
||||
rpc GetLatestBlock(GetLatestBlockRequest) returns (GetLatestBlockResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/blocks/latest";
|
||||
}
|
||||
// GetBlockByHeight queries block for given height.
|
||||
rpc GetBlockByHeight(GetBlockByHeightRequest) returns (GetBlockByHeightResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/blocks/{height}";
|
||||
}
|
||||
|
||||
// GetLatestValidatorSet queries latest validator-set.
|
||||
rpc GetLatestValidatorSet(GetLatestValidatorSetRequest) returns (GetLatestValidatorSetResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/validators/latest";
|
||||
}
|
||||
// GetValidatorSetByHeight queries validator-set at a given height.
|
||||
rpc GetValidatorSetByHeight(GetValidatorSetByHeightRequest) returns (GetValidatorSetByHeightResponse) {
|
||||
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/validators/{height}";
|
||||
}
|
||||
}
|
||||
|
||||
// GetValidatorSetByHeightRequest is the request type for the Query/GetValidatorSetByHeight RPC method.
|
||||
message GetValidatorSetByHeightRequest {
|
||||
int64 height = 1;
|
||||
// pagination defines an pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 2;
|
||||
}
|
||||
|
||||
// GetValidatorSetByHeightResponse is the response type for the Query/GetValidatorSetByHeight RPC method.
|
||||
message GetValidatorSetByHeightResponse {
|
||||
int64 block_height = 1;
|
||||
repeated Validator validators = 2;
|
||||
// pagination defines an pagination for the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 3;
|
||||
}
|
||||
|
||||
// GetLatestValidatorSetRequest is the request type for the Query/GetValidatorSetByHeight RPC method.
|
||||
message GetLatestValidatorSetRequest {
|
||||
// pagination defines an pagination for the request.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 1;
|
||||
}
|
||||
|
||||
// GetLatestValidatorSetResponse is the response type for the Query/GetValidatorSetByHeight RPC method.
|
||||
message GetLatestValidatorSetResponse {
|
||||
int64 block_height = 1;
|
||||
repeated Validator validators = 2;
|
||||
// pagination defines an pagination for the response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 3;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// GetBlockByHeightRequest is the request type for the Query/GetBlockByHeight RPC method.
|
||||
message GetBlockByHeightRequest {
|
||||
int64 height = 1;
|
||||
}
|
||||
|
||||
// GetBlockByHeightResponse is the response type for the Query/GetBlockByHeight RPC method.
|
||||
message GetBlockByHeightResponse {
|
||||
tendermint.types.BlockID block_id = 1;
|
||||
tendermint.types.Block block = 2;
|
||||
}
|
||||
|
||||
// GetLatestBlockRequest is the request type for the Query/GetLatestBlock RPC method.
|
||||
message GetLatestBlockRequest {}
|
||||
|
||||
// GetLatestBlockResponse is the response type for the Query/GetLatestBlock RPC method.
|
||||
message GetLatestBlockResponse {
|
||||
tendermint.types.BlockID block_id = 1;
|
||||
tendermint.types.Block block = 2;
|
||||
}
|
||||
|
||||
// GetSyncingRequest is the request type for the Query/GetSyncing RPC method.
|
||||
message GetSyncingRequest {}
|
||||
|
||||
// GetSyncingResponse is the response type for the Query/GetSyncing RPC method.
|
||||
message GetSyncingResponse {
|
||||
bool syncing = 1;
|
||||
}
|
||||
|
||||
// GetNodeInfoRequest is the request type for the Query/GetNodeInfo RPC method.
|
||||
message GetNodeInfoRequest {}
|
||||
|
||||
// GetNodeInfoResponse is the request type for the Query/GetNodeInfo RPC method.
|
||||
message GetNodeInfoResponse {
|
||||
tendermint.p2p.DefaultNodeInfo default_node_info = 1;
|
||||
VersionInfo application_version = 2;
|
||||
}
|
||||
|
||||
// VersionInfo is the type for the GetNodeInfoResponse message.
|
||||
message VersionInfo {
|
||||
string name = 1;
|
||||
string app_name = 2;
|
||||
string version = 3;
|
||||
string git_commit = 4;
|
||||
string build_tags = 5;
|
||||
string go_version = 6;
|
||||
repeated Module build_deps = 7;
|
||||
}
|
||||
|
||||
// Module is the type for VersionInfo
|
||||
message Module {
|
||||
// module path
|
||||
string path = 1;
|
||||
// module version
|
||||
string version = 2;
|
||||
// checksum
|
||||
string sum = 3;
|
||||
}
|
|
@ -258,10 +258,10 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App
|
|||
// service if API or gRPC is enabled, and avoid doing so in the general
|
||||
// case, because it spawns a new local tendermint RPC client.
|
||||
if config.API.Enable || config.GRPC.Enable {
|
||||
clientCtx = clientCtx.
|
||||
WithClient(local.New(tmNode))
|
||||
clientCtx = clientCtx.WithClient(local.New(tmNode))
|
||||
|
||||
app.RegisterTxService(clientCtx)
|
||||
app.RegisterTendermintService(clientCtx)
|
||||
}
|
||||
|
||||
var apiSrv *api.Server
|
||||
|
|
|
@ -43,6 +43,9 @@ type (
|
|||
// RegisterTxService registers the gRPC Query service for tx (such as tx
|
||||
// simulation, fetching txs by hash...).
|
||||
RegisterTxService(clientCtx client.Context)
|
||||
|
||||
// RegisterTendermintService registers the gRPC Query service for tendermint queries.
|
||||
RegisterTendermintService(clientCtx client.Context)
|
||||
}
|
||||
|
||||
// AppCreator is a function that allows us to lazily initialize an
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
|
@ -560,6 +561,8 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon
|
|||
authrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
|
||||
// Register new tx routes from grpc-gateway.
|
||||
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
|
||||
// Register new tendermint queries routes from grpc-gateway.
|
||||
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCRouter)
|
||||
|
||||
// Register legacy and grpc-gateway routes for all modules.
|
||||
ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router)
|
||||
|
@ -576,6 +579,11 @@ func (app *SimApp) RegisterTxService(clientCtx client.Context) {
|
|||
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
|
||||
}
|
||||
|
||||
// RegisterTendermintService implements the Application.RegisterTendermintService method.
|
||||
func (app *SimApp) RegisterTendermintService(clientCtx client.Context) {
|
||||
tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry)
|
||||
}
|
||||
|
||||
// RegisterSwaggerAPI registers swagger route with API Server
|
||||
func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) {
|
||||
statikFS, err := fs.New()
|
||||
|
|
|
@ -66,6 +66,9 @@ func startInProcess(cfg Config, val *Validator) error {
|
|||
|
||||
// Add the tx service in the gRPC router.
|
||||
app.RegisterTxService(val.ClientCtx)
|
||||
|
||||
// Add the tendermint queries service in the gRPC router.
|
||||
app.RegisterTendermintService(val.ClientCtx)
|
||||
}
|
||||
|
||||
if val.APIAddress != "" {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
syntax = "proto3";
|
||||
package tendermint.p2p;
|
||||
|
||||
option go_package = "github.com/tendermint/tendermint/proto/tendermint/p2p";
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
|
||||
message NetAddress {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string ip = 2 [(gogoproto.customname) = "IP"];
|
||||
uint32 port = 3;
|
||||
}
|
||||
|
||||
message ProtocolVersion {
|
||||
uint64 p2p = 1 [(gogoproto.customname) = "P2P"];
|
||||
uint64 block = 2;
|
||||
uint64 app = 3;
|
||||
}
|
||||
|
||||
message DefaultNodeInfo {
|
||||
ProtocolVersion protocol_version = 1 [(gogoproto.nullable) = false];
|
||||
string default_node_id = 2 [(gogoproto.customname) = "DefaultNodeID"];
|
||||
string listen_addr = 3;
|
||||
string network = 4;
|
||||
string version = 5;
|
||||
bytes channels = 6;
|
||||
string moniker = 7;
|
||||
DefaultNodeInfoOther other = 8 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message DefaultNodeInfoOther {
|
||||
string tx_index = 1;
|
||||
string rpc_address = 2 [(gogoproto.customname) = "RPCAddress"];
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
syntax = "proto3";
|
||||
package tendermint.types;
|
||||
|
||||
option go_package = "github.com/tendermint/tendermint/proto/tendermint/types";
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "tendermint/types/types.proto";
|
||||
import "tendermint/types/evidence.proto";
|
||||
|
||||
message Block {
|
||||
Header header = 1 [(gogoproto.nullable) = false];
|
||||
Data data = 2 [(gogoproto.nullable) = false];
|
||||
tendermint.types.EvidenceList evidence = 3 [(gogoproto.nullable) = false];
|
||||
Commit last_commit = 4;
|
||||
}
|
|
@ -18,7 +18,7 @@ func BenchmarkParseCoin(b *testing.B) {
|
|||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, coinStr := range coinStrs {
|
||||
coin, err := types.ParseCoin(coinStr)
|
||||
coin, err := types.ParseCoinNormalized(coinStr)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -599,11 +599,9 @@ var (
|
|||
// Denominations can be 3 ~ 128 characters long and support letters, followed by either
|
||||
// a letter, a number or a separator ('/').
|
||||
reDnmString = `[a-zA-Z][a-zA-Z0-9/]{2,127}`
|
||||
reAmt = `[[:digit:]]+`
|
||||
reDecAmt = `[[:digit:]]+(?:\.[[:digit:]]+)?|\.[[:digit:]]+`
|
||||
reSpc = `[[:space:]]*`
|
||||
reDnm *regexp.Regexp
|
||||
reCoin *regexp.Regexp
|
||||
reDecCoin *regexp.Regexp
|
||||
)
|
||||
|
||||
|
@ -625,7 +623,6 @@ func SetCoinDenomRegex(reFn func() string) {
|
|||
coinDenomRegex = reFn
|
||||
|
||||
reDnm = regexp.MustCompile(fmt.Sprintf(`^%s$`, coinDenomRegex()))
|
||||
reCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reAmt, reSpc, coinDenomRegex()))
|
||||
reDecCoin = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, reDecAmt, reSpc, coinDenomRegex()))
|
||||
}
|
||||
|
||||
|
@ -643,29 +640,17 @@ func mustValidateDenom(denom string) {
|
|||
}
|
||||
}
|
||||
|
||||
// ParseCoin parses a cli input for one coin type, returning errors if invalid or on an empty string
|
||||
// ParseCoinNormalized parses and normalize a cli input for one coin type, returning errors if invalid or on an empty string
|
||||
// as well.
|
||||
// Expected format: "{amount}{denomination}"
|
||||
func ParseCoin(coinStr string) (coin Coin, err error) {
|
||||
coinStr = strings.TrimSpace(coinStr)
|
||||
|
||||
matches := reCoin.FindStringSubmatch(coinStr)
|
||||
if matches == nil {
|
||||
return Coin{}, fmt.Errorf("invalid coin expression: %s", coinStr)
|
||||
}
|
||||
|
||||
denomStr, amountStr := matches[2], matches[1]
|
||||
|
||||
amount, ok := NewIntFromString(amountStr)
|
||||
if !ok {
|
||||
return Coin{}, fmt.Errorf("failed to parse coin amount: %s", amountStr)
|
||||
}
|
||||
|
||||
if err := ValidateDenom(denomStr); err != nil {
|
||||
func ParseCoinNormalized(coinStr string) (coin Coin, err error) {
|
||||
decCoin, err := ParseDecCoin(coinStr)
|
||||
if err != nil {
|
||||
return Coin{}, err
|
||||
}
|
||||
|
||||
return NewCoin(denomStr, amount), nil
|
||||
coin, _ = NormalizeDecCoin(decCoin).TruncateDecimal()
|
||||
return coin, nil
|
||||
}
|
||||
|
||||
// ParseCoinsNormalized will parse out a list of coins separated by commas, and normalize them by converting to smallest
|
||||
|
|
|
@ -3,6 +3,9 @@ package query
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/types"
|
||||
)
|
||||
|
||||
|
@ -10,6 +13,30 @@ import (
|
|||
// if the `limit` is not supplied, paginate will use `DefaultLimit`
|
||||
const DefaultLimit = 100
|
||||
|
||||
// ParsePagination validate PageRequest and returns page number & limit.
|
||||
func ParsePagination(pageReq *PageRequest) (page, limit int, err error) {
|
||||
offset := 0
|
||||
limit = DefaultLimit
|
||||
|
||||
if pageReq != nil {
|
||||
offset = int(pageReq.Offset)
|
||||
limit = int(pageReq.Limit)
|
||||
}
|
||||
if offset < 0 {
|
||||
return 1, 0, status.Error(codes.InvalidArgument, "offset must greater than 0")
|
||||
}
|
||||
|
||||
if limit < 0 {
|
||||
return 1, 0, status.Error(codes.InvalidArgument, "limit must greater than 0")
|
||||
} else if limit == 0 {
|
||||
limit = DefaultLimit
|
||||
}
|
||||
|
||||
page = offset/limit + 1
|
||||
|
||||
return page, limit, nil
|
||||
}
|
||||
|
||||
// Paginate does pagination of all the results in the PrefixStore based on the
|
||||
// provided PageRequest. onResult should be used to do actual unmarshaling.
|
||||
func Paginate(
|
||||
|
|
|
@ -43,6 +43,25 @@ func TestPaginationTestSuite(t *testing.T) {
|
|||
suite.Run(t, new(paginationTestSuite))
|
||||
}
|
||||
|
||||
func (s *paginationTestSuite) TestParsePagination() {
|
||||
s.T().Log("verify default values for empty page request")
|
||||
pageReq := &query.PageRequest{}
|
||||
page, limit, err := query.ParsePagination(pageReq)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(limit, query.DefaultLimit)
|
||||
s.Require().Equal(page, 1)
|
||||
|
||||
s.T().Log("verify with custom values")
|
||||
pageReq = &query.PageRequest{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
}
|
||||
page, limit, err = query.ParsePagination(pageReq)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(page, 1)
|
||||
s.Require().Equal(limit, 10)
|
||||
}
|
||||
|
||||
func (s *paginationTestSuite) TestPagination() {
|
||||
app, ctx, _ := setupTest()
|
||||
queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,566 @@
|
|||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: cosmos/base/tendermint/v1beta1/query.proto
|
||||
|
||||
/*
|
||||
Package query is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/descriptor"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = descriptor.ForMessage
|
||||
|
||||
func request_Service_GetNodeInfo_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetNodeInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.GetNodeInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetNodeInfo_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetNodeInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.GetNodeInfo(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_GetSyncing_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetSyncingRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.GetSyncing(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetSyncing_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetSyncingRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.GetSyncing(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_GetLatestBlock_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetLatestBlockRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.GetLatestBlock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetLatestBlock_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetLatestBlockRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.GetLatestBlock(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_GetBlockByHeight_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetBlockByHeightRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["height"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
|
||||
}
|
||||
|
||||
protoReq.Height, err = runtime.Int64(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetBlockByHeight(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetBlockByHeight_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetBlockByHeightRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["height"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
|
||||
}
|
||||
|
||||
protoReq.Height, err = runtime.Int64(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetBlockByHeight(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Service_GetLatestValidatorSet_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_Service_GetLatestValidatorSet_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetLatestValidatorSetRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_GetLatestValidatorSet_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetLatestValidatorSet(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetLatestValidatorSet_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetLatestValidatorSetRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_GetLatestValidatorSet_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetLatestValidatorSet(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_Service_GetValidatorSetByHeight_0 = &utilities.DoubleArray{Encoding: map[string]int{"height": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_Service_GetValidatorSetByHeight_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetValidatorSetByHeightRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["height"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
|
||||
}
|
||||
|
||||
protoReq.Height, err = runtime.Int64(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_GetValidatorSetByHeight_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetValidatorSetByHeight(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetValidatorSetByHeight_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetValidatorSetByHeightRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["height"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
|
||||
}
|
||||
|
||||
protoReq.Height, err = runtime.Int64(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_GetValidatorSetByHeight_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetValidatorSetByHeight(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerServer registers the http handlers for service Service to "mux".
|
||||
// UnaryRPC :call ServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterServiceHandlerFromEndpoint instead.
|
||||
func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ServiceServer) error {
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetNodeInfo_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_GetNodeInfo_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_GetNodeInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetSyncing_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_GetSyncing_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_GetSyncing_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetLatestBlock_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_GetLatestBlock_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_GetLatestBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetBlockByHeight_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_GetBlockByHeight_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_GetBlockByHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetLatestValidatorSet_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_GetLatestValidatorSet_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_GetLatestValidatorSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetValidatorSetByHeight_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_GetValidatorSetByHeight_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_GetValidatorSetByHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerFromEndpoint is same as RegisterServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterServiceHandler registers the http handlers for service Service to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterServiceHandlerClient(ctx, mux, NewServiceClient(conn))
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerClient registers the http handlers for service Service
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ServiceClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ServiceClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "ServiceClient" to call the correct interceptors.
|
||||
func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ServiceClient) error {
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetNodeInfo_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_GetNodeInfo_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_GetNodeInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetSyncing_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_GetSyncing_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_GetSyncing_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetLatestBlock_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_GetLatestBlock_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_GetLatestBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetBlockByHeight_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_GetBlockByHeight_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_GetBlockByHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetLatestValidatorSet_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_GetLatestValidatorSet_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_GetLatestValidatorSet_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetValidatorSetByHeight_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_GetValidatorSetByHeight_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_GetValidatorSetByHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_Service_GetNodeInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "node_info"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_Service_GetSyncing_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "syncing"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_Service_GetLatestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "latest"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_Service_GetBlockByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "blocks", "height"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validators", "latest"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validators", "height"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_Service_GetNodeInfo_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_GetSyncing_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_GetLatestBlock_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_GetBlockByHeight_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_GetLatestValidatorSet_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_GetValidatorSetByHeight_0 = runtime.ForwardResponseMessage
|
||||
)
|
|
@ -55,9 +55,10 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
|
|||
|
||||
response := DecodeResp(stdTx)
|
||||
|
||||
err = checkSignModeError(w, clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
|
||||
err = checkSignModeError(clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
|
||||
if err != nil {
|
||||
// Error is already returned by checkSignModeError.
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ import (
|
|||
genutilrest "github.com/cosmos/cosmos-sdk/x/genutil/client/rest"
|
||||
)
|
||||
|
||||
const unRegisteredConcreteTypeErr = "unregistered concrete type"
|
||||
|
||||
// QueryAccountRequestHandlerFn is the query accountREST Handler.
|
||||
func QueryAccountRequestHandlerFn(storeName string, clientCtx client.Context) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -110,9 +108,10 @@ func QueryTxsRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
|
|||
packStdTxResponse(w, clientCtx, txRes)
|
||||
}
|
||||
|
||||
err = checkSignModeError(w, clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
|
||||
err = checkSignModeError(clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
|
||||
if err != nil {
|
||||
// Error is already returned by checkSignModeError.
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -152,9 +151,10 @@ func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
|
|||
rest.WriteErrorResponse(w, http.StatusNotFound, fmt.Sprintf("no transaction found with hash %s", hashHexStr))
|
||||
}
|
||||
|
||||
err = checkSignModeError(w, clientCtx, output, "/cosmos/tx/v1beta1/tx/{txhash}")
|
||||
err = checkSignModeError(clientCtx, output, "/cosmos/tx/v1beta1/tx/{txhash}")
|
||||
if err != nil {
|
||||
// Error is already returned by checkSignModeError.
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -198,18 +198,22 @@ func packStdTxResponse(w http.ResponseWriter, clientCtx client.Context, txRes *s
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkSignModeError(w http.ResponseWriter, ctx client.Context, resp interface{}, grpcEndPoint string) error {
|
||||
// checkSignModeError checks if there are errors with marshalling non-amino
|
||||
// txs with amino.
|
||||
func checkSignModeError(ctx client.Context, resp interface{}, grpcEndPoint string) error {
|
||||
// LegacyAmino used intentionally here to handle the SignMode errors
|
||||
marshaler := ctx.LegacyAmino
|
||||
|
||||
_, err := marshaler.MarshalJSON(resp)
|
||||
if err != nil && strings.Contains(err.Error(), unRegisteredConcreteTypeErr) {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError,
|
||||
"This transaction was created with the new SIGN_MODE_DIRECT signing method, and therefore cannot be displayed"+
|
||||
" via legacy REST handlers, please use CLI or directly query the Tendermint RPC endpoint to query"+
|
||||
" this transaction. gRPC gateway endpoint is "+grpcEndPoint+". Please also see the REST endpoints migration"+
|
||||
" guide at "+clientrest.DeprecationURL+".")
|
||||
return err
|
||||
if err != nil {
|
||||
|
||||
// If there's an unmarshalling error, we assume that it's because we're
|
||||
// using amino to unmarshal a non-amino tx.
|
||||
return fmt.Errorf("this transaction cannot be displayed 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 query this transaction. The new REST endpoint (via gRPC-gateway) is %s. Please also see the"+
|
||||
"REST endpoints migration guide at %s for more info", grpcEndPoint, clientrest.DeprecationURL)
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
|
@ -16,16 +17,16 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
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"
|
||||
authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
|
||||
ibccli "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/client/cli"
|
||||
|
||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
rest2 "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"
|
||||
ibccli "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/client/cli"
|
||||
ibcsolomachinecli "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/client/cli"
|
||||
)
|
||||
|
||||
type IntegrationTestSuite struct {
|
||||
|
@ -129,51 +130,99 @@ func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
|
|||
s.Require().NotEmpty(txRes.TxHash)
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestQueryTxByHash() {
|
||||
// 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]
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
malleate func() *sdk.TxResponse
|
||||
}{
|
||||
{
|
||||
"Query by hash",
|
||||
func() *sdk.TxResponse {
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val0.APIAddress, txHash))
|
||||
s.Require().NoError(err)
|
||||
|
||||
var txResAmino sdk.TxResponse
|
||||
s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &txResAmino))
|
||||
return &txResAmino
|
||||
},
|
||||
},
|
||||
{
|
||||
"Query by height",
|
||||
func() *sdk.TxResponse {
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs?limit=10&page=1&tx.height=%d", val0.APIAddress, txHeight))
|
||||
s.Require().NoError(err)
|
||||
|
||||
var searchtxResult sdk.SearchTxsResult
|
||||
s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &searchtxResult))
|
||||
s.Require().Len(searchtxResult.Txs, 1)
|
||||
return searchtxResult.Txs[0]
|
||||
},
|
||||
},
|
||||
{
|
||||
"Query by event (transfer.recipient)",
|
||||
func() *sdk.TxResponse {
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs?transfer.recipient=%s", val0.APIAddress, txRecipient))
|
||||
s.Require().NoError(err)
|
||||
|
||||
var searchtxResult sdk.SearchTxsResult
|
||||
s.Require().NoError(val0.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &searchtxResult))
|
||||
s.Require().Len(searchtxResult.Txs, 1)
|
||||
return searchtxResult.Txs[0]
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
|
||||
txResponse := tc.malleate()
|
||||
|
||||
// Check that the height is correct.
|
||||
s.Require().Equal(txHeight, txResponse.Height)
|
||||
|
||||
// Check that the events are correct.
|
||||
s.Require().Contains(
|
||||
txResponse.RawLog,
|
||||
fmt.Sprintf("{\"key\":\"recipient\",\"value\":\"%s\"}", txRecipient),
|
||||
)
|
||||
|
||||
// Check that the Msg is correct.
|
||||
stdTx, ok := txResponse.Tx.GetCachedValue().(legacytx.StdTx)
|
||||
s.Require().True(ok)
|
||||
msgs := stdTx.GetMsgs()
|
||||
s.Require().Equal(len(msgs), 1)
|
||||
msg, ok := msgs[0].(*types.MsgSend)
|
||||
s.Require().True(ok)
|
||||
s.Require().Equal(txRecipient, msg.ToAddress)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestQueryTxWithStdTx() {
|
||||
val0 := s.network.Validators[0]
|
||||
|
||||
// We broadcasted a StdTx in SetupSuite.
|
||||
// we just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration
|
||||
// We just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration
|
||||
s.Require().NotEmpty(s.stdTxRes.TxHash)
|
||||
|
||||
// We now fetch the tx by hash on the `/tx/{hash}` route.
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val0.APIAddress, s.stdTxRes.TxHash))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// txJSON should contain the whole tx, we just make sure that our custom
|
||||
// memo is there.
|
||||
s.Require().Contains(string(txJSON), s.stdTx.Memo)
|
||||
s.testQueryTx(s.stdTxRes.Height, s.stdTxRes.TxHash, val0.Address.String())
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestQueryTxByHeight() {
|
||||
val0 := s.network.Validators[0]
|
||||
|
||||
// We broadcasted a StdTx in SetupSuite.
|
||||
// we just check for a non-empty height here, as we'll need to for querying.
|
||||
s.Require().NotEmpty(s.stdTxRes.Height)
|
||||
|
||||
// We now fetch the tx on `/txs` route, filtering by `tx.height`
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs?limit=10&page=1&tx.height=%d", val0.APIAddress, s.stdTxRes.Height))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// txJSON should contain the whole tx, we just make sure that our custom
|
||||
// memo is there.
|
||||
s.Require().Contains(string(txJSON), s.stdTx.Memo)
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestQueryTxByHashWithServiceMessage() {
|
||||
func (s *IntegrationTestSuite) TestQueryTxWithServiceMessage() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
|
||||
_, _, addr := testdata.KeyTestPubAddr()
|
||||
|
||||
// Right after this line, we're sending a tx. Might need to wait a block
|
||||
// to refresh sequences.
|
||||
// Might need to wait a block to refresh sequences from previous setups.
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
out, err := bankcli.ServiceMsgSendExec(
|
||||
val.ClientCtx,
|
||||
val.Address,
|
||||
val.Address,
|
||||
addr,
|
||||
sdk.NewCoins(sendTokens),
|
||||
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
|
||||
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
|
||||
|
@ -188,17 +237,7 @@ func (s *IntegrationTestSuite) TestQueryTxByHashWithServiceMessage() {
|
|||
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val.APIAddress, txRes.TxHash))
|
||||
s.Require().NoError(err)
|
||||
|
||||
var txResAmino sdk.TxResponse
|
||||
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &txResAmino))
|
||||
stdTx, ok := txResAmino.Tx.GetCachedValue().(legacytx.StdTx)
|
||||
s.Require().True(ok)
|
||||
msgs := stdTx.GetMsgs()
|
||||
s.Require().Equal(len(msgs), 1)
|
||||
_, ok = msgs[0].(*types.MsgSend)
|
||||
s.Require().True(ok)
|
||||
s.testQueryTx(txRes.Height, txRes.TxHash, addr.String())
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestMultipleSyncBroadcastTxRequests() {
|
||||
|
@ -303,42 +342,43 @@ func (s *IntegrationTestSuite) broadcastReq(stdTx legacytx.StdTx, mode string) (
|
|||
return rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", bz)
|
||||
}
|
||||
|
||||
func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
|
||||
// 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.
|
||||
func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.Command, args []string) {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
args := []string{
|
||||
"121", // dummy port-id
|
||||
"channel-0", // dummy channel-id
|
||||
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=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
|
||||
errMsg := "this transaction cannot be displayed 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 query this transaction. The new REST endpoint (via gRPC-gateway) is "
|
||||
|
||||
// Test that legacy endpoint return the above error message on IBC txs.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
url string
|
||||
}{
|
||||
{
|
||||
"Query by hash",
|
||||
fmt.Sprintf("%s/txs/%s", val.APIAddress, txRes.TxHash),
|
||||
},
|
||||
{
|
||||
"Query by height",
|
||||
fmt.Sprintf("%s/txs?tx.height=%d", val.APIAddress, txRes.Height),
|
||||
},
|
||||
}
|
||||
|
||||
// created a dummy txn for IBC, eventually it fails. Our intension is to test the error message of querying a
|
||||
// message which is signed with proto, since IBC won't support legacy amino at all we are considering a message from IBC module.
|
||||
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, ibccli.NewChannelCloseInitCmd(), args)
|
||||
s.Require().NoError(err)
|
||||
for _, tc := range testCases {
|
||||
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
|
||||
txJSON, err := rest.GetRequest(tc.url)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var txRes sdk.TxResponse
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
|
||||
var errResp rest.ErrorResponse
|
||||
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &errResp))
|
||||
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
// try to fetch the txn using legacy rest, this won't work since the ibc module doesn't support amino.
|
||||
txJSON, err := rest.GetRequest(fmt.Sprintf("%s/txs/%s", val.APIAddress, txRes.TxHash))
|
||||
s.Require().NoError(err)
|
||||
|
||||
var errResp rest.ErrorResponse
|
||||
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(txJSON, &errResp))
|
||||
|
||||
errMsg := "This transaction was created with the new SIGN_MODE_DIRECT signing method, " +
|
||||
"and therefore cannot be displayed via legacy REST handlers, please use CLI or directly query the Tendermint " +
|
||||
"RPC endpoint to query this transaction."
|
||||
|
||||
s.Require().Contains(errResp.Error, errMsg)
|
||||
s.Require().Contains(errResp.Error, errMsg)
|
||||
})
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
@ -350,7 +390,7 @@ func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
|
|||
|
||||
// generate broadcast only txn.
|
||||
args = append(args, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly))
|
||||
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, ibccli.NewChannelCloseInitCmd(), args)
|
||||
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
|
||||
s.Require().NoError(err)
|
||||
|
||||
txFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(out.Bytes()))
|
||||
|
@ -368,10 +408,80 @@ func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
|
|||
res, err := rest.PostRequest(fmt.Sprintf("%s/txs/decode", val.APIAddress), "application/json", bz)
|
||||
s.Require().NoError(err)
|
||||
|
||||
var errResp rest.ErrorResponse
|
||||
s.Require().NoError(val.ClientCtx.LegacyAmino.UnmarshalJSON(res, &errResp))
|
||||
s.Require().Contains(errResp.Error, errMsg)
|
||||
}
|
||||
|
||||
// TestLegacyRestErrMessages creates two IBC txs, one that fails, one that
|
||||
// succeeds, and make sure we cannot query any of them (with pretty error msg).
|
||||
// Our intension is to test the error message of querying a message which is
|
||||
// signed with proto, since IBC won't support legacy amino at all we are
|
||||
// considering a message from IBC module.
|
||||
func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
|
||||
val := s.network.Validators[0]
|
||||
|
||||
// Write consensus json to temp file, used for an IBC message.
|
||||
consensusJSON, cleanup := testutil.WriteToNewTempFile(
|
||||
s.T(),
|
||||
`{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`,
|
||||
)
|
||||
defer cleanup()
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
cmd *cobra.Command
|
||||
args []string
|
||||
code uint32
|
||||
}{
|
||||
{
|
||||
"Failing IBC message",
|
||||
ibccli.NewChannelCloseInitCmd(),
|
||||
[]string{
|
||||
"121", // dummy port-id
|
||||
"channel-0", // dummy channel-id
|
||||
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=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
|
||||
},
|
||||
uint32(7),
|
||||
},
|
||||
{
|
||||
"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),
|
||||
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=%s", flags.FlagFrom, val.Address.String()),
|
||||
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
|
||||
},
|
||||
uint32(0),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
|
||||
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, tc.cmd, tc.args)
|
||||
s.Require().NoError(err)
|
||||
var txRes sdk.TxResponse
|
||||
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
|
||||
s.Require().Equal(tc.code, txRes.Code)
|
||||
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
s.testQueryIBCTx(txRes, tc.cmd, tc.args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(IntegrationTestSuite))
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
v034gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v034"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v034"
|
||||
v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v036"
|
||||
)
|
||||
|
@ -28,6 +29,7 @@ func Migrate(appState types.AppMap, _ client.Context) types.AppMap {
|
|||
cryptocodec.RegisterCrypto(v036Codec)
|
||||
v036gov.RegisterLegacyAminoCodec(v036Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v036Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v036Codec)
|
||||
|
||||
// migrate genesis accounts state
|
||||
if appState[v034genAccounts.ModuleName] != nil {
|
||||
|
|
|
@ -10,8 +10,10 @@ import (
|
|||
v036genaccounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v036"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v036staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v036"
|
||||
v038staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v038"
|
||||
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
||||
)
|
||||
|
||||
// Migrate migrates exported state from v0.36/v0.37 to a v0.38 genesis state.
|
||||
|
@ -19,11 +21,14 @@ func Migrate(appState types.AppMap, _ client.Context) types.AppMap {
|
|||
v036Codec := codec.NewLegacyAmino()
|
||||
v036gov.RegisterLegacyAminoCodec(v036Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v036Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v036Codec)
|
||||
|
||||
v038Codec := codec.NewLegacyAmino()
|
||||
v038auth.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036gov.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v038Codec)
|
||||
v038upgrade.RegisterLegacyAminoCodec(v038Codec)
|
||||
|
||||
if appState[v036genaccounts.ModuleName] != nil {
|
||||
// unmarshal relative source genesis application state
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v036"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
||||
)
|
||||
|
||||
// Migrate migrates exported state from v0.38 to a v0.39 genesis state.
|
||||
|
@ -19,11 +21,15 @@ func Migrate(appState types.AppMap, _ client.Context) types.AppMap {
|
|||
v038auth.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036gov.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v038Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v038Codec)
|
||||
v038upgrade.RegisterLegacyAminoCodec(v038Codec)
|
||||
|
||||
v039Codec := codec.NewLegacyAmino()
|
||||
v039auth.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036gov.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v039Codec)
|
||||
v038upgrade.RegisterLegacyAminoCodec(v039Codec)
|
||||
|
||||
// migrate x/auth state (JSON serialization only)
|
||||
if appState[v038auth.ModuleName] != nil {
|
||||
|
|
|
@ -3,7 +3,6 @@ package v040
|
|||
import (
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v039"
|
||||
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
|
||||
v036supply "github.com/cosmos/cosmos-sdk/x/bank/legacy/v036"
|
||||
|
@ -22,10 +21,12 @@ import (
|
|||
v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040"
|
||||
v039mint "github.com/cosmos/cosmos-sdk/x/mint/legacy/v039"
|
||||
v040mint "github.com/cosmos/cosmos-sdk/x/mint/legacy/v040"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v039slashing "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v039"
|
||||
v040slashing "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v040"
|
||||
v038staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v038"
|
||||
v040staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v040"
|
||||
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
||||
)
|
||||
|
||||
func migrateGenutil(oldGenState v039genutil.GenesisState) *types.GenesisState {
|
||||
|
@ -37,10 +38,11 @@ func migrateGenutil(oldGenState v039genutil.GenesisState) *types.GenesisState {
|
|||
// Migrate migrates exported state from v0.39 to a v0.40 genesis state.
|
||||
func Migrate(appState types.AppMap, clientCtx client.Context) types.AppMap {
|
||||
v039Codec := codec.NewLegacyAmino()
|
||||
cryptocodec.RegisterCrypto(v039Codec)
|
||||
v039auth.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036gov.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036distr.RegisterLegacyAminoCodec(v039Codec)
|
||||
v036params.RegisterLegacyAminoCodec(v039Codec)
|
||||
v038upgrade.RegisterLegacyAminoCodec(v039Codec)
|
||||
|
||||
v040Codec := clientCtx.JSONMarshaler
|
||||
|
||||
|
|
|
@ -3,12 +3,18 @@ package v040
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v036"
|
||||
v040distr "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
v034gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v034"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
v040gov "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v040params "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
|
||||
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
||||
v040upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
)
|
||||
|
||||
func migrateVoteOption(oldVoteOption v034gov.VoteOption) v040gov.VoteOption {
|
||||
|
@ -60,10 +66,12 @@ func migrateProposalStatus(oldProposalStatus v034gov.ProposalStatus) v040gov.Pro
|
|||
}
|
||||
|
||||
func migrateContent(oldContent v036gov.Content) *codectypes.Any {
|
||||
var protoProposal proto.Message
|
||||
|
||||
switch oldContent := oldContent.(type) {
|
||||
case v036gov.TextProposal:
|
||||
{
|
||||
protoProposal := &v040gov.TextProposal{
|
||||
protoProposal = &v040gov.TextProposal{
|
||||
Title: oldContent.Title,
|
||||
Description: oldContent.Description,
|
||||
}
|
||||
|
@ -77,23 +85,61 @@ func migrateContent(oldContent v036gov.Content) *codectypes.Any {
|
|||
}
|
||||
case v036distr.CommunityPoolSpendProposal:
|
||||
{
|
||||
protoProposal := &v040distr.CommunityPoolSpendProposal{
|
||||
protoProposal = &v040distr.CommunityPoolSpendProposal{
|
||||
Title: oldContent.Title,
|
||||
Description: oldContent.Description,
|
||||
Recipient: oldContent.Recipient.String(),
|
||||
Amount: oldContent.Amount,
|
||||
}
|
||||
// Convert the content into Any.
|
||||
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
case v038upgrade.CancelSoftwareUpgradeProposal:
|
||||
{
|
||||
protoProposal = &v040upgrade.CancelSoftwareUpgradeProposal{
|
||||
Description: oldContent.Description,
|
||||
Title: oldContent.Title,
|
||||
}
|
||||
}
|
||||
case v038upgrade.SoftwareUpgradeProposal:
|
||||
{
|
||||
protoProposal = &v040upgrade.SoftwareUpgradeProposal{
|
||||
Description: oldContent.Description,
|
||||
Title: oldContent.Title,
|
||||
Plan: v040upgrade.Plan{
|
||||
Name: oldContent.Plan.Name,
|
||||
Time: oldContent.Plan.Time,
|
||||
Height: oldContent.Plan.Height,
|
||||
Info: oldContent.Plan.Info,
|
||||
},
|
||||
}
|
||||
}
|
||||
case v036params.ParameterChangeProposal:
|
||||
{
|
||||
newChanges := make([]v040params.ParamChange, len(oldContent.Changes))
|
||||
for i, oldChange := range oldContent.Changes {
|
||||
newChanges[i] = v040params.ParamChange{
|
||||
Subspace: oldChange.Subspace,
|
||||
Key: oldChange.Key,
|
||||
Value: oldChange.Value,
|
||||
}
|
||||
}
|
||||
|
||||
return contentAny
|
||||
protoProposal = &v040params.ParameterChangeProposal{
|
||||
Description: oldContent.Description,
|
||||
Title: oldContent.Title,
|
||||
Changes: newChanges,
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("'%T' is not a valid proposal content type", oldContent))
|
||||
panic(fmt.Errorf("%T is not a valid proposal content type", oldContent))
|
||||
}
|
||||
|
||||
// Convert the content into Any.
|
||||
contentAny, err := codectypes.NewAnyWithValue(protoProposal)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return contentAny
|
||||
}
|
||||
|
||||
// Migrate accepts exported v0.36 x/gov genesis state and migrates it to
|
||||
|
|
|
@ -12,6 +12,8 @@ import (
|
|||
v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v036"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040"
|
||||
v036params "github.com/cosmos/cosmos-sdk/x/params/legacy/v036"
|
||||
v038upgrade "github.com/cosmos/cosmos-sdk/x/upgrade/legacy/v038"
|
||||
)
|
||||
|
||||
func TestMigrate(t *testing.T) {
|
||||
|
@ -28,8 +30,8 @@ func TestMigrate(t *testing.T) {
|
|||
Proposals: []v036gov.Proposal{
|
||||
{
|
||||
Content: v036gov.TextProposal{
|
||||
Title: "foo_test",
|
||||
Description: "bar_test",
|
||||
Title: "foo_text",
|
||||
Description: "bar_text",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -40,6 +42,37 @@ func TestMigrate(t *testing.T) {
|
|||
Amount: sdk.NewCoins(sdk.NewCoin("footoken", sdk.NewInt(2))),
|
||||
},
|
||||
},
|
||||
{
|
||||
Content: v038upgrade.CancelSoftwareUpgradeProposal{
|
||||
Title: "foo_cancel_upgrade",
|
||||
Description: "bar_cancel_upgrade",
|
||||
},
|
||||
},
|
||||
{
|
||||
Content: v038upgrade.SoftwareUpgradeProposal{
|
||||
Title: "foo_software_upgrade",
|
||||
Description: "bar_software_upgrade",
|
||||
Plan: v038upgrade.Plan{
|
||||
Name: "foo_upgrade_name",
|
||||
Height: 123,
|
||||
Info: "foo_upgrade_info",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Content: v036params.ParameterChangeProposal{
|
||||
Title: "foo_param_change",
|
||||
Description: "bar_param_change",
|
||||
Changes: []v036params.ParamChange{
|
||||
{
|
||||
Subspace: "foo_param_change_subspace",
|
||||
Key: "foo_param_change_key",
|
||||
Subkey: "foo_param_change_subkey",
|
||||
Value: "foo_param_change_value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -52,76 +85,154 @@ func TestMigrate(t *testing.T) {
|
|||
var jsonObj map[string]interface{}
|
||||
err = json.Unmarshal(bz, &jsonObj)
|
||||
require.NoError(t, err)
|
||||
indentedBz, err := json.MarshalIndent(jsonObj, "", " ")
|
||||
indentedBz, err := json.MarshalIndent(jsonObj, "", "\t")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure about:
|
||||
// - TextProposal and CommunityPoolSpendProposal have correct any JSON.
|
||||
// - TextProposal has correct JSON.
|
||||
// - CommunityPoolSpendProposal has correct JSON.
|
||||
// - CancelSoftwareUpgradeProposal has correct JSON.
|
||||
// - SoftwareUpgradeProposal has correct JSON.
|
||||
// - ParameterChangeProposal has correct JSON.
|
||||
expected := `{
|
||||
"deposit_params": {
|
||||
"max_deposit_period": "0s",
|
||||
"min_deposit": []
|
||||
},
|
||||
"deposits": [],
|
||||
"proposals": [
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.gov.v1beta1.TextProposal",
|
||||
"description": "bar_test",
|
||||
"title": "foo_test"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.distribution.v1beta1.CommunityPoolSpendProposal",
|
||||
"amount": [
|
||||
{
|
||||
"amount": "2",
|
||||
"denom": "footoken"
|
||||
}
|
||||
],
|
||||
"description": "bar_community",
|
||||
"recipient": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
|
||||
"title": "foo_community"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"starting_proposal_id": "0",
|
||||
"tally_params": {
|
||||
"quorum": "0",
|
||||
"threshold": "0",
|
||||
"veto_threshold": "0"
|
||||
},
|
||||
"votes": [],
|
||||
"voting_params": {
|
||||
"voting_period": "0s"
|
||||
}
|
||||
"deposit_params": {
|
||||
"max_deposit_period": "0s",
|
||||
"min_deposit": []
|
||||
},
|
||||
"deposits": [],
|
||||
"proposals": [
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.gov.v1beta1.TextProposal",
|
||||
"description": "bar_text",
|
||||
"title": "foo_text"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.distribution.v1beta1.CommunityPoolSpendProposal",
|
||||
"amount": [
|
||||
{
|
||||
"amount": "2",
|
||||
"denom": "footoken"
|
||||
}
|
||||
],
|
||||
"description": "bar_community",
|
||||
"recipient": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
|
||||
"title": "foo_community"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.upgrade.v1beta1.CancelSoftwareUpgradeProposal",
|
||||
"description": "bar_cancel_upgrade",
|
||||
"title": "foo_cancel_upgrade"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.upgrade.v1beta1.SoftwareUpgradeProposal",
|
||||
"description": "bar_software_upgrade",
|
||||
"plan": {
|
||||
"height": "123",
|
||||
"info": "foo_upgrade_info",
|
||||
"name": "foo_upgrade_name",
|
||||
"time": "0001-01-01T00:00:00Z",
|
||||
"upgraded_client_state": null
|
||||
},
|
||||
"title": "foo_software_upgrade"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"content": {
|
||||
"@type": "/cosmos.params.v1beta1.ParameterChangeProposal",
|
||||
"changes": [
|
||||
{
|
||||
"key": "foo_param_change_key",
|
||||
"subspace": "foo_param_change_subspace",
|
||||
"value": "foo_param_change_value"
|
||||
}
|
||||
],
|
||||
"description": "bar_param_change",
|
||||
"title": "foo_param_change"
|
||||
},
|
||||
"deposit_end_time": "0001-01-01T00:00:00Z",
|
||||
"final_tally_result": {
|
||||
"abstain": "0",
|
||||
"no": "0",
|
||||
"no_with_veto": "0",
|
||||
"yes": "0"
|
||||
},
|
||||
"proposal_id": "0",
|
||||
"status": "PROPOSAL_STATUS_UNSPECIFIED",
|
||||
"submit_time": "0001-01-01T00:00:00Z",
|
||||
"total_deposit": [],
|
||||
"voting_end_time": "0001-01-01T00:00:00Z",
|
||||
"voting_start_time": "0001-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"starting_proposal_id": "0",
|
||||
"tally_params": {
|
||||
"quorum": "0",
|
||||
"threshold": "0",
|
||||
"veto_threshold": "0"
|
||||
},
|
||||
"votes": [],
|
||||
"voting_params": {
|
||||
"voting_period": "0s"
|
||||
}
|
||||
}`
|
||||
|
||||
require.Equal(t, expected, string(indentedBz))
|
||||
|
|
|
@ -46,7 +46,7 @@ to the counterparty channel. Any timeout set to 0 is disabled.`),
|
|||
srcChannel := args[1]
|
||||
receiver := args[2]
|
||||
|
||||
coin, err := sdk.ParseCoin(args[3])
|
||||
coin, err := sdk.ParseCoinNormalized(args[3])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
|
@ -182,6 +183,42 @@ func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.Weig
|
|||
|
||||
//____________________________________________________________________________
|
||||
|
||||
// ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer
|
||||
// channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current
|
||||
// supported version. Only 2^32 channels are allowed to be created.
|
||||
func ValidateTransferChannelParams(
|
||||
ctx sdk.Context,
|
||||
keeper keeper.Keeper,
|
||||
order channeltypes.Order,
|
||||
portID string,
|
||||
channelID string,
|
||||
version string,
|
||||
) error {
|
||||
// NOTE: for escrow address security only 2^32 channels are allowed to be created
|
||||
// Issue: https://github.com/cosmos/cosmos-sdk/issues/7737
|
||||
channelSequence, err := channeltypes.ParseChannelSequence(channelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if channelSequence > math.MaxUint32 {
|
||||
return sdkerrors.Wrapf(types.ErrMaxTransferChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, math.MaxUint32)
|
||||
}
|
||||
if order != channeltypes.UNORDERED {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order)
|
||||
}
|
||||
|
||||
// Require portID is the portID transfer module is bound to
|
||||
boundPort := keeper.GetPort(ctx)
|
||||
if boundPort != portID {
|
||||
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort)
|
||||
}
|
||||
|
||||
if version != types.Version {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnChanOpenInit implements the IBCModule interface
|
||||
func (am AppModule) OnChanOpenInit(
|
||||
ctx sdk.Context,
|
||||
|
@ -193,18 +230,8 @@ func (am AppModule) OnChanOpenInit(
|
|||
counterparty channeltypes.Counterparty,
|
||||
version string,
|
||||
) error {
|
||||
if order != channeltypes.UNORDERED {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order)
|
||||
}
|
||||
|
||||
// Require portID is the portID transfer module is bound to
|
||||
boundPort := am.keeper.GetPort(ctx)
|
||||
if boundPort != portID {
|
||||
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort)
|
||||
}
|
||||
|
||||
if version != types.Version {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
|
||||
if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Claim channel capability passed back by IBC module
|
||||
|
@ -227,18 +254,8 @@ func (am AppModule) OnChanOpenTry(
|
|||
version,
|
||||
counterpartyVersion string,
|
||||
) error {
|
||||
if order != channeltypes.UNORDERED {
|
||||
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order)
|
||||
}
|
||||
|
||||
// Require portID is the portID transfer module is bound to
|
||||
boundPort := am.keeper.GetPort(ctx)
|
||||
if boundPort != portID {
|
||||
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort)
|
||||
}
|
||||
|
||||
if version != types.Version {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got: %s, expected %s", version, types.Version)
|
||||
if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if counterpartyVersion != types.Version {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package transfer_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
|
||||
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
|
||||
|
@ -26,6 +28,11 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() {
|
|||
{
|
||||
"success", func() {}, true,
|
||||
},
|
||||
{
|
||||
"max channels reached", func() {
|
||||
testChannel.ID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1)
|
||||
}, false,
|
||||
},
|
||||
{
|
||||
"invalid order - ORDERED", func() {
|
||||
channel.Ordering = channeltypes.ORDERED
|
||||
|
@ -109,6 +116,11 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() {
|
|||
{
|
||||
"success", func() {}, true,
|
||||
},
|
||||
{
|
||||
"max channels reached", func() {
|
||||
testChannel.ID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1)
|
||||
}, false,
|
||||
},
|
||||
{
|
||||
"capability already claimed in INIT should pass", func() {
|
||||
err := suite.chainA.App.ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(testChannel.PortID, testChannel.ID))
|
||||
|
|
|
@ -13,4 +13,5 @@ var (
|
|||
ErrTraceNotFound = sdkerrors.Register(ModuleName, 6, "denomination trace not found")
|
||||
ErrSendDisabled = sdkerrors.Register(ModuleName, 7, "fungible token transfers from this chain are disabled")
|
||||
ErrReceiveDisabled = sdkerrors.Register(ModuleName, 8, "fungible token transfers to this chain are disabled")
|
||||
ErrMaxTransferChannels = sdkerrors.Register(ModuleName, 9, "max transfer channels")
|
||||
)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -39,11 +38,18 @@ var (
|
|||
DenomTraceKey = []byte{0x02}
|
||||
)
|
||||
|
||||
// GetEscrowAddress returns the escrow address for the specified channel
|
||||
//
|
||||
// CONTRACT: this assumes that there's only one bank bridge module that owns the
|
||||
// port associated with the channel ID so that the address created is actually
|
||||
// unique.
|
||||
// GetEscrowAddress returns the escrow address for the specified channel.
|
||||
// The escrow address follows the format as outlined in ADR 028:
|
||||
// https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md
|
||||
func GetEscrowAddress(portID, channelID string) sdk.AccAddress {
|
||||
return sdk.AccAddress(crypto.AddressHash([]byte(fmt.Sprintf("%s/%s", portID, channelID))))
|
||||
// a slash is used to create domain separation between port and channel identifiers to
|
||||
// prevent address collisions between escrow addresses created for different channels
|
||||
contents := fmt.Sprintf("%s/%s", portID, channelID)
|
||||
|
||||
// ADR 028 AddressHash construction
|
||||
preImage := []byte(Version)
|
||||
preImage = append(preImage, 0)
|
||||
preImage = append(preImage, contents...)
|
||||
hash := sha256.Sum256(preImage)
|
||||
return hash[:20]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
package v036
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
)
|
||||
|
||||
const (
|
||||
// ModuleName defines the name of the module
|
||||
ModuleName = "params"
|
||||
|
||||
// RouterKey defines the routing key for a ParameterChangeProposal
|
||||
RouterKey = "params"
|
||||
)
|
||||
|
||||
const (
|
||||
// ProposalTypeChange defines the type for a ParameterChangeProposal
|
||||
ProposalTypeChange = "ParameterChange"
|
||||
)
|
||||
|
||||
// Param module codespace constants
|
||||
const (
|
||||
DefaultCodespace = "params"
|
||||
|
||||
CodeUnknownSubspace = 1
|
||||
CodeSettingParameter = 2
|
||||
CodeEmptyData = 3
|
||||
)
|
||||
|
||||
// Assert ParameterChangeProposal implements v036gov.Content at compile-time
|
||||
var _ v036gov.Content = ParameterChangeProposal{}
|
||||
|
||||
// ParameterChangeProposal defines a proposal which contains multiple parameter
|
||||
// changes.
|
||||
type ParameterChangeProposal struct {
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Changes []ParamChange `json:"changes" yaml:"changes"`
|
||||
}
|
||||
|
||||
func NewParameterChangeProposal(title, description string, changes []ParamChange) ParameterChangeProposal {
|
||||
return ParameterChangeProposal{title, description, changes}
|
||||
}
|
||||
|
||||
// GetTitle returns the title of a parameter change proposal.
|
||||
func (pcp ParameterChangeProposal) GetTitle() string { return pcp.Title }
|
||||
|
||||
// GetDescription returns the description of a parameter change proposal.
|
||||
func (pcp ParameterChangeProposal) GetDescription() string { return pcp.Description }
|
||||
|
||||
// GetDescription returns the routing key of a parameter change proposal.
|
||||
func (pcp ParameterChangeProposal) ProposalRoute() string { return RouterKey }
|
||||
|
||||
// ProposalType returns the type of a parameter change proposal.
|
||||
func (pcp ParameterChangeProposal) ProposalType() string { return ProposalTypeChange }
|
||||
|
||||
// ValidateBasic validates the parameter change proposal
|
||||
func (pcp ParameterChangeProposal) ValidateBasic() error {
|
||||
err := v036gov.ValidateAbstract(pcp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ValidateChanges(pcp.Changes)
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (pcp ParameterChangeProposal) String() string {
|
||||
var b strings.Builder
|
||||
|
||||
b.WriteString(fmt.Sprintf(`Parameter Change Proposal:
|
||||
Title: %s
|
||||
Description: %s
|
||||
Changes:
|
||||
`, pcp.Title, pcp.Description))
|
||||
|
||||
for _, pc := range pcp.Changes {
|
||||
b.WriteString(fmt.Sprintf(` Param Change:
|
||||
Subspace: %s
|
||||
Key: %s
|
||||
Subkey: %X
|
||||
Value: %X
|
||||
`, pc.Subspace, pc.Key, pc.Subkey, pc.Value))
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// ParamChange defines a parameter change.
|
||||
type ParamChange struct {
|
||||
Subspace string `json:"subspace" yaml:"subspace"`
|
||||
Key string `json:"key" yaml:"key"`
|
||||
Subkey string `json:"subkey,omitempty" yaml:"subkey,omitempty"`
|
||||
Value string `json:"value" yaml:"value"`
|
||||
}
|
||||
|
||||
func NewParamChange(subspace, key, value string) ParamChange {
|
||||
return ParamChange{subspace, key, "", value}
|
||||
}
|
||||
|
||||
func NewParamChangeWithSubkey(subspace, key, subkey, value string) ParamChange {
|
||||
return ParamChange{subspace, key, subkey, value}
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (pc ParamChange) String() string {
|
||||
return fmt.Sprintf(`Param Change:
|
||||
Subspace: %s
|
||||
Key: %s
|
||||
Subkey: %X
|
||||
Value: %X
|
||||
`, pc.Subspace, pc.Key, pc.Subkey, pc.Value)
|
||||
}
|
||||
|
||||
// ValidateChange performs basic validation checks over a set of ParamChange. It
|
||||
// returns an error if any ParamChange is invalid.
|
||||
func ValidateChanges(changes []ParamChange) error {
|
||||
if len(changes) == 0 {
|
||||
return ErrEmptyChanges(DefaultCodespace)
|
||||
}
|
||||
|
||||
for _, pc := range changes {
|
||||
if len(pc.Subspace) == 0 {
|
||||
return ErrEmptySubspace(DefaultCodespace)
|
||||
}
|
||||
if len(pc.Key) == 0 {
|
||||
return ErrEmptyKey(DefaultCodespace)
|
||||
}
|
||||
if len(pc.Value) == 0 {
|
||||
return ErrEmptyValue(DefaultCodespace)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ErrUnknownSubspace returns an unknown subspace error.
|
||||
func ErrUnknownSubspace(codespace string, space string) error {
|
||||
return fmt.Errorf("unknown subspace %s", space)
|
||||
}
|
||||
|
||||
// ErrSettingParameter returns an error for failing to set a parameter.
|
||||
func ErrSettingParameter(codespace string, key, subkey, value, msg string) error {
|
||||
return fmt.Errorf("error setting parameter %s on %s (%s): %s", value, key, subkey, msg)
|
||||
}
|
||||
|
||||
// ErrEmptyChanges returns an error for empty parameter changes.
|
||||
func ErrEmptyChanges(codespace string) error {
|
||||
return fmt.Errorf("submitted parameter changes are empty")
|
||||
}
|
||||
|
||||
// ErrEmptySubspace returns an error for an empty subspace.
|
||||
func ErrEmptySubspace(codespace string) error {
|
||||
return fmt.Errorf("parameter subspace is empty")
|
||||
}
|
||||
|
||||
// ErrEmptyKey returns an error for when an empty key is given.
|
||||
func ErrEmptyKey(codespace string) error {
|
||||
return fmt.Errorf("parameter key is empty")
|
||||
}
|
||||
|
||||
// ErrEmptyValue returns an error for when an empty key is given.
|
||||
func ErrEmptyValue(codespace string) error {
|
||||
return fmt.Errorf("parameter value is empty")
|
||||
}
|
||||
|
||||
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
cdc.RegisterConcrete(ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal", nil)
|
||||
}
|
|
@ -51,7 +51,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
_, err := s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
unbond, err := sdk.ParseCoin("10stake")
|
||||
unbond, err := sdk.ParseCoinNormalized("10stake")
|
||||
s.Require().NoError(err)
|
||||
|
||||
val := s.network.Validators[0]
|
||||
|
|
|
@ -172,7 +172,7 @@ $ %s tx staking delegate %s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --f
|
|||
return err
|
||||
}
|
||||
|
||||
amount, err := sdk.ParseCoin(args[1])
|
||||
amount, err := sdk.ParseCoinNormalized(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ $ %s tx staking redelegate %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj %s1l2rsakp3
|
|||
return err
|
||||
}
|
||||
|
||||
amount, err := sdk.ParseCoin(args[2])
|
||||
amount, err := sdk.ParseCoinNormalized(args[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from
|
|||
return err
|
||||
}
|
||||
|
||||
amount, err := sdk.ParseCoin(args[1])
|
||||
amount, err := sdk.ParseCoinNormalized(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ $ %s tx staking unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from
|
|||
|
||||
func NewBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, sdk.Msg, error) {
|
||||
fAmount, _ := fs.GetString(FlagAmount)
|
||||
amount, err := sdk.ParseCoin(fAmount)
|
||||
amount, err := sdk.ParseCoinNormalized(fAmount)
|
||||
if err != nil {
|
||||
return txf, nil, err
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ func PrepareConfigForTxCreateValidator(flagSet *flag.FlagSet, moniker, nodeID, c
|
|||
// BuildCreateValidatorMsg makes a new MsgCreateValidator.
|
||||
func BuildCreateValidatorMsg(clientCtx client.Context, config TxCreateValidatorConfig, txBldr tx.Factory, generateOnly bool) (tx.Factory, sdk.Msg, error) {
|
||||
amounstStr := config.Amount
|
||||
amount, err := sdk.ParseCoin(amounstStr)
|
||||
amount, err := sdk.ParseCoinNormalized(amounstStr)
|
||||
|
||||
if err != nil {
|
||||
return txBldr, nil, err
|
||||
|
|
|
@ -39,7 +39,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
|
|||
_, err := s.network.WaitForHeight(1)
|
||||
s.Require().NoError(err)
|
||||
|
||||
unbond, err := sdk.ParseCoin("10stake")
|
||||
unbond, err := sdk.ParseCoinNormalized("10stake")
|
||||
s.Require().NoError(err)
|
||||
|
||||
val := s.network.Validators[0]
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
package v038
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
v036gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v036"
|
||||
)
|
||||
|
||||
const (
|
||||
// ModuleName is the name of this module
|
||||
ModuleName = "upgrade"
|
||||
|
||||
// RouterKey is used to route governance proposals
|
||||
RouterKey = ModuleName
|
||||
|
||||
// StoreKey is the prefix under which we store this module's data
|
||||
StoreKey = ModuleName
|
||||
|
||||
// QuerierKey is used to handle abci_query requests
|
||||
QuerierKey = ModuleName
|
||||
)
|
||||
|
||||
// Plan specifies information about a planned upgrade and when it should occur
|
||||
type Plan struct {
|
||||
// Sets the name for the upgrade. This name will be used by the upgraded version of the software to apply any
|
||||
// special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is also used
|
||||
// to detect whether a software version can handle a given upgrade. If no upgrade handler with this name has been
|
||||
// set in the software, it will be assumed that the software is out-of-date when the upgrade Time or Height
|
||||
// is reached and the software will exit.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// The time after which the upgrade must be performed.
|
||||
// Leave set to its zero value to use a pre-defined Height instead.
|
||||
Time time.Time `json:"time,omitempty"`
|
||||
|
||||
// The height at which the upgrade must be performed.
|
||||
// Only used if Time is not set.
|
||||
Height int64 `json:"height,omitempty"`
|
||||
|
||||
// Any application specific upgrade info to be included on-chain
|
||||
// such as a git commit that validators could automatically upgrade to
|
||||
Info string `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
func (p Plan) String() string {
|
||||
due := p.DueAt()
|
||||
dueUp := strings.ToUpper(due[0:1]) + due[1:]
|
||||
return fmt.Sprintf(`Upgrade Plan
|
||||
Name: %s
|
||||
%s
|
||||
Info: %s`, p.Name, dueUp, p.Info)
|
||||
}
|
||||
|
||||
// ValidateBasic does basic validation of a Plan
|
||||
func (p Plan) ValidateBasic() error {
|
||||
if len(p.Name) == 0 {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name cannot be empty")
|
||||
}
|
||||
if p.Height < 0 {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "height cannot be negative")
|
||||
}
|
||||
if p.Time.IsZero() && p.Height == 0 {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must set either time or height")
|
||||
}
|
||||
if !p.Time.IsZero() && p.Height != 0 {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot set both time and height")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ShouldExecute returns true if the Plan is ready to execute given the current context
|
||||
func (p Plan) ShouldExecute(ctx sdk.Context) bool {
|
||||
if !p.Time.IsZero() {
|
||||
return !ctx.BlockTime().Before(p.Time)
|
||||
}
|
||||
if p.Height > 0 {
|
||||
return p.Height <= ctx.BlockHeight()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DueAt is a string representation of when this plan is due to be executed
|
||||
func (p Plan) DueAt() string {
|
||||
if !p.Time.IsZero() {
|
||||
return fmt.Sprintf("time: %s", p.Time.UTC().Format(time.RFC3339))
|
||||
}
|
||||
return fmt.Sprintf("height: %d", p.Height)
|
||||
}
|
||||
|
||||
const (
|
||||
ProposalTypeSoftwareUpgrade string = "SoftwareUpgrade"
|
||||
ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade"
|
||||
)
|
||||
|
||||
// Software Upgrade Proposals
|
||||
type SoftwareUpgradeProposal struct {
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Plan Plan `json:"plan" yaml:"plan"`
|
||||
}
|
||||
|
||||
func NewSoftwareUpgradeProposal(title, description string, plan Plan) v036gov.Content {
|
||||
return SoftwareUpgradeProposal{title, description, plan}
|
||||
}
|
||||
|
||||
// Implements Proposal Interface
|
||||
var _ v036gov.Content = SoftwareUpgradeProposal{}
|
||||
|
||||
func (sup SoftwareUpgradeProposal) GetTitle() string { return sup.Title }
|
||||
func (sup SoftwareUpgradeProposal) GetDescription() string { return sup.Description }
|
||||
func (sup SoftwareUpgradeProposal) ProposalRoute() string { return RouterKey }
|
||||
func (sup SoftwareUpgradeProposal) ProposalType() string { return ProposalTypeSoftwareUpgrade }
|
||||
func (sup SoftwareUpgradeProposal) ValidateBasic() error {
|
||||
if err := sup.Plan.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
return v036gov.ValidateAbstract(sup)
|
||||
}
|
||||
|
||||
func (sup SoftwareUpgradeProposal) String() string {
|
||||
return fmt.Sprintf(`Software Upgrade Proposal:
|
||||
Title: %s
|
||||
Description: %s
|
||||
`, sup.Title, sup.Description)
|
||||
}
|
||||
|
||||
// Cancel Software Upgrade Proposals
|
||||
type CancelSoftwareUpgradeProposal struct {
|
||||
Title string `json:"title" yaml:"title"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
}
|
||||
|
||||
func NewCancelSoftwareUpgradeProposal(title, description string) v036gov.Content {
|
||||
return CancelSoftwareUpgradeProposal{title, description}
|
||||
}
|
||||
|
||||
// Implements Proposal Interface
|
||||
var _ v036gov.Content = CancelSoftwareUpgradeProposal{}
|
||||
|
||||
func (sup CancelSoftwareUpgradeProposal) GetTitle() string { return sup.Title }
|
||||
func (sup CancelSoftwareUpgradeProposal) GetDescription() string { return sup.Description }
|
||||
func (sup CancelSoftwareUpgradeProposal) ProposalRoute() string { return RouterKey }
|
||||
func (sup CancelSoftwareUpgradeProposal) ProposalType() string {
|
||||
return ProposalTypeCancelSoftwareUpgrade
|
||||
}
|
||||
func (sup CancelSoftwareUpgradeProposal) ValidateBasic() error {
|
||||
return v036gov.ValidateAbstract(sup)
|
||||
}
|
||||
|
||||
func (sup CancelSoftwareUpgradeProposal) String() string {
|
||||
return fmt.Sprintf(`Cancel Software Upgrade Proposal:
|
||||
Title: %s
|
||||
Description: %s
|
||||
`, sup.Title, sup.Description)
|
||||
}
|
||||
|
||||
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
cdc.RegisterConcrete(SoftwareUpgradeProposal{}, "cosmos-sdk/SoftwareUpgradeProposal", nil)
|
||||
cdc.RegisterConcrete(CancelSoftwareUpgradeProposal{}, "cosmos-sdk/CancelSoftwareUpgradeProposal", nil)
|
||||
}
|
Loading…
Reference in New Issue