mirror of
https://github.com/0glabs/0g-chain.git
synced 2025-04-04 15:55:23 +00:00
Merge 0b027e10ed
into dc888ceb78
This commit is contained in:
commit
008af7556c
@ -2,10 +2,13 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/huandu/skiplist"
|
"github.com/huandu/skiplist"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/mempool"
|
"github.com/cosmos/cosmos-sdk/types/mempool"
|
||||||
@ -14,11 +17,15 @@ import (
|
|||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MAX_TXS_PRE_SENDER_IN_MEMPOOL int = 10
|
const MAX_TXS_PRE_SENDER_IN_MEMPOOL int = 16
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ mempool.Mempool = (*PriorityNonceMempool)(nil)
|
_ mempool.Mempool = (*PriorityNonceMempool)(nil)
|
||||||
_ mempool.Iterator = (*PriorityNonceIterator)(nil)
|
_ mempool.Iterator = (*PriorityNonceIterator)(nil)
|
||||||
|
|
||||||
|
errMempoolTxGasPriceTooLow = errors.New("gas price is too low")
|
||||||
|
errMempoolTooManyTxs = errors.New("tx sender has too many txs in mempool")
|
||||||
|
errMempoolIsFull = errors.New("mempool is full")
|
||||||
)
|
)
|
||||||
|
|
||||||
// PriorityNonceMempool is a mempool implementation that stores txs
|
// PriorityNonceMempool is a mempool implementation that stores txs
|
||||||
@ -29,14 +36,19 @@ var (
|
|||||||
// priority to other sender txs and must be partially ordered by both sender-nonce
|
// priority to other sender txs and must be partially ordered by both sender-nonce
|
||||||
// and priority.
|
// and priority.
|
||||||
type PriorityNonceMempool struct {
|
type PriorityNonceMempool struct {
|
||||||
priorityIndex *skiplist.SkipList
|
priorityIndex *skiplist.SkipList
|
||||||
priorityCounts map[int64]int
|
priorityCounts map[int64]int
|
||||||
senderIndices map[string]*skiplist.SkipList
|
senderIndices map[string]*skiplist.SkipList
|
||||||
scores map[txMeta]txMeta
|
scores map[txMeta]txMeta
|
||||||
onRead func(tx sdk.Tx)
|
onRead func(tx sdk.Tx)
|
||||||
txReplacement func(op, np int64, oTx, nTx sdk.Tx) bool
|
txReplacement func(op, np int64, oTx, nTx sdk.Tx) bool
|
||||||
maxTx int
|
maxTx int
|
||||||
|
|
||||||
|
senderTxCntLock sync.RWMutex
|
||||||
counterBySender map[string]int
|
counterBySender map[string]int
|
||||||
|
txRecord map[txMeta]struct{}
|
||||||
|
|
||||||
|
txReplacedCallback func(ctx context.Context, oldTx, newTx sdk.Tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PriorityNonceIterator struct {
|
type PriorityNonceIterator struct {
|
||||||
@ -123,6 +135,12 @@ func PriorityNonceWithMaxTx(maxTx int) PriorityNonceMempoolOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PriorityNonceWithTxReplacedCallback(cb func(ctx context.Context, oldTx, newTx sdk.Tx)) PriorityNonceMempoolOption {
|
||||||
|
return func(mp *PriorityNonceMempool) {
|
||||||
|
mp.txReplacedCallback = cb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultPriorityMempool returns a priorityNonceMempool with no options.
|
// DefaultPriorityMempool returns a priorityNonceMempool with no options.
|
||||||
func DefaultPriorityMempool() mempool.Mempool {
|
func DefaultPriorityMempool() mempool.Mempool {
|
||||||
return NewPriorityMempool()
|
return NewPriorityMempool()
|
||||||
@ -137,6 +155,7 @@ func NewPriorityMempool(opts ...PriorityNonceMempoolOption) *PriorityNonceMempoo
|
|||||||
senderIndices: make(map[string]*skiplist.SkipList),
|
senderIndices: make(map[string]*skiplist.SkipList),
|
||||||
scores: make(map[txMeta]txMeta),
|
scores: make(map[txMeta]txMeta),
|
||||||
counterBySender: make(map[string]int),
|
counterBySender: make(map[string]int),
|
||||||
|
txRecord: make(map[txMeta]struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -169,67 +188,37 @@ func (mp *PriorityNonceMempool) NextSenderTx(sender string) sdk.Tx {
|
|||||||
// Inserting a duplicate tx with a different priority overwrites the existing tx,
|
// Inserting a duplicate tx with a different priority overwrites the existing tx,
|
||||||
// changing the total order of the mempool.
|
// changing the total order of the mempool.
|
||||||
func (mp *PriorityNonceMempool) Insert(ctx context.Context, tx sdk.Tx) error {
|
func (mp *PriorityNonceMempool) Insert(ctx context.Context, tx sdk.Tx) error {
|
||||||
if mp.maxTx > 0 && mp.CountTx() >= mp.maxTx {
|
// if mp.maxTx > 0 && mp.CountTx() >= mp.maxTx {
|
||||||
return mempool.ErrMempoolTxMaxCapacity
|
// return mempool.ErrMempoolTxMaxCapacity
|
||||||
} else if mp.maxTx < 0 {
|
// } else
|
||||||
|
if mp.maxTx < 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
|
sdkContext := sdk.UnwrapSDKContext(ctx)
|
||||||
|
priority := sdkContext.Priority()
|
||||||
|
txInfo, err := extractTxInfo(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sdkContext := sdk.UnwrapSDKContext(ctx)
|
|
||||||
priority := sdkContext.Priority()
|
|
||||||
|
|
||||||
var sender string
|
if !mp.canInsert(txInfo.sender) {
|
||||||
var nonce uint64
|
return errors.Wrapf(errMempoolTooManyTxs, "sender %s has too many txs in mempool", txInfo.sender)
|
||||||
|
|
||||||
if len(sigs) == 0 {
|
|
||||||
msgs := tx.GetMsgs()
|
|
||||||
if len(msgs) != 1 {
|
|
||||||
return fmt.Errorf("tx must have at least one signer")
|
|
||||||
}
|
|
||||||
msgEthTx, ok := msgs[0].(*evmtypes.MsgEthereumTx)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("tx must have at least one signer")
|
|
||||||
}
|
|
||||||
ethTx := msgEthTx.AsTransaction()
|
|
||||||
signer := gethtypes.NewEIP2930Signer(ethTx.ChainId())
|
|
||||||
ethSender, err := signer.Sender(ethTx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("tx must have at least one signer")
|
|
||||||
}
|
|
||||||
sender = sdk.AccAddress(ethSender.Bytes()).String()
|
|
||||||
nonce = ethTx.Nonce()
|
|
||||||
} else {
|
|
||||||
sig := sigs[0]
|
|
||||||
sender = sdk.AccAddress(sig.PubKey.Address()).String()
|
|
||||||
nonce = sig.Sequence
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := mp.counterBySender[sender]; !exists {
|
// init sender index if not exists
|
||||||
mp.counterBySender[sender] = 1
|
senderIndex, ok := mp.senderIndices[txInfo.sender]
|
||||||
} else {
|
|
||||||
if mp.counterBySender[sender] < MAX_TXS_PRE_SENDER_IN_MEMPOOL {
|
|
||||||
mp.counterBySender[sender] += 1
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("tx sender has too many txs in mempool")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key := txMeta{nonce: nonce, priority: priority, sender: sender}
|
|
||||||
|
|
||||||
senderIndex, ok := mp.senderIndices[sender]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
senderIndex = skiplist.New(skiplist.LessThanFunc(func(a, b any) int {
|
senderIndex = skiplist.New(skiplist.LessThanFunc(func(a, b any) int {
|
||||||
return skiplist.Uint64.Compare(b.(txMeta).nonce, a.(txMeta).nonce)
|
return skiplist.Uint64.Compare(b.(txMeta).nonce, a.(txMeta).nonce)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// initialize sender index if not found
|
// initialize sender index if not found
|
||||||
mp.senderIndices[sender] = senderIndex
|
mp.senderIndices[txInfo.sender] = senderIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newKey := txMeta{nonce: txInfo.nonce, priority: priority, sender: txInfo.sender}
|
||||||
|
|
||||||
// Since mp.priorityIndex is scored by priority, then sender, then nonce, a
|
// Since mp.priorityIndex is scored by priority, then sender, then nonce, a
|
||||||
// changed priority will create a new key, so we must remove the old key and
|
// changed priority will create a new key, so we must remove the old key and
|
||||||
// re-insert it to avoid having the same tx with different priorityIndex indexed
|
// re-insert it to avoid having the same tx with different priorityIndex indexed
|
||||||
@ -237,35 +226,145 @@ func (mp *PriorityNonceMempool) Insert(ctx context.Context, tx sdk.Tx) error {
|
|||||||
//
|
//
|
||||||
// This O(log n) remove operation is rare and only happens when a tx's priority
|
// This O(log n) remove operation is rare and only happens when a tx's priority
|
||||||
// changes.
|
// changes.
|
||||||
sk := txMeta{nonce: nonce, sender: sender}
|
|
||||||
if oldScore, txExists := mp.scores[sk]; txExists {
|
|
||||||
if mp.txReplacement != nil && !mp.txReplacement(oldScore.priority, priority, senderIndex.Get(key).Value.(sdk.Tx), tx) {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"tx doesn't fit the replacement rule, oldPriority: %v, newPriority: %v, oldTx: %v, newTx: %v",
|
|
||||||
oldScore.priority,
|
|
||||||
priority,
|
|
||||||
senderIndex.Get(key).Value.(sdk.Tx),
|
|
||||||
tx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
mp.priorityIndex.Remove(txMeta{
|
sk := txMeta{nonce: txInfo.nonce, sender: txInfo.sender}
|
||||||
nonce: nonce,
|
if oldScore, txExists := mp.scores[sk]; txExists {
|
||||||
sender: sender,
|
oldTx := senderIndex.Get(newKey).Value.(sdk.Tx)
|
||||||
priority: oldScore.priority,
|
return mp.doTxReplace(ctx, newKey, oldScore, oldTx, tx)
|
||||||
weight: oldScore.weight,
|
} else {
|
||||||
})
|
mempoolSize := mp.CountTx()
|
||||||
mp.priorityCounts[oldScore.priority]--
|
if mempoolSize >= mp.maxTx {
|
||||||
|
lowestPriority := mp.GetLowestPriority()
|
||||||
|
// find one to replace
|
||||||
|
if lowestPriority > 0 && priority <= lowestPriority {
|
||||||
|
return errors.Wrapf(errMempoolTxGasPriceTooLow, "tx with priority %d is too low, current lowest priority is %d", priority, lowestPriority)
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxIndexSize int
|
||||||
|
var lowerPriority int64 = math.MaxInt64
|
||||||
|
var selectedElement *skiplist.Element
|
||||||
|
for sender, index := range mp.senderIndices {
|
||||||
|
indexSize := index.Len()
|
||||||
|
if sender == txInfo.sender {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if indexSize > 1 {
|
||||||
|
tail := index.Back()
|
||||||
|
if tail != nil {
|
||||||
|
tailKey := tail.Key().(txMeta)
|
||||||
|
if tailKey.priority < lowerPriority {
|
||||||
|
lowerPriority = tailKey.priority
|
||||||
|
maxIndexSize = indexSize
|
||||||
|
selectedElement = tail
|
||||||
|
} else if tailKey.priority == lowerPriority {
|
||||||
|
if indexSize > maxIndexSize {
|
||||||
|
maxIndexSize = indexSize
|
||||||
|
selectedElement = tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selectedElement != nil {
|
||||||
|
key := selectedElement.Key().(txMeta)
|
||||||
|
replacedTx, _ := mp.doRemove(key, true)
|
||||||
|
|
||||||
|
// insert new tx
|
||||||
|
mp.doInsert(newKey, tx, true)
|
||||||
|
|
||||||
|
if mp.txReplacedCallback != nil && replacedTx != nil {
|
||||||
|
mp.txReplacedCallback(ctx, replacedTx, tx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not found any index more than 1 except sender's index
|
||||||
|
// We do not replace the sender's only tx in the mempool
|
||||||
|
return errMempoolIsFull
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mp.doInsert(newKey, tx, true)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) doInsert(newKey txMeta, tx sdk.Tx, incrCnt bool) {
|
||||||
|
senderIndex, ok := mp.senderIndices[newKey.sender]
|
||||||
|
if !ok {
|
||||||
|
senderIndex = skiplist.New(skiplist.LessThanFunc(func(a, b any) int {
|
||||||
|
return skiplist.Uint64.Compare(b.(txMeta).nonce, a.(txMeta).nonce)
|
||||||
|
}))
|
||||||
|
|
||||||
|
// initialize sender index if not found
|
||||||
|
mp.senderIndices[newKey.sender] = senderIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
mp.priorityCounts[priority]++
|
mp.priorityCounts[newKey.priority]++
|
||||||
|
newKey.senderElement = senderIndex.Set(newKey, tx)
|
||||||
|
|
||||||
// Since senderIndex is scored by nonce, a changed priority will overwrite the
|
mp.scores[txMeta{nonce: newKey.nonce, sender: newKey.sender}] = txMeta{priority: newKey.priority}
|
||||||
// existing key.
|
mp.priorityIndex.Set(newKey, tx)
|
||||||
key.senderElement = senderIndex.Set(key, tx)
|
|
||||||
|
|
||||||
mp.scores[sk] = txMeta{priority: priority}
|
if incrCnt {
|
||||||
mp.priorityIndex.Set(key, tx)
|
mp.incrSenderTxCnt(newKey.sender, newKey.nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) doRemove(oldKey txMeta, decrCnt bool) (sdk.Tx, error) {
|
||||||
|
scoreKey := txMeta{nonce: oldKey.nonce, sender: oldKey.sender}
|
||||||
|
score, ok := mp.scores[scoreKey]
|
||||||
|
if !ok {
|
||||||
|
return nil, mempool.ErrTxNotFound
|
||||||
|
}
|
||||||
|
tk := txMeta{nonce: oldKey.nonce, priority: score.priority, sender: oldKey.sender, weight: score.weight}
|
||||||
|
|
||||||
|
senderTxs, ok := mp.senderIndices[oldKey.sender]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("sender %s not found", oldKey.sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.priorityIndex.Remove(tk)
|
||||||
|
removedElem := senderTxs.Remove(tk)
|
||||||
|
delete(mp.scores, scoreKey)
|
||||||
|
mp.priorityCounts[score.priority]--
|
||||||
|
|
||||||
|
if decrCnt {
|
||||||
|
mp.decrSenderTxCnt(oldKey.sender, oldKey.nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
if removedElem == nil {
|
||||||
|
return nil, mempool.ErrTxNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return removedElem.Value.(sdk.Tx), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) doTxReplace(ctx context.Context, newMate, oldMate txMeta, oldTx, newTx sdk.Tx) error {
|
||||||
|
if mp.txReplacement != nil && !mp.txReplacement(oldMate.priority, newMate.priority, oldTx, newTx) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"tx doesn't fit the replacement rule, oldPriority: %v, newPriority: %v, oldTx: %v, newTx: %v",
|
||||||
|
oldMate.priority,
|
||||||
|
newMate.priority,
|
||||||
|
oldTx,
|
||||||
|
newTx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
e := mp.priorityIndex.Remove(txMeta{
|
||||||
|
nonce: newMate.nonce,
|
||||||
|
sender: newMate.sender,
|
||||||
|
priority: oldMate.priority,
|
||||||
|
weight: oldMate.weight,
|
||||||
|
})
|
||||||
|
replacedTx := e.Value.(sdk.Tx)
|
||||||
|
mp.priorityCounts[oldMate.priority]--
|
||||||
|
|
||||||
|
mp.doInsert(newMate, newTx, false)
|
||||||
|
|
||||||
|
if mp.txReplacedCallback != nil && replacedTx != nil {
|
||||||
|
mp.txReplacedCallback(ctx, replacedTx, newTx)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -421,45 +520,23 @@ func (mp *PriorityNonceMempool) CountTx() int {
|
|||||||
// Remove removes a transaction from the mempool in O(log n) time, returning an
|
// Remove removes a transaction from the mempool in O(log n) time, returning an
|
||||||
// error if unsuccessful.
|
// error if unsuccessful.
|
||||||
func (mp *PriorityNonceMempool) Remove(tx sdk.Tx) error {
|
func (mp *PriorityNonceMempool) Remove(tx sdk.Tx) error {
|
||||||
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
|
txInfo, err := extractTxInfo(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var sender string
|
|
||||||
var nonce uint64
|
|
||||||
if len(sigs) == 0 {
|
|
||||||
msgs := tx.GetMsgs()
|
|
||||||
if len(msgs) != 1 {
|
|
||||||
return fmt.Errorf("attempted to remove a tx with no signatures")
|
|
||||||
}
|
|
||||||
msgEthTx, ok := msgs[0].(*evmtypes.MsgEthereumTx)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("attempted to remove a tx with no signatures")
|
|
||||||
}
|
|
||||||
ethTx := msgEthTx.AsTransaction()
|
|
||||||
signer := gethtypes.NewEIP2930Signer(ethTx.ChainId())
|
|
||||||
ethSender, err := signer.Sender(ethTx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("attempted to remove a tx with no signatures")
|
|
||||||
}
|
|
||||||
sender = sdk.AccAddress(ethSender.Bytes()).String()
|
|
||||||
nonce = ethTx.Nonce()
|
|
||||||
} else {
|
|
||||||
sig := sigs[0]
|
|
||||||
sender = sdk.AccAddress(sig.PubKey.Address()).String()
|
|
||||||
nonce = sig.Sequence
|
|
||||||
}
|
|
||||||
|
|
||||||
scoreKey := txMeta{nonce: nonce, sender: sender}
|
mp.decrSenderTxCnt(txInfo.sender, txInfo.nonce)
|
||||||
|
|
||||||
|
scoreKey := txMeta{nonce: txInfo.nonce, sender: txInfo.sender}
|
||||||
score, ok := mp.scores[scoreKey]
|
score, ok := mp.scores[scoreKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return mempool.ErrTxNotFound
|
return mempool.ErrTxNotFound
|
||||||
}
|
}
|
||||||
tk := txMeta{nonce: nonce, priority: score.priority, sender: sender, weight: score.weight}
|
tk := txMeta{nonce: txInfo.nonce, priority: score.priority, sender: txInfo.sender, weight: score.weight}
|
||||||
|
|
||||||
senderTxs, ok := mp.senderIndices[sender]
|
senderTxs, ok := mp.senderIndices[txInfo.sender]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("sender %s not found", sender)
|
return fmt.Errorf("sender %s not found", txInfo.sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
mp.priorityIndex.Remove(tk)
|
mp.priorityIndex.Remove(tk)
|
||||||
@ -467,17 +544,76 @@ func (mp *PriorityNonceMempool) Remove(tx sdk.Tx) error {
|
|||||||
delete(mp.scores, scoreKey)
|
delete(mp.scores, scoreKey)
|
||||||
mp.priorityCounts[score.priority]--
|
mp.priorityCounts[score.priority]--
|
||||||
|
|
||||||
if _, exists := mp.counterBySender[sender]; exists {
|
return nil
|
||||||
if mp.counterBySender[sender] > 1 {
|
}
|
||||||
mp.counterBySender[sender] -= 1
|
|
||||||
} else {
|
func (mp *PriorityNonceMempool) GetLowestPriority() int64 {
|
||||||
delete(mp.counterBySender, sender)
|
if mp.priorityIndex.Len() == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
min := int64(math.MaxInt64)
|
||||||
|
for priority, count := range mp.priorityCounts {
|
||||||
|
if count > 0 {
|
||||||
|
if priority < min {
|
||||||
|
min = priority
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) canInsert(sender string) bool {
|
||||||
|
mp.senderTxCntLock.RLock()
|
||||||
|
defer mp.senderTxCntLock.RUnlock()
|
||||||
|
|
||||||
|
if _, exists := mp.counterBySender[sender]; exists {
|
||||||
|
return mp.counterBySender[sender] < MAX_TXS_PRE_SENDER_IN_MEMPOOL
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) incrSenderTxCnt(sender string, nonce uint64) error {
|
||||||
|
mp.senderTxCntLock.Lock()
|
||||||
|
defer mp.senderTxCntLock.Unlock()
|
||||||
|
|
||||||
|
existsKey := txMeta{nonce: nonce, sender: sender}
|
||||||
|
if _, exists := mp.txRecord[existsKey]; !exists {
|
||||||
|
mp.txRecord[existsKey] = struct{}{}
|
||||||
|
|
||||||
|
if _, exists := mp.counterBySender[sender]; !exists {
|
||||||
|
mp.counterBySender[sender] = 1
|
||||||
|
} else {
|
||||||
|
if mp.counterBySender[sender] < MAX_TXS_PRE_SENDER_IN_MEMPOOL {
|
||||||
|
mp.counterBySender[sender] += 1
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("tx sender has too many txs in mempool")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mp *PriorityNonceMempool) decrSenderTxCnt(sender string, nonce uint64) {
|
||||||
|
mp.senderTxCntLock.Lock()
|
||||||
|
defer mp.senderTxCntLock.Unlock()
|
||||||
|
|
||||||
|
existsKey := txMeta{nonce: nonce, sender: sender}
|
||||||
|
if _, exists := mp.txRecord[existsKey]; exists {
|
||||||
|
delete(mp.txRecord, existsKey)
|
||||||
|
|
||||||
|
if _, exists := mp.counterBySender[sender]; exists {
|
||||||
|
if mp.counterBySender[sender] > 1 {
|
||||||
|
mp.counterBySender[sender] -= 1
|
||||||
|
} else {
|
||||||
|
delete(mp.counterBySender, sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func IsEmpty(mempool mempool.Mempool) error {
|
func IsEmpty(mempool mempool.Mempool) error {
|
||||||
mp := mempool.(*PriorityNonceMempool)
|
mp := mempool.(*PriorityNonceMempool)
|
||||||
if mp.priorityIndex.Len() != 0 {
|
if mp.priorityIndex.Len() != 0 {
|
||||||
@ -508,3 +644,43 @@ func IsEmpty(mempool mempool.Mempool) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type txInfo struct {
|
||||||
|
sender string
|
||||||
|
nonce uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractTxInfo(tx sdk.Tx) (*txInfo, error) {
|
||||||
|
var sender string
|
||||||
|
var nonce uint64
|
||||||
|
|
||||||
|
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sigs) == 0 {
|
||||||
|
msgs := tx.GetMsgs()
|
||||||
|
if len(msgs) != 1 {
|
||||||
|
return nil, fmt.Errorf("tx must have at least one signer")
|
||||||
|
}
|
||||||
|
msgEthTx, ok := msgs[0].(*evmtypes.MsgEthereumTx)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("tx must have at least one signer")
|
||||||
|
}
|
||||||
|
ethTx := msgEthTx.AsTransaction()
|
||||||
|
signer := gethtypes.NewEIP2930Signer(ethTx.ChainId())
|
||||||
|
ethSender, err := signer.Sender(ethTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("tx must have at least one signer")
|
||||||
|
}
|
||||||
|
sender = sdk.AccAddress(ethSender.Bytes()).String()
|
||||||
|
nonce = ethTx.Nonce()
|
||||||
|
} else {
|
||||||
|
sig := sigs[0]
|
||||||
|
sender = sdk.AccAddress(sig.PubKey.Address()).String()
|
||||||
|
nonce = sig.Sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
return &txInfo{sender: sender, nonce: nonce}, nil
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||||
ethermintflags "github.com/evmos/ethermint/server/flags"
|
ethermintflags "github.com/evmos/ethermint/server/flags"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
@ -26,6 +28,8 @@ import (
|
|||||||
|
|
||||||
"github.com/0glabs/0g-chain/app"
|
"github.com/0glabs/0g-chain/app"
|
||||||
"github.com/0glabs/0g-chain/app/params"
|
"github.com/0glabs/0g-chain/app/params"
|
||||||
|
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -107,8 +111,6 @@ func (ac appCreator) newApp(
|
|||||||
skipLoadLatest = cast.ToBool(appOpts.Get(flagSkipLoadLatest))
|
skipLoadLatest = cast.ToBool(appOpts.Get(flagSkipLoadLatest))
|
||||||
}
|
}
|
||||||
|
|
||||||
mempool := app.NewPriorityMempool()
|
|
||||||
|
|
||||||
bApp := app.NewBaseApp(logger, db, ac.encodingConfig,
|
bApp := app.NewBaseApp(logger, db, ac.encodingConfig,
|
||||||
baseapp.SetPruning(pruningOpts),
|
baseapp.SetPruning(pruningOpts),
|
||||||
baseapp.SetMinGasPrices(strings.Replace(cast.ToString(appOpts.Get(server.FlagMinGasPrices)), ";", ",", -1)),
|
baseapp.SetMinGasPrices(strings.Replace(cast.ToString(appOpts.Get(server.FlagMinGasPrices)), ";", ",", -1)),
|
||||||
@ -123,8 +125,17 @@ func (ac appCreator) newApp(
|
|||||||
baseapp.SetIAVLDisableFastNode(cast.ToBool(iavlDisableFastNode)),
|
baseapp.SetIAVLDisableFastNode(cast.ToBool(iavlDisableFastNode)),
|
||||||
baseapp.SetIAVLLazyLoading(cast.ToBool(appOpts.Get(server.FlagIAVLLazyLoading))),
|
baseapp.SetIAVLLazyLoading(cast.ToBool(appOpts.Get(server.FlagIAVLLazyLoading))),
|
||||||
baseapp.SetChainID(chainID),
|
baseapp.SetChainID(chainID),
|
||||||
baseapp.SetMempool(mempool),
|
baseapp.SetTxInfoExtracter(extractTxInfo),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mempool := app.NewPriorityMempool(
|
||||||
|
app.PriorityNonceWithMaxTx(fixMempoolSize(appOpts)),
|
||||||
|
app.PriorityNonceWithTxReplacedCallback(func(ctx context.Context, oldTx, newTx sdk.Tx) {
|
||||||
|
bApp.RegisterMempoolTxReplacedEvent(ctx, oldTx, newTx)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
bApp.SetMempool(mempool)
|
||||||
|
|
||||||
bApp.SetTxEncoder(ac.encodingConfig.TxConfig.TxEncoder())
|
bApp.SetTxEncoder(ac.encodingConfig.TxConfig.TxEncoder())
|
||||||
abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp)
|
abciProposalHandler := app.NewDefaultProposalHandler(mempool, bApp)
|
||||||
bApp.SetPrepareProposal(abciProposalHandler.PrepareProposalHandler())
|
bApp.SetPrepareProposal(abciProposalHandler.PrepareProposalHandler())
|
||||||
@ -199,3 +210,72 @@ func accAddressesFromBech32(addresses ...string) ([]sdk.AccAddress, error) {
|
|||||||
}
|
}
|
||||||
return decodedAddresses, nil
|
return decodedAddresses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrMustHaveSigner error = errors.New("tx must have at least one signer")
|
||||||
|
|
||||||
|
func extractTxInfo(ctx sdk.Context, tx sdk.Tx) (*sdk.TxInfo, error) {
|
||||||
|
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sender string
|
||||||
|
var nonce uint64
|
||||||
|
var gasPrice uint64
|
||||||
|
var gasLimit uint64
|
||||||
|
var txType int32
|
||||||
|
|
||||||
|
if len(sigs) == 0 {
|
||||||
|
txType = 1
|
||||||
|
msgs := tx.GetMsgs()
|
||||||
|
if len(msgs) != 1 {
|
||||||
|
return nil, ErrMustHaveSigner
|
||||||
|
}
|
||||||
|
msgEthTx, ok := msgs[0].(*evmtypes.MsgEthereumTx)
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrMustHaveSigner
|
||||||
|
}
|
||||||
|
ethTx := msgEthTx.AsTransaction()
|
||||||
|
signer := gethtypes.NewEIP2930Signer(ethTx.ChainId())
|
||||||
|
ethSender, err := signer.Sender(ethTx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrMustHaveSigner
|
||||||
|
}
|
||||||
|
sender = sdk.AccAddress(ethSender.Bytes()).String()
|
||||||
|
nonce = ethTx.Nonce()
|
||||||
|
gasPrice = ethTx.GasPrice().Uint64()
|
||||||
|
gasLimit = ethTx.Gas()
|
||||||
|
} else {
|
||||||
|
sig := sigs[0]
|
||||||
|
sender = sdk.AccAddress(sig.PubKey.Address()).String()
|
||||||
|
nonce = sig.Sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
return &sdk.TxInfo{
|
||||||
|
SignerAddress: sender,
|
||||||
|
Nonce: nonce,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
TxType: txType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixMempoolSize(appOpts servertypes.AppOptions) int {
|
||||||
|
val1 := appOpts.Get("mempool.size")
|
||||||
|
val2 := appOpts.Get(server.FlagMempoolMaxTxs)
|
||||||
|
|
||||||
|
if val1 != nil && val2 != nil {
|
||||||
|
size1 := cast.ToInt(val1)
|
||||||
|
size2 := cast.ToInt(val2)
|
||||||
|
if size1 != size2 {
|
||||||
|
panic("the value of mempool.size and mempool.max-txs are different")
|
||||||
|
}
|
||||||
|
return size1
|
||||||
|
} else if val1 == nil && val2 == nil {
|
||||||
|
panic("not found mempool size in config")
|
||||||
|
} else if val1 == nil {
|
||||||
|
return cast.ToInt(val2)
|
||||||
|
} else { //if val2 == nil {
|
||||||
|
return cast.ToInt(val1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -250,7 +250,7 @@ replace (
|
|||||||
// TODO: Tag before release
|
// TODO: Tag before release
|
||||||
github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2
|
github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc2
|
||||||
// Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support
|
// Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, and includes eip712 support
|
||||||
github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.12
|
github.com/evmos/ethermint => github.com/0glabs/ethermint v0.21.0-0g.v3.1.14
|
||||||
// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
|
// See https://github.com/cosmos/cosmos-sdk/pull/10401, https://github.com/cosmos/cosmos-sdk/commit/0592ba6158cd0bf49d894be1cef4faeec59e8320
|
||||||
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
|
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
|
||||||
// Downgraded to avoid bugs in following commits which causes "version does not exist" errors
|
// Downgraded to avoid bugs in following commits which causes "version does not exist" errors
|
||||||
|
4
go.sum
4
go.sum
@ -213,8 +213,8 @@ github.com/0glabs/cometbft v0.37.9-0glabs.1 h1:KQJG17Y21suKP3QNICLto4b5Ak73XbSmK
|
|||||||
github.com/0glabs/cometbft v0.37.9-0glabs.1/go.mod h1:j0Q3RqrCd+cztWCugs3obbzC4NyHGBPZZjtm/fWV00I=
|
github.com/0glabs/cometbft v0.37.9-0glabs.1/go.mod h1:j0Q3RqrCd+cztWCugs3obbzC4NyHGBPZZjtm/fWV00I=
|
||||||
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10 h1:NJp0RwczHBO4EvrQdDxxftHOgUDBtNh7M/vpaG7wFtQ=
|
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10 h1:NJp0RwczHBO4EvrQdDxxftHOgUDBtNh7M/vpaG7wFtQ=
|
||||||
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10/go.mod h1:KskIVnhXTFqrw7CDccMvx7To5KzUsOomIsQV7sPGOog=
|
github.com/0glabs/cosmos-sdk v0.47.10-0glabs.10/go.mod h1:KskIVnhXTFqrw7CDccMvx7To5KzUsOomIsQV7sPGOog=
|
||||||
github.com/0glabs/ethermint v0.21.0-0g.v3.1.12 h1:IRVTFhDEH2J5w8ywQW7obXQxYhJYib70SNgKqLOXikU=
|
github.com/0glabs/ethermint v0.21.0-0g.v3.1.14 h1:Ns1TNEwcOScVt8qlAYK3tZ5Xf0o0v+7IRZCFb1BL2TY=
|
||||||
github.com/0glabs/ethermint v0.21.0-0g.v3.1.12/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
|
github.com/0glabs/ethermint v0.21.0-0g.v3.1.14/go.mod h1:6e/gOcDLhvlDWK3JLJVBgki0gD6H4E1eG7l9byocgWA=
|
||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
|
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
|
||||||
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
|
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
|
||||||
|
Loading…
Reference in New Issue
Block a user