diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index b2e5f70714..1f1db4e7a6 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -146,7 +146,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) gaspool = new(core.GasPool) - blockHash = common.Hash{0x13, 0x37} rejectedTxs []*rejectedTx includedTxs types.Transactions gasUsed = uint64(0) @@ -303,7 +302,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // 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()) receipt.Bloom = types.CreateBloom(receipt) // These three are non-consensus fields: diff --git a/core/chain_makers.go b/core/chain_makers.go index 37bddcfda5..e3e5867e99 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -130,7 +130,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti b.txs = append(b.txs, tx) b.receipts = append(b.receipts, receipt) if b.header.BlobGasUsed != nil { - *b.header.BlobGasUsed += receipt.BlobGasUsed + *b.header.BlobGasUsed += uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) } } diff --git a/core/state/journal.go b/core/state/journal.go index f3f976f24f..df698bd104 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -449,7 +449,6 @@ func (ch addLogChange) revert(s *StateDB) { } else { s.logs[ch.txhash] = logs[:len(logs)-1] } - s.logSize-- } func (ch addLogChange) dirtied() *common.Address { diff --git a/core/state/statedb.go b/core/state/statedb.go index 51453055c3..ed43ddc869 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -119,7 +119,6 @@ type StateDB struct { thash common.Hash txIndex int logs map[common.Hash][]*types.Log - logSize uint // Preimages occurred seen by VM in the scope of block. preimages map[common.Hash][]byte @@ -243,22 +242,12 @@ func (s *StateDB) Error() error { func (s *StateDB) AddLog(log *types.Log) { s.journal.logChange(s.thash) - log.TxHash = s.thash - log.TxIndex = uint(s.txIndex) - log.Index = s.logSize s.logs[s.thash] = append(s.logs[s.thash], log) - s.logSize++ } -// GetLogs returns the logs matching the specified transaction hash, and annotates -// them with the given blockNumber and blockHash. -func (s *StateDB) GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log { - logs := s.logs[hash] - for _, l := range logs { - l.BlockNumber = blockNumber - l.BlockHash = blockHash - } - return logs +// GetLogs returns the logs matching the specified transaction hash. +func (s *StateDB) GetLogs(hash common.Hash) []*types.Log { + return s.logs[hash] } func (s *StateDB) Logs() []*types.Log { @@ -674,7 +663,6 @@ func (s *StateDB) Copy() *StateDB { thash: s.thash, txIndex: s.txIndex, logs: make(map[common.Hash][]*types.Log, len(s.logs)), - logSize: s.logSize, preimages: maps.Clone(s.preimages), // Do we need to copy the access list and transient storage? diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index f319b0e63c..47b0b7e2ab 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -80,7 +80,6 @@ func TestBurn(t *testing.T) { // TestHooks is a basic sanity-check of all hooks func TestHooks(t *testing.T) { inner, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) - inner.SetTxContext(common.Hash{0x11}, 100) // For the log var result []string var wants = []string{ "0xaa00000000000000000000000000000000000000.balance: 0->100 (Unspecified)", @@ -89,7 +88,7 @@ func TestHooks(t *testing.T) { "0xaa00000000000000000000000000000000000000.code: (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728)", "0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000000 ->0x0000000000000000000000000000000000000000000000000000000000000011", "0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000011 ->0x0000000000000000000000000000000000000000000000000000000000000022", - "log 100", + "log 0xbb00000000000000000000000000000000000000", } emitF := func(format string, a ...any) { result = append(result, fmt.Sprintf(format, a...)) @@ -108,7 +107,7 @@ func TestHooks(t *testing.T) { emitF("%v.storage slot %v: %v ->%v", addr, slot, prev, new) }, OnLog: func(log *types.Log) { - emitF("log %v", log.TxIndex) + emitF("log %v", log.Address) }, }) sdb.AddBalance(common.Address{0xaa}, uint256.NewInt(100), tracing.BalanceChangeUnspecified) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 709b5ed510..3e296aa046 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -669,9 +669,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 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", - 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) { getKeys := func(dirty map[common.Address]int) string { diff --git a/core/state_processor.go b/core/state_processor.go index 322bd24f41..6dd114def2 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -137,16 +137,22 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // and uses the input parameters for its environment similar to ApplyTransaction. However, // 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) { + var result *ExecutionResult if hooks := evm.Config.Tracer; hooks != nil { if hooks.OnTxStart != nil { hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) } if hooks.OnTxEnd != nil { - defer func() { hooks.OnTxEnd(receipt, err) }() + defer func() { + if receipt != nil { + receipt = deriveFullReceipt(receipt, evm, result, statedb, blockNumber, blockHash, tx) + } + hooks.OnTxEnd(receipt, err) + }() } } // Apply the transaction to the current state (included in the env). - result, err := ApplyMessage(evm, msg, gp) + result, err = ApplyMessage(evm, msg, gp) if err != nil { return nil, err } @@ -165,19 +171,28 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, statedb.AccessEvents().Merge(evm.AccessEvents) } - return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), nil + receipt = MakeReceipt(result, statedb, tx, *usedGas, root) + return receipt, nil } // MakeReceipt generates the receipt object for a transaction given its execution result. -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 { - // Create a new receipt for the transaction, storing the intermediate root and gas used - // by the tx. +// It only populates the fields strictly required for consensus. +func MakeReceipt(result *ExecutionResult, statedb *state.StateDB, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt { receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas} if result.Failed() { receipt.Status = types.ReceiptStatusFailed } else { receipt.Status = types.ReceiptStatusSuccessful } + receipt.Logs = statedb.GetLogs(tx.Hash()) + receipt.Bloom = types.CreateBloom(receipt) + return receipt +} + +// deriveFullReceipt populates non-consensus fields. +func deriveFullReceipt(receipt *types.Receipt, evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction) *types.Receipt { + // Create a new receipt for the transaction, storing the intermediate root and gas used + // by the tx. receipt.TxHash = tx.Hash() receipt.GasUsed = result.UsedGas @@ -191,9 +206,14 @@ func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, b receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) } - // Set the receipt logs and create the bloom filter. - receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash) - receipt.Bloom = types.CreateBloom(receipt) + // Annotate the logs + for index, log := range receipt.Logs { + log.TxHash = tx.Hash() + log.TxIndex = uint(statedb.TxIndex()) + log.Index = uint(index) + log.BlockHash = blockHash + log.BlockNumber = blockNumber.Uint64() + } receipt.BlockHash = blockHash receipt.BlockNumber = blockNumber receipt.TransactionIndex = uint(statedb.TxIndex()) @@ -210,7 +230,7 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header * return nil, err } // 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, header.Number, common.Hash{}, tx, usedGas, evm) } // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index b997cf297b..787311a40c 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -301,8 +301,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes() } gasUsed += result.UsedGas - receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, tx, gasUsed, root) - blobGasUsed += receipts[i].BlobGasUsed + receipts[i] = core.MakeReceipt(result, sim.state, tx, gasUsed, root) + blobGasUsed += uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) logs := tracer.Logs() callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)} if result.Failed() { diff --git a/miner/worker.go b/miner/worker.go index 198745ad27..b239aa07ed 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -298,7 +298,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio env.receipts = append(env.receipts, receipt) env.sidecars = append(env.sidecars, sc) env.blobs += len(sc.Blobs) - *env.header.BlobGasUsed += receipt.BlobGasUsed + *env.header.BlobGasUsed += uint64(len(tx.BlobHashes()) * params.BlobTxBlobGasPerBlob) env.tcount++ return nil }