Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(x/auth): v2 adaptable tx instead of double decode #15910

Merged
merged 16 commits into from
Apr 26, 2023
Merged
4 changes: 2 additions & 2 deletions client/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion testutil/sims/tx_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion testutil/testnet/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 1 addition & 1 deletion tools/rosetta/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions tools/rosetta/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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 => ../..
2 changes: 0 additions & 2 deletions tools/rosetta/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
2 changes: 1 addition & 1 deletion x/auth/ante/feegrant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
23 changes: 5 additions & 18 deletions x/auth/ante/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions x/auth/signing/adapter.go
Original file line number Diff line number Diff line change
@@ -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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: changelog for public api break

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just make sure we update any previous CHANGELOG entry referring to this

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)
}
61 changes: 0 additions & 61 deletions x/auth/signing/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
}
144 changes: 144 additions & 0 deletions x/auth/tx/adapter.go
Original file line number Diff line number Diff line change
@@ -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,
},
}
}
}
Loading