Skip to content

Commit aa0e4b8

Browse files
committed
Implement standalone transaction prioritizer
Extract the logic of transaction prioritisation from various Ante handlers for both EVM and cosmos transactions into a side effect free lightweight API exposed via ABCI interface.
1 parent d356344 commit aa0e4b8

4 files changed

Lines changed: 169 additions & 6 deletions

File tree

app/app.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ type App struct {
386386
wsServerStartSignal chan struct{}
387387
httpServerStartSignalSent bool
388388
wsServerStartSignalSent bool
389+
390+
txPrioritizer sdk.TxPrioritizer
389391
}
390392

391393
type AppOption func(*App)
@@ -977,6 +979,8 @@ func New(
977979

978980
app.RegisterDeliverTxHook(app.AddCosmosEventsToEVMReceiptIfApplicable)
979981

982+
app.txPrioritizer = NewSeiTxPrioritizer(&app.EvmKeeper, &app.UpgradeKeeper, &app.ParamsKeeper).GetTxPriority
983+
app.BaseApp.SetTxPrioritizer(app.txPrioritizer)
980984
return app
981985
}
982986

app/prioritizer.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package app
2+
3+
import (
4+
"math/big"
5+
6+
sdk "github.com/cosmos/cosmos-sdk/types"
7+
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
8+
"github.com/cosmos/cosmos-sdk/x/auth/ante"
9+
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
10+
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
11+
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
12+
ethtypes "github.com/ethereum/go-ethereum/core/types"
13+
"github.com/sei-protocol/sei-chain/app/antedecorators"
14+
"github.com/sei-protocol/sei-chain/utils"
15+
"github.com/sei-protocol/sei-chain/x/evm/derived"
16+
evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper"
17+
evmtypes "github.com/sei-protocol/sei-chain/x/evm/types"
18+
oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types"
19+
)
20+
21+
var _ sdk.TxPrioritizer = (*SeiTxPrioritizer)(nil).GetTxPriority
22+
23+
type SeiTxPrioritizer struct {
24+
evmKeeper *evmkeeper.Keeper
25+
upgradeKeeper *upgradekeeper.Keeper
26+
paramsKeeper *paramskeeper.Keeper
27+
}
28+
29+
func NewSeiTxPrioritizer(ek *evmkeeper.Keeper, uk *upgradekeeper.Keeper, pk *paramskeeper.Keeper) *SeiTxPrioritizer {
30+
return &SeiTxPrioritizer{
31+
evmKeeper: ek,
32+
upgradeKeeper: uk,
33+
paramsKeeper: pk,
34+
}
35+
}
36+
37+
func (s *SeiTxPrioritizer) GetTxPriority(ctx sdk.Context, tx sdk.Tx) (int64, error) {
38+
if ctx.HasPriority() {
39+
// The context already has a priority set, return it.
40+
return ctx.Priority(), nil
41+
}
42+
if evmTx := evmtypes.GetEVMTransactionMessage(tx); evmTx != nil {
43+
return s.getEvmTxPriority(ctx, evmTx)
44+
}
45+
if feeTx, ok := tx.(sdk.FeeTx); ok {
46+
return s.getCosmosTxPriority(ctx, feeTx)
47+
}
48+
return 0, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must either be EVM or Fee")
49+
}
50+
51+
func (s *SeiTxPrioritizer) getEvmTxPriority(ctx sdk.Context, evmTx *evmtypes.MsgEVMTransaction) (int64, error) {
52+
53+
if s.isUnassociatedAssociate(ctx, evmTx) {
54+
return antedecorators.EVMAssociatePriority, nil
55+
}
56+
57+
// Check txData for sanity.
58+
txData, err := evmtypes.UnpackTxData(evmTx.Data)
59+
if err != nil {
60+
return 0, err
61+
}
62+
if txData.GetGasFeeCap().Cmp(s.getEvmBaseFee(ctx)) < 0 {
63+
return 0, sdkerrors.ErrInsufficientFee
64+
}
65+
minimumFee := s.evmKeeper.GetMinimumFeePerGas(ctx).TruncateInt().BigInt()
66+
if txData.GetGasFeeCap().Cmp(minimumFee) < 0 {
67+
return 0, sdkerrors.ErrInsufficientFee
68+
}
69+
if txData.GetGasTipCap().Sign() < 0 {
70+
return 0, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "gas fee cap cannot be negative")
71+
}
72+
// Check blob hashes for sanity.
73+
// If EVM version is Cancun or later, and the transaction contains at least one blob, we need to
74+
// make sure the transaction carries a non-zero blob fee cap.
75+
if evmTx.Derived.Version >= derived.Cancun && len(txData.GetBlobHashes()) > 0 {
76+
// For now we are simply assuming excessive blob gas is 0. In the future we might change it to be
77+
// dynamic based on prior block usage.
78+
chainConfig := evmtypes.DefaultChainConfig().EthereumConfig(s.evmKeeper.ChainID(ctx))
79+
if txData.GetBlobFeeCap().Cmp(eip4844.CalcBlobFee(chainConfig, &ethtypes.Header{Time: uint64(ctx.BlockTime().Unix())})) < 0 {
80+
return 0, sdkerrors.ErrInsufficientFee
81+
}
82+
}
83+
84+
gp := txData.EffectiveGasPrice(utils.Big0)
85+
priority := sdk.NewDecFromBigInt(gp).Quo(s.evmKeeper.GetPriorityNormalizer(ctx)).TruncateInt().BigInt()
86+
if priority.Cmp(big.NewInt(antedecorators.MaxPriority)) > 0 {
87+
priority = big.NewInt(antedecorators.MaxPriority)
88+
}
89+
return priority.Int64(), nil
90+
}
91+
92+
func (s *SeiTxPrioritizer) isUnassociatedAssociate(ctx sdk.Context, evmTx *evmtypes.MsgEVMTransaction) bool {
93+
// TODO: when is derived populated? Check that it is reasonable to use it here.
94+
if evmTx.Derived == nil {
95+
return false
96+
}
97+
98+
// TODO: this potentially looks up entries from KVstore. Do we want to?
99+
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx))
100+
_, isAssociated := s.evmKeeper.GetEVMAddress(ctx, evmTx.Derived.SenderSeiAddr)
101+
return evmTx.Derived.IsAssociate && !isAssociated
102+
}
103+
104+
func (s *SeiTxPrioritizer) getEvmBaseFee(ctx sdk.Context) *big.Int {
105+
const (
106+
pacific1 = "pacific-1"
107+
historicalBlockHeight = 114945913
108+
doneHeightName = "6.2.0"
109+
)
110+
if ctx.ChainID() == pacific1 {
111+
height := ctx.BlockHeight()
112+
if height < historicalBlockHeight {
113+
return s.evmKeeper.GetBaseFeePerGas(ctx).TruncateInt().BigInt()
114+
}
115+
116+
doneHeight := s.upgradeKeeper.GetDoneHeight(
117+
ctx.WithGasMeter(sdk.NewInfiniteGasMeter(1, 1)), doneHeightName)
118+
if height < doneHeight {
119+
return s.evmKeeper.GetCurrBaseFeePerGas(ctx).TruncateInt().BigInt()
120+
}
121+
}
122+
return s.evmKeeper.GetNextBaseFeePerGas(ctx).TruncateInt().BigInt()
123+
}
124+
125+
func (s *SeiTxPrioritizer) getCosmosTxPriority(ctx sdk.Context, feeTx sdk.FeeTx) (int64, error) {
126+
if isOracleTx(feeTx) {
127+
return antedecorators.OraclePriority, nil
128+
}
129+
130+
feeCoins := feeTx.GetFee()
131+
feeParams := s.paramsKeeper.GetFeesParams(ctx)
132+
feeCoins = feeCoins.NonZeroAmountsOf(append([]string{sdk.DefaultBondDenom}, feeParams.GetAllowedFeeDenoms()...))
133+
gas := feeTx.GetGas()
134+
// skip checking that fees meet a minimum threshold for the validator.
135+
var priority int64
136+
if gas > 0 {
137+
priority = ante.GetTxPriority(feeCoins, int64(gas))
138+
}
139+
return min(antedecorators.MaxPriority, priority), nil
140+
}
141+
142+
func isOracleTx(tx sdk.FeeTx) bool {
143+
if len(tx.GetMsgs()) == 0 {
144+
return false
145+
}
146+
for _, msg := range tx.GetMsgs() {
147+
switch msg.(type) {
148+
case *oracletypes.MsgAggregateExchangeRateVote:
149+
continue
150+
default:
151+
return false
152+
}
153+
}
154+
return true
155+
}

go.mod

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,19 @@ replace (
353353
github.com/CosmWasm/wasmvm => github.com/sei-protocol/sei-wasmvm v1.5.4-sei.0.0.3
354354
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.2
355355
github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0
356-
github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.66
356+
// TODO: To be replaced with a concrete version number. See:
357+
// - https://github.com/sei-protocol/sei-cosmos/pull/598
358+
github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.67-0.20250820133804-748608a73207
357359
github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.2.0
358360
github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.6
359361
github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.15.7-sei-3
360362
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
361363
github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.51
362364
// Latest goleveldb is broken, we have to stick to this version
363365
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
364-
github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.6.1
366+
// TODO: To be replaced with a concrete version number. See:
367+
// - https://github.com/sei-protocol/sei-tendermint/pull/301
368+
github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.6.2-0.20250819154648-ae86e6f22465
365369
github.com/tendermint/tm-db => github.com/sei-protocol/tm-db v0.0.4
366370
golang.org/x/crypto => golang.org/x/crypto v0.31.0
367371
google.golang.org/grpc => google.golang.org/grpc v1.33.2

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,16 +1991,16 @@ github.com/sei-protocol/go-ethereum v1.15.7-sei-3 h1:Xf6qYewZK8+534cXOZI6iDVGYkN
19911991
github.com/sei-protocol/go-ethereum v1.15.7-sei-3/go.mod h1:+S9k+jFzlyVTNcYGvqFhzN/SFhI6vA+aOY4T5tLSPL0=
19921992
github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA=
19931993
github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8=
1994-
github.com/sei-protocol/sei-cosmos v0.3.66 h1:DZL0OWpv+3/tleudTXUeMJtjb2C92O9PiNJBQoYDhBE=
1995-
github.com/sei-protocol/sei-cosmos v0.3.66/go.mod h1:xckXRG0A8Fxr69YNYTE8/aqSprVui3Byt5iJEiSrEQ4=
1994+
github.com/sei-protocol/sei-cosmos v0.3.67-0.20250820133804-748608a73207 h1:zHE2iXpIRLN8ejE7Jc3MliVqTEdkwFzSeGqvYQfYA0k=
1995+
github.com/sei-protocol/sei-cosmos v0.3.67-0.20250820133804-748608a73207/go.mod h1:FrZ7UI0wayVFR63Lf6IRD3c7r2VCsXgULO15EpmGRow=
19961996
github.com/sei-protocol/sei-db v0.0.51 h1:jK6Ps+jDbGdWIPZttaWk7VIsq8aLWWlkTp9axIraL/U=
19971997
github.com/sei-protocol/sei-db v0.0.51/go.mod h1:m5g7p0QeAS3dNJHIl28zQpzOgxQmvYqPb7t4hwgIOCA=
19981998
github.com/sei-protocol/sei-iavl v0.2.0 h1:OisPjXiDT+oe+aeckzDEFgkZCYuUjHgs/PP8DPicN+I=
19991999
github.com/sei-protocol/sei-iavl v0.2.0/go.mod h1:qRf8QYUPfrAO7K6VDB2B2l/N7K5L76OorioGBcJBIbw=
20002000
github.com/sei-protocol/sei-ibc-go/v3 v3.3.6 h1:HHWvrslBpkXBHUFs+azwl36NuFEJyMo6huvsNPG854c=
20012001
github.com/sei-protocol/sei-ibc-go/v3 v3.3.6/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA=
2002-
github.com/sei-protocol/sei-tendermint v0.6.1 h1:iWBlSVZGuyrU7ahf7i/RMd/ZZ01hd4Yvc//R/04gGYo=
2003-
github.com/sei-protocol/sei-tendermint v0.6.1/go.mod h1:hLgRpS2d6VM8XzlhEtFeosCYkpuviU2ztqmOairIivc=
2002+
github.com/sei-protocol/sei-tendermint v0.6.2-0.20250819154648-ae86e6f22465 h1:KxFtE3Cw0wZYRxnOw3wYE6ywHNl0nnn3kiX0RdH+v4o=
2003+
github.com/sei-protocol/sei-tendermint v0.6.2-0.20250819154648-ae86e6f22465/go.mod h1:hLgRpS2d6VM8XzlhEtFeosCYkpuviU2ztqmOairIivc=
20042004
github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY=
20052005
github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY=
20062006
github.com/sei-protocol/sei-wasmd v0.3.9 h1:gHbJcczxZYon4cYfdQz04sKmPdfDUtqA5mDDKW4dp2E=

0 commit comments

Comments
 (0)