diff --git a/Makefile b/Makefile index 8155404..398874e 100644 --- a/Makefile +++ b/Makefile @@ -134,7 +134,7 @@ test-unit: use-main @go test -v -race $(shell go list ./... | grep -v tests/) test-integration: tidy - @go test -v -race ./tests/integration + @go test -v -race ./tests/integration/... test-cover: tidy @echo Running unit tests and creating coverage report... diff --git a/abci/checktx/check_tx.go b/abci/checktx/check_tx.go new file mode 100644 index 0000000..df8cfe3 --- /dev/null +++ b/abci/checktx/check_tx.go @@ -0,0 +1,11 @@ +package checktx + +import ( + cometabci "github.com/cometbft/cometbft/abci/types" +) + +type ( + // CheckTx is baseapp's CheckTx method that checks the validity of a + // transaction. + CheckTx func(req *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) +) diff --git a/abci/checktx/check_tx_test.go b/abci/checktx/check_tx_test.go new file mode 100644 index 0000000..f463e3c --- /dev/null +++ b/abci/checktx/check_tx_test.go @@ -0,0 +1,328 @@ +package checktx_test + +import ( + "fmt" + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/math" + "cosmossdk.io/store" + storetypes "cosmossdk.io/store/types" + + cometabci "github.com/cometbft/cometbft/abci/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + db "github.com/cosmos/cosmos-db" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + "github.com/skip-mev/block-sdk/abci/checktx" + "github.com/skip-mev/block-sdk/block" + "github.com/skip-mev/block-sdk/lanes/mev" + mevlanetestutils "github.com/skip-mev/block-sdk/lanes/mev/testutils" + "github.com/skip-mev/block-sdk/testutils" + auctiontypes "github.com/skip-mev/block-sdk/x/auction/types" + blocksdktypes "github.com/skip-mev/block-sdk/x/blocksdk/types" +) + +type CheckTxTestSuite struct { + mevlanetestutils.MEVLaneTestSuiteBase +} + +func TestCheckTxTestSuite(t *testing.T) { + suite.Run(t, new(CheckTxTestSuite)) +} + +func (s *CheckTxTestSuite) TestCheckTxMempoolParity() { + bidTx, _, err := testutils.CreateAuctionTx( + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), + 0, + 0, + nil, + 100, + ) + s.Require().NoError(err) + + // create a tx that should not be inserted in the mev-lane + bidTx2, _, err := testutils.CreateAuctionTx( + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), + 1, + 0, + nil, + 100, + ) + s.Require().NoError(err) + + txs := map[sdk.Tx]bool{ + bidTx: true, + } + + mevLane := s.InitLane(math.LegacyOneDec(), txs) + mempool, err := block.NewLanedMempool(s.Ctx.Logger(), []block.Lane{mevLane}, moduleLaneFetcher{ + mevLane, + }) + s.Require().NoError(err) + + ba := &baseApp{ + s.Ctx, + } + mevLaneHandler := checktx.NewMEVCheckTxHandler( + ba, + s.EncCfg.TxConfig.TxDecoder(), + mevLane, + s.SetUpAnteHandler(txs), + ba.CheckTx, + ).CheckTx() + + handler := checktx.NewMempoolParityCheckTx( + s.Ctx.Logger(), + mempool, + s.EncCfg.TxConfig.TxDecoder(), + mevLaneHandler, + ).CheckTx() + + // test that a bid can be successfully inserted to mev-lane on CheckTx + s.Run("test bid insertion on CheckTx", func() { + txBz, err := s.EncCfg.TxConfig.TxEncoder()(bidTx) + s.Require().NoError(err) + + // check tx + res, err := handler(&cometabci.RequestCheckTx{Tx: txBz, Type: cometabci.CheckTxType_New}) + s.Require().NoError(err) + + s.Require().Equal(uint32(0), res.Code) + + // check that the mev-lane contains the bid + s.Require().True(mevLane.Contains(bidTx)) + }) + + // test that a bid-tx (not in mev-lane) can be removed from the mempool on ReCheck + s.Run("test bid removal on ReCheckTx", func() { + // assert that the mev-lane does not contain the bidTx2 + s.Require().False(mevLane.Contains(bidTx2)) + + // check tx + txBz, err := s.EncCfg.TxConfig.TxEncoder()(bidTx2) + s.Require().NoError(err) + + res, err := handler(&cometabci.RequestCheckTx{Tx: txBz, Type: cometabci.CheckTxType_Recheck}) + s.Require().NoError(err) + + s.Require().Equal(uint32(1), res.Code) + }) +} + +func (s *CheckTxTestSuite) TestMempoolParityCheckTx() { + s.Run("tx fails tx-decoding", func() { + handler := checktx.NewMempoolParityCheckTx( + s.Ctx.Logger(), + nil, + s.EncCfg.TxConfig.TxDecoder(), + nil, + ) + + res, err := handler.CheckTx()(&cometabci.RequestCheckTx{Tx: []byte("invalid-tx")}) + s.Require().NoError(err) + + s.Require().Equal(uint32(1), res.Code) + }) +} + +func (s *CheckTxTestSuite) TestMEVCheckTxHandler() { + txs := map[sdk.Tx]bool{} + + mevLane := s.InitLane(math.LegacyOneDec(), txs) + mempool, err := block.NewLanedMempool(s.Ctx.Logger(), []block.Lane{mevLane}, moduleLaneFetcher{ + mevLane, + }) + s.Require().NoError(err) + + ba := &baseApp{ + s.Ctx, + } + + acc := s.Accounts[0] + // create a tx that should not be inserted in the mev-lane + normalTx, err := testutils.CreateRandomTxBz(s.EncCfg.TxConfig, acc, 0, 1, 0, 0) + s.Require().NoError(err) + + var gotTx []byte + mevLaneHandler := checktx.NewMEVCheckTxHandler( + ba, + s.EncCfg.TxConfig.TxDecoder(), + mevLane, + s.SetUpAnteHandler(txs), + func(req *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) { + // expect the above free tx to be sent here + gotTx = req.Tx + return &cometabci.ResponseCheckTx{ + Code: uint32(0), + }, nil + }, + ).CheckTx() + + handler := checktx.NewMempoolParityCheckTx( + s.Ctx.Logger(), + mempool, + s.EncCfg.TxConfig.TxDecoder(), + mevLaneHandler, + ).CheckTx() + + // test that a normal tx can be successfully inserted to the mempool + s.Run("test non-mev tx insertion on CheckTx", func() { + res, err := handler(&cometabci.RequestCheckTx{Tx: normalTx, Type: cometabci.CheckTxType_New}) + s.Require().NoError(err) + + s.Require().Equal(uint32(0), res.Code) + s.Require().Equal(normalTx, gotTx) + }) +} + +func (s *CheckTxTestSuite) TestValidateBidTx() { + validBidTx, bundled, err := testutils.CreateAuctionTx( + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), + 0, + 0, + []testutils.Account{s.Accounts[0]}, + 100, + ) + s.Require().NoError(err) + + txBz, err := s.EncCfg.TxConfig.TxEncoder()(validBidTx) + s.Require().NoError(err) + + // create an invalid bid-tx (nested) + bidMsg := auctiontypes.NewMsgAuctionBid(s.Accounts[0].Address, sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), [][]byte{ + txBz, + }) + nestedBidTx, err := testutils.CreateTx( + s.EncCfg.TxConfig, + s.Accounts[0], + 0, + 0, + []sdk.Msg{bidMsg}, + ) + s.Require().NoError(err) + + // create an invalid bid-tx (signer invalid) + invalidBidMsg := auctiontypes.MsgAuctionBid{ + Bidder: "", + Bid: sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), + Transactions: nil, + } + invalidBidTx, err := testutils.CreateTx( + s.EncCfg.TxConfig, + s.Accounts[0], + 0, + 0, + []sdk.Msg{&invalidBidMsg}, + ) + s.Require().NoError(err) + + // create a tx that should not be inserted in the mev-lane + s.Require().NoError(err) + + txs := map[sdk.Tx]bool{ + validBidTx: true, + bundled[0]: true, + nestedBidTx: true, + invalidBidTx: true, + } + + mevLane := s.InitLane(math.LegacyOneDec(), txs) + + ba := &baseApp{ + s.Ctx, + } + mevLaneHandler := checktx.NewMEVCheckTxHandler( + ba, + s.EncCfg.TxConfig.TxDecoder(), + mevLane, + s.SetUpAnteHandler(txs), + ba.CheckTx, + ) + s.Run("expected bid-tx", func() { + bundledTx, err := s.EncCfg.TxConfig.TxEncoder()(bundled[0]) + s.Require().NoError(err) + + _, err = mevLaneHandler.ValidateBidTx(s.Ctx, validBidTx, &auctiontypes.BidInfo{ + Transactions: [][]byte{bundledTx}, + }) + s.Require().NoError(err) + }) + + s.Run("nested bid-tx", func() { + nestedBidTxBz, err := s.EncCfg.TxConfig.TxEncoder()(nestedBidTx) + s.Require().NoError(err) + + _, err = mevLaneHandler.ValidateBidTx(s.Ctx, nestedBidTx, &auctiontypes.BidInfo{ + Transactions: [][]byte{nestedBidTxBz}, + }) + s.Require().Error(err) + s.Require().Contains(err.Error(), "bundled tx cannot be a bid tx") + }) + + s.Run("invalid bid-tx", func() { + invalidBidTxBz, err := s.EncCfg.TxConfig.TxEncoder()(invalidBidTx) + s.Require().NoError(err) + + _, err = mevLaneHandler.ValidateBidTx(s.Ctx, invalidBidTx, &auctiontypes.BidInfo{ + Transactions: [][]byte{invalidBidTxBz}, + }) + s.Require().Error(err) + s.Require().Contains(err.Error(), "failed to get bid info") + }) +} + +type baseApp struct { + ctx sdk.Context +} + +// CommitMultiStore is utilized to retrieve the latest committed state. +func (ba *baseApp) CommitMultiStore() storetypes.CommitMultiStore { + db := db.NewMemDB() + return store.NewCommitMultiStore(db, ba.ctx.Logger(), nil) +} + +// CheckTx is baseapp's CheckTx method that checks the validity of a +// transaction. +func (baseApp) CheckTx(_ *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) { + return nil, fmt.Errorf("not implemented") +} + +// Logger is utilized to log errors. +func (ba *baseApp) Logger() log.Logger { + return ba.ctx.Logger() +} + +// LastBlockHeight is utilized to retrieve the latest block height. +func (ba *baseApp) LastBlockHeight() int64 { + return ba.ctx.BlockHeight() +} + +// GetConsensusParams is utilized to retrieve the consensus params. +func (baseApp) GetConsensusParams(ctx sdk.Context) cmtproto.ConsensusParams { + return ctx.ConsensusParams() +} + +// ChainID is utilized to retrieve the chain ID. +func (ba *baseApp) ChainID() string { + return ba.ctx.ChainID() +} + +type moduleLaneFetcher struct { + lane *mev.MEVLane +} + +func (mlf moduleLaneFetcher) GetLane(sdk.Context, string) (lane blocksdktypes.Lane, err error) { + return blocksdktypes.Lane{}, nil +} + +func (mlf moduleLaneFetcher) GetLanes(sdk.Context) []blocksdktypes.Lane { + return nil +} diff --git a/abci/checktx/mempool_parity_check_tx.go b/abci/checktx/mempool_parity_check_tx.go new file mode 100644 index 0000000..5cfdaaa --- /dev/null +++ b/abci/checktx/mempool_parity_check_tx.go @@ -0,0 +1,77 @@ +package checktx + +import ( + "fmt" + + "cosmossdk.io/log" + + cmtabci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/skip-mev/block-sdk/block" +) + +// MempoolParityCheckTx is a CheckTx function that evicts txs that are not in the app-side mempool +// on ReCheckTx. This handler is used to enforce parity in the app-side / comet mempools. +type MempoolParityCheckTx struct { + // logger + logger log.Logger + + // app side mempool interface + mempl block.Mempool + + // tx-decoder + txDecoder sdk.TxDecoder + + // checkTxHandler to wrap + checkTxHandler CheckTx +} + +// NewMempoolParityCheckTx returns a new MempoolParityCheckTx handler. +func NewMempoolParityCheckTx(logger log.Logger, mempl block.Mempool, txDecoder sdk.TxDecoder, checkTxHandler CheckTx) MempoolParityCheckTx { + return MempoolParityCheckTx{ + logger: logger, + mempl: mempl, + txDecoder: txDecoder, + checkTxHandler: checkTxHandler, + } +} + +// CheckTx returns a CheckTx handler that wraps a given CheckTx handler and evicts txs that are not +// in the app-side mempool on ReCheckTx. +func (m MempoolParityCheckTx) CheckTx() CheckTx { + return func(req *cmtabci.RequestCheckTx) (*cmtabci.ResponseCheckTx, error) { + // decode tx + tx, err := m.txDecoder(req.Tx) + if err != nil { + return sdkerrors.ResponseCheckTxWithEvents( + fmt.Errorf("failed to decode tx: %w", err), + 0, + 0, + nil, + false, + ), nil + } + + // if the mode is ReCheck and the app's mempool does not contain the given tx, we fail + // immediately, to purge the tx from the comet mempool. + if req.Type == cmtabci.CheckTxType_Recheck && !m.mempl.Contains(tx) { + m.logger.Debug( + "tx from comet mempool not found in app-side mempool", + "tx", tx, + ) + + return sdkerrors.ResponseCheckTxWithEvents( + fmt.Errorf("tx from comet mempool not found in app-side mempool"), + 0, + 0, + nil, + false, + ), nil + } + + // run the checkTxHandler + return m.checkTxHandler(req) + } +} diff --git a/lanes/mev/check_tx.go b/abci/checktx/mev_check_tx.go similarity index 68% rename from lanes/mev/check_tx.go rename to abci/checktx/mev_check_tx.go index 1d530a5..56a9703 100644 --- a/lanes/mev/check_tx.go +++ b/abci/checktx/mev_check_tx.go @@ -1,81 +1,89 @@ -package mev +package checktx import ( + "context" "fmt" - log "cosmossdk.io/log" - storetypes "cosmossdk.io/store/types" cometabci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + + "github.com/skip-mev/block-sdk/block" + mevlane "github.com/skip-mev/block-sdk/lanes/mev" "github.com/skip-mev/block-sdk/x/auction/types" ) -type ( - // CheckTxHandler is a wrapper around baseapp's CheckTx method that allows us to - // verify bid transactions against the latest committed state. All other transactions - // are executed normally using base app's CheckTx. This defines all of the - // dependencies that are required to verify a bid transaction. - CheckTxHandler struct { - // baseApp is utilized to retrieve the latest committed state and to call - // baseapp's CheckTx method. - baseApp BaseApp +// MevCheckTxHandler is a wrapper around baseapp's CheckTx method that allows us to +// verify bid transactions against the latest committed state. All other transactions +// are executed normally using base app's CheckTx. This defines all of the +// dependencies that are required to verify a bid transaction. +type MEVCheckTxHandler struct { + // baseApp is utilized to retrieve the latest committed state and to call + // baseapp's CheckTx method. + baseApp BaseApp - // txDecoder is utilized to decode transactions to determine if they are - // bid transactions. - txDecoder sdk.TxDecoder + // txDecoder is utilized to decode transactions to determine if they are + // bid transactions. + txDecoder sdk.TxDecoder - // MEVLane is utilized to retrieve the bid info of a transaction and to - // insert a bid transaction into the application-side mempool. - mevLane MEVLaneI + // MEVLane is utilized to retrieve the bid info of a transaction and to + // insert a bid transaction into the application-side mempool. + mevLane MEVLaneI - // anteHandler is utilized to verify the bid transaction against the latest - // committed state. - anteHandler sdk.AnteHandler - } + // anteHandler is utilized to verify the bid transaction against the latest + // committed state. + anteHandler sdk.AnteHandler - // CheckTx is baseapp's CheckTx method that checks the validity of a - // transaction. - CheckTx func(req *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) + // checkTxHandler is the wrapped CheckTx handler that is used to execute all non-bid txs + checkTxHandler CheckTx +} - // BaseApp is an interface that allows us to call baseapp's CheckTx method - // as well as retrieve the latest committed state. - BaseApp interface { - // CommitMultiStore is utilized to retrieve the latest committed state. - CommitMultiStore() storetypes.CommitMultiStore +// MEVLaneI defines the interface for the mev auction lane. This interface +// is utilized by both the x/auction module and the checkTx handler. +type MEVLaneI interface { + block.Lane + mevlane.Factory + GetTopAuctionTx(ctx context.Context) sdk.Tx +} - // CheckTx is baseapp's CheckTx method that checks the validity of a - // transaction. - CheckTx(req *cometabci.RequestCheckTx) (*cometabci.ResponseCheckTx, error) +// BaseApp is an interface that allows us to call baseapp's CheckTx method +// as well as retrieve the latest committed state. +type BaseApp interface { + // CommitMultiStore is utilized to retrieve the latest committed state. + CommitMultiStore() storetypes.CommitMultiStore - // Logger is utilized to log errors. - Logger() log.Logger + // Logger is utilized to log errors. + Logger() log.Logger - // LastBlockHeight is utilized to retrieve the latest block height. - LastBlockHeight() int64 + // LastBlockHeight is utilized to retrieve the latest block height. + LastBlockHeight() int64 - // GetConsensusParams is utilized to retrieve the consensus params. - GetConsensusParams(ctx sdk.Context) cmtproto.ConsensusParams + // GetConsensusParams is utilized to retrieve the consensus params. + GetConsensusParams(ctx sdk.Context) cmtproto.ConsensusParams - // ChainID is utilized to retrieve the chain ID. - ChainID() string - } -) + // ChainID is utilized to retrieve the chain ID. + ChainID() string +} -// NewCheckTxHandler constructs a new CheckTxHandler instance. -func NewCheckTxHandler( +// NewCheckTxHandler constructs a new CheckTxHandler instance. This method fails if the given LanedMempool does not have a lane +// adhering to the MevLaneI interface +func NewMEVCheckTxHandler( baseApp BaseApp, txDecoder sdk.TxDecoder, mevLane MEVLaneI, anteHandler sdk.AnteHandler, -) *CheckTxHandler { - return &CheckTxHandler{ - baseApp: baseApp, - txDecoder: txDecoder, - mevLane: mevLane, - anteHandler: anteHandler, + checkTxHandler CheckTx, +) *MEVCheckTxHandler { + return &MEVCheckTxHandler{ + baseApp: baseApp, + txDecoder: txDecoder, + mevLane: mevLane, + anteHandler: anteHandler, + checkTxHandler: checkTxHandler, } } @@ -85,7 +93,7 @@ func NewCheckTxHandler( // before we can insert it into the mempool against the latest commit state because // otherwise the auction can be griefed. No state changes are applied to the state // during this process. -func (handler *CheckTxHandler) CheckTx() CheckTx { +func (handler *MEVCheckTxHandler) CheckTx() CheckTx { return func(req *cometabci.RequestCheckTx) (resp *cometabci.ResponseCheckTx, err error) { defer func() { if rec := recover(); rec != nil { @@ -140,7 +148,7 @@ func (handler *CheckTxHandler) CheckTx() CheckTx { // If this is not a bid transaction, we just execute it normally. if bidInfo == nil { - resp, err := handler.baseApp.CheckTx(req) + resp, err := handler.checkTxHandler(req) if err != nil { handler.baseApp.Logger().Info( "failed to execute check tx", @@ -222,7 +230,7 @@ func (handler *CheckTxHandler) CheckTx() CheckTx { } // ValidateBidTx is utilized to verify the bid transaction against the latest committed state. -func (handler *CheckTxHandler) ValidateBidTx(ctx sdk.Context, bidTx sdk.Tx, bidInfo *types.BidInfo) (sdk.GasInfo, error) { +func (handler *MEVCheckTxHandler) ValidateBidTx(ctx sdk.Context, bidTx sdk.Tx, bidInfo *types.BidInfo) (sdk.GasInfo, error) { // Verify the bid transaction. ctx, err := handler.anteHandler(ctx, bidTx, false) if err != nil { @@ -243,7 +251,11 @@ func (handler *CheckTxHandler) ValidateBidTx(ctx sdk.Context, bidTx sdk.Tx, bidI } // bid txs cannot be included in bundled txs - bidInfo, _ := handler.mevLane.GetAuctionBidInfo(bundledTx) + bidInfo, err := handler.mevLane.GetAuctionBidInfo(bundledTx) + if err != nil { + return gasInfo, fmt.Errorf("invalid bid tx; failed to get bid info: %w", err) + } + if bidInfo != nil { return gasInfo, fmt.Errorf("invalid bid tx; bundled tx cannot be a bid tx") } @@ -258,7 +270,7 @@ func (handler *CheckTxHandler) ValidateBidTx(ctx sdk.Context, bidTx sdk.Tx, bidI // GetContextForBidTx is returns the latest committed state and sets the context given // the checkTx request. -func (handler *CheckTxHandler) GetContextForBidTx(req *cometabci.RequestCheckTx) sdk.Context { +func (handler *MEVCheckTxHandler) GetContextForBidTx(req *cometabci.RequestCheckTx) sdk.Context { // Retrieve the commit multi-store which is used to retrieve the latest committed state. ms := handler.baseApp.CommitMultiStore().CacheMultiStore() diff --git a/go.mod b/go.mod index a08f8ed..2bcd580 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/huandu/skiplist v1.2.0 - github.com/skip-mev/chaintestutil v0.0.0-20231213172849-7c623445dde1 + github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.17.0 diff --git a/go.sum b/go.sum index 483f29d..6d0ce59 100644 --- a/go.sum +++ b/go.sum @@ -1223,8 +1223,8 @@ github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= -github.com/skip-mev/chaintestutil v0.0.0-20231213172849-7c623445dde1 h1:x1hie4oqAp0Ay0ijolPKaKVFAHXKuMulBir2RGe1oc0= -github.com/skip-mev/chaintestutil v0.0.0-20231213172849-7c623445dde1/go.mod h1:mcyq67cXQTzyhCg2LSBeFS+u7GzWng5xnTFfUAqIHn4= +github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4 h1:uX3mI+MRH4wPclt4MS2BAGKXxxOoKfxy384zbXb6MQc= +github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4/go.mod h1:o3naFS52DumeJLR6h+0YoMV09YvxOALaou9WZuSJOIg= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= diff --git a/lanes/mev/abci_test.go b/lanes/mev/abci_test.go index 32488f6..95680b9 100644 --- a/lanes/mev/abci_test.go +++ b/lanes/mev/abci_test.go @@ -13,13 +13,13 @@ import ( ) func (s *MEVTestSuite) TestPrepareLane() { - s.ctx = s.ctx.WithExecMode(sdk.ExecModePrepareProposal) + s.Ctx = s.Ctx.WithExecMode(sdk.ExecModePrepareProposal) s.Run("can prepare a lane with no txs in mempool", func() { - lane := s.initLane(math.LegacyOneDec(), nil) + lane := s.InitLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - proposal, err := lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err := lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(0, len(proposal.Txs)) s.Require().Equal(0, len(proposal.Info.TxsByLane)) @@ -29,9 +29,9 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Run("can prepare a lane with a single bid tx in mempool", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -40,12 +40,12 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().NoError(err) size := s.getTxSize(bidTx) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) - s.Require().NoError(lane.Insert(s.ctx, bidTx)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx)) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(1, len(proposal.Txs)) s.Require().Equal(1, len(proposal.Info.TxsByLane)) @@ -53,16 +53,16 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().Equal(uint64(100), proposal.Info.GasLimit) expectedProposal := []sdk.Tx{bidTx} - txBzs, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), expectedProposal) + txBzs, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), expectedProposal) s.Require().NoError(err) s.Require().Equal(txBzs[0], proposal.Txs[0]) }) s.Run("can prepare a lane with multiple bid txs where highest bid fails", func() { bidTx1, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -71,9 +71,9 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().NoError(err) bidTx2, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[1], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(200)), + s.EncCfg.TxConfig, + s.Accounts[1], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(200)), 0, 0, nil, @@ -81,13 +81,13 @@ func (s *MEVTestSuite) TestPrepareLane() { ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx1: true, bidTx2: false}) - s.Require().NoError(lane.Insert(s.ctx, bidTx1)) - s.Require().NoError(lane.Insert(s.ctx, bidTx2)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx1: true, bidTx2: false}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx1)) + s.Require().NoError(lane.Insert(s.Ctx, bidTx2)) proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(1, len(proposal.Txs)) s.Require().Equal(1, len(proposal.Info.TxsByLane)) @@ -95,16 +95,16 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().Equal(uint64(100), proposal.Info.GasLimit) expectedProposal := []sdk.Tx{bidTx1} - txBzs, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), expectedProposal) + txBzs, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), expectedProposal) s.Require().NoError(err) s.Require().Equal(txBzs[0], proposal.Txs[0]) }) s.Run("can prepare a lane with multiple bid txs where highest bid passes", func() { bidTx1, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -113,9 +113,9 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().NoError(err) bidTx2, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[1], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(200)), + s.EncCfg.TxConfig, + s.Accounts[1], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(200)), 0, 0, nil, @@ -123,13 +123,13 @@ func (s *MEVTestSuite) TestPrepareLane() { ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx1: false, bidTx2: true}) - s.Require().NoError(lane.Insert(s.ctx, bidTx1)) - s.Require().NoError(lane.Insert(s.ctx, bidTx2)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx1: false, bidTx2: true}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx1)) + s.Require().NoError(lane.Insert(s.Ctx, bidTx2)) proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(1, len(proposal.Txs)) s.Require().Equal(1, len(proposal.Info.TxsByLane)) @@ -137,29 +137,29 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().Equal(uint64(100), proposal.Info.GasLimit) expectedProposal := []sdk.Tx{bidTx2} - txBzs, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), expectedProposal) + txBzs, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), expectedProposal) s.Require().NoError(err) s.Require().Equal(txBzs[0], proposal.Txs[0]) }) s.Run("can build a proposal with bid tx that has a bundle", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - s.Require().NoError(lane.Insert(s.ctx, bidTx)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx)) proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(3, len(proposal.Txs)) s.Require().Equal(1, len(proposal.Info.TxsByLane)) @@ -168,29 +168,29 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().Equal(uint64(100), proposal.Info.GasLimit) expectedProposal := []sdk.Tx{bidTx, bundle[0], bundle[1]} - txBzs, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), expectedProposal) + txBzs, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), expectedProposal) s.Require().NoError(err) s.Require().Equal(txBzs, proposal.Txs) }) s.Run("can reject a bid that is too large", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(200)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(200)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - s.Require().NoError(lane.Insert(s.ctx, bidTx)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx)) proposal := proposals.NewProposal(log.NewNopLogger(), s.getTxSize(bidTx), 100000) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(0, len(proposal.Txs)) s.Require().Equal(0, len(proposal.Info.TxsByLane)) @@ -200,9 +200,9 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Run("can reject a bid that is too gas intensive", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(200)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(200)), 0, 0, nil, @@ -210,12 +210,12 @@ func (s *MEVTestSuite) TestPrepareLane() { ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) - s.Require().NoError(lane.Insert(s.ctx, bidTx)) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) + s.Require().NoError(lane.Insert(s.Ctx, bidTx)) proposal := proposals.NewProposal(log.NewNopLogger(), s.getTxSize(bidTx), 99) - proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) + proposal, err = lane.PrepareLane(s.Ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) s.Require().Equal(0, len(proposal.Txs)) s.Require().Equal(0, len(proposal.Info.TxsByLane)) @@ -225,44 +225,44 @@ func (s *MEVTestSuite) TestPrepareLane() { } func (s *MEVTestSuite) TestProcessLane() { - s.ctx = s.ctx.WithExecMode(sdk.ExecModeProcessProposal) + s.Ctx = s.Ctx.WithExecMode(sdk.ExecModeProcessProposal) s.Run("can process an empty proposal", func() { - lane := s.initLane(math.LegacyOneDec(), nil) + lane := s.InitLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, nil) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, nil) s.Require().NoError(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal, err = lane.ProcessLane(s.ctx, proposal, nil, block.NoOpProcessLanesHandler()) + proposal, err = lane.ProcessLane(s.Ctx, proposal, nil, block.NoOpProcessLanesHandler()) s.Require().NoError(err) s.Require().Equal(0, len(proposal.Txs)) }) s.Run("can process a proposal with tx that does not belong to this lane", func() { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 100) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 100) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), nil) + lane := s.InitLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, []sdk.Tx{tx}) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, []sdk.Tx{tx}) s.Require().NoError(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(1, len(remainingTxs)) - finalProposal, err := lane.ProcessLane(s.ctx, proposal, []sdk.Tx{tx}, block.NoOpProcessLanesHandler()) + finalProposal, err := lane.ProcessLane(s.Ctx, proposal, []sdk.Tx{tx}, block.NoOpProcessLanesHandler()) s.Require().NoError(err) s.Require().Equal(0, len(finalProposal.Txs)) }) s.Run("can process a proposal with bad bid tx", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -272,126 +272,126 @@ func (s *MEVTestSuite) TestProcessLane() { partialProposal := []sdk.Tx{bidTx} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().Error(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can process a proposal with a bad bundled tx", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0], bundle[1]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().Error(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can process a proposal with mismatching txs in bundle", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[1], bundle[0]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().Error(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can process a proposal with missing bundle tx", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().Error(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can process a valid proposal", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0], bundle[1]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().NoError(err) s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) }) s.Run("can process a valid proposal with a single bid with no bundle", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 0, 0, @@ -402,137 +402,137 @@ func (s *MEVTestSuite) TestProcessLane() { partialProposal := []sdk.Tx{bidTx} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().NoError(err) s.Require().Equal(1, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) }) s.Run("can reject a block proposal that exceeds its gas limit", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0], bundle[1]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().NoError(err) s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 99) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can reject a block proposal that exceeds its block size", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0], bundle[1]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().NoError(err) s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) s.Run("can accept a block proposal with bid and other txs", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) - otherTx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 100) + otherTx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 100) s.Require().NoError(err) partialProposal := []sdk.Tx{bidTx, bundle[0], bundle[1], otherTx} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().NoError(err) s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(1, len(remainingTxs)) s.Require().Equal(otherTx, remainingTxs[0]) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - proposal, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + proposal, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) s.Require().Len(proposal.Txs, 3) - encodedTxs, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), []sdk.Tx{bidTx, bundle[0], bundle[1]}) + encodedTxs, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), []sdk.Tx{bidTx, bundle[0], bundle[1]}) s.Require().NoError(err) s.Require().Equal(encodedTxs, proposal.Txs) }) s.Run("rejects a block where the bid tx is not the first tx", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) - otherTx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 100) + otherTx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 100) s.Require().NoError(err) partialProposal := []sdk.Tx{otherTx, bidTx, bundle[0], bundle[1]} - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.ctx, partialProposal) + txsFromLane, remainingTxs, err := mev.NewProposalHandler(lane.BaseLane, lane.Factory).ProcessLaneHandler()(s.Ctx, partialProposal) s.Require().Error(err) s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) - _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) + _, err = lane.ProcessLane(s.Ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) } func (s *MEVTestSuite) TestVerifyBidBasic() { - lane := s.initLane(math.LegacyOneDec(), nil) + lane := s.InitLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) @@ -540,9 +540,9 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { s.Run("can verify a bid with no bundled txs", func() { bidTx, expectedBundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -550,15 +550,15 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - bundle, err := handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + bundle, err := handler.VerifyBidBasic(s.Ctx, bidTx, proposal, limits) s.Require().NoError(err) s.compare(bundle, expectedBundle) }) s.Run("can reject a tx that is not a bid", func() { tx, err := testutils.CreateRandomTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], 0, 1, 0, @@ -566,15 +566,15 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - _, err = handler.VerifyBidBasic(s.ctx, tx, proposal, limits) + _, err = handler.VerifyBidBasic(s.Ctx, tx, proposal, limits) s.Require().Error(err) }) s.Run("can reject a bundle that is too gas intensive", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -582,18 +582,18 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.Ctx, bidTx, proposal, limits) s.Require().Error(err) }) s.Run("can reject a bundle that is too large", func() { bidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) @@ -602,15 +602,15 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { proposal := proposals.NewProposal(log.NewNopLogger(), size-1, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) - _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.Ctx, bidTx, proposal, limits) s.Require().Error(err) }) s.Run("can reject a bundle with malformed txs", func() { bidMsg, err := testutils.CreateMsgAuctionBid( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 3, ) @@ -619,15 +619,15 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { bidMsg.Transactions[2] = []byte("invalid") bidTx, err := testutils.CreateTx( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], 0, 0, []sdk.Msg{bidMsg}, ) s.Require().NoError(err) - _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.Ctx, bidTx, proposal, limits) s.Require().Error(err) }) } @@ -635,9 +635,9 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { func (s *MEVTestSuite) TestVerifyBidTx() { s.Run("can verify a valid bid", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -645,17 +645,17 @@ func (s *MEVTestSuite) TestVerifyBidTx() { ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) - s.Require().NoError(handler.VerifyBidTx(s.ctx, bidTx, bundle)) + s.Require().NoError(handler.VerifyBidTx(s.Ctx, bidTx, bundle)) }) s.Run("can reject a bid transaction", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -663,46 +663,46 @@ func (s *MEVTestSuite) TestVerifyBidTx() { ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) - s.Require().Error(handler.VerifyBidTx(s.ctx, bidTx, bundle)) + s.Require().Error(handler.VerifyBidTx(s.Ctx, bidTx, bundle)) }) s.Run("can reject a bid transaction with a bad bundle", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) - s.Require().Error(handler.VerifyBidTx(s.ctx, bidTx, bundle)) + s.Require().Error(handler.VerifyBidTx(s.Ctx, bidTx, bundle)) }) s.Run("can reject a bid transaction with a bundle that has another bid tx", func() { bidTx, bundle, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, - s.accounts[0:2], + s.Accounts[0:2], 100, ) s.Require().NoError(err) otherBidTx, _, err := testutils.CreateAuctionTx( - s.encCfg.TxConfig, - s.accounts[0], - sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)), + s.EncCfg.TxConfig, + s.Accounts[0], + sdk.NewCoin(s.GasTokenDenom, math.NewInt(100)), 0, 0, nil, @@ -711,9 +711,9 @@ func (s *MEVTestSuite) TestVerifyBidTx() { s.Require().NoError(err) bundle = append(bundle, otherBidTx) - lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true, otherBidTx: true}) + lane := s.InitLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true, otherBidTx: true}) handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) - s.Require().Error(handler.VerifyBidTx(s.ctx, bidTx, bundle)) + s.Require().Error(handler.VerifyBidTx(s.Ctx, bidTx, bundle)) }) } diff --git a/lanes/mev/factory_test.go b/lanes/mev/factory_test.go index 6102bc2..24f78f2 100644 --- a/lanes/mev/factory_test.go +++ b/lanes/mev/factory_test.go @@ -19,7 +19,7 @@ func (s *MEVTestSuite) TestIsAuctionTx() { { "normal sdk tx", func() sdk.Tx { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 2, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 2, 0, 0) s.Require().NoError(err) return tx }, @@ -29,13 +29,13 @@ func (s *MEVTestSuite) TestIsAuctionTx() { { "malformed auction bid tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - msgs := testutils.CreateRandomMsgs(s.accounts[0].Address, 2) + msgs := testutils.CreateRandomMsgs(s.Accounts[0].Address, 2) msgs = append(msgs, msgAuctionBid) - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -45,12 +45,12 @@ func (s *MEVTestSuite) TestIsAuctionTx() { { "valid auction bid tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -60,15 +60,15 @@ func (s *MEVTestSuite) TestIsAuctionTx() { { "tx with multiple MsgAuctionBid messages", func() sdk.Tx { - bid1, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + bid1, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - bid2, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 1, 2) + bid2, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 1, 2) s.Require().NoError(err) msgs := []sdk.Msg{bid1, bid2} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -81,7 +81,7 @@ func (s *MEVTestSuite) TestIsAuctionTx() { s.Run(tc.name, func() { tx := tc.createTx() - bidInfo, err := s.config.GetAuctionBidInfo(tx) + bidInfo, err := s.Config.GetAuctionBidInfo(tx) s.Require().Equal(tc.isAuctionTx, bidInfo != nil) if tc.expectedError { @@ -104,12 +104,12 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { "normal auction tx", func() sdk.Tx { tx, err := testutils.CreateAuctionTxWithSigners( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 1, 0, - s.accounts[0:1], + s.Accounts[0:1], ) s.Require().NoError(err) @@ -117,7 +117,7 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { }, []map[string]struct{}{ { - s.accounts[0].Address.String(): {}, + s.Accounts[0].Address.String(): {}, }, }, false, @@ -125,7 +125,7 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { { "normal sdk tx", func() sdk.Tx { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 10, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 10, 0, 0) s.Require().NoError(err) return tx @@ -137,12 +137,12 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { "multiple signers on auction tx", func() sdk.Tx { tx, err := testutils.CreateAuctionTxWithSigners( - s.encCfg.TxConfig, - s.accounts[0], + s.EncCfg.TxConfig, + s.Accounts[0], sdk.NewCoin("stake", math.NewInt(100)), 1, 0, - s.accounts[0:3], + s.Accounts[0:3], ) s.Require().NoError(err) @@ -150,13 +150,13 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { }, []map[string]struct{}{ { - s.accounts[0].Address.String(): {}, + s.Accounts[0].Address.String(): {}, }, { - s.accounts[1].Address.String(): {}, + s.Accounts[1].Address.String(): {}, }, { - s.accounts[2].Address.String(): {}, + s.Accounts[2].Address.String(): {}, }, }, false, @@ -167,7 +167,7 @@ func (s *MEVTestSuite) TestGetTransactionSigners() { s.Run(tc.name, func() { tx := tc.createTx() - bidInfo, _ := s.config.GetAuctionBidInfo(tx) + bidInfo, _ := s.Config.GetAuctionBidInfo(tx) if tc.expectedError { s.Require().Nil(bidInfo) } else { @@ -186,10 +186,10 @@ func (s *MEVTestSuite) TestWrapBundleTransaction() { { "normal sdk tx", func() (sdk.Tx, []byte) { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 0) s.Require().NoError(err) - bz, err := s.encCfg.TxConfig.TxEncoder()(tx) + bz, err := s.EncCfg.TxConfig.TxEncoder()(tx) s.Require().NoError(err) return tx, bz @@ -212,16 +212,16 @@ func (s *MEVTestSuite) TestWrapBundleTransaction() { s.Run(tc.name, func() { tx, bz := tc.createBundleTx() - wrappedTx, err := s.config.WrapBundleTransaction(bz) + wrappedTx, err := s.Config.WrapBundleTransaction(bz) if tc.expectedError { s.Require().Error(err) } else { s.Require().NoError(err) - txBytes, err := s.encCfg.TxConfig.TxEncoder()(tx) + txBytes, err := s.EncCfg.TxConfig.TxEncoder()(tx) s.Require().NoError(err) - wrappedTxBytes, err := s.encCfg.TxConfig.TxEncoder()(wrappedTx) + wrappedTxBytes, err := s.EncCfg.TxConfig.TxEncoder()(wrappedTx) s.Require().NoError(err) s.Require().Equal(txBytes, wrappedTxBytes) @@ -241,7 +241,7 @@ func (s *MEVTestSuite) TestGetBidder() { { "normal sdk tx", func() sdk.Tx { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 0) s.Require().NoError(err) return tx @@ -253,31 +253,31 @@ func (s *MEVTestSuite) TestGetBidder() { { "valid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, - s.accounts[0].Address.String(), + s.Accounts[0].Address.String(), false, true, }, { "invalid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - randomMsg := testutils.CreateRandomMsgs(s.accounts[0].Address, 1)[0] + randomMsg := testutils.CreateRandomMsgs(s.Accounts[0].Address, 1)[0] s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid, randomMsg} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -291,7 +291,7 @@ func (s *MEVTestSuite) TestGetBidder() { s.Run(tc.name, func() { tx := tc.createTx() - bidInfo, err := s.config.GetAuctionBidInfo(tx) + bidInfo, err := s.Config.GetAuctionBidInfo(tx) if tc.expectedError { s.Require().Error(err) } else { @@ -316,7 +316,7 @@ func (s *MEVTestSuite) TestGetBid() { { "normal sdk tx", func() sdk.Tx { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 0) s.Require().NoError(err) return tx @@ -328,12 +328,12 @@ func (s *MEVTestSuite) TestGetBid() { { "valid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -344,15 +344,15 @@ func (s *MEVTestSuite) TestGetBid() { { "invalid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - randomMsg := testutils.CreateRandomMsgs(s.accounts[0].Address, 1)[0] + randomMsg := testutils.CreateRandomMsgs(s.Accounts[0].Address, 1)[0] s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid, randomMsg} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx }, @@ -366,7 +366,7 @@ func (s *MEVTestSuite) TestGetBid() { s.Run(tc.name, func() { tx := tc.createTx() - bidInfo, err := s.config.GetAuctionBidInfo(tx) + bidInfo, err := s.Config.GetAuctionBidInfo(tx) if tc.expectedError { s.Require().Error(err) } else { @@ -390,7 +390,7 @@ func (s *MEVTestSuite) TestGetBundledTransactions() { { "normal sdk tx", func() (sdk.Tx, [][]byte) { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 0, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 0, 0) s.Require().NoError(err) return tx, nil @@ -401,12 +401,12 @@ func (s *MEVTestSuite) TestGetBundledTransactions() { { "valid auction tx", func() (sdk.Tx, [][]byte) { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx, msgAuctionBid.Transactions }, @@ -416,15 +416,15 @@ func (s *MEVTestSuite) TestGetBundledTransactions() { { "invalid auction tx", func() (sdk.Tx, [][]byte) { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - randomMsg := testutils.CreateRandomMsgs(s.accounts[0].Address, 1)[0] + randomMsg := testutils.CreateRandomMsgs(s.Accounts[0].Address, 1)[0] s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid, randomMsg} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 0, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 0, msgs) s.Require().NoError(err) return tx, nil }, @@ -437,7 +437,7 @@ func (s *MEVTestSuite) TestGetBundledTransactions() { s.Run(tc.name, func() { tx, expectedBundledTxs := tc.createTx() - bidInfo, err := s.config.GetAuctionBidInfo(tx) + bidInfo, err := s.Config.GetAuctionBidInfo(tx) if tc.expectedError { s.Require().Error(err) } else { @@ -462,7 +462,7 @@ func (s *MEVTestSuite) TestGetTimeout() { { "normal sdk tx", func() sdk.Tx { - tx, err := testutils.CreateRandomTx(s.encCfg.TxConfig, s.accounts[0], 0, 1, 1, 0) + tx, err := testutils.CreateRandomTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 1, 1, 0) s.Require().NoError(err) return tx @@ -474,12 +474,12 @@ func (s *MEVTestSuite) TestGetTimeout() { { "valid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 10, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 10, msgs) s.Require().NoError(err) return tx }, @@ -490,15 +490,15 @@ func (s *MEVTestSuite) TestGetTimeout() { { "invalid auction tx", func() sdk.Tx { - msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.encCfg.TxConfig, s.accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) + msgAuctionBid, err := testutils.CreateMsgAuctionBid(s.EncCfg.TxConfig, s.Accounts[0], sdk.NewInt64Coin("stake", 100), 0, 2) s.Require().NoError(err) - randomMsg := testutils.CreateRandomMsgs(s.accounts[0].Address, 1)[0] + randomMsg := testutils.CreateRandomMsgs(s.Accounts[0].Address, 1)[0] s.Require().NoError(err) msgs := []sdk.Msg{msgAuctionBid, randomMsg} - tx, err := testutils.CreateTx(s.encCfg.TxConfig, s.accounts[0], 0, 10, msgs) + tx, err := testutils.CreateTx(s.EncCfg.TxConfig, s.Accounts[0], 0, 10, msgs) s.Require().NoError(err) return tx }, @@ -512,7 +512,7 @@ func (s *MEVTestSuite) TestGetTimeout() { s.Run(tc.name, func() { tx := tc.createTx() - bidInfo, err := s.config.GetAuctionBidInfo(tx) + bidInfo, err := s.Config.GetAuctionBidInfo(tx) if tc.expectedError { s.Require().Error(err) } else { diff --git a/lanes/mev/lane.go b/lanes/mev/lane.go index f517226..485cbb9 100644 --- a/lanes/mev/lane.go +++ b/lanes/mev/lane.go @@ -1,11 +1,6 @@ package mev import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/skip-mev/block-sdk/block" "github.com/skip-mev/block-sdk/block/base" ) @@ -14,8 +9,6 @@ const ( LaneName = "mev" ) -var _ MEVLaneI = (*MEVLane)(nil) - // MEVLane defines a MEV (Maximal Extracted Value) auction lane. The MEV auction lane // hosts transactions that want to bid for inclusion at the top of the next block. // The MEV auction lane stores bid transactions that are sorted by their bid price. @@ -23,14 +16,6 @@ var _ MEVLaneI = (*MEVLane)(nil) // The bundled transactions of the selected bid transaction are also included in the // next block. type ( - // MEVLaneI defines the interface for the mev auction lane. This interface - // is utilized by both the x/auction module and the checkTx handler. - MEVLaneI interface { //nolint - block.Lane - Factory - GetTopAuctionTx(ctx context.Context) sdk.Tx - } - MEVLane struct { //nolint *base.BaseLane diff --git a/lanes/mev/mev_test.go b/lanes/mev/mev_test.go index ea500c2..a04487e 100644 --- a/lanes/mev/mev_test.go +++ b/lanes/mev/mev_test.go @@ -1,117 +1,35 @@ package mev_test import ( - "crypto/sha256" - "encoding/hex" - "fmt" - "math/rand" "testing" - "time" - "cosmossdk.io/log" - "cosmossdk.io/math" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter" - "github.com/skip-mev/block-sdk/block/base" "github.com/skip-mev/block-sdk/block/utils" - "github.com/skip-mev/block-sdk/lanes/mev" - testutils "github.com/skip-mev/block-sdk/testutils" + "github.com/skip-mev/block-sdk/lanes/mev/testutils" ) type MEVTestSuite struct { - suite.Suite - - encCfg testutils.EncodingConfig - config mev.Factory - ctx sdk.Context - accounts []testutils.Account - gasTokenDenom string + testutils.MEVLaneTestSuiteBase } func TestMEVTestSuite(t *testing.T) { suite.Run(t, new(MEVTestSuite)) } -func (s *MEVTestSuite) SetupTest() { - // Init encoding config - s.encCfg = testutils.CreateTestEncodingConfig() - s.config = mev.NewDefaultAuctionFactory(s.encCfg.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()) - testCtx := testutil.DefaultContextWithDB(s.T(), storetypes.NewKVStoreKey("test"), storetypes.NewTransientStoreKey("transient_test")) - s.ctx = testCtx.Ctx.WithExecMode(sdk.ExecModePrepareProposal) - s.ctx = s.ctx.WithBlockHeight(1) - - // Init accounts - random := rand.New(rand.NewSource(time.Now().Unix())) - s.accounts = testutils.RandomAccounts(random, 10) - s.gasTokenDenom = "stake" -} - -func (s *MEVTestSuite) initLane( - maxBlockSpace math.LegacyDec, - expectedExecution map[sdk.Tx]bool, -) *mev.MEVLane { - config := base.NewLaneConfig( - log.NewNopLogger(), - s.encCfg.TxConfig.TxEncoder(), - s.encCfg.TxConfig.TxDecoder(), - s.setUpAnteHandler(expectedExecution), - signer_extraction.NewDefaultAdapter(), - maxBlockSpace, - ) - - factory := mev.NewDefaultAuctionFactory(s.encCfg.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()) - return mev.NewMEVLane(config, factory, factory.MatchHandler()) -} - -func (s *MEVTestSuite) setUpAnteHandler(expectedExecution map[sdk.Tx]bool) sdk.AnteHandler { - txCache := make(map[string]bool) - for tx, pass := range expectedExecution { - bz, err := s.encCfg.TxConfig.TxEncoder()(tx) - s.Require().NoError(err) - - hash := sha256.Sum256(bz) - hashStr := hex.EncodeToString(hash[:]) - txCache[hashStr] = pass - } - - anteHandler := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { - bz, err := s.encCfg.TxConfig.TxEncoder()(tx) - s.Require().NoError(err) - - hash := sha256.Sum256(bz) - hashStr := hex.EncodeToString(hash[:]) - - pass, found := txCache[hashStr] - if !found { - return ctx, fmt.Errorf("tx not found") - } - - if pass { - return ctx, nil - } - - return ctx, fmt.Errorf("tx failed") - } - - return anteHandler -} - func (s *MEVTestSuite) getTxSize(tx sdk.Tx) int64 { - txBz, err := s.encCfg.TxConfig.TxEncoder()(tx) + txBz, err := s.EncCfg.TxConfig.TxEncoder()(tx) s.Require().NoError(err) return int64(len(txBz)) } func (s *MEVTestSuite) compare(first, second []sdk.Tx) { - firstBytes, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), first) + firstBytes, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), first) s.Require().NoError(err) - secondBytes, err := utils.GetEncodedTxs(s.encCfg.TxConfig.TxEncoder(), second) + secondBytes, err := utils.GetEncodedTxs(s.EncCfg.TxConfig.TxEncoder(), second) s.Require().NoError(err) s.Require().Equal(firstBytes, secondBytes) diff --git a/lanes/mev/testutils/testutil.go b/lanes/mev/testutils/testutil.go new file mode 100644 index 0000000..5b72fe7 --- /dev/null +++ b/lanes/mev/testutils/testutil.go @@ -0,0 +1,95 @@ +package testutils + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "math/rand" + "time" + + "cosmossdk.io/log" + "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter" + "github.com/skip-mev/block-sdk/block/base" + "github.com/skip-mev/block-sdk/lanes/mev" + testutils "github.com/skip-mev/block-sdk/testutils" +) + +type MEVLaneTestSuiteBase struct { + suite.Suite + + EncCfg testutils.EncodingConfig + Config mev.Factory + Ctx sdk.Context + Accounts []testutils.Account + GasTokenDenom string +} + +func (s *MEVLaneTestSuiteBase) SetupTest() { + // Init encoding config + s.EncCfg = testutils.CreateTestEncodingConfig() + s.Config = mev.NewDefaultAuctionFactory(s.EncCfg.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()) + testCtx := testutil.DefaultContextWithDB(s.T(), storetypes.NewKVStoreKey("test"), storetypes.NewTransientStoreKey("transient_test")) + s.Ctx = testCtx.Ctx.WithExecMode(sdk.ExecModePrepareProposal) + s.Ctx = s.Ctx.WithBlockHeight(1) + + // Init accounts + random := rand.New(rand.NewSource(time.Now().Unix())) + s.Accounts = testutils.RandomAccounts(random, 10) + s.GasTokenDenom = "stake" +} + +func (s *MEVLaneTestSuiteBase) InitLane( + maxBlockSpace math.LegacyDec, + expectedExecution map[sdk.Tx]bool, +) *mev.MEVLane { + config := base.NewLaneConfig( + log.NewNopLogger(), + s.EncCfg.TxConfig.TxEncoder(), + s.EncCfg.TxConfig.TxDecoder(), + s.SetUpAnteHandler(expectedExecution), + signer_extraction.NewDefaultAdapter(), + maxBlockSpace, + ) + + factory := mev.NewDefaultAuctionFactory(s.EncCfg.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()) + return mev.NewMEVLane(config, factory, factory.MatchHandler()) +} + +func (s *MEVLaneTestSuiteBase) SetUpAnteHandler(expectedExecution map[sdk.Tx]bool) sdk.AnteHandler { + txCache := make(map[string]bool) + for tx, pass := range expectedExecution { + bz, err := s.EncCfg.TxConfig.TxEncoder()(tx) + s.Require().NoError(err) + + hash := sha256.Sum256(bz) + hashStr := hex.EncodeToString(hash[:]) + txCache[hashStr] = pass + } + + anteHandler := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + bz, err := s.EncCfg.TxConfig.TxEncoder()(tx) + s.Require().NoError(err) + + hash := sha256.Sum256(bz) + hashStr := hex.EncodeToString(hash[:]) + + pass, found := txCache[hashStr] + if !found { + return ctx, fmt.Errorf("tx not found") + } + + if pass { + return ctx, nil + } + + return ctx, fmt.Errorf("tx failed") + } + + return anteHandler +} diff --git a/tests/app/app.go b/tests/app/app.go index 8c9e69f..8e91a68 100644 --- a/tests/app/app.go +++ b/tests/app/app.go @@ -42,10 +42,10 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/skip-mev/block-sdk/abci" + "github.com/skip-mev/block-sdk/abci/checktx" "github.com/skip-mev/block-sdk/block" "github.com/skip-mev/block-sdk/block/base" service "github.com/skip-mev/block-sdk/block/service" - "github.com/skip-mev/block-sdk/lanes/mev" auctionkeeper "github.com/skip-mev/block-sdk/x/auction/keeper" blocksdkkeeper "github.com/skip-mev/block-sdk/x/blocksdk/keeper" ) @@ -93,7 +93,7 @@ type TestApp struct { FeeGrantKeeper feegrantkeeper.Keeper // custom checkTx handler - checkTxHandler mev.CheckTx + checkTxHandler checktx.CheckTx } func init() { @@ -276,12 +276,18 @@ func New( // Step 7: Set the custom CheckTx handler on BaseApp. This is only required if you // use the MEV lane. - checkTxHandler := mev.NewCheckTxHandler( + mevCheckTx := checktx.NewMEVCheckTxHandler( app.App, app.txConfig.TxDecoder(), mevLane, anteHandler, + app.App.CheckTx, ) + checkTxHandler := checktx.NewMempoolParityCheckTx( + app.Logger(), mempool, + app.txConfig.TxDecoder(), mevCheckTx.CheckTx(), + ) + app.SetCheckTx(checkTxHandler.CheckTx()) // ---------------------------------------------------------------------------- // @@ -325,7 +331,7 @@ func (app *TestApp) CheckTx(req *cometabci.RequestCheckTx) (*cometabci.ResponseC } // SetCheckTx sets the checkTxHandler for the app. -func (app *TestApp) SetCheckTx(handler mev.CheckTx) { +func (app *TestApp) SetCheckTx(handler checktx.CheckTx) { app.checkTxHandler = handler } diff --git a/tests/integration/network/mempool_test.go b/tests/integration/network/mempool_test.go new file mode 100644 index 0000000..1a34559 --- /dev/null +++ b/tests/integration/network/mempool_test.go @@ -0,0 +1,302 @@ +package integration_test + +import ( + "context" + "fmt" + "time" + + "cosmossdk.io/math" + cmthttp "github.com/cometbft/cometbft/rpc/client/http" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "google.golang.org/grpc" + + "github.com/skip-mev/chaintestutil/account" + "github.com/skip-mev/chaintestutil/network" + + blockservicetypes "github.com/skip-mev/block-sdk/block/service/types" + auctiontypes "github.com/skip-mev/block-sdk/x/auction/types" +) + +const ( + free = "free" + base = "base" + mev = "mev" +) + +var cdc *codec.ProtoCodec + +func init() { + ir := codectypes.NewInterfaceRegistry() + + authtypes.RegisterInterfaces(ir) + cryptocodec.RegisterInterfaces(ir) + cdc = codec.NewProtoCodec(ir) +} + +// TestLanedMempool tests that the block-sdk mempool is properly synced w/ comet's mempool +func (s *NetworkTestSuite) TestLanedMempoolSyncWithComet() { + cc, closefn, err := s.NetworkSuite.GetGRPC() + s.Require().NoError(err) + defer closefn() + + tmClient, err := s.NetworkSuite.GetCometClient() + s.Require().NoError(err) + + blockClient := blockservicetypes.NewServiceClient(cc) + + ctx, closeCtx := context.WithTimeout(context.Background(), 1*time.Minute) + defer closeCtx() + val := s.NetworkSuite.Network.Validators[0].ValAddress + s.Require().NoError(err) + acc := *s.Accounts[0] + + s.Run("test free-lane sync", func() { + s.Run("all valid txs", func() { + // create a bunch of delegation txs and check the app-mempool v. comet-mempool + msg := createFreeTx(acc.Address(), val, sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(10))) + s.Require().NoError(s.checkParity(ctx, tmClient, blockClient, cc, acc, free, msg)) + }) + + s.Run("bid Verify invalidates later tx Verify", func() { + // create a new account + zeroAccount := account.NewAccount() + + status, err := tmClient.Status(ctx) + s.Require().NoError(err) + + // initialize the account w/ enough for a single tx + send := banktypes.NewMsgSend(acc.Address(), zeroAccount.Address(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(3000100)))) + + seq, _, err := getAccount(ctx, authtypes.NewQueryClient(cc), acc) + s.Require().NoError(err) + + // send the tx (pay for fees) + tx, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: acc, + GasLimit: 1000000, + TimeoutHeight: uint64(status.SyncInfo.LatestBlockHeight) + 1, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq, + OverrideSequence: true, + }, send) + s.Require().NoError(err) + + // commit tx + res, err := tmClient.BroadcastTxCommit(ctx, tx) + s.Require().NoError(err) + s.Require().Equal(uint32(0), res.TxResult.Code) + + // create a delegation tx -> this should spend fees in zeroAccount + msg := banktypes.NewMsgSend(zeroAccount.Address(), acc.Address(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1)))) + + // update the balance of zeroAccount to pay for the next tx + updateMsg := banktypes.NewMsgSend(acc.Address(), zeroAccount.Address(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000)))) + + status, err = tmClient.Status(ctx) + s.Require().NoError(err) + nextHeight := uint64(status.SyncInfo.LatestBlockHeight) + 1 + + // pay for fees of next tx for zeroAccount (account for bid sequence) + tx2, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: acc, + GasLimit: 1000000, + TimeoutHeight: nextHeight, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq + 2, + OverrideSequence: true, + }, updateMsg) + s.Require().NoError(err) + + seq2, _, err := getAccount(ctx, authtypes.NewQueryClient(cc), *zeroAccount) + s.Require().NoError(err) + + // spends all funds in account on fee deduction -> fees are refilled after bid + txToWrap, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: *zeroAccount, + GasLimit: 1000000, + TimeoutHeight: 100000000, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 3000000)), + Sequence: seq2, + OverrideSequence: true, + }, msg) + s.Require().NoError(err) + + // first delegate tx (just used to increment sequence) + firstDelegateTx, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: *zeroAccount, + GasLimit: 1000000, + TimeoutHeight: 100000000, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq2, + OverrideSequence: true, + }, msg) + s.Require().NoError(err) + + // ordered after bid, and shld fail in PrepareProposal as there will be no funds to pay (will be removed from lane) + secondDelegateTx, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: *zeroAccount, + GasLimit: 1000000, + TimeoutHeight: 100000000, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq2 + 1, + OverrideSequence: true, + }, msg) + s.Require().NoError(err) + + // create a bid wrapping firstDelegateTx, tx2 -> i.e spend funds in zeroAccount and refill + bid := auctiontypes.NewMsgAuctionBid(acc.Address(), sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000)), [][]byte{txToWrap, tx2}) + bidTx, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: acc, + GasLimit: 1000000, + TimeoutHeight: nextHeight, + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq + 1, + OverrideSequence: true, + }, bid) + s.Require().NoError(err) + + // broadcast txs + resp, err := tmClient.BroadcastTxSync(ctx, bidTx) + s.Require().NoError(err) + s.Require().Equal(uint32(0), resp.Code) + + resp, err = tmClient.BroadcastTxSync(ctx, firstDelegateTx) + s.Require().NoError(err) + s.Require().Equal(uint32(0), resp.Code) + + resp, err = tmClient.BroadcastTxSync(ctx, secondDelegateTx) + s.Require().NoError(err) + s.Require().Equal(uint32(0), resp.Code) + + // wait for commit of bid + s.Require().NoError(waitForTxCommit(ctx, tmClient, cmttypes.Tx(bidTx).Hash())) + + // check mempool size + txs, err := tmClient.NumUnconfirmedTxs(ctx) + s.Require().NoError(err) + + cmtTxs := uint64(txs.Total) + + // check app mempool size + appTxDist, err := blockClient.GetTxDistribution(ctx, &blockservicetypes.GetTxDistributionRequest{}) + s.Require().NoError(err) + + // check parity + appTxs := 0 + for _, tx := range appTxDist.Distribution { + appTxs += int(tx) + } + + s.Require().Equal(appTxs, int(cmtTxs)) + }) + }) +} + +func createFreeTx(delegator sdk.AccAddress, validator sdk.ValAddress, amount sdk.Coin) sdk.Msg { + return stakingtypes.NewMsgDelegate(delegator.String(), validator.String(), amount) +} + +func getAccount(ctx context.Context, cc authtypes.QueryClient, acc account.Account) (uint64, uint64, error) { + resp, err := cc.Account(ctx, &authtypes.QueryAccountRequest{Address: acc.Address().String()}) + if err != nil { + return 0, 0, err + } + + var accI sdk.AccountI + if err := cdc.UnpackAny(resp.Account, &accI); err != nil { + return 0, 0, err + } + + return accI.GetSequence(), accI.GetAccountNumber(), nil +} + +func (s *NetworkTestSuite) checkParity( + ctx context.Context, tmClient *cmthttp.HTTP, blockClient blockservicetypes.ServiceClient, + cc *grpc.ClientConn, acc account.Account, lane string, msg sdk.Msg, +) error { + seq, _, err := getAccount(ctx, authtypes.NewQueryClient(cc), acc) + if err != nil { + return err + } + + res, err := tmClient.Status(ctx) + if err != nil { + return err + } + + height := res.SyncInfo.LatestBlockHeight + // send 100 txs to the app and check mempool sizes + numTxs := 100 + txsCh := make(chan []byte, numTxs) + done := make(chan struct{}) + + // spin GR to wait on tx inclusions + go func() { + for tx := range txsCh { + // check for tx inclusion + waitForTxCommit(ctx, tmClient, tx) + } + close(done) + }() + + for i := 0; i < numTxs; i++ { + tx, err := s.NetworkSuite.CreateTxBytes(ctx, network.TxGenInfo{ + Account: acc, + GasLimit: 1000000, + TimeoutHeight: uint64(height + 10), + Fee: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)), + Sequence: seq + uint64(i), + OverrideSequence: true, + }, msg) + if err != nil { + return err + } + + res, err := tmClient.BroadcastTxSync(ctx, tx) + if err != nil { + return err + } + + txsCh <- res.Hash + } + // all txs are sent + close(txsCh) + + // wait for all txs to be included before checking size + <-done + + // check comet mempool size + txs, err := tmClient.NumUnconfirmedTxs(ctx) + if err != nil { + return err + } + + cmtTxs := uint64(txs.Total) + + // check app mempool size + appTxs, err := blockClient.GetTxDistribution(ctx, &blockservicetypes.GetTxDistributionRequest{}) + if err != nil { + return err + } + + if cmtTxs != appTxs.Distribution[lane] { + return fmt.Errorf("mempool size mismatch: %d != %d", cmtTxs, appTxs.Distribution[free]) + } + + return nil +} + +func waitForTxCommit(ctx context.Context, client *cmthttp.HTTP, hash []byte) error { + _, err := client.Tx(ctx, hash, false) + for ; err != nil; _, err = client.Tx(ctx, hash, false) { + time.Sleep(time.Millisecond) + } + return nil +} diff --git a/tests/integration/network_test.go b/tests/integration/network/network_test.go similarity index 99% rename from tests/integration/network_test.go rename to tests/integration/network/network_test.go index f1ce804..046b7f4 100644 --- a/tests/integration/network_test.go +++ b/tests/integration/network/network_test.go @@ -26,8 +26,6 @@ func TestNetworkTestSuite(t *testing.T) { } func (s *NetworkTestSuite) TestGetLanes() { - s.T().Parallel() - common := []string{ fmt.Sprintf("--%s=json", tmcli.OutputFlag), } diff --git a/testutils/networksuite/networksuite.go b/testutils/networksuite/networksuite.go index faafa15..85d46bf 100644 --- a/testutils/networksuite/networksuite.go +++ b/testutils/networksuite/networksuite.go @@ -6,12 +6,6 @@ import ( "os" "cosmossdk.io/log" - pruningtypes "cosmossdk.io/store/pruning/types" - dbm "github.com/cosmos/cosmos-db" - "github.com/cosmos/cosmos-sdk/baseapp" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - "cosmossdk.io/math" "github.com/cosmos/gogoproto/proto" "github.com/skip-mev/chaintestutil/network" @@ -19,6 +13,18 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + pruningtypes "cosmossdk.io/store/pruning/types" + cmtrand "github.com/cometbft/cometbft/libs/rand" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/baseapp" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/skip-mev/chaintestutil/account" + "github.com/skip-mev/block-sdk/lanes/base" "github.com/skip-mev/block-sdk/lanes/free" "github.com/skip-mev/block-sdk/lanes/mev" @@ -27,13 +33,22 @@ import ( blocksdktypes "github.com/skip-mev/block-sdk/x/blocksdk/types" ) -// NetworkTestSuite is a test suite for tests that initializes a network instance. +var ( + chainID = "chain-" + cmtrand.NewRand().Str(6) + + genBalance = sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000000000000)) +) + +// NetworkTestSuite is a test suite for query tests that initializes a network instance. type NetworkTestSuite struct { suite.Suite NetworkSuite *network.TestSuite AuctionState auctiontypes.GenesisState BlockSDKState blocksdktypes.GenesisState + AuthState authtypes.GenesisState + BankState banktypes.GenesisState + Accounts []*account.Account } // SetupSuite setups the local network with a genesis state. @@ -55,6 +70,7 @@ func (nts *NetworkTestSuite) SetupSuite() { } ) cfg.AppConstructor = appCons + cfg.ChainID = chainID updateGenesisConfigState := func(moduleName string, moduleState proto.Message) { buf, err := cfg.Codec.MarshalJSON(moduleState) @@ -70,9 +86,51 @@ func (nts *NetworkTestSuite) SetupSuite() { nts.BlockSDKState = populateBlockSDK(r, nts.BlockSDKState) updateGenesisConfigState(blocksdktypes.ModuleName, &nts.BlockSDKState) + // add genesis accounts + nts.Accounts = []*account.Account{ + account.NewAccount(), + } + + require.NoError(nts.T(), cfg.Codec.UnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &nts.AuthState)) + require.NoError(nts.T(), cfg.Codec.UnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &nts.BankState)) + + addGenesisAccounts(&nts.AuthState, &nts.BankState, nts.Accounts) + + // update genesis + updateGenesisConfigState(authtypes.ModuleName, &nts.AuthState) + updateGenesisConfigState(banktypes.ModuleName, &nts.BankState) + nts.NetworkSuite = network.NewSuite(nts.T(), cfg) } +// addGenesisAccount adds a genesis account to the auth / bank genesis state. +func addGenesisAccounts(authGenState *authtypes.GenesisState, bankGenState *banktypes.GenesisState, accs []*account.Account) { + balances := make([]banktypes.Balance, len(accs)) + accounts := make(authtypes.GenesisAccounts, len(accs)) + + // create accounts / update bank state w/ account + gen balance + for i, acc := range accs { + // base account + bacc := authtypes.NewBaseAccount(acc.Address(), acc.PubKey(), 0, 0) + + accounts[i] = bacc + balances[i] = banktypes.Balance{ + Address: acc.Address().String(), + Coins: sdk.NewCoins(genBalance), + } + } + + // update auth state w/ accounts + var err error + authGenState.Accounts, err = authtypes.PackAccounts(accounts) + if err != nil { + panic(err) + } + + // update bank state w/ balances + bankGenState.Balances = balances +} + func populateAuction(_ *rand.Rand, auctionState auctiontypes.GenesisState) auctiontypes.GenesisState { // TODO intercept and populate state randomly if desired return auctionState