Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skip mev block sdk integration #79

Merged
merged 2 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions app/abci_check_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

abci "github.com/cometbft/cometbft/abci/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/skip-mev/block-sdk/v2/abci/checktx"
"github.com/sunriselayer/sunrise/pkg/blob"
blobtypes "github.com/sunriselayer/sunrise/x/blob/types"
)
Expand All @@ -31,7 +32,7 @@ func (app *App) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error)
return sdkerrors.ResponseCheckTxWithEvents(blobtypes.ErrNoBlobs, 0, 0, []abci.Event{}, false), blobtypes.ErrNoBlobs
}
// don't do anything special if we have a normal transaction
return app.BaseApp.CheckTx(req)
return app.checkTxHandler(req)
}

switch req.Type {
Expand All @@ -47,5 +48,10 @@ func (app *App) CheckTx(req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error)
}

req.Tx = btx.Tx
return app.BaseApp.CheckTx(req)
return app.checkTxHandler(req)
}

// SetCheckTx sets the checkTxHandler for the app.
func (app *App) SetCheckTx(handler checktx.CheckTx) {
app.checkTxHandler = handler
}
10 changes: 9 additions & 1 deletion app/abci_prepare_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func (app *App) NewProposalContext(header cmtproto.Header) sdk.Context {
func (app *App) PrepareProposal(req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) {
defer telemetry.MeasureSince(time.Now(), "prepare_proposal")

res, err := app.BaseApp.PrepareProposal(req)
if err != nil {
panic(err)
}

// create a context using a branch of the state and loaded using the
// proposal height and chain-id
sdkCtx := app.NewProposalContext(cmtproto.Header{
Expand All @@ -56,6 +61,9 @@ func (app *App) PrepareProposal(req *abci.RequestPrepareProposal) (*abci.Respons
app.txConfig.SignModeHandler(),
ante.DefaultSigVerificationGasConsumer,
app.IBCKeeper,
app.auctionkeeper,
app.mevLane,
app.txConfig.TxEncoder(),
)

var txs [][]byte
Expand All @@ -74,7 +82,7 @@ func (app *App) PrepareProposal(req *abci.RequestPrepareProposal) (*abci.Respons
if app.LastBlockHeight() == 0 {
txs = make([][]byte, 0)
} else {
txs = FilterTxs(app.Logger(), sdkCtx, handler, app.txConfig, req.Txs)
txs = FilterTxs(app.Logger(), sdkCtx, handler, app.txConfig, res.Txs)
}

// build the square from the set of valid and prioritised transactions.
Expand Down
8 changes: 8 additions & 0 deletions app/abci_process_proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (app *App) ProcessProposal(req *abci.RequestProcessProposal) (retResp *abci
}
}()

res, err := app.BaseApp.ProcessProposal(req)
if err != nil {
return res, err
}

// Create the anteHander that are used to check the validity of
// transactions. All transactions need to be equally validated here
// so that the nonce number is always correctly incremented (which
Expand All @@ -51,6 +56,9 @@ func (app *App) ProcessProposal(req *abci.RequestProcessProposal) (retResp *abci
app.txConfig.SignModeHandler(),
ante.DefaultSigVerificationGasConsumer,
app.IBCKeeper,
app.auctionkeeper,
app.mevLane,
app.txConfig.TxEncoder(),
)
sdkCtx := app.NewProposalContext(cmtproto.Header{
ChainID: app.ChainID(),
Expand Down
6 changes: 6 additions & 0 deletions app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante"
ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper"

auctionante "github.com/skip-mev/block-sdk/v2/x/auction/ante"
auctionkeeper "github.com/skip-mev/block-sdk/v2/x/auction/keeper"
feeante "github.com/sunriselayer/sunrise/x/fee/ante"
)

Expand All @@ -24,6 +26,9 @@ func NewAnteHandler(
signModeHandler *signing.HandlerMap,
sigGasConsumer ante.SignatureVerificationGasConsumer,
channelKeeper *ibckeeper.Keeper,
auctionkeeper auctionkeeper.Keeper,
MEVLane auctionante.MEVLane,
TxEncoder sdk.TxEncoder,
) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
// Wraps the panic with the string format of the transaction
Expand Down Expand Up @@ -69,6 +74,7 @@ func NewAnteHandler(
ante.NewIncrementSequenceDecorator(accountKeeper),
// Ensure that the tx is not a IBC packet or update message that has already been processed.
ibcante.NewRedundantRelayDecorator(channelKeeper),
auctionante.NewAuctionDecorator(auctionkeeper, TxEncoder, MEVLane),
)
}

Expand Down
113 changes: 113 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ import (
ibcfeekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper"
ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper"
ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper"
"github.com/skip-mev/block-sdk/v2/abci"
"github.com/skip-mev/block-sdk/v2/abci/checktx"
"github.com/skip-mev/block-sdk/v2/block"
"github.com/skip-mev/block-sdk/v2/block/base"
"github.com/skip-mev/block-sdk/v2/block/service"
mevlane "github.com/skip-mev/block-sdk/v2/lanes/mev"
auctionkeeper "github.com/skip-mev/block-sdk/v2/x/auction/keeper"
"github.com/sunriselayer/sunrise/app/ante"

banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
Expand Down Expand Up @@ -123,6 +131,7 @@ type App struct {
GroupKeeper groupkeeper.Keeper
ConsensusParamsKeeper consensuskeeper.Keeper
CircuitBreakerKeeper circuitkeeper.Keeper
auctionkeeper auctionkeeper.Keeper

// IBC
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
Expand All @@ -149,6 +158,10 @@ type App struct {

// simulation manager
sm *module.SimulationManager

// custom structure for skip-mev protection
mevLane *mevlane.MEVLane
checkTxHandler checktx.CheckTx
}

func init() {
Expand Down Expand Up @@ -357,6 +370,88 @@ func New(

/**** Module Options ****/

// ---------------------------------------------------------------------------- //
// ------------------------- Begin `Skip MEV` Code ---------------------------- //
// ---------------------------------------------------------------------------- //
// STEP 1-3: Create the Block SDK lanes.
mevLane, freeLane, defaultLane := CreateLanes(app)

// STEP 4: Construct a mempool based off the lanes. Note that the order of the lanes
// matters. Blocks are constructed from the top lane to the bottom lane. The top lane
// is the first lane in the array and the bottom lane is the last lane in the array.
mempool, err := block.NewLanedMempool(
app.Logger(),
[]block.Lane{mevLane, freeLane, defaultLane},
)
if err != nil {
panic(err)
}

// The application's mempool is now powered by the Block SDK!
app.App.SetMempool(mempool)

// STEP 5: Create a global ante handler that will be called on each transaction when
// proposals are being built and verified. Note that this step must be done before
// setting the ante handler on the lanes.
anteHandler := ante.NewAnteHandler(
app.AccountKeeper,
app.BankKeeper,
app.FeeGrantKeeper,
app.BlobKeeper,
app.FeeKeeper,
app.txConfig.SignModeHandler(),
ante.DefaultSigVerificationGasConsumer,
app.IBCKeeper,
app.auctionkeeper,
mevLane,
app.txConfig.TxEncoder(),
)
// Set the ante handler on the lanes.
opt := []base.LaneOption{
base.WithAnteHandler(anteHandler),
}
mevLane.WithOptions(
opt...,
)
freeLane.WithOptions(
opt...,
)
defaultLane.WithOptions(
opt...,
)

app.mevLane = mevLane

// Step 6: Create the proposal handler and set it on the app. Now the application
// will build and verify proposals using the Block SDK!
proposalHandler := abci.NewProposalHandler(
app.Logger(),
app.txConfig.TxDecoder(),
app.txConfig.TxEncoder(),
mempool,
)
app.App.SetPrepareProposal(proposalHandler.PrepareProposalHandler())
app.App.SetProcessProposal(proposalHandler.ProcessProposalHandler())

// Step 7: Set the custom CheckTx handler on BaseApp. This is only required if you
// use the MEV lane.
mevCheckTx := checktx.NewMEVCheckTxHandler(
app.App,
app.txConfig.TxDecoder(),
mevLane,
anteHandler,
app.App.CheckTx,
)
checkTxHandler := checktx.NewMempoolParityCheckTx(
app.Logger(), mempool,
app.txConfig.TxDecoder(), mevCheckTx.CheckTx(),
)

app.SetCheckTx(checkTxHandler.CheckTx())
// ---------------------------------------------------------------------------- //
// ------------------------- End `Skip MEV` Code ------------------------------ //
// ---------------------------------------------------------------------------- //

app.ModuleManager.RegisterInvariants(app.CrisisKeeper)

// add test gRPC service for testing gRPC queries in isolation
Expand Down Expand Up @@ -452,7 +547,12 @@ func (app *App) SimulationManager() *module.SimulationManager {
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
// Register the base app API routes.
app.App.RegisterAPIRoutes(apiSvr, apiConfig)

// Register the Block SDK mempool API routes.
service.RegisterGRPCGatewayRoutes(apiSvr.ClientCtx, apiSvr.GRPCGatewayRouter)

// register swagger API in app.go so that other applications can override easily
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
panic(err)
Expand All @@ -462,6 +562,19 @@ func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig
docs.RegisterOpenAPIService(Name, apiSvr.Router)
}

// RegisterTxService implements the Application.RegisterTxService method.
func (app *App) RegisterTxService(clientCtx client.Context) {
// Register the base app transaction service.
app.App.RegisterTxService(clientCtx)

// Register the Block SDK mempool transaction service.
mempool, ok := app.App.Mempool().(block.Mempool)
if !ok {
panic("mempool is not a block.Mempool")
}
service.RegisterMempoolService(app.GRPCQueryRouter(), mempool)
}

// GetIBCKeeper returns the IBC keeper.
func (app *App) GetIBCKeeper() *ibckeeper.Keeper {
return app.IBCKeeper
Expand Down
94 changes: 94 additions & 0 deletions app/lanes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package app

import (
"cosmossdk.io/math"

signerextraction "github.com/skip-mev/block-sdk/v2/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/v2/block/base"
defaultlane "github.com/skip-mev/block-sdk/v2/lanes/base"
freelane "github.com/skip-mev/block-sdk/v2/lanes/free"
mevlane "github.com/skip-mev/block-sdk/v2/lanes/mev"
)

// CreateLanes walks through the process of creating the lanes for the block sdk. In this function
// 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 *App) (*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()

// 2. Create the configurations for each lane. These configurations determine how many
// transactions the lane can store, the maximum block space the lane can consume, and
// the signer extractor used to extract the expected signers from a transaction.
//
// IMPORTANT NOTE: If the block sdk module is utilized to store lanes, than the maximum
// block space will be replaced with what is in state / in the genesis file.

// Create a mev configuration that accepts 1000 transactions and consumes 20% of the
// block space.
mevConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyMustNewDecFromStr("0.2"),
SignerExtractor: signerAdapter,
MaxTxs: 1000,
}

// Create a free configuration that accepts 1000 transactions and consumes 20% of the
// block space.
freeConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyMustNewDecFromStr("0.2"),
SignerExtractor: signerAdapter,
MaxTxs: 1000,
}

// Create a default configuration that accepts 1000 transactions and consumes 60% of the
// block space.
defaultConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyMustNewDecFromStr("0.6"),
SignerExtractor: signerAdapter,
MaxTxs: 1000,
}

// 3. Create the match handlers for each lane. These match handlers determine whether or not
// a transaction belongs in the lane.

// Create the final match handler for the mev lane.
factory := mevlane.NewDefaultAuctionFactory(app.txConfig.TxDecoder(), signerAdapter)
mevMatchHandler := factory.MatchHandler()

// Create the final match handler for the free lane.
freeMatchHandler := freelane.DefaultMatchHandler()

// Create the final match handler for the default lane.
defaultMatchHandler := base.DefaultMatchHandler()

// 4. Create the lanes.
mevLane := mevlane.NewMEVLane(
mevConfig,
factory,
mevMatchHandler,
)

freeLane := freelane.NewFreeLane(
freeConfig,
base.DefaultTxPriority(),
freeMatchHandler,
)

defaultLane := defaultlane.NewDefaultLane(
defaultConfig,
defaultMatchHandler,
)

return mevLane, freeLane, defaultLane
}
Loading
Loading