From 9ec6c91d40e9f5b4c579617fa9c7dcda1849f877 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:14:31 -0500 Subject: [PATCH] chore: Update Lane Specific Readmes (backport #254) (#256) * chore: Update Lane Specific Readmes (#254) * nits * e2e shorter testing time (cherry picked from commit 4bfb7ce5252582dd7c8f7b763088bb2bc8754cb0) # Conflicts: # abci/abci.go # lanes/base/abci_test.go # lanes/build-your-own/README.md # lanes/mev/abci_test.go # lanes/terminator/lane.go * lint fix * read me fix --------- Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com> Co-authored-by: David Terpay --- abci/abci.go | 4 +- block/proposals/proposals.go | 15 +++--- block/proposals/proposals_test.go | 20 ++++---- lanes/base/README.md | 11 ++-- lanes/base/abci_test.go | 82 ++++++++++-------------------- lanes/build-your-own/README.md | 83 +++++++++++++++++-------------- lanes/free/README.md | 9 ++-- lanes/mev/README.md | 6 ++- lanes/mev/abci_test.go | 42 ++++++++-------- lanes/terminator/lane.go | 3 -- 10 files changed, 125 insertions(+), 150 deletions(-) diff --git a/abci/abci.go b/abci/abci.go index 4284e6d9..d2896ceb 100644 --- a/abci/abci.go +++ b/abci/abci.go @@ -71,7 +71,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler { ) // Fill the proposal with transactions from each lane. - finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder)) + finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.logger)) if err != nil { h.logger.Error("failed to prepare proposal", "err", err) return &abci.ResponsePrepareProposal{Txs: make([][]byte, 0)}, err @@ -130,7 +130,7 @@ func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler { // Build handler that will verify the partial proposals according to each lane's verification logic. processLanesHandler := ChainProcessLanes(h.mempool.Registry()) - finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder), decodedTxs) + finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.logger), decodedTxs) if err != nil { h.logger.Error("failed to validate the proposal", "err", err) return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err diff --git a/block/proposals/proposals.go b/block/proposals/proposals.go index a966ce81..24b93049 100644 --- a/block/proposals/proposals.go +++ b/block/proposals/proposals.go @@ -17,27 +17,24 @@ type ( Txs [][]byte // Cache is a cache of the selected transactions in the proposal. Cache map[string]struct{} - // TxEncoder is the transaction encoder. - TxEncoder sdk.TxEncoder // Info contains information about the state of the proposal. Info types.ProposalInfo } ) // NewProposalWithContext returns a new empty proposal. -func NewProposalWithContext(logger log.Logger, ctx sdk.Context, txEncoder sdk.TxEncoder) Proposal { +func NewProposalWithContext(ctx sdk.Context, logger log.Logger) Proposal { maxBlockSize, maxGasLimit := GetBlockLimits(ctx) - return NewProposal(logger, txEncoder, maxBlockSize, maxGasLimit) + return NewProposal(logger, maxBlockSize, maxGasLimit) } // NewProposal returns a new empty proposal. Any transactions added to the proposal // will be subject to the given max block size and max gas limit. -func NewProposal(logger log.Logger, txEncoder sdk.TxEncoder, maxBlockSize int64, maxGasLimit uint64) Proposal { +func NewProposal(logger log.Logger, maxBlockSize int64, maxGasLimit uint64) Proposal { return Proposal{ - Logger: logger, - TxEncoder: txEncoder, - Txs: make([][]byte, 0), - Cache: make(map[string]struct{}), + Logger: logger, + Txs: make([][]byte, 0), + Cache: make(map[string]struct{}), Info: types.ProposalInfo{ TxsByLane: make(map[string]uint64), MaxBlockSize: maxBlockSize, diff --git a/block/proposals/proposals_test.go b/block/proposals/proposals_test.go index 29c54089..50cee905 100644 --- a/block/proposals/proposals_test.go +++ b/block/proposals/proposals_test.go @@ -32,7 +32,7 @@ func TestUpdateProposal(t *testing.T) { lane.On("GetMaxBlockSpace").Return(math.LegacyNewDec(1)).Maybe() t.Run("can update with no transactions", func(t *testing.T) { - proposal := proposals.NewProposal(log.NewTestLogger(t), nil, 100, 100) + proposal := proposals.NewProposal(log.NewTestLogger(t), 100, 100) err := proposal.UpdateProposal(lane, nil) require.NoError(t, err) @@ -64,7 +64,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) gasLimit := 100 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), uint64(gasLimit)) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) @@ -113,7 +113,7 @@ func TestUpdateProposal(t *testing.T) { gasLimit += 100 } - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), gasLimit) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), gasLimit) txsWithInfo, err := getTxsWithInfo(txs) require.NoError(t, err) @@ -153,7 +153,7 @@ func TestUpdateProposal(t *testing.T) { size := int64(len(txBzs[0])) gasLimit := uint64(100) - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), size, gasLimit) + proposal := proposals.NewProposal(log.NewTestLogger(t), size, gasLimit) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) @@ -219,7 +219,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) + len(txBzs[1]) gasLimit := 200 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), uint64(gasLimit)) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) @@ -263,7 +263,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) gasLimit := 100 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), uint64(gasLimit)) lane := mocks.NewLane(t) @@ -304,7 +304,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) gasLimit := 100 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), uint64(gasLimit)) lane := mocks.NewLane(t) @@ -345,7 +345,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) gasLimit := 100 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size)-1, uint64(gasLimit)) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size)-1, uint64(gasLimit)) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) @@ -381,7 +381,7 @@ func TestUpdateProposal(t *testing.T) { size := len(txBzs[0]) gasLimit := 100 - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)-1) + proposal := proposals.NewProposal(log.NewTestLogger(t), int64(size), uint64(gasLimit)-1) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) @@ -425,7 +425,7 @@ func TestUpdateProposal(t *testing.T) { txBzs, err := utils.GetEncodedTxs(encodingConfig.TxConfig.TxEncoder(), []sdk.Tx{tx, tx2}) require.NoError(t, err) - proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), 10000, 10000) + proposal := proposals.NewProposal(log.NewTestLogger(t), 10000, 10000) txsWithInfo, err := getTxsWithInfo([]sdk.Tx{tx}) require.NoError(t, err) diff --git a/lanes/base/README.md b/lanes/base/README.md index 451a4d92..4f0b52c3 100644 --- a/lanes/base/README.md +++ b/lanes/base/README.md @@ -15,6 +15,8 @@ $ go install github.com/skip-mev/block-sdk ## 📚 Usage +> Note: Please visit [app.go](../../tests/app/lanes.go) to see a sample base app set up. + 1. First determine the set of lanes that you want to use in your application. The available lanes can be found in our [Lane App Store](https://docs.skip.money/chains/lanes/existing-lanes/default). @@ -45,8 +47,7 @@ func NewApp() { // 1. Create the lanes. // // NOTE: The lanes are ordered by priority. The first lane is the highest priority - // lane and the last lane is the lowest priority lane. Top of block lane allows - // transactions to bid for inclusion at the top of the next block. + // lane and the last lane is the lowest priority lane. // // For more information on how to utilize the LaneConfig please // visit the README in docs.skip.money/chains/lanes/build-your-own-lane#-lane-config. @@ -57,15 +58,15 @@ func NewApp() { TxEncoder: app.txConfig.TxEncoder(), TxDecoder: app.txConfig.TxDecoder(), MaxBlockSpace: math.LegacyZeroDec(), - MaxTxs: 0, + MaxTxs: 5000, } - defaultLane := defaultlane.NewDefaultLane(defaultConfig) + defaultLane := defaultlane.NewDefaultLane(defaultConfig, base.DefaultMatchHandler()) // 2. Set up the relative priority of lanes lanes := []block.Lane{ defaultLane, } - mempool := block.NewLanedMempool(app.Logger(), true, lanes...) + mempool := block.NewLanedMempool(app.Logger(), lanes) app.App.SetMempool(mempool) ... diff --git a/lanes/base/abci_test.go b/lanes/base/abci_test.go index 27b0c0b4..5801e414 100644 --- a/lanes/base/abci_test.go +++ b/lanes/base/abci_test.go @@ -45,8 +45,7 @@ func (s *BaseTestSuite) TestPrepareLane() { s.Require().NoError(err) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), int64(len(txBz)), 1, ) @@ -89,8 +88,7 @@ func (s *BaseTestSuite) TestPrepareLane() { MaxGasLimit: 10, } emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), limit.MaxTxBytes, limit.MaxGasLimit, ) @@ -134,8 +132,7 @@ func (s *BaseTestSuite) TestPrepareLane() { MaxGasLimit: 10, } emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), limit.MaxTxBytes, limit.MaxGasLimit, ) @@ -178,8 +175,7 @@ func (s *BaseTestSuite) TestPrepareLane() { MaxGasLimit: 10, } emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), limit.MaxTxBytes, limit.MaxGasLimit, ) @@ -219,8 +215,7 @@ func (s *BaseTestSuite) TestPrepareLane() { s.Require().NoError(err) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), int64(len(txBz)), 10, ) @@ -279,8 +274,7 @@ func (s *BaseTestSuite) TestPrepareLane() { size := int64(len(txBz1)) + int64(len(txBz2)) gasLimit := uint64(20) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), size, gasLimit, ) @@ -336,8 +330,7 @@ func (s *BaseTestSuite) TestPrepareLane() { size := int64(len(txBz1)) + int64(len(txBz2)) gasLimit := uint64(2) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), size, gasLimit, ) @@ -396,8 +389,7 @@ func (s *BaseTestSuite) TestPrepareLane() { size := int64(len(txBz1)) + int64(len(txBz2)) - 1 gasLimit := uint64(3) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), size, gasLimit, ) @@ -456,8 +448,7 @@ func (s *BaseTestSuite) TestPrepareLane() { size := int64(len(txBz1)) + int64(len(txBz2)) - 1 gasLimit := uint64(1) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), size, gasLimit, ) @@ -498,8 +489,7 @@ func (s *BaseTestSuite) TestPrepareLane() { s.Require().NoError(err) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), int64(len(txBz))*10, 1000000, ) @@ -556,7 +546,6 @@ func (s *BaseTestSuite) TestPrepareLane() { emptyProposal := proposals.NewProposal( log.NewNopLogger(), - s.encodingConfig.TxConfig.TxEncoder(), int64(len(txBz))*10, 1000000, ) @@ -610,8 +599,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -681,8 +669,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -764,8 +751,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -807,8 +793,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -850,8 +835,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -912,8 +896,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -964,8 +947,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -1021,8 +1003,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -1079,8 +1060,7 @@ func (s *BaseTestSuite) TestProcessLane() { s.Require().Len(remainingTxs, 0) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 100000, 100000, ) @@ -1119,8 +1099,7 @@ func (s *BaseTestSuite) TestProcessLane() { // Set the size to be 1 less than the size of the transaction maxSize := s.getTxSize(tx1) - 1 emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), maxSize, 1000000, ) @@ -1158,8 +1137,7 @@ func (s *BaseTestSuite) TestProcessLane() { maxSize := s.getTxSize(tx1) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), maxSize, 9, ) @@ -1209,8 +1187,7 @@ func (s *BaseTestSuite) TestProcessLane() { maxSize := s.getTxSize(tx1) + s.getTxSize(tx2) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), maxSize, 19, ) @@ -1260,8 +1237,7 @@ func (s *BaseTestSuite) TestProcessLane() { maxSize := s.getTxSize(tx1) + s.getTxSize(tx2) - 1 emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), maxSize, 20, ) @@ -1343,7 +1319,6 @@ func (s *BaseTestSuite) TestProcessLane() { emptyProposal := proposals.NewProposal( log.NewNopLogger(), - s.encodingConfig.TxConfig.TxEncoder(), 1000, 1000, ) @@ -1423,7 +1398,6 @@ func (s *BaseTestSuite) TestProcessLane() { emptyProposal := proposals.NewProposal( log.NewNopLogger(), - s.encodingConfig.TxConfig.TxEncoder(), 1000, 1000, ) @@ -1507,7 +1481,6 @@ func (s *BaseTestSuite) TestProcessLane() { emptyProposal := proposals.NewProposal( log.NewNopLogger(), - s.encodingConfig.TxConfig.TxEncoder(), 1000, 1000, ) @@ -1558,8 +1531,7 @@ func (s *BaseTestSuite) TestPrepareProcessParity() { // Construct a block proposal with the transactions in the mempool emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 1000000000000000, 1000000000000000, ) @@ -1579,8 +1551,7 @@ func (s *BaseTestSuite) TestPrepareProcessParity() { // Verify the same proposal with the process lanes handler emptyProposal = proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 1000000000000000, 1000000000000000, ) @@ -1638,8 +1609,7 @@ func (s *BaseTestSuite) TestIterateMempoolAndProcessProposalParity() { s.Require().Equal(len(txsToInsert), len(retrievedTxs)) emptyProposal := proposals.NewProposal( - log.NewTestLogger(s.T()), - s.encodingConfig.TxConfig.TxEncoder(), + log.NewNopLogger(), 1000000000000000, 1000000000000000, ) diff --git a/lanes/build-your-own/README.md b/lanes/build-your-own/README.md index d5ecc61c..0718b0cc 100644 --- a/lanes/build-your-own/README.md +++ b/lanes/build-your-own/README.md @@ -19,7 +19,7 @@ The Block SDK is designed to be modular and extensible. This means that developers can build their own lanes and customize the block building/verification logic to fit their needs. This guide will walk through the process of building a custom lane and configuring it in the application. Developers should -extend the base lane (`block/base/lane.go`) to build their own lanes. +extend the base lane [`block/base/lane.go`](../../block/base/README.md) to build their own lanes. There are **five** components to building a custom lane using the base lane: @@ -38,7 +38,7 @@ handler for processing transactions that are included in block proposals. This is the data structure that is responsible for storing transactions as they are being verified and are waiting to be included in proposals. -`block/base/mempool.go` provides an out-of-the-box implementation that should be +[`block/base/mempool.go`](../../block/base/mempool.go) provides an out-of-the-box implementation that should be used as a starting point for building out the mempool and should cover most use cases. To utilize the mempool, you must implement a `TxPriority[C]` struct that does the following: @@ -52,7 +52,7 @@ does the following: * Implements a `MinValue` method that returns the minimum priority value that a transaction can have. -The default implementation can be found in `block/base/mempool.go` - see `DefaultTxPriority`. +The default implementation can be found in [`block/base/mempool.go`](../../block/base/mempool.go) - see `DefaultTxPriority`. > Scenario What if we wanted to prioritize transactions by the amount they have staked on @@ -153,11 +153,10 @@ lane := base.NewBaseLane( ### 2. 🤝 MatchHandler `MatchHandler` is utilized to determine if a transaction should be included in -the lane. **This function can be a stateless or stateful check on the -transaction!** The default implementation can be found in `block/base/handlers.go`. +the lane. The default implementation can be found in `block/base/handlers.go`. The match handler can be as custom as desired. Following the example above, if -we wanted to make a lane that only accepts transactions if they have a large +we wanted to make a lane that only accepts staking transactions if they have a large amount staked, we could do the following: ```golang @@ -220,11 +219,24 @@ lane := base.NewBaseLane( ) ``` -### [OPTIONAL] Steps 3-5 +#### Considerations + +The default lane's match handler is a simple implementation that matches +any transaction. As such, it is important to note that the order in which +lanes are added to the `LanedMempool` matters. Transactions are only +considered for inclusion in the first lane that matches them. If no lanes +match the transaction, it will be rejected. + +To that, if you want to configure a lane that should come after the default +lane, we recommend you utilize the `NewMatchHandler` defined in +[`block/base/handlers.go`](../../block/base/handlers.go). This will allow you to +create a match handler that matches transactions that the default match handler does not match. + +### [OPTIONAL] Steps 3-4 The remaining steps walk through the process of creating custom block building/verification logic. The default implementation found in -`block/base/handlers.go` should fit most use cases. Please reference that file +[`block/base/handlers.go`](../../block/base/handlers.go) should fit most use cases. Please reference that file for more details on the default implementation and whether it fits your use case. Implementing custom block building/verification logic is a bit more involved @@ -235,19 +247,19 @@ you implement any of the handlers, you must implement all of them in most cases. ### 3. 🛠️ PrepareLaneHandler The `PrepareLaneHandler` is an optional field you can set on the base lane. -This handler is responsible for the transaction selection logic when a new proposal +This handler is responsible for the transaction selection and verification logic when a new proposal is requested. The handler should return the following for a given lane: 1. The transactions to be included in the block proposal. 2. The transactions to be removed from the lane's mempool. -3. An error if the lane is unable to prepare a block proposal. +3. An error if the lane is unable to prepare a block proposal. An error should only be returned if the lane is unable to prepare a block proposal due to an internal error. When collecting transactions to include in the block proposal, the handler must respect the lane limits - i.e. the maximum number of bytes and units of gas that the lane can use in the block proposal. This is defined in the -`limit proposals.LaneLimits` struct. +`proposals.LaneLimits` struct. ```golang type ( @@ -297,35 +309,41 @@ customLane := NewCustomLane( customLane.SetPrepareLaneHandler(customlane.PrepareLaneHandler()) ``` -See `lanes/mev/abci.go` for an example of how to set up a custom `PrepareLaneHandler`. +See [`lanes/mev/abci.go`](../mev/abci.go) for an example of how to set up a custom `PrepareLaneHandler`. ### 4. 🆗 ProcessLaneHandler The `ProcessLaneHandler` is an optional field you can set on the base lane. This handler is responsible for verifying the transactions in the block proposal -that belong to the lane. +that belong to the lane and returning transactions that do not belong to the lane. ```golang -// ProcessLaneHandler is responsible for processing transactions that are -// included in a block and belong to a given lane. This handler must return an -// error if the transactions are not correctly ordered, do not belong to this -// lane, or any other relevant error. -ProcessLaneHandler func(ctx sdk.Context, partialProposal []sdk.Tx) error +// ProcessLaneHandler is responsible for processing transactions that are included in a block and +// belong to a given lane. The handler must return the transactions that were successfully processed +// and the transactions that it cannot process because they belong to a different lane. +type ProcessLaneHandler func(ctx sdk.Context, partialProposal []sdk.Tx) ( + txsFromLane []sdk.Tx, + remainingTxs []sdk.Tx, + err error, +) ``` -The `partialProposal` is a slice of transactions that belong to the lane and -are included in the block proposal. The handler should return an error if the -transactions are not correctly ordered, do not belong to this lane, or any -other relevant error. +The `partialProposal` is a slice of transactions that may or may not belong to the lane and +are included in the block proposal. Transactions that belong to your lane _must_ be contiguous +from the start of the slice. All transactions that do not belong to your lane _must_ be contiguous +from the end of the slice. Given the description above, the default implementation is simple. It will continue to verify transactions in the block proposal under the following criteria: -1. All of the transactions included in `partialProposal` must belong to this -lane i.e. they must match the lane's `MatchHandler`. +1. All of the transactions included in `partialProposal` that _match_ the lane +must be continuous from the start of the slice. If they are interleaved with +transactions that do not match the lane, the handler will return an error. 2. All of the transactions must be ordered respecting the ordering rules of the mempool i.e. the transactions must be ordered by their priority which is defined -by the `TxPriority[C]` struct. +by the `TxPriority[C]` struct. Since the mempool is responsible for ordering +transactions, you can utilize the `Compare` method defined be the mempool to +verify the ordering of the transactions. 3. All of the transactions must be valid and pass the AnteHandler check. Similar to the setup of handlers above, if a more involved verification process @@ -346,7 +364,7 @@ customLane := NewCustomLane( customLane.SetProcessLaneHandler(customlane.ProcessLaneHandler()) ``` -See `lanes/mev/abci.go` for an example of how to set up a custom `ProcessLaneHandler`. +See [`lanes/mev/abci.go`](../mev/abci.go) for an example of how to set up a custom `ProcessLaneHandler`. ### 5. 📝 Lane Configuration @@ -365,7 +383,6 @@ config := base.LaneConfig{ AnteHandler: app.AnteHandler(), MaxTxs: 0, MaxBlockSpace: math.LegacyZeroDec(), - IgnoreList: []block.Lane{}, } ``` @@ -378,7 +395,7 @@ transactions as they are being considered for a new proposal or are being processed in a proposed block. We recommend user's utilize the same antehandler chain that is used in the base app. If developers want a certain `AnteDecorator` to be ignored if it qualifies for a given lane, they can do so by using the -`NewIgnoreDecorator` defined in `block/ante.go`. +`NewIgnoreDecorator` defined in [`block/ante.go`](../../block/ante.go). For example, a free lane might want to ignore the `DeductFeeDecorator` so that its transactions are not charged any fees. Where ever the `AnteHandler` is @@ -425,16 +442,6 @@ transactions as possible. If a block proposal request has a `MaxTxBytes` of 1000 and the lane has a `MaxBlockSpace` of 0.5, the lane will attempt to fill the block with 500 bytes. -#### **[OPTIONAL] IgnoreList** - -`IgnoreList` defines the list of lanes to ignore when processing transactions. -For example, say there are two lanes: default and free. The free lane is -processed after the default lane. In this case, the free lane should be added -to the ignore list of the default lane. Otherwise, the transactions that belong -to the free lane will be processed by the default lane (which accepts all -transactions by default). - - ### Set up Once you have created your custom lane, you can configure it in the application diff --git a/lanes/free/README.md b/lanes/free/README.md index 090a7655..3b5dbcd0 100644 --- a/lanes/free/README.md +++ b/lanes/free/README.md @@ -15,6 +15,8 @@ $ go install github.com/skip-mev/block-sdk ## 📚 Usage +> Note: Please visit [app.go](../../tests/app/lanes.go) to see a sample base app set up. + 1. First determine the set of lanes that you want to use in your application. The available lanes can be found in our [Lane App Store](https://docs.skip.money/chains/lanes/existing-lanes/default). @@ -49,8 +51,7 @@ func NewApp() { // 1. Create the lanes. // // NOTE: The lanes are ordered by priority. The first lane is the highest priority - // lane and the last lane is the lowest priority lane. Top of block lane allows - // transactions to bid for inclusion at the top of the next block. + // lane and the last lane is the lowest priority lane. // // For more information on how to utilize the LaneConfig please // visit the README in docs.skip.money/chains/lanes/build-your-own-lane#-lane-config. @@ -73,14 +74,14 @@ func NewApp() { MaxBlockSpace: math.LegacyZeroDec(), MaxTxs: 0, } - defaultLane := defaultlane.NewDefaultLane(defaultConfig) + defaultLane := defaultlane.NewDefaultLane(defaultConfig, base.DefaultMatchHandler()) // 2. Set up the relative priority of lanes lanes := []block.Lane{ freeLane, defaultLane, } - mempool := block.NewLanedMempool(app.Logger(), true, lanes...) + mempool := block.NewLanedMempool(app.Logger(), lanes) app.App.SetMempool(mempool) ... diff --git a/lanes/mev/README.md b/lanes/mev/README.md index 2e959d49..0ffb1996 100644 --- a/lanes/mev/README.md +++ b/lanes/mev/README.md @@ -15,11 +15,13 @@ $ go install github.com/skip-mev/block-sdk ## 📚 Usage +> Note: Please visit [app.go](../../tests/app/lanes.go) to see a sample base app set up. + 1. This guide assumes you have already set up the [Block SDK (and the default lane)](https://docs.skip.money/chains/overview) 2. You will need to instantiate the `x/auction` module into your application. This module is responsible for processing auction transactions and distributing revenue to the auction house. The `x/auction` module is also responsible for ensuring the -validity of auction transactions. *The `x/auction` module should not exist on its +validity of auction transactions. The `x/auction` module should not exist on its own. **This is the most intensive part of the set up process.** 3. Next, add the MEV lane into the `lane` object on your `app.go`. The first lane is the highest priority lane and the last lane is the lowest priority lane. @@ -137,7 +139,7 @@ NOTE: This example walks through setting up the MEV and Default lanes. MaxBlockSpace: math.LegacyZeroDec(), MaxTxs: 0, } - defaultLane := base.NewStandardLane(defaultConfig) + defaultLane := base.NewStandardLane(defaultConfig, base.DefaultMatchHandler()) // 2. Set up the relative priority of lanes lanes := []block.Lane{ diff --git a/lanes/mev/abci_test.go b/lanes/mev/abci_test.go index 3e4635c1..b4649148 100644 --- a/lanes/mev/abci_test.go +++ b/lanes/mev/abci_test.go @@ -16,7 +16,7 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Run("can prepare a lane with no txs in mempool", func() { lane := s.initLane(math.LegacyOneDec(), nil) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) proposal, err := lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -42,7 +42,7 @@ func (s *MEVTestSuite) TestPrepareLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) s.Require().NoError(lane.Insert(s.ctx, bidTx)) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -84,7 +84,7 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().NoError(lane.Insert(s.ctx, bidTx1)) s.Require().NoError(lane.Insert(s.ctx, bidTx2)) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000) + proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -126,7 +126,7 @@ func (s *MEVTestSuite) TestPrepareLane() { s.Require().NoError(lane.Insert(s.ctx, bidTx1)) s.Require().NoError(lane.Insert(s.ctx, bidTx2)) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000) + proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -156,7 +156,7 @@ func (s *MEVTestSuite) TestPrepareLane() { 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.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000) + proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 100000) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -187,7 +187,7 @@ func (s *MEVTestSuite) TestPrepareLane() { 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.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 100000) + proposal := proposals.NewProposal(log.NewNopLogger(), s.getTxSize(bidTx), 100000) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -212,7 +212,7 @@ func (s *MEVTestSuite) TestPrepareLane() { lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true}) s.Require().NoError(lane.Insert(s.ctx, bidTx)) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 99) + proposal := proposals.NewProposal(log.NewNopLogger(), s.getTxSize(bidTx), 99) proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler()) s.Require().NoError(err) @@ -228,7 +228,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Run("can process an empty proposal", func() { lane := s.initLane(math.LegacyOneDec(), nil) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) txsFromLane, remainingTxs, err := lane.ProcessLaneHandler()(s.ctx, nil) s.Require().NoError(err) @@ -245,7 +245,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().NoError(err) lane := s.initLane(math.LegacyOneDec(), nil) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) txsFromLane, remainingTxs, err := lane.ProcessLaneHandler()(s.ctx, []sdk.Tx{tx}) s.Require().NoError(err) @@ -278,7 +278,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -304,7 +304,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -330,7 +330,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -356,7 +356,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -382,7 +382,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) }) @@ -408,7 +408,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(1, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) }) @@ -434,7 +434,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 20000, 99) + proposal := proposals.NewProposal(log.NewNopLogger(), 20000, 99) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -460,7 +460,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(3, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -490,7 +490,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(1, len(remainingTxs)) s.Require().Equal(otherTx, remainingTxs[0]) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) proposal, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().NoError(err) s.Require().Len(proposal.Txs, 3) @@ -524,7 +524,7 @@ func (s *MEVTestSuite) TestProcessLane() { s.Require().Equal(0, len(txsFromLane)) s.Require().Equal(0, len(remainingTxs)) - proposal := proposals.NewProposal(log.NewNopLogger(), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000) + proposal := proposals.NewProposal(log.NewNopLogger(), 200000, 1000000) _, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler()) s.Require().Error(err) }) @@ -532,7 +532,7 @@ func (s *MEVTestSuite) TestProcessLane() { func (s *MEVTestSuite) TestVerifyBidBasic() { lane := s.initLane(math.LegacyOneDec(), nil) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), 200, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) s.Run("can verify a bid with no bundled txs", func() { @@ -596,7 +596,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() { s.Require().NoError(err) size := s.getTxSize(bidTx) - proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), size-1, 100) + proposal := proposals.NewProposal(log.NewNopLogger(), size-1, 100) limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace()) _, err = lane.VerifyBidBasic(s.ctx, bidTx, proposal, limits) diff --git a/lanes/terminator/lane.go b/lanes/terminator/lane.go index e74f3036..8aed74a3 100644 --- a/lanes/terminator/lane.go +++ b/lanes/terminator/lane.go @@ -79,9 +79,6 @@ func (t Terminator) GetTxInfo(_ sdk.Context, _ sdk.Tx) (utils.TxWithInfo, error) // SetAnteHandler is a no-op func (t Terminator) SetAnteHandler(sdk.AnteHandler) {} -// SetIgnoreList is a no-op -func (t Terminator) SetIgnoreList([]block.Lane) {} - // Match is a no-op func (t Terminator) Match(sdk.Context, sdk.Tx) bool { return false