feat(x/tx): legacy amino json sign mode handler (#15515)

This commit is contained in:
Matt Kocubinski 2023-04-03 15:13:45 -05:00 committed by GitHub
parent 723256f769
commit 5e90819765
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 3014 additions and 615 deletions

View File

@ -17,3 +17,6 @@ echo "Generating API module"
echo "Generate Pulsar Test Data"
(cd testutil/testdata; buf generate --template buf.gen.pulsar.yaml)
echo "Generate x/tx"
(cd x/tx; make codegen)

View File

@ -195,6 +195,7 @@ replace (
cosmossdk.io/x/evidence => ../x/evidence
cosmossdk.io/x/feegrant => ../x/feegrant
cosmossdk.io/x/nft => ../x/nft
cosmossdk.io/x/tx => ../x/tx
cosmossdk.io/x/upgrade => ../x/upgrade
)

View File

@ -204,8 +204,6 @@ cosmossdk.io/log v1.0.0 h1:NGKZ/A5rd4PduDfoscgABklX557PWjQINbosZy/m3Jk=
cosmossdk.io/log v1.0.0/go.mod h1:CwX9BLiBruZb7lzLlRr3R231d/fVPUXk8gAdV4LQap0=
cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw=
cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k=
cosmossdk.io/x/tx v0.5.0 h1:01wPSoiYDHlfudV0fn867SBXI3uI/8tpatBgVVSnFzI=
cosmossdk.io/x/tx v0.5.0/go.mod h1:kDcwrN6QbCj+9NXVHL8qipMzA9YlMr9NpZa08SHCdLA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=

View File

@ -1,6 +1,7 @@
package aminojson
import (
"context"
"fmt"
"reflect"
"testing"
@ -38,6 +39,7 @@ import (
paramsapi "cosmossdk.io/api/cosmos/params/v1beta1"
slashingapi "cosmossdk.io/api/cosmos/slashing/v1beta1"
stakingapi "cosmossdk.io/api/cosmos/staking/v1beta1"
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
upgradeapi "cosmossdk.io/api/cosmos/upgrade/v1beta1"
vestingapi "cosmossdk.io/api/cosmos/vesting/v1beta1"
"cosmossdk.io/x/evidence"
@ -45,6 +47,7 @@ import (
feegranttypes "cosmossdk.io/x/feegrant"
feegrantmodule "cosmossdk.io/x/feegrant/module"
"cosmossdk.io/x/tx/signing/aminojson"
signing_testutil "cosmossdk.io/x/tx/signing/testutil"
"cosmossdk.io/x/upgrade"
upgradetypes "cosmossdk.io/x/upgrade/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@ -57,7 +60,10 @@ import (
"github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/bech32"
"github.com/cosmos/cosmos-sdk/types/module/testutil"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
@ -367,6 +373,50 @@ func TestAminoJSON_Equivalence(t *testing.T) {
aminoJSON, err := aj.Marshal(msg)
require.NoError(t, err)
require.Equal(t, string(legacyAminoJSON), string(aminoJSON))
// test amino json signer handler equivalence
gogoMsg, ok := gogo.(types.Msg)
if !ok {
// not signable
return
}
handlerOptions := signing_testutil.HandlerArgumentOptions{
ChainId: "test-chain",
Memo: "sometestmemo",
Msg: tt.pulsar,
AccNum: 1,
AccSeq: 2,
SignerAddress: "signerAddress",
Fee: &txv1beta1.Fee{
Amount: []*v1beta1.Coin{{Denom: "uatom", Amount: "1000"}},
},
}
signerData, txData, err := signing_testutil.MakeHandlerArguments(handlerOptions)
require.NoError(t, err)
handler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
signBz, err := handler.GetSignBytes(context.Background(), signerData, txData)
require.NoError(t, err)
legacyHandler := tx.NewSignModeLegacyAminoJSONHandler()
txBuilder := encCfg.TxConfig.NewTxBuilder()
require.NoError(t, txBuilder.SetMsgs([]types.Msg{gogoMsg}...))
txBuilder.SetMemo(handlerOptions.Memo)
txBuilder.SetFeeAmount(types.Coins{types.NewInt64Coin("uatom", 1000)})
theTx := txBuilder.GetTx()
legacySigningData := signing.SignerData{
ChainID: handlerOptions.ChainId,
Address: handlerOptions.SignerAddress,
AccountNumber: handlerOptions.AccNum,
Sequence: handlerOptions.AccSeq,
}
legacySignBz, err := legacyHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
legacySigningData, theTx)
require.NoError(t, err)
require.Equal(t, string(legacySignBz), string(signBz))
})
})
}
@ -624,6 +674,50 @@ func TestAminoJSON_LegacyParity(t *testing.T) {
return
}
require.Equal(t, string(gogoBytes), string(newGogoBytes))
// test amino json signer handler equivalence
msg, ok := tc.gogo.(types.Msg)
if !ok {
// not signable
return
}
handlerOptions := signing_testutil.HandlerArgumentOptions{
ChainId: "test-chain",
Memo: "sometestmemo",
Msg: tc.pulsar,
AccNum: 1,
AccSeq: 2,
SignerAddress: "signerAddress",
Fee: &txv1beta1.Fee{
Amount: []*v1beta1.Coin{{Denom: "uatom", Amount: "1000"}},
},
}
signerData, txData, err := signing_testutil.MakeHandlerArguments(handlerOptions)
require.NoError(t, err)
handler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
signBz, err := handler.GetSignBytes(context.Background(), signerData, txData)
require.NoError(t, err)
legacyHandler := tx.NewSignModeLegacyAminoJSONHandler()
txBuilder := encCfg.TxConfig.NewTxBuilder()
require.NoError(t, txBuilder.SetMsgs([]types.Msg{msg}...))
txBuilder.SetMemo(handlerOptions.Memo)
txBuilder.SetFeeAmount(types.Coins{types.NewInt64Coin("uatom", 1000)})
theTx := txBuilder.GetTx()
legacySigningData := signing.SignerData{
ChainID: handlerOptions.ChainId,
Address: handlerOptions.SignerAddress,
AccountNumber: handlerOptions.AccNum,
Sequence: handlerOptions.AccSeq,
}
legacySignBz, err := legacyHandler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
legacySigningData, theTx)
require.NoError(t, err)
require.Equal(t, string(legacySignBz), string(signBz))
})
}
}
@ -687,14 +781,14 @@ func TestDecimalMutation(t *testing.T) {
require.NoError(t, err)
rateBz, _ = encCfg.Amino.MarshalJSON(rates)
// these assertions show behavior prior to the merge of https://github.com/cosmos/cosmos-sdk/pull/15506
// and should be updated to reflect the new behavior once a release of math is made and updated in ./tests/go.mod
// require.NotEqual(t, `{"rate":"0","max_rate":"0","max_change_rate":"0"}`, string(rateBz))
// require.Equal(t,
// `{"rate":"0.000000000000000000","max_rate":"0.000000000000000000","max_change_rate":"0.000000000000000000"}`,
// string(rateBz))
// prior to the merge of https://github.com/cosmos/cosmos-sdk/pull/15506
// gogoproto.Marshal would mutate Decimal fields changing JSON output as shown in the assertions below
//require.NotEqual(t, `{"rate":"0","max_rate":"0","max_change_rate":"0"}`, string(rateBz))
//require.Equal(t,
// `{"rate":"0.000000000000000000","max_rate":"0.000000000000000000","max_change_rate":"0.000000000000000000"}`,
// string(rateBz))
// new behavior
// This is no longer the case, new behavior:
require.Equal(t, `{"rate":"0","max_rate":"0","max_change_rate":"0"}`, string(rateBz))
}

View File

@ -20,6 +20,12 @@ var _ signing.SignModeHandler = signModeLegacyAminoJSONHandler{}
// SignModeHandler.
type signModeLegacyAminoJSONHandler struct{}
// NewSignModeLegacyAminoJSONHandler returns a new signModeLegacyAminoJSONHandler.
// Note: The public constructor is only used for testing.
func NewSignModeLegacyAminoJSONHandler() signing.SignModeHandler {
return signModeLegacyAminoJSONHandler{}
}
func (s signModeLegacyAminoJSONHandler) DefaultMode() signingtypes.SignMode {
return signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
}

View File

@ -48,3 +48,4 @@ require a `signing.ProtoFileResolver` interface instead of `protodesc.Resolver`.
* [#15302](https://github.com/cosmos/cosmos-sdk/pull/15302) Add support for a custom registry (e.g. gogo's MergedRegistry) to be plugged into SIGN_MODE_TEXTUAL.
* [#15557](https://github.com/cosmos/cosmos-sdk/pull/15557) Implement unknown field filtering.
* [#15515](https://github.com/cosmos/cosmos-sdk/pull/15515) Implement SIGN_MODE_LEGACY_AMINO_JSON handler.

View File

@ -1,2 +1,3 @@
codegen:
@(cd internal/testpb; buf generate)
@(cd signing/aminojson/internal; make codegen)

View File

@ -1,7 +1,6 @@
syntax = "proto3";
package testpb;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "cosmos/tx/v1beta1/tx.proto";
@ -103,7 +102,7 @@ message TestVersion1 {
TestVersion1 a = 2;
TestVersion1 b = 3; // [(gogoproto.nullable) = false] generates invalid recursive structs;
repeated TestVersion1 c = 4;
repeated TestVersion1 d = 5 [(gogoproto.nullable) = false];
repeated TestVersion1 d = 5;
oneof sum {
int32 e = 6;
TestVersion1 f = 7;
@ -112,7 +111,7 @@ message TestVersion1 {
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
}
message TestVersion2 {
int64 x = 1;
@ -128,7 +127,7 @@ message TestVersion2 {
repeated TestVersion1 h = 9; // [(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
uint64 new_field = 25;
}
message TestVersion3 {
@ -145,7 +144,7 @@ message TestVersion3 {
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
string non_critical_field = 1031;
}
@ -162,7 +161,7 @@ message TestVersion3LoneOneOfValue {
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
string non_critical_field = 1031;
}
@ -179,7 +178,7 @@ message TestVersion3LoneNesting {
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
string non_critical_field = 1031;
message Inner1 {
@ -220,7 +219,7 @@ message TestVersion4LoneNesting {
repeated TestVersion1 h = 9; //[(gogoproto.castrepeated) = "TestVersion1"];
// google.protobuf.Timestamp i = 10;
// google.protobuf.Timestamp j = 11; // [(gogoproto.stdtime) = true];
Customer1 k = 12 [(gogoproto.embed) = true];
Customer1 k = 12;
string non_critical_field = 1031;
message Inner1 {
@ -271,7 +270,7 @@ message TestVersionFD1WithExtraAny {
}
message AnyWithExtra {
google.protobuf.Any a = 1 [(gogoproto.embed) = true];
google.protobuf.Any a = 1;
int64 b = 3;
int64 c = 4;
}

View File

@ -0,0 +1,132 @@
package aminojson
import (
"context"
"encoding/json"
"fmt"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoregistry"
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/x/tx/decode"
"cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson/internal/aminojsonpb"
)
// SignModeHandler implements the SIGN_MODE_LEGACY_AMINO_JSON signing mode.
type SignModeHandler struct {
fileResolver protodesc.Resolver
typeResolver protoregistry.MessageTypeResolver
encoder Encoder
}
// SignModeHandlerOptions are the options for the SignModeHandler.
type SignModeHandlerOptions struct {
FileResolver protodesc.Resolver
TypeResolver protoregistry.MessageTypeResolver
Encoder *Encoder
}
// NewSignModeHandler returns a new SignModeHandler.
func NewSignModeHandler(options SignModeHandlerOptions) *SignModeHandler {
h := &SignModeHandler{}
if options.FileResolver == nil {
h.fileResolver = protoregistry.GlobalFiles
} else {
h.fileResolver = options.FileResolver
}
if options.TypeResolver == nil {
h.typeResolver = protoregistry.GlobalTypes
} else {
h.typeResolver = options.TypeResolver
}
if options.Encoder == nil {
h.encoder = NewAminoJSON()
} else {
h.encoder = *options.Encoder
}
return h
}
// Mode implements the Mode method of the SignModeHandler interface.
func (h SignModeHandler) Mode() signingv1beta1.SignMode {
return signingv1beta1.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
}
// GetSignBytes implements the GetSignBytes method of the SignModeHandler interface.
func (h SignModeHandler) GetSignBytes(_ context.Context, signerData signing.SignerData, txData signing.TxData) ([]byte, error) {
body := txData.Body
_, err := decode.RejectUnknownFields(
txData.BodyBytes, body.ProtoReflect().Descriptor(), false, h.fileResolver)
if err != nil {
return nil, err
}
if (len(body.ExtensionOptions) > 0) || (len(body.NonCriticalExtensionOptions) > 0) {
return nil, fmt.Errorf("%s does not support protobuf extension options: invalid request", h.Mode())
}
if signerData.Address == "" {
return nil, fmt.Errorf("got empty address in %s handler: invalid request", h.Mode())
}
tip := txData.AuthInfo.Tip
if tip != nil && tip.Tipper == "" {
return nil, fmt.Errorf("tipper cannot be empty")
}
isTipper := tip != nil && tip.Tipper == signerData.Address
// We set a convention that if the tipper signs with LEGACY_AMINO_JSON, then
// they sign over empty fees and 0 gas.
var fee *aminojsonpb.AminoSignFee
if isTipper {
fee = &aminojsonpb.AminoSignFee{
Amount: nil,
Gas: 0,
}
} else {
f := txData.AuthInfo.Fee
if f == nil {
return nil, fmt.Errorf("fee cannot be nil when tipper is not signer")
}
fee = &aminojsonpb.AminoSignFee{
Amount: f.Amount,
Gas: f.GasLimit,
Payer: f.Payer,
Granter: f.Granter,
}
}
signDoc := &aminojsonpb.AminoSignDoc{
AccountNumber: signerData.AccountNumber,
TimeoutHeight: body.TimeoutHeight,
ChainId: signerData.ChainId,
Sequence: signerData.Sequence,
Memo: body.Memo,
Msgs: txData.Body.Messages,
Fee: fee,
}
bz, err := h.encoder.Marshal(signDoc)
if err != nil {
return nil, err
}
return sortJSON(bz)
}
// sortJSON sorts the JSON keys of the given JSON encoded byte slice.
func sortJSON(toSortJSON []byte) ([]byte, error) {
var c interface{}
err := json.Unmarshal(toSortJSON, &c)
if err != nil {
return nil, err
}
js, err := json.Marshal(c)
if err != nil {
return nil, err
}
return js, nil
}
var _ signing.SignModeHandler = (*SignModeHandler)(nil)

View File

@ -0,0 +1,117 @@
package aminojson_test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoregistry"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
"cosmossdk.io/x/tx/signing/aminojson"
"cosmossdk.io/x/tx/signing/testutil"
)
func TestAminoJsonSignMode(t *testing.T) {
fee := &txv1beta1.Fee{
Amount: []*basev1beta1.Coin{{Denom: "uatom", Amount: "1000"}},
}
handlerOptions := testutil.HandlerArgumentOptions{
ChainId: "test-chain",
Memo: "sometestmemo",
Tip: &txv1beta1.Tip{Tipper: "tipper", Amount: []*basev1beta1.Coin{{Denom: "Tip-token", Amount: "10"}}},
Msg: &bankv1beta1.MsgSend{
FromAddress: "foo",
ToAddress: "bar",
Amount: []*basev1beta1.Coin{{Denom: "demon", Amount: "100"}},
},
AccNum: 1,
AccSeq: 2,
SignerAddress: "signerAddress",
Fee: fee,
}
testCases := []struct {
name string
malleate func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions
error string
}{
{
name: "happy path",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
return opts
},
},
{
name: "empty signer",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
opts.SignerAddress = ""
return opts
},
error: "got empty address in SIGN_MODE_LEGACY_AMINO_JSON handler: invalid request",
},
{
name: "nil tip",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
opts.Tip = nil
return opts
},
},
{
name: "empty tipper",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
opts.Tip.Tipper = ""
return opts
},
error: "tipper cannot be empty",
},
{
name: "nil fee",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
opts.Tip.Tipper = "tipper"
opts.Fee = nil
return opts
},
error: "fee cannot be nil",
},
{
name: "tipper is signer",
malleate: func(opts testutil.HandlerArgumentOptions) testutil.HandlerArgumentOptions {
opts.Tip.Tipper = opts.SignerAddress
return opts
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts := tc.malleate(handlerOptions)
signerData, txData, err := testutil.MakeHandlerArguments(opts)
require.NoError(t, err)
handler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
_, err = handler.GetSignBytes(context.Background(), signerData, txData)
if tc.error != "" {
require.Error(t, err)
require.Contains(t, err.Error(), tc.error)
return
}
require.NoError(t, err)
})
}
}
func TestNewSignModeHandler(t *testing.T) {
handler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
require.NotNil(t, handler)
aj := aminojson.NewAminoJSON()
handler = aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{
FileResolver: protoregistry.GlobalFiles,
TypeResolver: protoregistry.GlobalTypes,
Encoder: &aj,
})
require.NotNil(t, handler)
}

View File

@ -1,3 +1,3 @@
codegen:
@echo "Generating proto files"
buf generate
@buf generate

View File

@ -0,0 +1,30 @@
syntax = "proto3";
import "cosmos_proto/cosmos.proto";
import "amino/amino.proto";
import "cosmos/base/v1beta1/coin.proto";
import "google/protobuf/any.proto";
import "cosmos/tx/v1beta1/tx.proto";
// AminoSignFee is the legacy amino json sign mode compatible version of txv1beta1.Fee, and differs from that message
// by the name of the Gas field (GasLimit in txv1beta.Fee).
// Note: this is only used for signing, see x/tx/signing/aminojson.go for more details.
message AminoSignFee {
repeated cosmos.base.v1beta1.Coin amount = 1 [(amino.dont_omitempty) = true, (amino.encoding) = "legacy_coins"];
uint64 gas = 2 [(amino.dont_omitempty) = true];
string payer = 3;
string granter = 4;
}
// AminoSignDoc is a message container used to generate the SIGN_MODE_LEGACY_AMINO_JSON sign bytes with proto3 API.
// Note: This is only used for generated JSON in signing, see x/tx/signing/aminojson.go for more details.
message AminoSignDoc {
uint64 account_number = 1;
uint64 sequence = 2;
uint64 timeout_height = 3;
string chain_id = 4;
string memo = 5;
AminoSignFee fee = 6;
repeated google.protobuf.Any msgs = 7;
cosmos.tx.v1beta1.Tip tip = 8;
}

File diff suppressed because it is too large Load Diff

View File

@ -5,3 +5,7 @@ deps:
owner: cosmos
repository: cosmos-proto
commit: 1935555c206d4afb9e94615dfd0fad31
- remote: buf.build
owner: cosmos
repository: gogo-proto
commit: 34d970b699f84aa382f3c29773a60836

View File

@ -1,5 +1,6 @@
version: v1
deps:
- buf.build/cosmos/gogo-proto
- buf.build/cosmos/cosmos-proto
lint:
use:

View File

@ -2,7 +2,9 @@ package std
import (
"cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson"
"cosmossdk.io/x/tx/signing/direct"
"cosmossdk.io/x/tx/signing/direct_aux"
"cosmossdk.io/x/tx/signing/textual"
)
@ -10,6 +12,10 @@ import (
type SignModeOptions struct {
// Textual are options for SIGN_MODE_TEXTUAL
Textual textual.SignModeOptions
// DirectAux are options for SIGN_MODE_DIRECT_AUX
DirectAux direct_aux.SignModeHandlerOptions
// AminoJSON are options for SIGN_MODE_LEGACY_AMINO_JSON
AminoJSON aminojson.SignModeHandlerOptions
}
// HandlerMap returns a sign mode handler map that Cosmos SDK apps can use out
@ -20,8 +26,17 @@ func (s SignModeOptions) HandlerMap() (*signing.HandlerMap, error) {
return nil, err
}
directAux, err := direct_aux.NewSignModeHandler(s.DirectAux)
if err != nil {
return nil, err
}
aminoJSON := aminojson.NewSignModeHandler(s.AminoJSON)
return signing.NewHandlerMap(
direct.SignModeHandler{},
txt,
directAux,
aminoJSON,
), nil
}

View File

@ -0,0 +1,90 @@
package testutil
import (
"github.com/cosmos/cosmos-proto/anyutil"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"cosmossdk.io/api/cosmos/crypto/secp256k1"
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
"cosmossdk.io/x/tx/signing"
)
type HandlerArgumentOptions struct {
ChainId string
Memo string
Msg proto.Message
AccNum uint64
AccSeq uint64
Tip *txv1beta1.Tip
Fee *txv1beta1.Fee
SignerAddress string
}
func MakeHandlerArguments(options HandlerArgumentOptions) (signing.SignerData, signing.TxData, error) {
pk := &secp256k1.PubKey{
Key: make([]byte, 256),
}
anyPk, err := anyutil.New(pk)
if err != nil {
return signing.SignerData{}, signing.TxData{}, err
}
signerInfo := []*txv1beta1.SignerInfo{
{
PublicKey: anyPk,
ModeInfo: &txv1beta1.ModeInfo{
Sum: &txv1beta1.ModeInfo_Single_{
Single: &txv1beta1.ModeInfo_Single{
Mode: signingv1beta1.SignMode_SIGN_MODE_DIRECT_AUX,
},
},
},
Sequence: options.AccSeq,
},
}
anyMsg, err := anyutil.New(options.Msg)
if err != nil {
return signing.SignerData{}, signing.TxData{}, err
}
txBody := &txv1beta1.TxBody{
Messages: []*anypb.Any{anyMsg},
Memo: options.Memo,
}
authInfo := &txv1beta1.AuthInfo{
Fee: options.Fee,
Tip: options.Tip,
SignerInfos: signerInfo,
}
bodyBz, err := proto.Marshal(txBody)
if err != nil {
return signing.SignerData{}, signing.TxData{}, err
}
authInfoBz, err := proto.Marshal(authInfo)
if err != nil {
return signing.SignerData{}, signing.TxData{}, err
}
txData := signing.TxData{
Body: txBody,
AuthInfo: authInfo,
AuthInfoBytes: authInfoBz,
BodyBytes: bodyBz,
}
signerAddress := options.SignerAddress
signerData := signing.SignerData{
ChainId: options.ChainId,
AccountNumber: options.AccNum,
Sequence: options.AccSeq,
Address: signerAddress,
PubKey: anyPk,
}
return signerData, txData, nil
}