Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.

Commit f1cde2a

Browse files
Alex Johnsondavidterpay
andauthored
fix: mempool lane size check on CheckTx (#561)
* push * init * fix setup * format * fix test * use lane * ok * finalize * fix everything * lint fix: * Update abci/checktx/mempool_parity_check_tx.go Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com> * lint fix * tidy * remove * cleanup --------- Co-authored-by: David Terpay <david.terpay@gmail.com> Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com>
1 parent 242fdf2 commit f1cde2a

35 files changed

+615
-342
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
> **Note**: The BlockSDK is open source software that Skip maintains. We strive to be responsive to questions and issues within 1-2 weeks - please ask in our [#block-sdk-support discord](https://discord.com/invite/hFeHVAE26P) channel, or open a GitHub issue!
2727
28-
**Please note the status of BlockSDK maintainenace:**
28+
**Please note the status of BlockSDK maintenance:**
2929

3030
1. We are not currently providing hands-on support for new integrations.
3131
2. We have not yet completed our entire testing process for the FreeLane. We recommend integrators who want to have the best experience utilize the MEV Lane and the Default Lane only at this time.

abci/abci.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
sdk "github.com/cosmos/cosmos-sdk/types"
99

1010
"github.com/cosmos/cosmos-sdk/baseapp"
11+
1112
"github.com/skip-mev/block-sdk/v2/block"
1213
"github.com/skip-mev/block-sdk/v2/block/proposals"
1314
"github.com/skip-mev/block-sdk/v2/block/utils"

abci/checktx/check_tx_test.go

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ func (s *CheckTxTestSuite) TestCheckTxMempoolParity() {
4343
)
4444
s.Require().NoError(err)
4545

46+
hugeBidTx, _, err := testutils.CreateNAuctionTx(
47+
s.EncCfg.TxConfig,
48+
s.Accounts[0],
49+
sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)),
50+
0,
51+
0,
52+
[]testutils.Account{s.Accounts[0]},
53+
100,
54+
100000,
55+
)
56+
s.Require().NoError(err)
57+
4658
// create a tx that should not be inserted in the mev-lane
4759
bidTx2, _, err := testutils.CreateAuctionTx(
4860
s.EncCfg.TxConfig,
@@ -56,10 +68,11 @@ func (s *CheckTxTestSuite) TestCheckTxMempoolParity() {
5668
s.Require().NoError(err)
5769

5870
txs := map[sdk.Tx]bool{
59-
bidTx: true,
71+
bidTx: true,
72+
hugeBidTx: true,
6073
}
6174

62-
mevLane := s.InitLane(math.LegacyOneDec(), txs)
75+
mevLane := s.InitLane(math.LegacyOneDec(), txs, true)
6376
mempool, err := block.NewLanedMempool(s.Ctx.Logger(), []block.Lane{mevLane})
6477
s.Require().NoError(err)
6578

@@ -69,6 +82,7 @@ func (s *CheckTxTestSuite) TestCheckTxMempoolParity() {
6982
ba := &baseApp{
7083
s.Ctx,
7184
}
85+
7286
mevLaneHandler := checktx.NewMEVCheckTxHandler(
7387
ba,
7488
cacheDecoder.TxDecoder(),
@@ -82,6 +96,7 @@ func (s *CheckTxTestSuite) TestCheckTxMempoolParity() {
8296
mempool,
8397
cacheDecoder.TxDecoder(),
8498
mevLaneHandler,
99+
ba,
85100
).CheckTx()
86101

87102
// test that a bid can be successfully inserted to mev-lane on CheckTx
@@ -99,6 +114,36 @@ func (s *CheckTxTestSuite) TestCheckTxMempoolParity() {
99114
s.Require().True(mevLane.Contains(bidTx))
100115
})
101116

117+
// test that a bid will fail to be inserted as it is too large
118+
s.Run("test bid insertion failure on CheckTx - too large", func() {
119+
txBz, err := s.EncCfg.TxConfig.TxEncoder()(hugeBidTx)
120+
s.Require().NoError(err)
121+
122+
// check tx
123+
res, err := handler(&cometabci.RequestCheckTx{Tx: txBz, Type: cometabci.CheckTxType_New})
124+
s.Require().NoError(err)
125+
126+
s.Require().Equal(uint32(1), res.Code)
127+
128+
// check that the mev-lane does not contain the bid
129+
s.Require().False(mevLane.Contains(bidTx))
130+
})
131+
132+
// test that a bid can be successfully inserted to mev-lane on CheckTx
133+
s.Run("test bid insertion on CheckTx", func() {
134+
txBz, err := s.EncCfg.TxConfig.TxEncoder()(bidTx)
135+
s.Require().NoError(err)
136+
137+
// check tx
138+
res, err := handler(&cometabci.RequestCheckTx{Tx: txBz, Type: cometabci.CheckTxType_New})
139+
s.Require().NoError(err)
140+
141+
s.Require().Equal(uint32(0), res.Code)
142+
143+
// check that the mev-lane contains the bid
144+
s.Require().True(mevLane.Contains(bidTx))
145+
})
146+
102147
// test that a bid-tx (not in mev-lane) can be removed from the mempool on ReCheck
103148
s.Run("test bid removal on ReCheckTx", func() {
104149
// assert that the mev-lane does not contain the bidTx2
@@ -128,13 +173,17 @@ func (s *CheckTxTestSuite) TestRemovalOnRecheckTx() {
128173
)
129174
s.Require().NoError(err)
130175

131-
mevLane := s.InitLane(math.LegacyOneDec(), nil)
176+
mevLane := s.InitLane(math.LegacyOneDec(), nil, true)
132177
mempool, err := block.NewLanedMempool(s.Ctx.Logger(), []block.Lane{mevLane})
133178
s.Require().NoError(err)
134179

135180
cacheDecoder, err := utils.NewDefaultCacheTxDecoder(s.EncCfg.TxConfig.TxDecoder())
136181
s.Require().NoError(err)
137182

183+
ba := &baseApp{
184+
s.Ctx,
185+
}
186+
138187
handler := checktx.NewMempoolParityCheckTx(
139188
s.Ctx.Logger(),
140189
mempool,
@@ -143,6 +192,7 @@ func (s *CheckTxTestSuite) TestRemovalOnRecheckTx() {
143192
// always fail
144193
return &cometabci.ResponseCheckTx{Code: 1}, nil
145194
},
195+
ba,
146196
).CheckTx()
147197

148198
s.Run("tx is removed on check-tx failure when re-check", func() {
@@ -169,11 +219,16 @@ func (s *CheckTxTestSuite) TestMempoolParityCheckTx() {
169219
cacheDecoder, err := utils.NewDefaultCacheTxDecoder(s.EncCfg.TxConfig.TxDecoder())
170220
s.Require().NoError(err)
171221

222+
ba := &baseApp{
223+
s.Ctx,
224+
}
225+
172226
handler := checktx.NewMempoolParityCheckTx(
173227
s.Ctx.Logger(),
174228
nil,
175229
cacheDecoder.TxDecoder(),
176230
nil,
231+
ba,
177232
)
178233

179234
res, err := handler.CheckTx()(&cometabci.RequestCheckTx{Tx: []byte("invalid-tx")})
@@ -186,7 +241,7 @@ func (s *CheckTxTestSuite) TestMempoolParityCheckTx() {
186241
func (s *CheckTxTestSuite) TestMEVCheckTxHandler() {
187242
txs := map[sdk.Tx]bool{}
188243

189-
mevLane := s.InitLane(math.LegacyOneDec(), txs)
244+
mevLane := s.InitLane(math.LegacyOneDec(), txs, true)
190245
mempool, err := block.NewLanedMempool(s.Ctx.Logger(), []block.Lane{mevLane})
191246
s.Require().NoError(err)
192247

@@ -222,6 +277,7 @@ func (s *CheckTxTestSuite) TestMEVCheckTxHandler() {
222277
mempool,
223278
cacheDecoder.TxDecoder(),
224279
mevLaneHandler,
280+
ba,
225281
).CheckTx()
226282

227283
// test that a normal tx can be successfully inserted to the mempool
@@ -287,7 +343,7 @@ func (s *CheckTxTestSuite) TestValidateBidTx() {
287343
invalidBidTx: true,
288344
}
289345

290-
mevLane := s.InitLane(math.LegacyOneDec(), txs)
346+
mevLane := s.InitLane(math.LegacyOneDec(), txs, true)
291347

292348
cacheDecoder, err := utils.NewDefaultCacheTxDecoder(s.EncCfg.TxConfig.TxDecoder())
293349
s.Require().NoError(err)
@@ -347,7 +403,7 @@ func (ba *baseApp) CommitMultiStore() storetypes.CommitMultiStore {
347403

348404
// CheckTx is baseapp's CheckTx method that checks the validity of a
349405
// transaction.
350-
func (baseApp) CheckTx(_ *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) {
406+
func (ba *baseApp) CheckTx(_ *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) {
351407
return nil, fmt.Errorf("not implemented")
352408
}
353409

@@ -362,8 +418,17 @@ func (ba *baseApp) LastBlockHeight() int64 {
362418
}
363419

364420
// GetConsensusParams is utilized to retrieve the consensus params.
365-
func (baseApp) GetConsensusParams(ctx sdk.Context) cmtproto.ConsensusParams {
366-
return ctx.ConsensusParams()
421+
func (ba *baseApp) GetConsensusParams(_ sdk.Context) cmtproto.ConsensusParams {
422+
return cmtproto.ConsensusParams{
423+
Block: &cmtproto.BlockParams{
424+
MaxBytes: 10000,
425+
MaxGas: 10000,
426+
},
427+
Evidence: nil,
428+
Validator: nil,
429+
Version: nil,
430+
Abci: nil,
431+
}
367432
}
368433

369434
// ChainID is utilized to retrieve the chain ID.

abci/checktx/mempool_parity_check_tx.go

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package checktx
33
import (
44
"fmt"
55

6+
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
7+
68
"cosmossdk.io/log"
79

810
cmtabci "github.com/cometbft/cometbft/abci/types"
@@ -26,6 +28,10 @@ type MempoolParityCheckTx struct {
2628

2729
// checkTxHandler to wrap
2830
checkTxHandler CheckTx
31+
32+
// baseApp is utilized to retrieve the latest committed state and to call
33+
// baseapp's CheckTx method.
34+
baseApp BaseApp
2935
}
3036

3137
// NewMempoolParityCheckTx returns a new MempoolParityCheckTx handler.
@@ -34,12 +40,14 @@ func NewMempoolParityCheckTx(
3440
mempl block.Mempool,
3541
txDecoder sdk.TxDecoder,
3642
checkTxHandler CheckTx,
43+
baseApp BaseApp,
3744
) MempoolParityCheckTx {
3845
return MempoolParityCheckTx{
3946
logger: logger,
4047
mempl: mempl,
4148
txDecoder: txDecoder,
4249
checkTxHandler: checkTxHandler,
50+
baseApp: baseApp,
4351
}
4452
}
4553

@@ -79,29 +87,119 @@ func (m MempoolParityCheckTx) CheckTx() CheckTx {
7987
), nil
8088
}
8189

82-
// run the checkTxHandler
83-
res, checkTxError := m.checkTxHandler(req)
84-
85-
// if re-check fails for a transaction, we'll need to explicitly purge the tx from
86-
// the app-side mempool
87-
if isInvalidCheckTxExecution(res, checkTxError) && isReCheck {
88-
// check if the tx exists first
89-
if txInMempool {
90+
// prepare cleanup closure to remove tx if marked
91+
removeTx := false
92+
defer func() {
93+
if removeTx {
9094
// remove the tx
9195
if err := m.mempl.Remove(tx); err != nil {
9296
m.logger.Debug(
9397
"failed to remove tx from app-side mempool when purging for re-check failure",
9498
"removal-err", err,
95-
"check-tx-err", checkTxError,
9699
)
97100
}
98101
}
102+
}()
103+
104+
// run the checkTxHandler
105+
res, checkTxError := m.checkTxHandler(req)
106+
// if re-check fails for a transaction, we'll need to explicitly purge the tx from
107+
// the app-side mempool
108+
if isInvalidCheckTxExecution(res, checkTxError) && isReCheck && txInMempool {
109+
removeTx = true
110+
}
111+
112+
sdkCtx := m.GetContextForTx(req)
113+
lane, err := m.matchLane(sdkCtx, tx)
114+
if err != nil {
115+
if isReCheck && txInMempool {
116+
removeTx = true
117+
}
118+
119+
m.logger.Debug("failed to match lane", "lane", lane, "err", err)
120+
return sdkerrors.ResponseCheckTxWithEvents(
121+
err,
122+
0,
123+
0,
124+
nil,
125+
false,
126+
), nil
127+
}
128+
129+
consensusParams := sdkCtx.ConsensusParams()
130+
laneSize := lane.GetMaxBlockSpace().MulInt64(consensusParams.GetBlock().GetMaxBytes()).TruncateInt64()
131+
132+
txSize := int64(len(req.Tx))
133+
if txSize > laneSize {
134+
if isReCheck && txInMempool {
135+
removeTx = true
136+
}
137+
138+
m.logger.Debug(
139+
"tx size exceeds max block bytes",
140+
"tx", tx,
141+
"tx size", txSize,
142+
"max bytes", laneSize,
143+
)
144+
145+
return sdkerrors.ResponseCheckTxWithEvents(
146+
fmt.Errorf("tx size exceeds max bytes for lane %s", lane.Name()),
147+
0,
148+
0,
149+
nil,
150+
false,
151+
), nil
99152
}
100153

101154
return res, checkTxError
102155
}
103156
}
104157

158+
// matchLane returns a Lane if the given tx matches the Lane.
159+
func (m MempoolParityCheckTx) matchLane(ctx sdk.Context, tx sdk.Tx) (block.Lane, error) {
160+
var lane block.Lane
161+
// find corresponding lane for this tx
162+
for _, l := range m.mempl.Registry() {
163+
if l.Match(ctx, tx) {
164+
lane = l
165+
break
166+
}
167+
}
168+
169+
if lane == nil {
170+
m.logger.Debug(
171+
"failed match tx to lane",
172+
"tx", tx,
173+
)
174+
175+
return nil, fmt.Errorf("failed match tx to lane")
176+
}
177+
178+
return lane, nil
179+
}
180+
105181
func isInvalidCheckTxExecution(resp *cmtabci.ResponseCheckTx, checkTxErr error) bool {
106182
return resp == nil || resp.Code != 0 || checkTxErr != nil
107183
}
184+
185+
// GetContextForTx is returns the latest committed state and sets the context given
186+
// the checkTx request.
187+
func (m MempoolParityCheckTx) GetContextForTx(req *cmtabci.RequestCheckTx) sdk.Context {
188+
// Retrieve the commit multi-store which is used to retrieve the latest committed state.
189+
ms := m.baseApp.CommitMultiStore().CacheMultiStore()
190+
191+
// Create a new context based off of the latest committed state.
192+
header := cmtproto.Header{
193+
Height: m.baseApp.LastBlockHeight(),
194+
ChainID: m.baseApp.ChainID(),
195+
}
196+
ctx, _ := sdk.NewContext(ms, header, true, m.baseApp.Logger()).CacheContext()
197+
198+
// Set the remaining important context values.
199+
ctx = ctx.
200+
WithTxBytes(req.Tx).
201+
WithEventManager(sdk.NewEventManager()).
202+
WithConsensusParams(m.baseApp.GetConsensusParams(ctx))
203+
204+
return ctx
205+
}

abci/checktx/mev_check_tx.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"github.com/skip-mev/block-sdk/v2/x/auction/types"
1818
)
1919

20-
// MevCheckTxHandler is a wrapper around baseapp's CheckTx method that allows us to
20+
// MEVCheckTxHandler is a wrapper around baseapp's CheckTx method that allows us to
2121
// verify bid transactions against the latest committed state. All other transactions
2222
// are executed normally using base app's CheckTx. This defines all of the
2323
// dependencies that are required to verify a bid transaction.
@@ -69,7 +69,7 @@ type BaseApp interface {
6969
ChainID() string
7070
}
7171

72-
// NewCheckTxHandler constructs a new CheckTxHandler instance. This method fails if the given LanedMempool does not have a lane
72+
// NewMEVCheckTxHandler constructs a new CheckTxHandler instance. This method fails if the given LanedMempool does not have a lane
7373
// adhering to the MevLaneI interface
7474
func NewMEVCheckTxHandler(
7575
baseApp BaseApp,
@@ -87,7 +87,7 @@ func NewMEVCheckTxHandler(
8787
}
8888
}
8989

90-
// CheckTxHandler is a wrapper around baseapp's CheckTx method that allows us to
90+
// CheckTx is a wrapper around baseapp's CheckTx method that allows us to
9191
// verify bid transactions against the latest committed state. All other transactions
9292
// are executed normally. We must verify each bid tx and all of its bundled transactions
9393
// before we can insert it into the mempool against the latest commit state because

0 commit comments

Comments
 (0)