From 6d959001169ce78360887faf882680bf52b09ae8 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Sun, 28 May 2023 22:14:01 +0800 Subject: [PATCH] feat: support extension options for build tx (backport: #15992) (#16317) --- CHANGELOG.md | 1 + client/tx/factory.go | 28 ++++++++++++++ client/tx/tx_test.go | 67 ++++++++++++++++------------------ client/tx_config.go | 7 ++++ types/module/testutil/codec.go | 35 ++++++++++++++++++ 5 files changed, 103 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5575dfd7f2cb..a3cc44f06434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (baseapp) [#16290](https://github.com/cosmos/cosmos-sdk/pull/16290) Add circuit breaker setter in baseapp. * (x/group) [#16191](https://github.com/cosmos/cosmos-sdk/pull/16191) Add EventProposalPruned event to group module whenever a proposal is pruned. +* (tx) [#15992](https://github.com/cosmos/cosmos-sdk/pull/15992) Add `WithExtensionOptions` in tx Factory to allow `SetExtensionOptions` with given extension options. ### Improvements diff --git a/client/tx/factory.go b/client/tx/factory.go index 99195f2c2170..aa7940a2d7b3 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -41,6 +42,7 @@ type Factory struct { feeGranter sdk.AccAddress feePayer sdk.AccAddress gasPrices sdk.DecCoins + extOptions []*codectypes.Any signMode signing.SignMode simulateAndExecute bool preprocessTxHook client.PreprocessTxFn @@ -279,6 +281,28 @@ func (f Factory) PreprocessTx(keyname string, builder client.TxBuilder) error { return f.preprocessTxHook(f.chainID, key.GetType(), builder) } +// WithExtensionOptions returns a Factory with given extension options added to the existing options, +// Example to add dynamic fee extension options: +// +// extOpt := ethermint.ExtensionOptionDynamicFeeTx{ +// MaxPriorityPrice: sdk.NewInt(1000000), +// } +// +// extBytes, _ := extOpt.Marshal() +// +// extOpts := []*types.Any{ +// { +// TypeUrl: "/ethermint.types.v1.ExtensionOptionDynamicFeeTx", +// Value: extBytes, +// }, +// } +// +// txf.WithExtensionOptions(extOpts...) +func (f Factory) WithExtensionOptions(extOpts ...*codectypes.Any) Factory { + f.extOptions = extOpts + return f +} + // BuildUnsignedTx builds a transaction to be signed given a set of messages. // Once created, the fee, memo, and messages are set. func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) { @@ -327,6 +351,10 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) { tx.SetFeePayer(f.feePayer) tx.SetTimeoutHeight(f.TimeoutHeight()) + if etx, ok := tx.(client.ExtendedTxBuilder); ok { + etx.SetExtensionOptions(f.extOptions...) + } + return tx, nil } diff --git a/client/tx/tx_test.go b/client/tx/tx_test.go index 9c687a42ebb1..b9eb1a7a42b8 100644 --- a/client/tx/tx_test.go +++ b/client/tx/tx_test.go @@ -21,6 +21,7 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" txtypes "github.com/cosmos/cosmos-sdk/types/tx" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" ante "github.com/cosmos/cosmos-sdk/x/auth/ante" @@ -108,6 +109,16 @@ func TestCalculateGas(t *testing.T) { } } +func mockTxFactory(txCfg client.TxConfig) tx.Factory { + return tx.Factory{}. + WithTxConfig(txCfg). + WithAccountNumber(50). + WithSequence(23). + WithFees("50stake"). + WithMemo("memo"). + WithChainID("test-chain") +} + func TestBuildSimTx(t *testing.T) { txCfg, cdc := newTestTxConfig(t) @@ -117,17 +128,7 @@ func TestBuildSimTx(t *testing.T) { path := hd.CreateHDPath(118, 0, 0).String() _, _, err = kb.NewMnemonic("test_key1", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - - txf := tx.Factory{}. - WithTxConfig(txCfg). - WithAccountNumber(50). - WithSequence(23). - WithFees("50stake"). - WithMemo("memo"). - WithChainID("test-chain"). - WithSignMode(txCfg.SignModeHandler().DefaultMode()). - WithKeybase(kb) - + txf := mockTxFactory(txCfg).WithSignMode(txCfg.SignModeHandler().DefaultMode()).WithKeybase(kb) msg := banktypes.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) bz, err := txf.BuildSimTx(msg) require.NoError(t, err) @@ -143,16 +144,7 @@ func TestBuildUnsignedTx(t *testing.T) { _, _, err = kb.NewMnemonic("test_key1", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - - txf := tx.Factory{}. - WithTxConfig(txConfig). - WithAccountNumber(50). - WithSequence(23). - WithFees("50stake"). - WithMemo("memo"). - WithChainID("test-chain"). - WithKeybase(kb) - + txf := mockTxFactory(txConfig).WithKeybase(kb) msg := banktypes.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) tx, err := txf.BuildUnsignedTx(msg) require.NoError(t, err) @@ -163,6 +155,23 @@ func TestBuildUnsignedTx(t *testing.T) { require.Empty(t, sigs) } +func TestBuildUnsignedTxWithWithExtensionOptions(t *testing.T) { + txCfg := moduletestutil.MakeBuilderTestTxConfig() + extOpts := []*codectypes.Any{ + { + TypeUrl: "/test", + Value: []byte("test"), + }, + } + txf := mockTxFactory(txCfg).WithExtensionOptions(extOpts...) + msg := banktypes.NewMsgSend(sdk.AccAddress("from"), sdk.AccAddress("to"), nil) + tx, err := txf.BuildUnsignedTx(msg) + require.NoError(t, err) + require.NotNil(t, tx) + txb := tx.(*moduletestutil.TestTxBuilder) + require.Equal(t, extOpts, txb.ExtOptions) +} + func TestMnemonicInMemo(t *testing.T) { txConfig, cdc := newTestTxConfig(t) kb, err := keyring.New(t.Name(), "test", t.TempDir(), nil, cdc) @@ -239,13 +248,7 @@ func TestSign(t *testing.T) { requireT.NotEqual(pubKey1.Bytes(), pubKey2.Bytes()) t.Log("Pub keys:", pubKey1, pubKey2) - txfNoKeybase := tx.Factory{}. - WithTxConfig(txConfig). - WithAccountNumber(50). - WithSequence(23). - WithFees("50stake"). - WithMemo("memo"). - WithChainID("test-chain") + txfNoKeybase := mockTxFactory(txConfig) txfDirect := txfNoKeybase. WithKeybase(kb). WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT) @@ -406,13 +409,7 @@ func TestPreprocessHook(t *testing.T) { return nil }) - txfDirect := tx.Factory{}. - WithTxConfig(txConfig). - WithAccountNumber(50). - WithSequence(23). - WithFees("50stake"). - WithMemo("memo"). - WithChainID("test-chain"). + txfDirect := mockTxFactory(txConfig). WithKeybase(kb). WithSignMode(signingtypes.SignMode_SIGN_MODE_DIRECT). WithPreprocessTxHook(preprocessHook) diff --git a/client/tx_config.go b/client/tx_config.go index 5c5fd2695e40..530ced16a553 100644 --- a/client/tx_config.go +++ b/client/tx_config.go @@ -1,6 +1,7 @@ package client import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" @@ -48,4 +49,10 @@ type ( SetFeeGranter(feeGranter sdk.AccAddress) AddAuxSignerData(tx.AuxSignerData) error } + + // ExtendedTxBuilder extends the TxBuilder interface, + // which is used to set extension options to be included in a transaction. + ExtendedTxBuilder interface { + SetExtensionOptions(extOpts ...*codectypes.Any) + } ) diff --git a/types/module/testutil/codec.go b/types/module/testutil/codec.go index b54085c584e7..3011efdae937 100644 --- a/types/module/testutil/codec.go +++ b/types/module/testutil/codec.go @@ -41,3 +41,38 @@ func MakeTestEncodingConfig(modules ...module.AppModuleBasic) TestEncodingConfig return encCfg } + +func MakeTestTxConfig() client.TxConfig { + interfaceRegistry := types.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + return tx.NewTxConfig(cdc, tx.DefaultSignModes) +} + +type TestBuilderTxConfig struct { + client.TxConfig + TxBuilder *TestTxBuilder +} + +func MakeBuilderTestTxConfig() TestBuilderTxConfig { + return TestBuilderTxConfig{ + TxConfig: MakeTestTxConfig(), + } +} + +func (cfg TestBuilderTxConfig) NewTxBuilder() client.TxBuilder { + if cfg.TxBuilder == nil { + cfg.TxBuilder = &TestTxBuilder{ + TxBuilder: cfg.TxConfig.NewTxBuilder(), + } + } + return cfg.TxBuilder +} + +type TestTxBuilder struct { + client.TxBuilder + ExtOptions []*types.Any +} + +func (b *TestTxBuilder) SetExtensionOptions(extOpts ...*types.Any) { + b.ExtOptions = extOpts +}