Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9b17b0a
core/types: add 1559 compatibility to Transaction helpers
adietrichs Feb 5, 2021
e1bb4a8
core/txpool: update TxPool for EIP-1559 compatibility
adietrichs Feb 5, 2021
1785e33
core/txpool: add Tip as secondary comparison criterion on txPricedLis…
adietrichs Feb 15, 2021
ef9e28b
core/txpool: add ErrTipAboveFeeCap error and respective check during …
adietrichs Feb 15, 2021
9209005
core/txpool: refactor: create txLookup.RemotesBelowTip() to facilitat…
adietrichs Feb 15, 2021
1a114fb
core/txpool: tests: add dynamicFeeTransaction() helper function
adietrichs Feb 15, 2021
ce51585
core/txpool: tests: create TestTransactionTypeNotSupported()
adietrichs Feb 15, 2021
91ea2f3
core/txpool: tests: create TestTransactionTipAboveFeeCap()
adietrichs Feb 15, 2021
ba79aa2
core/txpool: tests: create TestTransactionPoolRepricingDynamicFee()
adietrichs Feb 15, 2021
6ade382
core/txpool: tests: add dynamic fee transactions to TestTransactionPo…
adietrichs Feb 15, 2021
503ad99
core/txpool: tests: create TestTransactionPoolUnderpricingDynamicFee()
adietrichs Feb 15, 2021
685ccaa
core/txpool: tests: create TestTransactionReplacementDynamicFee()
adietrichs Feb 15, 2021
cff2662
core/tx_pool_test: update signer and remove invalid type test
lightclient Apr 6, 2021
e9de7a6
core/tx_pool_test: rename dynamicFeeTransaction to dynamicFeeTx
lightclient Apr 27, 2021
a53fac4
core: remove tx_list cap function
lightclient Apr 29, 2021
146b299
core/tx_pool: revert log change and simplify test
lightclient Apr 29, 2021
2c32c94
core/types/transaction: add godoc for tip and fee cap cmp functions
lightclient Apr 29, 2021
0d79add
core/tx_pool_test: increase test space for repricing test
lightclient Apr 29, 2021
63d83e5
core/tx_pool_test: clean up tx pool tests
lightclient Apr 29, 2021
8c177a4
core/tx_pool_test: rewrite underpriced txs test
lightclient Apr 30, 2021
9164512
core/tx_pool: fix comment
lightclient May 3, 2021
5c35013
core/tx_pool: update aleut references to london
lightclient May 6, 2021
ab92339
core/tx_pool: remove gas target references
lightclient May 10, 2021
052b113
core/tx_list: require both fee cap and tip be bumped to replace exist…
lightclient May 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 23 additions & 33 deletions core/tx_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,21 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
// If there's an older better transaction, abort
old := l.txs.Get(tx.Nonce())
if old != nil {
// threshold = oldGP * (100 + priceBump) / 100
// thresholdFeeCap = oldFC * (100 + priceBump) / 100
a := big.NewInt(100 + int64(priceBump))
a = a.Mul(a, old.GasPrice())
aFeeCap := new(big.Int).Mul(a, old.FeeCap())
aTip := a.Mul(a, old.Tip())

// thresholdTip = oldTip * (100 + priceBump) / 100
b := big.NewInt(100)
threshold := a.Div(a, b)
// Have to ensure that the new gas price is higher than the old gas
// price as well as checking the percentage threshold to ensure that
thresholdFeeCap := aFeeCap.Div(aFeeCap, b)
thresholdTip := aTip.Div(aTip, b)

// Have to ensure that either the new fee cap or tip is higher than the
// old ones as well as checking the percentage threshold to ensure that
// this is accurate for low (Wei-level) gas price replacements
if old.GasPriceCmp(tx) >= 0 || tx.GasPriceIntCmp(threshold) < 0 {
if (old.FeeCapCmp(tx) >= 0 || tx.FeeCapIntCmp(thresholdFeeCap) < 0) ||
(old.TipCmp(tx) >= 0 || tx.TipIntCmp(thresholdTip) < 0) {
return false, nil
}
}
Expand Down Expand Up @@ -413,8 +419,15 @@ func (h priceHeap) Len() int { return len(h) }
func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

func (h priceHeap) Less(i, j int) bool {
// Sort primarily by price, returning the cheaper one
switch h[i].GasPriceCmp(h[j]) {
// Sort primarily by fee cap, returning the cheaper one
switch h[i].FeeCapCmp(h[j]) {
case -1:
return true
case 1:
return false
}
// Sort secondarily by tip, returning the cheaper one
switch h[i].TipCmp(h[j]) {
case -1:
return true
case 1:
Expand Down Expand Up @@ -476,30 +489,6 @@ func (l *txPricedList) Removed(count int) {
l.Reheap()
}

// Cap finds all the transactions below the given price threshold, drops them
// from the priced list and returns them for further removal from the entire pool.
//
// Note: only remote transactions will be considered for eviction.
func (l *txPricedList) Cap(threshold *big.Int) types.Transactions {
drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop
for len(*l.remotes) > 0 {
// Discard stale transactions if found during cleanup
cheapest := (*l.remotes)[0]
if l.all.GetRemote(cheapest.Hash()) == nil { // Removed or migrated
heap.Pop(l.remotes)
l.stales--
continue
}
// Stop the discards if we've reached the threshold
if cheapest.GasPriceIntCmp(threshold) >= 0 {
break
}
heap.Pop(l.remotes)
drop = append(drop, cheapest)
}
return drop
}

// Underpriced checks whether a transaction is cheaper than (or as cheap as) the
// lowest priced (remote) transaction currently being tracked.
func (l *txPricedList) Underpriced(tx *types.Transaction) bool {
Expand All @@ -520,7 +509,8 @@ func (l *txPricedList) Underpriced(tx *types.Transaction) bool {
// If the remote transaction is even cheaper than the
// cheapest one tracked locally, reject it.
cheapest := []*types.Transaction(*l.remotes)[0]
return cheapest.GasPriceCmp(tx) >= 0
cmp := cheapest.FeeCapCmp(tx)
return cmp > 0 || (cmp == 0 && cheapest.TipCmp(tx) >= 0)
}

// Discard finds a number of most underpriced transactions, removes them from the
Expand Down
42 changes: 36 additions & 6 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ var (
// than some meaningful limit a user might use. This is not a consensus error
// making the transaction invalid, rather a DOS protection.
ErrOversizedData = errors.New("oversized data")

// ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a
// transaction with a tip higher than the total fee cap.
ErrTipAboveFeeCap = errors.New("tip higher than fee cap")
)

var (
Expand Down Expand Up @@ -230,6 +234,7 @@ type TxPool struct {

istanbul bool // Fork indicator whether we are in the istanbul stage.
eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions.
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions.

currentState *state.StateDB // Current state in the blockchain head
pendingNonces *txNoncer // Pending state tracking virtual nonces
Expand Down Expand Up @@ -426,10 +431,18 @@ func (pool *TxPool) SetGasPrice(price *big.Int) {
pool.mu.Lock()
defer pool.mu.Unlock()

old := pool.gasPrice
pool.gasPrice = price
for _, tx := range pool.priced.Cap(price) {
pool.removeTx(tx.Hash(), false)
// if the min miner fee increased, remove transactions below the new threshold
if price.Cmp(old) > 0 {
// pool.priced is sorted by FeeCap, so we have to iterate through pool.all instead
drop := pool.all.RemotesBelowTip(price)
for _, tx := range drop {
pool.removeTx(tx.Hash(), false)
}
pool.priced.Removed(len(drop))
}

log.Info("Transaction pool price threshold updated", "price", price)
}

Expand Down Expand Up @@ -540,13 +553,17 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit
}
// Ensure feeCap is less than or equal to tip.
if pool.eip1559 && tx.FeeCapIntCmp(tx.Tip()) < 0 {
return ErrTipAboveFeeCap
}
// Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx)
if err != nil {
return ErrInvalidSender
}
// Drop non-local transactions under our own minimal accepted gas price
if !local && tx.GasPriceIntCmp(pool.gasPrice) < 0 {
// Drop non-local transactions under our own minimal accepted gas price or tip
if !local && tx.TipIntCmp(pool.gasPrice) < 0 {
return ErrUnderpriced
}
// Ensure the transaction adheres to nonce ordering
Expand Down Expand Up @@ -598,7 +615,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
if uint64(pool.all.Count()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
// If the new transaction is underpriced, don't accept it
if !isLocal && pool.priced.Underpriced(tx) {
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.FeeCap())
underpricedTxMeter.Mark(1)
return false, ErrUnderpriced
}
Expand All @@ -615,7 +632,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
}
// Kick out the underpriced remote transactions.
for _, tx := range drop {
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.FeeCap())
underpricedTxMeter.Mark(1)
pool.removeTx(tx.Hash(), false)
}
Expand Down Expand Up @@ -1205,6 +1222,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
next := new(big.Int).Add(newHead.Number, big.NewInt(1))
pool.istanbul = pool.chainconfig.IsIstanbul(next)
pool.eip2718 = pool.chainconfig.IsBerlin(next)
pool.eip1559 = pool.chainconfig.IsLondon(next)
}

// promoteExecutables moves transactions that have become processable from the
Expand Down Expand Up @@ -1709,6 +1727,18 @@ func (t *txLookup) RemoteToLocals(locals *accountSet) int {
return migrated
}

// RemotesBelowTip finds all remote transactions below the given tip threshold.
func (t *txLookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
found := make(types.Transactions, 0, 128)
t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool {
if tx.TipIntCmp(threshold) < 0 {
found = append(found, tx)
}
return true
}, false, true) // Only iterate remotes
return found
}

// numSlots calculates the number of slots needed for a single transaction.
func numSlots(tx *types.Transaction) int {
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
Expand Down
Loading