Skip to content

Commit

Permalink
add priority lane
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Dec 6, 2023
1 parent c6252bb commit efe8e75
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 5 deletions.
15 changes: 14 additions & 1 deletion app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ante

import (
"cosmossdk.io/errors"
"cosmossdk.io/math"
ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante"
ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper"

Expand Down Expand Up @@ -69,7 +70,19 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
return nil, 0, errors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}

return feeTx.GetFee(), 1 /* FIFO */, nil
// priority calculated based on the fee value
feeValueInBaseUnit := math.OneInt()
for _, coin := range feeTx.GetFee() {
quotePrice, err := options.MoveKeeper.GetPoolSpotPrice(ctx, coin.Denom)
if err != nil {
return nil, 1, err
}

quoteValueInBaseUnit := quotePrice.MulInt(coin.Amount).TruncateInt()
feeValueInBaseUnit = feeValueInBaseUnit.Add(quoteValueInBaseUnit)
}

return feeTx.GetFee(), feeValueInBaseUnit.Int64(), nil
}

anteDecorators := []sdk.AnteDecorator{
Expand Down
10 changes: 6 additions & 4 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"
baselane "github.com/skip-mev/block-sdk/lanes/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"
Expand Down Expand Up @@ -1008,17 +1007,20 @@ func NewInitiaApp(
applanes.FreeLaneMatchHandler(),
)

defaultLaneConfig := blockbase.LaneConfig{
priorityLaneConfig := blockbase.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0,
SignerExtractor: signerExtractor,
}
defaultLane := baselane.NewDefaultLane(defaultLaneConfig)
priorityLane := applanes.NewPriorityLane(
priorityLaneConfig,
movekeeper.NewDexKeeper(app.MoveKeeper),
)

lanes := []block.Lane{mevLane, freeLane, defaultLane}
lanes := []block.Lane{mevLane, freeLane, priorityLane}
mempool := block.NewLanedMempool(app.Logger(), true, lanes...)
app.SetMempool(mempool)

Expand Down
166 changes: 166 additions & 0 deletions app/lanes/priority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package lanes

import (
"context"
"errors"
"fmt"

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

movetypes "github.com/initia-labs/initia/x/move/types"

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"
)

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
// 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
// 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, moveKeeper movetypes.AnteKeeper) *PriorityLane {
lane := blockbase.NewBaseLane(
cfg,
LaneName,
NewMempool(blockbase.NewDefaultTxPriority(), cfg.SignerExtractor, cfg.MaxTxs),
blockbase.DefaultMatchHandler(),
)

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{}),
}
}

// 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
}

0 comments on commit efe8e75

Please sign in to comment.