Skip to content

Commit 3c69343

Browse files
authored
Merge pull request #23 from 0glabs/mempool
add bridge to sync tx replacement events between app mempool and cometbft mempool during checkTx
2 parents eb5d71a + 7b722ad commit 3c69343

File tree

5 files changed

+130
-28
lines changed

5 files changed

+130
-28
lines changed

baseapp/abci.go

+28-12
Original file line numberDiff line numberDiff line change
@@ -376,19 +376,35 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
376376
return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace)
377377
}
378378

379-
return abci.ResponseCheckTx{
380-
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
381-
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
382-
Log: result.Log,
383-
Data: result.Data,
384-
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
385-
Priority: priority,
386-
SignerAddress: txInfo.SignerAddress,
387-
Nonce: txInfo.Nonce,
388-
GasLimit: txInfo.GasLimit,
389-
GasPrice: txInfo.GasPrice,
390-
Type: txInfo.Type,
379+
resp := abci.ResponseCheckTx{
380+
GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints?
381+
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
382+
Log: result.Log,
383+
Data: result.Data,
384+
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
385+
Priority: priority,
386+
}
387+
388+
txHash := genTxHash(req.Tx)
389+
390+
app.mempoolSyncLock.Lock()
391+
if _, exists := app.mempoolSyncCache[txHash]; exists {
392+
replacedTx := app.mempoolSyncCache[txHash]
393+
resp.ReplacedTx = make([]byte, len(replacedTx))
394+
copy(resp.ReplacedTx, replacedTx)
395+
delete(app.mempoolSyncCache, txHash)
396+
}
397+
app.mempoolSyncLock.Unlock()
398+
399+
if txInfo != nil {
400+
resp.SignerAddress = txInfo.SignerAddress
401+
resp.Nonce = txInfo.Nonce
402+
resp.GasLimit = txInfo.GasLimit
403+
resp.GasPrice = txInfo.GasPrice
404+
resp.Type = txInfo.TxType
391405
}
406+
407+
return resp
392408
}
393409

394410
// DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode.

baseapp/baseapp.go

+43-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package baseapp
22

33
import (
4+
"context"
5+
"crypto/sha256"
6+
"encoding/hex"
47
"errors"
58
"fmt"
69
"sort"
710
"strings"
11+
"sync"
812

913
dbm "github.com/cometbft/cometbft-db"
1014
abci "github.com/cometbft/cometbft/abci/types"
@@ -145,6 +149,9 @@ type BaseApp struct { //nolint: maligned
145149
abciListeners []ABCIListener
146150

147151
chainID string
152+
153+
mempoolSyncLock sync.RWMutex
154+
mempoolSyncCache map[string][]byte
148155
}
149156

150157
// NewBaseApp returns a reference to an initialized BaseApp. It accepts a
@@ -165,6 +172,7 @@ func NewBaseApp(
165172
msgServiceRouter: NewMsgServiceRouter(),
166173
txDecoder: txDecoder,
167174
fauxMerkleMode: false,
175+
mempoolSyncCache: make(map[string][]byte),
168176
}
169177

170178
for _, option := range options {
@@ -727,6 +735,13 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
727735
}
728736

729737
if mode == runTxModeCheck {
738+
if app.txInfoExtracter != nil {
739+
txInfo, err = app.txInfoExtracter(ctx, tx)
740+
if err != nil {
741+
return gInfo, nil, anteEvents, priority, nil, err
742+
}
743+
}
744+
730745
err = app.mempool.Insert(ctx, tx)
731746
if err != nil {
732747
return gInfo, nil, anteEvents, priority, nil, err
@@ -779,13 +794,6 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re
779794
}
780795
}
781796

782-
if mode == runTxModeCheck && app.txInfoExtracter != nil {
783-
txInfo, err = app.txInfoExtracter(ctx, tx)
784-
if err != nil {
785-
return gInfo, nil, anteEvents, priority, nil, err
786-
}
787-
}
788-
789797
return gInfo, result, anteEvents, priority, txInfo, err
790798
}
791799

@@ -923,3 +931,31 @@ func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) {
923931
func (app *BaseApp) Close() error {
924932
return nil
925933
}
934+
935+
func (app *BaseApp) RegisterMempoolTxReplacedEvent(ctx context.Context, oldTx, newTx sdk.Tx) error {
936+
newRawTx, err := app.txEncoder(newTx)
937+
if err != nil {
938+
return err
939+
}
940+
941+
oldRawTx, err := app.txEncoder(oldTx)
942+
if err != nil {
943+
return err
944+
}
945+
946+
newRawTxHash := genTxHash(newRawTx)
947+
948+
app.mempoolSyncLock.Lock()
949+
app.mempoolSyncCache[newRawTxHash] = oldRawTx
950+
app.mempoolSyncLock.Unlock()
951+
952+
oldRawTxHash := genTxHash(oldRawTx)
953+
app.Logger().Debug("Mempool tx replaced event registered", "new_tx_hash", newRawTxHash, "old_tx_hash", oldRawTxHash)
954+
955+
return nil
956+
}
957+
958+
func genTxHash(tx []byte) string {
959+
hash := sha256.Sum256(tx)
960+
return hex.EncodeToString(hash[:])
961+
}

types/mempool/mempool.go

+30
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ type Mempool interface {
2525
Remove(sdk.Tx) error
2626
}
2727

28+
type MempoolExt interface {
29+
Mempool
30+
31+
// SelectBy use callback to iterate over the mempool, it's thread-safe to use.
32+
SelectBy(context.Context, [][]byte, func(sdk.Tx) bool)
33+
34+
// GetSenderUncommittedTxsCount returns the number of uncommitted transactions for a given sender.
35+
GetSenderUncommittedTxnCount(ctx context.Context, sender string) int
36+
}
37+
2838
// Iterator defines an app-side mempool iterator interface that is as minimal as possible. The order of iteration
2939
// is determined by the app-side mempool implementation.
3040
type Iterator interface {
@@ -39,3 +49,23 @@ var (
3949
ErrTxNotFound = errors.New("tx not found in mempool")
4050
ErrMempoolTxMaxCapacity = errors.New("pool reached max tx capacity")
4151
)
52+
53+
func SelectBy(ctx context.Context, mempool Mempool, txs [][]byte, callback func(sdk.Tx) bool) {
54+
if ext, ok := mempool.(MempoolExt); ok {
55+
ext.SelectBy(ctx, txs, callback)
56+
return
57+
}
58+
59+
// fallback to old behavior, without holding the lock while iteration.
60+
iter := mempool.Select(ctx, txs)
61+
for iter != nil && callback(iter.Tx()) {
62+
iter = iter.Next()
63+
}
64+
}
65+
66+
func GetSenderUncommittedTxnCount(ctx context.Context, mempool Mempool, sender string) int {
67+
if ext, ok := mempool.(MempoolExt); ok {
68+
return ext.GetSenderUncommittedTxnCount(ctx, sender)
69+
}
70+
return 0
71+
}

types/tx_msg.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ type (
7777
Nonce uint64
7878
GasLimit uint64
7979
GasPrice uint64
80-
Type int32
80+
TxType int32
8181
}
8282

8383
TxInfoExtracter func(ctx Context, tx Tx) (*TxInfo, error)

x/auth/ante/validator_tx_fee.go

+28-8
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,42 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins,
4545
return feeCoins, priority, nil
4646
}
4747

48+
const (
49+
chainBaseDenom = "neuron"
50+
cosmosGasDenom = "ua0gi"
51+
standardDenom = "a0gi"
52+
53+
cosmosGasDenomConversionMultiplier = 1e12
54+
standardDenomConversionMultiplier = 1e18
55+
)
56+
4857
// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price
4958
// provided in a transaction.
5059
// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors
5160
// where txs with multiple coins could not be prioritize as expected.
52-
func getTxPriority(fee sdk.Coins, gas int64) int64 {
61+
func getTxPriority(fee sdk.Coins, gasLimit int64) int64 {
5362
var priority int64
63+
64+
totalFeeInBaseDenom := sdk.NewInt(0)
65+
5466
for _, c := range fee {
55-
p := int64(math.MaxInt64)
56-
gasPrice := c.Amount.QuoRaw(gas)
57-
if gasPrice.IsInt64() {
58-
p = gasPrice.Int64()
59-
}
60-
if priority == 0 || p < priority {
61-
priority = p
67+
if c.Denom == chainBaseDenom {
68+
totalFeeInBaseDenom = totalFeeInBaseDenom.Add(c.Amount)
69+
} else if c.Denom == cosmosGasDenom {
70+
totalFeeInBaseDenom = totalFeeInBaseDenom.Add(c.Amount.MulRaw(cosmosGasDenomConversionMultiplier))
71+
} else if c.Denom == standardDenom {
72+
totalFeeInBaseDenom = totalFeeInBaseDenom.Add(c.Amount.MulRaw(standardDenomConversionMultiplier))
73+
} else {
74+
// ignore other denominations
6275
}
6376
}
6477

78+
gasPrice := totalFeeInBaseDenom.QuoRaw(gasLimit)
79+
if gasPrice.IsInt64() {
80+
priority = gasPrice.Int64()
81+
} else {
82+
priority = int64(math.MaxInt64)
83+
}
84+
6585
return priority
6686
}

0 commit comments

Comments
 (0)