# Cosmos SDK Middlewares Problem
Context: [Make middlewares less confusing](https://github.com/cosmos/cosmos-sdk/issues/11955)
## Before 0.46-beta
Antehandlers is a set of functions which should execute linearly.
```go
type AnteHandler func(ctx Context, tx Tx, simulate bool) (newCtx Context, err error)
```
In fact we never create directly the AnteHandlers, instead we create decorators, which are wrapped into AnteHandler closures:
```go
func (d Decorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler)
(newCtx sdk.Context, err error) {
// prepare
// optional: defer / recover hacks to escape the linear flow (sic!)
// optional: simulate logic (sic!)
// optional: update context
return next(ctx, tx, simulate)
}
// here we translate the decorator into AnteHandler:
func ChainAnteDecorators(chain ...AnteDecorator) AnteHandler {
// ...
return func(ctx Context, tx Tx, simulate bool) (Context, error) {
return chain[0].AnteHandle(ctx, tx, simulate, ChainAnteDecorators(chain[1:]...))
}
}
```
Examples:
+ [ContextDecorator with GasMeter](https://github.com/cosmos/cosmos-sdk/blob/release%2Fv0.45.x/x/auth/ante/setup.go#L32)
## 0.46-beta:
Middleware concept was created to modularize the execution for 3 major transaction flows: `CheckTx`, `DeliverTx` and `SimulateTx`.
We compose middlewares using list: `A, B,...` and we run them sequentially:
```
A
A_precode
B
B_precode
...
DeliverTx()
...
B_postcode
A_postcode
```
We clearly separate the concerns for
+ CheckTx
+ DeliverTx
+ Simulate
Wrapping code is more clean, and more modular, examples:
+ [gas middleware](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/x/auth/middleware/gas.go#L43)
+ [fee grant](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/x/auth/middleware/fee.go#L114) is still complex but it's more modular.
More: [Middleware ADR](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/docs/architecture/adr-045-check-delivertx-middlewares.md).
## Antehandlers vs 0.46-beta2 Middlewares
I consider 0.46-beta2 middlewares approach superior to Antehandlers:
+ Modularization and clear separation of concern: checkTx, deliverTx, simulate, and helper functions.
+ Easier code
+ easy way to implement tendermint event indexer
+ Antehandlers are not linear - there are needed "hacks" to escape linearity (eg gas meter)
+ Implementing tx [priority](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/x/auth/middleware/fee.go#L97) or advanced [fee market](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/x/auth/middleware/fee.go#L97) with middleware is straightforward.
With Antehandlers it will be hacky: priority must be set in tx Response type. So probably using `defer`.
Personally, I think the 0.46-beta middleware design requires better documentation, rather than revert to AnteHandlers. Superior design could be based on Dependency Injection mentioned by Aaron.
## Alternatives
_DRAFTS_
```go
type DeliverTxMiddleware interface {
// comment with dependencies
Pre(ctx context.Context, req Request) (Context, Request, error)
Post(ctx context.Context, req Request, resp Response, err error)
Recover(ctx context.Context, req Request, resp Response, panicErr interface{})
}
type Executor struct {
deliverTx func(ctx Context, req Request) (Response, ResponseCheckTx, error)
ms []DeliverTxMiddleware
}
func (e Executor) DeliverTx(ctx, req) (Response, error){
_, _, resp, err := e.execute(ctx, req, e.ms)
return resp, err
}
func (e Executor) execute(ctx context.Context, req Request, ms []DeliverTxMiddleware) (Context, Request, Response, error) {
if len(ms) == 0 {
return e.handler(ctx, req)
}
var err error
var resp = Response{}
var m = ms[0]
defer func(){
if r := recover(); r != nil {
m.Recover(ctx, req, resp, r)
}
}
ctx, req, err = m.Pre(ctx, req)
if err != nil {
return ctx, req, resp, err
}
// recurse
ctx, req, resp, err = e.Execute(ctx, req, ms[1:])
resp, err = m.Post(ctx, req, resp, err)
return ctx, req, res, err
}
func ComposeDeliverTx(h tx.Handler, ms ...DeliverTxMiddleware) tx.Handler {
return Executor{h, ms}
}
```
Execution graph:
```
A.pre 🡪 B.pre 🡪 ... 🡾
RunMsgs
A.post 🡨 B.post 🡨 ... 🡷
```
### Example
Let's try to implement [gas handler]() using the Executor:
```go
type gasHandler struct {
sdkCtx sdk.Context
}
func (h *gasHandler) Pre(ctx context.Context, req tx.Request) (context.Context, tx.Request, error) {
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
if err != nil {
return ctx, req, err
}
h.sdkCtx = sdkCtx
return sdk.WrapSDKContext(sdkCtx), req, err
}
func (h *gasHandler) Post(ctx context.Context, req tx.Request, resp tx.Response, err error) (context.Context, tx.Response, error) {
return ctx, populateGas(resp, h.sdkCtx), err
}
```
vs 0.46-beta Middleware version:
```go
type gasTxHandler struct {
next tx.Handler
}
func (txh gasTxHandler) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
if err != nil {
return tx.Response{}, err
}
res, err := txh.next.DeliverTx(sdk.WrapSDKContext(sdkCtx), req)
return populateGas(res, sdkCtx), err
}
```
### Comments
+ the draft above builds on the same idea as the Middleweare design
+ we clearly break down the code into `pre`, `post` and `recover` actions