diff --git a/.circleci/config.yml b/.circleci/config.yml index a6f67a43c02b..04ec877e3f9f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,9 @@ executors: - image: tendermintdev/docker-website-deployment environment: AWS_REGION: us-east-1 + protoc: + docker: + - image: tendermintdev/docker-protoc commands: make: @@ -73,6 +76,15 @@ jobs: key: go-src-v1-{{ .Revision }} paths: - ".git" + proto: + executor: protoc + steps: + - make: + target: protoc-gen-gocosmos + description: "Generate go plugin for protoc" + - make: + target: proto-gen proto-lint proto-check-breaking + description: "Lint and verify Protocol Buffer definitions" test-sim-nondeterminism: executor: golang @@ -182,6 +194,9 @@ workflows: tags: only: - /^v.*/ + - proto: + requires: + - setup-dependencies - test-sim-nondeterminism: requires: - setup-dependencies diff --git a/Makefile b/Makefile index 8d947640f75a..03abf9fa66a8 100644 --- a/Makefile +++ b/Makefile @@ -11,28 +11,19 @@ MOCKS_DIR = $(CURDIR)/tests/mocks export GO111MODULE = on -all: tools build lint test - # The below include contains the tools and runsim targets. include contrib/devtools/Makefile -######################################## -### Build +all: tools build lint test + +############################################################################### +### Build ### +############################################################################### build: go.sum @go build -mod=readonly ./... .PHONY: build -update-swagger-docs: statik - $(BINDIR)/statik -src=client/lcd/swagger-ui -dest=client/lcd -f -m - @if [ -n "$(git status --porcelain)" ]; then \ - echo "\033[91mSwagger docs are out of sync!!!\033[0m";\ - exit 1;\ - else \ - echo "\033[92mSwagger docs are in sync\033[0m";\ - fi -.PHONY: update-swagger-docs - mocks: $(MOCKS_DIR) mockgen -source=x/auth/types/account_retriever.go -package mocks -destination tests/mocks/account_retriever.go .PHONY: mocks @@ -40,8 +31,17 @@ mocks: $(MOCKS_DIR) $(MOCKS_DIR): mkdir -p $(MOCKS_DIR) -######################################## -### Tools & dependencies +distclean: + rm -rf \ + gitian-build-darwin/ \ + gitian-build-linux/ \ + gitian-build-windows/ \ + .gitian-builder-cache/ +.PHONY: distclean + +############################################################################### +### Tools & Dependencies ### +############################################################################### go-mod-cache: go.sum @echo "--> Download go modules to local cache" @@ -53,16 +53,19 @@ go.sum: go.mod @go mod verify @go mod tidy -distclean: - rm -rf \ - gitian-build-darwin/ \ - gitian-build-linux/ \ - gitian-build-windows/ \ - .gitian-builder-cache/ -.PHONY: distclean +############################################################################### +### Documentation ### +############################################################################### -######################################## -### Documentation +update-swagger-docs: statik + $(BINDIR)/statik -src=client/lcd/swagger-ui -dest=client/lcd -f -m + @if [ -n "$(git status --porcelain)" ]; then \ + echo "\033[91mSwagger docs are out of sync!!!\033[0m";\ + exit 1;\ + else \ + echo "\033[92mSwagger docs are in sync\033[0m";\ + fi +.PHONY: update-swagger-docs godocs: @echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/cosmos-sdk/types" @@ -85,8 +88,9 @@ sync-docs: aws cloudfront create-invalidation --distribution-id ${CF_DISTRIBUTION_ID} --profile terraform --path "/*" ; .PHONY: sync-docs -######################################## -### Testing +############################################################################### +### Tests & Simulation ### +############################################################################### test: test-unit test-all: test-unit test-ledger-mock test-race test-cover @@ -173,6 +177,14 @@ test-cover: @export VERSION=$(VERSION); bash -x tests/test_cover.sh .PHONY: test-cover +benchmark: + @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) +.PHONY: benchmark + +############################################################################### +### Linting ### +############################################################################### + lint: golangci-lint $(BINDIR)/golangci-lint run find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s @@ -185,12 +197,9 @@ format: tools find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs goimports -w -local github.com/cosmos/cosmos-sdk .PHONY: format -benchmark: - @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) -.PHONY: benchmark - -######################################## -### Devdoc +############################################################################### +### Devdoc ### +############################################################################### DEVDOC_SAVE = docker commit `docker ps -a -n 1 -q` devdoc:local @@ -213,3 +222,20 @@ devdoc-update: docker pull tendermint/devdoc .PHONY: devdoc devdoc-clean devdoc-init devdoc-save devdoc-update + +############################################################################### +### Protobuf ### +############################################################################### + +proto-all: proto-gen proto-lint proto-check-breaking + +proto-gen: + @./scripts/protocgen.sh + +proto-lint: + @buf check lint --error-format=json + +proto-check-breaking: + @buf check breaking --against-input '.git#branch=master' + +.PHONY: proto-all proto-gen proto-lint proto-check-breaking diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 000000000000..8507c9cd41c0 --- /dev/null +++ b/buf.yaml @@ -0,0 +1,19 @@ +build: + roots: + - . +lint: + use: + - DEFAULT + - COMMENTS + - FILE_LOWER_SNAKE_CASE + except: + - UNARY_RPC + - COMMENT_FIELD + - PACKAGE_DIRECTORY_MATCH + ignore: + - third_party +breaking: + use: + - FILE + ignore: + - third_party diff --git a/codec/amino.go b/codec/amino.go new file mode 100644 index 000000000000..b2300aef6cc3 --- /dev/null +++ b/codec/amino.go @@ -0,0 +1,70 @@ +package codec + +import ( + "bytes" + "encoding/json" + "fmt" + + amino "github.com/tendermint/go-amino" + cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino" + tmtypes "github.com/tendermint/tendermint/types" +) + +// Cdc defines a global generic sealed Amino codec to be used throughout sdk. It +// has all Tendermint crypto and evidence types registered. +// +// TODO: Consider removing this global. +var Cdc *Codec + +func init() { + cdc := New() + RegisterCrypto(cdc) + RegisterEvidences(cdc) + Cdc = cdc.Seal() +} + +// Codec defines a type alias for an Amino codec. +type Codec = amino.Codec + +func New() *Codec { + return amino.NewCodec() +} + +// RegisterCrypto registers all crypto dependency types with the provided Amino +// codec. +func RegisterCrypto(cdc *Codec) { + cryptoamino.RegisterAmino(cdc) +} + +// RegisterEvidences registers Tendermint evidence types with the provided Amino +// codec. +func RegisterEvidences(cdc *Codec) { + tmtypes.RegisterEvidences(cdc) +} + +// MarshalJSONIndent provides a utility for indented JSON encoding of an object +// via an Amino codec. It returns an error if it cannot serialize or indent as +// JSON. +func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { + bz, err := cdc.MarshalJSON(obj) + if err != nil { + return nil, err + } + + var out bytes.Buffer + if err = json.Indent(&out, bz, "", " "); err != nil { + return nil, err + } + + return out.Bytes(), nil +} + +// MustMarshalJSONIndent executes MarshalJSONIndent except it panics upon failure. +func MustMarshalJSONIndent(cdc *Codec, obj interface{}) []byte { + bz, err := MarshalJSONIndent(cdc, obj) + if err != nil { + panic(fmt.Sprintf("failed to marshal JSON: %s", err)) + } + + return bz +} diff --git a/codec/amino_codec.go b/codec/amino_codec.go new file mode 100644 index 000000000000..185c441366b3 --- /dev/null +++ b/codec/amino_codec.go @@ -0,0 +1,59 @@ +package codec + +// AminoCodec defines a codec that utilizes Amino for both binary and JSON +// encoding. +type AminoCodec struct { + amino *Codec +} + +func NewAminoCodec(amino *Codec) Marshaler { + return &AminoCodec{amino} +} + +func (ac *AminoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return ac.amino.MarshalBinaryBare(o) +} + +func (ac *AminoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + return ac.amino.MustMarshalBinaryBare(o) +} + +func (ac *AminoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + return ac.amino.MarshalBinaryLengthPrefixed(o) +} + +func (ac *AminoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + return ac.amino.MustMarshalBinaryLengthPrefixed(o) +} + +func (ac *AminoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return ac.amino.UnmarshalBinaryBare(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + ac.amino.MustUnmarshalBinaryBare(bz, ptr) +} + +func (ac *AminoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + return ac.amino.UnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + ac.amino.MustUnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (ac *AminoCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + return ac.amino.MarshalJSON(o) +} + +func (ac *AminoCodec) MustMarshalJSON(o interface{}) []byte { + return ac.amino.MustMarshalJSON(o) +} + +func (ac *AminoCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + return ac.amino.UnmarshalJSON(bz, ptr) +} + +func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + ac.amino.MustUnmarshalJSON(bz, ptr) +} diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go new file mode 100644 index 000000000000..31eeb413e828 --- /dev/null +++ b/codec/amino_codec_test.go @@ -0,0 +1,118 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" + amino "github.com/tendermint/go-amino" +) + +func createTestCodec() *amino.Codec { + cdc := amino.NewCodec() + + cdc.RegisterInterface((*testdata.Animal)(nil), nil) + cdc.RegisterConcrete(testdata.Dog{}, "testdata/Dog", nil) + cdc.RegisterConcrete(testdata.Cat{}, "testdata/Cat", nil) + + return cdc +} + +func TestAminoCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewAminoCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewAminoCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/codec.go b/codec/codec.go index 6cf2f623d7e4..203a1ec1bbb6 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -1,65 +1,60 @@ package codec import ( - "bytes" - "encoding/json" - "fmt" + "encoding/binary" + "io" - amino "github.com/tendermint/go-amino" - cryptoamino "github.com/tendermint/tendermint/crypto/encoding/amino" - tmtypes "github.com/tendermint/tendermint/types" + "github.com/gogo/protobuf/proto" ) -// amino codec to marshal/unmarshal -type Codec = amino.Codec - -func New() *Codec { - return amino.NewCodec() -} - -// Register the go-crypto to the codec -func RegisterCrypto(cdc *Codec) { - cryptoamino.RegisterAmino(cdc) -} - -// RegisterEvidences registers Tendermint evidence types with the provided codec. -func RegisterEvidences(cdc *Codec) { - tmtypes.RegisterEvidences(cdc) -} - -// attempt to make some pretty json -func MarshalJSONIndent(cdc *Codec, obj interface{}) ([]byte, error) { - bz, err := cdc.MarshalJSON(obj) - if err != nil { - return nil, err +type ( + // Marshaler defines the interface module codecs must implement in order to support + // backwards compatibility with Amino while allowing custom Protobuf-based + // serialization. Note, Amino can still be used without any dependency on + // Protobuf. There are three typical implementations that fulfill this contract: + // + // 1. AminoCodec: Provides full Amino serialization compatibility. + // 2. ProtoCodec: Provides full Protobuf serialization compatibility. + // 3. HybridCodec: Provides Protobuf serialization for binary encoding and Amino + // for JSON encoding. + Marshaler interface { + MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) + MustMarshalBinaryBare(o ProtoMarshaler) []byte + + MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) + MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte + + UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error + MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) + + UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error + MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) + + MarshalJSON(o interface{}) ([]byte, error) // nolint: stdmethods + MustMarshalJSON(o interface{}) []byte + + UnmarshalJSON(bz []byte, ptr interface{}) error // nolint: stdmethods + MustUnmarshalJSON(bz []byte, ptr interface{}) } - var out bytes.Buffer - err = json.Indent(&out, bz, "", " ") - if err != nil { - return nil, err - } - return out.Bytes(), nil -} + // ProtoMarshaler defines an interface a type must implement as protocol buffer + // defined message. + ProtoMarshaler interface { + proto.Message // for JSON serialization -// MustMarshalJSONIndent executes MarshalJSONIndent except it panics upon failure. -func MustMarshalJSONIndent(cdc *Codec, obj interface{}) []byte { - bz, err := MarshalJSONIndent(cdc, obj) - if err != nil { - panic(fmt.Sprintf("failed to marshal JSON: %s", err)) + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + MarshalToSizedBuffer(dAtA []byte) (int, error) + Size() int + Unmarshal(data []byte) error } +) - return bz -} - -//__________________________________________________________________ +func encodeUvarint(w io.Writer, u uint64) (err error) { + var buf [10]byte -// generic sealed codec to be used throughout sdk -var Cdc *Codec + n := binary.PutUvarint(buf[:], u) + _, err = w.Write(buf[0:n]) -func init() { - cdc := New() - RegisterCrypto(cdc) - RegisterEvidences(cdc) - Cdc = cdc.Seal() + return err } diff --git a/codec/hybrid_codec.go b/codec/hybrid_codec.go new file mode 100644 index 000000000000..c004df1425ce --- /dev/null +++ b/codec/hybrid_codec.go @@ -0,0 +1,63 @@ +package codec + +// HybridCodec defines a codec that utilizes Protobuf for binary encoding +// and Amino for JSON encoding. +type HybridCodec struct { + proto Marshaler + amino Marshaler +} + +func NewHybridCodec(amino *Codec) Marshaler { + return &HybridCodec{ + proto: NewProtoCodec(), + amino: NewAminoCodec(amino), + } +} + +func (hc *HybridCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return hc.proto.MarshalBinaryBare(o) +} + +func (hc *HybridCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + return hc.proto.MustMarshalBinaryBare(o) +} + +func (hc *HybridCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + return hc.proto.MarshalBinaryLengthPrefixed(o) +} + +func (hc *HybridCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + return hc.proto.MustMarshalBinaryLengthPrefixed(o) +} + +func (hc *HybridCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return hc.proto.UnmarshalBinaryBare(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + hc.proto.MustUnmarshalBinaryBare(bz, ptr) +} + +func (hc *HybridCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + return hc.proto.UnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + hc.proto.MustUnmarshalBinaryLengthPrefixed(bz, ptr) +} + +func (hc *HybridCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + return hc.amino.MarshalJSON(o) +} + +func (hc *HybridCodec) MustMarshalJSON(o interface{}) []byte { + return hc.amino.MustMarshalJSON(o) +} + +func (hc *HybridCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + return hc.amino.UnmarshalJSON(bz, ptr) +} + +func (hc *HybridCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + hc.amino.MustUnmarshalJSON(bz, ptr) +} diff --git a/codec/hybrid_codec_test.go b/codec/hybrid_codec_test.go new file mode 100644 index 000000000000..353f0c389643 --- /dev/null +++ b/codec/hybrid_codec_test.go @@ -0,0 +1,107 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" +) + +func TestHybridCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewHybridCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewHybridCodec(createTestCodec()), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/proto_codec.go b/codec/proto_codec.go new file mode 100644 index 000000000000..f8a4169d4d8b --- /dev/null +++ b/codec/proto_codec.go @@ -0,0 +1,130 @@ +package codec + +import ( + "bytes" + "encoding/binary" + "fmt" + "strings" + + "github.com/gogo/protobuf/jsonpb" +) + +// ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON +// encoding. +type ProtoCodec struct{} + +func NewProtoCodec() Marshaler { + return &ProtoCodec{} +} + +func (pc *ProtoCodec) MarshalBinaryBare(o ProtoMarshaler) ([]byte, error) { + return o.Marshal() +} + +func (pc *ProtoCodec) MustMarshalBinaryBare(o ProtoMarshaler) []byte { + bz, err := pc.MarshalBinaryBare(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) MarshalBinaryLengthPrefixed(o ProtoMarshaler) ([]byte, error) { + bz, err := pc.MarshalBinaryBare(o) + if err != nil { + return nil, err + } + + buf := new(bytes.Buffer) + if err := encodeUvarint(buf, uint64(o.Size())); err != nil { + return nil, err + } + + if _, err := buf.Write(bz); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (pc *ProtoCodec) MustMarshalBinaryLengthPrefixed(o ProtoMarshaler) []byte { + bz, err := pc.MarshalBinaryLengthPrefixed(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error { + return ptr.Unmarshal(bz) +} + +func (pc *ProtoCodec) MustUnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) { + if err := pc.UnmarshalBinaryBare(bz, ptr); err != nil { + panic(err) + } +} + +func (pc *ProtoCodec) UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error { + size, n := binary.Uvarint(bz) + if n < 0 { + return fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", n) + } + + if size > uint64(len(bz)-n) { + return fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-n) + } else if size < uint64(len(bz)-n) { + return fmt.Errorf("too many bytes to read; want: %v, got: %v", size, len(bz)-n) + } + + bz = bz[n:] + return ptr.Unmarshal(bz) +} + +func (pc *ProtoCodec) MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) { + if err := pc.UnmarshalBinaryLengthPrefixed(bz, ptr); err != nil { + panic(err) + } +} + +func (pc *ProtoCodec) MarshalJSON(o interface{}) ([]byte, error) { // nolint: stdmethods + m, ok := o.(ProtoMarshaler) + if !ok { + return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o) + } + + buf := new(bytes.Buffer) + + marshaler := &jsonpb.Marshaler{} + if err := marshaler.Marshal(buf, m); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func (pc *ProtoCodec) MustMarshalJSON(o interface{}) []byte { + bz, err := pc.MarshalJSON(o) + if err != nil { + panic(err) + } + + return bz +} + +func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr interface{}) error { // nolint: stdmethods + m, ok := ptr.(ProtoMarshaler) + if !ok { + return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr) + } + + return jsonpb.Unmarshal(strings.NewReader(string(bz)), m) +} + +func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr interface{}) { + if err := pc.UnmarshalJSON(bz, ptr); err != nil { + panic(err) + } +} diff --git a/codec/proto_codec_test.go b/codec/proto_codec_test.go new file mode 100644 index 000000000000..c49544e060f1 --- /dev/null +++ b/codec/proto_codec_test.go @@ -0,0 +1,107 @@ +package codec_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/testdata" + "github.com/stretchr/testify/require" +) + +func TestProtoCodec(t *testing.T) { + testCases := []struct { + name string + codec codec.Marshaler + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool + }{ + { + "valid encoding and decoding", + codec.NewProtoCodec(), + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, + { + "invalid decode type", + codec.NewProtoCodec(), + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + bz, err := tc.codec.MarshalBinaryBare(tc.input) + + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + + bz, err = tc.codec.MarshalJSON(tc.input) + if tc.marshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) + } else { + var bz2 []byte + require.NoError(t, err) + require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) + require.Equal(t, bz, bz2) + + err := tc.codec.UnmarshalJSON(bz, tc.recv) + if tc.unmarshalErr { + require.Error(t, err) + require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + } else { + require.NoError(t, err) + require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) + require.Equal(t, tc.input, tc.recv) + } + } + }) + } +} diff --git a/codec/testdata/animal.go b/codec/testdata/animal.go new file mode 100644 index 000000000000..05c8102487d8 --- /dev/null +++ b/codec/testdata/animal.go @@ -0,0 +1,20 @@ +package testdata + +// DONTCOVER +// nolint + +import ( + "fmt" +) + +type Animal interface { + Greet() string +} + +func (c Cat) Greet() string { + return fmt.Sprintf("Meow, my name is %s", c.Moniker) +} + +func (d Dog) Greet() string { + return fmt.Sprintf("Roof, my name is %s", d.Name) +} diff --git a/codec/testdata/proto.pb.go b/codec/testdata/proto.pb.go new file mode 100644 index 000000000000..d92daf3ec229 --- /dev/null +++ b/codec/testdata/proto.pb.go @@ -0,0 +1,579 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: codec/testdata/proto.proto + +package testdata + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Dog struct { + Size_ string `protobuf:"bytes,1,opt,name=size,proto3" json:"size,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (m *Dog) Reset() { *m = Dog{} } +func (m *Dog) String() string { return proto.CompactTextString(m) } +func (*Dog) ProtoMessage() {} +func (*Dog) Descriptor() ([]byte, []int) { + return fileDescriptor_ae1353846770e6e2, []int{0} +} +func (m *Dog) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Dog) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Dog.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Dog) XXX_Merge(src proto.Message) { + xxx_messageInfo_Dog.Merge(m, src) +} +func (m *Dog) XXX_Size() int { + return m.Size() +} +func (m *Dog) XXX_DiscardUnknown() { + xxx_messageInfo_Dog.DiscardUnknown(m) +} + +var xxx_messageInfo_Dog proto.InternalMessageInfo + +func (m *Dog) GetSize_() string { + if m != nil { + return m.Size_ + } + return "" +} + +func (m *Dog) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type Cat struct { + Moniker string `protobuf:"bytes,1,opt,name=moniker,proto3" json:"moniker,omitempty"` + Lives int32 `protobuf:"varint,2,opt,name=lives,proto3" json:"lives,omitempty"` +} + +func (m *Cat) Reset() { *m = Cat{} } +func (m *Cat) String() string { return proto.CompactTextString(m) } +func (*Cat) ProtoMessage() {} +func (*Cat) Descriptor() ([]byte, []int) { + return fileDescriptor_ae1353846770e6e2, []int{1} +} +func (m *Cat) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Cat) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Cat.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Cat) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cat.Merge(m, src) +} +func (m *Cat) XXX_Size() int { + return m.Size() +} +func (m *Cat) XXX_DiscardUnknown() { + xxx_messageInfo_Cat.DiscardUnknown(m) +} + +var xxx_messageInfo_Cat proto.InternalMessageInfo + +func (m *Cat) GetMoniker() string { + if m != nil { + return m.Moniker + } + return "" +} + +func (m *Cat) GetLives() int32 { + if m != nil { + return m.Lives + } + return 0 +} + +func init() { + proto.RegisterType((*Dog)(nil), "cosmos_sdk.codec.v1.Dog") + proto.RegisterType((*Cat)(nil), "cosmos_sdk.codec.v1.Cat") +} + +func init() { proto.RegisterFile("codec/testdata/proto.proto", fileDescriptor_ae1353846770e6e2) } + +var fileDescriptor_ae1353846770e6e2 = []byte{ + // 195 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4a, 0xce, 0x4f, 0x49, + 0x4d, 0xd6, 0x2f, 0x49, 0x2d, 0x2e, 0x49, 0x49, 0x2c, 0x49, 0xd4, 0x2f, 0x28, 0xca, 0x2f, 0xc9, + 0xd7, 0x03, 0x93, 0x42, 0xc2, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, + 0x60, 0x65, 0x7a, 0x65, 0x86, 0x4a, 0xba, 0x5c, 0xcc, 0x2e, 0xf9, 0xe9, 0x42, 0x42, 0x5c, 0x2c, + 0xc5, 0x99, 0x55, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0x36, 0x48, 0x2c, 0x2f, + 0x31, 0x37, 0x55, 0x82, 0x09, 0x22, 0x06, 0x62, 0x2b, 0x99, 0x72, 0x31, 0x3b, 0x27, 0x96, 0x08, + 0x49, 0x70, 0xb1, 0xe7, 0xe6, 0xe7, 0x65, 0x66, 0xa7, 0x16, 0x41, 0x75, 0xc0, 0xb8, 0x42, 0x22, + 0x5c, 0xac, 0x39, 0x99, 0x65, 0xa9, 0xc5, 0x60, 0x5d, 0xac, 0x41, 0x10, 0x8e, 0x93, 0xeb, 0x89, + 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, + 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x69, 0xa7, 0x67, 0x96, 0x64, 0x94, 0x26, + 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0xdc, 0x07, 0xa5, 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x51, 0x7d, + 0x93, 0xc4, 0x06, 0xf6, 0x88, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x64, 0x25, 0x07, 0xc7, 0xe6, + 0x00, 0x00, 0x00, +} + +func (m *Dog) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Dog) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Dog) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintProto(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Size_) > 0 { + i -= len(m.Size_) + copy(dAtA[i:], m.Size_) + i = encodeVarintProto(dAtA, i, uint64(len(m.Size_))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Cat) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Cat) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Cat) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Lives != 0 { + i = encodeVarintProto(dAtA, i, uint64(m.Lives)) + i-- + dAtA[i] = 0x10 + } + if len(m.Moniker) > 0 { + i -= len(m.Moniker) + copy(dAtA[i:], m.Moniker) + i = encodeVarintProto(dAtA, i, uint64(len(m.Moniker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintProto(dAtA []byte, offset int, v uint64) int { + offset -= sovProto(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Dog) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Size_) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + return n +} + +func (m *Cat) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Moniker) + if l > 0 { + n += 1 + l + sovProto(uint64(l)) + } + if m.Lives != 0 { + n += 1 + sovProto(uint64(m.Lives)) + } + return n +} + +func sovProto(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozProto(x uint64) (n int) { + return sovProto(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Dog) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Dog: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Dog: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Size_ = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Cat) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Cat: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Cat: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Moniker", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProto + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProto + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Moniker = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Lives", wireType) + } + m.Lives = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProto + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Lives |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipProto(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProto + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipProto(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowProto + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthProto + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupProto + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthProto + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthProto = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowProto = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupProto = fmt.Errorf("proto: unexpected end of group") +) diff --git a/codec/testdata/proto.proto b/codec/testdata/proto.proto new file mode 100644 index 000000000000..ed8c0418dbce --- /dev/null +++ b/codec/testdata/proto.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package cosmos_sdk.codec.v1; + +option go_package = "github.com/cosmos/cosmos-sdk/codec/testdata"; + +message Dog { + string size = 1; + string name = 2; +} + +message Cat { + string moniker = 1; + int32 lives = 2; +} diff --git a/contrib/devtools/Makefile b/contrib/devtools/Makefile index 735ab395178c..f0bf0ae77b27 100644 --- a/contrib/devtools/Makefile +++ b/contrib/devtools/Makefile @@ -1,3 +1,6 @@ +.PHONY: all tools tools-clean statik runsim golangci-lint \ +protoc buf protoc-gen-buf-check-breaking protoc-gen-buf-check-lint protoc-gen-gocosmos + ### # Find OS and Go environment # GO contains the Go binary @@ -15,13 +18,11 @@ ifeq ($(GO),) $(error could not find go. Is it in PATH? $(GO)) endif -GOPATH ?= $(shell $(GO) env GOPATH) -GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com -GOLANGCI_LINT_HASHSUM := 8d21cc95da8d3daf8321ac40091456fc26123c964d7c2281d339d431f2f4c840 +all: tools -### -# Functions -### +############################################################################### +### Functions ### +############################################################################### go_get = $(if $(findstring Windows_NT,$(OS)),\ IF NOT EXIST $(GITHUBDIR)$(FS)$(1)$(FS) ( mkdir $(GITHUBDIR)$(FS)$(1) ) else (cd .) &\ @@ -35,19 +36,27 @@ cd $(GITHUBDIR)$(FS)$(1)$(FS)$(2) && git fetch origin && git checkout -q $(3) mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) mkfile_dir := $(shell cd $(shell dirname $(mkfile_path)); pwd) -### -# tools -### -TOOLS_DESTDIR ?= $(GOPATH)/bin +############################################################################### +### Tools ### +############################################################################### -GOLANGCI_LINT = $(TOOLS_DESTDIR)/golangci-lint -STATIK = $(TOOLS_DESTDIR)/statik -RUNSIM = $(TOOLS_DESTDIR)/runsim +BIN ?= /usr/local/bin +UNAME_S ?= $(shell uname -s) +UNAME_M ?= $(shell uname -m) -all: tools +GOPATH ?= $(shell $(GO) env GOPATH) +GITHUBDIR := $(GOPATH)$(FS)src$(FS)github.com +GOLANGCI_LINT_HASHSUM := f11179f445385a4a6d5079d67de63fe48a9113cee8e9ee0ced19327a83a4394b -tools: statik runsim golangci-lint +BUF_VERSION ?= 0.4.0 + +TOOLS_DESTDIR ?= $(GOPATH)/bin +GOLANGCI_LINT = $(TOOLS_DESTDIR)/golangci-lint +STATIK = $(TOOLS_DESTDIR)/statik +RUNSIM = $(TOOLS_DESTDIR)/runsim + +tools: protoc buf statik runsim golangci-lint golangci-lint: $(GOLANGCI_LINT) $(GOLANGCI_LINT): $(mkfile_dir)/install-golangci-lint.sh @@ -74,8 +83,47 @@ $(RUNSIM): @echo "Installing runsim..." @(cd /tmp && go get github.com/cosmos/tools/cmd/runsim@v1.0.0) +PROTOC_VERSION ?= 3.11.2 +ifeq ($(UNAME_S),Linux) + PROTOC_ZIP ?= protoc-3.11.2-linux-x86_64.zip +endif +ifeq ($(UNAME_S),Darwin) + PROTOC_ZIP ?= protoc-3.11.2-osx-x86_64.zip +endif + +protoc: + @echo "Installing protoc compiler..." + @(cd /tmp; \ + curl -OL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/${PROTOC_ZIP}"; \ + unzip -o ${PROTOC_ZIP} -d /usr/local bin/protoc; \ + unzip -o ${PROTOC_ZIP} -d /usr/local 'include/*'; \ + rm -f ${PROTOC_ZIP}) + +protoc-gen-gocosmos: + @echo "Installing protoc-gen-gocosmos..." + @go install github.com/regen-network/cosmos-proto/protoc-gen-gocosmos + +buf: protoc-gen-buf-check-breaking protoc-gen-buf-check-lint + @echo "Installing buf..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/buf" && \ + chmod +x "${BIN}/buf" + +protoc-gen-buf-check-breaking: + @echo "Installing protoc-gen-buf-check-breaking..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/protoc-gen-buf-check-breaking-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/protoc-gen-buf-check-breaking" && \ + chmod +x "${BIN}/protoc-gen-buf-check-breaking" + +protoc-gen-buf-check-lint: + @echo "Installing protoc-gen-buf-check-lint..." + @curl -sSL \ + "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/protoc-gen-buf-check-lint-${UNAME_S}-${UNAME_M}" \ + -o "${BIN}/protoc-gen-buf-check-lint" && \ + chmod +x "${BIN}/protoc-gen-buf-check-lint" + tools-clean: rm -f $(STATIK) $(GOLANGCI_LINT) $(RUNSIM) rm -f tools-stamp - -.PHONY: all tools tools-clean diff --git a/docs/core/encoding.md b/docs/core/encoding.md index 6629612a3a24..ac05f52c676a 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -1,37 +1,84 @@ # Encoding +> NOTE: This document a WIP. + ## Pre-requisite Readings {hide} - [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq} ## Encoding -Every Cosmos SDK application exposes a global `codec` to marshal/unmarshal structs and interfaces in order to store and/or transfer them. As of now, the `codec` used in the Cosmos SDK is [go-amino](https://github.com/tendermint/go-amino), which possesses the following important properties: - -- Interface support. -- Deterministic encoding of value (which is required considering that blockchains are deterministic replicated state-machines). -- Upgradeable schemas. - -The application's `codec` is typically initialized in the [application's constructor function](../basics/app-anatomy.md#constructor-function), where it is also passed to each of the application's modules via the [basic manager](../building-modules/module-manager.md#basic-manager). - -Among other things, the `codec` is used by module's [`keeper`s](../building-modules/keeper.md) to marshal objects into `[]byte` before storing them in the module's [`KVStore`](./store.md#kvstore), or to unmarshal them from `[]byte` when retrieving them: +The Cosmos SDK utilizes two binary wire encoding protocols, [Amino](https://github.com/tendermint/go-amino/) +and [Protocol Buffers](https://developers.google.com/protocol-buffers), where Amino +is an object encoding specification. It is a subset of Proto3 with an extension for +interface support. See the [Proto3 spec](https://developers.google.com/protocol-buffers/docs/proto3) +for more information on Proto3, which Amino is largely compatible with (but not with Proto2). + +Due to Amino having significant performance drawbacks, being reflection-based, and +not having any meaningful cross-language/client support, Protocol Buffers, specifically +[gogoprotobuf](https://github.com/gogo/protobuf/), is being used in place of Amino. +Note, this process of using Protocol Buffers over Amino is still an ongoing process. + +Binary wire encoding of types in the Cosmos SDK can be broken down into two main +categories, client encoding and store encoding. Client encoding mainly revolves +around transaction processing and signing, whereas store encoding revolves around +types used in state-machine transitions and what is ultimately stored in the Merkle +tree. + +For store encoding, protobuf definitions can exist for any type and will typically +have an Amino-based "intermediary" type. Specifically, the protobuf-based type +definition is used for serialization and persistence, whereas the Amino-based type +is used for business logic in the state-machine where they may converted back-n-forth. +Note, the Amino-based types may slowly be phased-out in the future so developers +should take note to use the protobuf message definitions where possible. + +In the `codec` package, there exists two core interfaces, `Marshaler` and `ProtoMarshaler`, +where the former encapsulates the current Amino interface except it operates on +types implementing the latter instead of generic `interface{}` types. + +In addition, there exists three implementations of `Marshaler`. The first being +`AminoCodec`, where both binary and JSON serialization is handled via Amino. The +second being `ProtoCodec`, where both binary and JSON serialization is handled +via Protobuf. Finally, `HybridCodec`, a codec that utilizes Protobuf for binary +serialization and Amino for JSON serialization. The `HybridCodec` is typically +the codec that used in majority in situations as it's easier to use for client +and state serialization. + +This means that modules may use Amino or Protobuf encoding but the types must +implement `ProtoMarshaler`. If modules wish to avoid implementing this interface +for their types, they may use an Amino codec directly. + +### Amino + +Every module uses an Amino codec to serialize types and interfaces. This codec typically +has types and interfaces registered in that module's domain only (e.g. messages), +but there are exceptions like `x/gov`. Each module exposes a `RegisterCodec` function +that allows a user to provide a codec and have all the types registered. An application +will call this method for each necessary module. + +Where there is no protobuf-based type definition for a module (see below), Amino +is used to encode and decode raw wire bytes to the concrete type or interface: ```go -// typical pattern to marshal an object to []byte before storing it -bz := keeper.cdc.MustMarshalBinaryBare(object) - -//typical pattern to unmarshal an object from []byte when retrieving it -keeper.cdc.MustUnmarshalBinaryBare(bz, &object) +bz := keeper.cdc.MustMarshalBinaryBare(typeOrInterface) +keeper.cdc.MustUnmarshalBinaryBare(bz, &typeOrInterface) ``` -Alternatively, it is possible to use `MustMarshalBinaryLengthPrefixed`/`MustUnmarshalBinaryLengthPrefixed` instead of `MustMarshalBinaryBare`/`MustUnmarshalBinaryBare` for the same encoding prefixed by a `uvarint` encoding of the object to encode. +Note, there are length-prefixed variants of the above functionality and this is +typically used for when the data needs to be streamed or grouped together +(e.g. `ResponseDeliverTx.Data`) -Another important use of the `codec` is the encoding and decoding of [transactions](./transactions.md). Transactions are defined at the Cosmos SDK level, but passed to the underlying consensus engine in order to be relayed to other peers. Since the underlying consensus engine is agnostic to the application, it only accepts transactions in the form of `[]byte`. The encoding is done by an object called `TxEncoder` and the decoding by an object called `TxDecoder`. +Another important use of the Amino is the encoding and decoding of +[transactions](./transactions.md). Transactions are defined by the application or +the SDK, but passed to the underlying consensus engine in order to be relayed to +other peers. Since the underlying consensus engine is agnostic to the application, +it only accepts transactions in the form of raw bytes. The encoding is done by an +object called `TxEncoder` and the decoding by an object called `TxDecoder`. +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L45-L49 @@ -39,6 +86,18 @@ A standard implementation of both these objects can be found in the [`auth` modu +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/stdtx.go#L241-L266 +### Gogoproto + +Modules are encouraged to utilize Protobuf encoding for their respective types. +If modules do not contain any interfaces (e.g. `Account` or `Content`), then they +may simply accept a `Marshaler` as the codec which is implemented via the `HybridCodec` +without any further customization. + +However, if modules are to handle type interfaces, they should seek to extend the +`Marshaler` interface contract for these types (e.g. `MarshalAccount`). Note, they +should still use a `HybridCodec` internally. These extended contracts will typically +use concrete types with unique `oneof` messages. + ## Next {hide} -Learn about [events](./events.md) {hide} \ No newline at end of file +Learn about [events](./events.md) {hide} diff --git a/go.mod b/go.mod index 612c513549fc..6ebb9fdde282 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/pelletier/go-toml v1.6.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.6 + github.com/regen-network/cosmos-proto v0.1.0 github.com/spf13/afero v1.2.1 // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -30,6 +31,8 @@ require ( gopkg.in/yaml.v2 v2.2.8 ) -go 1.13 +replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.1 replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 + +go 1.13 diff --git a/go.sum b/go.sum index 4fd5999711d2..097236eff67f 100644 --- a/go.sum +++ b/go.sum @@ -17,7 +17,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -74,13 +73,10 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -88,10 +84,6 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -127,8 +119,6 @@ github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -145,12 +135,10 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -159,12 +147,9 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -186,7 +171,6 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -196,7 +180,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -211,6 +194,10 @@ github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/regen-network/cosmos-proto v0.1.0 h1:gsV+YO2kMvY430zQn8ioPXRxEJgb/ms0iMPeWo3VEyY= +github.com/regen-network/cosmos-proto v0.1.0/go.mod h1:+r7jN10xXCypD4yBgzKOa+vgLz0riqYMHeDcKekxPvA= +github.com/regen-network/protobuf v1.3.2-alpha.regen.1 h1:YdeZbBS0lG1D13COb7b57+nM/RGgIs8WF9DwitU6EBM= +github.com/regen-network/protobuf v1.3.2-alpha.regen.1/go.mod h1:lye6mqhOn/GCw1zRl3uPD5VP8rC+LPMyTyPAyQV872U= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -234,13 +221,10 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= @@ -288,14 +272,15 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -305,8 +290,10 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -323,14 +310,14 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -338,19 +325,21 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f h1:2wh8dWY8959cBGQvk1RD+/eQBgRYYDaZ+hT0/zsARoA= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -363,12 +352,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh new file mode 100755 index 000000000000..0818824a41b8 --- /dev/null +++ b/scripts/protocgen.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -eo pipefail + +proto_dirs=$(find . -path ./third_party -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) +for dir in $proto_dirs; do + protoc \ + -I. \ + --gocosmos_out=plugins=interfacetype,paths=source_relative:. \ + $(find "${dir}" -name '*.proto') +done diff --git a/third_party/proto/cosmos-proto/cosmos.proto b/third_party/proto/cosmos-proto/cosmos.proto new file mode 100644 index 000000000000..a59821d4f6b4 --- /dev/null +++ b/third_party/proto/cosmos-proto/cosmos.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package cosmos_proto; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/regen-network/cosmos-proto"; + +extend google.protobuf.MessageOptions { + string interface_type = 93001; +} diff --git a/third_party/proto/gogoproto/gogo.proto b/third_party/proto/gogoproto/gogo.proto new file mode 100644 index 000000000000..588291f0ec20 --- /dev/null +++ b/third_party/proto/gogoproto/gogo.proto @@ -0,0 +1,145 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; +package gogoproto; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "GoGoProtos"; +option go_package = "github.com/gogo/protobuf/gogoproto"; + +extend google.protobuf.EnumOptions { + optional bool goproto_enum_prefix = 62001; + optional bool goproto_enum_stringer = 62021; + optional bool enum_stringer = 62022; + optional string enum_customname = 62023; + optional bool enumdecl = 62024; +} + +extend google.protobuf.EnumValueOptions { + optional string enumvalue_customname = 66001; +} + +extend google.protobuf.FileOptions { + optional bool goproto_getters_all = 63001; + optional bool goproto_enum_prefix_all = 63002; + optional bool goproto_stringer_all = 63003; + optional bool verbose_equal_all = 63004; + optional bool face_all = 63005; + optional bool gostring_all = 63006; + optional bool populate_all = 63007; + optional bool stringer_all = 63008; + optional bool onlyone_all = 63009; + + optional bool equal_all = 63013; + optional bool description_all = 63014; + optional bool testgen_all = 63015; + optional bool benchgen_all = 63016; + optional bool marshaler_all = 63017; + optional bool unmarshaler_all = 63018; + optional bool stable_marshaler_all = 63019; + + optional bool sizer_all = 63020; + + optional bool goproto_enum_stringer_all = 63021; + optional bool enum_stringer_all = 63022; + + optional bool unsafe_marshaler_all = 63023; + optional bool unsafe_unmarshaler_all = 63024; + + optional bool goproto_extensions_map_all = 63025; + optional bool goproto_unrecognized_all = 63026; + optional bool gogoproto_import = 63027; + optional bool protosizer_all = 63028; + optional bool compare_all = 63029; + optional bool typedecl_all = 63030; + optional bool enumdecl_all = 63031; + + optional bool goproto_registration = 63032; + optional bool messagename_all = 63033; + + optional bool goproto_sizecache_all = 63034; + optional bool goproto_unkeyed_all = 63035; +} + +extend google.protobuf.MessageOptions { + optional bool goproto_getters = 64001; + optional bool goproto_stringer = 64003; + optional bool verbose_equal = 64004; + optional bool face = 64005; + optional bool gostring = 64006; + optional bool populate = 64007; + optional bool stringer = 67008; + optional bool onlyone = 64009; + + optional bool equal = 64013; + optional bool description = 64014; + optional bool testgen = 64015; + optional bool benchgen = 64016; + optional bool marshaler = 64017; + optional bool unmarshaler = 64018; + optional bool stable_marshaler = 64019; + + optional bool sizer = 64020; + + optional bool unsafe_marshaler = 64023; + optional bool unsafe_unmarshaler = 64024; + + optional bool goproto_extensions_map = 64025; + optional bool goproto_unrecognized = 64026; + + optional bool protosizer = 64028; + optional bool compare = 64029; + + optional bool typedecl = 64030; + + optional bool messagename = 64033; + + optional bool goproto_sizecache = 64034; + optional bool goproto_unkeyed = 64035; +} + +extend google.protobuf.FieldOptions { + optional bool nullable = 65001; + optional bool embed = 65002; + optional string customtype = 65003; + optional string customname = 65004; + optional string jsontag = 65005; + optional string moretags = 65006; + optional string casttype = 65007; + optional string castkey = 65008; + optional string castvalue = 65009; + + optional bool stdtime = 65010; + optional bool stdduration = 65011; + optional bool wktpointer = 65012; + + optional string castrepeated = 65013; +} \ No newline at end of file diff --git a/types/codec.go b/types/codec.go index 3d789afe9f0a..fdd884bd5f84 100644 --- a/types/codec.go +++ b/types/codec.go @@ -1,6 +1,8 @@ package types -import "github.com/cosmos/cosmos-sdk/codec" +import ( + "github.com/cosmos/cosmos-sdk/codec" +) // Register the sdk message type func RegisterCodec(cdc *codec.Codec) { diff --git a/types/coin.go b/types/coin.go index 98eaa6b806df..12d82a6e01e9 100644 --- a/types/coin.go +++ b/types/coin.go @@ -11,20 +11,6 @@ import ( //----------------------------------------------------------------------------- // Coin -// Coin hold some amount of one currency. -// -// CONTRACT: A coin will never hold a negative amount of any denomination. -// -// TODO: Make field members private for further safety. -type Coin struct { - Denom string `json:"denom"` - - // To allow the use of unsigned integers (see: #1273) a larger refactor will - // need to be made. So we use signed integers for now with safety measures in - // place preventing negative values being used. - Amount Int `json:"amount"` -} - // NewCoin returns a new coin with a denomination and amount. It will panic if // the amount is negative. func NewCoin(denom string, amount Int) Coin { diff --git a/types/coin_test.go b/types/coin_test.go index a090deb01518..63b3fe38e4ec 100644 --- a/types/coin_test.go +++ b/types/coin_test.go @@ -685,3 +685,18 @@ func TestMarshalJSONCoins(t *testing.T) { }) } } + +func TestCoinAminoEncoding(t *testing.T) { + c := NewInt64Coin(testDenom1, 5) + + bz1, err := cdc.MarshalBinaryBare(c) + require.NoError(t, err) + + bz2, err := cdc.MarshalBinaryLengthPrefixed(c) + require.NoError(t, err) + + bz3, err := c.Marshal() + require.NoError(t, err) + require.Equal(t, bz1, bz3) + require.Equal(t, bz2[1:], bz3) +} diff --git a/types/dec_coin.go b/types/dec_coin.go index 9b6e700104e7..87bf3d8a728c 100644 --- a/types/dec_coin.go +++ b/types/dec_coin.go @@ -11,12 +11,6 @@ import ( // ---------------------------------------------------------------------------- // Decimal Coin -// DecCoin defines a coin which can have additional decimal points -type DecCoin struct { - Denom string `json:"denom"` - Amount Dec `json:"amount"` -} - // NewDecCoin creates a new DecCoin instance from an Int. func NewDecCoin(denom string, amount Int) DecCoin { if err := validate(denom, amount); err != nil { @@ -134,7 +128,7 @@ func (coin DecCoin) IsPositive() bool { // // TODO: Remove once unsigned integers are used. func (coin DecCoin) IsNegative() bool { - return coin.Amount.Sign() == -1 + return coin.Amount.IsNegative() } // String implements the Stringer interface for DecCoin. It returns a diff --git a/types/decimal.go b/types/decimal.go index 839523080656..d6917182b66c 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -10,10 +10,12 @@ import ( "testing" ) +var _ CustomProtobufType = (*Dec)(nil) + // NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int type Dec struct { - *big.Int `json:"int"` + i *big.Int } // number of decimal places @@ -193,21 +195,27 @@ func MustNewDecFromStr(s string) Dec { //______________________________________________________________________________________________ //nolint -func (d Dec) IsNil() bool { return d.Int == nil } // is decimal nil -func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // is equal to zero -func (d Dec) IsNegative() bool { return (d.Int).Sign() == -1 } // is negative -func (d Dec) IsPositive() bool { return (d.Int).Sign() == 1 } // is positive -func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } // equal decimals -func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than -func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) < 0 } // less than -func (d Dec) LTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.Int)} } // reverse the decimal sign -func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.Int)} } // absolute value +func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil +func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero +func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative +func (d Dec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive +func (d Dec) Equal(d2 Dec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals +func (d Dec) GT(d2 Dec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than +func (d Dec) GTE(d2 Dec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal +func (d Dec) LT(d2 Dec) bool { return (d.i).Cmp(d2.i) < 0 } // less than +func (d Dec) LTE(d2 Dec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.i)} } // reverse the decimal sign +func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.i)} } // absolute value + +// BigInt returns a copy of the underlying big.Int. +func (d Dec) BigInt() *big.Int { + copy := new(big.Int) + return copy.Set(d.i) +} // addition func (d Dec) Add(d2 Dec) Dec { - res := new(big.Int).Add(d.Int, d2.Int) + res := new(big.Int).Add(d.i, d2.i) if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -217,7 +225,7 @@ func (d Dec) Add(d2 Dec) Dec { // subtraction func (d Dec) Sub(d2 Dec) Dec { - res := new(big.Int).Sub(d.Int, d2.Int) + res := new(big.Int).Sub(d.i, d2.i) if res.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -227,7 +235,7 @@ func (d Dec) Sub(d2 Dec) Dec { // multiplication func (d Dec) Mul(d2 Dec) Dec { - mul := new(big.Int).Mul(d.Int, d2.Int) + mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndRound(mul) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -238,7 +246,7 @@ func (d Dec) Mul(d2 Dec) Dec { // multiplication truncate func (d Dec) MulTruncate(d2 Dec) Dec { - mul := new(big.Int).Mul(d.Int, d2.Int) + mul := new(big.Int).Mul(d.i, d2.i) chopped := chopPrecisionAndTruncate(mul) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -249,7 +257,7 @@ func (d Dec) MulTruncate(d2 Dec) Dec { // multiplication func (d Dec) MulInt(i Int) Dec { - mul := new(big.Int).Mul(d.Int, i.i) + mul := new(big.Int).Mul(d.i, i.i) if mul.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -259,7 +267,7 @@ func (d Dec) MulInt(i Int) Dec { // MulInt64 - multiplication with int64 func (d Dec) MulInt64(i int64) Dec { - mul := new(big.Int).Mul(d.Int, big.NewInt(i)) + mul := new(big.Int).Mul(d.i, big.NewInt(i)) if mul.BitLen() > 255+DecimalPrecisionBits { panic("Int overflow") @@ -269,11 +277,12 @@ func (d Dec) MulInt64(i int64) Dec { // quotient func (d Dec) Quo(d2 Dec) Dec { + // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRound(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -286,10 +295,10 @@ func (d Dec) Quo(d2 Dec) Dec { func (d Dec) QuoTruncate(d2 Dec) Dec { // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndTruncate(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -301,10 +310,10 @@ func (d Dec) QuoTruncate(d2 Dec) Dec { // quotient, round up func (d Dec) QuoRoundUp(d2 Dec) Dec { // multiply precision twice - mul := new(big.Int).Mul(d.Int, precisionReuse) + mul := new(big.Int).Mul(d.i, precisionReuse) mul.Mul(mul, precisionReuse) - quo := new(big.Int).Quo(mul, d2.Int) + quo := new(big.Int).Quo(mul, d2.i) chopped := chopPrecisionAndRoundUp(quo) if chopped.BitLen() > 255+DecimalPrecisionBits { @@ -315,13 +324,13 @@ func (d Dec) QuoRoundUp(d2 Dec) Dec { // quotient func (d Dec) QuoInt(i Int) Dec { - mul := new(big.Int).Quo(d.Int, i.i) + mul := new(big.Int).Quo(d.i, i.i) return Dec{mul} } // QuoInt64 - quotient with int64 func (d Dec) QuoInt64(i int64) Dec { - mul := new(big.Int).Quo(d.Int, big.NewInt(i)) + mul := new(big.Int).Quo(d.i, big.NewInt(i)) return Dec{mul} } @@ -397,7 +406,7 @@ func (d Dec) ApproxSqrt() (Dec, error) { // is integer, e.g. decimals are zero func (d Dec) IsInteger() bool { - return new(big.Int).Rem(d.Int, precisionReuse).Sign() == 0 + return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 } // format decimal state @@ -409,8 +418,8 @@ func (d Dec) Format(s fmt.State, verb rune) { } func (d Dec) String() string { - if d.Int == nil { - return d.Int.String() + if d.i == nil { + return d.i.String() } isNeg := d.IsNegative() @@ -418,7 +427,7 @@ func (d Dec) String() string { d = d.Neg() } - bzInt, err := d.Int.MarshalText() + bzInt, err := d.i.MarshalText() if err != nil { return "" } @@ -537,7 +546,7 @@ func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { // RoundInt64 rounds the decimal using bankers rounding func (d Dec) RoundInt64() int64 { - chopped := chopPrecisionAndRoundNonMutative(d.Int) + chopped := chopPrecisionAndRoundNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -546,7 +555,7 @@ func (d Dec) RoundInt64() int64 { // RoundInt round the decimal using bankers rounding func (d Dec) RoundInt() Int { - return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.Int)) + return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) } //___________________________________________________________________________________ @@ -563,7 +572,7 @@ func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { // TruncateInt64 truncates the decimals from the number and returns an int64 func (d Dec) TruncateInt64() int64 { - chopped := chopPrecisionAndTruncateNonMutative(d.Int) + chopped := chopPrecisionAndTruncateNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") } @@ -572,18 +581,18 @@ func (d Dec) TruncateInt64() int64 { // TruncateInt truncates the decimals from the number and returns an Int func (d Dec) TruncateInt() Int { - return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) + return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // TruncateDec truncates the decimals from the number and returns a Dec func (d Dec) TruncateDec() Dec { - return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.Int)) + return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // Ceil returns the smallest interger value (as a decimal) that is greater than // or equal to the given decimal. func (d Dec) Ceil() Dec { - tmp := new(big.Int).Set(d.Int) + tmp := new(big.Int).Set(d.i) quo, rem := tmp, big.NewInt(0) quo, rem = quo.QuoRem(tmp, precisionReuse, rem) @@ -639,58 +648,26 @@ func SortableDecBytes(dec Dec) []byte { //___________________________________________________________________________________ // reuse nil values -var ( - nilAmino string - nilJSON []byte -) +var nilJSON []byte func init() { empty := new(big.Int) - bz, err := empty.MarshalText() - if err != nil { - panic("bad nil amino init") - } - nilAmino = string(bz) - - nilJSON, err = json.Marshal(string(bz)) - if err != nil { - panic("bad nil json init") - } -} - -// wraps d.MarshalText() -func (d Dec) MarshalAmino() (string, error) { - if d.Int == nil { - return nilAmino, nil - } - bz, err := d.Int.MarshalText() - return string(bz), err -} - -// requires a valid JSON string - strings quotes and calls UnmarshalText -func (d *Dec) UnmarshalAmino(text string) (err error) { - tempInt := new(big.Int) - err = tempInt.UnmarshalText([]byte(text)) - if err != nil { - return err - } - d.Int = tempInt - return nil + bz, _ := empty.MarshalText() + nilJSON, _ = json.Marshal(string(bz)) } // MarshalJSON marshals the decimal func (d Dec) MarshalJSON() ([]byte, error) { - if d.Int == nil { + if d.i == nil { return nilJSON, nil } - return json.Marshal(d.String()) } // UnmarshalJSON defines custom decoding scheme func (d *Dec) UnmarshalJSON(bz []byte) error { - if d.Int == nil { - d.Int = new(big.Int) + if d.i == nil { + d.i = new(big.Int) } var text string @@ -698,17 +675,80 @@ func (d *Dec) UnmarshalJSON(bz []byte) error { if err != nil { return err } + // TODO: Reuse dec allocation newDec, err := NewDecFromStr(text) if err != nil { return err } - d.Int = newDec.Int + + d.i = newDec.i return nil } -// MarshalYAML returns Ythe AML representation. -func (d Dec) MarshalYAML() (interface{}, error) { return d.String(), nil } +// MarshalYAML returns the YAML representation. +func (d Dec) MarshalYAML() (interface{}, error) { + return d.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (d Dec) Marshal() ([]byte, error) { + if d.i == nil { + d.i = new(big.Int) + } + return d.i.MarshalText() +} + +// MarshalTo implements the gogo proto custom type interface. +func (d *Dec) MarshalTo(data []byte) (n int, err error) { + if d.i == nil { + d.i = new(big.Int) + } + if len(d.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := d.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (d *Dec) Unmarshal(data []byte) error { + if len(data) == 0 { + d = nil + return nil + } + + if d.i == nil { + d.i = new(big.Int) + } + + if err := d.i.UnmarshalText(data); err != nil { + return err + } + + if d.i.BitLen() > maxBitLen { + return fmt.Errorf("decimal out of range; got: %d, max: %d", d.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (d *Dec) Size() int { + bz, _ := d.Marshal() + return len(bz) +} + +// Override Amino binary serialization by proxying to protobuf. +func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } +func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } //___________________________________________________________________________________ // helpers diff --git a/types/decimal_test.go b/types/decimal_test.go index 48c691a100dc..b88f146094fe 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,14 +1,15 @@ package types import ( + "encoding/json" + "fmt" "math/big" "testing" + "github.com/cosmos/cosmos-sdk/codec" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" + yaml "gopkg.in/yaml.v2" ) // create a decimal from a decimal string (ex. "1234.5678") @@ -273,7 +274,7 @@ var cdc = codec.New() func TestDecMarshalJSON(t *testing.T) { decimal := func(i int64) Dec { d := NewDec(0) - d.Int = new(big.Int).SetInt64(i) + d.i = new(big.Int).SetInt64(i) return d } tests := []struct { @@ -317,18 +318,6 @@ func TestZeroDeserializationJSON(t *testing.T) { require.NotNil(t, err) } -func TestSerializationText(t *testing.T) { - d := mustNewDecFromStr(t, "0.333") - - bz, err := d.MarshalText() - require.NoError(t, err) - - d2 := Dec{new(big.Int)} - err = d2.UnmarshalText(bz) - require.NoError(t, err) - require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -} - func TestSerializationGocodecJSON(t *testing.T) { d := mustNewDecFromStr(t, "0.333") @@ -341,39 +330,12 @@ func TestSerializationGocodecJSON(t *testing.T) { require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } -func TestSerializationGocodecBinary(t *testing.T) { - d := mustNewDecFromStr(t, "0.333") - - bz, err := cdc.MarshalBinaryLengthPrefixed(d) - require.NoError(t, err) - - var d2 Dec - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &d2) - require.NoError(t, err) - require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) -} - type testDEmbedStruct struct { Field1 string `json:"f1"` Field2 int `json:"f2"` Field3 Dec `json:"f3"` } -// TODO make work for UnmarshalJSON -func TestEmbeddedStructSerializationGocodec(t *testing.T) { - obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)} - bz, err := cdc.MarshalBinaryLengthPrefixed(obj) - require.Nil(t, err) - - var obj2 testDEmbedStruct - err = cdc.UnmarshalBinaryLengthPrefixed(bz, &obj2) - require.Nil(t, err) - - require.Equal(t, obj.Field1, obj2.Field1) - require.Equal(t, obj.Field2, obj2.Field2) - require.True(t, obj.Field3.Equal(obj2.Field3), "original: %v, unmarshalled: %v", obj, obj2) -} - func TestStringOverflow(t *testing.T) { // two random 64 bit primes dec1, err := NewDecFromStr("51643150036226787134389711697696177267") @@ -511,3 +473,62 @@ func TestDecSortableBytes(t *testing.T) { assert.Panics(t, func() { SortableDecBytes(NewDec(1000000000000000001)) }) assert.Panics(t, func() { SortableDecBytes(NewDec(-1000000000000000001)) }) } + +func TestDecEncoding(t *testing.T) { + testCases := []struct { + input Dec + rawBz string + jsonStr string + yamlStr string + }{ + { + NewDec(0), "30", + "\"0.000000000000000000\"", + "\"0.000000000000000000\"\n", + }, + { + NewDecWithPrec(4, 2), + "3430303030303030303030303030303030", + "\"0.040000000000000000\"", + "\"0.040000000000000000\"\n", + }, + { + NewDecWithPrec(-4, 2), + "2D3430303030303030303030303030303030", + "\"-0.040000000000000000\"", + "\"-0.040000000000000000\"\n", + }, + { + NewDecWithPrec(1414213562373095049, 18), + "31343134323133353632333733303935303439", + "\"1.414213562373095049\"", + "\"1.414213562373095049\"\n", + }, + { + NewDecWithPrec(-1414213562373095049, 18), + "2D31343134323133353632333733303935303439", + "\"-1.414213562373095049\"", + "\"-1.414213562373095049\"\n", + }, + } + + for _, tc := range testCases { + bz, err := tc.input.Marshal() + require.NoError(t, err) + require.Equal(t, tc.rawBz, fmt.Sprintf("%X", bz)) + + var other Dec + require.NoError(t, (&other).Unmarshal(bz)) + require.True(t, tc.input.Equal(other)) + + bz, err = json.Marshal(tc.input) + require.NoError(t, err) + require.Equal(t, tc.jsonStr, string(bz)) + require.NoError(t, json.Unmarshal(bz, &other)) + require.True(t, tc.input.Equal(other)) + + bz, err = yaml.Marshal(tc.input) + require.NoError(t, err) + require.Equal(t, tc.yamlStr, string(bz)) + } +} diff --git a/types/int.go b/types/int.go index caabdb11318c..9cc99a013263 100644 --- a/types/int.go +++ b/types/int.go @@ -1,6 +1,7 @@ package types import ( + "encoding" "encoding/json" "fmt" "testing" @@ -52,12 +53,6 @@ func max(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Set(i) } -// MarshalAmino for custom encoding scheme -func marshalAmino(i *big.Int) (string, error) { - bz, err := i.MarshalText() - return string(bz), err -} - func unmarshalText(i *big.Int, text string) error { if err := i.UnmarshalText([]byte(text)); err != nil { return err @@ -70,32 +65,7 @@ func unmarshalText(i *big.Int, text string) error { return nil } -// UnmarshalAmino for custom decoding scheme -func unmarshalAmino(i *big.Int, text string) (err error) { - return unmarshalText(i, text) -} - -// MarshalJSON for custom encoding scheme -// Must be encoded as a string for JSON precision -func marshalJSON(i *big.Int) ([]byte, error) { - text, err := i.MarshalText() - if err != nil { - return nil, err - } - return json.Marshal(string(text)) -} - -// UnmarshalJSON for custom decoding scheme -// Must be encoded as a string for JSON precision -func unmarshalJSON(i *big.Int, bz []byte) error { - var text string - err := json.Unmarshal(bz, &text) - if err != nil { - return err - } - - return unmarshalText(i, text) -} +var _ CustomProtobufType = (*Int)(nil) // Int wraps integer with 256 bit range bound // Checks overflow, underflow and division by zero @@ -341,40 +311,107 @@ func (i Int) String() string { return i.i.String() } -// MarshalAmino defines custom encoding scheme -func (i Int) MarshalAmino() (string, error) { +// MarshalJSON defines custom encoding scheme +func (i Int) MarshalJSON() ([]byte, error) { if i.i == nil { // Necessary since default Uint initialization has i.i as nil i.i = new(big.Int) } - return marshalAmino(i.i) + return marshalJSON(i.i) } -// UnmarshalAmino defines custom decoding scheme -func (i *Int) UnmarshalAmino(text string) error { +// UnmarshalJSON defines custom decoding scheme +func (i *Int) UnmarshalJSON(bz []byte) error { if i.i == nil { // Necessary since default Int initialization has i.i as nil i.i = new(big.Int) } - return unmarshalAmino(i.i, text) + return unmarshalJSON(i.i, bz) } -// MarshalJSON defines custom encoding scheme -func (i Int) MarshalJSON() ([]byte, error) { - if i.i == nil { // Necessary since default Uint initialization has i.i as nil +// MarshalJSON for custom encoding scheme +// Must be encoded as a string for JSON precision +func marshalJSON(i encoding.TextMarshaler) ([]byte, error) { + text, err := i.MarshalText() + if err != nil { + return nil, err + } + + return json.Marshal(string(text)) +} + +// UnmarshalJSON for custom decoding scheme +// Must be encoded as a string for JSON precision +func unmarshalJSON(i *big.Int, bz []byte) error { + var text string + if err := json.Unmarshal(bz, &text); err != nil { + return err + } + + return unmarshalText(i, text) +} + +// MarshalYAML returns the YAML representation. +func (i Int) MarshalYAML() (interface{}, error) { + return i.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (i Int) Marshal() ([]byte, error) { + if i.i == nil { i.i = new(big.Int) } - return marshalJSON(i.i) + return i.i.MarshalText() } -// UnmarshalJSON defines custom decoding scheme -func (i *Int) UnmarshalJSON(bz []byte) error { - if i.i == nil { // Necessary since default Int initialization has i.i as nil +// MarshalTo implements the gogo proto custom type interface. +func (i *Int) MarshalTo(data []byte) (n int, err error) { + if i.i == nil { i.i = new(big.Int) } - return unmarshalJSON(i.i, bz) + if len(i.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := i.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (i *Int) Unmarshal(data []byte) error { + if len(data) == 0 { + i = nil + return nil + } + + if i.i == nil { + i.i = new(big.Int) + } + + if err := i.i.UnmarshalText(data); err != nil { + return err + } + + if i.i.BitLen() > maxBitLen { + return fmt.Errorf("integer out of range; got: %d, max: %d", i.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (i *Int) Size() int { + bz, _ := i.Marshal() + return len(bz) } -// MarshalYAML returns Ythe AML representation. -func (i Int) MarshalYAML() (interface{}, error) { return i.String(), nil } +// Override Amino binary serialization by proxying to protobuf. +func (i Int) MarshalAmino() ([]byte, error) { return i.Marshal() } +func (i *Int) UnmarshalAmino(bz []byte) error { return i.Unmarshal(bz) } // intended to be used with require/assert: require.True(IntEq(...)) func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) { diff --git a/types/int_test.go b/types/int_test.go index 072b2f47bb9a..7a8ceade1748 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -282,21 +282,21 @@ func TestEncodingRandom(t *testing.T) { ni := NewInt(n) var ri Int - str, err := ni.MarshalAmino() + str, err := ni.Marshal() require.Nil(t, err) - err = (&ri).UnmarshalAmino(str) + err = (&ri).Unmarshal(str) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "binary mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) bz, err := ni.MarshalJSON() require.Nil(t, err) err = (&ri).UnmarshalJSON(bz) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "json mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) } for i := 0; i < 1000; i++ { @@ -304,21 +304,21 @@ func TestEncodingRandom(t *testing.T) { ni := NewUint(n) var ri Uint - str, err := ni.MarshalAmino() + str, err := ni.Marshal() require.Nil(t, err) - err = (&ri).UnmarshalAmino(str) + err = (&ri).Unmarshal(str) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalAmino * UnmarshalAmino is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "binary mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) bz, err := ni.MarshalJSON() require.Nil(t, err) err = (&ri).UnmarshalJSON(bz) require.Nil(t, err) - require.Equal(t, ni, ri, "MarshalJSON * UnmarshalJSON is not identity. tc #%d, Expected %s, Actual %s", i, ni.String(), ri.String()) - require.True(t, ni.i != ri.i, "Pointer addresses are equal. tc #%d", i) + require.Equal(t, ni, ri, "json mismatch; tc #%d, expected %s, actual %s", i, ni.String(), ri.String()) + require.True(t, ni.i != ri.i, "pointer addresses are equal; tc #%d", i) } } @@ -326,29 +326,71 @@ func TestEncodingTableInt(t *testing.T) { var i Int cases := []struct { - i Int - bz []byte - str string + i Int + jsonBz []byte + rawBz []byte }{ - {NewInt(0), []byte("\"0\""), "0"}, - {NewInt(100), []byte("\"100\""), "100"}, - {NewInt(51842), []byte("\"51842\""), "51842"}, - {NewInt(19513368), []byte("\"19513368\""), "19513368"}, - {NewInt(999999999999), []byte("\"999999999999\""), "999999999999"}, + { + NewInt(0), + []byte("\"0\""), + []byte{0x30}, + }, + { + NewInt(100), + []byte("\"100\""), + []byte{0x31, 0x30, 0x30}, + }, + { + NewInt(-100), + []byte("\"-100\""), + []byte{0x2d, 0x31, 0x30, 0x30}, + }, + { + NewInt(51842), + []byte("\"51842\""), + []byte{0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewInt(-51842), + []byte("\"-51842\""), + []byte{0x2d, 0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewInt(19513368), + []byte("\"19513368\""), + []byte{0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewInt(-19513368), + []byte("\"-19513368\""), + []byte{0x2d, 0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewInt(999999999999), + []byte("\"999999999999\""), + []byte{0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, + { + NewInt(-999999999999), + []byte("\"-999999999999\""), + []byte{0x2d, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, } for tcnum, tc := range cases { bz, err := tc.i.MarshalJSON() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + require.Equal(t, tc.jsonBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) - str, err := tc.i.MarshalAmino() + bz, err = tc.i.Marshal() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum) - err = (&i).UnmarshalAmino(str) + require.Equal(t, tc.rawBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + + err = (&i).Unmarshal(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) } @@ -358,29 +400,51 @@ func TestEncodingTableUint(t *testing.T) { var i Uint cases := []struct { - i Uint - bz []byte - str string + i Uint + jsonBz []byte + rawBz []byte }{ - {NewUint(0), []byte("\"0\""), "0"}, - {NewUint(100), []byte("\"100\""), "100"}, - {NewUint(51842), []byte("\"51842\""), "51842"}, - {NewUint(19513368), []byte("\"19513368\""), "19513368"}, - {NewUint(999999999999), []byte("\"999999999999\""), "999999999999"}, + { + NewUint(0), + []byte("\"0\""), + []byte{0x30}, + }, + { + NewUint(100), + []byte("\"100\""), + []byte{0x31, 0x30, 0x30}, + }, + { + NewUint(51842), + []byte("\"51842\""), + []byte{0x35, 0x31, 0x38, 0x34, 0x32}, + }, + { + NewUint(19513368), + []byte("\"19513368\""), + []byte{0x31, 0x39, 0x35, 0x31, 0x33, 0x33, 0x36, 0x38}, + }, + { + NewUint(999999999999), + []byte("\"999999999999\""), + []byte{0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39}, + }, } for tcnum, tc := range cases { bz, err := tc.i.MarshalJSON() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.bz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + require.Equal(t, tc.jsonBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + err = (&i).UnmarshalJSON(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) - str, err := tc.i.MarshalAmino() + bz, err = tc.i.Marshal() require.Nil(t, err, "Error marshaling Int. tc #%d, err %s", tcnum, err) - require.Equal(t, tc.str, str, "Marshaled value is different from exported. tc #%d", tcnum) - err = (&i).UnmarshalAmino(str) + require.Equal(t, tc.rawBz, bz, "Marshaled value is different from exported. tc #%d", tcnum) + + err = (&i).Unmarshal(bz) require.Nil(t, err, "Error unmarshaling Int. tc #%d, err %s", tcnum, err) require.Equal(t, tc.i, i, "Unmarshaled value is different from exported. tc #%d", tcnum) } @@ -391,15 +455,15 @@ func TestSerializationOverflow(t *testing.T) { x := Int{bx} y := new(Int) - // require amino deserialization to fail due to overflow - xStr, err := x.MarshalAmino() + bz, err := x.Marshal() require.NoError(t, err) - err = y.UnmarshalAmino(xStr) + // require deserialization to fail due to overflow + err = y.Unmarshal(bz) require.Error(t, err) // require JSON deserialization to fail due to overflow - bz, err := x.MarshalJSON() + bz, err = x.MarshalJSON() require.NoError(t, err) err = y.UnmarshalJSON(bz) diff --git a/types/proto.go b/types/proto.go new file mode 100644 index 000000000000..e4cdbdc511c0 --- /dev/null +++ b/types/proto.go @@ -0,0 +1,20 @@ +package types + +import ( + _ "github.com/gogo/protobuf/gogoproto" // nolint + _ "github.com/regen-network/cosmos-proto" // nolint +) + +// CustomProtobufType defines the interface custom gogo proto types must implement +// in order to be used as a "customtype" extension. +// +// ref: https://github.com/gogo/protobuf/blob/master/custom_types.md +type CustomProtobufType interface { + Marshal() ([]byte, error) + MarshalTo(data []byte) (n int, err error) + Unmarshal(data []byte) error + Size() int + + MarshalJSON() ([]byte, error) + UnmarshalJSON(data []byte) error +} diff --git a/types/types.pb.go b/types/types.pb.go new file mode 100644 index 000000000000..4ea0bfeec523 --- /dev/null +++ b/types/types.pb.go @@ -0,0 +1,595 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: types/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Coin defines a token with a denomination and an amount. +// +// NOTE: The amount field is an Int which implements the custom method +// signatures required by gogoproto. +type Coin struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Amount Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=Int" json:"amount"` +} + +func (m *Coin) Reset() { *m = Coin{} } +func (*Coin) ProtoMessage() {} +func (*Coin) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{0} +} +func (m *Coin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Coin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Coin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Coin) XXX_Merge(src proto.Message) { + xxx_messageInfo_Coin.Merge(m, src) +} +func (m *Coin) XXX_Size() int { + return m.Size() +} +func (m *Coin) XXX_DiscardUnknown() { + xxx_messageInfo_Coin.DiscardUnknown(m) +} + +var xxx_messageInfo_Coin proto.InternalMessageInfo + +func (m *Coin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +// DecCoin defines a token with a denomination and a decimal amount. +// +// NOTE: The amount field is an Dec which implements the custom method +// signatures required by gogoproto. +type DecCoin struct { + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + Amount Dec `protobuf:"bytes,2,opt,name=amount,proto3,customtype=Dec" json:"amount"` +} + +func (m *DecCoin) Reset() { *m = DecCoin{} } +func (*DecCoin) ProtoMessage() {} +func (*DecCoin) Descriptor() ([]byte, []int) { + return fileDescriptor_2c0f90c600ad7e2e, []int{1} +} +func (m *DecCoin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DecCoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DecCoin.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DecCoin) XXX_Merge(src proto.Message) { + xxx_messageInfo_DecCoin.Merge(m, src) +} +func (m *DecCoin) XXX_Size() int { + return m.Size() +} +func (m *DecCoin) XXX_DiscardUnknown() { + xxx_messageInfo_DecCoin.DiscardUnknown(m) +} + +var xxx_messageInfo_DecCoin proto.InternalMessageInfo + +func (m *DecCoin) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func init() { + proto.RegisterType((*Coin)(nil), "cosmos_sdk.v1.Coin") + proto.RegisterType((*DecCoin)(nil), "cosmos_sdk.v1.DecCoin") +} + +func init() { proto.RegisterFile("types/types.proto", fileDescriptor_2c0f90c600ad7e2e) } + +var fileDescriptor_2c0f90c600ad7e2e = []byte{ + // 214 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xa9, 0x2c, 0x48, + 0x2d, 0xd6, 0x07, 0x93, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xbc, 0xc9, 0xf9, 0xc5, 0xb9, + 0xf9, 0xc5, 0xf1, 0xc5, 0x29, 0xd9, 0x7a, 0x65, 0x86, 0x52, 0x6a, 0x25, 0x19, 0x99, 0x45, 0x29, + 0xf1, 0x05, 0x89, 0x45, 0x25, 0x95, 0xfa, 0x60, 0x15, 0xfa, 0xe9, 0xf9, 0xe9, 0xf9, 0x08, 0x16, + 0x44, 0x9b, 0x92, 0x23, 0x17, 0x8b, 0x73, 0x7e, 0x66, 0x9e, 0x90, 0x08, 0x17, 0x6b, 0x4a, 0x6a, + 0x5e, 0x7e, 0xae, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x84, 0x23, 0xa4, 0xcc, 0xc5, 0x96, + 0x98, 0x9b, 0x5f, 0x9a, 0x57, 0x22, 0xc1, 0x04, 0x12, 0x76, 0xe2, 0x3e, 0x71, 0x4f, 0x9e, 0xe1, + 0xd6, 0x3d, 0x79, 0x66, 0xcf, 0xbc, 0x92, 0x20, 0xa8, 0x94, 0x92, 0x0b, 0x17, 0xbb, 0x4b, 0x6a, + 0x32, 0x39, 0xa6, 0xb8, 0xa4, 0x26, 0xc3, 0x4c, 0x71, 0x72, 0xb9, 0xf1, 0x50, 0x8e, 0xa1, 0xe1, + 0x91, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, + 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x29, 0xa5, 0x67, + 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x3c, 0x0b, 0xa5, 0x74, 0x8b, 0x53, + 0xb2, 0x21, 0x61, 0x91, 0xc4, 0x06, 0xf6, 0x95, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xc6, + 0x8c, 0x7d, 0x21, 0x01, 0x00, 0x00, +} + +func (m *Coin) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Coin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Coin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DecCoin) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DecCoin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DecCoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Coin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *DecCoin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Coin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Coin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Coin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DecCoin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DecCoin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DecCoin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/types/types.proto b/types/types.proto new file mode 100644 index 000000000000..49da4e5c69f9 --- /dev/null +++ b/types/types.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package cosmos_sdk.v1; + +import "third_party/proto/gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = false; + +// Coin defines a token with a denomination and an amount. +// +// NOTE: The amount field is an Int which implements the custom method +// signatures required by gogoproto. +message Coin { + string denom = 1; + string amount = 2 [ (gogoproto.customtype) = "Int", (gogoproto.nullable) = false ]; +} + +// DecCoin defines a token with a denomination and a decimal amount. +// +// NOTE: The amount field is an Dec which implements the custom method +// signatures required by gogoproto. +message DecCoin { + string denom = 1; + string amount = 2 [ (gogoproto.customtype) = "Dec", (gogoproto.nullable) = false ]; +} diff --git a/types/uint.go b/types/uint.go index 976b6414a93f..2305d7386728 100644 --- a/types/uint.go +++ b/types/uint.go @@ -49,6 +49,8 @@ func ZeroUint() Uint { return Uint{big.NewInt(0)} } // OneUint returns Uint value with one. func OneUint() Uint { return Uint{big.NewInt(1)} } +var _ CustomProtobufType = (*Uint)(nil) + // Uint64 converts Uint to uint64 // Panics if the value is out of range func (u Uint) Uint64() uint64 { @@ -130,38 +132,81 @@ func MaxUint(u1, u2 Uint) Uint { return NewUintFromBigInt(max(u1.i, u2.i)) } // Human readable string func (u Uint) String() string { return u.i.String() } -// MarshalAmino defines custom encoding scheme -func (u Uint) MarshalAmino() (string, error) { +// MarshalJSON defines custom encoding scheme +func (u Uint) MarshalJSON() ([]byte, error) { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } - return marshalAmino(u.i) + return marshalJSON(u.i) } -// UnmarshalAmino defines custom decoding scheme -func (u *Uint) UnmarshalAmino(text string) error { +// UnmarshalJSON defines custom decoding scheme +func (u *Uint) UnmarshalJSON(bz []byte) error { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } - return unmarshalAmino(u.i, text) + return unmarshalJSON(u.i, bz) } -// MarshalJSON defines custom encoding scheme -func (u Uint) MarshalJSON() ([]byte, error) { - if u.i == nil { // Necessary since default Uint initialization has i.i as nil +// Marshal implements the gogo proto custom type interface. +func (u Uint) Marshal() ([]byte, error) { + if u.i == nil { u.i = new(big.Int) } - return marshalJSON(u.i) + return u.i.MarshalText() } -// UnmarshalJSON defines custom decoding scheme -func (u *Uint) UnmarshalJSON(bz []byte) error { - if u.i == nil { // Necessary since default Uint initialization has i.i as nil +// MarshalTo implements the gogo proto custom type interface. +func (u *Uint) MarshalTo(data []byte) (n int, err error) { + if u.i == nil { u.i = new(big.Int) } - return unmarshalJSON(u.i, bz) + if len(u.i.Bytes()) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := u.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil } +// Unmarshal implements the gogo proto custom type interface. +func (u *Uint) Unmarshal(data []byte) error { + if len(data) == 0 { + u = nil + return nil + } + + if u.i == nil { + u.i = new(big.Int) + } + + if err := u.i.UnmarshalText(data); err != nil { + return err + } + + if u.i.BitLen() > maxBitLen { + return fmt.Errorf("integer out of range; got: %d, max: %d", u.i.BitLen(), maxBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (u *Uint) Size() int { + bz, _ := u.Marshal() + return len(bz) +} + +// Override Amino binary serialization by proxying to protobuf. +func (u Uint) MarshalAmino() ([]byte, error) { return u.Marshal() } +func (u *Uint) UnmarshalAmino(bz []byte) error { return u.Unmarshal(bz) } + //__________________________________________________________________________ // UintOverflow returns true if a given unsigned integer overflows and false diff --git a/x/simulation/rand_util.go b/x/simulation/rand_util.go index b494b0fb8aab..7ef09100d545 100644 --- a/x/simulation/rand_util.go +++ b/x/simulation/rand_util.go @@ -69,9 +69,9 @@ func RandomDecAmount(r *rand.Rand, max sdk.Dec) sdk.Dec { case 0: // randInt = big.NewInt(0) case 1: - randInt = max.Int // the underlying big int with all precision bits. + randInt = max.BigInt() // the underlying big int with all precision bits. default: // NOTE: there are 10 total cases. - randInt = big.NewInt(0).Rand(r, max.Int) + randInt = big.NewInt(0).Rand(r, max.BigInt()) } return sdk.NewDecFromBigIntWithPrec(randInt, sdk.Precision) }