diff --git a/CHANGELOG.md b/CHANGELOG.md index faa7b5de251a..2e9afc75a238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (x/auth) [#14650](https://github.com/cosmos/cosmos-sdk/pull/14650) Add Textual SignModeHandler. It is however **NOT** enabled by default, and should only be used for **TESTING** purposes until `SIGN_MODE_TEXTUAL` is fully released. * (cli) [#14655](https://github.com/cosmos/cosmos-sdk/pull/14655) Add a new command to list supported algos. * (x/crisis) [#14588](https://github.com/cosmos/cosmos-sdk/pull/14588) Use CacheContext() in AssertInvariants() * (client) [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) Add `simd config` command is now a sub-command, for setting, getting and migrating Cosmos SDK configuration files. diff --git a/go.mod b/go.mod index bd0a942abbee..05257d13d0e5 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0-beta.7 cosmossdk.io/math v1.0.0-beta.4 + cosmossdk.io/x/tx v0.1.0 github.com/99designs/keyring v1.2.1 github.com/armon/go-metrics v0.4.1 github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 diff --git a/go.sum b/go.sum index 910bd1b02d3e..0ef6d48857ed 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= +cosmossdk.io/x/tx v0.1.0 h1:uyyYVjG22B+jf54N803Z99Y1uPvfuNP3K1YShoCHYL8= +cosmossdk.io/x/tx v0.1.0/go.mod h1:qsDv7e1fSftkF16kpSAk+7ROOojyj+SC0Mz3ukI52EQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= diff --git a/proto/cosmos/tx/signing/v1beta1/signing.proto b/proto/cosmos/tx/signing/v1beta1/signing.proto index 12d5868ba8f4..faad739b5aab 100644 --- a/proto/cosmos/tx/signing/v1beta1/signing.proto +++ b/proto/cosmos/tx/signing/v1beta1/signing.proto @@ -25,7 +25,9 @@ enum SignMode { // SIGN_MODE_TEXTUAL is a future signing mode that will verify some // human-readable textual representation on top of the binary representation - // from SIGN_MODE_DIRECT. It is currently not supported. + // from SIGN_MODE_DIRECT. It is currently experimental, and should be used + // for testing purposes only, until Textual is fully released. Please follow + // the tracking issue https://github.com/cosmos/cosmos-sdk/issues/11970. SIGN_MODE_TEXTUAL = 2; // SIGN_MODE_DIRECT_AUX specifies a signing mode which uses diff --git a/simapp/go.mod b/simapp/go.mod index a7cc2cdb7d9b..4d68c020de87 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -31,6 +31,7 @@ require ( cloud.google.com/go/storage v1.27.0 // indirect cosmossdk.io/collections v0.0.0-20230106101515-aeac21494476 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect + cosmossdk.io/x/tx v0.1.0 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index 1480ce87f05f..c163b08138e3 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -62,6 +62,8 @@ cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= cosmossdk.io/tools/rosetta v0.2.0 h1:Ae499UiZ9yPNCXvjOBO/R9I1pksCJfxoqWauEZgA/gs= cosmossdk.io/tools/rosetta v0.2.0/go.mod h1:3mn8QuE2wLUdTi77/gbDXdFqXZdBdiBJhgAWUTSXPv8= +cosmossdk.io/x/tx v0.1.0 h1:uyyYVjG22B+jf54N803Z99Y1uPvfuNP3K1YShoCHYL8= +cosmossdk.io/x/tx v0.1.0/go.mod h1:qsDv7e1fSftkF16kpSAk+7ROOojyj+SC0Mz3ukI52EQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= diff --git a/tests/go.mod b/tests/go.mod index a476011c07b0..2e1195dbb3c2 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -32,6 +32,7 @@ require ( cosmossdk.io/collections v0.0.0-20230106101515-aeac21494476 // indirect cosmossdk.io/core v0.4.1 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect + cosmossdk.io/x/tx v0.1.0 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index bb0cf2687028..12771437d21a 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -60,6 +60,8 @@ cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= +cosmossdk.io/x/tx v0.1.0 h1:uyyYVjG22B+jf54N803Z99Y1uPvfuNP3K1YShoCHYL8= +cosmossdk.io/x/tx v0.1.0/go.mod h1:qsDv7e1fSftkF16kpSAk+7ROOojyj+SC0Mz3ukI52EQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= diff --git a/x/auth/tx/config.go b/x/auth/tx/config.go index 5e6f1074e891..5193f1b745d7 100644 --- a/x/auth/tx/config.go +++ b/x/auth/tx/config.go @@ -3,6 +3,7 @@ package tx import ( "fmt" + "cosmossdk.io/x/tx/textual" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,10 +22,25 @@ type config struct { // NewTxConfig returns a new protobuf TxConfig using the provided ProtoCodec and sign modes. The // first enabled sign mode will become the default sign mode. +// // NOTE: Use NewTxConfigWithHandler to provide a custom signing handler in case the sign mode -// is not supported by default (eg: SignMode_SIGN_MODE_EIP_191). +// is not supported by default (eg: SignMode_SIGN_MODE_EIP_191). Use NewTxConfigWithTextual +// to enable SIGN_MODE_TEXTUAL (for testing purposes for now). func NewTxConfig(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode) client.TxConfig { - return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes)) + for _, m := range enabledSignModes { + if m == signingtypes.SignMode_SIGN_MODE_TEXTUAL { + panic("cannot use NewTxConfig with SIGN_MODE_TEXTUAL enabled; please use NewTxConfigWithTextual") + } + } + + return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, textual.NewTextual(nil))) +} + +// NewTxConfigWithTextual is like NewTxConfig with the ability to add +// a SIGN_MODE_TEXTUAL renderer. It is currently still EXPERIMENTAL, for should +// be used for TESTING purposes only, until Textual is fully released. +func NewTxConfigWithTextual(protoCodec codec.ProtoCodecMarshaler, enabledSignModes []signingtypes.SignMode, textual textual.Textual) client.TxConfig { + return NewTxConfigWithHandler(protoCodec, makeSignModeHandler(enabledSignModes, textual)) } // NewTxConfig returns a new protobuf TxConfig using the provided ProtoCodec and signing handler. diff --git a/x/auth/tx/config/config.go b/x/auth/tx/config/config.go index 3f6085836e94..5a9305bd4435 100644 --- a/x/auth/tx/config/config.go +++ b/x/auth/tx/config/config.go @@ -1,11 +1,17 @@ package tx import ( + "context" "fmt" + "google.golang.org/grpc/codes" + grpcstatus "google.golang.org/grpc/status" + + bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" + "cosmossdk.io/x/tx/textual" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -15,6 +21,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/posthandler" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank/types" feegrantkeeper "github.com/cosmos/cosmos-sdk/x/feegrant/keeper" ) @@ -31,8 +38,11 @@ type TxInputs struct { Config *txconfigv1.Config ProtoCodecMarshaler codec.ProtoCodecMarshaler - AccountKeeper ante.AccountKeeper `optional:"true"` - BankKeeper authtypes.BankKeeper `optional:"true"` + AccountKeeper ante.AccountKeeper `optional:"true"` + // BankKeeper is the expected bank keeper to be passed to AnteHandlers + BankKeeper authtypes.BankKeeper `optional:"true"` + // TxBankKeeper is the expected bank keeper to be passed to Textual + TxBankKeeper BankKeeper FeeGrantKeeper feegrantkeeper.Keeper `optional:"true"` } @@ -45,7 +55,8 @@ type TxOutputs struct { } func ProvideModule(in TxInputs) TxOutputs { - txConfig := tx.NewTxConfig(in.ProtoCodecMarshaler, tx.DefaultSignModes) + textual := newTextualWithBankKeeper(in.TxBankKeeper) + txConfig := tx.NewTxConfigWithTextual(in.ProtoCodecMarshaler, tx.DefaultSignModes, textual) baseAppOption := func(app *baseapp.BaseApp) { // AnteHandlers @@ -109,3 +120,49 @@ func newAnteHandler(txConfig client.TxConfig, in TxInputs) (sdk.AnteHandler, err return anteHandler, nil } + +// newTextualWithBankKeeper creates a new Textual struct using the given +// BankKeeper to retrieve coin metadata. +func newTextualWithBankKeeper(bk BankKeeper) textual.Textual { + textual := textual.NewTextual(func(ctx context.Context, denom string) (*bankv1beta1.Metadata, error) { + res, err := bk.DenomMetadata(ctx, &types.QueryDenomMetadataRequest{Denom: denom}) + if err != nil { + status, ok := grpcstatus.FromError(err) + if !ok { + return nil, err + } + + // This means we didn't find any metadata for this denom. Returning + // empty metadata. + if status.Code() == codes.NotFound { + return nil, nil + } + + return nil, err + } + + m := &bankv1beta1.Metadata{ + Base: res.Metadata.Base, + Display: res.Metadata.Display, + // fields below are not strictly needed by Textual + // but added here for completeness. + Description: res.Metadata.Description, + Name: res.Metadata.Name, + Symbol: res.Metadata.Symbol, + Uri: res.Metadata.URI, + UriHash: res.Metadata.URIHash, + } + m.DenomUnits = make([]*bankv1beta1.DenomUnit, len(res.Metadata.DenomUnits)) + for i, d := range res.Metadata.DenomUnits { + m.DenomUnits[i] = &bankv1beta1.DenomUnit{ + Denom: d.Denom, + Exponent: d.Exponent, + Aliases: d.Aliases, + } + } + + return m, nil + }) + + return textual +} diff --git a/x/auth/tx/config/expected_keepers.go b/x/auth/tx/config/expected_keepers.go new file mode 100644 index 000000000000..581e71ac1994 --- /dev/null +++ b/x/auth/tx/config/expected_keepers.go @@ -0,0 +1,12 @@ +package tx + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// BankKeeper defines the contract needed for tx-related APIs +type BankKeeper interface { + DenomMetadata(c context.Context, req *types.QueryDenomMetadataRequest) (*types.QueryDenomMetadataResponse, error) +} diff --git a/x/auth/tx/mode_handler.go b/x/auth/tx/mode_handler.go index 19e34df49a24..9f33c1ef652a 100644 --- a/x/auth/tx/mode_handler.go +++ b/x/auth/tx/mode_handler.go @@ -3,6 +3,7 @@ package tx import ( "fmt" + "cosmossdk.io/x/tx/textual" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/signing" ) @@ -12,11 +13,17 @@ var DefaultSignModes = []signingtypes.SignMode{ signingtypes.SignMode_SIGN_MODE_DIRECT, signingtypes.SignMode_SIGN_MODE_DIRECT_AUX, signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + // We currently don't add SIGN_MODE_TEXTUAL as part of the default sign + // modes, as it's not released yet (including the Ledger app). However, + // textual's sign mode handler is already available in this package. If you + // want to use textual for **TESTING** purposes, feel free to create a + // handler that includes SIGN_MODE_TEXTUAL. + // ref: Tracking issue for SIGN_MODE_TEXTUAL https://github.com/cosmos/cosmos-sdk/issues/11970 } // makeSignModeHandler returns the default protobuf SignModeHandler supporting // SIGN_MODE_DIRECT, SIGN_MODE_DIRECT_AUX and SIGN_MODE_LEGACY_AMINO_JSON. -func makeSignModeHandler(modes []signingtypes.SignMode) signing.SignModeHandler { +func makeSignModeHandler(modes []signingtypes.SignMode, txt textual.Textual) signing.SignModeHandler { if len(modes) < 1 { panic(fmt.Errorf("no sign modes enabled")) } @@ -29,6 +36,8 @@ func makeSignModeHandler(modes []signingtypes.SignMode) signing.SignModeHandler handlers[i] = signModeDirectHandler{} case signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON: handlers[i] = signModeLegacyAminoJSONHandler{} + case signingtypes.SignMode_SIGN_MODE_TEXTUAL: + handlers[i] = signModeTextualHandler{t: txt} case signingtypes.SignMode_SIGN_MODE_DIRECT_AUX: handlers[i] = signModeDirectAuxHandler{} default: diff --git a/x/auth/tx/textual.go b/x/auth/tx/textual.go new file mode 100644 index 000000000000..3abc9f8acda7 --- /dev/null +++ b/x/auth/tx/textual.go @@ -0,0 +1,71 @@ +package tx + +import ( + "context" + "fmt" + + "cosmossdk.io/x/tx/textual" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "google.golang.org/protobuf/types/known/anypb" + + txsigning "cosmossdk.io/x/tx/signing" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/signing" +) + +// signModeTextualHandler defines the SIGN_MODE_TEXTUAL SignModeHandler. +// It is currently not enabled by default, but you can enable it manually +// for TESTING purposes. It will be enabled once SIGN_MODE_TEXTUAL is fully +// released, see https://github.com/cosmos/cosmos-sdk/issues/11970. +type signModeTextualHandler struct { + t textual.Textual +} + +var _ signing.SignModeHandler = signModeTextualHandler{} + +// DefaultMode implements SignModeHandler.DefaultMode +func (signModeTextualHandler) DefaultMode() signingtypes.SignMode { + return signingtypes.SignMode_SIGN_MODE_TEXTUAL +} + +// Modes implements SignModeHandler.Modes +func (signModeTextualHandler) Modes() []signingtypes.SignMode { + return []signingtypes.SignMode{signingtypes.SignMode_SIGN_MODE_TEXTUAL} +} + +// GetSignBytes implements SignModeHandler.GetSignBytes +func (h signModeTextualHandler) GetSignBytes(mode signingtypes.SignMode, data signing.SignerData, tx sdk.Tx) ([]byte, error) { + panic("SIGN_MODE_TEXTUAL needs GetSignBytesWithContext") +} + +// GetSignBytesWithContext implements SignModeHandler.GetSignBytesWithContext +func (h signModeTextualHandler) GetSignBytesWithContext(ctx context.Context, mode signingtypes.SignMode, data signing.SignerData, tx sdk.Tx) ([]byte, error) { + if mode != signingtypes.SignMode_SIGN_MODE_TEXTUAL { + return nil, fmt.Errorf("expected %s, got %s", signingtypes.SignMode_SIGN_MODE_TEXTUAL, mode) + } + + protoTx, ok := tx.(*wrapper) + if !ok { + return nil, fmt.Errorf("can only handle a protobuf Tx, got %T", tx) + } + + bodyBz := protoTx.getBodyBytes() + authInfoBz := protoTx.getAuthInfoBytes() + + pbAny, err := codectypes.NewAnyWithValue(data.PubKey) + if err != nil { + return nil, err + } + + return h.t.GetSignBytes(ctx, bodyBz, authInfoBz, txsigning.SignerData{ + Address: data.Address, + ChainId: data.ChainID, + AccountNumber: data.AccountNumber, + Sequence: data.Sequence, + PubKey: &anypb.Any{ + TypeUrl: pbAny.TypeUrl, + Value: pbAny.Value, + }, + }) +} diff --git a/x/nft/go.mod b/x/nft/go.mod index 6b761087938d..febe7a16d2d4 100644 --- a/x/nft/go.mod +++ b/x/nft/go.mod @@ -23,6 +23,7 @@ require ( require ( cosmossdk.io/collections v0.0.0-20230106101515-aeac21494476 // indirect + cosmossdk.io/x/tx v0.1.0 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect diff --git a/x/nft/go.sum b/x/nft/go.sum index 8f3eff367d66..f353a3734b1a 100644 --- a/x/nft/go.sum +++ b/x/nft/go.sum @@ -47,6 +47,8 @@ cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= +cosmossdk.io/x/tx v0.1.0 h1:uyyYVjG22B+jf54N803Z99Y1uPvfuNP3K1YShoCHYL8= +cosmossdk.io/x/tx v0.1.0/go.mod h1:qsDv7e1fSftkF16kpSAk+7ROOojyj+SC0Mz3ukI52EQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= diff --git a/x/tx/textual/any.go b/x/tx/textual/any.go index 3256832c6d16..ab2a5132c227 100644 --- a/x/tx/textual/any.go +++ b/x/tx/textual/any.go @@ -33,7 +33,7 @@ func (ar anyValueRenderer) Format(ctx context.Context, v protoreflect.Value) ([] internalMsg, err := anymsg.UnmarshalNew() if err != nil { - return nil, err + return nil, fmt.Errorf("error unmarshalling any %s: %w", anymsg.TypeUrl, err) } vr, err := ar.tr.GetMessageValueRenderer(internalMsg.ProtoReflect().Descriptor()) if err != nil {