---
# System prepended metadata

title: Cosmos SDK Middlewares Problem

---

# 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
