diff --git a/lanes/base/README.md b/lanes/base/README.md index 48c7399..4f80073 100644 --- a/lanes/base/README.md +++ b/lanes/base/README.md @@ -17,19 +17,19 @@ $ go install github.com/skip-mev/block-sdk 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). This guide -only sets up the `default lane` -2. In your base application, you will need to create a `LanedMempool` composed of the -`lanes` you want to use. +[Lane App Store](https://docs.skip.money/chains/lanes/existing-lanes/default). +This guide only sets up the `default lane` +2. In your base application, you will need to create a `LanedMempool` composed +of the `lanes` you want to use. 3. Next, order the lanes by priority. The first lane is the highest priority lane and the last lane is the lowest priority lane. **It is recommended that the last lane is the default lane.** -3. You will also need to create a `PrepareProposalHandler` and a +4. You will also need to create a `PrepareProposalHandler` and a `ProcessProposalHandler` that will be responsible for preparing and processing proposals respectively. Configure the order of the lanes in the `PrepareProposalHandler` and `ProcessProposalHandler` to match the order of the lanes in the `LanedMempool`. -4. Configure your `app.go` to include the following: +5. Configure your `app.go` to include the following: ```golang import ( diff --git a/lanes/base/lane.go b/lanes/base/lane.go index 136284f..9842592 100644 --- a/lanes/base/lane.go +++ b/lanes/base/lane.go @@ -22,7 +22,7 @@ type DefaultLane struct { *base.BaseLane } -// NewStandardLane returns a new default lane. +// NewDefaultLane returns a new default lane. func NewDefaultLane(cfg base.LaneConfig) *DefaultLane { lane := base.NewBaseLane( cfg, diff --git a/lanes/build-your-own/README.md b/lanes/build-your-own/README.md index 83b295c..f025adf 100644 --- a/lanes/build-your-own/README.md +++ b/lanes/build-your-own/README.md @@ -13,36 +13,48 @@ To install the Block SDK, run the following command: $ go install github.com/skip-mev/block-sdk ``` -## 🤔 How to use it [1 hour] +## 🤔 How to use it [30 min] There are **five** required components to building a custom lane using the base lane: -1. `Mempool` - The lane's mempool is responsible for storing transactions that have been verified and are waiting to be included in proposals. -2. `MatchHandler` - This is responsible for determining whether a transaction should belong to this lane. -3. [**OPTIONAL**] `PrepareLaneHandler` - Allows developers to define their own handler to customize the how transactions are verified and ordered before they are included into a proposal. -4. [**OPTIONAL**] `CheckOrderHandler` - Allows developers to define their own handler that will run any custom checks on whether transactions included in block proposals are in the correct order (respecting the ordering rules of the lane and the ordering rules of the other lanes). -5. [**OPTIONAL**] `ProcessLaneHandler` - Allows developers to define their own handler for processing transactions that are included in block proposals. +1. `Mempool` - The lane's mempool is responsible for storing transactions that +have been verified and are waiting to be included in proposals. +2. `MatchHandler` - This is responsible for determining whether a transaction +should belong to this lane. +3. [**OPTIONAL**] `PrepareLaneHandler` - Allows developers to define their own +handler to customize the how transactions are verified and ordered before they +are included into a proposal. +4. [**OPTIONAL**] `CheckOrderHandler` - Allows developers to define their own +handler that will run any custom checks on whether transactions included in +block proposals are in the correct order (respecting the ordering rules of the +lane and the ordering rules of the other lanes). +5. [**OPTIONAL**] `ProcessLaneHandler` - Allows developers to define their own +handler for processing transactions that are included in block proposals. 6. `Configuration` - Configure high-level options for your lane. ### 1. 🗄️ Mempool -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 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: +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 +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: -- Implements a `GetTxPriority` method that returns the priority (as defined +* Implements a `GetTxPriority` method that returns the priority (as defined by the type `[C]`) of a given transaction. -- Implements a `Compare` method that returns the relative priority of two +* Implements a `Compare` method that returns the relative priority of two transactions. If the first transaction has a higher priority, the method should return -1, if the second transaction has a higher priority the method should return 1, otherwise the method should return 0. -- Implements a `MinValue` method that returns the minimum priority value +* 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`. -:::info Scenario -What if we wanted to prioritize transactions by the amount they have staked on a chain? - -::: +> Scenario +What if we wanted to prioritize transactions by the amount they have staked on +a chain? We could do the following: @@ -100,7 +112,8 @@ func (p *CustomTxPriority) CustomTxPriority() TxPriority[string] { #### Using a Custom TxPriority -To utilize this new priority configuration in a lane, all you have to then do is pass in the `TxPriority[C]` to the `NewMempool` function. +To utilize this new priority configuration in a lane, all you have to then do +is pass in the `TxPriority[C]` to the `NewMempool` function. ```golang // Create the lane config @@ -136,9 +149,13 @@ 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`. +`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 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 amount staked, we could do the following: +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 +amount staked, we could do the following: ```golang // CustomMatchHandler returns a custom implementation of the MatchHandler. It @@ -173,7 +190,8 @@ func (h *Handler) CustomMatchHandler() block.MatchHandler { #### Using a Custom MatchHandler -If we wanted to create the lane using the custom match handler along with the custom mempool, we could do the following: +If we wanted to create the lane using the custom match handler along with the +custom mempool, we could do the following: ```golang // Pseudocode for creating the custom match handler @@ -201,9 +219,15 @@ lane := base.NewBaseLane( ### [OPTIONAL] Steps 3-5 -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 for more details on the default implementation and whether it fits your use case. +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 +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 than the previous steps and is a all or nothing approach. This means that if you implement any of the handlers, you must implement all of them in most cases. If you do not implement all of them, the lane may have unintended behavior. +Implementing custom block building/verification logic is a bit more involved +than the previous steps and is a all or nothing approach. This means that if +you implement any of the handlers, you must implement all of them in most cases. + If you do not implement all of them, the lane may have unintended behavior. ### 3. 🛠️ PrepareLaneHandler @@ -226,13 +250,15 @@ PrepareLaneHandler func(ctx sdk.Context,proposal BlockProposal,maxTxBytes int64) (txsToInclude [][]byte, txsToRemove []sdk.Tx, err error) ``` -The default implementation is simple. It will continue to select transactions from its mempool under the following criteria: +The default implementation is simple. It will continue to select transactions +from its mempool under the following criteria: 1. The transactions is not already included in the block proposal. 2. The transaction is valid and passes the AnteHandler check. 3. The transaction is not too large to be included in the block. -If a more involved selection process is required, you can implement your own `PrepareLaneHandler` and and set it after creating the base lane. +If a more involved selection process is required, you can implement your own +`PrepareLaneHandler` and and set it after creating the base lane. ```golang // Pseudocode for creating the custom prepare lane handler @@ -250,7 +276,9 @@ customLane.SetPrepareLaneHandler(customlane.PrepareLaneHandler()) ### 4. ✅ CheckOrderHandler -The `CheckOrderHandler` is an optional field you can set on the base lane. This handler is responsible for verifying the ordering of the transactions in the block proposal that belong to the lane. +The `CheckOrderHandler` is an optional field you can set on the base lane. +This handler is responsible for verifying the ordering of the transactions in +the block proposal that belong to the lane. ```golang // CheckOrderHandler is responsible for checking the order of transactions that @@ -262,12 +290,20 @@ The `CheckOrderHandler` is an optional field you can set on the base lane. This CheckOrderHandler func(ctx sdk.Context, txs []sdk.Tx) error ``` -The default implementation is simple and utilizes the same `TxPriority` struct that the mempool uses to determine if transactions are in order. The criteria for determining if transactions are in order is as follows: +The default implementation is simple and utilizes the same `TxPriority` struct +that the mempool uses to determine if transactions are in order. The criteria +for determining if transactions are in order is as follows: -1. The transactions are in order according to the `TxPriority` struct. i.e. any two transactions (that match to the lane) `tx1` and `tx2` where `tx1` has a higher priority than `tx2` should be ordered before `tx2`. -2. The transactions are contiguous. i.e. there are no transactions from other lanes in between the transactions that belong to this lane. i.e. if `tx1` and `tx2` belong to the lane, there should be no transactions from other lanes in between `tx1` and `tx2`. +1. The transactions are in order according to the `TxPriority` struct. i.e. +any two transactions (that match to the lane) `tx1` and `tx2` where `tx1` has a +higher priority than `tx2` should be ordered before `tx2`. +2. The transactions are contiguous. i.e. there are no transactions from other +lanes in between the transactions that belong to this lane. i.e. if `tx1` and +`tx2` belong to the lane, there should be no transactions from other lanes in +between `tx1` and `tx2`. -If a more involved ordering process is required, you can implement your own `CheckOrderHandler` and and set it after creating the base lane. +If a more involved ordering process is required, you can implement your own +`CheckOrderHandler` and and set it after creating the base lane. ```golang // Pseudocode for creating the custom check order handler @@ -285,7 +321,14 @@ customLane.SetCheckOrderHandler(customlane.CheckOrderHandler()) ### 5. 🆗 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. This handler is executed after the `CheckOrderHandler` so the transactions passed into this function SHOULD already be in order respecting the ordering rules of the lane and respecting the ordering rules of mempool relative to the lanes it has. This means that if the first transaction does not belong to the lane, the remaining transactions should not belong to the lane either. +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. This handler is executed after the `CheckOrderHandler` +so the transactions passed into this function SHOULD already be in order +respecting the ordering rules of the lane and respecting the ordering rules of +mempool relative to the lanes it has. This means that if the first transaction +does not belong to the lane, the remaining transactions should not belong to +the lane either. ```golang // ProcessLaneHandler is responsible for processing transactions that are @@ -296,12 +339,17 @@ The `ProcessLaneHandler` is an optional field you can set on the base lane. This ProcessLaneHandler func(ctx sdk.Context, txs []sdk.Tx) ([]sdk.Tx, error) ``` -Given the invarients above, the default implementation is simple. It will continue to verify transactions in the block proposal under the following criteria: +Given the invarients above, the default implementation is simple. It will +continue to verify transactions in the block proposal under the following criteria: -1. If a transaction matches to this lane, verify it and continue. If it is not valid, return an error. -2. If a transaction does not match to this lane, return the remaining transactions to the next lane to process. +1. If a transaction matches to this lane, verify it and continue. If it is not +valid, return an error. +2. If a transaction does not match to this lane, return the remaining +transactions to the next lane to process. -Similar to the setup of handlers above, if a more involved verification process is required, you can implement your own `ProcessLaneHandler` and and set it after creating the base lane. +Similar to the setup of handlers above, if a more involved verification process +is required, you can implement your own `ProcessLaneHandler` and and set it +after creating the base lane. ```golang // Pseudocode for creating the custom check order handler @@ -319,16 +367,23 @@ customLane.SetProcessLaneHandler(customlane.ProcessLaneHandler()) ### 6. 📝 Lane Configuration -Once you have created your custom lane, you can configure it in the application by doing the following: +Once you have created your custom lane, you can configure it in the application +by doing the following: 1. Create a custom `LaneConfig` struct that defines the configuration of the lane. -2. Instantiate the lane with the custom `LaneConfig` struct alongside any other dependencies (mempool, match handler, etc.). +2. Instantiate the lane with the custom `LaneConfig` struct alongside any other +dependencies (mempool, match handler, etc.). 3. Instantiate a new `LanedMempool` with the custom lane. 4. Set the `LanedMempool` on the `BaseApp` instance. 5. Set up the proposal handlers of the Block SDK to use your lane. 6. That's it! You're done! -The lane config (`LaneConfig`) is a simple configuration object that defines the desired amount of block space the lane should utilize when building a proposal, an antehandler that is used to verify transactions as they are added/verified to/in a proposal, and more. By default, we recommend that user's pass in all of the base apps configurations (txDecoder, logger, etc.). A sample `LaneConfig` might look like the following: +The lane config (`LaneConfig`) is a simple configuration object that defines +the desired amount of block space the lane should utilize when building a +proposal, an antehandler that is used to verify transactions as they are +added/verified to/in a proposal, and more. By default, we recommend that user's +pass in all of the base apps configurations (txDecoder, logger, etc.). A sample +`LaneConfig` might look like the following: ```golang config := block.LaneConfig{ @@ -346,9 +401,16 @@ The three most important parameters to set are the `AnteHandler`, `MaxTxs`, and #### **AnteHandler** -With the default implementation, the `AnteHandler` is responsible for verifying 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/utils/ante.go`. +With the default implementation, the `AnteHandler` is responsible for verifying +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/utils/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 defined, we could add the following to ignore the `DeductFeeDecorator`: +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 +defined, we could add the following to ignore the `DeductFeeDecorator`: ```golang anteDecorators := []sdk.AnteDecorator{ @@ -367,22 +429,35 @@ anteDecorators := []sdk.AnteDecorator{ } ``` -Anytime a transaction that qualifies for the free lane is being processed, the `DeductFeeDecorator` will be ignored and no fees will be deducted! +Anytime a transaction that qualifies for the free lane is being processed, the +`DeductFeeDecorator` will be ignored and no fees will be deducted! #### **MaxTxs** This sets the maximum number of transactions allowed in the mempool with the semantics: -- if `MaxTxs` == 0, there is no cap on the number of transactions in the mempool -- if `MaxTxs` > 0, the mempool will cap the number of transactions it stores, and will prioritize transactions by their priority and sender-nonce (sequence number) when evicting transactions. -- if `MaxTxs` < 0, `Insert` is a no-op. +* if `MaxTxs` == 0, there is no cap on the number of transactions in the mempool +* if `MaxTxs` > 0, the mempool will cap the number of transactions it stores, +and will prioritize transactions by their priority and sender-nonce +(sequence number) when evicting transactions. +* if `MaxTxs` < 0, `Insert` is a no-op. #### **MaxBlockSpace** -MaxBlockSpace is the maximum amount of block space that the lane will attempt to fill when building a proposal. This parameter may be useful lanes that should be limited (such as a free or onboarding lane) in space usage. Setting this to 0 will allow the lane to fill the block with as many transactions as possible. +MaxBlockSpace is the maximum amount of block space that the lane will attempt +to fill when building a proposal. This parameter may be useful lanes that +should be limited (such as a free or onboarding lane) in space usage. +Setting this to 0 will allow the lane to fill the block with as many +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. +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). +`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). diff --git a/lanes/mev/README.md b/lanes/mev/README.md index cbbd248..17258b8 100644 --- a/lanes/mev/README.md +++ b/lanes/mev/README.md @@ -21,10 +21,10 @@ module is responsible for processing auction transactions and distributing reven to the auction house. The `x/builder` module is also responsible for ensuring the validity of auction transactions. *The `x/builder` 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. Since the MEV lane is meant to auction -off the top of the block, **it should be the highest priority lane**. The default lane -should follow. +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. +Since the MEV lane is meant to auction off the top of the block, **it should be +the highest priority lane**. The default lane should follow. 4. You will also need to create a `PrepareProposalHandler` and a `ProcessProposalHandler` that will be responsible for preparing and processing proposals respectively. Configure the order of the lanes in the @@ -77,7 +77,7 @@ NOTE: This example walks through setting up the MEV and Default lanes. a. First add the keeper to the app's struct definition. We also want to add MEV lane's custom checkTx handler to the app's struct definition. This will - allow us to override the default checkTx handler to process bid transactions + allow us to override the default checkTx handler to process bid transactions before they are inserted into the `LanedMempool`. NOTE: The custom handler is required as otherwise the auction can be held hostage by a malicious users. diff --git a/lanes/mev/check_tx.go b/lanes/mev/check_tx.go index ab18630..dbe890b 100644 --- a/lanes/mev/check_tx.go +++ b/lanes/mev/check_tx.go @@ -63,7 +63,7 @@ type ( } ) -// NewCheckTxHandler is a base for CheckTxHandler. +// NewCheckTxHandler constructs a new CheckTxHandler instance. func NewCheckTxHandler( baseApp BaseApp, txDecoder sdk.TxDecoder, diff --git a/lanes/mev/lane.go b/lanes/mev/lane.go index 2457352..d3da91b 100644 --- a/lanes/mev/lane.go +++ b/lanes/mev/lane.go @@ -31,7 +31,6 @@ type ( } MEVLane struct { //nolint - // LaneConfig defines the base lane configuration. *base.BaseLane // Factory defines the API/functionality which is responsible for determining diff --git a/tests/app/app.go b/tests/app/app.go index ad953e6..8185791 100644 --- a/tests/app/app.go +++ b/tests/app/app.go @@ -262,7 +262,7 @@ func New( // // 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. + // MEV lane allows transactions to bid for inclusion at the top of the next block. mevConfig := base.LaneConfig{ Logger: app.Logger(), TxEncoder: app.txConfig.TxEncoder(),