mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
core/types: reduce allocations for transaction comparison
This commit is contained in:
parent
bf8f63dcd2
commit
c42b31a1f6
4 changed files with 63 additions and 37 deletions
|
|
@ -514,26 +514,15 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer pool.mu.Unlock()
|
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))
|
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
|
||||||
for addr, list := range pool.pending {
|
for addr, list := range pool.pending {
|
||||||
txs := list.Flatten()
|
txs := list.Flatten()
|
||||||
|
|
||||||
// If the miner requests tip enforcement, cap the lists now
|
// 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 {
|
for i, tx := range txs {
|
||||||
if minTipBig != nil {
|
if filter.MinTip != nil {
|
||||||
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
if tx.EffectiveGasTipIntCmp(filter.MinTip, filter.BaseFee) < 0 {
|
||||||
txs = txs[:i]
|
txs = txs[:i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// 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.
|
// If baseFee is nil then the sorting is based on gasFeeCap.
|
||||||
type priceHeap struct {
|
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
|
list []*types.Transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,6 +677,10 @@ func (l *pricedList) Reheap() {
|
||||||
// SetBaseFee updates the base fee and triggers a re-heap. Note that Removed is not
|
// 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.
|
// necessary to call right before SetBaseFee when processing a new block.
|
||||||
func (l *pricedList) SetBaseFee(baseFee *big.Int) {
|
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()
|
l.Reheap()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -355,51 +356,55 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
|
||||||
// Note: if the effective gasTipCap is negative, this method returns both error
|
// Note: if the effective gasTipCap is negative, this method returns both error
|
||||||
// the actual negative value, _and_ ErrGasFeeCapTooLow
|
// the actual negative value, _and_ ErrGasFeeCapTooLow
|
||||||
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
|
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
|
||||||
dst := new(big.Int)
|
dst := new(uint256.Int)
|
||||||
err := tx.calcEffectiveGasTip(dst, baseFee)
|
base := new(uint256.Int)
|
||||||
return dst, err
|
if baseFee != nil {
|
||||||
|
base.SetFromBig(baseFee)
|
||||||
|
}
|
||||||
|
err := tx.calcEffectiveGasTip(dst, base)
|
||||||
|
return dst.ToBig(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// calcEffectiveGasTip calculates the effective gas tip of the transaction and
|
// calcEffectiveGasTip calculates the effective gas tip of the transaction and
|
||||||
// saves the result to dst.
|
// 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 {
|
if baseFee == nil {
|
||||||
dst.Set(tx.inner.gasTipCap())
|
dst.SetFromBig(tx.inner.gasTipCap())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
gasFeeCap := tx.inner.gasFeeCap()
|
dst.SetFromBig(tx.inner.gasFeeCap())
|
||||||
if gasFeeCap.Cmp(baseFee) < 0 {
|
if dst.Cmp(baseFee) < 0 {
|
||||||
err = ErrGasFeeCapTooLow
|
err = ErrGasFeeCapTooLow
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.Sub(gasFeeCap, baseFee)
|
dst.Sub(dst, baseFee)
|
||||||
gasTipCap := tx.inner.gasTipCap()
|
gasTipCap := new(uint256.Int)
|
||||||
|
gasTipCap.SetFromBig(tx.inner.gasTipCap())
|
||||||
if gasTipCap.Cmp(dst) < 0 {
|
if gasTipCap.Cmp(dst) < 0 {
|
||||||
dst.Set(gasTipCap)
|
dst.Set(gasTipCap)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
|
func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *uint256.Int) int {
|
||||||
func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int) int {
|
|
||||||
if baseFee == nil {
|
if baseFee == nil {
|
||||||
return tx.GasTipCapCmp(other)
|
return tx.GasTipCapCmp(other)
|
||||||
}
|
}
|
||||||
// Use more efficient internal method.
|
// 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)
|
tx.calcEffectiveGasTip(txTip, baseFee)
|
||||||
other.calcEffectiveGasTip(otherTip, baseFee)
|
other.calcEffectiveGasTip(otherTip, baseFee)
|
||||||
return txTip.Cmp(otherTip)
|
return txTip.Cmp(otherTip)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
|
// 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 {
|
if baseFee == nil {
|
||||||
return tx.GasTipCapIntCmp(other)
|
return tx.GasTipCapIntCmp(other.ToBig())
|
||||||
}
|
}
|
||||||
txTip := new(big.Int)
|
txTip := new(uint256.Int)
|
||||||
tx.calcEffectiveGasTip(txTip, baseFee)
|
tx.calcEffectiveGasTip(txTip, baseFee)
|
||||||
return txTip.Cmp(other)
|
return txTip.Cmp(other)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The values in those tests are from the Transaction Tests
|
// The values in those tests are from the Transaction Tests
|
||||||
|
|
@ -609,12 +610,12 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
|
||||||
Data: nil,
|
Data: nil,
|
||||||
}
|
}
|
||||||
tx, _ := SignNewTx(key, signer, txdata)
|
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.Run("Original", func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := tx.EffectiveGasTip(baseFee)
|
_, err := tx.EffectiveGasTip(baseFee.ToBig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -623,7 +624,7 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
|
||||||
|
|
||||||
b.Run("IntoMethod", func(b *testing.B) {
|
b.Run("IntoMethod", func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
dst := new(big.Int)
|
dst := new(uint256.Int)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
err := tx.calcEffectiveGasTip(dst, baseFee)
|
err := tx.calcEffectiveGasTip(dst, baseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -666,23 +667,25 @@ func TestEffectiveGasTipInto(t *testing.T) {
|
||||||
tx, _ := SignNewTx(key, signer, txdata)
|
tx, _ := SignNewTx(key, signer, txdata)
|
||||||
|
|
||||||
var baseFee *big.Int
|
var baseFee *big.Int
|
||||||
|
var baseFee2 *uint256.Int
|
||||||
if tc.baseFee != nil {
|
if tc.baseFee != nil {
|
||||||
baseFee = big.NewInt(*tc.baseFee)
|
baseFee = big.NewInt(*tc.baseFee)
|
||||||
|
baseFee2 = uint256.NewInt(uint64(*tc.baseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get result from original method
|
// Get result from original method
|
||||||
orig, origErr := tx.EffectiveGasTip(baseFee)
|
orig, origErr := tx.EffectiveGasTip(baseFee)
|
||||||
|
|
||||||
// Get result from new method
|
// Get result from new method
|
||||||
dst := new(big.Int)
|
dst := new(uint256.Int)
|
||||||
newErr := tx.calcEffectiveGasTip(dst, baseFee)
|
newErr := tx.calcEffectiveGasTip(dst, baseFee2)
|
||||||
|
|
||||||
// Compare results
|
// Compare results
|
||||||
if (origErr != nil) != (newErr != nil) {
|
if (origErr != nil) != (newErr != nil) {
|
||||||
t.Fatalf("case %d: error mismatch: orig %v, new %v", i, origErr, newErr)
|
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)
|
t.Fatalf("case %d: result mismatch: orig %v, new %v", i, orig, dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -692,3 +695,28 @@ func TestEffectiveGasTipInto(t *testing.T) {
|
||||||
func intPtr(i int64) *int64 {
|
func intPtr(i int64) *int64 {
|
||||||
return &i
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue