block

package
v1.3.0-alpha.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2023 License: Apache-2.0 Imports: 8 Imported by: 2

README

Block SDK Mempool & Lanes

Overview

This document describes how the Block SDK mempool and lanes operate at a high level. To learn more about how to construct lanes, please visit the build my own lane readme and/or the base lane documentation. To read about how proposals are construct, visit the abci readme.

Mempools are traditionally used to temporarily store transactions before they are added to a block. The Block SDK mempool is no different. However, instead of treating each transaction the same, the Block SDK allows for developers to create Lanes that permit transactions to be ordered differently based on the properties of the transaction itself.

What was once a single monolithic data structure, is now a collection of sub-mempools that can be configured to order transactions in a way that makes sense for the application.

Lanes

Lanes are utilized to allow developers to create custom transaction order, validation, and execution logic. Each lane is responsible for maintaining its own mempool - ordering transactions as it desires only for the transactions it wants to accept. For example, a lane may only accept transactions that are staking related, such as the free lane. The free lane may then order the transactions based on the user's on-chain stake.

When proposals are constructed, the transactions from a given lane are selected based on highest to lowest priority, validated according to the lane's verfication logic, and included in the proposal.

Each lane must implement the Lane interface, although it is highly recommended that developers extend the base lane to create new lanes.

// LaneMempool defines the interface a lane's mempool should implement. The basic API
// is the same as the sdk.Mempool, but it also includes a Compare function that is used
// to determine the relative priority of two transactions belonging in the same lane.
type LaneMempool interface {
	sdkmempool.Mempool

	// Compare determines the relative priority of two transactions belonging in the same lane. Compare
	// will return -1 if this transaction has a lower priority than the other transaction, 0 if they have
	// the same priority, and 1 if this transaction has a higher priority than the other transaction.
	Compare(ctx sdk.Context, this, other sdk.Tx) (int, error)

	// Contains returns true if the transaction is contained in the mempool.
	Contains(tx sdk.Tx) bool

	// Priority returns the priority of a transaction that belongs to this lane.
	Priority(ctx sdk.Context, tx sdk.Tx) any
}

// Lane defines an interface used for matching transactions to lanes, storing transactions,
// and constructing partial blocks.
type Lane interface {
	LaneMempool

	// PrepareLane builds a portion of the block. It inputs the current context, proposal, and a
	// function to call the next lane in the chain. This handler should update the context as needed
	// and add transactions to the proposal. Note, the lane should only add transactions up to the
	// max block space for the lane.
	PrepareLane(
		ctx sdk.Context,
		proposal proposals.Proposal,
		next PrepareLanesHandler,
	) (proposals.Proposal, error)

	// ProcessLane verifies this lane's portion of a proposed block. It inputs the current context,
	// proposal, transactions that belong to this lane, and a function to call the next lane in the
	// chain. This handler should update the context as needed and add transactions to the proposal.
	// The entire process lane chain should end up constructing the same proposal as the prepare lane
	// chain.
	ProcessLane(
		ctx sdk.Context,
		proposal proposals.Proposal,
		txs []sdk.Tx,
		next ProcessLanesHandler,
	) (proposals.Proposal, error)

	// GetMaxBlockSpace returns the max block space for the lane as a relative percentage.
	GetMaxBlockSpace() math.LegacyDec

	// SetMaxBlockSpace sets the max block space for the lane as a relative percentage.
	SetMaxBlockSpace(math.LegacyDec)

	// Name returns the name of the lane.
	Name() string

	// Match determines if a transaction belongs to this lane.
	Match(ctx sdk.Context, tx sdk.Tx) bool

	// GetTxInfo returns various information about the transaction that
	// belongs to the lane including its priority, signer's, sequence number,
	// size and more.
	GetTxInfo(ctx sdk.Context, tx sdk.Tx) (utils.TxWithInfo, error)
}

Lane Priorities

Each lane has a priority that is used to determine the order in which lanes are processed. The higher the priority, the earlier the lane is processed. For example, if we have three lanes - MEV, free, and default - proposals will be constructed in the following order:

  1. MEV
  2. Free
  3. Default

Proposals will then be verified in the same order. Please see the readme above for more information on how proposals are constructed using lanes.

The ordering of lane's priorities is determined based on the order passed into the constructor of the Block SDK mempool i.e. LanedMempool.

Block SDK mempool

The LanedMempool is a wrapper on top of the collection of lanes. It is solely responsible for adding transactions to the appropriate lanes. Transactions are always inserted / removed to the first lane that accepts / matches the transactions. Transactions should only match to one lane.. In the case where a transaction can match to multiple lanes, the transaction will be inserted into the lane that has the highest priority.

To read more about the underlying implementation of the Block SDK mempool, please see the implementation here.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type IgnoreDecorator added in v1.1.0

type IgnoreDecorator struct {
	// contains filtered or unexported fields
}

IgnoreDecorator is an AnteDecorator that wraps an existing AnteDecorator. It allows for the AnteDecorator to be ignored for specified lanes.

func NewIgnoreDecorator added in v1.1.0

func NewIgnoreDecorator(decorator sdk.AnteDecorator, lanes ...Lane) *IgnoreDecorator

NewIgnoreDecorator returns a new IgnoreDecorator instance.

func (IgnoreDecorator) AnteHandle added in v1.1.0

func (sd IgnoreDecorator) AnteHandle(
	ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler,
) (sdk.Context, error)

AnteHandle implements the sdk.AnteDecorator interface. If the transaction belongs to one of the lanes, the next AnteHandler is called. Otherwise, the decorator's AnteHandler is called.

type Lane

type Lane interface {
	LaneMempool

	// PrepareLane builds a portion of the block. It inputs the current context, proposal, and a
	// function to call the next lane in the chain. This handler should update the context as needed
	// and add transactions to the proposal. Note, the lane should only add transactions up to the
	// max block space for the lane.
	PrepareLane(
		ctx sdk.Context,
		proposal proposals.Proposal,
		next PrepareLanesHandler,
	) (proposals.Proposal, error)

	// ProcessLane verifies this lane's portion of a proposed block. It inputs the current context,
	// proposal, transactions that belong to this lane, and a function to call the next lane in the
	// chain. This handler should update the context as needed and add transactions to the proposal.
	// The entire process lane chain should end up constructing the same proposal as the prepare lane
	// chain.
	ProcessLane(
		ctx sdk.Context,
		proposal proposals.Proposal,
		txs []sdk.Tx,
		next ProcessLanesHandler,
	) (proposals.Proposal, error)

	// GetMaxBlockSpace returns the max block space for the lane as a relative percentage.
	GetMaxBlockSpace() math.LegacyDec

	// Name returns the name of the lane.
	Name() string

	// Match determines if a transaction belongs to this lane.
	Match(ctx sdk.Context, tx sdk.Tx) bool

	// GetTxInfo returns various information about the transaction that
	// belongs to the lane including its priority, signer's, sequence number,
	// size and more.
	GetTxInfo(ctx sdk.Context, tx sdk.Tx) (utils.TxWithInfo, error)
}

Lane defines an interface used for matching transactions to lanes, storing transactions, and constructing partial blocks.

type LaneMempool

type LaneMempool interface {
	sdkmempool.Mempool

	// Compare determines the relative priority of two transactions belonging in the same lane. Compare
	// will return -1 if this transaction has a lower priority than the other transaction, 0 if they have
	// the same priority, and 1 if this transaction has a higher priority than the other transaction.
	Compare(ctx sdk.Context, this, other sdk.Tx) (int, error)

	// Contains returns true if the transaction is contained in the mempool.
	Contains(tx sdk.Tx) bool

	// Priority returns the priority of a transaction that belongs to this lane.
	Priority(ctx sdk.Context, tx sdk.Tx) any
}

LaneMempool defines the interface a lane's mempool should implement. The basic API is the same as the sdk.Mempool, but it also includes a Compare function that is used to determine the relative priority of two transactions belonging in the same lane.

type LanedMempool

type LanedMempool struct {
	// contains filtered or unexported fields
}

LanedMempool defines the Block SDK mempool implementation. It contains a registry of lanes, which allows for customizable block proposal construction.

func NewLanedMempool

func NewLanedMempool(
	logger log.Logger,
	lanes []Lane,
) (*LanedMempool, error)

NewLanedMempool returns a new Block SDK LanedMempool. The laned mempool comprises a registry of lanes. Each lane is responsible for selecting transactions according to its own selection logic. The lanes are ordered according to their priority. The first lane in the registry has the highest priority. Proposals are verified according to the order of the lanes in the registry. Each transaction SHOULD only belong in one lane.

func (*LanedMempool) Contains

func (m *LanedMempool) Contains(tx sdk.Tx) (contains bool)

Contains returns true if the transaction is contained in any of the lanes.

func (*LanedMempool) CountTx

func (m *LanedMempool) CountTx() int

CountTx returns the total number of transactions in the mempool. This will be the sum of the number of transactions in each lane.

func (*LanedMempool) GetTxDistribution

func (m *LanedMempool) GetTxDistribution() map[string]int

GetTxDistribution returns the number of transactions in each lane.

func (*LanedMempool) Insert

func (m *LanedMempool) Insert(ctx context.Context, tx sdk.Tx) (err error)

Insert will insert a transaction into the mempool. It inserts the transaction into the first lane that it matches.

func (*LanedMempool) Registry

func (m *LanedMempool) Registry() []Lane

Registry returns the mempool's lane registry.

func (*LanedMempool) Remove

func (m *LanedMempool) Remove(tx sdk.Tx) (err error)

Remove removes a transaction from the mempool. This assumes that the transaction is contained in only one of the lanes.

func (*LanedMempool) Select

func (m *LanedMempool) Select(_ context.Context, _ [][]byte) sdkmempool.Iterator

Insert returns a nil iterator.

TODO: - Determine if it even makes sense to return an iterator. What does that even mean in the context where you have multiple lanes? - Perhaps consider implementing and returning a no-op iterator?

func (*LanedMempool) ValidateBasic

func (m *LanedMempool) ValidateBasic() error

ValidateBasic validates the mempools configuration. ValidateBasic ensures the following: - The sum of the lane max block space percentages is less than or equal to 1. - There is no unused block space.

type Mempool

type Mempool interface {
	sdkmempool.Mempool

	// Registry returns the mempool's lane registry.
	Registry() []Lane

	// Contains returns the any of the lanes currently contain the transaction.
	Contains(tx sdk.Tx) bool

	// GetTxDistribution returns the number of transactions in each lane.
	GetTxDistribution() map[string]int
}

Mempool defines the Block SDK mempool interface.

type PrepareLanesHandler

type PrepareLanesHandler func(ctx sdk.Context, proposal proposals.Proposal) (proposals.Proposal, error)

PrepareLanesHandler wraps all of the lanes' PrepareLane function into a single chained function. You can think of it like an AnteHandler, but for preparing proposals in the context of lanes instead of modules.

func NoOpPrepareLanesHandler

func NoOpPrepareLanesHandler() PrepareLanesHandler

NoOpPrepareLanesHandler returns a no-op prepare lanes handler. This should only be used for testing.

type ProcessLanesHandler

type ProcessLanesHandler func(ctx sdk.Context, proposal proposals.Proposal, txs []sdk.Tx) (proposals.Proposal, error)

ProcessLanesHandler wraps all of the lanes' ProcessLane functions into a single chained function. You can think of it like an AnteHandler, but for processing proposals in the context of lanes instead of modules.

func NoOpProcessLanesHandler

func NoOpProcessLanesHandler() ProcessLanesHandler

NoOpProcessLanesHandler returns a no-op process lanes handler. This should only be used for testing.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL