Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 3 additions & 14 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,26 +514,15 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
pool.mu.Lock()
defer pool.mu.Unlock()

// Convert the new uint256.Int types to the old big.Int ones used by the legacy pool
var (
minTipBig *big.Int
baseFeeBig *big.Int
)
if filter.MinTip != nil {
minTipBig = filter.MinTip.ToBig()
}
if filter.BaseFee != nil {
baseFeeBig = filter.BaseFee.ToBig()
}
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
for addr, list := range pool.pending {
txs := list.Flatten()

// If the miner requests tip enforcement, cap the lists now
if minTipBig != nil || filter.GasLimitCap != 0 {
if filter.MinTip != nil || filter.GasLimitCap != 0 {
for i, tx := range txs {
if minTipBig != nil {
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
if filter.MinTip != nil {
if tx.EffectiveGasTipIntCmp(filter.MinTip, filter.BaseFee) < 0 {
txs = txs[:i]
break
}
Expand Down
8 changes: 6 additions & 2 deletions core/txpool/legacypool/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ func (l *list) subTotalCost(txs []*types.Transaction) {
// then the heap is sorted based on the effective tip based on the given base fee.
// If baseFee is nil then the sorting is based on gasFeeCap.
type priceHeap struct {
baseFee *big.Int // heap should always be re-sorted after baseFee is changed
baseFee *uint256.Int // heap should always be re-sorted after baseFee is changed
list []*types.Transaction
}

Expand Down Expand Up @@ -677,6 +677,10 @@ func (l *pricedList) Reheap() {
// SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not
// necessary to call right before SetBaseFee when processing a new block.
func (l *pricedList) SetBaseFee(baseFee *big.Int) {
l.urgent.baseFee = baseFee
base := new(uint256.Int)
if baseFee != nil {
base.SetFromBig(baseFee)
}
l.urgent.baseFee = base
l.Reheap()
}
48 changes: 31 additions & 17 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
)

var (
Expand All @@ -36,6 +37,7 @@ var (
ErrInvalidTxType = errors.New("transaction type not valid in this context")
ErrTxTypeNotSupported = errors.New("transaction type not supported")
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
ErrUint256Overflow = errors.New("bigint overflow, too large for uint256")
errShortTypedTx = errors.New("typed transaction too short")
errInvalidYParity = errors.New("'yParity' field must be 0 or 1")
errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match")
Expand Down Expand Up @@ -352,54 +354,66 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
}

// EffectiveGasTip returns the effective miner gasTipCap for the given base fee.
// Note: if the effective gasTipCap is negative, this method returns both error
// the actual negative value, _and_ ErrGasFeeCapTooLow
// Note: if the effective gasTipCap would be negative, this method
// returns ErrGasFeeCapTooLow, and value is undefined.
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
dst := new(big.Int)
err := tx.calcEffectiveGasTip(dst, baseFee)
return dst, err
dst := new(uint256.Int)
base := new(uint256.Int)
if baseFee != nil {
if base.SetFromBig(baseFee) {
return nil, ErrUint256Overflow
}
}
err := tx.calcEffectiveGasTip(dst, base)
return dst.ToBig(), err
}

// calcEffectiveGasTip calculates the effective gas tip of the transaction and
// saves the result to dst.
func (tx *Transaction) calcEffectiveGasTip(dst *big.Int, baseFee *big.Int) error {
func (tx *Transaction) calcEffectiveGasTip(dst *uint256.Int, baseFee *uint256.Int) error {
if baseFee == nil {
dst.Set(tx.inner.gasTipCap())
if dst.SetFromBig(tx.inner.gasTipCap()) {
return ErrUint256Overflow
}
return nil
}

var err error
gasFeeCap := tx.inner.gasFeeCap()
if gasFeeCap.Cmp(baseFee) < 0 {
if dst.SetFromBig(tx.inner.gasFeeCap()) {
return ErrUint256Overflow
}
if dst.Cmp(baseFee) < 0 {
err = ErrGasFeeCapTooLow
}

dst.Sub(gasFeeCap, baseFee)
gasTipCap := tx.inner.gasTipCap()
dst.Sub(dst, baseFee)
gasTipCap := new(uint256.Int)
if gasTipCap.SetFromBig(tx.inner.gasTipCap()) {
return ErrUint256Overflow
}
if gasTipCap.Cmp(dst) < 0 {
dst.Set(gasTipCap)
}
return err
}

// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int) int {
func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *uint256.Int) int {
if baseFee == nil {
return tx.GasTipCapCmp(other)
}
// Use more efficient internal method.
txTip, otherTip := new(big.Int), new(big.Int)
txTip, otherTip := new(uint256.Int), new(uint256.Int)
tx.calcEffectiveGasTip(txTip, baseFee)
other.calcEffectiveGasTip(otherTip, baseFee)
return txTip.Cmp(otherTip)
}

// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) int {
func (tx *Transaction) EffectiveGasTipIntCmp(other *uint256.Int, baseFee *uint256.Int) int {
if baseFee == nil {
return tx.GasTipCapIntCmp(other)
return tx.GasTipCapIntCmp(other.ToBig())
}
txTip := new(big.Int)
txTip := new(uint256.Int)
tx.calcEffectiveGasTip(txTip, baseFee)
return txTip.Cmp(other)
}
Expand Down
68 changes: 55 additions & 13 deletions core/types/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
)

// The values in those tests are from the Transaction Tests
Expand Down Expand Up @@ -609,12 +610,12 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)
baseFee := big.NewInt(1000000000) // 1 gwei
baseFee := uint256.NewInt(1000000000) // 1 gwei

b.Run("Original", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_, err := tx.EffectiveGasTip(baseFee)
_, err := tx.EffectiveGasTip(baseFee.ToBig())
if err != nil {
b.Fatal(err)
}
Expand All @@ -623,7 +624,7 @@ func BenchmarkEffectiveGasTip(b *testing.B) {

b.Run("IntoMethod", func(b *testing.B) {
b.ReportAllocs()
dst := new(big.Int)
dst := new(uint256.Int)
for i := 0; i < b.N; i++ {
err := tx.calcEffectiveGasTip(dst, baseFee)
if err != nil {
Expand All @@ -634,9 +635,6 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
}

func TestEffectiveGasTipInto(t *testing.T) {
signer := LatestSigner(params.TestChainConfig)
key, _ := crypto.GenerateKey()

testCases := []struct {
tipCap int64
feeCap int64
Expand All @@ -652,8 +650,26 @@ func TestEffectiveGasTipInto(t *testing.T) {
{tipCap: 50, feeCap: 100, baseFee: nil}, // nil base fee
}

// original, non-allocation golfed version
orig := func(tx *Transaction, baseFee *big.Int) (*big.Int, error) {
if baseFee == nil {
return tx.GasTipCap(), nil
}
var err error
gasFeeCap := tx.GasFeeCap()
if gasFeeCap.Cmp(baseFee) < 0 {
err = ErrGasFeeCapTooLow
}
gasFeeCap = gasFeeCap.Sub(gasFeeCap, baseFee)
gasTipCap := tx.GasTipCap()
if gasTipCap.Cmp(gasFeeCap) < 0 {
return gasTipCap, err
}
return gasFeeCap, err
}

for i, tc := range testCases {
txdata := &DynamicFeeTx{
tx := NewTx(&DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 0,
GasTipCap: big.NewInt(tc.tipCap),
Expand All @@ -662,27 +678,28 @@ func TestEffectiveGasTipInto(t *testing.T) {
To: &common.Address{},
Value: big.NewInt(0),
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)
})

var baseFee *big.Int
var baseFee2 *uint256.Int
if tc.baseFee != nil {
baseFee = big.NewInt(*tc.baseFee)
baseFee2 = uint256.NewInt(uint64(*tc.baseFee))
}

// Get result from original method
Comment thread
cskiraly marked this conversation as resolved.
orig, origErr := tx.EffectiveGasTip(baseFee)
orig, origErr := orig(tx, baseFee)

// Get result from new method
dst := new(big.Int)
newErr := tx.calcEffectiveGasTip(dst, baseFee)
dst := new(uint256.Int)
newErr := tx.calcEffectiveGasTip(dst, baseFee2)

// Compare results
if (origErr != nil) != (newErr != nil) {
t.Fatalf("case %d: error mismatch: orig %v, new %v", i, origErr, newErr)
}

if orig.Cmp(dst) != 0 {
if origErr == nil && orig.Cmp(dst.ToBig()) != 0 {
t.Fatalf("case %d: result mismatch: orig %v, new %v", i, orig, dst)
}
}
Expand All @@ -692,3 +709,28 @@ func TestEffectiveGasTipInto(t *testing.T) {
func intPtr(i int64) *int64 {
return &i
}

func BenchmarkEffectiveGasTipCmp(b *testing.B) {
signer := LatestSigner(params.TestChainConfig)
key, _ := crypto.GenerateKey()
txdata := &DynamicFeeTx{
ChainID: big.NewInt(1),
Nonce: 0,
GasTipCap: big.NewInt(2000000000),
GasFeeCap: big.NewInt(3000000000),
Gas: 21000,
To: &common.Address{},
Value: big.NewInt(0),
Data: nil,
}
tx, _ := SignNewTx(key, signer, txdata)
other, _ := SignNewTx(key, signer, txdata)
baseFee := uint256.NewInt(1000000000) // 1 gwei

b.Run("Original", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
tx.EffectiveGasTipCmp(other, baseFee)
}
})
}