Skip to content

Commit c6aae24

Browse files
committed
core/txpool: reject invalid transaction in local tracker
1 parent 389bc8c commit c6aae24

File tree

6 files changed

+44
-18
lines changed

6 files changed

+44
-18
lines changed

core/txpool/blobpool/blobpool.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,19 +1085,24 @@ func (p *BlobPool) SetGasTip(tip *big.Int) {
10851085
p.updateStorageMetrics()
10861086
}
10871087

1088-
// validateTx checks whether a transaction is valid according to the consensus
1089-
// rules and adheres to some heuristic limits of the local node (price and size).
1090-
func (p *BlobPool) validateTx(tx *types.Transaction) error {
1091-
// Ensure the transaction adheres to basic pool filters (type, size, tip) and
1092-
// consensus rules
1093-
baseOpts := &txpool.ValidationOptions{
1088+
// ValidateTxBasics checks whether a transaction is valid according to the consensus
1089+
// rules, but does not check state-dependent validation such as sufficient balance.
1090+
// This check is meant as an early check which only needs to be performed once,
1091+
// and does not require the pool mutex to be held.
1092+
func (p *BlobPool) ValidateTxBasics(tx *types.Transaction) error {
1093+
opts := &txpool.ValidationOptions{
10941094
Config: p.chain.Config(),
10951095
Accept: 1 << types.BlobTxType,
10961096
MaxSize: txMaxSize,
10971097
MinTip: p.gasTip.ToBig(),
10981098
}
1099+
return txpool.ValidateTransaction(tx, p.head, p.signer, opts)
1100+
}
10991101

1100-
if err := p.txValidationFn(tx, p.head, p.signer, baseOpts); err != nil {
1102+
// validateTx checks whether a transaction is valid according to the consensus
1103+
// rules and adheres to some heuristic limits of the local node (price and size).
1104+
func (p *BlobPool) validateTx(tx *types.Transaction) error {
1105+
if err := p.ValidateTxBasics(tx); err != nil {
11011106
return err
11021107
}
11031108
// Ensure the transaction adheres to the stateful pool filters (nonce, balance)

core/txpool/legacypool/legacypool.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -545,11 +545,11 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
545545
return pending
546546
}
547547

548-
// validateTxBasics checks whether a transaction is valid according to the consensus
548+
// ValidateTxBasics checks whether a transaction is valid according to the consensus
549549
// rules, but does not check state-dependent validation such as sufficient balance.
550550
// This check is meant as an early check which only needs to be performed once,
551551
// and does not require the pool mutex to be held.
552-
func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error {
552+
func (pool *LegacyPool) ValidateTxBasics(tx *types.Transaction) error {
553553
opts := &txpool.ValidationOptions{
554554
Config: pool.chainconfig,
555555
Accept: 0 |
@@ -560,10 +560,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction) error {
560560
MaxSize: txMaxSize,
561561
MinTip: pool.gasTip.Load().ToBig(),
562562
}
563-
if err := txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts); err != nil {
564-
return err
565-
}
566-
return nil
563+
return txpool.ValidateTransaction(tx, pool.currentHead.Load(), pool.signer, opts)
567564
}
568565

569566
// validateTx checks whether a transaction is valid according to the consensus
@@ -903,7 +900,7 @@ func (pool *LegacyPool) Add(txs []*types.Transaction, sync bool) []error {
903900
// Exclude transactions with basic errors, e.g invalid signatures and
904901
// insufficient intrinsic gas as soon as possible and cache senders
905902
// in transactions before obtaining lock
906-
if err := pool.validateTxBasics(tx); err != nil {
903+
if err := pool.ValidateTxBasics(tx); err != nil {
907904
errs[i] = err
908905
log.Trace("Discarding invalid transaction", "hash", tx.Hash(), "err", err)
909906
invalidTxMeter.Mark(1)

core/txpool/locals/tx_tracker.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ func (tracker *TxTracker) TrackAll(txs []*types.Transaction) {
8888
if tx.Type() == types.BlobTxType {
8989
continue
9090
}
91+
// Ignore the transactions which are failed for fundamental
92+
// validation such as invalid parameters.
93+
if tracker.pool.ValidateTxBasics(tx) != nil {
94+
continue
95+
}
9196
// If we're already tracking it, it's a no-op
9297
if _, ok := tracker.all[tx.Hash()]; ok {
9398
continue

core/txpool/subpool.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ type SubPool interface {
129129
// retrieve blobs from the pools directly instead of the network.
130130
GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof)
131131

132+
// ValidateTxBasics checks whether a transaction is valid according to the consensus
133+
// rules, but does not check state-dependent validation such as sufficient balance.
134+
// This check is meant as a static check which can be performed without holding the
135+
// pool mutex.
136+
ValidateTxBasics(tx *types.Transaction) error
137+
132138
// Add enqueues a batch of transactions into the pool if they are valid. Due
133139
// to the large transaction churn, add may postpone fully integrating the tx
134140
// to a later point to batch multiple ones together.

core/txpool/txpool.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,17 @@ func (p *TxPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Pr
325325
return nil, nil
326326
}
327327

328+
// ValidateTxBasics checks whether a transaction is valid according to the consensus
329+
// rules, but does not check state-dependent validation such as sufficient balance.
330+
func (p *TxPool) ValidateTxBasics(tx *types.Transaction) error {
331+
for _, subpool := range p.subpools {
332+
if subpool.Filter(tx) {
333+
return subpool.ValidateTxBasics(tx)
334+
}
335+
}
336+
return fmt.Errorf("%w: received type %d", core.ErrTxTypeNotSupported, tx.Type())
337+
}
338+
328339
// Add enqueues a batch of transactions into the pool if they are valid. Due
329340
// to the large transaction churn, add may postpone fully integrating the tx
330341
// to a later point to batch multiple ones together.

eth/api_backend.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,15 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri
272272
}
273273

274274
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
275-
if err := b.eth.txPool.Add([]*types.Transaction{signedTx}, false)[0]; err != nil {
276-
return err
277-
}
278275
if locals := b.eth.localTxTracker; locals != nil {
279276
locals.Track(signedTx)
280277
}
281-
return nil
278+
// TODO(rjl493456442): If a transaction fails stateful validation (e.g., no
279+
// available slot), an error will be returned to the user. However, locally
280+
// submitted transactions may be resubmitted later via the local tracker, which
281+
// could cause confusion that a previously "rejected" transaction is later
282+
// accepted.
283+
return b.eth.txPool.Add([]*types.Transaction{signedTx}, false)[0]
282284
}
283285

284286
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {

0 commit comments

Comments
 (0)