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
2 changes: 1 addition & 1 deletion core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2290,7 +2290,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
// Disable tracing for prefetcher executions.
vmCfg := bc.vmConfig
vmCfg.Tracer = nil
go bc.prefetcher.Prefetch(block, throwaway, &vmCfg, interruptCh)
go bc.prefetcher.Prefetch(block.Transactions(), block.Header(), block.GasLimit(), throwaway, &vmCfg, interruptCh)

// 2.do trie prefetch for MPT trie node cache
// it is for the big state trie tree, prefetch based on transaction's From/To address.
Expand Down
39 changes: 19 additions & 20 deletions core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,36 +44,35 @@ func NewStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePr

// Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{}) {
// only goal is to warm the state caches.
func (p *statePrefetcher) Prefetch(transactions types.Transactions, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{}) {
var (
header = block.Header()
signer = types.MakeSigner(p.config, header.Number, header.Time)
)
transactions := block.Transactions()
txChan := make(chan int, prefetchThread)
// No need to execute the first batch, since the main processor will do it.

for i := 0; i < prefetchThread; i++ {
go func() {
newStatedb := statedb.CopyDoPrefetch()
if !p.config.IsHertzfix(header.Number) {
newStatedb.EnableWriteOnSharedStorage()
}
gaspool := new(GasPool).AddGas(block.GasLimit())
blockContext := NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(blockContext, newStatedb, p.config, *cfg)

gaspool := new(GasPool).AddGas(gasLimit)
evm := vm.NewEVM(NewEVMBlockContext(header, p.chain, nil), newStatedb, p.config, *cfg)
// Iterate over and process the individual transactions
for {
select {
case txIndex := <-txChan:
tx := transactions[txIndex]
// Convert the transaction into an executable message and pre-cache its sender
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
msg.SkipNonceChecks = true
msg.SkipFromEOACheck = true
if err != nil {
return // Also invalid block, bail out
}
// Disable the nonce check
msg.SkipNonceChecks = true

newStatedb.SetTxContext(tx.Hash(), txIndex)
// We attempt to apply a transaction. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
Expand All @@ -99,36 +98,36 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c

// PrefetchMining processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and snapshot clean state. Only used for mining stage
// only goal is to warm the state caches. Only used for mining stage.
func (p *statePrefetcher) PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) {
var signer = types.MakeSigner(p.config, header.Number, header.Time)

txCh := make(chan *types.Transaction, 2*prefetchThread)
for i := 0; i < prefetchThread; i++ {
go func(startCh <-chan *types.Transaction, stopCh <-chan struct{}) {
idx := 0
newStatedb := statedb.CopyDoPrefetch()
if !p.config.IsHertzfix(header.Number) {
if !p.config.IsHertzfix(header.Number) { // need in local env before Hertzfix hard fork
newStatedb.EnableWriteOnSharedStorage()
}
gaspool := new(GasPool).AddGas(gasLimit)
blockContext := NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(blockContext, newStatedb, p.config, cfg)

evm := vm.NewEVM(NewEVMBlockContext(header, p.chain, nil), newStatedb, p.config, cfg)
idx := 0
// Iterate over and process the individual transactions
for {
select {
case tx := <-startCh:
// Convert the transaction into an executable message and pre-cache its sender
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
msg.SkipNonceChecks = true
msg.SkipFromEOACheck = true
if err != nil {
return // Also invalid block, bail out
}
// Disable the nonce check
msg.SkipNonceChecks = true

idx++
newStatedb.SetTxContext(tx.Hash(), idx)
ApplyMessage(evm, msg, gaspool)
gaspool = new(GasPool).AddGas(gasLimit)
ApplyMessage(evm, msg, new(GasPool).AddGas(gasLimit))

case <-stopCh:
return
}
Expand Down
2 changes: 1 addition & 1 deletion core/state_prefetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestPrefetchLeaking(t *testing.T) {

Track(ctx, t, func(ctx context.Context) {
close(inter)
go archive.prefetcher.Prefetch(block, statedb, &archive.vmConfig, inter)
go archive.prefetcher.Prefetch(block.Transactions(), block.Header(), block.GasLimit(), statedb, &archive.vmConfig, inter)
time.Sleep(1 * time.Second)
})
}
Expand Down
4 changes: 2 additions & 2 deletions core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ type TransactionsByPriceAndNonce interface {
type Prefetcher interface {
// Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
Prefetch(block *types.Block, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{})
// only goal is to warm the state caches.
Prefetch(transactions types.Transactions, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{})
// PrefetchMining used for pre-caching transaction signatures and state trie nodes. Only used for mining stage.
PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction)
}
Expand Down
13 changes: 13 additions & 0 deletions miner/bid_simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)

const prefetchTxNumber = 100

var (
bidPreCheckTimer = metrics.NewRegisteredTimer("bid/preCheck", nil)
bidTryInterruptTimer = metrics.NewRegisteredTimer("bid/sim/tryInterrupt", nil)
Expand Down Expand Up @@ -67,6 +69,7 @@ var (
type bidWorker interface {
prepareWork(params *generateParams, witness bool) (*environment, error)
etherbase() common.Address
getPrefetcher() core.Prefetcher
fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error)
}

Expand Down Expand Up @@ -754,6 +757,16 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
bidSim1stBidTimer.UpdateSince(time.UnixMilli(int64(b.chain.GetHeaderByHash(bidRuntime.bid.ParentHash).MilliTimestamp())))
}

if len(bidRuntime.bid.Txs) > prefetchTxNumber {
interruptPrefetchCh := make(chan struct{})
defer close(interruptPrefetchCh)
throwaway := bidRuntime.env.state.CopyDoPrefetch()
// Disable tracing for prefetcher executions.
vmCfg := *b.chain.GetVMConfig()
vmCfg.Tracer = nil
go b.bidWorker.getPrefetcher().Prefetch(bidRuntime.bid.Txs, bidRuntime.env.header, gasLimit, throwaway, &vmCfg, interruptPrefetchCh)
}

// commit transactions in bid
for _, tx := range bidRuntime.bid.Txs {
select {
Expand Down
4 changes: 4 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ func (w *worker) setBestBidFetcher(fetcher bidFetcher) {
w.bidFetcher = fetcher
}

func (w *worker) getPrefetcher() core.Prefetcher {
return w.prefetcher
}

// setEtherbase sets the etherbase used to initialize the block coinbase field.
func (w *worker) setEtherbase(addr common.Address) {
w.confMu.Lock()
Expand Down