diff --git a/client/tx/tx.go b/client/tx/tx.go index 78de623a460..d9446906c42 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -173,7 +173,7 @@ func SignWithPrivKey( // Generate the bytes to be signed. signBytes, err := authsigning.GetSignBytesAdapter( - ctx, txConfig.TxEncoder(), txConfig.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) + ctx, txConfig.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) if err != nil { return sigV2, err } @@ -319,7 +319,7 @@ func Sign(ctx context.Context, txf Factory, name string, txBuilder client.TxBuil } bytesToSign, err := authsigning.GetSignBytesAdapter( - ctx, txf.txConfig.TxEncoder(), txf.txConfig.SignModeHandler(), + ctx, txf.txConfig.SignModeHandler(), signMode, signerData, txBuilder.GetTx()) if err != nil { return err diff --git a/testutil/sims/tx_helpers.go b/testutil/sims/tx_helpers.go index 415ea292be4..dc4ae15ed30 100644 --- a/testutil/sims/tx_helpers.go +++ b/testutil/sims/tx_helpers.go @@ -67,7 +67,7 @@ func GenSignedMockTx(r *rand.Rand, txConfig client.TxConfig, msgs []sdk.Msg, fee } signBytes, err := authsign.GetSignBytesAdapter( - context.Background(), txConfig.TxEncoder(), txConfig.SignModeHandler(), signMode, signerData, + context.Background(), txConfig.SignModeHandler(), signMode, signerData, tx.GetTx()) if err != nil { panic(err) diff --git a/testutil/testnet/genesis.go b/testutil/testnet/genesis.go index bfc1755c816..fb62d9e4f16 100644 --- a/testutil/testnet/genesis.go +++ b/testutil/testnet/genesis.go @@ -143,7 +143,6 @@ func (b *GenesisBuilder) GenTx(privVal secp256k1.PrivKey, val cmttypes.GenesisVa // Generate bytes to be signed. bytesToSign, err := authsigning.GetSignBytesAdapter( context.Background(), - txConf.TxEncoder(), txConf.SignModeHandler(), signing.SignMode_SIGN_MODE_DIRECT, authsigning.SignerData{ diff --git a/tools/rosetta/converter.go b/tools/rosetta/converter.go index 429add923a7..3bbdbe9fb42 100644 --- a/tools/rosetta/converter.go +++ b/tools/rosetta/converter.go @@ -116,7 +116,7 @@ func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sd txEncode: cfg.TxEncoder(), bytesToSign: func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error) { bytesToSign, err := authsigning.GetSignBytesAdapter( - context.Background(), cfg.TxEncoder(), cfg.SignModeHandler(), + context.Background(), cfg.SignModeHandler(), signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, tx) if err != nil { return nil, err diff --git a/tools/rosetta/go.mod b/tools/rosetta/go.mod index 7979dd8039f..6f855eda417 100644 --- a/tools/rosetta/go.mod +++ b/tools/rosetta/go.mod @@ -138,3 +138,6 @@ require ( pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +// this seems to be required +replace github.com/cosmos/cosmos-sdk => ../.. diff --git a/tools/rosetta/go.sum b/tools/rosetta/go.sum index c7cc2785691..91ffa461dfe 100644 --- a/tools/rosetta/go.sum +++ b/tools/rosetta/go.sum @@ -172,8 +172,6 @@ github.com/cosmos/cosmos-db v1.0.0-rc.1 h1:SjnT8B6WKMW9WEIX32qMhnEEKcI7ZP0+G1Sa9 github.com/cosmos/cosmos-db v1.0.0-rc.1/go.mod h1:Dnmk3flSf5lkwCqvvjNpoxjpXzhxnCAFzKHlbaForso= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8 h1:zIl1WnrW5ZP1VwhpbwVBZtCntkNKYNIkg4233/dZ3BU= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230424095137-b73c17cb9cc8/go.mod h1:JicgV9n3SAu5uuoyDvQ2gSHYLyFvyRrIUYB5T2Q4HRw= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= diff --git a/x/auth/ante/feegrant_test.go b/x/auth/ante/feegrant_test.go index 31cebeaec98..b8b1a893dc3 100644 --- a/x/auth/ante/feegrant_test.go +++ b/x/auth/ante/feegrant_test.go @@ -242,7 +242,7 @@ func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, PubKey: p.PubKey(), } signBytes, err := authsign.GetSignBytesAdapter( - context.Background(), gen.TxEncoder(), gen.SignModeHandler(), signMode, signerData, tx.GetTx()) + context.Background(), gen.SignModeHandler(), signMode, signerData, tx.GetTx()) if err != nil { panic(err) } diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index c38ec4741d9..6021842b2a8 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -10,10 +10,8 @@ import ( errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/tx/decode" txsigning "cosmossdk.io/x/tx/signing" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/types/registry" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" @@ -239,7 +237,7 @@ func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool { } func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - sigTx, ok := tx.(authsigning.SigVerifiableTx) + sigTx, ok := tx.(authsigning.Tx) if !ok { return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") } @@ -300,22 +298,11 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul Value: anyPk.Value, }, } - decodeCtx, err := decode.NewDecoder(decode.Options{ProtoFiles: registry.MergedProtoRegistry()}) - if err != nil { - return ctx, err - } - // note: this is performance hit is temporary. Ultimately, the tx will be decoded once in BaseApp, - // but for now we need double decoding to support both SignModeHandlers. - decodedTx, err := decodeCtx.Decode(ctx.TxBytes()) - if err != nil { - return ctx, err - } - txData := txsigning.TxData{ - Body: decodedTx.Tx.Body, - AuthInfo: decodedTx.Tx.AuthInfo, - AuthInfoBytes: decodedTx.TxRaw.AuthInfoBytes, - BodyBytes: decodedTx.TxRaw.BodyBytes, + adaptableTx, ok := tx.(authsigning.V2AdaptableTx) + if !ok { + return ctx, fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx) } + txData := adaptableTx.GetSigningTxData() err = authsigning.VerifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData) if err != nil { var errMsg string diff --git a/x/auth/signing/adapter.go b/x/auth/signing/adapter.go new file mode 100644 index 00000000000..db1bb5fc65c --- /dev/null +++ b/x/auth/signing/adapter.go @@ -0,0 +1,60 @@ +package signing + +import ( + "context" + "fmt" + + "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/types/tx/signing" +) + +// V2AdaptableTx is an interface that wraps the GetSigningTxData method. +// GetSigningTxData returns an x/tx/signing.TxData representation of a transaction for use in signing +// interoperability with x/tx. +type V2AdaptableTx interface { + GetSigningTxData() txsigning.TxData +} + +// GetSignBytesAdapter returns the sign bytes for a given transaction and sign mode. It accepts the arguments expected +// for signing in x/auth/tx and converts them to the arguments expected by the txsigning.HandlerMap, then applies +// HandlerMap.GetSignBytes to get the sign bytes. +func GetSignBytesAdapter( + ctx context.Context, + handlerMap *txsigning.HandlerMap, + mode signing.SignMode, + signerData SignerData, + tx sdk.Tx, +) ([]byte, error) { + adaptableTx, ok := tx.(V2AdaptableTx) + if !ok { + return nil, fmt.Errorf("expected tx to be V2AdaptableTx, got %T", tx) + } + txData := adaptableTx.GetSigningTxData() + + txSignMode, err := internalSignModeToAPI(mode) + if err != nil { + return nil, err + } + + anyPk, err := codectypes.NewAnyWithValue(signerData.PubKey) + if err != nil { + return nil, err + } + + txSignerData := txsigning.SignerData{ + ChainID: signerData.ChainID, + AccountNumber: signerData.AccountNumber, + Sequence: signerData.Sequence, + Address: signerData.Address, + PubKey: &anypb.Any{ + TypeUrl: anyPk.TypeUrl, + Value: anyPk.Value, + }, + } + // Generate the bytes to be signed. + return handlerMap.GetSignBytes(ctx, txSignMode, txSignerData, txData) +} diff --git a/x/auth/signing/verify.go b/x/auth/signing/verify.go index 6455e60b782..6dbf7543a26 100644 --- a/x/auth/signing/verify.go +++ b/x/auth/signing/verify.go @@ -4,16 +4,10 @@ import ( "context" "fmt" - "google.golang.org/protobuf/types/known/anypb" - signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" - "cosmossdk.io/x/tx/decode" txsigning "cosmossdk.io/x/tx/signing" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/registry" "github.com/cosmos/cosmos-sdk/types/tx/signing" ) @@ -107,58 +101,3 @@ func VerifySignature( return fmt.Errorf("unexpected SignatureData %T", signatureData) } } - -// GetSignBytesAdapter returns the sign bytes for a given transaction and sign mode. It accepts the arguments expected -// for signing in x/auth/tx and converts them to the arguments expected by the txsigning.HandlerMap, then applies -// HandlerMap.GetSignBytes to get the sign bytes. -func GetSignBytesAdapter( - ctx context.Context, - encoder sdk.TxEncoder, - handlerMap *txsigning.HandlerMap, - mode signing.SignMode, - signerData SignerData, - tx sdk.Tx, -) ([]byte, error) { - // round trip performance hit. - // could be avoided if we had a way to get the bytes from the txBuilder. - txBytes, err := encoder(tx) - if err != nil { - return nil, err - } - decodeCtx, err := decode.NewDecoder(decode.Options{ProtoFiles: registry.MergedProtoRegistry()}) - if err != nil { - return nil, err - } - decodedTx, err := decodeCtx.Decode(txBytes) - if err != nil { - return nil, err - } - txData := txsigning.TxData{ - Body: decodedTx.Tx.Body, - AuthInfo: decodedTx.Tx.AuthInfo, - AuthInfoBytes: decodedTx.TxRaw.AuthInfoBytes, - BodyBytes: decodedTx.TxRaw.BodyBytes, - } - txSignMode, err := internalSignModeToAPI(mode) - if err != nil { - return nil, err - } - - anyPk, err := codectypes.NewAnyWithValue(signerData.PubKey) - if err != nil { - return nil, err - } - - txSignerData := txsigning.SignerData{ - ChainID: signerData.ChainID, - AccountNumber: signerData.AccountNumber, - Sequence: signerData.Sequence, - Address: signerData.Address, - PubKey: &anypb.Any{ - TypeUrl: anyPk.TypeUrl, - Value: anyPk.Value, - }, - } - // Generate the bytes to be signed. - return handlerMap.GetSignBytes(ctx, txSignMode, txSignerData, txData) -} diff --git a/x/auth/tx/adapter.go b/x/auth/tx/adapter.go new file mode 100644 index 00000000000..1c2f113a7b8 --- /dev/null +++ b/x/auth/tx/adapter.go @@ -0,0 +1,144 @@ +package tx + +import ( + "google.golang.org/protobuf/types/known/anypb" + + basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + multisigv1beta1 "cosmossdk.io/api/cosmos/crypto/multisig/v1beta1" + signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" + txsigning "cosmossdk.io/x/tx/signing" + "github.com/cosmos/cosmos-sdk/types/tx" +) + +// GetSigningTxData returns an x/tx/signing.TxData representation of a transaction for use in the signing +// API defined in x/tx. +func (w *wrapper) GetSigningTxData() txsigning.TxData { + body := w.tx.Body + authInfo := w.tx.AuthInfo + + msgs := make([]*anypb.Any, len(body.Messages)) + for i, msg := range body.Messages { + msgs[i] = &anypb.Any{ + TypeUrl: msg.TypeUrl, + Value: msg.Value, + } + } + + extOptions := make([]*anypb.Any, len(body.ExtensionOptions)) + for i, extOption := range body.ExtensionOptions { + extOptions[i] = &anypb.Any{ + TypeUrl: extOption.TypeUrl, + Value: extOption.Value, + } + } + + nonCriticalExtOptions := make([]*anypb.Any, len(body.NonCriticalExtensionOptions)) + for i, extOption := range body.NonCriticalExtensionOptions { + nonCriticalExtOptions[i] = &anypb.Any{ + TypeUrl: extOption.TypeUrl, + Value: extOption.Value, + } + } + + feeCoins := authInfo.Fee.Amount + feeAmount := make([]*basev1beta1.Coin, len(feeCoins)) + for i, coin := range feeCoins { + feeAmount[i] = &basev1beta1.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + } + } + + var txTip *txv1beta1.Tip + tip := authInfo.Tip + if tip != nil { + tipCoins := tip.GetAmount() + tipAmount := make([]*basev1beta1.Coin, len(tipCoins)) + for i, coin := range tipCoins { + tipAmount[i] = &basev1beta1.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + } + } + txTip = &txv1beta1.Tip{ + Amount: tipAmount, + Tipper: tip.Tipper, + } + } + + txSignerInfos := make([]*txv1beta1.SignerInfo, len(authInfo.SignerInfos)) + for i, signerInfo := range authInfo.SignerInfos { + modeInfo := &txv1beta1.ModeInfo{} + adaptModeInfo(signerInfo.ModeInfo, modeInfo) + txSignerInfo := &txv1beta1.SignerInfo{ + PublicKey: &anypb.Any{ + TypeUrl: signerInfo.PublicKey.TypeUrl, + Value: signerInfo.PublicKey.Value, + }, + Sequence: signerInfo.Sequence, + ModeInfo: modeInfo, + } + txSignerInfos[i] = txSignerInfo + } + + txAuthInfo := &txv1beta1.AuthInfo{ + SignerInfos: txSignerInfos, + Fee: &txv1beta1.Fee{ + Amount: feeAmount, + GasLimit: authInfo.Fee.GasLimit, + Payer: authInfo.Fee.Payer, + Granter: authInfo.Fee.Granter, + }, + Tip: txTip, + } + + txBody := &txv1beta1.TxBody{ + Messages: msgs, + Memo: body.Memo, + TimeoutHeight: body.TimeoutHeight, + ExtensionOptions: extOptions, + NonCriticalExtensionOptions: nonCriticalExtOptions, + } + txData := txsigning.TxData{ + AuthInfo: txAuthInfo, + AuthInfoBytes: w.getAuthInfoBytes(), + Body: txBody, + BodyBytes: w.getBodyBytes(), + } + return txData +} + +func adaptModeInfo(legacy *tx.ModeInfo, res *txv1beta1.ModeInfo) { + // handle nil modeInfo. this is permissible through the code path: + // https://github.com/cosmos/cosmos-sdk/blob/4a6a1e3cb8de459891cb0495052589673d14ef51/x/auth/tx/builder.go#L295 + // -> https://github.com/cosmos/cosmos-sdk/blob/b7841e3a76a38d069c1b9cb3d48368f7a67e9c26/x/auth/tx/sigs.go#L15-L17 + // when signature.Data is nil. + if legacy == nil { + return + } + + switch mi := legacy.Sum.(type) { + case *tx.ModeInfo_Single_: + res.Sum = &txv1beta1.ModeInfo_Single_{ + Single: &txv1beta1.ModeInfo_Single{ + Mode: signingv1beta1.SignMode(legacy.GetSingle().Mode), + }, + } + case *tx.ModeInfo_Multi_: + multiModeInfos := legacy.GetMulti().ModeInfos + modeInfos := make([]*txv1beta1.ModeInfo, len(multiModeInfos)) + for _, modeInfo := range multiModeInfos { + adaptModeInfo(modeInfo, &txv1beta1.ModeInfo{}) + } + res.Sum = &txv1beta1.ModeInfo_Multi_{ + Multi: &txv1beta1.ModeInfo_Multi{ + Bitarray: &multisigv1beta1.CompactBitArray{ + Elems: mi.Multi.Bitarray.Elems, + ExtraBitsStored: mi.Multi.Bitarray.ExtraBitsStored, + }, + ModeInfos: modeInfos, + }, + } + } +} diff --git a/x/auth/tx/aux_test.go b/x/auth/tx/aux_test.go index 90481f5767c..5f62efa2987 100644 --- a/x/auth/tx/aux_test.go +++ b/x/auth/tx/aux_test.go @@ -140,7 +140,7 @@ func TestBuilderWithAux(t *testing.T) { } signBz, err = authsigning.GetSignBytesAdapter( - context.Background(), txConfig.TxEncoder(), txConfig.SignModeHandler(), signing.SignMode_SIGN_MODE_DIRECT, + context.Background(), txConfig.SignModeHandler(), signing.SignMode_SIGN_MODE_DIRECT, signerData, w.GetTx()) require.NoError(t, err) diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index e796f6884d0..d9452a170a7 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -4,7 +4,6 @@ import ( "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" diff --git a/x/auth/tx/direct_test.go b/x/auth/tx/direct_test.go index 09365541ee6..737deda61ff 100644 --- a/x/auth/tx/direct_test.go +++ b/x/auth/tx/direct_test.go @@ -78,7 +78,7 @@ func TestDirectModeHandler(t *testing.T) { } signBytes, err := signing.GetSignBytesAdapter( - context.Background(), txConfig.TxEncoder(), txConfig.SignModeHandler(), defaultSignMode, signingData, + context.Background(), txConfig.SignModeHandler(), defaultSignMode, signingData, txBuilder.GetTx()) require.NoError(t, err) require.NotNil(t, signBytes) @@ -124,7 +124,7 @@ func TestDirectModeHandler(t *testing.T) { err = txBuilder.SetSignatures(sig) require.NoError(t, err) signBytes, err = signing.GetSignBytesAdapter( - context.Background(), txConfig.TxEncoder(), txConfig.SignModeHandler(), defaultSignMode, signingData, + context.Background(), txConfig.SignModeHandler(), defaultSignMode, signingData, txBuilder.GetTx()) require.NoError(t, err) require.Equal(t, expectedSignBytes, signBytes) diff --git a/x/auth/tx/testutil/suite.go b/x/auth/tx/testutil/suite.go index ab9ab69096d..d4f2cbd884b 100644 --- a/x/auth/tx/testutil/suite.go +++ b/x/auth/tx/testutil/suite.go @@ -138,7 +138,7 @@ func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() { Sequence: seq1, PubKey: pubkey, } - signBytes, err := signing.GetSignBytesAdapter(context.Background(), s.TxConfig.TxEncoder(), + signBytes, err := signing.GetSignBytesAdapter(context.Background(), s.TxConfig.SignModeHandler(), defaultSignMode, signerData, sigTx) s.Require().NoError(err) sigBz, err := privKey.Sign(signBytes) @@ -151,7 +151,7 @@ func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() { Sequence: mseq, PubKey: multisigPk, } - mSignBytes, err := signing.GetSignBytesAdapter(context.Background(), s.TxConfig.TxEncoder(), + mSignBytes, err := signing.GetSignBytesAdapter(context.Background(), s.TxConfig.SignModeHandler(), defaultSignMode, signerData, sigTx) s.Require().NoError(err) mSigBz1, err := privKey.Sign(mSignBytes)