mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-07 04:23:52 +00:00
Merge branch 'ethereum:master' into portal
This commit is contained in:
commit
1221812f67
20 changed files with 257 additions and 95 deletions
|
|
@ -371,7 +371,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
|
|||
}
|
||||
p.head, p.state = head, state
|
||||
|
||||
// Index all transactions on disk and delete anything inprocessable
|
||||
// Index all transactions on disk and delete anything unprocessable
|
||||
var fails []uint64
|
||||
index := func(id uint64, size uint32, blob []byte) {
|
||||
if p.parseTransaction(id, size, blob) != nil {
|
||||
|
|
@ -1446,7 +1446,12 @@ func (p *BlobPool) drop() {
|
|||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
|
||||
func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
|
||||
// If only plain transactions are requested, this pool is unsuitable as it
|
||||
// contains none, don't even bother.
|
||||
if filter.OnlyPlainTxs {
|
||||
return nil
|
||||
}
|
||||
// Track the amount of time waiting to retrieve the list of pending blob txs
|
||||
// from the pool and the amount of time actually spent on assembling the data.
|
||||
// The latter will be pretty much moot, but we've kept it to have symmetric
|
||||
|
|
@ -1456,29 +1461,30 @@ func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *u
|
|||
pendwaitHist.Update(time.Since(pendStart).Nanoseconds())
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
defer func(start time.Time) {
|
||||
pendtimeHist.Update(time.Since(start).Nanoseconds())
|
||||
}(time.Now())
|
||||
execStart := time.Now()
|
||||
defer func() {
|
||||
pendtimeHist.Update(time.Since(execStart).Nanoseconds())
|
||||
}()
|
||||
|
||||
pending := make(map[common.Address][]*txpool.LazyTransaction)
|
||||
pending := make(map[common.Address][]*txpool.LazyTransaction, len(p.index))
|
||||
for addr, txs := range p.index {
|
||||
var lazies []*txpool.LazyTransaction
|
||||
lazies := make([]*txpool.LazyTransaction, 0, len(txs))
|
||||
for _, tx := range txs {
|
||||
// If transaction filtering was requested, discard badly priced ones
|
||||
if minTip != nil && baseFee != nil {
|
||||
if tx.execFeeCap.Lt(baseFee) {
|
||||
if filter.MinTip != nil && filter.BaseFee != nil {
|
||||
if tx.execFeeCap.Lt(filter.BaseFee) {
|
||||
break // basefee too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
tip := new(uint256.Int).Sub(tx.execFeeCap, baseFee)
|
||||
tip := new(uint256.Int).Sub(tx.execFeeCap, filter.BaseFee)
|
||||
if tip.Gt(tx.execTipCap) {
|
||||
tip = tx.execTipCap
|
||||
}
|
||||
if tip.Lt(minTip) {
|
||||
if tip.Lt(filter.MinTip) {
|
||||
break // allowed or remaining tip too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
}
|
||||
if blobFee != nil {
|
||||
if tx.blobFeeCap.Lt(blobFee) {
|
||||
if filter.BlobFee != nil {
|
||||
if tx.blobFeeCap.Lt(filter.BlobFee) {
|
||||
break // blobfee too low, cannot be included, discard rest of txs from the account
|
||||
}
|
||||
}
|
||||
|
|
@ -1486,9 +1492,9 @@ func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *u
|
|||
lazies = append(lazies, &txpool.LazyTransaction{
|
||||
Pool: p,
|
||||
Hash: tx.hash,
|
||||
Time: time.Now(), // TODO(karalabe): Maybe save these and use that?
|
||||
GasFeeCap: tx.execFeeCap.ToBig(),
|
||||
GasTipCap: tx.execTipCap.ToBig(),
|
||||
Time: execStart, // TODO(karalabe): Maybe save these and use that?
|
||||
GasFeeCap: tx.execFeeCap,
|
||||
GasTipCap: tx.execTipCap,
|
||||
Gas: tx.execGas,
|
||||
BlobGas: tx.blobGas,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
|
|||
return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx)
|
||||
}
|
||||
|
||||
// makeUnsignedTx is a utility method to construct a random blob tranasaction
|
||||
// makeUnsignedTx is a utility method to construct a random blob transaction
|
||||
// without signing it.
|
||||
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
|
||||
return &types.BlobTx{
|
||||
|
|
@ -391,7 +391,7 @@ func TestOpenDrops(t *testing.T) {
|
|||
id, _ := store.Put(blob)
|
||||
filled[id] = struct{}{}
|
||||
}
|
||||
// Insert a sequence of transactions with partially passed nonces to veirfy
|
||||
// Insert a sequence of transactions with partially passed nonces to verify
|
||||
// that the included part of the set will get dropped (case 4).
|
||||
var (
|
||||
overlapper, _ = crypto.GenerateKey()
|
||||
|
|
@ -1288,3 +1288,65 @@ func TestAdd(t *testing.T) {
|
|||
pool.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks the time it takes to assemble the lazy pending transaction list
|
||||
// from the pool contents.
|
||||
func BenchmarkPoolPending100Mb(b *testing.B) { benchmarkPoolPending(b, 100_000_000) }
|
||||
func BenchmarkPoolPending1GB(b *testing.B) { benchmarkPoolPending(b, 1_000_000_000) }
|
||||
func BenchmarkPoolPending10GB(b *testing.B) { benchmarkPoolPending(b, 10_000_000_000) }
|
||||
|
||||
func benchmarkPoolPending(b *testing.B, datacap uint64) {
|
||||
// Calculate the maximum number of transaction that would fit into the pool
|
||||
// and generate a set of random accounts to seed them with.
|
||||
capacity := datacap / params.BlobTxBlobGasPerBlob
|
||||
|
||||
var (
|
||||
basefee = uint64(1050)
|
||||
blobfee = uint64(105)
|
||||
signer = types.LatestSigner(testChainConfig)
|
||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||
chain = &testBlockChain{
|
||||
config: testChainConfig,
|
||||
basefee: uint256.NewInt(basefee),
|
||||
blobfee: uint256.NewInt(blobfee),
|
||||
statedb: statedb,
|
||||
}
|
||||
pool = New(Config{Datadir: ""}, chain)
|
||||
)
|
||||
|
||||
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
|
||||
b.Fatalf("failed to create blob pool: %v", err)
|
||||
}
|
||||
// Fill the pool up with one random transaction from each account with the
|
||||
// same price and everything to maximize the worst case scenario
|
||||
for i := 0; i < int(capacity); i++ {
|
||||
blobtx := makeUnsignedTx(0, 10, basefee+10, blobfee)
|
||||
blobtx.R = uint256.NewInt(1)
|
||||
blobtx.S = uint256.NewInt(uint64(100 + i))
|
||||
blobtx.V = uint256.NewInt(0)
|
||||
tx := types.NewTx(blobtx)
|
||||
addr, err := types.Sender(signer, tx)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000))
|
||||
pool.add(tx)
|
||||
}
|
||||
statedb.Commit(0, true)
|
||||
defer pool.Close()
|
||||
|
||||
// Benchmark assembling the pending
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
p := pool.Pending(txpool.PendingFilter{
|
||||
MinTip: uint256.NewInt(1),
|
||||
BaseFee: chain.basefee,
|
||||
BlobFee: chain.blobfee,
|
||||
})
|
||||
if len(p) != int(capacity) {
|
||||
b.Fatalf("have %d want %d", len(p), capacity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
// transaction from each account to determine which account to evict from.
|
||||
//
|
||||
// The heap internally tracks a slice of cheapest transactions from each account
|
||||
// and a mapping from addresses to indices for direct removals/udates.
|
||||
// and a mapping from addresses to indices for direct removals/updates.
|
||||
//
|
||||
// The goal of the heap is to decide which account has the worst bottleneck to
|
||||
// evict transactions from.
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
|
|||
// Benchmarks how many priority recalculations can be done.
|
||||
func BenchmarkPriorityCalculation(b *testing.B) {
|
||||
// The basefee and blob fee is constant for all transactions across a block,
|
||||
// so we can assume theit absolute jump counts can be pre-computed.
|
||||
// so we can assume their absolute jump counts can be pre-computed.
|
||||
basefee := uint256.NewInt(17_200_000_000) // 17.2 Gwei is the 22.03.2023 zero-emission basefee, random number
|
||||
blobfee := uint256.NewInt(123_456_789_000) // Completely random, no idea what this will be
|
||||
|
||||
|
|
|
|||
|
|
@ -522,7 +522,12 @@ func (pool *LegacyPool) ContentFrom(addr common.Address) ([]*types.Transaction,
|
|||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
|
||||
func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
|
||||
// If only blob transactions are requested, this pool is unsuitable as it
|
||||
// contains none, don't even bother.
|
||||
if filter.OnlyBlobTxs {
|
||||
return nil
|
||||
}
|
||||
pool.mu.Lock()
|
||||
defer pool.mu.Unlock()
|
||||
|
||||
|
|
@ -531,13 +536,12 @@ func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobF
|
|||
minTipBig *big.Int
|
||||
baseFeeBig *big.Int
|
||||
)
|
||||
if minTip != nil {
|
||||
minTipBig = minTip.ToBig()
|
||||
if filter.MinTip != nil {
|
||||
minTipBig = filter.MinTip.ToBig()
|
||||
}
|
||||
if baseFee != nil {
|
||||
baseFeeBig = baseFee.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()
|
||||
|
|
@ -559,8 +563,8 @@ func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobF
|
|||
Hash: txs[i].Hash(),
|
||||
Tx: txs[i],
|
||||
Time: txs[i].Time(),
|
||||
GasFeeCap: txs[i].GasFeeCap(),
|
||||
GasTipCap: txs[i].GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(txs[i].GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(txs[i].GasTipCap()),
|
||||
Gas: txs[i].Gas(),
|
||||
BlobGas: txs[i].BlobGas(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ type LazyTransaction struct {
|
|||
Hash common.Hash // Transaction hash to pull up if needed
|
||||
Tx *types.Transaction // Transaction if already resolved
|
||||
|
||||
Time time.Time // Time when the transaction was first seen
|
||||
GasFeeCap *big.Int // Maximum fee per gas the transaction may consume
|
||||
GasTipCap *big.Int // Maximum miner tip per gas the transaction can pay
|
||||
Time time.Time // Time when the transaction was first seen
|
||||
GasFeeCap *uint256.Int // Maximum fee per gas the transaction may consume
|
||||
GasTipCap *uint256.Int // Maximum miner tip per gas the transaction can pay
|
||||
|
||||
Gas uint64 // Amount of gas required by the transaction
|
||||
BlobGas uint64 // Amount of blob gas required by the transaction
|
||||
|
|
@ -70,6 +70,21 @@ type LazyResolver interface {
|
|||
// may request (and relinquish) exclusive access to certain addresses.
|
||||
type AddressReserver func(addr common.Address, reserve bool) error
|
||||
|
||||
// PendingFilter is a collection of filter rules to allow retrieving a subset
|
||||
// of transactions for announcement or mining.
|
||||
//
|
||||
// Note, the entries here are not arbitrary useful filters, rather each one has
|
||||
// a very specific call site in mind and each one can be evaluated very cheaply
|
||||
// by the pool implementations. Only add new ones that satisfy those constraints.
|
||||
type PendingFilter struct {
|
||||
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
||||
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
||||
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
||||
|
||||
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
||||
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
||||
}
|
||||
|
||||
// SubPool represents a specialized transaction pool that lives on its own (e.g.
|
||||
// blob pool). Since independent of how many specialized pools we have, they do
|
||||
// need to be updated in lockstep and assemble into one coherent view for block
|
||||
|
|
@ -118,7 +133,7 @@ type SubPool interface {
|
|||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction
|
||||
Pending(filter PendingFilter) map[common.Address][]*LazyTransaction
|
||||
|
||||
// SubscribeTransactions subscribes to new transaction events. The subscriber
|
||||
// can decide whether to receive notifications only for newly seen transactions
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// TxStatus is the current status of a transaction as seen by the pool.
|
||||
|
|
@ -357,10 +356,10 @@ func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
|
|||
//
|
||||
// The transactions can also be pre-filtered by the dynamic fee components to
|
||||
// reduce allocations and load on downstream subsystems.
|
||||
func (p *TxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction {
|
||||
func (p *TxPool) Pending(filter PendingFilter) map[common.Address][]*LazyTransaction {
|
||||
txs := make(map[common.Address][]*LazyTransaction)
|
||||
for _, subpool := range p.subpools {
|
||||
for addr, set := range subpool.Pending(minTip, baseFee, blobFee) {
|
||||
for addr, set := range subpool.Pending(filter) {
|
||||
txs[addr] = set
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -359,7 +361,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
|||
)
|
||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||
if overflow {
|
||||
uint64CodeOffset = 0xffffffffffffffff
|
||||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
|
@ -377,7 +379,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
|||
)
|
||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||
if overflow {
|
||||
uint64CodeOffset = 0xffffffffffffffff
|
||||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
addr := common.Address(a.Bytes20())
|
||||
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||
|
|
|
|||
|
|
@ -187,7 +187,12 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
|
|||
// outside of this function, as part of the dynamic gas, and that will make it
|
||||
// also become correctly reported to tracers.
|
||||
contract.Gas += coldCost
|
||||
return gas + coldCost, nil
|
||||
|
||||
var overflow bool
|
||||
if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
|
|||
}
|
||||
|
||||
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
|
||||
pending := b.eth.txPool.Pending(nil, nil, nil)
|
||||
pending := b.eth.txPool.Pending(txpool.PendingFilter{})
|
||||
var txs types.Transactions
|
||||
for _, batch := range pending {
|
||||
for _, lazy := range batch {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -263,7 +264,7 @@ func (c *SimulatedBeacon) Rollback() {
|
|||
|
||||
// Fork sets the head to the provided hash.
|
||||
func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
|
||||
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 {
|
||||
if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 {
|
||||
return errors.New("pending block dirty")
|
||||
}
|
||||
parent := c.eth.BlockChain().GetBlockByHash(parentHash)
|
||||
|
|
@ -275,7 +276,7 @@ func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
|
|||
|
||||
// AdjustTime creates a new block with an adjusted timestamp.
|
||||
func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error {
|
||||
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 {
|
||||
if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 {
|
||||
return errors.New("could not adjust time on non-empty block")
|
||||
}
|
||||
parent := c.eth.BlockChain().CurrentBlock()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -74,7 +73,7 @@ type txPool interface {
|
|||
|
||||
// Pending should return pending transactions.
|
||||
// The slice should be modifiable by the caller.
|
||||
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction
|
||||
Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction
|
||||
|
||||
// SubscribeTransactions subscribes to new transaction events. The subscriber
|
||||
// can decide whether to receive notifications only for newly seen transactions
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []erro
|
|||
}
|
||||
|
||||
// Pending returns all the transactions known to the pool
|
||||
func (p *testTxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
|
||||
func (p *testTxPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
|
|
@ -112,8 +112,8 @@ func (p *testTxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee
|
|||
Hash: tx.Hash(),
|
||||
Tx: tx,
|
||||
Time: tx.Time(),
|
||||
GasFeeCap: tx.GasFeeCap(),
|
||||
GasTipCap: tx.GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
|
||||
Gas: tx.Gas(),
|
||||
BlobGas: tx.BlobGas(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
|
@ -36,7 +37,7 @@ const (
|
|||
// syncTransactions starts sending all currently pending transactions to the given peer.
|
||||
func (h *handler) syncTransactions(p *eth.Peer) {
|
||||
var hashes []common.Hash
|
||||
for _, batch := range h.txpool.Pending(nil, nil, nil) {
|
||||
for _, batch := range h.txpool.Pending(txpool.PendingFilter{OnlyPlainTxs: true}) {
|
||||
for _, tx := range batch {
|
||||
hashes = append(hashes, tx.Hash)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -611,6 +611,10 @@ func (s *Service) reportBlock(conn *connWrapper, block *types.Block) error {
|
|||
// Gather the block details from the header or block chain
|
||||
details := s.assembleBlockStats(block)
|
||||
|
||||
// Short circuit if the block detail is not available.
|
||||
if details == nil {
|
||||
return nil
|
||||
}
|
||||
// Assemble the block report and send it to the server
|
||||
log.Trace("Sending new block to ethstats", "number", details.Number, "hash", details.Hash)
|
||||
|
||||
|
|
@ -638,10 +642,16 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
|
|||
// check if backend is a full node
|
||||
fullBackend, ok := s.backend.(fullNodeBackend)
|
||||
if ok {
|
||||
// Retrieve current chain head if no block is given.
|
||||
if block == nil {
|
||||
head := fullBackend.CurrentBlock()
|
||||
block, _ = fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(head.Number.Uint64()))
|
||||
}
|
||||
// Short circuit if no block is available. It might happen when
|
||||
// the blockchain is reorging.
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
header = block.Header()
|
||||
td = fullBackend.GetTd(context.Background(), header.Hash())
|
||||
|
||||
|
|
|
|||
|
|
@ -1818,6 +1818,7 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
|
|||
tx *types.Transaction
|
||||
err error
|
||||
)
|
||||
b.SetPoS()
|
||||
switch i {
|
||||
case 0:
|
||||
// transfer 1000wei
|
||||
|
|
@ -1866,7 +1867,6 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
|
|||
b.AddTx(tx)
|
||||
txHashes[i] = tx.Hash()
|
||||
}
|
||||
b.SetPoS()
|
||||
})
|
||||
return backend, txHashes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,28 +21,31 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// txWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap
|
||||
type txWithMinerFee struct {
|
||||
tx *txpool.LazyTransaction
|
||||
from common.Address
|
||||
fees *big.Int
|
||||
fees *uint256.Int
|
||||
}
|
||||
|
||||
// newTxWithMinerFee creates a wrapped transaction, calculating the effective
|
||||
// miner gasTipCap if a base fee is provided.
|
||||
// Returns error in case of a negative effective miner gasTipCap.
|
||||
func newTxWithMinerFee(tx *txpool.LazyTransaction, from common.Address, baseFee *big.Int) (*txWithMinerFee, error) {
|
||||
tip := new(big.Int).Set(tx.GasTipCap)
|
||||
func newTxWithMinerFee(tx *txpool.LazyTransaction, from common.Address, baseFee *uint256.Int) (*txWithMinerFee, error) {
|
||||
tip := new(uint256.Int).Set(tx.GasTipCap)
|
||||
if baseFee != nil {
|
||||
if tx.GasFeeCap.Cmp(baseFee) < 0 {
|
||||
return nil, types.ErrGasFeeCapTooLow
|
||||
}
|
||||
tip = math.BigMin(tx.GasTipCap, new(big.Int).Sub(tx.GasFeeCap, baseFee))
|
||||
tip = new(uint256.Int).Sub(tx.GasFeeCap, baseFee)
|
||||
if tip.Gt(tx.GasTipCap) {
|
||||
tip = tx.GasTipCap
|
||||
}
|
||||
}
|
||||
return &txWithMinerFee{
|
||||
tx: tx,
|
||||
|
|
@ -87,7 +90,7 @@ type transactionsByPriceAndNonce struct {
|
|||
txs map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions
|
||||
heads txByPriceAndTime // Next transaction for each unique account (price heap)
|
||||
signer types.Signer // Signer for the set of transactions
|
||||
baseFee *big.Int // Current base fee
|
||||
baseFee *uint256.Int // Current base fee
|
||||
}
|
||||
|
||||
// newTransactionsByPriceAndNonce creates a transaction set that can retrieve
|
||||
|
|
@ -96,10 +99,15 @@ type transactionsByPriceAndNonce struct {
|
|||
// Note, the input map is reowned so the caller should not interact any more with
|
||||
// if after providing it to the constructor.
|
||||
func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce {
|
||||
// Convert the basefee from header format to uint256 format
|
||||
var baseFeeUint *uint256.Int
|
||||
if baseFee != nil {
|
||||
baseFeeUint = uint256.MustFromBig(baseFee)
|
||||
}
|
||||
// Initialize a price and received time based heap with the head transactions
|
||||
heads := make(txByPriceAndTime, 0, len(txs))
|
||||
for from, accTxs := range txs {
|
||||
wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFee)
|
||||
wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFeeUint)
|
||||
if err != nil {
|
||||
delete(txs, from)
|
||||
continue
|
||||
|
|
@ -114,12 +122,12 @@ func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address]
|
|||
txs: txs,
|
||||
heads: heads,
|
||||
signer: signer,
|
||||
baseFee: baseFee,
|
||||
baseFee: baseFeeUint,
|
||||
}
|
||||
}
|
||||
|
||||
// Peek returns the next transaction by price.
|
||||
func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *big.Int) {
|
||||
func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *uint256.Int) {
|
||||
if len(t.heads) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -145,3 +153,14 @@ func (t *transactionsByPriceAndNonce) Shift() {
|
|||
func (t *transactionsByPriceAndNonce) Pop() {
|
||||
heap.Pop(&t.heads)
|
||||
}
|
||||
|
||||
// Empty returns if the price heap is empty. It can be used to check it simpler
|
||||
// than calling peek and checking for nil return.
|
||||
func (t *transactionsByPriceAndNonce) Empty() bool {
|
||||
return len(t.heads) == 0
|
||||
}
|
||||
|
||||
// Clear removes the entire content of the heap.
|
||||
func (t *transactionsByPriceAndNonce) Clear() {
|
||||
t.heads, t.txs = nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
func TestTransactionPriceNonceSortLegacy(t *testing.T) {
|
||||
|
|
@ -92,8 +93,8 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
|
|||
Hash: tx.Hash(),
|
||||
Tx: tx,
|
||||
Time: tx.Time(),
|
||||
GasFeeCap: tx.GasFeeCap(),
|
||||
GasTipCap: tx.GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
|
||||
Gas: tx.Gas(),
|
||||
BlobGas: tx.BlobGas(),
|
||||
})
|
||||
|
|
@ -160,8 +161,8 @@ func TestTransactionTimeSort(t *testing.T) {
|
|||
Hash: tx.Hash(),
|
||||
Tx: tx,
|
||||
Time: tx.Time(),
|
||||
GasFeeCap: tx.GasFeeCap(),
|
||||
GasTipCap: tx.GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
|
||||
Gas: tx.Gas(),
|
||||
BlobGas: tx.BlobGas(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ type worker struct {
|
|||
mu sync.RWMutex // The lock used to protect the coinbase and extra fields
|
||||
coinbase common.Address
|
||||
extra []byte
|
||||
tip *big.Int // Minimum tip needed for non-local transaction to include them
|
||||
tip *uint256.Int // Minimum tip needed for non-local transaction to include them
|
||||
|
||||
pendingMu sync.RWMutex
|
||||
pendingTasks map[common.Hash]*task
|
||||
|
|
@ -253,7 +253,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
|
|||
isLocalBlock: isLocalBlock,
|
||||
coinbase: config.Etherbase,
|
||||
extra: config.ExtraData,
|
||||
tip: config.GasPrice,
|
||||
tip: uint256.MustFromBig(config.GasPrice),
|
||||
pendingTasks: make(map[common.Hash]*task),
|
||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||
|
|
@ -334,7 +334,7 @@ func (w *worker) setExtra(extra []byte) {
|
|||
func (w *worker) setGasTip(tip *big.Int) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
w.tip = tip
|
||||
w.tip = uint256.MustFromBig(tip)
|
||||
}
|
||||
|
||||
// setRecommitInterval updates the interval for miner sealing work recommitting.
|
||||
|
|
@ -556,15 +556,17 @@ func (w *worker) mainLoop() {
|
|||
Hash: tx.Hash(),
|
||||
Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in
|
||||
Time: tx.Time(),
|
||||
GasFeeCap: tx.GasFeeCap(),
|
||||
GasTipCap: tx.GasTipCap(),
|
||||
GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
|
||||
GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
|
||||
Gas: tx.Gas(),
|
||||
BlobGas: tx.BlobGas(),
|
||||
})
|
||||
}
|
||||
txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee)
|
||||
plainTxs := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) // Mixed bag of everrything, yolo
|
||||
blobTxs := newTransactionsByPriceAndNonce(w.current.signer, nil, w.current.header.BaseFee) // Empty bag, don't bother optimising
|
||||
|
||||
tcount := w.current.tcount
|
||||
w.commitTransactions(w.current, txset, nil, new(big.Int))
|
||||
w.commitTransactions(w.current, plainTxs, blobTxs, nil)
|
||||
|
||||
// Only update the snapshot if any new transactions were added
|
||||
// to the pending block
|
||||
|
|
@ -802,7 +804,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ
|
|||
return receipt, err
|
||||
}
|
||||
|
||||
func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, minTip *big.Int) error {
|
||||
func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||
gasLimit := env.header.GasLimit
|
||||
if env.gasPool == nil {
|
||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||
|
|
@ -821,8 +823,33 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
|
|||
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
|
||||
break
|
||||
}
|
||||
// If we don't have enough blob space for any further blob transactions,
|
||||
// skip that list altogether
|
||||
if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock {
|
||||
log.Trace("Not enough blob space for further blob transactions")
|
||||
blobTxs.Clear()
|
||||
// Fall though to pick up any plain txs
|
||||
}
|
||||
// Retrieve the next transaction and abort if all done.
|
||||
ltx, tip := txs.Peek()
|
||||
var (
|
||||
ltx *txpool.LazyTransaction
|
||||
txs *transactionsByPriceAndNonce
|
||||
)
|
||||
pltx, ptip := plainTxs.Peek()
|
||||
bltx, btip := blobTxs.Peek()
|
||||
|
||||
switch {
|
||||
case pltx == nil:
|
||||
txs, ltx = blobTxs, bltx
|
||||
case bltx == nil:
|
||||
txs, ltx = plainTxs, pltx
|
||||
default:
|
||||
if ptip.Lt(btip) {
|
||||
txs, ltx = blobTxs, bltx
|
||||
} else {
|
||||
txs, ltx = plainTxs, pltx
|
||||
}
|
||||
}
|
||||
if ltx == nil {
|
||||
break
|
||||
}
|
||||
|
|
@ -837,11 +864,6 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
|
|||
txs.Pop()
|
||||
continue
|
||||
}
|
||||
// If we don't receive enough tip for the next transaction, skip the account
|
||||
if tip.Cmp(minTip) < 0 {
|
||||
log.Trace("Not enough tip for transaction", "hash", ltx.Hash, "tip", tip, "needed", minTip)
|
||||
break // If the next-best is too low, surely no better will be available
|
||||
}
|
||||
// Transaction seems to fit, pull it up from the pool
|
||||
tx := ltx.Resolve()
|
||||
if tx == nil {
|
||||
|
|
@ -1005,35 +1027,49 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
|
|||
w.mu.RUnlock()
|
||||
|
||||
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
|
||||
var baseFee *uint256.Int
|
||||
filter := txpool.PendingFilter{
|
||||
MinTip: tip,
|
||||
}
|
||||
if env.header.BaseFee != nil {
|
||||
baseFee = uint256.MustFromBig(env.header.BaseFee)
|
||||
filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
|
||||
}
|
||||
var blobFee *uint256.Int
|
||||
if env.header.ExcessBlobGas != nil {
|
||||
blobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
|
||||
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
|
||||
}
|
||||
pending := w.eth.TxPool().Pending(uint256.MustFromBig(tip), baseFee, blobFee)
|
||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
||||
pendingPlainTxs := w.eth.TxPool().Pending(filter)
|
||||
|
||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
|
||||
pendingBlobTxs := w.eth.TxPool().Pending(filter)
|
||||
|
||||
// Split the pending transactions into locals and remotes.
|
||||
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending
|
||||
localPlainTxs, remotePlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
|
||||
localBlobTxs, remoteBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
|
||||
|
||||
for _, account := range w.eth.TxPool().Locals() {
|
||||
if txs := remoteTxs[account]; len(txs) > 0 {
|
||||
delete(remoteTxs, account)
|
||||
localTxs[account] = txs
|
||||
if txs := remotePlainTxs[account]; len(txs) > 0 {
|
||||
delete(remotePlainTxs, account)
|
||||
localPlainTxs[account] = txs
|
||||
}
|
||||
if txs := remoteBlobTxs[account]; len(txs) > 0 {
|
||||
delete(remoteBlobTxs, account)
|
||||
localBlobTxs[account] = txs
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the block with all available pending transactions.
|
||||
if len(localTxs) > 0 {
|
||||
txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee)
|
||||
if err := w.commitTransactions(env, txs, interrupt, new(big.Int)); err != nil {
|
||||
if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
|
||||
plainTxs := newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
|
||||
blobTxs := newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
|
||||
|
||||
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(remoteTxs) > 0 {
|
||||
txs := newTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee)
|
||||
if err := w.commitTransactions(env, txs, interrupt, tip); err != nil {
|
||||
if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
|
||||
plainTxs := newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
|
||||
blobTxs := newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
|
||||
|
||||
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -910,6 +910,8 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
|||
if chainID == nil {
|
||||
chainID = new(big.Int)
|
||||
}
|
||||
// disallow setting Merge out of order
|
||||
isMerge = isMerge && c.IsLondon(num)
|
||||
return Rules{
|
||||
ChainID: new(big.Int).Set(chainID),
|
||||
IsHomestead: c.IsHomestead(num),
|
||||
|
|
@ -923,9 +925,9 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
|||
IsBerlin: c.IsBerlin(num),
|
||||
IsLondon: c.IsLondon(num),
|
||||
IsMerge: isMerge,
|
||||
IsShanghai: c.IsShanghai(num, timestamp),
|
||||
IsCancun: c.IsCancun(num, timestamp),
|
||||
IsPrague: c.IsPrague(num, timestamp),
|
||||
IsVerkle: c.IsVerkle(num, timestamp),
|
||||
IsShanghai: isMerge && c.IsShanghai(num, timestamp),
|
||||
IsCancun: isMerge && c.IsCancun(num, timestamp),
|
||||
IsPrague: isMerge && c.IsPrague(num, timestamp),
|
||||
IsVerkle: isMerge && c.IsVerkle(num, timestamp),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue