refactor: Move TxDecoder into its own middleware (#10612)

* WIP: middleware refactor

* refactor `tx.Request`

* Add MsgResponses any in sdk.Result

* add helper functions in abci

* refactor tips

* review changes

* Fix mock tests

* Update baseapp/abci.go

* Update baseapp/abci.go

* Update types/tx/middleware.go

* Update types/tx/middleware.go

* tx.Response to abci conversion

* refactor makeABCIData

* Add comments

* Fix build

* fix build error

* fix tests

* fix test

* fix tests

* Fix TestSimulateTx

* fix tests

* fix test

* Fix build

* Simplify code

* fix test build

* Use repeated bytes in txMsgData

* Fix grpc-gateway test

* Make proto-gen

* Automagically register MsgResponse

* review changes

* Use froydi's trick

* Use Any in TxMsgData

* Finally remove API breaking change

* Revert unnecessary stuff

* refactor: Move TxDecoder into its own middleware

* Add test for txDecoderMiddleware

* Fix some baseapp tests

* Fix some more tests

* Fix mock tests

* Fix middleware tests

* Add cl

* Fix tests

* Update types/tx/middleware.go

Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>

Co-authored-by: atheesh <atheesh@vitwit.com>
Co-authored-by: atheeshp <59333759+atheeshp@users.noreply.github.com>
This commit is contained in:
Amaury 2021-12-06 10:26:15 +01:00 committed by GitHub
parent 9566c99185
commit b3e922d08b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 302 additions and 208 deletions

View File

@ -112,6 +112,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/gov) [\#10373](https://github.com/cosmos/cosmos-sdk/pull/10373) Removed gov `keeper.{MustMarshal, MustUnmarshal}`.
* [\#10348](https://github.com/cosmos/cosmos-sdk/pull/10348) StdSignBytes takes a new argument of type `*tx.Tip` for signing over tips using LEGACY_AMINO_JSON.
* [\#10208](https://github.com/cosmos/cosmos-sdk/pull/10208) The `x/auth/signing.Tx` interface now also includes a new `GetTip() *tx.Tip` method for verifying tipped transactions. The `x/auth/types` expected BankKeeper interface now expects the `SendCoins` method too.
* [\#10612](https://github.com/cosmos/cosmos-sdk/pull/10612) `baseapp.NewBaseApp` constructor function doesn't take the `sdk.TxDecoder` anymore. This logic has been moved into the TxDecoderMiddleware.
### Client Breaking Changes

View File

@ -250,13 +250,8 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type))
}
reqTx, err := app.txDecoder(req.Tx)
if err != nil {
return sdkerrors.ResponseCheckTx(err, 0, 0, app.trace)
}
ctx := app.getContextForTx(mode, req.Tx)
res, checkRes, err := app.txHandler.CheckTx(ctx, tx.Request{Tx: reqTx, TxBytes: req.Tx}, tx.RequestCheckTx{Type: req.Type})
res, checkRes, err := app.txHandler.CheckTx(ctx, tx.Request{TxBytes: req.Tx}, tx.RequestCheckTx{Type: req.Type})
if err != nil {
return sdkerrors.ResponseCheckTx(err, uint64(res.GasUsed), uint64(res.GasWanted), app.trace)
}
@ -285,14 +280,9 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx
}
}
}()
reqTx, err := app.txDecoder(req.Tx)
if err != nil {
abciRes = sdkerrors.ResponseDeliverTx(err, 0, 0, app.trace)
return abciRes
}
ctx := app.getContextForTx(runTxModeDeliver, req.Tx)
res, err := app.txHandler.DeliverTx(ctx, tx.Request{Tx: reqTx, TxBytes: req.Tx})
res, err := app.txHandler.DeliverTx(ctx, tx.Request{TxBytes: req.Tx})
if err != nil {
abciRes = sdkerrors.ResponseDeliverTx(err, uint64(res.GasUsed), uint64(res.GasWanted), app.trace)
return abciRes

View File

@ -25,20 +25,20 @@ func TestGetBlockRentionHeight(t *testing.T) {
expected int64
}{
"defaults": {
bapp: baseapp.NewBaseApp(name, logger, db, nil),
bapp: baseapp.NewBaseApp(name, logger, db),
maxAgeBlocks: 0,
commitHeight: 499000,
expected: 0,
},
"pruning unbonding time only": {
bapp: baseapp.NewBaseApp(name, logger, db, nil, baseapp.SetMinRetainBlocks(1)),
bapp: baseapp.NewBaseApp(name, logger, db, baseapp.SetMinRetainBlocks(1)),
maxAgeBlocks: 362880,
commitHeight: 499000,
expected: 136120,
},
"pruning iavl snapshot only": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
baseapp.SetMinRetainBlocks(1),
),
@ -48,7 +48,7 @@ func TestGetBlockRentionHeight(t *testing.T) {
},
"pruning state sync snapshot only": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetSnapshotInterval(50000),
baseapp.SetSnapshotKeepRecent(3),
baseapp.SetMinRetainBlocks(1),
@ -59,7 +59,7 @@ func TestGetBlockRentionHeight(t *testing.T) {
},
"pruning min retention only": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetMinRetainBlocks(400000),
),
maxAgeBlocks: 0,
@ -68,7 +68,7 @@ func TestGetBlockRentionHeight(t *testing.T) {
},
"pruning all conditions": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
baseapp.SetMinRetainBlocks(400000),
baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3),
@ -79,7 +79,7 @@ func TestGetBlockRentionHeight(t *testing.T) {
},
"no pruning due to no persisted state": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
baseapp.SetMinRetainBlocks(400000),
baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3),
@ -90,7 +90,7 @@ func TestGetBlockRentionHeight(t *testing.T) {
},
"disable pruning": {
bapp: baseapp.NewBaseApp(
name, logger, db, nil,
name, logger, db,
baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
baseapp.SetMinRetainBlocks(0),
baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3),
@ -127,7 +127,7 @@ func TestBaseAppCreateQueryContextRejectsNegativeHeights(t *testing.T) {
logger := defaultLogger()
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, logger, db, nil)
app := baseapp.NewBaseApp(name, logger, db)
proves := []bool{
false, true,

View File

@ -52,7 +52,6 @@ type BaseApp struct { // nolint: maligned
queryRouter sdk.QueryRouter // router for redirecting query calls
grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls
interfaceRegistry types.InterfaceRegistry
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
txHandler tx.Handler // txHandler for {Deliver,Check}Tx and simulations
initChainer sdk.InitChainer // initialize state with validators and state blob
@ -137,7 +136,7 @@ type BaseApp struct { // nolint: maligned
//
// NOTE: The db is used to store the version number for now.
func NewBaseApp(
name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp),
name string, logger log.Logger, db dbm.DB, options ...func(*BaseApp),
) *BaseApp {
app := &BaseApp{
logger: logger,
@ -147,7 +146,6 @@ func NewBaseApp(
storeLoader: DefaultStoreLoader,
queryRouter: NewQueryRouter(),
grpcQueryRouter: NewGRPCQueryRouter(),
txDecoder: txDecoder,
fauxMerkleMode: false,
}

View File

@ -24,6 +24,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/snapshots"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
@ -40,9 +41,13 @@ var (
capKey1 = sdk.NewKVStoreKey("key1")
capKey2 = sdk.NewKVStoreKey("key2")
interfaceRegistry = testdata.NewTestInterfaceRegistry()
encCfg = simapp.MakeTestEncodingConfig()
)
func init() {
registerTestCodec(encCfg.Amino)
}
type paramStore struct {
db *dbm.MemDB
}
@ -90,13 +95,10 @@ func newBaseApp(name string, options ...func(*baseapp.BaseApp)) *baseapp.BaseApp
db := dbm.NewMemDB()
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
return baseapp.NewBaseApp(name, logger, db, testTxDecoder(codec), options...)
return baseapp.NewBaseApp(name, logger, db, options...)
}
func registerTestCodec(cdc *codec.LegacyAmino) {
// register Tx, Msg
sdk.RegisterLegacyAminoCodec(cdc)
// register test types
cdc.RegisterConcrete(&txTest{}, "cosmos-sdk/baseapp/txTest", nil)
cdc.RegisterConcrete(&msgCounter{}, "cosmos-sdk/baseapp/msgCounter", nil)
@ -106,10 +108,7 @@ func registerTestCodec(cdc *codec.LegacyAmino) {
}
// aminoTxEncoder creates a amino TxEncoder for testing purposes.
func aminoTxEncoder() sdk.TxEncoder {
cdc := codec.NewLegacyAmino()
registerTestCodec(cdc)
func aminoTxEncoder(cdc *codec.LegacyAmino) sdk.TxEncoder {
return legacytx.StdTxConfig{Cdc: cdc}.TxEncoder()
}
@ -132,6 +131,7 @@ func setupBaseApp(t *testing.T, options ...func(*baseapp.BaseApp)) *baseapp.Base
func testTxHandler(options middleware.TxHandlerOptions, customTxHandlerMiddleware handlerFun) tx.Handler {
return middleware.ComposeMiddlewares(
middleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
middleware.NewTxDecoderMiddleware(options.TxDecoder),
middleware.GasTxMiddleware,
middleware.RecoveryTxMiddleware,
middleware.NewIndexEventsTxMiddleware(options.IndexEvents),
@ -161,7 +161,8 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { return ctx, nil },
)
@ -200,7 +201,7 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options
tx.Msgs = append(tx.Msgs, msgKeyValue{Key: key, Value: value})
keyCounter++
}
txBytes, err := codec.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
resp := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
require.True(t, resp.IsOK(), "%v", resp.String())
@ -245,7 +246,7 @@ func TestLoadVersion(t *testing.T) {
pruningOpt := baseapp.SetPruning(storetypes.PruneNothing)
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app := baseapp.NewBaseApp(name, logger, db, pruningOpt)
// make a cap key and mount the store
err := app.LoadLatestVersion() // needed to make stores non-nil
@ -272,7 +273,7 @@ func TestLoadVersion(t *testing.T) {
commitID2 := storetypes.CommitID{Version: 2, Hash: res.Data}
// reload with LoadLatestVersion
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app = baseapp.NewBaseApp(name, logger, db, pruningOpt)
app.MountStores()
err = app.LoadLatestVersion()
require.Nil(t, err)
@ -280,7 +281,7 @@ func TestLoadVersion(t *testing.T) {
// reload with LoadVersion, see if you can commit the same block and get
// the same result
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app = baseapp.NewBaseApp(name, logger, db, pruningOpt)
err = app.LoadVersion(1)
require.Nil(t, err)
testLoadVersionHelper(t, app, int64(1), commitID1)
@ -359,7 +360,7 @@ func TestSetLoader(t *testing.T) {
if tc.setLoader != nil {
opts = append(opts, tc.setLoader)
}
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...)
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, opts...)
app.MountStores(sdk.NewKVStoreKey(tc.loadStoreKey))
err := app.LoadLatestVersion()
require.Nil(t, err)
@ -381,7 +382,7 @@ func TestVersionSetterGetter(t *testing.T) {
pruningOpt := baseapp.SetPruning(storetypes.PruneDefault)
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app := baseapp.NewBaseApp(name, logger, db, pruningOpt)
require.Equal(t, "", app.Version())
res := app.Query(abci.RequestQuery{Path: "app/version"})
@ -401,7 +402,7 @@ func TestLoadVersionInvalid(t *testing.T) {
pruningOpt := baseapp.SetPruning(storetypes.PruneNothing)
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app := baseapp.NewBaseApp(name, logger, db, pruningOpt)
err := app.LoadLatestVersion()
require.Nil(t, err)
@ -416,7 +417,7 @@ func TestLoadVersionInvalid(t *testing.T) {
commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data}
// create a new app with the stores mounted under the same cap key
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app = baseapp.NewBaseApp(name, logger, db, pruningOpt)
// require we can load the latest version
err = app.LoadVersion(1)
@ -438,7 +439,7 @@ func TestLoadVersionPruning(t *testing.T) {
pruningOpt := baseapp.SetPruning(pruningOptions)
db := dbm.NewMemDB()
name := t.Name()
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app := baseapp.NewBaseApp(name, logger, db, pruningOpt)
// make a cap key and mount the store
capKey := sdk.NewKVStoreKey("key1")
@ -476,7 +477,7 @@ func TestLoadVersionPruning(t *testing.T) {
}
// reload with LoadLatestVersion, check it loads last version
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
app = baseapp.NewBaseApp(name, logger, db, pruningOpt)
app.MountStores(capKey)
err = app.LoadLatestVersion()
@ -494,7 +495,7 @@ func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight in
func TestOptionFunction(t *testing.T) {
logger := defaultLogger()
db := dbm.NewMemDB()
bap := baseapp.NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name"))
bap := baseapp.NewBaseApp("starting name", logger, db, testChangeNameHelper("new name"))
require.Equal(t, bap.GetName(), "new name", "BaseApp should have had name changed via option function")
}
@ -504,23 +505,6 @@ func testChangeNameHelper(name string) func(*baseapp.BaseApp) {
}
}
// Test that txs can be unmarshalled and read and that
// correct error codes are returned when not
func TestTxDecoder(t *testing.T) {
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
app := newBaseApp(t.Name())
tx := newTxCounter(1, 0)
txBytes := codec.MustMarshal(tx)
dTx, err := app.TxDecoder(txBytes)
require.NoError(t, err)
cTx := dTx.(txTest)
require.Equal(t, tx.Counter, cTx.Counter)
}
// Test that Info returns the latest committed state.
func TestInfo(t *testing.T) {
app := newBaseApp(t.Name())
@ -589,7 +573,7 @@ func TestInitChainer(t *testing.T) {
// we can reload the same app later
db := dbm.NewMemDB()
logger := defaultLogger()
app := baseapp.NewBaseApp(name, logger, db, nil)
app := baseapp.NewBaseApp(name, logger, db)
capKey := sdk.NewKVStoreKey("main")
capKey2 := sdk.NewKVStoreKey("key2")
app.MountStores(capKey, capKey2)
@ -644,7 +628,7 @@ func TestInitChainer(t *testing.T) {
require.Equal(t, value, res.Value)
// reload app
app = baseapp.NewBaseApp(name, logger, db, nil)
app = baseapp.NewBaseApp(name, logger, db)
app.SetInitChainer(initChainer)
app.MountStores(capKey, capKey2)
err = app.LoadLatestVersion() // needed to make stores non-nil
@ -668,7 +652,7 @@ func TestInitChain_WithInitialHeight(t *testing.T) {
name := t.Name()
db := dbm.NewMemDB()
logger := defaultLogger()
app := baseapp.NewBaseApp(name, logger, db, nil)
app := baseapp.NewBaseApp(name, logger, db)
app.InitChain(
abci.RequestInitChain{
@ -684,7 +668,7 @@ func TestBeginBlock_WithInitialHeight(t *testing.T) {
name := t.Name()
db := dbm.NewMemDB()
logger := defaultLogger()
app := baseapp.NewBaseApp(name, logger, db, nil)
app := baseapp.NewBaseApp(name, logger, db)
app.InitChain(
abci.RequestInitChain{
@ -973,7 +957,8 @@ func TestCheckTx(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
customHandlerTxTest(t, capKey1, counterKey),
)
@ -985,17 +970,13 @@ func TestCheckTx(t *testing.T) {
nTxs := int64(5)
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
for i := int64(0); i < nTxs; i++ {
tx := newTxCounter(i, 0) // no messages
txBytes, err := codec.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
r := app.CheckTx(abci.RequestCheckTx{Tx: txBytes})
require.Empty(t, r.GetEvents())
require.True(t, r.IsOK(), fmt.Sprintf("%v", r))
require.True(t, r.IsOK(), fmt.Sprintf("%+v", r))
}
checkStateStore := app.CheckState().Context().KVStore(capKey1)
@ -1026,6 +1007,7 @@ func TestDeliverTx(t *testing.T) {
anteKey := []byte("ante-key")
// test increments in the handler
deliverKey := []byte("deliver-key")
txHandlerOpt := func(bapp *baseapp.BaseApp) {
legacyRouter := middleware.NewLegacyRouter()
r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey))
@ -1033,7 +1015,8 @@ func TestDeliverTx(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
customHandlerTxTest(t, capKey1, anteKey),
)
@ -1042,10 +1025,6 @@ func TestDeliverTx(t *testing.T) {
app := setupBaseApp(t, txHandlerOpt)
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
nBlocks := 3
txPerHeight := 5
@ -1057,7 +1036,7 @@ func TestDeliverTx(t *testing.T) {
counter := int64(blockN*txPerHeight + i)
tx := newTxCounter(counter, counter)
txBytes, err := codec.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -1086,6 +1065,7 @@ func TestMultiMsgDeliverTx(t *testing.T) {
// increment the msg counter
deliverKey := []byte("deliver-key")
deliverKey2 := []byte("deliver-key2")
txHandlerOpt := func(bapp *baseapp.BaseApp) {
legacyRouter := middleware.NewLegacyRouter()
r1 := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey))
@ -1095,7 +1075,8 @@ func TestMultiMsgDeliverTx(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
customHandlerTxTest(t, capKey1, anteKey),
)
@ -1103,17 +1084,13 @@ func TestMultiMsgDeliverTx(t *testing.T) {
}
app := setupBaseApp(t, txHandlerOpt)
// Create same codec used in txDecoder
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
// run a multi-msg tx
// with all msgs the same route
header := tmproto.Header{Height: 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
tx := newTxCounter(0, 0, 1, 2)
txBytes, err := codec.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
@ -1133,7 +1110,7 @@ func TestMultiMsgDeliverTx(t *testing.T) {
tx = newTxCounter(1, 3)
tx.Msgs = append(tx.Msgs, msgCounter2{0})
tx.Msgs = append(tx.Msgs, msgCounter2{1})
txBytes, err = codec.Marshal(tx)
txBytes, err = encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
@ -1183,7 +1160,8 @@ func TestSimulateTx(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { return ctx, nil },
)
@ -1193,10 +1171,6 @@ func TestSimulateTx(t *testing.T) {
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
cdc := codec.NewLegacyAmino()
registerTestCodec(cdc)
nBlocks := 3
for blockN := 0; blockN < nBlocks; blockN++ {
count := int64(blockN + 1)
@ -1205,7 +1179,7 @@ func TestSimulateTx(t *testing.T) {
tx := newTxCounter(count, count)
tx.GasLimit = gasConsumed
txBytes, err := cdc.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.Nil(t, err)
// simulate a message, check gas reported
@ -1258,7 +1232,8 @@ func TestRunInvalidTransaction(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) {
return
@ -1274,7 +1249,7 @@ func TestRunInvalidTransaction(t *testing.T) {
// transaction with no messages
{
emptyTx := &txTest{}
_, result, err := app.SimDeliver(aminoTxEncoder(), emptyTx)
_, result, err := app.SimDeliver(aminoTxEncoder(encCfg.Amino), emptyTx)
require.Nil(t, result)
space, code, _ := sdkerrors.ABCIInfo(err, false)
@ -1300,7 +1275,7 @@ func TestRunInvalidTransaction(t *testing.T) {
for _, testCase := range testCases {
tx := testCase.tx
_, _, err := app.SimDeliver(aminoTxEncoder(), tx)
_, _, err := app.SimDeliver(aminoTxEncoder(encCfg.Amino), tx)
if testCase.fail {
require.Error(t, err)
@ -1317,7 +1292,7 @@ func TestRunInvalidTransaction(t *testing.T) {
// transaction with no known route
{
unknownRouteTx := txTest{[]sdk.Msg{&msgNoRoute{}}, 0, false, math.MaxUint64}
_, result, err := app.SimDeliver(aminoTxEncoder(), unknownRouteTx)
_, result, err := app.SimDeliver(aminoTxEncoder(encCfg.Amino), unknownRouteTx)
require.Error(t, err)
require.Nil(t, result)
@ -1326,7 +1301,7 @@ func TestRunInvalidTransaction(t *testing.T) {
require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err)
unknownRouteTx = txTest{[]sdk.Msg{&msgCounter{}, &msgNoRoute{}}, 0, false, math.MaxUint64}
_, result, err = app.SimDeliver(aminoTxEncoder(), unknownRouteTx)
_, result, err = app.SimDeliver(aminoTxEncoder(encCfg.Amino), unknownRouteTx)
require.Error(t, err)
require.Nil(t, result)
@ -1340,8 +1315,10 @@ func TestRunInvalidTransaction(t *testing.T) {
tx := newTxCounter(0, 0)
tx.Msgs = append(tx.Msgs, &msgNoDecode{})
// new codec so we can encode the tx, but we shouldn't be able to decode
// new codec so we can encode the tx, but we shouldn't be able to decode,
// because baseapp's codec is not aware of msgNoDecode.
newCdc := codec.NewLegacyAmino()
sdk.RegisterLegacyAminoCodec(newCdc) // register Tx, Msg
registerTestCodec(newCdc)
newCdc.RegisterConcrete(&msgNoDecode{}, "cosmos-sdk/baseapp/msgNoDecode", nil)
@ -1382,7 +1359,8 @@ func TestTxGasLimits(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
ante,
)
@ -1421,7 +1399,7 @@ func TestTxGasLimits(t *testing.T) {
for i, tc := range testCases {
tx := tc.tx
tx.GasLimit = gasGranted
gInfo, result, err := app.SimDeliver(aminoTxEncoder(), tx)
gInfo, result, err := app.SimDeliver(aminoTxEncoder(encCfg.Amino), tx)
// check gas used and wanted
require.Equal(t, tc.gasUsed, gInfo.GasUsed, fmt.Sprintf("tc #%d; gas: %v, result: %v, err: %s", i, gInfo, result, err))
@ -1469,7 +1447,8 @@ func TestMaxBlockGasLimits(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
ante,
)
@ -1514,7 +1493,7 @@ func TestMaxBlockGasLimits(t *testing.T) {
// execute the transaction multiple times
for j := 0; j < tc.numDelivers; j++ {
_, result, err := app.SimDeliver(aminoTxEncoder(), tx)
_, result, err := app.SimDeliver(aminoTxEncoder(encCfg.Amino), tx)
ctx := app.DeliverState().Context()
@ -1546,7 +1525,6 @@ func TestMaxBlockGasLimits(t *testing.T) {
func TestBaseAppMiddleware(t *testing.T) {
anteKey := []byte("ante-key")
deliverKey := []byte("deliver-key")
cdc := codec.NewLegacyAmino()
txHandlerOpt := func(bapp *baseapp.BaseApp) {
legacyRouter := middleware.NewLegacyRouter()
@ -1555,7 +1533,8 @@ func TestBaseAppMiddleware(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
customHandlerTxTest(t, capKey1, anteKey),
)
@ -1564,7 +1543,6 @@ func TestBaseAppMiddleware(t *testing.T) {
app := setupBaseApp(t, txHandlerOpt)
app.InitChain(abci.RequestInitChain{})
registerTestCodec(cdc)
header := tmproto.Header{Height: app.LastBlockHeight() + 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
@ -1575,7 +1553,7 @@ func TestBaseAppMiddleware(t *testing.T) {
// the next txs ante handler execution (customHandlerTxTest).
tx := newTxCounter(0, 0)
tx.setFailOnAnte(true)
txBytes, err := cdc.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
require.Empty(t, res.Events)
@ -1590,7 +1568,7 @@ func TestBaseAppMiddleware(t *testing.T) {
tx = newTxCounter(0, 0)
tx.setFailOnHandler(true)
txBytes, err = cdc.Marshal(tx)
txBytes, err = encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -1606,7 +1584,7 @@ func TestBaseAppMiddleware(t *testing.T) {
// implicitly checked by previous tx executions
tx = newTxCounter(1, 0)
txBytes, err = cdc.Marshal(tx)
txBytes, err = encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -1635,9 +1613,6 @@ func TestGasConsumptionBadTx(t *testing.T) {
return ctx, nil
}
cdc := codec.NewLegacyAmino()
registerTestCodec(cdc)
txHandlerOpt := func(bapp *baseapp.BaseApp) {
legacyRouter := middleware.NewLegacyRouter()
r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
@ -1649,7 +1624,8 @@ func TestGasConsumptionBadTx(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
ante,
)
@ -1673,7 +1649,7 @@ func TestGasConsumptionBadTx(t *testing.T) {
tx := newTxCounter(5, 0)
tx.GasLimit = gasWanted
tx.setFailOnAnte(true)
txBytes, err := cdc.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -1681,7 +1657,7 @@ func TestGasConsumptionBadTx(t *testing.T) {
// require next tx to fail due to black gas limit
tx = newTxCounter(5, 0)
txBytes, err = cdc.Marshal(tx)
txBytes, err = encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -1710,7 +1686,8 @@ func TestQuery(t *testing.T) {
txHandler := testTxHandler(
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: testTxDecoder(encCfg.Amino),
},
func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) {
store := ctx.KVStore(capKey1)
@ -1738,7 +1715,7 @@ func TestQuery(t *testing.T) {
require.Equal(t, 0, len(res.Value))
// query is still empty after a CheckTx
_, resTx, err := app.SimCheck(aminoTxEncoder(), tx)
_, resTx, err := app.SimCheck(aminoTxEncoder(encCfg.Amino), tx)
require.NoError(t, err)
require.NotNil(t, resTx)
res = app.Query(query)
@ -1748,7 +1725,7 @@ func TestQuery(t *testing.T) {
header := tmproto.Header{Height: app.LastBlockHeight() + 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
_, resTx, err = app.SimDeliver(aminoTxEncoder(), tx)
_, resTx, err = app.SimDeliver(aminoTxEncoder(encCfg.Amino), tx)
require.NoError(t, err)
require.NotNil(t, resTx)
res = app.Query(query)
@ -2030,16 +2007,15 @@ func TestWithRouter(t *testing.T) {
customRouter := &testCustomRouter{routes: sync.Map{}}
r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey))
customRouter.AddRoute(r)
txHandler := middleware.NewRunMsgsTxHandler(middleware.NewMsgServiceRouter(interfaceRegistry), customRouter)
txHandler := middleware.ComposeMiddlewares(
middleware.NewRunMsgsTxHandler(middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry), customRouter),
middleware.NewTxDecoderMiddleware(testTxDecoder(encCfg.Amino)),
)
bapp.SetTxHandler(txHandler)
}
app := setupBaseApp(t, txHandlerOpt)
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
codec := codec.NewLegacyAmino()
registerTestCodec(codec)
nBlocks := 3
txPerHeight := 5
@ -2051,7 +2027,7 @@ func TestWithRouter(t *testing.T) {
counter := int64(blockN*txPerHeight + i)
tx := newTxCounter(counter, counter)
txBytes, err := codec.Marshal(tx)
txBytes, err := encCfg.Amino.Marshal(tx)
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
@ -2074,7 +2050,7 @@ func TestBaseApp_EndBlock(t *testing.T) {
},
}
app := baseapp.NewBaseApp(name, logger, db, nil)
app := baseapp.NewBaseApp(name, logger, db)
app.SetParamStore(&paramStore{db: dbm.NewMemDB()})
app.InitChain(abci.RequestInitChain{
ConsensusParams: cp,

View File

@ -55,7 +55,7 @@ func TestRegisterQueryServiceTwice(t *testing.T) {
db := dbm.NewMemDB()
encCfg := simapp.MakeTestEncodingConfig()
logger, _ := log.NewDefaultLogger("plain", "info", false)
app := baseapp.NewBaseApp("test", logger, db, encCfg.TxConfig.TxDecoder())
app := baseapp.NewBaseApp("test", logger, db)
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)
testdata.RegisterInterfaces(encCfg.InterfaceRegistry)

View File

@ -36,13 +36,8 @@ func (app *BaseApp) SimCheck(txEncoder sdk.TxEncoder, sdkTx sdk.Tx) (sdk.GasInfo
// Simulate executes a tx in simulate mode to get result and gas info.
func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) {
sdkTx, err := app.txDecoder(txBytes)
if err != nil {
return sdk.GasInfo{}, nil, err
}
ctx := app.getContextForTx(runTxModeSimulate, txBytes)
res, err := app.txHandler.SimulateTx(ctx, tx.Request{Tx: sdkTx, TxBytes: txBytes})
res, err := app.txHandler.SimulateTx(ctx, tx.Request{TxBytes: txBytes})
gasInfo := sdk.GasInfo{
GasWanted: res.GasWanted,
GasUsed: res.GasUsed,

View File

@ -45,13 +45,6 @@ func (app *BaseApp) GetName() string {
return app.name
}
// GetName return name.
//
// This method is only accessible in baseapp tests.
func (app *BaseApp) TxDecoder(txBytes []byte) (sdk.Tx, error) {
return app.txDecoder(txBytes)
}
// CreateQueryContext calls app's createQueryContext.
//
// This method is only accessible in baseapp tests.

View File

@ -23,6 +23,7 @@ import (
func testTxHandler(options middleware.TxHandlerOptions) tx.Handler {
return middleware.ComposeMiddlewares(
middleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
middleware.NewTxDecoderMiddleware(options.TxDecoder),
middleware.GasTxMiddleware,
middleware.RecoveryTxMiddleware,
middleware.NewIndexEventsTxMiddleware(options.IndexEvents),
@ -42,7 +43,7 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
capKeyMainStore := sdk.NewKVStoreKey("main")
// Create BaseApp.
baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx)
baseApp := bam.NewBaseApp("kvstore", logger, db)
// Set mounts for BaseApp's MultiStore.
baseApp.MountStores(capKeyMainStore)
@ -59,6 +60,7 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
middleware.TxHandlerOptions{
LegacyRouter: legacyRouter,
MsgServiceRouter: middleware.NewMsgServiceRouter(encCfg.InterfaceRegistry),
TxDecoder: decodeTx,
},
)
baseApp.SetTxHandler(txHandler)

View File

@ -205,7 +205,7 @@ func NewSimApp(
legacyAmino := encodingConfig.Amino
interfaceRegistry := encodingConfig.InterfaceRegistry
bApp := baseapp.NewBaseApp(appName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...)
bApp := baseapp.NewBaseApp(appName, logger, db, baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
@ -431,6 +431,7 @@ func (app *SimApp) setTxHandler(txConfig client.TxConfig, indexEventsStr []strin
FeegrantKeeper: app.FeeGrantKeeper,
SignModeHandler: txConfig.SignModeHandler(),
SigGasConsumer: authmiddleware.DefaultSigVerificationGasConsumer,
TxDecoder: txConfig.TxDecoder(),
})
if err != nil {
panic(err)

View File

@ -78,7 +78,7 @@ func TestRunMigrations(t *testing.T) {
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
// Create a new baseapp and configurator for the purpose of this test.
bApp := baseapp.NewBaseApp(appName, logger, db, encCfg.TxConfig.TxDecoder())
bApp := baseapp.NewBaseApp(appName, logger, db)
bApp.SetCommitMultiStoreTracer(nil)
bApp.SetInterfaceRegistry(encCfg.InterfaceRegistry)
msr := authmiddleware.NewMsgServiceRouter(encCfg.InterfaceRegistry)

View File

@ -22,6 +22,19 @@ type ResponseSimulateTx struct {
Result *sdk.Result
}
// Request is the tx request type used in middlewares.
// At least one of Tx or TxBytes must be set. If only TxBytes is set, then
// Tx will be populated by the TxDecoderMiddleware. If only Tx is set, then
// some middlewares (such as signature verification) will fail.
//
// In practice, the middleware stack is called from {Check,Deliver}Tx, which
// only passes the TxBytes. Then, the TxDecoderMiddleware decodes the bytes
// into the Tx field.
type Request struct {
Tx sdk.Tx
TxBytes []byte
}
// Response is the tx response type used in middlewares.
type Response struct {
GasWanted uint64
@ -34,12 +47,6 @@ type Response struct {
Events []abci.Event
}
// Request is the tx request type used in middlewares.
type Request struct {
Tx sdk.Tx
TxBytes []byte
}
// RequestCheckTx is the additional request type used in middlewares CheckTx
// method.
type RequestCheckTx struct {

View File

@ -16,7 +16,7 @@ func (s *MWTestSuite) TestValidateBasic() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.ValidateBasicMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.ValidateBasicMiddleware)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
@ -54,7 +54,7 @@ func (s *MWTestSuite) TestValidateBasic() {
func (s *MWTestSuite) TestValidateMemo() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.ValidateMemoMiddleware(s.app.AccountKeeper))
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.ValidateMemoMiddleware(s.app.AccountKeeper))
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
@ -90,7 +90,7 @@ func (s *MWTestSuite) TestConsumeGasForTxSize() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.ConsumeTxSizeGasMiddleware(s.app.AccountKeeper))
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.ConsumeTxSizeGasMiddleware(s.app.AccountKeeper))
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
@ -174,7 +174,7 @@ func (s *MWTestSuite) TestConsumeGasForTxSize() {
func (s *MWTestSuite) TestTxHeightTimeoutMiddleware() {
ctx := s.SetupTest(true)
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.TxTimeoutHeightMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.TxTimeoutHeightMiddleware)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()

View File

@ -13,7 +13,7 @@ func (s *MWTestSuite) TestRejectExtensionOptionsMiddleware() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.RejectExtensionOptionsMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.RejectExtensionOptionsMiddleware)
// no extension options should not trigger an error
theTx := txBuilder.GetTx()

View File

@ -13,7 +13,7 @@ func (s *MWTestSuite) TestEnsureMempoolFees() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.MempoolFeeMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.MempoolFeeMiddleware)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
@ -55,7 +55,7 @@ func (s *MWTestSuite) TestDeductFees() {
ctx := s.SetupTest(false) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.DeductFeeMiddleware(
s.app.AccountKeeper,
s.app.BankKeeper,

View File

@ -31,7 +31,7 @@ func (s *MWTestSuite) TestDeductFeesNoDelegation() {
protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes)
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.DeductFeeMiddleware(
s.app.AccountKeeper,
s.app.BankKeeper,

View File

@ -50,7 +50,7 @@ func (s *MWTestSuite) setupGasTx() (signing.Tx, []byte, sdk.Context, uint64) {
func (s *MWTestSuite) TestSetup() {
testTx, _, ctx, gasLimit := s.setupGasTx()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.GasTxMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.GasTxMiddleware)
testcases := []struct {
name string
@ -77,62 +77,48 @@ func (s *MWTestSuite) TestSetup() {
func (s *MWTestSuite) TestRecoverPanic() {
testTx, txBytes, ctx, gasLimit := s.setupGasTx()
txHandler := middleware.ComposeMiddlewares(outOfGasTxHandler{}, middleware.GasTxMiddleware, middleware.RecoveryTxMiddleware)
txHandler := middleware.ComposeMiddlewares(outOfGasTxHandler, middleware.GasTxMiddleware, middleware.RecoveryTxMiddleware)
res, _, err := txHandler.CheckTx(sdk.WrapSDKContext(ctx), tx.Request{Tx: testTx, TxBytes: txBytes}, tx.RequestCheckTx{})
s.Require().Error(err, "Did not return error on OutOfGas panic")
s.Require().True(errors.Is(sdkerrors.ErrOutOfGas, err), "Returned error is not an out of gas error")
s.Require().Equal(gasLimit, uint64(res.GasWanted))
txHandler = middleware.ComposeMiddlewares(outOfGasTxHandler{}, middleware.GasTxMiddleware)
txHandler = middleware.ComposeMiddlewares(outOfGasTxHandler, middleware.GasTxMiddleware)
s.Require().Panics(func() {
txHandler.CheckTx(sdk.WrapSDKContext(ctx), tx.Request{Tx: testTx, TxBytes: txBytes}, tx.RequestCheckTx{})
}, "Recovered from non-Out-of-Gas panic")
}
// outOfGasTxHandler is a test middleware that will throw OutOfGas panic.
type outOfGasTxHandler struct{}
var _ tx.Handler = outOfGasTxHandler{}
func (txh outOfGasTxHandler) DeliverTx(ctx context.Context, _ tx.Request) (tx.Response, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
overLimit := sdkCtx.GasMeter().Limit() + 1
// Should panic with outofgas error
sdkCtx.GasMeter().ConsumeGas(overLimit, "test panic")
panic("not reached")
}
func (txh outOfGasTxHandler) CheckTx(ctx context.Context, _ tx.Request, _ tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
overLimit := sdkCtx.GasMeter().Limit() + 1
// Should panic with outofgas error
sdkCtx.GasMeter().ConsumeGas(overLimit, "test panic")
panic("not reached")
}
func (txh outOfGasTxHandler) SimulateTx(ctx context.Context, _ tx.Request) (tx.Response, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
overLimit := sdkCtx.GasMeter().Limit() + 1
// Should panic with outofgas error
sdkCtx.GasMeter().ConsumeGas(overLimit, "test panic")
panic("not reached")
// customTxHandler is a test middleware that will run a custom function.
type customTxHandler struct {
fn func(context.Context, tx.Request) (tx.Response, error)
}
// noopTxHandler is a test middleware that does nothing.
type noopTxHandler struct{}
var _ tx.Handler = customTxHandler{}
var _ tx.Handler = noopTxHandler{}
func (txh noopTxHandler) CheckTx(_ context.Context, _ tx.Request, _ tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
return tx.Response{}, tx.ResponseCheckTx{}, nil
func (h customTxHandler) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return h.fn(ctx, req)
}
func (txh noopTxHandler) SimulateTx(_ context.Context, _ tx.Request) (tx.Response, error) {
func (h customTxHandler) CheckTx(ctx context.Context, req tx.Request, _ tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
res, err := h.fn(ctx, req)
return res, tx.ResponseCheckTx{}, err
}
func (h customTxHandler) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return h.fn(ctx, req)
}
// noopTxHandler is a test middleware that returns an empty response.
var noopTxHandler = customTxHandler{func(_ context.Context, _ tx.Request) (tx.Response, error) {
return tx.Response{}, nil
}
func (txh noopTxHandler) DeliverTx(ctx context.Context, _ tx.Request) (tx.Response, error) {
return tx.Response{}, nil
}
}}
// outOfGasTxHandler is a test middleware that panics with an outOfGas error.
var outOfGasTxHandler = customTxHandler{func(ctx context.Context, _ tx.Request) (tx.Response, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
overLimit := sdkCtx.GasMeter().Limit() + 1
// Should panic with outofgas error
sdkCtx.GasMeter().ConsumeGas(overLimit, "test panic")
panic("not reached")
}}

View File

@ -32,6 +32,10 @@ func ComposeMiddlewares(txHandler tx.Handler, middlewares ...tx.Middleware) tx.H
type TxHandlerOptions struct {
Debug bool
// TxDecoder is used to decode the raw tx bytes into a sdk.Tx.
TxDecoder sdk.TxDecoder
// IndexEvents defines the set of events in the form {eventType}.{attributeKey},
// which informs Tendermint what to index. If empty, all events will be indexed.
IndexEvents map[string]struct{}
@ -49,6 +53,10 @@ type TxHandlerOptions struct {
// NewDefaultTxHandler defines a TxHandler middleware stacks that should work
// for most applications.
func NewDefaultTxHandler(options TxHandlerOptions) (tx.Handler, error) {
if options.TxDecoder == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "txDecoder is required for middlewares")
}
if options.AccountKeeper == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for middlewares")
}
@ -68,6 +76,7 @@ func NewDefaultTxHandler(options TxHandlerOptions) (tx.Handler, error) {
return ComposeMiddlewares(
NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
NewTxDecoderMiddleware(options.TxDecoder),
// Set a new GasMeter on sdk.Context.
//
// Make sure the Gas middleware is outside of all other middlewares

View File

@ -1025,6 +1025,7 @@ func (s *MWTestSuite) TestCustomSignatureVerificationGasConsumer() {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)
}
},
TxDecoder: s.clientCtx.TxConfig.TxDecoder(),
},
)
s.Require().NoError(err)

View File

@ -12,7 +12,7 @@ func (s *MWTestSuite) TestPriority() {
ctx := s.SetupTest(true) // setup
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
txHandler := middleware.ComposeMiddlewares(noopTxHandler{}, middleware.TxPriorityMiddleware)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, middleware.TxPriorityMiddleware)
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()

View File

@ -27,7 +27,7 @@ func (s *MWTestSuite) TestSetPubKey() {
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
require := s.Require()
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.SetPubKeyMiddleware(s.app.AccountKeeper),
)
@ -127,7 +127,7 @@ func (s *MWTestSuite) TestSigVerification() {
// make block height non-zero to ensure account numbers part of signBytes
ctx = ctx.WithBlockHeight(1)
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.SetPubKeyMiddleware(s.app.AccountKeeper),
middleware.SigVerificationMiddleware(
s.app.AccountKeeper,
@ -239,7 +239,7 @@ func (s *MWTestSuite) TestSigVerification_ExplicitAmino() {
gasLimit := testdata.NewTestGasLimit()
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.SetPubKeyMiddleware(s.app.AccountKeeper),
middleware.SigVerificationMiddleware(
s.app.AccountKeeper,
@ -342,7 +342,7 @@ func (s *MWTestSuite) runSigMiddlewares(params types.Params, _ bool, privs ...cr
s.Require().NoError(err)
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.SetPubKeyMiddleware(s.app.AccountKeeper),
middleware.SigGasConsumeMiddleware(s.app.AccountKeeper, middleware.DefaultSigVerificationGasConsumer),
middleware.SigVerificationMiddleware(
@ -382,7 +382,7 @@ func (s *MWTestSuite) TestIncrementSequenceMiddleware() {
s.Require().NoError(err)
txHandler := middleware.ComposeMiddlewares(
noopTxHandler{},
noopTxHandler,
middleware.IncrementSequenceMiddleware(s.app.AccountKeeper),
)

View File

@ -89,6 +89,7 @@ func (s *MWTestSuite) SetupTest(isCheckTx bool) sdk.Context {
FeegrantKeeper: s.app.FeeGrantKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
TxDecoder: s.clientCtx.TxConfig.TxDecoder(),
})
s.Require().NoError(err)
s.txHandler = txHandler

77
x/auth/middleware/tx.go Normal file
View File

@ -0,0 +1,77 @@
package middleware
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
)
type txDecoderHandler struct {
next tx.Handler
txDecoder sdk.TxDecoder
}
// NewTxDecoderMiddleware creates a new middleware that will decode tx bytes
// into a sdk.Tx. As input request, at least one of Tx or TxBytes must be set.
// If only TxBytes is set, then TxDecoderMiddleware will populate the Tx field.
// If only Tx is set, then TxBytes will be left empty, but some middlewares
// such as signature verification might fail.
func NewTxDecoderMiddleware(txDecoder sdk.TxDecoder) tx.Middleware {
return func(txh tx.Handler) tx.Handler {
return txDecoderHandler{next: txh, txDecoder: txDecoder}
}
}
var _ tx.Handler = gasTxHandler{}
// CheckTx implements tx.Handler.CheckTx.
func (h txDecoderHandler) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
newReq, err := h.populateReq(req)
if err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return h.next.CheckTx(ctx, newReq, checkReq)
}
// DeliverTx implements tx.Handler.DeliverTx.
func (h txDecoderHandler) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
newReq, err := h.populateReq(req)
if err != nil {
return tx.Response{}, err
}
return h.next.DeliverTx(ctx, newReq)
}
// SimulateTx implements tx.Handler.SimulateTx method.
func (h txDecoderHandler) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
newReq, err := h.populateReq(req)
if err != nil {
return tx.Response{}, err
}
return h.next.SimulateTx(ctx, newReq)
}
// populateReq takes a tx.Request, and if its Tx field is not set, then
// decodes the TxBytes and populates the decoded Tx field. It leaves
// req.TxBytes untouched.
func (h txDecoderHandler) populateReq(req tx.Request) (tx.Request, error) {
if len(req.TxBytes) == 0 && req.Tx == nil {
return tx.Request{}, sdkerrors.ErrInvalidRequest.Wrap("got empty tx request")
}
sdkTx := req.Tx
var err error
if len(req.TxBytes) != 0 {
sdkTx, err = h.txDecoder(req.TxBytes)
if err != nil {
return tx.Request{}, err
}
}
return tx.Request{Tx: sdkTx, TxBytes: req.TxBytes}, nil
}

View File

@ -0,0 +1,57 @@
package middleware_test
import (
"context"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
)
func (s *MWTestSuite) TestTxDecoderMiddleware() {
ctx := s.SetupTest(true) // setup
require := s.Require()
// Create a tx.
priv1, _, addr1 := testdata.KeyTestPubAddr()
txBuilder := s.clientCtx.TxConfig.NewTxBuilder()
err := txBuilder.SetMsgs(testdata.NewTestMsg(addr1))
require.NoError(err)
sdkTx, txBz, err := s.createTestTx(txBuilder, []cryptotypes.PrivKey{priv1}, []uint64{1}, []uint64{0}, ctx.ChainID())
require.NoError(err)
// Create a custom tx.Handler that checks that the req.Tx field is
// correctly populated.
txReqChecker := customTxHandler{func(c context.Context, r tx.Request) (tx.Response, error) {
require.NotNil(r.Tx)
require.Equal(sdkTx.GetMsgs()[0], r.Tx.GetMsgs()[0])
return tx.Response{}, nil
}}
testcases := []struct {
name string
req tx.Request
expErr bool
}{
{"empty tx bz", tx.Request{}, true},
{"tx bz and tx both given as inputs", tx.Request{Tx: sdkTx, TxBytes: txBz}, false},
{"tx bz only given as input", tx.Request{TxBytes: txBz}, false},
{"tx only given as input", tx.Request{Tx: sdkTx}, false},
}
for _, tc := range testcases {
s.Run(tc.name, func() {
txHandler := middleware.ComposeMiddlewares(
txReqChecker,
middleware.NewTxDecoderMiddleware(s.clientCtx.TxConfig.TxDecoder()),
)
_, err := txHandler.DeliverTx(sdk.WrapSDKContext(ctx), tc.req)
if tc.expErr {
require.Error(err)
} else {
require.NoError(err)
}
})
}
}

View File

@ -124,7 +124,7 @@ func TestSetLoader(t *testing.T) {
// load the app with the existing db
opts := []func(*baseapp.BaseApp){baseapp.SetPruning(storetypes.PruneNothing)}
origapp := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...)
origapp := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, opts...)
origapp.MountStores(sdk.NewKVStoreKey(tc.origStoreKey))
err := origapp.LoadLatestVersion()
require.Nil(t, err)
@ -140,7 +140,7 @@ func TestSetLoader(t *testing.T) {
}
// load the new app with the original app db
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...)
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, opts...)
app.MountStores(sdk.NewKVStoreKey(tc.loadStoreKey))
err = app.LoadLatestVersion()
require.Nil(t, err)