Skip to content

Commit 3bb0c90

Browse files
committed
fix: align temporary reject check for included tx from txpool
doc
1 parent 03083a8 commit 3bb0c90

File tree

6 files changed

+44
-49
lines changed

6 files changed

+44
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
- [\#471](https://github.com/cosmos/evm/pull/471) Notify new block for mempool in time.
1010
- [\#492](https://github.com/cosmos/evm/pull/492) Duplicate case switch to avoid empty execution block
11+
- [\#494](https://github.com/cosmos/evm/pull/494) Align temporary reject check for included tx from txpool.
1112

1213
### IMPROVEMENTS
1314

mempool/txpool/legacypool/legacypool.go

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package legacypool
1919

2020
import (
21-
"errors"
2221
"maps"
2322
"math/big"
2423
"slices"
@@ -31,6 +30,7 @@ import (
3130
"github.com/ethereum/go-ethereum/common/prque"
3231
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
3332
"github.com/ethereum/go-ethereum/core"
33+
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
3434
"github.com/ethereum/go-ethereum/core/types"
3535
"github.com/ethereum/go-ethereum/core/vm"
3636
"github.com/ethereum/go-ethereum/crypto/kzg4844"
@@ -58,25 +58,6 @@ const (
5858
txMaxSize = 4 * txSlotSize // 128KB
5959
)
6060

61-
var (
62-
// ErrTxPoolOverflow is returned if the transaction pool is full and can't accept
63-
// another remote transaction.
64-
ErrTxPoolOverflow = errors.New("txpool is full")
65-
66-
// ErrOutOfOrderTxFromDelegated is returned when the transaction with gapped
67-
// nonce received from the accounts with delegation or pending delegation.
68-
ErrOutOfOrderTxFromDelegated = errors.New("gapped-nonce tx from delegated accounts")
69-
70-
// ErrAuthorityReserved is returned if a transaction has an authorization
71-
// signed by an address which already has in-flight transactions known to the
72-
// pool.
73-
ErrAuthorityReserved = errors.New("authority already reserved")
74-
75-
// ErrFutureReplacePending is returned if a future transaction replaces a pending
76-
// one. Future transactions should only be able to replace other future transactions.
77-
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
78-
)
79-
8061
var (
8162
evictionInterval = time.Minute // Time interval to check for evictable transactions
8263
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
@@ -623,7 +604,7 @@ func (pool *LegacyPool) checkDelegationLimit(tx *types.Transaction) error {
623604
if pending == nil {
624605
// Transaction with gapped nonce is not supported for delegated accounts
625606
if pool.pendingNonces.get(from) != tx.Nonce() {
626-
return ErrOutOfOrderTxFromDelegated
607+
return legacypool.ErrOutOfOrderTxFromDelegated
627608
}
628609
return nil
629610
}
@@ -654,7 +635,7 @@ func (pool *LegacyPool) validateAuth(tx *types.Transaction) error {
654635
count += queue.Len()
655636
}
656637
if count > 1 {
657-
return ErrAuthorityReserved
638+
return legacypool.ErrAuthorityReserved
658639
}
659640
// Because there is no exclusive lock held between different subpools
660641
// when processing transactions, the SetCode transaction may be accepted
@@ -665,7 +646,7 @@ func (pool *LegacyPool) validateAuth(tx *types.Transaction) error {
665646
// that attackers cannot easily stack a SetCode transaction when the sender
666647
// is reserved by other pools.
667648
if pool.reserver.Has(auth) {
668-
return ErrAuthorityReserved
649+
return legacypool.ErrAuthorityReserved
669650
}
670651
}
671652
}
@@ -730,7 +711,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) {
730711
// replacements to 25% of the slots
731712
if pool.changesSinceReorg > int(pool.config.GlobalSlots/4) {
732713
throttleTxMeter.Mark(1)
733-
return false, ErrTxPoolOverflow
714+
return false, legacypool.ErrTxPoolOverflow
734715
}
735716

736717
// New transaction is better than our worse ones, make room for it.
@@ -741,7 +722,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) {
741722
if !success {
742723
log.Trace("Discarding overflown transaction", "hash", hash)
743724
overflowedTxMeter.Mark(1)
744-
return false, ErrTxPoolOverflow
725+
return false, legacypool.ErrTxPoolOverflow
745726
}
746727

747728
// If the new transaction is a future transaction it should never churn pending transactions
@@ -760,7 +741,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) {
760741
pool.priced.Put(dropTx)
761742
}
762743
log.Trace("Discarding future transaction replacing pending tx", "hash", hash)
763-
return false, ErrFutureReplacePending
744+
return false, legacypool.ErrFutureReplacePending
764745
}
765746
}
766747

mempool/txpool/legacypool/legacypool_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/ethereum/go-ethereum/core"
3434
"github.com/ethereum/go-ethereum/core/state"
3535
"github.com/ethereum/go-ethereum/core/tracing"
36+
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
3637
"github.com/ethereum/go-ethereum/core/types"
3738
"github.com/ethereum/go-ethereum/core/vm"
3839
"github.com/ethereum/go-ethereum/crypto"
@@ -1674,8 +1675,8 @@ func TestUnderpricing(t *testing.T) {
16741675
t.Fatalf("failed to add well priced transaction: %v", err)
16751676
}
16761677
// Ensure that replacing a pending transaction with a future transaction fails
1677-
if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); !errors.Is(err, ErrFutureReplacePending) {
1678-
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending)
1678+
if err := pool.addRemoteSync(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); !errors.Is(err, legacypool.ErrFutureReplacePending) {
1679+
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, legacypool.ErrFutureReplacePending)
16791680
}
16801681
pending, queued = pool.Stats()
16811682
if pending != 4 {
@@ -2275,8 +2276,8 @@ func TestSetCodeTransactions(t *testing.T) {
22752276
statedb.SetCode(aa, []byte{byte(vm.ADDRESS), byte(vm.PUSH0), byte(vm.SSTORE)})
22762277

22772278
// Send gapped transaction, it should be rejected.
2278-
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, ErrOutOfOrderTxFromDelegated) {
2279-
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrOutOfOrderTxFromDelegated, err)
2279+
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), keyA)); !errors.Is(err, legacypool.ErrOutOfOrderTxFromDelegated) {
2280+
t.Fatalf("%s: error mismatch: want %v, have %v", name, legacypool.ErrOutOfOrderTxFromDelegated, err)
22802281
}
22812282
// Send transactions. First is accepted, second is rejected.
22822283
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), keyA)); err != nil {
@@ -2355,8 +2356,8 @@ func TestSetCodeTransactions(t *testing.T) {
23552356
t.Fatalf("%s: failed to add with pending delegation: %v", name, err)
23562357
}
23572358
// Delegation rejected since two txs are already in-flight.
2358-
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); !errors.Is(err, ErrAuthorityReserved) {
2359-
t.Fatalf("%s: error mismatch: want %v, have %v", name, ErrAuthorityReserved, err)
2359+
if err := pool.addRemoteSync(setCodeTx(0, keyA, []unsignedAuth{{0, keyB}})); !errors.Is(err, legacypool.ErrAuthorityReserved) {
2360+
t.Fatalf("%s: error mismatch: want %v, have %v", name, legacypool.ErrAuthorityReserved, err)
23602361
}
23612362
},
23622363
},

rpc/backend/call_tx.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"encoding/json"
77
"fmt"
88
"math/big"
9-
"strings"
109

1110
"github.com/ethereum/go-ethereum/common"
1211
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -16,7 +15,6 @@ import (
1615
"google.golang.org/grpc/codes"
1716
"google.golang.org/grpc/status"
1817

19-
"github.com/cosmos/evm/mempool"
2018
rpctypes "github.com/cosmos/evm/rpc/types"
2119
evmtypes "github.com/cosmos/evm/x/vm/types"
2220

@@ -147,19 +145,16 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
147145
}
148146

149147
txHash := ethereumTx.AsTransaction().Hash()
150-
151148
syncCtx := b.ClientCtx.WithBroadcastMode(flags.BroadcastSync)
152149
rsp, err := syncCtx.BroadcastTx(txBytes)
153150
if rsp != nil && rsp.Code != 0 {
151+
if HandleBroadcastRawLog(rsp.RawLog, txHash) {
152+
b.Logger.Debug("transaction temporarily rejected or queued", "hash", txHash.Hex())
153+
return txHash, nil
154+
}
154155
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
155156
}
156157
if err != nil {
157-
// Check if this is a nonce gap error that was successfully queued
158-
if strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) {
159-
// Transaction was successfully queued due to nonce gap, return success to client
160-
b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex())
161-
return txHash, nil
162-
}
163158
b.Logger.Error("failed to broadcast tx", "error", err.Error())
164159
return txHash, fmt.Errorf("failed to broadcast transaction: %w", err)
165160
}

rpc/backend/sign_tx.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"errors"
55
"fmt"
66
"math/big"
7-
"strings"
87

98
"github.com/ethereum/go-ethereum/accounts/keystore"
109
"github.com/ethereum/go-ethereum/common"
@@ -13,7 +12,6 @@ import (
1312
"github.com/ethereum/go-ethereum/crypto"
1413
"github.com/ethereum/go-ethereum/signer/core/apitypes"
1514

16-
"github.com/cosmos/evm/mempool"
1715
evmtypes "github.com/cosmos/evm/x/vm/types"
1816

1917
errorsmod "cosmossdk.io/errors"
@@ -106,15 +104,13 @@ func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, e
106104
syncCtx := b.ClientCtx.WithBroadcastMode(flags.BroadcastSync)
107105
rsp, err := syncCtx.BroadcastTx(txBytes)
108106
if rsp != nil && rsp.Code != 0 {
107+
if HandleBroadcastRawLog(rsp.RawLog, txHash) {
108+
b.Logger.Debug("transaction temporarily rejected or queued", "hash", txHash.Hex())
109+
return txHash, nil
110+
}
109111
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
110112
}
111113
if err != nil {
112-
// Check if this is a nonce gap error that was successfully queued
113-
if strings.Contains(err.Error(), mempool.ErrNonceGap.Error()) {
114-
// Transaction was successfully queued due to nonce gap, return success to client
115-
b.Logger.Debug("transaction queued due to nonce gap", "hash", txHash.Hex())
116-
return txHash, nil
117-
}
118114
b.Logger.Error("failed to broadcast tx", "error", err.Error())
119115
return txHash, err
120116
}

rpc/backend/utils.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/ethereum/go-ethereum/common"
1111
"github.com/ethereum/go-ethereum/common/hexutil"
12+
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
1213
ethtypes "github.com/ethereum/go-ethereum/core/types"
1314
"google.golang.org/grpc/codes"
1415
"google.golang.org/grpc/status"
@@ -17,6 +18,8 @@ import (
1718
"github.com/cometbft/cometbft/proto/tendermint/crypto"
1819
cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types"
1920

21+
"github.com/cosmos/evm/mempool"
22+
"github.com/cosmos/evm/mempool/txpool"
2023
"github.com/cosmos/evm/rpc/types"
2124
cosmosevmtypes "github.com/cosmos/evm/types"
2225
"github.com/cosmos/evm/utils"
@@ -291,3 +294,21 @@ func GetHexProofs(proof *crypto.ProofOps) []string {
291294
}
292295
return proofs
293296
}
297+
298+
// HandleBroadcastRawLog checks the RawLog for known temporary rejection or nonce gap error.
299+
// NOTE: make sure it sync with the latest go-ethereum logic when upgrade:
300+
// https://github.com/ethereum/go-ethereum/blob/master/core/txpool/locals/errors.go#L29
301+
func HandleBroadcastRawLog(rawLog string, txHash common.Hash) bool {
302+
switch rawLog {
303+
case legacypool.ErrOutOfOrderTxFromDelegated.Error(),
304+
txpool.ErrInflightTxLimitReached.Error(),
305+
legacypool.ErrAuthorityReserved.Error(),
306+
txpool.ErrUnderpriced.Error(),
307+
legacypool.ErrTxPoolOverflow.Error(),
308+
legacypool.ErrFutureReplacePending.Error():
309+
return true
310+
case mempool.ErrNonceGap.Error():
311+
return true
312+
}
313+
return false
314+
}

0 commit comments

Comments
 (0)