Skip to content

Commit

Permalink
Merge pull request #35 from initia-labs/fix/free-lane
Browse files Browse the repository at this point in the history
fix: use custom free lane
  • Loading branch information
beer-1 authored Dec 13, 2023
2 parents 70af2d3 + 8d1fe85 commit 571b047
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 162 deletions.
8 changes: 1 addition & 7 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ import (
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
blockbase "github.com/skip-mev/block-sdk/block/base"
freelane "github.com/skip-mev/block-sdk/lanes/free"
"github.com/skip-mev/block-sdk/lanes/mev"
"github.com/skip-mev/block-sdk/x/auction"
auctionante "github.com/skip-mev/block-sdk/x/auction/ante"
Expand Down Expand Up @@ -1002,12 +1001,7 @@ func NewInitiaApp(
MaxTxs: 10,
SignerExtractor: signerExtractor,
}

freeLane := freelane.NewFreeLane(
freeConfig,
blockbase.DefaultTxPriority(),
applanes.FreeLaneMatchHandler(),
)
freeLane := applanes.NewFreeLane(freeConfig, applanes.FreeLaneMatchHandler())

priorityLaneConfig := blockbase.LaneConfig{
Logger: app.Logger(),
Expand Down
36 changes: 31 additions & 5 deletions app/lanes/free.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,49 @@ import (

channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"

"github.com/skip-mev/block-sdk/block/base"
"github.com/skip-mev/block-sdk/block"
blockbase "github.com/skip-mev/block-sdk/block/base"
)

// FreeLaneMatchHandler returns the default match handler for the free lane. The
// default implementation matches transactions that are ibc related. In particular,
// any transaction that is a MsgTimeout, MsgAcknowledgement.
func FreeLaneMatchHandler() base.MatchHandler {
func FreeLaneMatchHandler() blockbase.MatchHandler {
return func(ctx sdk.Context, tx sdk.Tx) bool {
for _, msg := range tx.GetMsgs() {
switch msg.(type) {
case *channeltypes.MsgTimeout:
return true
continue
case *channeltypes.MsgAcknowledgement:
return true
continue
default:
return false
}
}

return false
return true
}
}

const (
// FreeLaneName defines the name of the free lane.
FreeLaneName = "free"
)

// NewFreeLane returns a new free lane.
func NewFreeLane(
cfg blockbase.LaneConfig,
matchFn blockbase.MatchHandler,
) block.Lane {
lane, err := blockbase.NewBaseLane(
cfg,
FreeLaneName,
blockbase.WithMatchHandler(matchFn),
blockbase.WithMempool(NewMempool(blockbase.NewDefaultTxPriority(), cfg.SignerExtractor, cfg.MaxTxs)),
)
if err != nil {
panic(err)
}

return lane
}
132 changes: 132 additions & 0 deletions app/lanes/mempool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package lanes

import (
"context"
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
blockbase "github.com/skip-mev/block-sdk/block/base"
)

type (
txKey struct {
nonce uint64
sender string
}

// Mempool 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.
Mempool[C comparable] struct {
// index defines an index of transactions.
index sdkmempool.Mempool

// signerExtractor defines the signer extraction adapter that allows us to
// extract the signer from a transaction.
extractor signer_extraction.Adapter

// 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[txKey]struct{}
}
)

// NewMempool returns a new Mempool.
func NewMempool[C comparable](txPriority blockbase.TxPriority[C], extractor signer_extraction.Adapter, maxTx int) *Mempool[C] {
return &Mempool[C]{
index: blockbase.NewPriorityMempool(
blockbase.PriorityNonceMempoolConfig[C]{
TxPriority: txPriority,
MaxTx: maxTx,
},
extractor,
),
extractor: extractor,
txCache: make(map[txKey]struct{}),
}
}

// Priority returns the priority of the transaction.
func (cm *Mempool[C]) Priority(ctx sdk.Context, tx sdk.Tx) any {
return 1
}

// CountTx returns the number of transactions in the mempool.
func (cm *Mempool[C]) CountTx() int {
return cm.index.CountTx()
}

// 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 *Mempool[C]) Select(ctx context.Context, txs [][]byte) sdkmempool.Iterator {
return cm.index.Select(ctx, txs)
}

// Compare return 0 to ignore priority check in ProcessLaneHandler.
func (cm *Mempool[C]) Compare(ctx sdk.Context, this sdk.Tx, other sdk.Tx) (int, error) {
return 0, nil
}

// Contains returns true if the transaction is contained in the mempool.
func (cm *Mempool[C]) Contains(tx sdk.Tx) bool {
if key, err := cm.getTxKey(tx); err != nil {
return false
} else {
if _, ok := cm.txCache[key]; ok {
return true
} else {
return false
}
}
}

// Insert inserts a transaction into the mempool.
func (cm *Mempool[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)
}

if key, err := cm.getTxKey(tx); err != nil {
return err
} else {
cm.txCache[key] = struct{}{}
}

return nil
}

// Remove removes a transaction from the mempool.
func (cm *Mempool[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)
}

if key, err := cm.getTxKey(tx); err != nil {
return err
} else {
delete(cm.txCache, key)
}

return nil
}

func (cm *Mempool[C]) getTxKey(tx sdk.Tx) (txKey, error) {
signers, err := cm.extractor.GetSigners(tx)
if err != nil {
return txKey{}, err
}
if len(signers) == 0 {
return txKey{}, fmt.Errorf("attempted to remove a tx with no signatures")
}
sig := signers[0]
sender := sig.Signer.String()
nonce := sig.Sequence
return txKey{nonce, sender}, nil
}
159 changes: 9 additions & 150 deletions app/lanes/priority.go
Original file line number Diff line number Diff line change
@@ -1,171 +1,30 @@
package lanes

import (
"context"
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"

signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
blockbase "github.com/skip-mev/block-sdk/block/base"
)

const (
// LaneName defines the name of the default lane.
LaneName = "priority"
// PriorityLaneName defines the name of the priority lane.
PriorityLaneName = "priority"
)

var _ block.Lane = (*PriorityLane)(nil)

// DefaultLane defines a default lane implementation. The default lane orders
// transactions by the transaction fees. The default lane accepts any transaction
// PriorityLane defines a priority lane implementation. The priority lane orders
// transactions by the transaction fees. The priority lane accepts any transaction
// that should not be ignored (as defined by the IgnoreList in the LaneConfig).
// The default lane builds and verifies blocks in a similar fashion to how the
// The priority lane builds and verifies blocks in a similar fashion to how the
// CometBFT/Tendermint consensus engine builds and verifies blocks pre SDK version
// 0.47.0.
type PriorityLane struct {
*blockbase.BaseLane
}

// NewPriorityLane returns a new default lane.
func NewPriorityLane(cfg blockbase.LaneConfig) *PriorityLane {
func NewPriorityLane(cfg blockbase.LaneConfig) block.Lane {
lane, err := blockbase.NewBaseLane(
cfg,
LaneName,
PriorityLaneName,
blockbase.WithMempool(NewMempool(blockbase.NewDefaultTxPriority(), cfg.SignerExtractor, cfg.MaxTxs)),
)
if err != nil {
panic(err)
}
lane.LaneMempool = NewMempool(blockbase.NewDefaultTxPriority(), cfg.SignerExtractor, cfg.MaxTxs)

if err := lane.ValidateBasic(); err != nil {
panic(err)
}

return &PriorityLane{
BaseLane: lane,
}
}

type (
txKey struct {
nonce uint64
sender string
}

// Mempool 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.
Mempool[C comparable] struct {
// index defines an index of transactions.
index sdkmempool.Mempool

// signerExtractor defines the signer extraction adapter that allows us to
// extract the signer from a transaction.
extractor signer_extraction.Adapter

// 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[txKey]struct{}
}
)

// NewMempool returns a new Mempool.
func NewMempool[C comparable](txPriority blockbase.TxPriority[C], extractor signer_extraction.Adapter, maxTx int) *Mempool[C] {
return &Mempool[C]{
index: blockbase.NewPriorityMempool(
blockbase.PriorityNonceMempoolConfig[C]{
TxPriority: txPriority,
MaxTx: maxTx,
},
extractor,
),
extractor: extractor,
txCache: make(map[txKey]struct{}),
}
}

// Priority returns the priority of the transaction.
func (cm *Mempool[C]) Priority(ctx sdk.Context, tx sdk.Tx) any {
return 1
}

// CountTx returns the number of transactions in the mempool.
func (cm *Mempool[C]) CountTx() int {
return cm.index.CountTx()
}

// 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 *Mempool[C]) Select(ctx context.Context, txs [][]byte) sdkmempool.Iterator {
return cm.index.Select(ctx, txs)
}

// Compare return 0 to ignore priority check in ProcessLaneHandler.
func (cm *Mempool[C]) Compare(ctx sdk.Context, this sdk.Tx, other sdk.Tx) (int, error) {
return 0, nil
}

// Contains returns true if the transaction is contained in the mempool.
func (cm *Mempool[C]) Contains(tx sdk.Tx) bool {
if key, err := cm.getTxKey(tx); err != nil {
return false
} else {
if _, ok := cm.txCache[key]; ok {
return true
} else {
return false
}
}
}

// Insert inserts a transaction into the mempool.
func (cm *Mempool[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)
}

if key, err := cm.getTxKey(tx); err != nil {
return err
} else {
cm.txCache[key] = struct{}{}
}

return nil
}

// Remove removes a transaction from the mempool.
func (cm *Mempool[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)
}

if key, err := cm.getTxKey(tx); err != nil {
return err
} else {
delete(cm.txCache, key)
}

return nil
}

func (cm *Mempool[C]) getTxKey(tx sdk.Tx) (txKey, error) {
signers, err := cm.extractor.GetSigners(tx)
if err != nil {
return txKey{}, err
}
if len(signers) == 0 {
return txKey{}, fmt.Errorf("attempted to remove a tx with no signatures")
}
sig := signers[0]
sender := sig.Signer.String()
nonce := sig.Sequence
return txKey{nonce, sender}, nil
return lane
}

0 comments on commit 571b047

Please sign in to comment.