diff --git a/abci/abci_test.go b/abci/abci_test.go index 634d4071..c1eca5f1 100644 --- a/abci/abci_test.go +++ b/abci/abci_test.go @@ -3,7 +3,6 @@ package abci_test import ( "context" "math/rand" - "os" "testing" "cosmossdk.io/math" @@ -531,7 +530,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() { s.Require().NoError(err) proposalHandler := abci.NewProposalHandler( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encodingConfig.TxConfig.TxDecoder(), s.encodingConfig.TxConfig.TxEncoder(), mempool, @@ -577,7 +576,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() { s.Require().NoError(err) proposalHandler := abci.NewProposalHandler( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encodingConfig.TxConfig.TxDecoder(), s.encodingConfig.TxConfig.TxEncoder(), mempool, @@ -625,7 +624,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() { s.Require().NoError(err) proposalHandler := abci.NewProposalHandler( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encodingConfig.TxConfig.TxDecoder(), s.encodingConfig.TxConfig.TxEncoder(), mempool, @@ -673,7 +672,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() { s.Require().NoError(err) proposalHandler := abci.NewProposalHandler( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encodingConfig.TxConfig.TxDecoder(), s.encodingConfig.TxConfig.TxEncoder(), mempool, diff --git a/abci/utils_test.go b/abci/utils_test.go index 1de32a00..014c1b5e 100644 --- a/abci/utils_test.go +++ b/abci/utils_test.go @@ -63,20 +63,22 @@ func (s *ProposalsTestSuite) setUpCustomMatchHandlerLane(maxBlockSpace math.Lega SignerExtractor: signeradaptors.NewDefaultAdapter(), } - lane := base.NewBaseLane( + options := []base.LaneOption{ + base.WithMatchHandler(mh), + base.WithMempoolConfigs[string](cfg, base.DefaultTxPriority()), + } + + lane, err := base.NewBaseLane( cfg, name, - base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, cfg.SignerExtractor, 0), - mh, + options..., ) - - lane.SetPrepareLaneHandler(lane.DefaultPrepareLaneHandler()) - lane.SetProcessLaneHandler(lane.DefaultProcessLaneHandler()) + s.Require().NoError(err) return lane } -func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *defaultlane.DefaultLane { +func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *base.BaseLane { cfg := base.LaneConfig{ Logger: log.NewNopLogger(), TxEncoder: s.encodingConfig.TxConfig.TxEncoder(), @@ -103,7 +105,7 @@ func (s *ProposalsTestSuite) setUpTOBLane(maxBlockSpace math.LegacyDec, expected return mev.NewMEVLane(cfg, factory, factory.MatchHandler()) } -func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *free.FreeLane { +func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *base.BaseLane { cfg := base.LaneConfig{ Logger: log.NewNopLogger(), TxEncoder: s.encodingConfig.TxConfig.TxEncoder(), @@ -125,15 +127,19 @@ func (s *ProposalsTestSuite) setUpPanicLane(name string, maxBlockSpace math.Lega SignerExtractor: signeradaptors.NewDefaultAdapter(), } - lane := base.NewBaseLane( + options := []base.LaneOption{ + base.WithMatchHandler(base.DefaultMatchHandler()), + base.WithMempoolConfigs[string](cfg, base.DefaultTxPriority()), + base.WithPrepareLaneHandler(base.PanicPrepareLaneHandler()), + base.WithProcessLaneHandler(base.PanicProcessLaneHandler()), + } + + lane, err := base.NewBaseLane( cfg, name, - base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, cfg.SignerExtractor, 0), - base.DefaultMatchHandler(), + options..., ) - - lane.SetPrepareLaneHandler(base.PanicPrepareLaneHandler()) - lane.SetProcessLaneHandler(base.PanicProcessLaneHandler()) + s.Require().NoError(err) return lane } diff --git a/block/README.md b/block/README.md index f3715f9b..c1cccab9 100644 --- a/block/README.md +++ b/block/README.md @@ -71,9 +71,6 @@ type Lane interface { // Name returns the name of the lane. Name() string - // SetAnteHandler sets the lane's antehandler. - SetAnteHandler(antehander sdk.AnteHandler) - // Match determines if a transaction belongs to this lane. Match(ctx sdk.Context, tx sdk.Tx) bool diff --git a/block/base/README.md b/block/base/README.md index 9dd2a4d9..4e1135f1 100644 --- a/block/base/README.md +++ b/block/base/README.md @@ -44,7 +44,7 @@ func DefaultMatchHandler() base.MatchHandler { } ``` -The default `MatchHandler` is implemented in the [base lane](./handlers.go) and matches all transactions. +The default `MatchHandler` is implemented in the [base lane](./match.go) and matches all transactions. ## PrepareLaneHandler @@ -60,7 +60,7 @@ PrepareLaneHandler func( To create a custom lane with a custom `PrepareLaneHandler`, you must implement this function and set it on the lane after it has been created. Please visit the [MEV lane's](../../lanes/mev/abci.go) `PrepareLaneHandler` for an example of how to implement this function. -The default `PrepareLaneHandler` is implemented in the [base lane](./handlers.go). It reaps transactions from the mempool, validates them, ensures that the lane's block space limit is not exceeded, and returns the transactions to be included in the block and the ones that need to be removed. +The default `PrepareLaneHandler` is implemented in the [base lane](./proposals.go). It reaps transactions from the mempool, validates them, ensures that the lane's block space limit is not exceeded, and returns the transactions to be included in the block and the ones that need to be removed. ## ProcessLaneHandler @@ -74,7 +74,7 @@ ProcessLaneHandler func(ctx sdk.Context, partialProposal []sdk.Tx) ( ) ``` -Note that block proposals built using the Block SDK contain contiguous sections of transactions in the block that belong to a given lane, to read more about how proposals are constructed relative to other lanes, please visit the [abci section](../../abci/README.md). As such, a given lane will recieve some transactions in (partialProposal) that belong to it and some that do not. The transactions that belong to it must be contiguous from the start, and the transactions that do not belong to it must be contiguous from the end. The lane must return the transactions that belong to it and the transactions that do not belong to it. The transactions that do not belong to it will be passed to the next lane in the proposal. The default `ProcessLaneHandler` is implemented in the [base lane](./handlers.go). It verifies the transactions that belong to the lane and returns them alongside the transactions that do not belong to the lane. +Note that block proposals built using the Block SDK contain contiguous sections of transactions in the block that belong to a given lane, to read more about how proposals are constructed relative to other lanes, please visit the [abci section](../../abci/README.md). As such, a given lane will recieve some transactions in (partialProposal) that belong to it and some that do not. The transactions that belong to it must be contiguous from the start, and the transactions that do not belong to it must be contiguous from the end. The lane must return the transactions that belong to it and the transactions that do not belong to it. The transactions that do not belong to it will be passed to the next lane in the proposal. The default `ProcessLaneHandler` is implemented in the [base lane](./proposals.go). It verifies the transactions that belong to the lane and returns them alongside the transactions that do not belong to the lane. Please visit the [MEV lane's](../../lanes/mev/abci.go) `ProcessLaneHandler` for an example of how to implement a custom handler. diff --git a/block/base/lane.go b/block/base/lane.go index 5f8beb3d..74fed03a 100644 --- a/block/base/lane.go +++ b/block/base/lane.go @@ -50,17 +50,35 @@ type BaseLane struct { //nolint func NewBaseLane( cfg LaneConfig, laneName string, - laneMempool block.LaneMempool, - matchHandlerFn MatchHandler, -) *BaseLane { + options ...LaneOption, +) (*BaseLane, error) { lane := &BaseLane{ - cfg: cfg, - laneName: laneName, - LaneMempool: laneMempool, - matchHandler: matchHandlerFn, + cfg: cfg, + laneName: laneName, } - return lane + lane.LaneMempool = NewMempool( + DefaultTxPriority(), + lane.cfg.TxEncoder, + lane.cfg.SignerExtractor, + lane.cfg.MaxTxs, + ) + + lane.matchHandler = DefaultMatchHandler() + + handler := NewDefaultProposalHandler(lane) + lane.prepareLaneHandler = handler.PrepareLaneHandler() + lane.processLaneHandler = handler.ProcessLaneHandler() + + for _, option := range options { + option(lane) + } + + if err := lane.ValidateBasic(); err != nil { + return nil, err + } + + return lane, nil } // ValidateBasic ensures that the lane was constructed properly. In the case that @@ -83,39 +101,16 @@ func (l *BaseLane) ValidateBasic() error { } if l.prepareLaneHandler == nil { - l.prepareLaneHandler = l.DefaultPrepareLaneHandler() + return fmt.Errorf("prepare lane handler cannot be nil") } if l.processLaneHandler == nil { - l.processLaneHandler = l.DefaultProcessLaneHandler() + return fmt.Errorf("process lane handler cannot be nil") } return nil } -// SetPrepareLaneHandler sets the prepare lane handler for the lane. This handler -// is called when a new proposal is being requested and the lane needs to submit -// transactions it wants included in the block. -func (l *BaseLane) SetPrepareLaneHandler(prepareLaneHandler PrepareLaneHandler) { - if prepareLaneHandler == nil { - panic("prepare lane handler cannot be nil") - } - - l.prepareLaneHandler = prepareLaneHandler -} - -// SetProcessLaneHandler sets the process lane handler for the lane. This handler -// is called when a new proposal is being verified and the lane needs to verify -// that the transactions included in the proposal are valid respecting the verification -// logic of the lane. -func (l *BaseLane) SetProcessLaneHandler(processLaneHandler ProcessLaneHandler) { - if processLaneHandler == nil { - panic("process lane handler cannot be nil") - } - - l.processLaneHandler = processLaneHandler -} - // Match returns true if the transaction should be processed by this lane. This // function first determines if the transaction matches the lane and then checks // if the transaction is on the ignore list. If the transaction is on the ignore @@ -129,11 +124,6 @@ func (l *BaseLane) Name() string { return l.laneName } -// SetAnteHandler sets the ante handler for the lane. -func (l *BaseLane) SetAnteHandler(anteHandler sdk.AnteHandler) { - l.cfg.AnteHandler = anteHandler -} - // Logger returns the logger for the lane. func (l *BaseLane) Logger() log.Logger { return l.cfg.Logger @@ -154,3 +144,12 @@ func (l *BaseLane) TxEncoder() sdk.TxEncoder { func (l *BaseLane) GetMaxBlockSpace() math.LegacyDec { return l.cfg.MaxBlockSpace } + +// WithOptions returns a new lane with the given options. +func (l *BaseLane) WithOptions(options ...LaneOption) *BaseLane { + for _, option := range options { + option(l) + } + + return l +} diff --git a/block/base/match.go b/block/base/match.go new file mode 100644 index 00000000..3559f32e --- /dev/null +++ b/block/base/match.go @@ -0,0 +1,42 @@ +package base + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// DefaultMatchHandler returns a default implementation of the MatchHandler. It matches all +// transactions. +func DefaultMatchHandler() MatchHandler { + return func(ctx sdk.Context, tx sdk.Tx) bool { + return true + } +} + +// VerifyNoMatches returns an error if any of the transactions match the lane. +func (l *BaseLane) VerifyNoMatches(ctx sdk.Context, txs []sdk.Tx) error { + for _, tx := range txs { + if l.Match(ctx, tx) { + return fmt.Errorf("transaction belongs to lane when it should not") + } + } + + return nil +} + +// NewMatchHandler returns a match handler that matches transactions +// that match the lane and do not match with any of the provided match handlers. +// In the context of building an application, you would want to use this to +// ignore the match handlers of other lanes in the application. +func NewMatchHandler(mh MatchHandler, ignoreMHs ...MatchHandler) MatchHandler { + return func(ctx sdk.Context, tx sdk.Tx) bool { + for _, ignoreMH := range ignoreMHs { + if ignoreMH(ctx, tx) { + return false + } + } + + return mh(ctx, tx) + } +} diff --git a/block/base/options.go b/block/base/options.go new file mode 100644 index 00000000..7636a4f6 --- /dev/null +++ b/block/base/options.go @@ -0,0 +1,80 @@ +package base + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/skip-mev/block-sdk/block" +) + +// LaneOption defines a function that can be used to set options on a lane. +type LaneOption func(*BaseLane) + +// WithAnteHandler sets the ante handler for the lane. +func WithAnteHandler(anteHandler sdk.AnteHandler) LaneOption { + return func(l *BaseLane) { l.cfg.AnteHandler = anteHandler } +} + +// WithPrepareLaneHandler sets the prepare lane handler for the lane. This handler +// is called when a new proposal is being requested and the lane needs to submit +// transactions it wants included in the block. +func WithPrepareLaneHandler(prepareLaneHandler PrepareLaneHandler) LaneOption { + return func(l *BaseLane) { + if prepareLaneHandler == nil { + panic("prepare lane handler cannot be nil") + } + + l.prepareLaneHandler = prepareLaneHandler + } +} + +// WithProcessLaneHandler sets the process lane handler for the lane. This handler +// is called when a new proposal is being verified and the lane needs to verify +// that the transactions included in the proposal are valid respecting the verification +// logic of the lane. +func WithProcessLaneHandler(processLaneHandler ProcessLaneHandler) LaneOption { + return func(l *BaseLane) { + if processLaneHandler == nil { + panic("process lane handler cannot be nil") + } + + l.processLaneHandler = processLaneHandler + } +} + +// WithMatchHandler sets the match handler for the lane. This handler is called +// when a new transaction is being submitted to the lane and the lane needs to +// determine if the transaction should be processed by the lane. +func WithMatchHandler(matchHandler MatchHandler) LaneOption { + return func(l *BaseLane) { + if matchHandler == nil { + panic("match handler cannot be nil") + } + + l.matchHandler = matchHandler + } +} + +// WithMempool sets the mempool for the lane. This mempool is used to store +// transactions that are waiting to be processed. +func WithMempool(mempool block.LaneMempool) LaneOption { + return func(l *BaseLane) { + if mempool == nil { + panic("mempool cannot be nil") + } + + l.LaneMempool = mempool + } +} + +// WithMempoolConfigs sets the mempool for the lane with the given lane config +// and TxPriority struct. This mempool is used to store transactions that are waiting +// to be processed. +func WithMempoolConfigs[C comparable](cfg LaneConfig, txPriority TxPriority[C]) LaneOption { + return func(l *BaseLane) { + l.LaneMempool = NewMempool( + txPriority, + cfg.TxEncoder, + cfg.SignerExtractor, + cfg.MaxTxs, + ) + } +} diff --git a/block/base/handlers.go b/block/base/proposals.go similarity index 69% rename from block/base/handlers.go rename to block/base/proposals.go index 9308c525..e25427b6 100644 --- a/block/base/handlers.go +++ b/block/base/proposals.go @@ -8,11 +8,24 @@ import ( "github.com/skip-mev/block-sdk/block/proposals" ) +// DefaultProposalHandler returns a default implementation of the PrepareLaneHandler and +// ProcessLaneHandler. +type DefaultProposalHandler struct { + lane *BaseLane +} + +// NewDefaultProposalHandler returns a new default proposal handler. +func NewDefaultProposalHandler(lane *BaseLane) *DefaultProposalHandler { + return &DefaultProposalHandler{ + lane: lane, + } +} + // DefaultPrepareLaneHandler returns a default implementation of the PrepareLaneHandler. It // selects all transactions in the mempool that are valid and not already in the partial // proposal. It will continue to reap transactions until the maximum blockspace/gas for this // lane has been reached. Additionally, any transactions that are invalid will be returned. -func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { +func (h *DefaultProposalHandler) PrepareLaneHandler() PrepareLaneHandler { return func(ctx sdk.Context, proposal proposals.Proposal, limit proposals.LaneLimits) ([]sdk.Tx, []sdk.Tx, error) { var ( totalSize int64 @@ -23,23 +36,23 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { // Select all transactions in the mempool that are valid and not already in the // partial proposal. - for iterator := l.Select(ctx, nil); iterator != nil; iterator = iterator.Next() { + for iterator := h.lane.Select(ctx, nil); iterator != nil; iterator = iterator.Next() { tx := iterator.Tx() - txInfo, err := l.GetTxInfo(ctx, tx) + txInfo, err := h.lane.GetTxInfo(ctx, tx) if err != nil { - l.Logger().Info("failed to get hash of tx", "err", err) + h.lane.Logger().Info("failed to get hash of tx", "err", err) txsToRemove = append(txsToRemove, tx) continue } // Double check that the transaction belongs to this lane. - if !l.Match(ctx, tx) { - l.Logger().Info( + if !h.lane.Match(ctx, tx) { + h.lane.Logger().Info( "failed to select tx for lane; tx does not belong to lane", "tx_hash", txInfo.Hash, - "lane", l.Name(), + "lane", h.lane.Name(), ) txsToRemove = append(txsToRemove, tx) @@ -48,10 +61,10 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { // if the transaction is already in the (partial) block proposal, we skip it. if proposal.Contains(txInfo.Hash) { - l.Logger().Info( + h.lane.Logger().Info( "failed to select tx for lane; tx is already in proposal", "tx_hash", txInfo.Hash, - "lane", l.Name(), + "lane", h.lane.Name(), ) continue @@ -59,9 +72,9 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { // If the transaction is too large, we break and do not attempt to include more txs. if updatedSize := totalSize + txInfo.Size; updatedSize > limit.MaxTxBytes { - l.Logger().Info( + h.lane.Logger().Info( "failed to select tx for lane; tx bytes above the maximum allowed", - "lane", l.Name(), + "lane", h.lane.Name(), "tx_size", txInfo.Size, "total_size", totalSize, "max_tx_bytes", limit.MaxTxBytes, @@ -74,9 +87,9 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { // If the gas limit of the transaction is too large, we break and do not attempt to include more txs. if updatedGas := totalGas + txInfo.GasLimit; updatedGas > limit.MaxGasLimit { - l.Logger().Info( + h.lane.Logger().Info( "failed to select tx for lane; gas limit above the maximum allowed", - "lane", l.Name(), + "lane", h.lane.Name(), "tx_gas", txInfo.GasLimit, "total_gas", totalGas, "max_gas", limit.MaxGasLimit, @@ -88,8 +101,8 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { } // Verify the transaction. - if err = l.VerifyTx(ctx, tx, false); err != nil { - l.Logger().Info( + if err = h.lane.VerifyTx(ctx, tx, false); err != nil { + h.lane.Logger().Info( "failed to verify tx", "tx_hash", txInfo.Hash, "err", err, @@ -114,18 +127,18 @@ func (l *BaseLane) DefaultPrepareLaneHandler() PrepareLaneHandler { // 2. Transactions that do not belong to the lane must be contiguous from the end of the partial proposal. // 3. Transactions must be ordered respecting the priority defined by the lane (e.g. gas price). // 4. Transactions must be valid according to the verification logic of the lane. -func (l *BaseLane) DefaultProcessLaneHandler() ProcessLaneHandler { +func (h *DefaultProposalHandler) ProcessLaneHandler() ProcessLaneHandler { return func(ctx sdk.Context, partialProposal []sdk.Tx) ([]sdk.Tx, []sdk.Tx, error) { if len(partialProposal) == 0 { return nil, nil, nil } for index, tx := range partialProposal { - if !l.Match(ctx, tx) { + if !h.lane.Match(ctx, tx) { // If the transaction does not belong to this lane, we return the remaining transactions // iff there are no matches in the remaining transactions after this index. if index+1 < len(partialProposal) { - if err := l.VerifyNoMatches(ctx, partialProposal[index+1:]); err != nil { + if err := h.lane.VerifyNoMatches(ctx, partialProposal[index+1:]); err != nil { return nil, nil, fmt.Errorf("failed to verify no matches: %w", err) } } @@ -136,12 +149,12 @@ func (l *BaseLane) DefaultProcessLaneHandler() ProcessLaneHandler { // If the transactions do not respect the priority defined by the mempool, we consider the proposal // to be invalid if index > 0 { - if v, err := l.Compare(ctx, partialProposal[index-1], tx); v == -1 || err != nil { + if v, err := h.lane.Compare(ctx, partialProposal[index-1], tx); v == -1 || err != nil { return nil, nil, fmt.Errorf("transaction at index %d has a higher priority than %d", index, index-1) } } - if err := l.VerifyTx(ctx, tx, false); err != nil { + if err := h.lane.VerifyTx(ctx, tx, false); err != nil { return nil, nil, fmt.Errorf("failed to verify tx: %w", err) } } @@ -151,38 +164,3 @@ func (l *BaseLane) DefaultProcessLaneHandler() ProcessLaneHandler { return partialProposal, nil, nil } } - -// VerifyNoMatches returns an error if any of the transactions match the lane. -func (l *BaseLane) VerifyNoMatches(ctx sdk.Context, txs []sdk.Tx) error { - for _, tx := range txs { - if l.Match(ctx, tx) { - return fmt.Errorf("transaction belongs to lane when it should not") - } - } - - return nil -} - -// DefaultMatchHandler returns a default implementation of the MatchHandler. It matches all -// transactions. -func DefaultMatchHandler() MatchHandler { - return func(ctx sdk.Context, tx sdk.Tx) bool { - return true - } -} - -// NewMatchHandler returns a match handler that matches transactions -// that match the lane and do not match with any of the provided match handlers. -// In the context of building an application, you would want to use this to -// ignore the match handlers of other lanes in the application. -func NewMatchHandler(mh MatchHandler, ignoreMHs ...MatchHandler) MatchHandler { - return func(ctx sdk.Context, tx sdk.Tx) bool { - for _, ignoreMH := range ignoreMHs { - if ignoreMH(ctx, tx) { - return false - } - } - - return mh(ctx, tx) - } -} diff --git a/block/lane.go b/block/lane.go index 5606e6ec..ab5a2807 100644 --- a/block/lane.go +++ b/block/lane.go @@ -64,9 +64,6 @@ type Lane interface { // Name returns the name of the lane. Name() string - // SetAnteHandler sets the lane's antehandler. - SetAnteHandler(antehander sdk.AnteHandler) - // Match determines if a transaction belongs to this lane. Match(ctx sdk.Context, tx sdk.Tx) bool diff --git a/block/mempool_test.go b/block/mempool_test.go index d925cfc9..d9b25559 100644 --- a/block/mempool_test.go +++ b/block/mempool_test.go @@ -2,7 +2,6 @@ package block_test import ( "math/rand" - "os" "testing" "time" @@ -32,8 +31,8 @@ type BlockBusterTestSuite struct { // Define all of the lanes utilized in the test suite mevLane *mev.MEVLane - baseLane *defaultlane.DefaultLane - freeLane *free.FreeLane + baseLane *base.BaseLane + freeLane *base.BaseLane gasTokenDenom string lanes []block.Lane @@ -114,7 +113,7 @@ func (suite *BlockBusterTestSuite) SetupTest() { // Mempool set up var err error - suite.mempool, err = block.NewLanedMempool(log.NewTMLogger(os.Stdout), suite.lanes) + suite.mempool, err = block.NewLanedMempool(log.NewNopLogger(), suite.lanes) suite.Require().NoError(err) // Accounts set up diff --git a/block/mocks/lane.go b/block/mocks/lane.go index c2cf8be4..60a1351b 100644 --- a/block/mocks/lane.go +++ b/block/mocks/lane.go @@ -251,11 +251,6 @@ func (_m *Lane) Select(_a0 context.Context, _a1 [][]byte) mempool.Iterator { return r0 } -// SetAnteHandler provides a mock function with given fields: antehander -func (_m *Lane) SetAnteHandler(antehander types.AnteHandler) { - _m.Called(antehander) -} - // NewLane creates a new instance of Lane. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewLane(t interface { diff --git a/lanes/base/abci_test.go b/lanes/base/abci_test.go index d1610408..10e7c493 100644 --- a/lanes/base/abci_test.go +++ b/lanes/base/abci_test.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "fmt" "math/rand" - "os" "cosmossdk.io/math" "github.com/cometbft/cometbft/libs/log" @@ -594,7 +593,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 2) s.Require().Len(remainingTxs, 0) @@ -664,7 +663,7 @@ func (s *BaseTestSuite) TestProcessLane() { ) // - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 3) s.Require().Len(remainingTxs, 0) @@ -746,7 +745,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 4) s.Require().Len(remainingTxs, 0) @@ -788,7 +787,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 1) s.Require().Len(remainingTxs, 0) @@ -830,7 +829,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().Error(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 0) @@ -891,7 +890,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().Error(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 0) @@ -942,7 +941,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 2) s.Require().Len(remainingTxs, 0) @@ -998,7 +997,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().Error(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 0) @@ -1055,7 +1054,7 @@ func (s *BaseTestSuite) TestProcessLane() { tx2, } - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().Error(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 0) @@ -1092,7 +1091,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 1) s.Require().Len(remainingTxs, 0) @@ -1131,7 +1130,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 1) s.Require().Len(remainingTxs, 0) @@ -1181,7 +1180,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 2) s.Require().Len(remainingTxs, 0) @@ -1231,7 +1230,7 @@ func (s *BaseTestSuite) TestProcessLane() { }, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 2) s.Require().Len(remainingTxs, 0) @@ -1312,7 +1311,7 @@ func (s *BaseTestSuite) TestProcessLane() { []base.MatchHandler{mh}, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 2) s.Require().Len(remainingTxs, 2) @@ -1391,7 +1390,7 @@ func (s *BaseTestSuite) TestProcessLane() { []base.MatchHandler{mh}, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().NoError(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 4) @@ -1475,7 +1474,7 @@ func (s *BaseTestSuite) TestProcessLane() { []base.MatchHandler{mh}, ) - txsFromLane, remainingTxs, err := lane.DefaultProcessLaneHandler()(s.ctx, proposal) + txsFromLane, remainingTxs, err := base.NewDefaultProposalHandler(lane).ProcessLaneHandler()(s.ctx, proposal) s.Require().Error(err) s.Require().Len(txsFromLane, 0) s.Require().Len(remainingTxs, 0) @@ -1631,9 +1630,9 @@ func (s *BaseTestSuite) TestIterateMempoolAndProcessProposalParity() { func (s *BaseTestSuite) initLane( maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool, -) *defaultlane.DefaultLane { +) *base.BaseLane { config := base.NewLaneConfig( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encodingConfig.TxConfig.TxEncoder(), s.encodingConfig.TxConfig.TxDecoder(), s.setUpAnteHandler(expectedExecution), @@ -1648,7 +1647,7 @@ func (s *BaseTestSuite) initLaneWithMatchHandlers( maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool, matchHandlers []base.MatchHandler, -) *defaultlane.DefaultLane { +) *base.BaseLane { config := base.NewLaneConfig( log.NewNopLogger(), s.encodingConfig.TxConfig.TxEncoder(), diff --git a/lanes/base/lane.go b/lanes/base/lane.go index ce28595e..e5739456 100644 --- a/lanes/base/lane.go +++ b/lanes/base/lane.go @@ -1,7 +1,6 @@ package base import ( - "github.com/skip-mev/block-sdk/block" "github.com/skip-mev/block-sdk/block/base" ) @@ -10,36 +9,24 @@ const ( LaneName = "default" ) -var _ block.Lane = (*DefaultLane)(nil) - -// DefaultLane defines a default lane implementation. The default lane orders -// transactions by the transaction fees. The default lane accepts any transaction. -// The default lane builds and verifies blocks in a similar fashion to how the -// CometBFT/Tendermint consensus engine builds and verifies blocks pre SDK version -// 0.47.0. -type DefaultLane struct { - *base.BaseLane -} +// NewDefaultLane returns a new default lane. The DefaultLane defines a default +// lane implementation. The default lane orders transactions by the transaction fees. +// The default lane accepts any transaction. The default lane builds and verifies blocks +// in a similar fashion to how the CometBFT/Tendermint consensus engine builds and verifies +// blocks pre SDK version 0.47.0. +func NewDefaultLane(cfg base.LaneConfig, matchHandler base.MatchHandler) *base.BaseLane { + options := []base.LaneOption{ + base.WithMatchHandler(matchHandler), + } -// NewDefaultLane returns a new default lane. -func NewDefaultLane(cfg base.LaneConfig, matchHandler base.MatchHandler) *DefaultLane { - lane := base.NewBaseLane( + lane, err := base.NewBaseLane( cfg, LaneName, - base.NewMempool[string]( - base.DefaultTxPriority(), - cfg.TxEncoder, - cfg.SignerExtractor, - cfg.MaxTxs, - ), - matchHandler, + options..., ) - - if err := lane.ValidateBasic(); err != nil { + if err != nil { panic(err) } - return &DefaultLane{ - BaseLane: lane, - } + return lane } diff --git a/lanes/free/lane.go b/lanes/free/lane.go index ceabef76..132b2af5 100644 --- a/lanes/free/lane.go +++ b/lanes/free/lane.go @@ -4,7 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/skip-mev/block-sdk/block" "github.com/skip-mev/block-sdk/block/base" ) @@ -13,39 +12,27 @@ const ( LaneName = "free" ) -var _ block.Lane = (*FreeLane)(nil) - -// FreeLane defines the lane that is responsible for processing free transactions. -// By default, transactions that are staking related are considered free. -type FreeLane struct { //nolint - *base.BaseLane -} - // NewFreeLane returns a new free lane. -func NewFreeLane( +func NewFreeLane[C comparable]( cfg base.LaneConfig, - txPriority base.TxPriority[string], + txPriority base.TxPriority[C], matchFn base.MatchHandler, -) *FreeLane { - lane := base.NewBaseLane( +) *base.BaseLane { + options := []base.LaneOption{ + base.WithMatchHandler(matchFn), + base.WithMempoolConfigs[C](cfg, txPriority), + } + + lane, err := base.NewBaseLane( cfg, LaneName, - base.NewMempool[string]( - txPriority, - cfg.TxEncoder, - cfg.SignerExtractor, - cfg.MaxTxs, - ), - matchFn, + options..., ) - - if err := lane.ValidateBasic(); err != nil { + if err != nil { panic(err) } - return &FreeLane{ - BaseLane: lane, - } + return lane } // DefaultMatchHandler returns the default match handler for the free lane. The diff --git a/lanes/mev/abci.go b/lanes/mev/abci.go index 5910f214..7b00e3b3 100644 --- a/lanes/mev/abci.go +++ b/lanes/mev/abci.go @@ -10,11 +10,25 @@ import ( "github.com/skip-mev/block-sdk/block/proposals" ) +// Implements the MEV lane's PrepareLaneHandler and ProcessLaneHandler. +type ProposalHandler struct { + lane *base.BaseLane + factory Factory +} + +// NewProposalHandler returns a new mev proposal handler. +func NewProposalHandler(lane *base.BaseLane, factory Factory) *ProposalHandler { + return &ProposalHandler{ + lane: lane, + factory: factory, + } +} + // PrepareLaneHandler will attempt to select the highest bid transaction that is valid // and whose bundled transactions are valid and include them in the proposal. It // will return no transactions if no valid bids are found. If any of the bids are invalid, // it will return them and will only remove the bids and not the bundled transactions. -func (l *MEVLane) PrepareLaneHandler() base.PrepareLaneHandler { +func (h *ProposalHandler) PrepareLaneHandler() base.PrepareLaneHandler { return func(ctx sdk.Context, proposal proposals.Proposal, limit proposals.LaneLimits) ([]sdk.Tx, []sdk.Tx, error) { // Define all of the info we need to select transactions for the partial proposal. var ( @@ -24,11 +38,11 @@ func (l *MEVLane) PrepareLaneHandler() base.PrepareLaneHandler { // Attempt to select the highest bid transaction that is valid and whose // bundled transactions are valid. - for iterator := l.Select(ctx, nil); iterator != nil; iterator = iterator.Next() { + for iterator := h.lane.Select(ctx, nil); iterator != nil; iterator = iterator.Next() { bidTx := iterator.Tx() - if !l.Match(ctx, bidTx) { - l.Logger().Info("failed to select auction bid tx for lane; tx does not match lane") + if !h.lane.Match(ctx, bidTx) { + h.lane.Logger().Info("failed to select auction bid tx for lane; tx does not match lane") txsToRemove = append(txsToRemove, bidTx) continue @@ -36,9 +50,9 @@ func (l *MEVLane) PrepareLaneHandler() base.PrepareLaneHandler { cacheCtx, write := ctx.CacheContext() - bundle, err := l.VerifyBidBasic(cacheCtx, bidTx, proposal, limit) + bundle, err := h.VerifyBidBasic(cacheCtx, bidTx, proposal, limit) if err != nil { - l.Logger().Info( + h.lane.Logger().Info( "failed to select auction bid tx for lane; tx is invalid", "err", err, ) @@ -47,8 +61,8 @@ func (l *MEVLane) PrepareLaneHandler() base.PrepareLaneHandler { continue } - if err := l.VerifyBidTx(cacheCtx, bidTx, bundle); err != nil { - l.Logger().Info( + if err := h.VerifyBidTx(cacheCtx, bidTx, bundle); err != nil { + h.lane.Logger().Info( "failed to select auction bid tx for lane; tx is invalid", "err", err, ) @@ -84,18 +98,18 @@ func (l *MEVLane) PrepareLaneHandler() base.PrepareLaneHandler { // 4. The bundled transactions must match the transactions in the block proposal in the // same order they were defined in the bid transaction. // 5. The bundled transactions must not be bid transactions. -func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { +func (h *ProposalHandler) ProcessLaneHandler() base.ProcessLaneHandler { return func(ctx sdk.Context, partialProposal []sdk.Tx) ([]sdk.Tx, []sdk.Tx, error) { if len(partialProposal) == 0 { return nil, nil, nil } bidTx := partialProposal[0] - if !l.Match(ctx, bidTx) { + if !h.lane.Match(ctx, bidTx) { // If the transaction does not belong to this lane, we return the remaining transactions // iff there are no matches in the remaining transactions after this index. if len(partialProposal) > 1 { - if err := l.VerifyNoMatches(ctx, partialProposal[1:]); err != nil { + if err := h.lane.VerifyNoMatches(ctx, partialProposal[1:]); err != nil { return nil, nil, fmt.Errorf("failed to verify no matches: %w", err) } } @@ -103,9 +117,9 @@ func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { return nil, partialProposal, nil } - bidInfo, err := l.GetAuctionBidInfo(bidTx) + bidInfo, err := h.factory.GetAuctionBidInfo(bidTx) if err != nil { - return nil, nil, fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", l.Name(), err) + return nil, nil, fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", h.lane.Name(), err) } if bidInfo == nil { @@ -118,7 +132,7 @@ func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { return nil, nil, fmt.Errorf( "expected %d transactions in lane %s but got %d", bundleSize, - l.Name(), + h.lane.Name(), len(partialProposal), ) } @@ -126,17 +140,17 @@ func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { // Ensure the transactions in the proposal match the bundled transactions in the bid transaction. bundle := partialProposal[1:bundleSize] for index, bundledTxBz := range bidInfo.Transactions { - bundledTx, err := l.WrapBundleTransaction(bundledTxBz) + bundledTx, err := h.factory.WrapBundleTransaction(bundledTxBz) if err != nil { return nil, nil, fmt.Errorf("invalid bid tx; failed to decode bundled tx: %w", err) } - expectedTxBz, err := l.TxEncoder()(bundledTx) + expectedTxBz, err := h.lane.TxEncoder()(bundledTx) if err != nil { return nil, nil, fmt.Errorf("invalid bid tx; failed to encode bundled tx: %w", err) } - actualTxBz, err := l.TxEncoder()(bundle[index]) + actualTxBz, err := h.lane.TxEncoder()(bundle[index]) if err != nil { return nil, nil, fmt.Errorf("invalid bid tx; failed to encode tx: %w", err) } @@ -150,7 +164,7 @@ func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { // Verify the top-level bid transaction. // // TODO: There is duplicate work being done in VerifyBidTx and here. - if err := l.VerifyBidTx(ctx, bidTx, bundle); err != nil { + if err := h.VerifyBidTx(ctx, bidTx, bundle); err != nil { return nil, nil, fmt.Errorf("invalid bid tx; failed to verify bid tx: %w", err) } @@ -160,23 +174,23 @@ func (l *MEVLane) ProcessLaneHandler() base.ProcessLaneHandler { // VerifyBidBasic will verify that the bid transaction and all of its bundled // transactions respect the basic invariants of the lane (e.g. size, gas limit). -func (l *MEVLane) VerifyBidBasic( +func (h *ProposalHandler) VerifyBidBasic( ctx sdk.Context, bidTx sdk.Tx, proposal proposals.Proposal, limit proposals.LaneLimits, ) ([]sdk.Tx, error) { // Verify the transaction is a bid transaction. - bidInfo, err := l.GetAuctionBidInfo(bidTx) + bidInfo, err := h.factory.GetAuctionBidInfo(bidTx) if err != nil { - return nil, fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", l.Name(), err) + return nil, fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", h.lane.Name(), err) } if bidInfo == nil { return nil, fmt.Errorf("bid info is nil") } - txInfo, err := l.GetTxInfo(ctx, bidTx) + txInfo, err := h.lane.GetTxInfo(ctx, bidTx) if err != nil { return nil, fmt.Errorf("err retrieving transaction info: %s", err) } @@ -192,12 +206,12 @@ func (l *MEVLane) VerifyBidBasic( // Verify size and gas limit of the bundled transactions. for index, bundledTxBz := range bidInfo.Transactions { - bundledTx, err := l.WrapBundleTransaction(bundledTxBz) + bundledTx, err := h.factory.WrapBundleTransaction(bundledTxBz) if err != nil { return nil, fmt.Errorf("invalid bid tx; failed to decode bundled tx: %w", err) } - bundledTxInfo, err := l.GetTxInfo(ctx, bundledTx) + bundledTxInfo, err := h.lane.GetTxInfo(ctx, bundledTx) if err != nil { return nil, fmt.Errorf("err retrieving transaction info: %s", err) } @@ -232,10 +246,10 @@ func (l *MEVLane) VerifyBidBasic( // VerifyBidTx will verify that the bid transaction and all of its bundled // transactions are valid. -func (l *MEVLane) VerifyBidTx(ctx sdk.Context, bidTx sdk.Tx, bundle []sdk.Tx) error { - bidInfo, err := l.GetAuctionBidInfo(bidTx) +func (h *ProposalHandler) VerifyBidTx(ctx sdk.Context, bidTx sdk.Tx, bundle []sdk.Tx) error { + bidInfo, err := h.factory.GetAuctionBidInfo(bidTx) if err != nil { - return fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", l.Name(), err) + return fmt.Errorf("failed to get bid info from auction bid tx for lane %s: %w", h.lane.Name(), err) } if bidInfo == nil { @@ -243,17 +257,17 @@ func (l *MEVLane) VerifyBidTx(ctx sdk.Context, bidTx sdk.Tx, bundle []sdk.Tx) er } // verify the top-level bid transaction - if err = l.VerifyTx(ctx, bidTx, false); err != nil { + if err = h.lane.VerifyTx(ctx, bidTx, false); err != nil { return fmt.Errorf("invalid bid tx; failed to execute ante handler: %w", err) } // verify all of the bundled transactions for _, bundledTx := range bundle { - if l.Match(ctx, bundledTx) { + if h.lane.Match(ctx, bundledTx) { return fmt.Errorf("invalid bid tx; bundled tx is another bid transaction") } - if err = l.VerifyTx(ctx, bundledTx, false); err != nil { + if err = h.lane.VerifyTx(ctx, bundledTx, false); err != nil { return fmt.Errorf("invalid bid tx; failed to execute bundled transaction: %w", err) } } diff --git a/lanes/mev/abci_test.go b/lanes/mev/abci_test.go index 29463314..814bc836 100644 --- a/lanes/mev/abci_test.go +++ b/lanes/mev/abci_test.go @@ -8,6 +8,7 @@ import ( "github.com/skip-mev/block-sdk/block" "github.com/skip-mev/block-sdk/block/proposals" "github.com/skip-mev/block-sdk/block/utils" + "github.com/skip-mev/block-sdk/lanes/mev" testutils "github.com/skip-mev/block-sdk/testutils" ) @@ -226,7 +227,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - txsFromLane, remainingTxs, err := lane.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)) @@ -243,7 +244,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), nil) proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) - txsFromLane, remainingTxs, err := lane.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)) @@ -269,7 +270,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) - txsFromLane, remainingTxs, err := lane.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)) @@ -295,7 +296,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) - txsFromLane, remainingTxs, err := lane.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)) @@ -321,7 +322,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -347,7 +348,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -373,7 +374,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -399,7 +400,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -425,7 +426,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -451,7 +452,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -480,7 +481,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -515,7 +516,7 @@ func (s *MEVTestSuite) TestProcessLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true}) - txsFromLane, remainingTxs, err := lane.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)) @@ -531,6 +532,8 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) + handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) + s.Run("can verify a bid with no bundled txs", func() { bidTx, expectedBundle, err := testutils.CreateAuctionTx( s.encCfg.TxConfig, @@ -543,7 +546,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - bundle, err := lane.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + bundle, err := handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) s.Require().NoError(err) s.compare(bundle, expectedBundle) }) @@ -559,7 +562,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - _, err = lane.VerifyBidBasic(s.ctx, tx, proposal, limits) + _, err = handler.VerifyBidBasic(s.ctx, tx, proposal, limits) s.Require().Error(err) }) @@ -575,7 +578,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - _, err = lane.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) s.Require().Error(err) }) @@ -595,7 +598,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { proposal := proposals.NewProposal(log.NewNopLogger(), size-1, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) - _, err = lane.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) s.Require().Error(err) }) @@ -620,7 +623,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { ) s.Require().NoError(err) - _, err = lane.VerifyBidBasic(s.ctx, bidTx, proposal, limits) + _, err = handler.VerifyBidBasic(s.ctx, bidTx, proposal, limits) s.Require().Error(err) }) } @@ -639,7 +642,9 @@ func (s *MEVTestSuite) TestVerifyBidTx() { s.Require().NoError(err) lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) - s.Require().NoError(lane.VerifyBidTx(s.ctx, bidTx, bundle)) + + handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) + s.Require().NoError(handler.VerifyBidTx(s.ctx, bidTx, bundle)) }) s.Run("can reject a bid transaction", func() { @@ -655,7 +660,9 @@ func (s *MEVTestSuite) TestVerifyBidTx() { s.Require().NoError(err) lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false}) - s.Require().Error(lane.VerifyBidTx(s.ctx, bidTx, bundle)) + + handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) + s.Require().Error(handler.VerifyBidTx(s.ctx, bidTx, bundle)) }) s.Run("can reject a bid transaction with a bad bundle", func() { @@ -671,7 +678,9 @@ func (s *MEVTestSuite) TestVerifyBidTx() { s.Require().NoError(err) lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false}) - s.Require().Error(lane.VerifyBidTx(s.ctx, bidTx, bundle)) + + handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) + 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() { @@ -699,6 +708,8 @@ func (s *MEVTestSuite) TestVerifyBidTx() { bundle = append(bundle, otherBidTx) lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true, otherBidTx: true}) - s.Require().Error(lane.VerifyBidTx(s.ctx, bidTx, bundle)) + + handler := mev.NewProposalHandler(lane.BaseLane, lane.Factory) + s.Require().Error(handler.VerifyBidTx(s.ctx, bidTx, bundle)) }) } diff --git a/lanes/mev/lane.go b/lanes/mev/lane.go index c4a8d8c9..f517226b 100644 --- a/lanes/mev/lane.go +++ b/lanes/mev/lane.go @@ -47,30 +47,29 @@ func NewMEVLane( factory Factory, matchHandler base.MatchHandler, ) *MEVLane { - lane := &MEVLane{ - BaseLane: base.NewBaseLane( - cfg, - LaneName, - base.NewMempool[string]( - TxPriority(factory), - cfg.TxEncoder, - cfg.SignerExtractor, - cfg.MaxTxs, - ), - matchHandler, - ), - Factory: factory, + options := []base.LaneOption{ + base.WithMatchHandler(matchHandler), + base.WithMempoolConfigs[string](cfg, TxPriority(factory)), } - // Set the prepare lane handler to the TOB one - lane.SetPrepareLaneHandler(lane.PrepareLaneHandler()) - - // Set the process lane handler to the TOB one - lane.SetProcessLaneHandler(lane.ProcessLaneHandler()) - - if err := lane.ValidateBasic(); err != nil { + baseLane, err := base.NewBaseLane( + cfg, + LaneName, + options..., + ) + if err != nil { panic(err) } - return lane + // Create the mev proposal handler. + handler := NewProposalHandler(baseLane, factory) + baseLane.WithOptions( + base.WithPrepareLaneHandler(handler.PrepareLaneHandler()), + base.WithProcessLaneHandler(handler.ProcessLaneHandler()), + ) + + return &MEVLane{ + BaseLane: baseLane, + Factory: factory, + } } diff --git a/lanes/mev/mev_test.go b/lanes/mev/mev_test.go index d1e3cd21..439228ff 100644 --- a/lanes/mev/mev_test.go +++ b/lanes/mev/mev_test.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "fmt" "math/rand" - "os" "testing" "time" @@ -56,7 +55,7 @@ func (s *MEVTestSuite) initLane( expectedExecution map[sdk.Tx]bool, ) *mev.MEVLane { config := base.NewLaneConfig( - log.NewTMLogger(os.Stdout), + log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), s.encCfg.TxConfig.TxDecoder(), s.setUpAnteHandler(expectedExecution), diff --git a/tests/app/app.go b/tests/app/app.go index a1077f22..f860a226 100644 --- a/tests/app/app.go +++ b/tests/app/app.go @@ -67,6 +67,7 @@ import ( "github.com/skip-mev/block-sdk/abci" "github.com/skip-mev/block-sdk/block" + "github.com/skip-mev/block-sdk/block/base" "github.com/skip-mev/block-sdk/lanes/mev" auctionmodule "github.com/skip-mev/block-sdk/x/auction" auctionkeeper "github.com/skip-mev/block-sdk/x/auction/keeper" @@ -300,9 +301,18 @@ func New( app.App.SetAnteHandler(anteHandler) // Set the ante handler on the lanes. - mevLane.SetAnteHandler(anteHandler) - freeLane.SetAnteHandler(anteHandler) - defaultLane.SetAnteHandler(anteHandler) + opt := []base.LaneOption{ + base.WithAnteHandler(anteHandler), + } + mevLane.WithOptions( + opt..., + ) + freeLane.WithOptions( + opt..., + ) + defaultLane.WithOptions( + opt..., + ) // Step 6: Create the proposal handler and set it on the app. Now the application // will build and verify proposals using the Block SDK! diff --git a/tests/app/lanes.go b/tests/app/lanes.go index 44e3423b..bae08350 100644 --- a/tests/app/lanes.go +++ b/tests/app/lanes.go @@ -13,7 +13,7 @@ import ( // we create three separate lanes - MEV, Free, and Default - and then return them. // // NOTE: Application Developers should closely replicate this function in their own application. -func CreateLanes(app *TestApp) (*mevlane.MEVLane, *freelane.FreeLane, *defaultlane.DefaultLane) { +func CreateLanes(app *TestApp) (*mevlane.MEVLane, *base.BaseLane, *base.BaseLane) { // 1. Create the signer extractor. This is used to extract the expected signers from // a transaction. Each lane can have a different signer extractor if needed. signerAdapter := signerextraction.NewDefaultAdapter()