From 9a67d3e6de44ef173adc45e88f2d7d68fa3541cb Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 23 Sep 2024 09:22:30 +0200 Subject: [PATCH 01/11] fix(client/v2): support legacydec --- client/v2/autocli/flag/builder.go | 2 ++ client/v2/autocli/flag/legacy_dec.go | 44 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 client/v2/autocli/flag/legacy_dec.go diff --git a/client/v2/autocli/flag/builder.go b/client/v2/autocli/flag/builder.go index 6ff325c53bdb..bdd42634dd35 100644 --- a/client/v2/autocli/flag/builder.go +++ b/client/v2/autocli/flag/builder.go @@ -26,6 +26,7 @@ const ( ValidatorAddressStringScalarType = "cosmos.ValidatorAddressString" ConsensusAddressStringScalarType = "cosmos.ConsensusAddressString" PubkeyScalarType = "cosmos.Pubkey" + DecScalarType = "cosmos.Dec" ) // Builder manages options for building pflag flags for protobuf messages. @@ -67,6 +68,7 @@ func (b *Builder) init() { b.scalarFlagTypes[ValidatorAddressStringScalarType] = validatorAddressStringType{} b.scalarFlagTypes[ConsensusAddressStringScalarType] = consensusAddressStringType{} b.scalarFlagTypes[PubkeyScalarType] = pubkeyType{} + b.scalarFlagTypes[DecScalarType] = decType{} } } diff --git a/client/v2/autocli/flag/legacy_dec.go b/client/v2/autocli/flag/legacy_dec.go new file mode 100644 index 000000000000..010e9406eaaf --- /dev/null +++ b/client/v2/autocli/flag/legacy_dec.go @@ -0,0 +1,44 @@ +package flag + +import ( + "context" + + "cosmossdk.io/math" + "google.golang.org/protobuf/reflect/protoreflect" +) + +type decType struct{} + +func (a decType) NewValue(_ *context.Context, _ *Builder) Value { + return &decValue{} +} + +func (a decType) DefaultValue() string { + return "0" +} + +type decValue struct { + value string +} + +func (a decValue) Get(protoreflect.Value) (protoreflect.Value, error) { + return protoreflect.ValueOf(a.value), nil +} + +func (a decValue) String() string { + return a.value +} + +func (a *decValue) Set(s string) error { + dec, err := math.LegacyNewDecFromStr(s) + if err != nil { + return err + } + a.value = dec.String() + + return nil +} + +func (a decValue) Type() string { + return "math.LegacyDec" +} From b723b0a1e87961969852a5d6c1b92479906dbf3a Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 23 Sep 2024 14:06:36 +0200 Subject: [PATCH 02/11] better errors --- client/v2/autocli/flag/legacy_dec.go | 2 +- x/auth/tx/builder.go | 10 +++++----- x/tx/decode/decode.go | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/v2/autocli/flag/legacy_dec.go b/client/v2/autocli/flag/legacy_dec.go index 010e9406eaaf..3b51505938a1 100644 --- a/client/v2/autocli/flag/legacy_dec.go +++ b/client/v2/autocli/flag/legacy_dec.go @@ -40,5 +40,5 @@ func (a *decValue) Set(s string) error { } func (a decValue) Type() string { - return "math.LegacyDec" + return "cosmos.Dec" } diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index 423bca3a0870..2b1c866e8e0a 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -112,7 +112,7 @@ var marshalOption = proto.MarshalOptions{ func (w *builder) getTx() (*gogoTxWrapper, error) { anyMsgs, err := msgsV1toAnyV2(w.msgs) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to convert messages: %w", err) } body := &txv1beta1.TxBody{ Messages: anyMsgs, @@ -136,12 +136,12 @@ func (w *builder) getTx() (*gogoTxWrapper, error) { bodyBytes, err := marshalOption.Marshal(body) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to marshal body: %w", err) } authInfoBytes, err := marshalOption.Marshal(authInfo) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to marshal auth info: %w", err) } txRawBytes, err := marshalOption.Marshal(&txv1beta1.TxRaw{ @@ -150,12 +150,12 @@ func (w *builder) getTx() (*gogoTxWrapper, error) { Signatures: w.signatures, }) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to marshal tx raw: %w", err) } decodedTx, err := w.decoder.Decode(txRawBytes) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decode tx: %w", err) } return newWrapperFromDecodedTx(w.addressCodec, w.codec, decodedTx) diff --git a/x/tx/decode/decode.go b/x/tx/decode/decode.go index 994d54cf488b..bf4f3a54f31f 100644 --- a/x/tx/decode/decode.go +++ b/x/tx/decode/decode.go @@ -84,7 +84,7 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { err = proto.Unmarshal(txBytes, &raw) if err != nil { - return nil, err + return nil, errorsmod.Wrap(ErrTxDecode, err.Error()) } var body v1beta1.TxBody @@ -136,7 +136,7 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { dynamicMsg := dynamicpb.NewMessageType(msgDesc.(protoreflect.MessageDescriptor)).New().Interface() err = anyMsg.UnmarshalTo(dynamicMsg) if err != nil { - return nil, err + return nil, errorsmod.Wrap(ErrTxDecode, fmt.Sprintf("cannot unmarshal Any message: %v", err)) } dynamicMsgs = append(dynamicMsgs, dynamicMsg) @@ -148,7 +148,7 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { msg := reflect.New(gogoType.Elem()).Interface().(gogoproto.Message) err = d.codec.Unmarshal(anyMsg.Value, msg) if err != nil { - return nil, err + return nil, errorsmod.Wrap(ErrTxDecode, err.Error()) } msgs = append(msgs, msg) From 45e25a71332b3834a36e13d04bb9024dda9efdc6 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 13:49:25 +0200 Subject: [PATCH 03/11] fixes --- client/v2/autocli/flag/legacy_dec.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/v2/autocli/flag/legacy_dec.go b/client/v2/autocli/flag/legacy_dec.go index 3b51505938a1..ed23cc6197e7 100644 --- a/client/v2/autocli/flag/legacy_dec.go +++ b/client/v2/autocli/flag/legacy_dec.go @@ -4,6 +4,7 @@ import ( "context" "cosmossdk.io/math" + "google.golang.org/protobuf/reflect/protoreflect" ) @@ -34,7 +35,10 @@ func (a *decValue) Set(s string) error { if err != nil { return err } - a.value = dec.String() + + // we need to convert from float representation to non-float representation using default precision + // 0.5 -> 500000000000000000 + a.value = dec.BigInt().String() return nil } From 310ecea4a9902be9816ffb4b25347776db03d7b4 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 13:51:47 +0200 Subject: [PATCH 04/11] cl --- client/v2/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index a3702845c575..8bd7877b448a 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -53,6 +53,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#17709](https://github.com/cosmos/cosmos-sdk/pull/17709) Address codecs have been removed from `autocli.AppOptions` and `flag.Builder`. Instead client/v2 uses the address codecs present in the context (introduced in [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503)). +### Bug Fixes + +* [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` unmarshalling in txs. + ## [v2.0.0-beta.5] - 2024-09-18 ### Improvements From 036bc1551a7f175c7657c233f043bfe79bbcce84 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 14:16:12 +0200 Subject: [PATCH 05/11] lint --- client/v2/autocli/flag/legacy_dec.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/v2/autocli/flag/legacy_dec.go b/client/v2/autocli/flag/legacy_dec.go index ed23cc6197e7..073afa94f1f5 100644 --- a/client/v2/autocli/flag/legacy_dec.go +++ b/client/v2/autocli/flag/legacy_dec.go @@ -3,9 +3,9 @@ package flag import ( "context" - "cosmossdk.io/math" - "google.golang.org/protobuf/reflect/protoreflect" + + "cosmossdk.io/math" ) type decType struct{} From 04aadcc856f1999ccd856d5a7fa25ada80918bf5 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 14:20:34 +0200 Subject: [PATCH 06/11] fix marshalling --- client/v2/autocli/query.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index d308bcd7633a..05fa3c6d0ca1 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -11,6 +11,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" "cosmossdk.io/math" "cosmossdk.io/x/tx/signing/aminojson" + "cosmossdk.io/x/tx/signing/textual" "github.com/spf13/cobra" "google.golang.org/protobuf/reflect/protoreflect" @@ -171,7 +172,7 @@ func (b *Builder) BuildQueryMethodCommand(ctx context.Context, descriptor protor } func encoder(encoder aminojson.Encoder) aminojson.Encoder { - return encoder.DefineTypeEncoding("google.protobuf.Duration", func(_ *aminojson.Encoder, msg protoreflect.Message, w io.Writer) error { + customEncoder := encoder.DefineTypeEncoding("google.protobuf.Duration", func(_ *aminojson.Encoder, msg protoreflect.Message, w io.Writer) error { var ( secondsName protoreflect.Name = "seconds" nanosName protoreflect.Name = "nanos" @@ -231,4 +232,18 @@ func encoder(encoder aminojson.Encoder) aminojson.Encoder { _, err = fmt.Fprintf(w, `"%s"`, sdk.NewDecCoinFromDec(denom, amountDec)) // TODO(@julienrbrt): Eventually remove this SDK dependency return err }) + + customEncoder.DefineScalarEncoding("cosmos.Dec", func(_ *aminojson.Encoder, value protoreflect.Value, w io.Writer) error { + // this is a hack to use textual definition of decimal rendering instead of duplication the whole encoder here + // if we were to remove textual, let's just copy the code from encoder logic here + formatted, err := textual.NewDecValueRenderer().Format(context.Background(), value) + if err != nil { + return fmt.Errorf("cannot format decimal: %w", err) + } + + _, err = fmt.Fprintf(w, `"%s"`, formatted[0].Content) + return nil + }) + + return customEncoder } From 6b0833de8c6b080350427470e007c49611d55080 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 14:21:36 +0200 Subject: [PATCH 07/11] just copy now --- client/v2/autocli/query.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index 05fa3c6d0ca1..b678beaaf744 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -5,13 +5,13 @@ import ( "errors" "fmt" "io" + "math/big" "strings" "time" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" "cosmossdk.io/math" "cosmossdk.io/x/tx/signing/aminojson" - "cosmossdk.io/x/tx/signing/textual" "github.com/spf13/cobra" "google.golang.org/protobuf/reflect/protoreflect" @@ -234,14 +234,27 @@ func encoder(encoder aminojson.Encoder) aminojson.Encoder { }) customEncoder.DefineScalarEncoding("cosmos.Dec", func(_ *aminojson.Encoder, value protoreflect.Value, w io.Writer) error { - // this is a hack to use textual definition of decimal rendering instead of duplication the whole encoder here - // if we were to remove textual, let's just copy the code from encoder logic here - formatted, err := textual.NewDecValueRenderer().Format(context.Background(), value) + decStr := value.String() + + // If the decimal doesn't contain a point, we assume it's a value formatted using the legacy + // `math.Dec`. So we try to parse it as an integer and then convert it to a + // decimal. + if !strings.Contains(decStr, ".") { + parsedInt, ok := new(big.Int).SetString(decStr, 10) + if !ok { + return fmt.Errorf("invalid decimal: %s", decStr) + } + + // We assume the decimal has 18 digits of precision. + decStr = math.LegacyNewDecFromBigIntWithPrec(parsedInt, math.LegacyPrecision).String() + } + + formatted, err := math.FormatDec(decStr) if err != nil { - return fmt.Errorf("cannot format decimal: %w", err) + return fmt.Errorf("cannot format decimal %s: %w", decStr, err) } - _, err = fmt.Fprintf(w, `"%s"`, formatted[0].Content) + _, err = fmt.Fprintf(w, `"%s"`, formatted) return nil }) From ea371eb175b5be051094b28241a013d6fe990b2e Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 14:21:53 +0200 Subject: [PATCH 08/11] cl --- client/v2/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index 8bd7877b448a..b49389327cc0 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` unmarshalling in txs. +* [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` marshalling in queries. ## [v2.0.0-beta.5] - 2024-09-18 From 0ced709cb7781ea3a64c7531064721329a09a5b3 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 14:54:01 +0200 Subject: [PATCH 09/11] lint --- client/v2/autocli/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index b678beaaf744..73a7ee472ca4 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -255,7 +255,7 @@ func encoder(encoder aminojson.Encoder) aminojson.Encoder { } _, err = fmt.Fprintf(w, `"%s"`, formatted) - return nil + return err }) return customEncoder From 3504e4107e13bf68e2b81eab73b9971b719a1ef6 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 7 Oct 2024 15:12:01 +0200 Subject: [PATCH 10/11] updates --- client/v2/autocli/query.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index 73a7ee472ca4..790a94f8cb91 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -235,6 +235,9 @@ func encoder(encoder aminojson.Encoder) aminojson.Encoder { customEncoder.DefineScalarEncoding("cosmos.Dec", func(_ *aminojson.Encoder, value protoreflect.Value, w io.Writer) error { decStr := value.String() + if strings.Contains(decStr, "[") { // check if it's a bytes field (e.g mint inflation) + decStr = string(value.Bytes()) + } // If the decimal doesn't contain a point, we assume it's a value formatted using the legacy // `math.Dec`. So we try to parse it as an integer and then convert it to a From e6e45832efce5017ded0123d6e31cfe00ae75778 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 8 Oct 2024 08:23:18 +0200 Subject: [PATCH 11/11] revert marshal changes (fixed by #22161) --- client/v2/CHANGELOG.md | 1 - client/v2/autocli/query.go | 33 +-------------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index b49389327cc0..8bd7877b448a 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -56,7 +56,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` unmarshalling in txs. -* [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` marshalling in queries. ## [v2.0.0-beta.5] - 2024-09-18 diff --git a/client/v2/autocli/query.go b/client/v2/autocli/query.go index 790a94f8cb91..d308bcd7633a 100644 --- a/client/v2/autocli/query.go +++ b/client/v2/autocli/query.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "math/big" "strings" "time" @@ -172,7 +171,7 @@ func (b *Builder) BuildQueryMethodCommand(ctx context.Context, descriptor protor } func encoder(encoder aminojson.Encoder) aminojson.Encoder { - customEncoder := encoder.DefineTypeEncoding("google.protobuf.Duration", func(_ *aminojson.Encoder, msg protoreflect.Message, w io.Writer) error { + return encoder.DefineTypeEncoding("google.protobuf.Duration", func(_ *aminojson.Encoder, msg protoreflect.Message, w io.Writer) error { var ( secondsName protoreflect.Name = "seconds" nanosName protoreflect.Name = "nanos" @@ -232,34 +231,4 @@ func encoder(encoder aminojson.Encoder) aminojson.Encoder { _, err = fmt.Fprintf(w, `"%s"`, sdk.NewDecCoinFromDec(denom, amountDec)) // TODO(@julienrbrt): Eventually remove this SDK dependency return err }) - - customEncoder.DefineScalarEncoding("cosmos.Dec", func(_ *aminojson.Encoder, value protoreflect.Value, w io.Writer) error { - decStr := value.String() - if strings.Contains(decStr, "[") { // check if it's a bytes field (e.g mint inflation) - decStr = string(value.Bytes()) - } - - // If the decimal doesn't contain a point, we assume it's a value formatted using the legacy - // `math.Dec`. So we try to parse it as an integer and then convert it to a - // decimal. - if !strings.Contains(decStr, ".") { - parsedInt, ok := new(big.Int).SetString(decStr, 10) - if !ok { - return fmt.Errorf("invalid decimal: %s", decStr) - } - - // We assume the decimal has 18 digits of precision. - decStr = math.LegacyNewDecFromBigIntWithPrec(parsedInt, math.LegacyPrecision).String() - } - - formatted, err := math.FormatDec(decStr) - if err != nil { - return fmt.Errorf("cannot format decimal %s: %w", decStr, err) - } - - _, err = fmt.Fprintf(w, `"%s"`, formatted) - return err - }) - - return customEncoder }