From f4ef9d601608203114bd074f01b7a550adf94f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Fri, 18 Nov 2022 20:37:46 +0100 Subject: [PATCH 1/8] feat(app): Update post handlers --- baseapp/baseapp.go | 4 ++-- baseapp/options.go | 2 +- types/handler.go | 40 ++++++++++++++++++++++++++++++++++++-- x/auth/posthandler/post.go | 8 ++++---- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 31f61e7199d1..bf2885b1db9c 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -63,7 +63,7 @@ type BaseApp struct { //nolint: maligned mempool mempool.Mempool // application side mempool anteHandler sdk.AnteHandler // ante handler for fee and auth - postHandler sdk.AnteHandler // post handler, optional, e.g. for tips + postHandler sdk.PostHandler // post handler, optional, e.g. for tips initChainer sdk.InitChainer // initialize state with validators and state blob beginBlocker sdk.BeginBlocker // logic to run before any txs processProposal sdk.ProcessProposalHandler // the handler which runs on ABCI ProcessProposal @@ -739,7 +739,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // // Note: If the postHandler fails, we also revert the runMsgs state. if app.postHandler != nil { - newCtx, err := app.postHandler(runMsgCtx, tx, mode == runTxModeSimulate) + newCtx, err := app.postHandler(runMsgCtx, tx, result, mode == runTxModeSimulate, err == nil) if err != nil { return gInfo, nil, nil, priority, err } diff --git a/baseapp/options.go b/baseapp/options.go index f41f4e961ab2..fdb351c6468e 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -164,7 +164,7 @@ func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) { app.anteHandler = ah } -func (app *BaseApp) SetPostHandler(ph sdk.AnteHandler) { +func (app *BaseApp) SetPostHandler(ph sdk.PostHandler) { if app.sealed { panic("SetPostHandler() on sealed BaseApp") } diff --git a/types/handler.go b/types/handler.go index 87762744ee86..8175bfc60221 100644 --- a/types/handler.go +++ b/types/handler.go @@ -7,11 +7,19 @@ type Handler func(ctx Context, msg Msg) (*Result, error) // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err error) -// AnteDecorator wraps the next AnteHandler to perform custom pre- and post-processing. +// PostHandler +type PostHandler func(ctx Context, tx Tx, res *Result, simulate, success bool) (newCtx Context, err error) + +// AnteDecorator wraps the next AnteHandler to perform custom pre-processing. type AnteDecorator interface { AnteHandle(ctx Context, tx Tx, simulate bool, next AnteHandler) (newCtx Context, err error) } +// PostDecorator wraps the next PostHandler to perform custom post-processing. +type PostDecorator interface { + PostHandle(ctx Context, tx Tx, res *Result, simulate, success bool, next PostHandler) (newCtx Context, err error) +} + // ChainDecorator chains AnteDecorators together with each AnteDecorator // wrapping over the decorators further along chain and returns a single AnteHandler. // @@ -41,6 +49,29 @@ func ChainAnteDecorators(chain ...AnteDecorator) AnteHandler { } } +// ChainPostDecorators chains PostDecorators together with each PostDecorator +// wrapping over the decorators further along chain and returns a single PostHandler. +// +// NOTE: The first element is outermost decorator, while the last element is innermost +// decorator. Decorator ordering is critical since some decorators will expect +// certain checks and updates to be performed (e.g. the Context) before the decorator +// is run. These expectations should be documented clearly in a CONTRACT docline +// in the decorator's godoc. +func ChainPostDecorators(chain ...PostDecorator) PostHandler { + if len(chain) == 0 { + return nil + } + + // handle non-terminated decorators chain + if (chain[len(chain)-1] != Terminator{}) { + chain = append(chain, Terminator{}) + } + + return func(ctx Context, tx Tx, res *Result, simulate, success bool) (Context, error) { + return chain[0].PostHandle(ctx, tx, res, simulate, success, ChainPostDecorators(chain[1:]...)) + } +} + // Terminator AnteDecorator will get added to the chain to simplify decorator code // Don't need to check if next == nil further up the chain // @@ -61,7 +92,12 @@ func ChainAnteDecorators(chain ...AnteDecorator) AnteHandler { // snd \ \ \ / type Terminator struct{} -// Simply return provided Context and nil error +// AnteHandle returns the provided Context and nil error func (t Terminator) AnteHandle(ctx Context, _ Tx, _ bool, _ AnteHandler) (Context, error) { return ctx, nil } + +// PostHandler returns the provided Context and nil error +func (t Terminator) PostHandle(ctx Context, _ Tx, _ *Result, _, _ bool, _ PostHandler) (Context, error) { + return ctx, nil +} diff --git a/x/auth/posthandler/post.go b/x/auth/posthandler/post.go index 8d3fb7776c63..40310cad5ae7 100644 --- a/x/auth/posthandler/post.go +++ b/x/auth/posthandler/post.go @@ -7,9 +7,9 @@ import ( // HandlerOptions are the options required for constructing a default SDK PostHandler. type HandlerOptions struct{} -// NewPostHandler returns an empty posthandler chain. -func NewPostHandler(options HandlerOptions) (sdk.AnteHandler, error) { - postDecorators := []sdk.AnteDecorator{} +// NewPostHandler returns an empty PostHandler chain. +func NewPostHandler(_ HandlerOptions) (sdk.PostHandler, error) { + postDecorators := []sdk.PostDecorator{} - return sdk.ChainAnteDecorators(postDecorators...), nil + return sdk.ChainPostDecorators(postDecorators...), nil } From 73a85e7439964ab8d4fb5ea2eb9c301b5eed04c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Mon, 21 Nov 2022 11:21:11 +0100 Subject: [PATCH 2/8] docs --- docs/docs/core/00-baseapp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/core/00-baseapp.md b/docs/docs/core/00-baseapp.md index b7ad57e58a80..4d8b2d18943f 100644 --- a/docs/docs/core/00-baseapp.md +++ b/docs/docs/core/00-baseapp.md @@ -363,7 +363,7 @@ First, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the ` ### PostHandler -_PostHandler_ are like `AnteHandler` (they share the same signature), but they execute after [`RunMsgs`](#runmsgs). +`PostHandler` is similar to `AnteHandler`, but it, as the name suggests, executes custom post tx processing logic after [`RunMsgs`](#runmsgs) is called. `PostHandler` receives the `Result` of the the `RunMsgs` in order to enable this customizable behavior. Like `AnteHandler`s, `PostHandler`s are theoretically optional, one use case for `PostHandler`s is transaction tips (enabled by default in simapp). Other use cases like unused gas refund can also be enabled by `PostHandler`s. From 70e44d0a89498f8703332574141f10d2ce888cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Mon, 21 Nov 2022 11:24:57 +0100 Subject: [PATCH 3/8] c++ --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6a275d62a2b..23696cb9fbbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking +* (baseapp, x/auth/posthandler) [#13940](https://github.com/cosmos/cosmos-sdk/pull/13940) Update `PostHandler` to receive the `runTx` call `Result` and success boolean. * (codec) [#13307](https://github.com/cosmos/cosmos-sdk/pull/13307) Register all modules' `Msg`s with group's ModuleCdc so that Amino sign bytes are correctly generated. * (codec) [#13196](https://github.com/cosmos/cosmos-sdk/pull/13196) Register all modules' `Msg`s with gov's ModuleCdc so that Amino sign bytes are correctly generated. * (group) [#13592](https://github.com/cosmos/cosmos-sdk/pull/13592) Fix group types registration with Amino. From 514542032f31504b193c5162a29197511e116841 Mon Sep 17 00:00:00 2001 From: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com> Date: Mon, 21 Nov 2022 14:35:32 +0100 Subject: [PATCH 4/8] add post decorator mocks and tests (#13945) --- testutil/mock/types_handler.go | 42 ++++++++++++++++++++++++++++++++-- types/handler_test.go | 32 ++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/testutil/mock/types_handler.go b/testutil/mock/types_handler.go index efcbd1e7f873..ed72b673cdbd 100644 --- a/testutil/mock/types_handler.go +++ b/testutil/mock/types_handler.go @@ -1,7 +1,8 @@ // Code generated by MockGen. // Source: types/handler.go -// Chanes: -// + AnteHandler(...): calling `next` at the end of the function to run all anthe handler chain. +// Manual changes: +// + AnteHandler(...): calling `next` at the end of the function to run all ante handler chain. +// + PostHandler(...): calling `next` at the end of the function to run all post handler chain. // Package mock is a generated GoMock package. package mock @@ -50,3 +51,40 @@ func (mr *MockAnteDecoratorMockRecorder) AnteHandle(ctx, tx, simulate, next inte mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnteHandle", reflect.TypeOf((*MockAnteDecorator)(nil).AnteHandle), ctx, tx, simulate, next) } + +// MockPostDecorator is a mock of PostDecorator interface. +type MockPostDecorator struct { + ctrl *gomock.Controller + recorder *MockPostDecoratorMockRecorder +} + +// MockPostDecoratorMockRecorder is the mock recorder for MockPostDecorator. +type MockPostDecoratorMockRecorder struct { + mock *MockPostDecorator +} + +// NewMockPostDecorator creates a new mock instance. +func NewMockPostDecorator(ctrl *gomock.Controller) *MockPostDecorator { + mock := &MockPostDecorator{ctrl: ctrl} + mock.recorder = &MockPostDecoratorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPostDecorator) EXPECT() *MockPostDecoratorMockRecorder { + return m.recorder +} + +// PostHandle mocks base method. +func (m *MockPostDecorator) PostHandle(ctx types.Context, tx types.Tx, res *types.Result, simulate, success bool, next types.PostHandler) (types.Context, error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "PostHandle", ctx, tx, res, simulate, success, next) + // NOTE: we need to edit the generated code to call the "next handler" + return next(ctx, tx, res, simulate, success) +} + +// PostHandle indicates an expected call of PostHandle. +func (mr *MockPostDecoratorMockRecorder) PostHandle(ctx, tx, res, simulate, success, next interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostHandle", reflect.TypeOf((*MockPostDecorator)(nil).PostHandle), ctx, tx, res, simulate, success, next) +} diff --git a/types/handler_test.go b/types/handler_test.go index d656360a4ac8..d12ee9a2fd8a 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -45,3 +45,35 @@ func (s *handlerTestSuite) TestChainAnteDecorators() { mockAnteDecorator2)(ctx, tx, true) s.Require().NoError(err) } + +func (s *handlerTestSuite) TestChainPostDecorators() { + // test panic when passing an empty sclice of PostDecorators + s.Require().Nil(sdk.ChainPostDecorators([]sdk.PostDecorator{}...)) + + // Create empty context as well as transaction + ctx := sdk.Context{} + tx := sdk.Tx(nil) + res := &sdk.Result{} + + // Create mocks + mockCtrl := gomock.NewController(s.T()) + mockPostDecorator1 := mock.NewMockPostDecorator(mockCtrl) + mockPostDecorator2 := mock.NewMockPostDecorator(mockCtrl) + + // Test chaining only one post decorator + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) + _, err := sdk.ChainPostDecorators(mockPostDecorator1)(ctx, tx, res, true, true) + s.Require().NoError(err) + + // Tests chaining multiple post decorators + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) + mockPostDecorator2.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) + // NOTE: we can't check that mockAnteDecorator2 is passed as the last argument because + // ChainAnteDecorators wraps the decorators into closures, so each decorator is + // receiving a closure. + _, err = sdk.ChainPostDecorators( + mockPostDecorator1, + mockPostDecorator2, + )(ctx, tx, res, true, true) + s.Require().NoError(err) +} From b12c0b3e43098f8b904d66be5a9923986c932ccf Mon Sep 17 00:00:00 2001 From: Vladislav Varadinov Date: Mon, 12 Dec 2022 18:14:05 +0200 Subject: [PATCH 5/8] fix: Added godoc for the PostHandler and reference comment for follow up PR (#14261) --- baseapp/baseapp.go | 1 + types/handler.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index bf2885b1db9c..f5da970f56dd 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -739,6 +739,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // // Note: If the postHandler fails, we also revert the runMsgs state. if app.postHandler != nil { + // Follow-up Ref: https://github.com/cosmos/cosmos-sdk/pull/13941 newCtx, err := app.postHandler(runMsgCtx, tx, result, mode == runTxModeSimulate, err == nil) if err != nil { return gInfo, nil, nil, priority, err diff --git a/types/handler.go b/types/handler.go index 8175bfc60221..fe441eada3a1 100644 --- a/types/handler.go +++ b/types/handler.go @@ -7,7 +7,8 @@ type Handler func(ctx Context, msg Msg) (*Result, error) // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err error) -// PostHandler +// PostHandler like AnteHandler but it executes after RunMsgs. Runs on success +// or failure and enables use cases like gas refunding. type PostHandler func(ctx Context, tx Tx, res *Result, simulate, success bool) (newCtx Context, err error) // AnteDecorator wraps the next AnteHandler to perform custom pre-processing. From 51319039b106baf681f0e465f17ad335df36b8b4 Mon Sep 17 00:00:00 2001 From: Vladislav Varadinov Date: Thu, 15 Dec 2022 10:24:50 +0200 Subject: [PATCH 6/8] refactor: Use only MsgResponses from Result in PostHandler (#14299) --- baseapp/baseapp.go | 8 ++------ testutil/mock/types_handler.go | 7 ++++--- types/handler.go | 12 +++++++----- types/handler_test.go | 10 +++++----- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 80de38408ef3..64ca8c2a6120 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -732,19 +732,15 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // and we're in DeliverTx. Note, runMsgs will never return a reference to a // Result if any single message fails or does not have a registered Handler. result, err = app.runMsgs(runMsgCtx, msgs, mode) + if err == nil { // Run optional postHandlers. // // Note: If the postHandler fails, we also revert the runMsgs state. if app.postHandler != nil { - // The runMsgCtx context currently contains events emitted by the ante handler. - // We clear this to correctly order events without duplicates. - // Note that the state is still preserved. - postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) - // Follow-up Ref: https://github.com/cosmos/cosmos-sdk/pull/13941 - newCtx, err := app.postHandler(postCtx, tx, result, mode == runTxModeSimulate, err == nil) + newCtx, err := app.postHandler(runMsgCtx, tx, result.MsgResponses, mode == runTxModeSimulate, err == nil) if err != nil { return gInfo, nil, nil, priority, err } diff --git a/testutil/mock/types_handler.go b/testutil/mock/types_handler.go index ed72b673cdbd..9c45d97f9238 100644 --- a/testutil/mock/types_handler.go +++ b/testutil/mock/types_handler.go @@ -8,6 +8,7 @@ package mock import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" reflect "reflect" gomock "github.com/golang/mock/gomock" @@ -76,11 +77,11 @@ func (m *MockPostDecorator) EXPECT() *MockPostDecoratorMockRecorder { } // PostHandle mocks base method. -func (m *MockPostDecorator) PostHandle(ctx types.Context, tx types.Tx, res *types.Result, simulate, success bool, next types.PostHandler) (types.Context, error) { +func (m *MockPostDecorator) PostHandle(ctx types.Context, tx types.Tx, msgResponses []*codectypes.Any, simulate, success bool, next types.PostHandler) (types.Context, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "PostHandle", ctx, tx, res, simulate, success, next) + m.ctrl.Call(m, "PostHandle", ctx, tx, msgResponses, simulate, success, next) // NOTE: we need to edit the generated code to call the "next handler" - return next(ctx, tx, res, simulate, success) + return next(ctx, tx, msgResponses, simulate, success) } // PostHandle indicates an expected call of PostHandle. diff --git a/types/handler.go b/types/handler.go index fe441eada3a1..110208bbeaa6 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,5 +1,7 @@ package types +import codectypes "github.com/cosmos/cosmos-sdk/codec/types" + // Handler defines the core of the state transition function of an application. type Handler func(ctx Context, msg Msg) (*Result, error) @@ -9,7 +11,7 @@ type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err er // PostHandler like AnteHandler but it executes after RunMsgs. Runs on success // or failure and enables use cases like gas refunding. -type PostHandler func(ctx Context, tx Tx, res *Result, simulate, success bool) (newCtx Context, err error) +type PostHandler func(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool) (newCtx Context, err error) // AnteDecorator wraps the next AnteHandler to perform custom pre-processing. type AnteDecorator interface { @@ -18,7 +20,7 @@ type AnteDecorator interface { // PostDecorator wraps the next PostHandler to perform custom post-processing. type PostDecorator interface { - PostHandle(ctx Context, tx Tx, res *Result, simulate, success bool, next PostHandler) (newCtx Context, err error) + PostHandle(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool, next PostHandler) (newCtx Context, err error) } // ChainDecorator chains AnteDecorators together with each AnteDecorator @@ -68,8 +70,8 @@ func ChainPostDecorators(chain ...PostDecorator) PostHandler { chain = append(chain, Terminator{}) } - return func(ctx Context, tx Tx, res *Result, simulate, success bool) (Context, error) { - return chain[0].PostHandle(ctx, tx, res, simulate, success, ChainPostDecorators(chain[1:]...)) + return func(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool) (Context, error) { + return chain[0].PostHandle(ctx, tx, msgResponses, simulate, success, ChainPostDecorators(chain[1:]...)) } } @@ -99,6 +101,6 @@ func (t Terminator) AnteHandle(ctx Context, _ Tx, _ bool, _ AnteHandler) (Contex } // PostHandler returns the provided Context and nil error -func (t Terminator) PostHandle(ctx Context, _ Tx, _ *Result, _, _ bool, _ PostHandler) (Context, error) { +func (t Terminator) PostHandle(ctx Context, _ Tx, _ []*codectypes.Any, _, _ bool, _ PostHandler) (Context, error) { return ctx, nil } diff --git a/types/handler_test.go b/types/handler_test.go index cfb50a88fd1d..f18002627078 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -49,19 +49,19 @@ func (s *handlerTestSuite) TestChainPostDecorators() { mockPostDecorator2 := mock.NewMockPostDecorator(mockCtrl) // Test chaining only one post decorator - mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) - _, err := sdk.ChainPostDecorators(mockPostDecorator1)(ctx, tx, res, true, true) + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) + _, err := sdk.ChainPostDecorators(mockPostDecorator1)(ctx, tx, res.MsgResponses, true, true) s.Require().NoError(err) // Tests chaining multiple post decorators - mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) - mockPostDecorator2.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res), true, gomock.Eq(true), gomock.Any()).Times(1) + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) + mockPostDecorator2.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) // NOTE: we can't check that mockAnteDecorator2 is passed as the last argument because // ChainAnteDecorators wraps the decorators into closures, so each decorator is // receiving a closure. _, err = sdk.ChainPostDecorators( mockPostDecorator1, mockPostDecorator2, - )(ctx, tx, res, true, true) + )(ctx, tx, res.MsgResponses, true, true) s.Require().NoError(err) } From 62777944411198e3f98d62950c76fa703ef6c0fa Mon Sep 17 00:00:00 2001 From: Vladislav Varadinov Date: Mon, 9 Jan 2023 12:20:15 +0200 Subject: [PATCH 7/8] fix: remove MsgResponses from PostHandler (#14522) --- baseapp/baseapp.go | 2 +- testutil/mock/types_handler.go | 11 +++++------ types/handler.go | 16 +++++++--------- types/handler_test.go | 21 ++++++++++----------- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 6b720c97134c..95e0f7386c4d 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -725,7 +725,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // Note: If the postHandler fails, we also revert the runMsgs state. if app.postHandler != nil { // Follow-up Ref: https://github.com/cosmos/cosmos-sdk/pull/13941 - newCtx, err := app.postHandler(runMsgCtx, tx, result.MsgResponses, mode == runTxModeSimulate, err == nil) + newCtx, err := app.postHandler(runMsgCtx, tx, mode == runTxModeSimulate, err == nil) if err != nil { return gInfo, nil, anteEvents, priority, err } diff --git a/testutil/mock/types_handler.go b/testutil/mock/types_handler.go index 9c45d97f9238..c3a59d0362b2 100644 --- a/testutil/mock/types_handler.go +++ b/testutil/mock/types_handler.go @@ -8,7 +8,6 @@ package mock import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" reflect "reflect" gomock "github.com/golang/mock/gomock" @@ -77,15 +76,15 @@ func (m *MockPostDecorator) EXPECT() *MockPostDecoratorMockRecorder { } // PostHandle mocks base method. -func (m *MockPostDecorator) PostHandle(ctx types.Context, tx types.Tx, msgResponses []*codectypes.Any, simulate, success bool, next types.PostHandler) (types.Context, error) { +func (m *MockPostDecorator) PostHandle(ctx types.Context, tx types.Tx, simulate, success bool, next types.PostHandler) (types.Context, error) { m.ctrl.T.Helper() - m.ctrl.Call(m, "PostHandle", ctx, tx, msgResponses, simulate, success, next) + m.ctrl.Call(m, "PostHandle", ctx, tx, simulate, success, next) // NOTE: we need to edit the generated code to call the "next handler" - return next(ctx, tx, msgResponses, simulate, success) + return next(ctx, tx, simulate, success) } // PostHandle indicates an expected call of PostHandle. -func (mr *MockPostDecoratorMockRecorder) PostHandle(ctx, tx, res, simulate, success, next interface{}) *gomock.Call { +func (mr *MockPostDecoratorMockRecorder) PostHandle(ctx, tx, simulate, success, next interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostHandle", reflect.TypeOf((*MockPostDecorator)(nil).PostHandle), ctx, tx, res, simulate, success, next) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostHandle", reflect.TypeOf((*MockPostDecorator)(nil).PostHandle), ctx, tx, simulate, success, next) } diff --git a/types/handler.go b/types/handler.go index 110208bbeaa6..1a86c1660551 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,7 +1,5 @@ package types -import codectypes "github.com/cosmos/cosmos-sdk/codec/types" - // Handler defines the core of the state transition function of an application. type Handler func(ctx Context, msg Msg) (*Result, error) @@ -11,7 +9,7 @@ type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err er // PostHandler like AnteHandler but it executes after RunMsgs. Runs on success // or failure and enables use cases like gas refunding. -type PostHandler func(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool) (newCtx Context, err error) +type PostHandler func(ctx Context, tx Tx, simulate, success bool) (newCtx Context, err error) // AnteDecorator wraps the next AnteHandler to perform custom pre-processing. type AnteDecorator interface { @@ -20,10 +18,10 @@ type AnteDecorator interface { // PostDecorator wraps the next PostHandler to perform custom post-processing. type PostDecorator interface { - PostHandle(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool, next PostHandler) (newCtx Context, err error) + PostHandle(ctx Context, tx Tx, simulate, success bool, next PostHandler) (newCtx Context, err error) } -// ChainDecorator chains AnteDecorators together with each AnteDecorator +// ChainAnteDecorators ChainDecorator chains AnteDecorators together with each AnteDecorator // wrapping over the decorators further along chain and returns a single AnteHandler. // // NOTE: The first element is outermost decorator, while the last element is innermost @@ -70,8 +68,8 @@ func ChainPostDecorators(chain ...PostDecorator) PostHandler { chain = append(chain, Terminator{}) } - return func(ctx Context, tx Tx, msgResponses []*codectypes.Any, simulate, success bool) (Context, error) { - return chain[0].PostHandle(ctx, tx, msgResponses, simulate, success, ChainPostDecorators(chain[1:]...)) + return func(ctx Context, tx Tx, simulate, success bool) (Context, error) { + return chain[0].PostHandle(ctx, tx, simulate, success, ChainPostDecorators(chain[1:]...)) } } @@ -100,7 +98,7 @@ func (t Terminator) AnteHandle(ctx Context, _ Tx, _ bool, _ AnteHandler) (Contex return ctx, nil } -// PostHandler returns the provided Context and nil error -func (t Terminator) PostHandle(ctx Context, _ Tx, _ []*codectypes.Any, _, _ bool, _ PostHandler) (Context, error) { +// PostHandle returns the provided Context and nil error +func (t Terminator) PostHandle(ctx Context, _ Tx, _, _ bool, _ PostHandler) (Context, error) { return ctx, nil } diff --git a/types/handler_test.go b/types/handler_test.go index f18002627078..3d20d3023d2d 100644 --- a/types/handler_test.go +++ b/types/handler_test.go @@ -34,34 +34,33 @@ func TestChainAnteDecorators(t *testing.T) { require.NoError(t, err) } -func (s *handlerTestSuite) TestChainPostDecorators() { +func TestChainPostDecorators(t *testing.T) { // test panic when passing an empty sclice of PostDecorators - s.Require().Nil(sdk.ChainPostDecorators([]sdk.PostDecorator{}...)) + require.Nil(t, sdk.ChainPostDecorators([]sdk.PostDecorator{}...)) // Create empty context as well as transaction ctx := sdk.Context{} tx := sdk.Tx(nil) - res := &sdk.Result{} // Create mocks - mockCtrl := gomock.NewController(s.T()) + mockCtrl := gomock.NewController(t) mockPostDecorator1 := mock.NewMockPostDecorator(mockCtrl) mockPostDecorator2 := mock.NewMockPostDecorator(mockCtrl) // Test chaining only one post decorator - mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) - _, err := sdk.ChainPostDecorators(mockPostDecorator1)(ctx, tx, res.MsgResponses, true, true) - s.Require().NoError(err) + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Eq(true), gomock.Any()).Times(1) + _, err := sdk.ChainPostDecorators(mockPostDecorator1)(ctx, tx, true, true) + require.NoError(t, err) // Tests chaining multiple post decorators - mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) - mockPostDecorator2.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), gomock.Eq(res.MsgResponses), true, gomock.Eq(true), gomock.Any()).Times(1) + mockPostDecorator1.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Eq(true), gomock.Any()).Times(1) + mockPostDecorator2.EXPECT().PostHandle(gomock.Eq(ctx), gomock.Eq(tx), true, gomock.Eq(true), gomock.Any()).Times(1) // NOTE: we can't check that mockAnteDecorator2 is passed as the last argument because // ChainAnteDecorators wraps the decorators into closures, so each decorator is // receiving a closure. _, err = sdk.ChainPostDecorators( mockPostDecorator1, mockPostDecorator2, - )(ctx, tx, res.MsgResponses, true, true) - s.Require().NoError(err) + )(ctx, tx, true, true) + require.NoError(t, err) } From 1e3745f7fa0cd5bbdee99bba2d9e2008fa4a7198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Wed, 11 Jan 2023 12:28:10 +0100 Subject: [PATCH 8/8] Update CHANGELOG.md Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae84af432e8..3f289b6d9fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,7 +124,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking -* (baseapp, x/auth/posthandler) [#13940](https://github.com/cosmos/cosmos-sdk/pull/13940) Update `PostHandler` to receive the `runTx` call `Result` and success boolean. +* (baseapp, x/auth/posthandler) [#13940](https://github.com/cosmos/cosmos-sdk/pull/13940) Update `PostHandler` to receive the `runTx` success boolean. * (x/group) [#13742](https://github.com/cosmos/cosmos-sdk/pull/13742) Migrate group policy account from module accounts to base account. * (codec) [#13307](https://github.com/cosmos/cosmos-sdk/pull/13307) Register all modules' `Msg`s with group's ModuleCdc so that Amino sign bytes are correctly generated. * (codec) [#13196](https://github.com/cosmos/cosmos-sdk/pull/13196) Register all modules' `Msg`s with gov's ModuleCdc so that Amino sign bytes are correctly generated.