Skip to content

core, miner: do not populate receipts field during mining #31813

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
3 changes: 1 addition & 2 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
1 change: 0 additions & 1 deletion core/state/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,6 @@ func (ch addLogChange) revert(s *StateDB) {
} else {
s.logs[ch.txhash] = logs[:len(logs)-1]
}
s.logSize--
}

func (ch addLogChange) dirtied() *common.Address {
Expand Down
18 changes: 3 additions & 15 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -675,7 +664,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?
Expand Down
5 changes: 2 additions & 3 deletions core/state/statedb_hooked_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand All @@ -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...))
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions core/state/statedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
40 changes: 30 additions & 10 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logs constructed during the block insertion (e.g., full sync) will be emitted to the log subscribers, which assumes the logs should be fully annotated.

Here, the logs are partially annotated, missing blockNumber and blockHash fields.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? I don't see where they are emitted to the log subscribers. I only see them written to the db and later on read from the db during collectLogs and the missing fields are derived

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gary has a point. This is where the logs are being sent out to subscribers:

bc.logsFeed.Send(logs)

I missed this. We don't have pending subscription anymore but the log subscription to newly mined logs is there.

I think it will be tricky to derive the fields in the consumer unless we change the structure of the logsFeed. At least would need the header and unflattened logs.

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

Expand All @@ -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())
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions internal/ethapi/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,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
}
Expand Down