core, cmd, eth, internal, miner: rework makeReceipt

pull/30791/head
Gary Rong 3 days ago
parent 6485d5e3ff
commit 7c19e2a9fb
  1. 9
      cmd/evm/internal/t8ntool/execution.go
  2. 27
      core/blockchain.go
  3. 6
      core/chain_makers.go
  4. 15
      core/state/statedb.go
  5. 4
      core/state/statedb_test.go
  6. 61
      core/state_processor.go
  7. 2
      core/types.go
  8. 25
      core/types/log.go
  9. 4
      core/types/receipt.go
  10. 2
      eth/tracers/api.go
  11. 13
      internal/ethapi/simulate.go
  12. 14
      miner/miner.go
  13. 8
      miner/worker.go

@ -151,7 +151,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
gaspool = new(core.GasPool) gaspool = new(core.GasPool)
blockHash = common.Hash{0x13, 0x37}
rejectedTxs []*rejectedTx rejectedTxs []*rejectedTx
includedTxs types.Transactions includedTxs types.Transactions
gasUsed = uint64(0) gasUsed = uint64(0)
@ -312,7 +311,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
} }
// Set the receipt logs and create the bloom filter. // Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash) receipt.Logs = statedb.GetLogs(tx.Hash())
// TODO (rjl493456442) should we derive fields for logs? receipts?
receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
// These three are non-consensus fields: // These three are non-consensus fields:
//receipt.BlockHash //receipt.BlockHash
@ -367,9 +368,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
var requests [][]byte var requests [][]byte
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) { if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
// EIP-6110 deposits // EIP-6110 deposits
var allLogs []*types.Log var allLogs [][]*types.Log
for _, receipt := range receipts { for _, receipt := range receipts {
allLogs = append(allLogs, receipt.Logs...) allLogs = append(allLogs, receipt.Logs)
} }
depositRequests, err := core.ParseDepositLogs(allLogs, chainConfig) depositRequests, err := core.ParseDepositLogs(allLogs, chainConfig)
if err != nil { if err != nil {

@ -34,7 +34,6 @@ import (
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/common/prque"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/state/snapshot"
@ -1534,7 +1533,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead. // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held. // This function expects the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) { func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs [][]*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if err := bc.writeBlockWithState(block, receipts, state); err != nil { if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err return NonStatTy, err
} }
@ -1552,7 +1551,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
bc.chainFeed.Send(ChainEvent{Header: block.Header()}) bc.chainFeed.Send(ChainEvent{Header: block.Header()})
if len(logs) > 0 { if len(logs) > 0 {
bc.logsFeed.Send(logs) bc.logsFeed.Send(types.DeriveLogFields(block.Hash(), block.NumberU64(), logs, block.Transactions(), false))
} }
// In theory, we should fire a ChainHeadEvent when we inject // In theory, we should fire a ChainHeadEvent when we inject
// a canonical block, but sometimes we can insert a batch of // a canonical block, but sometimes we can insert a batch of
@ -2157,25 +2156,11 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
// collectLogs collects the logs that were generated or removed during the // collectLogs collects the logs that were generated or removed during the
// processing of a block. These logs are later announced as deleted or reborn. // processing of a block. These logs are later announced as deleted or reborn.
func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
var blobGasPrice *big.Int var logs [][]*types.Log
excessBlobGas := b.ExcessBlobGas() for _, receipt := range rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64()) {
if excessBlobGas != nil { logs = append(logs, receipt.Logs)
blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas)
}
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
if err := receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Time(), b.BaseFee(), blobGasPrice, b.Transactions()); err != nil {
log.Error("Failed to derive block receipts fields", "hash", b.Hash(), "number", b.NumberU64(), "err", err)
}
var logs []*types.Log
for _, receipt := range receipts {
for _, log := range receipt.Logs {
if removed {
log.Removed = true
}
logs = append(logs, log)
}
} }
return logs return types.DeriveLogFields(b.Hash(), b.NumberU64(), logs, b.Transactions(), removed)
} }
// reorg takes two blocks, an old chain and a new chain and will reconstruct the // reorg takes two blocks, an old chain and a new chain and will reconstruct the

@ -124,6 +124,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
} }
b.txs = append(b.txs, tx) b.txs = append(b.txs, tx)
b.receipts = append(b.receipts, receipt) b.receipts = append(b.receipts, receipt)
if b.header.BlobGasUsed != nil { if b.header.BlobGasUsed != nil {
*b.header.BlobGasUsed += receipt.BlobGasUsed *b.header.BlobGasUsed += receipt.BlobGasUsed
} }
@ -350,9 +351,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
var requests [][]byte var requests [][]byte
if config.IsPrague(b.header.Number, b.header.Time) { if config.IsPrague(b.header.Number, b.header.Time) {
// EIP-6110 deposits // EIP-6110 deposits
var blockLogs []*types.Log var blockLogs [][]*types.Log
for _, r := range b.receipts { for _, r := range b.receipts {
blockLogs = append(blockLogs, r.Logs...) blockLogs = append(blockLogs, r.Logs)
} }
depositRequests, err := ParseDepositLogs(blockLogs, config) depositRequests, err := ParseDepositLogs(blockLogs, config)
if err != nil { if err != nil {
@ -421,7 +422,6 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil { if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.BaseFee(), blobGasPrice, txs); err != nil {
panic(err) panic(err)
} }
// Re-expand to ensure all receipts are returned. // Re-expand to ensure all receipts are returned.
receipts = receipts[:receiptsCount] receipts = receipts[:receiptsCount]

@ -244,15 +244,12 @@ func (s *StateDB) AddLog(log *types.Log) {
s.logSize++ s.logSize++
} }
// GetLogs returns the logs matching the specified transaction hash, and annotates // GetLogs returns the logs matching the specified transaction hash.
// them with the given blockNumber and blockHash. //
func (s *StateDB) GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log { // TODO (rjl493456442) these logs are partially annotated (with transaction
logs := s.logs[hash] // information), please get rid of these annotations as well.
for _, l := range logs { func (s *StateDB) GetLogs(hash common.Hash) []*types.Log {
l.BlockNumber = blockNumber return s.logs[hash]
l.BlockHash = blockHash
}
return logs
} }
func (s *StateDB) Logs() []*types.Log { func (s *StateDB) Logs() []*types.Log {

@ -673,9 +673,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d",
state.GetRefund(), checkstate.GetRefund()) state.GetRefund(), checkstate.GetRefund())
} }
if !reflect.DeepEqual(state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) { if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) {
return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v",
state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{}))
} }
if !maps.Equal(state.journal.dirties, checkstate.journal.dirties) { if !maps.Equal(state.journal.dirties, checkstate.journal.dirties) {
getKeys := func(dirty map[common.Address]int) string { getKeys := func(dirty map[common.Address]int) string {

@ -18,14 +18,12 @@ package core
import ( import (
"fmt" "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -58,12 +56,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
receipts types.Receipts receipts types.Receipts
usedGas = new(uint64) usedGas = new(uint64)
header = block.Header() header = block.Header()
blockHash = block.Hash() allLogs [][]*types.Log
blockNumber = block.Number()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit()) gp = new(GasPool).AddGas(block.GasLimit())
) )
// Mutate the block and state according to any hard-fork specs // Mutate the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
@ -96,12 +91,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i)
receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, tx, usedGas, evm) receipt, err := ApplyTransactionWithEVM(msg, gp, statedb, tx, usedGas, evm)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
} }
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...) allLogs = append(allLogs, receipt.Logs)
} }
// Read requests if Prague is enabled. // Read requests if Prague is enabled.
var requests [][]byte var requests [][]byte
@ -134,16 +129,17 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// ApplyTransactionWithEVM attempts to apply a transaction to the given state database // ApplyTransactionWithEVM attempts to apply a transaction to the given state database
// and uses the input parameters for its environment similar to ApplyTransaction. However, // and uses the input parameters for its environment similar to ApplyTransaction. However,
// this method takes an already created EVM instance as input. // this method takes an already created EVM instance as input.
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
if hooks := evm.Config.Tracer; hooks != nil { if hooks := evm.Config.Tracer; hooks != nil {
if hooks.OnTxStart != nil { if hooks.OnTxStart != nil {
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
} }
if hooks.OnTxEnd != nil { if hooks.OnTxEnd != nil {
// TODO (rjl493456442) the receipt only contain consensus fields,
// should we derive the others here?
defer func() { hooks.OnTxEnd(receipt, err) }() defer func() { hooks.OnTxEnd(receipt, err) }()
} }
} }
// Create a new context to be used in the EVM environment. // Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg) txContext := NewEVMTxContext(msg)
evm.SetTxContext(txContext) evm.SetTxContext(txContext)
@ -153,9 +149,9 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Update the state with pending changes. // Update the state with pending changes.
var root []byte var root []byte
blockNumber := evm.Context.BlockNumber
if evm.ChainConfig().IsByzantium(blockNumber) { if evm.ChainConfig().IsByzantium(blockNumber) {
evm.StateDB.Finalise(true) evm.StateDB.Finalise(true)
} else { } else {
@ -163,11 +159,13 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
} }
*usedGas += result.UsedGas *usedGas += result.UsedGas
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil return MakeReceipt(evm, result, statedb, tx, *usedGas, root), nil
} }
// MakeReceipt generates the receipt object for a transaction given its execution result. // MakeReceipt generates the receipt object for a transaction based on its execution
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { // result. Note that the generated receipt only includes the consensus fields. Any
// additional fields must be derived separately by the caller if needed.
func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
// Create a new receipt for the transaction, storing the intermediate root and gas used // Create a new receipt for the transaction, storing the intermediate root and gas used
// by the tx. // by the tx.
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas} receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
@ -176,31 +174,17 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
} else { } else {
receipt.Status = types.ReceiptStatusSuccessful receipt.Status = types.ReceiptStatusSuccessful
} }
receipt.TxHash = tx.Hash() // Set the receipt logs and create the bloom filter.
receipt.GasUsed = result.UsedGas receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
if tx.Type() == types.BlobTxType {
receipt.BlobGasUsed = uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob)
receipt.BlobGasPrice = evm.Context.BlobBaseFee
}
// If the transaction created a contract, store the creation address in the receipt.
if tx.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}
// Merge the tx-local access event into the "block-local" one, in order to collect // Merge the tx-local access event into the "block-local" one, in order to collect
// all values, so that the witness can be built. // all values, so that the witness can be built.
//
// TODO (rjl493456442) relocate it to a better place.
if statedb.GetTrie().IsVerkle() { if statedb.GetTrie().IsVerkle() {
statedb.AccessEvents().Merge(evm.AccessEvents) statedb.AccessEvents().Merge(evm.AccessEvents)
} }
// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
receipt.BlockHash = blockHash
receipt.BlockNumber = blockNumber
receipt.TransactionIndex = uint(statedb.TxIndex())
return receipt return receipt
} }
@ -208,13 +192,16 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b
// and uses the input parameters for its environment. It returns the receipt // and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed, // for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid. // indicating the block was invalid.
//
// Note that the generated receipt only includes the consensus fields. Any
// additional fields must be derived separately by the caller if needed.
func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) { func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, error) {
msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee) msg, err := TransactionToMessage(tx, types.MakeSigner(evm.ChainConfig(), header.Number, header.Time), header.BaseFee)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Create a new context to be used in the EVM environment // Create a new context to be used in the EVM environment
return ApplyTransactionWithEVM(msg, gp, statedb, header.Number, header.Hash(), tx, usedGas, evm) return ApplyTransactionWithEVM(msg, gp, statedb, tx, usedGas, evm)
} }
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
@ -312,9 +299,10 @@ func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Addres
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by // ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
// BeaconDepositContract. // BeaconDepositContract.
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) { func ParseDepositLogs(logs [][]*types.Log, config *params.ChainConfig) ([]byte, error) {
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type) deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
for _, log := range logs { for _, subLogs := range logs {
for _, log := range subLogs {
if log.Address == config.DepositContractAddress { if log.Address == config.DepositContractAddress {
request, err := types.DepositLogToRequest(log.Data) request, err := types.DepositLogToRequest(log.Data)
if err != nil { if err != nil {
@ -323,5 +311,6 @@ func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, er
deposits = append(deposits, request...) deposits = append(deposits, request...)
} }
} }
}
return deposits, nil return deposits, nil
} }

@ -55,6 +55,6 @@ type Processor interface {
type ProcessResult struct { type ProcessResult struct {
Receipts types.Receipts Receipts types.Receipts
Requests [][]byte Requests [][]byte
Logs []*types.Log Logs [][]*types.Log
GasUsed uint64 GasUsed uint64
} }

@ -59,3 +59,28 @@ type logMarshaling struct {
TxIndex hexutil.Uint TxIndex hexutil.Uint
Index hexutil.Uint Index hexutil.Uint
} }
// DeriveLogFields fills the logs with contextual infos like corresponding block
// and transaction info.
func DeriveLogFields(hash common.Hash, number uint64, logs [][]*Log, txs []*Transaction, removed bool) []*Log {
var (
combined []*Log
logIndex = uint(0)
)
for i := 0; i < len(txs); i++ {
for j := 0; j < len(logs[i]); j++ {
l := logs[i][j]
l.BlockNumber = number
l.BlockHash = hash
l.TxHash = txs[i].Hash()
l.TxIndex = uint(i)
l.Index = logIndex
if removed {
l.Removed = true
}
combined = append(combined, l)
logIndex++
}
}
return combined
}

@ -321,8 +321,8 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
} }
} }
// DeriveFields fills the receipts with their computed fields based on consensus // DeriveFields fills the receipts and logs with their computed fields based
// data and contextual infos like containing block and transactions. // on consensus data and contextual infos like containing block and transactions.
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error { func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, time uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error {
signer := MakeSigner(config, new(big.Int).SetUint64(number), time) signer := MakeSigner(config, new(big.Int).SetUint64(number), time)

@ -1037,7 +1037,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
// Call Prepare to clear out the statedb access list // Call Prepare to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
_, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, evm) _, err = core.ApplyTransactionWithEVM(message, new(core.GasPool).AddGas(message.GasLimit), statedb, tx, &usedGas, evm)
if err != nil { if err != nil {
return nil, fmt.Errorf("tracing failed: %w", err) return nil, fmt.Errorf("tracing failed: %w", err)
} }

@ -179,6 +179,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
txes = make([]*types.Transaction, len(block.Calls)) txes = make([]*types.Transaction, len(block.Calls))
callResults = make([]simCallResult, len(block.Calls)) callResults = make([]simCallResult, len(block.Calls))
receipts = make([]*types.Receipt, len(block.Calls)) receipts = make([]*types.Receipt, len(block.Calls))
// Block hash will be repaired after execution. // Block hash will be repaired after execution.
tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0) tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0)
vmConfig = &vm.Config{ vmConfig = &vm.Config{
@ -206,7 +207,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
tx := call.ToTransaction(types.DynamicFeeTxType) tx := call.ToTransaction(types.DynamicFeeTxType)
txes[i] = tx txes[i] = tx
tracer.reset(tx.Hash(), uint(i)) tracer.reset(tx.Hash(), uint(i))
// EoA check is always skipped, even in validation mode.
// EOA check is always skipped, even in validation mode.
msg := call.ToMessage(header.BaseFee, !sim.validate, true) msg := call.ToMessage(header.BaseFee, !sim.validate, true)
evm.SetTxContext(core.NewEVMTxContext(msg)) evm.SetTxContext(core.NewEVMTxContext(msg))
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
@ -222,10 +224,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes() root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
} }
gasUsed += result.UsedGas gasUsed += result.UsedGas
receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, tx, gasUsed, root) receipts[i] = core.MakeReceipt(evm, result, sim.state, tx, gasUsed, root)
blobGasUsed += receipts[i].BlobGasUsed blobGasUsed += tx.BlobGas()
logs := tracer.Logs()
callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)} callRes := simCallResult{ReturnValue: result.Return(), Logs: tracer.Logs(), GasUsed: hexutil.Uint64(result.UsedGas)}
if result.Failed() { if result.Failed() {
callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed) callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed)
if errors.Is(result.Err, vm.ErrExecutionReverted) { if errors.Is(result.Err, vm.ErrExecutionReverted) {
@ -242,6 +244,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
} }
header.Root = sim.state.IntermediateRoot(true) header.Root = sim.state.IntermediateRoot(true)
header.GasUsed = gasUsed header.GasUsed = gasUsed
if sim.chainConfig.IsCancun(header.Number, header.Time) { if sim.chainConfig.IsCancun(header.Number, header.Time) {
header.BlobGasUsed = &blobGasUsed header.BlobGasUsed = &blobGasUsed
} }

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool"
@ -133,13 +134,13 @@ func (miner *Miner) BuildPayload(args *BuildPayloadArgs, witness bool) (*Payload
// getPending retrieves the pending block based on the current head block. // getPending retrieves the pending block based on the current head block.
// The result might be nil if pending generation is failed. // The result might be nil if pending generation is failed.
func (miner *Miner) getPending() *newPayloadResult { func (miner *Miner) getPending() *newPayloadResult {
header := miner.chain.CurrentHeader()
miner.pendingMu.Lock() miner.pendingMu.Lock()
defer miner.pendingMu.Unlock() defer miner.pendingMu.Unlock()
header := miner.chain.CurrentHeader()
if cached := miner.pending.resolve(header.Hash()); cached != nil { if cached := miner.pending.resolve(header.Hash()); cached != nil {
return cached return cached
} }
var ( var (
timestamp = uint64(time.Now().Unix()) timestamp = uint64(time.Now().Unix())
withdrawal types.Withdrawals withdrawal types.Withdrawals
@ -160,6 +161,15 @@ func (miner *Miner) getPending() *newPayloadResult {
if ret.err != nil { if ret.err != nil {
return nil return nil
} }
// Derive the receipt fields for RPC querying.
var blobGasPrice *big.Int
if ret.block.ExcessBlobGas() != nil {
blobGasPrice = eip4844.CalcBlobFee(*ret.block.ExcessBlobGas())
}
err := types.Receipts(ret.receipts).DeriveFields(miner.chain.Config(), ret.block.Hash(), ret.block.NumberU64(), ret.block.Time(), ret.block.BaseFee(), blobGasPrice, ret.block.Transactions())
if err != nil {
return nil
}
miner.pending.update(header.Hash(), ret) miner.pending.update(header.Hash(), ret)
return ret return ret
} }

@ -76,7 +76,7 @@ type newPayloadResult struct {
fees *big.Int // total block fees fees *big.Int // total block fees
sidecars []*types.BlobTxSidecar // collected blobs of blob transactions sidecars []*types.BlobTxSidecar // collected blobs of blob transactions
stateDB *state.StateDB // StateDB after executing the transactions stateDB *state.StateDB // StateDB after executing the transactions
receipts []*types.Receipt // Receipts collected during construction receipts []*types.Receipt // Receipts collected during construction, only contain consensus fields
requests [][]byte // Consensus layer requests collected during block construction requests [][]byte // Consensus layer requests collected during block construction
witness *stateless.Witness // Witness is an optional stateless proof witness *stateless.Witness // Witness is an optional stateless proof
} }
@ -113,11 +113,10 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
} }
body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals} body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
allLogs := make([]*types.Log, 0) var allLogs [][]*types.Log
for _, r := range work.receipts { for _, r := range work.receipts {
allLogs = append(allLogs, r.Logs...) allLogs = append(allLogs, r.Logs)
} }
// Collect consensus-layer requests if Prague is enabled. // Collect consensus-layer requests if Prague is enabled.
var requests [][]byte var requests [][]byte
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) { if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
@ -138,7 +137,6 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
reqHash := types.CalcRequestsHash(requests) reqHash := types.CalcRequestsHash(requests)
work.header.RequestsHash = &reqHash work.header.RequestsHash = &reqHash
} }
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts) block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts)
if err != nil { if err != nil {
return &newPayloadResult{err: err} return &newPayloadResult{err: err}

Loading…
Cancel
Save