From 51537eb4e3b5afe61d27f7c09e4cf308720ca3a8 Mon Sep 17 00:00:00 2001 From: David Terpay Date: Tue, 15 Aug 2023 16:39:57 -0400 Subject: [PATCH] more updates --- block/lane_abci.go | 67 ------------- block/lane_constructor.go | 198 -------------------------------------- block/lane_handlers.go | 155 ----------------------------- block/lane_interface.go | 71 -------------- block/lane_mempool.go | 159 ------------------------------ lanes/terminator/lane.go | 4 - 6 files changed, 654 deletions(-) delete mode 100644 block/lane_abci.go delete mode 100644 block/lane_constructor.go delete mode 100644 block/lane_handlers.go delete mode 100644 block/lane_interface.go delete mode 100644 block/lane_mempool.go diff --git a/block/lane_abci.go b/block/lane_abci.go deleted file mode 100644 index a70b102..0000000 --- a/block/lane_abci.go +++ /dev/null @@ -1,67 +0,0 @@ -package blockbuster - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/pob/blockbuster/utils" -) - -// PrepareLane will prepare a partial proposal for the lane. It will select transactions from the -// lane respecting the selection logic of the prepareLaneHandler. It will then update the partial -// proposal with the selected transactions. If the proposal is unable to be updated, we return an -// error. The proposal will only be modified if it passes all of the invarient checks. -func (l *LaneConstructor) PrepareLane( - ctx sdk.Context, - proposal BlockProposal, - maxTxBytes int64, - next PrepareLanesHandler, -) (BlockProposal, error) { - txs, txsToRemove, err := l.prepareLaneHandler(ctx, proposal, maxTxBytes) - if err != nil { - return proposal, err - } - - // Remove all transactions that were invalid during the creation of the partial proposal. - if err := utils.RemoveTxsFromLane(txsToRemove, l); err != nil { - l.Logger().Error( - "failed to remove transactions from lane", - "lane", l.Name(), - "err", err, - ) - } - - // Update the proposal with the selected transactions. - if err := proposal.UpdateProposal(l, txs); err != nil { - return proposal, err - } - - return next(ctx, proposal) -} - -// CheckOrder checks that the ordering logic of the lane is respected given the set of transactions -// in the block proposal. If the ordering logic is not respected, we return an error. -func (l *LaneConstructor) CheckOrder(ctx sdk.Context, txs []sdk.Tx) error { - return l.checkOrderHandler(ctx, txs) -} - -// ProcessLane verifies that the transactions included in the block proposal are valid respecting -// the verification logic of the lane (processLaneHandler). If the transactions are valid, we -// return the transactions that do not belong to this lane to the next lane. If the transactions -// are invalid, we return an error. -func (l *LaneConstructor) ProcessLane(ctx sdk.Context, txs []sdk.Tx, next ProcessLanesHandler) (sdk.Context, error) { - remainingTxs, err := l.processLaneHandler(ctx, txs) - if err != nil { - return ctx, err - } - - return next(ctx, remainingTxs) -} - -// AnteVerifyTx verifies that the transaction is valid respecting the ante verification logic of -// of the antehandler chain. -func (l *LaneConstructor) AnteVerifyTx(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { - if l.cfg.AnteHandler != nil { - return l.cfg.AnteHandler(ctx, tx, simulate) - } - - return ctx, nil -} diff --git a/block/lane_constructor.go b/block/lane_constructor.go deleted file mode 100644 index 7107814..0000000 --- a/block/lane_constructor.go +++ /dev/null @@ -1,198 +0,0 @@ -package blockbuster - -import ( - "fmt" - - "cosmossdk.io/log" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var _ Lane = (*LaneConstructor)(nil) - -// LaneConstructor is a generic implementation of a lane. It is meant to be used -// as a base for other lanes to be built on top of. It provides a default -// implementation of the MatchHandler, PrepareLaneHandler, ProcessLaneHandler, -// and CheckOrderHandler. To extend this lane, you must either utilize the default -// handlers or construct your own that you pass into the constructor/setters. -type LaneConstructor struct { - // cfg stores functionality required to encode/decode transactions, maintains how - // many transactions are allowed in this lane's mempool, and the amount of block - // space this lane is allowed to consume. - cfg LaneConfig - - // laneName is the name of the lane. - laneName string - - // LaneMempool is the mempool that is responsible for storing transactions - // that are waiting to be processed. - LaneMempool - - // matchHandler is the function that determines whether or not a transaction - // should be processed by this lane. - matchHandler MatchHandler - - // prepareLaneHandler is the function that is called when a new proposal is being - // requested and the lane needs to submit transactions it wants included in the block. - prepareLaneHandler PrepareLaneHandler - - // checkOrderHandler is the function that is called when a new proposal is being - // verified and the lane needs to verify that the transactions included in the proposal - // respect the ordering rules of the lane and does not interleave transactions from other lanes. - checkOrderHandler CheckOrderHandler - - // processLaneHandler is the function that 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. - processLaneHandler ProcessLaneHandler -} - -// NewLaneConstructor returns a new lane constructor. When creating this lane, the type -// of the lane must be specified. The type of the lane is directly associated with the -// type of the mempool that is used to store transactions that are waiting to be processed. -func NewLaneConstructor( - cfg LaneConfig, - laneName string, - laneMempool LaneMempool, - matchHandlerFn MatchHandler, -) *LaneConstructor { - lane := &LaneConstructor{ - cfg: cfg, - laneName: laneName, - LaneMempool: laneMempool, - matchHandler: matchHandlerFn, - } - - if err := lane.ValidateBasic(); err != nil { - panic(err) - } - - return lane -} - -// ValidateBasic ensures that the lane was constructed properly. In the case that -// the lane was not constructed with proper handlers, default handlers are set. -func (l *LaneConstructor) ValidateBasic() error { - if err := l.cfg.ValidateBasic(); err != nil { - return err - } - - if l.laneName == "" { - return fmt.Errorf("lane name cannot be empty") - } - - if l.LaneMempool == nil { - return fmt.Errorf("lane mempool cannot be nil") - } - - if l.matchHandler == nil { - return fmt.Errorf("match handler cannot be nil") - } - - if l.prepareLaneHandler == nil { - l.prepareLaneHandler = l.DefaultPrepareLaneHandler() - } - - if l.processLaneHandler == nil { - l.processLaneHandler = l.DefaultProcessLaneHandler() - } - - if l.checkOrderHandler == nil { - l.checkOrderHandler = l.DefaultCheckOrderHandler() - } - - 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 *LaneConstructor) 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 *LaneConstructor) SetProcessLaneHandler(processLaneHandler ProcessLaneHandler) { - if processLaneHandler == nil { - panic("process lane handler cannot be nil") - } - - l.processLaneHandler = processLaneHandler -} - -// SetCheckOrderHandler sets the check order 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 respect the ordering rules of -// the lane and does not include transactions from other lanes. -func (l *LaneConstructor) SetCheckOrderHandler(checkOrderHandler CheckOrderHandler) { - if checkOrderHandler == nil { - panic("check order handler cannot be nil") - } - - l.checkOrderHandler = checkOrderHandler -} - -// 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 -// list, it returns false. -func (l *LaneConstructor) Match(ctx sdk.Context, tx sdk.Tx) bool { - return l.matchHandler(ctx, tx) && !l.CheckIgnoreList(ctx, tx) -} - -// CheckIgnoreList returns true if the transaction is on the ignore list. The ignore -// list is utilized to prevent transactions that should be considered in other lanes -// from being considered from this lane. -func (l *LaneConstructor) CheckIgnoreList(ctx sdk.Context, tx sdk.Tx) bool { - for _, lane := range l.cfg.IgnoreList { - if lane.Match(ctx, tx) { - return true - } - } - - return false -} - -// Name returns the name of the lane. -func (l *LaneConstructor) Name() string { - return l.laneName -} - -// SetIgnoreList sets the ignore list for the lane. The ignore list is a list -// of lanes that the lane should ignore when processing transactions. -func (l *LaneConstructor) SetIgnoreList(lanes []Lane) { - l.cfg.IgnoreList = lanes -} - -// SetAnteHandler sets the ante handler for the lane. -func (l *LaneConstructor) SetAnteHandler(anteHandler sdk.AnteHandler) { - l.cfg.AnteHandler = anteHandler -} - -// Logger returns the logger for the lane. -func (l *LaneConstructor) Logger() log.Logger { - return l.cfg.Logger -} - -// TxDecoder returns the tx decoder for the lane. -func (l *LaneConstructor) TxDecoder() sdk.TxDecoder { - return l.cfg.TxDecoder -} - -// TxEncoder returns the tx encoder for the lane. -func (l *LaneConstructor) TxEncoder() sdk.TxEncoder { - return l.cfg.TxEncoder -} - -// GetMaxBlockSpace returns the maximum amount of block space that the lane is -// allowed to consume as a percentage of the total block space. -func (l *LaneConstructor) GetMaxBlockSpace() math.LegacyDec { - return l.cfg.MaxBlockSpace -} diff --git a/block/lane_handlers.go b/block/lane_handlers.go deleted file mode 100644 index 0a87a5d..0000000 --- a/block/lane_handlers.go +++ /dev/null @@ -1,155 +0,0 @@ -package blockbuster - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/pob/blockbuster/utils" -) - -// 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 block space for this -// lane has been reached. Additionally, any transactions that are invalid will be returned. -func (l *LaneConstructor) DefaultPrepareLaneHandler() PrepareLaneHandler { - return func(ctx sdk.Context, proposal BlockProposal, maxTxBytes int64) ([][]byte, []sdk.Tx, error) { - var ( - totalSize int64 - txs [][]byte - txsToRemove []sdk.Tx - ) - - // 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() { - tx := iterator.Tx() - - txBytes, hash, err := utils.GetTxHashStr(l.TxEncoder(), tx) - if err != nil { - l.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( - "failed to select tx for lane; tx does not belong to lane", - "tx_hash", hash, - "lane", l.Name(), - ) - - txsToRemove = append(txsToRemove, tx) - continue - } - - // if the transaction is already in the (partial) block proposal, we skip it. - if proposal.Contains(txBytes) { - l.Logger().Info( - "failed to select tx for lane; tx is already in proposal", - "tx_hash", hash, - "lane", l.Name(), - ) - - continue - } - - // If the transaction is too large, we break and do not attempt to include more txs. - txSize := int64(len(txBytes)) - if updatedSize := totalSize + txSize; updatedSize > maxTxBytes { - l.Logger().Info( - "tx bytes above the maximum allowed", - "lane", l.Name(), - "tx_size", txSize, - "total_size", totalSize, - "max_tx_bytes", maxTxBytes, - "tx_hash", hash, - ) - - break - } - - // Verify the transaction. - if ctx, err = l.AnteVerifyTx(ctx, tx, false); err != nil { - l.Logger().Info( - "failed to verify tx", - "tx_hash", hash, - "err", err, - ) - - txsToRemove = append(txsToRemove, tx) - continue - } - - totalSize += txSize - txs = append(txs, txBytes) - } - - return txs, txsToRemove, nil - } -} - -// DefaultProcessLaneHandler returns a default implementation of the ProcessLaneHandler. It -// verifies all transactions in the lane that matches to the lane. If any transaction -// fails to verify, the entire proposal is rejected. If the handler comes across a transaction -// that does not match the lane's matcher, it will return the remaining transactions in the -// proposal. -func (l *LaneConstructor) DefaultProcessLaneHandler() ProcessLaneHandler { - return func(ctx sdk.Context, txs []sdk.Tx) ([]sdk.Tx, error) { - var err error - - // Process all transactions that match the lane's matcher. - for index, tx := range txs { - if l.Match(ctx, tx) { - if ctx, err = l.AnteVerifyTx(ctx, tx, false); err != nil { - return nil, fmt.Errorf("failed to verify tx: %w", err) - } - } else { - return txs[index:], nil - } - } - - // This means we have processed all transactions in the proposal. - return nil, nil - } -} - -// DefaultCheckOrderHandler returns a default implementation of the CheckOrderHandler. It -// ensures the following invariants: -// -// 1. All transactions that belong to this lane respect the ordering logic defined by the -// lane. -// 2. Transactions that belong to other lanes cannot be interleaved with transactions that -// belong to this lane. -func (l *LaneConstructor) DefaultCheckOrderHandler() CheckOrderHandler { - return func(ctx sdk.Context, txs []sdk.Tx) error { - seenOtherLaneTx := false - - for index, tx := range txs { - if l.Match(ctx, tx) { - if seenOtherLaneTx { - return fmt.Errorf("the %s lane contains a transaction that belongs to another lane", l.Name()) - } - - // If the transactions do not respect the priority defined by the mempool, we consider the proposal - // to be invalid - if index > 0 && l.Compare(ctx, txs[index-1], tx) == -1 { - return fmt.Errorf("transaction at index %d has a higher priority than %d", index, index-1) - } - } else { - seenOtherLaneTx = true - } - } - - 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 - } -} diff --git a/block/lane_interface.go b/block/lane_interface.go deleted file mode 100644 index 59ee35e..0000000 --- a/block/lane_interface.go +++ /dev/null @@ -1,71 +0,0 @@ -package blockbuster - -import ( - "cosmossdk.io/log" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" -) - -// 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. -// -//go:generate mockery --name LaneMempool --output ./utils/mocks --outpkg mocks --case underscore -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 - - // Contains returns true if the transaction is contained in the mempool. - Contains(tx sdk.Tx) bool -} - -// Lane defines an interface used for matching transactions to lanes, storing transactions, -// and constructing partial blocks. -// -//go:generate mockery --name Lane --output ./utils/mocks --outpkg mocks --case underscore -type Lane interface { - LaneMempool - - // PrepareLane builds a portion of the block. It inputs the maxTxBytes that can be - // included in the proposal for the given lane, the partial proposal, and a function - // to call the next lane in the chain. The next lane in the chain will be called with - // the updated proposal and context. - PrepareLane( - ctx sdk.Context, - proposal BlockProposal, - maxTxBytes int64, - next PrepareLanesHandler, - ) (BlockProposal, error) - - // CheckOrder validates that transactions belonging to this lane are not misplaced - // in the block proposal and respect the ordering rules of the lane. - CheckOrder(ctx sdk.Context, txs []sdk.Tx) error - - // ProcessLane verifies this lane's portion of a proposed block. It inputs the transactions - // that may belong to this lane and a function to call the next lane in the chain. The next - // lane in the chain will be called with the updated context and filtered down transactions. - ProcessLane(ctx sdk.Context, proposalTxs []sdk.Tx, next ProcessLanesHandler) (sdk.Context, error) - - // GetMaxBlockSpace returns the max block space for the lane as a relative percentage. - GetMaxBlockSpace() math.LegacyDec - - // Logger returns the lane's logger. - Logger() log.Logger - - // Name returns the name of the lane. - Name() string - - // SetAnteHandler sets the lane's antehandler. - SetAnteHandler(antehander sdk.AnteHandler) - - // SetIgnoreList sets the lanes that should be ignored by this lane. - SetIgnoreList(ignoreList []Lane) - - // Match determines if a transaction belongs to this lane. - Match(ctx sdk.Context, tx sdk.Tx) bool -} diff --git a/block/lane_mempool.go b/block/lane_mempool.go deleted file mode 100644 index e102ee8..0000000 --- a/block/lane_mempool.go +++ /dev/null @@ -1,159 +0,0 @@ -package blockbuster - -import ( - "context" - "errors" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" - "github.com/skip-mev/pob/blockbuster/utils" -) - -type ( - // ConstructorMempool defines a mempool that orders transactions based on the - // txPriority. The mempool is a wrapper on top of the SDK's Priority Nonce mempool. - // It include's additional helper functions that allow users to determine if a - // transaction is already in the mempool and to compare the priority of two - // transactions. - ConstructorMempool[C comparable] struct { - // index defines an index of transactions. - index sdkmempool.Mempool - - // txPriority defines the transaction priority function. It is used to - // retrieve the priority of a given transaction and to compare the priority - // of two transactions. The index utilizes this struct to order transactions - // in the mempool. - txPriority TxPriority[C] - - // txEncoder defines the sdk.Tx encoder that allows us to encode transactions - // to bytes. - txEncoder sdk.TxEncoder - - // txCache is a map of all transactions in the mempool. It is used - // to quickly check if a transaction is already in the mempool. - txCache map[string]struct{} - } -) - -// DefaultTxPriority returns a default implementation of the TxPriority. It prioritizes -// transactions by their fee. -func DefaultTxPriority() TxPriority[string] { - return TxPriority[string]{ - GetTxPriority: func(goCtx context.Context, tx sdk.Tx) string { - feeTx, ok := tx.(sdk.FeeTx) - if !ok { - return "" - } - - return feeTx.GetFee().String() - }, - Compare: func(a, b string) int { - aCoins, _ := sdk.ParseCoinsNormalized(a) - bCoins, _ := sdk.ParseCoinsNormalized(b) - - switch { - case aCoins == nil && bCoins == nil: - return 0 - - case aCoins == nil: - return -1 - - case bCoins == nil: - return 1 - - default: - switch { - case aCoins.IsAllGT(bCoins): - return 1 - - case aCoins.IsAllLT(bCoins): - return -1 - - default: - return 0 - } - } - }, - MinValue: "", - } -} - -// NewConstructorMempool returns a new ConstructorMempool. -func NewConstructorMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder, maxTx int) *ConstructorMempool[C] { - return &ConstructorMempool[C]{ - index: NewPriorityMempool( - PriorityNonceMempoolConfig[C]{ - TxPriority: txPriority, - MaxTx: maxTx, - }, - ), - txPriority: txPriority, - txEncoder: txEncoder, - txCache: make(map[string]struct{}), - } -} - -// Insert inserts a transaction into the mempool. -func (cm *ConstructorMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error { - if err := cm.index.Insert(ctx, tx); err != nil { - return fmt.Errorf("failed to insert tx into auction index: %w", err) - } - - _, txHashStr, err := utils.GetTxHashStr(cm.txEncoder, tx) - if err != nil { - cm.Remove(tx) - return err - } - - cm.txCache[txHashStr] = struct{}{} - - return nil -} - -// Remove removes a transaction from the mempool. -func (cm *ConstructorMempool[C]) Remove(tx sdk.Tx) error { - if err := cm.index.Remove(tx); err != nil && !errors.Is(err, sdkmempool.ErrTxNotFound) { - return fmt.Errorf("failed to remove transaction from the mempool: %w", err) - } - - _, txHashStr, err := utils.GetTxHashStr(cm.txEncoder, tx) - if err != nil { - return fmt.Errorf("failed to get tx hash string: %w", err) - } - - delete(cm.txCache, txHashStr) - - return nil -} - -// Select returns an iterator of all transactions in the mempool. NOTE: If you -// remove a transaction from the mempool while iterating over the transactions, -// the iterator will not be aware of the removal and will continue to iterate -// over the removed transaction. Be sure to reset the iterator if you remove a transaction. -func (cm *ConstructorMempool[C]) Select(ctx context.Context, txs [][]byte) sdkmempool.Iterator { - return cm.index.Select(ctx, txs) -} - -// CountTx returns the number of transactions in the mempool. -func (cm *ConstructorMempool[C]) CountTx() int { - return cm.index.CountTx() -} - -// Contains returns true if the transaction is contained in the mempool. -func (cm *ConstructorMempool[C]) Contains(tx sdk.Tx) bool { - _, txHashStr, err := utils.GetTxHashStr(cm.txEncoder, tx) - if err != nil { - return false - } - - _, ok := cm.txCache[txHashStr] - return ok -} - -// Compare determines the relative priority of two transactions belonging in the same lane. -func (cm *ConstructorMempool[C]) Compare(ctx sdk.Context, this sdk.Tx, other sdk.Tx) int { - firstPriority := cm.txPriority.GetTxPriority(ctx, this) - secondPriority := cm.txPriority.GetTxPriority(ctx, other) - return cm.txPriority.Compare(firstPriority, secondPriority) -} diff --git a/lanes/terminator/lane.go b/lanes/terminator/lane.go index c828792..3fce765 100644 --- a/lanes/terminator/lane.go +++ b/lanes/terminator/lane.go @@ -14,10 +14,6 @@ const ( LaneName = "Terminator" ) -const ( - LaneName = "Terminator" -) - // Terminator Lane will get added to the chain to simplify chaining code so that we // don't need to check if next == nil further up the chain //