mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
refactor(trace): clean outdated fields (#842)
* clean trace: remove ExtraData, disable prestateTracer, collect bytecodes in top level * fix * fix * fix * fix * fix * more cleanup * more cleanup * refactor(trace): clean outdated fields * fix bytecodes in trace * chore: auto version bump [bot] * chore: auto version bump [bot] * use hexutil.Bytes --------- Co-authored-by: Ömer Faruk Irmak <omerfirmak@gmail.com> Co-authored-by: omerfirmak <omerfirmak@users.noreply.github.com> Co-authored-by: lispc <lispc@users.noreply.github.com>
This commit is contained in:
parent
df08f60183
commit
0cecc1986e
5 changed files with 83 additions and 159 deletions
|
|
@ -17,12 +17,21 @@ type BlockTrace struct {
|
|||
Header *Header `json:"header"`
|
||||
Transactions []*TransactionData `json:"transactions"`
|
||||
StorageTrace *StorageTrace `json:"storageTrace"`
|
||||
Bytecodes []*BytecodeTrace `json:"codes"`
|
||||
TxStorageTraces []*StorageTrace `json:"txStorageTraces,omitempty"`
|
||||
ExecutionResults []*ExecutionResult `json:"executionResults"`
|
||||
WithdrawTrieRoot common.Hash `json:"withdraw_trie_root,omitempty"`
|
||||
StartL1QueueIndex uint64 `json:"startL1QueueIndex"`
|
||||
}
|
||||
|
||||
// BytecodeTrace stores all accessed bytecodes
|
||||
type BytecodeTrace struct {
|
||||
CodeSize uint64 `json:"codeSize"`
|
||||
KeccakCodeHash common.Hash `json:"keccakCodeHash"`
|
||||
PoseidonCodeHash common.Hash `json:"hash"`
|
||||
Code hexutil.Bytes `json:"code"`
|
||||
}
|
||||
|
||||
// StorageTrace stores proofs of storage needed by storage circuit
|
||||
type StorageTrace struct {
|
||||
// Root hash before block execution:
|
||||
|
|
@ -61,13 +70,8 @@ type ExecutionResult struct {
|
|||
// currently they are just `from` and `to` account
|
||||
AccountsAfter []*AccountWrapper `json:"accountAfter"`
|
||||
|
||||
// `PoseidonCodeHash` only exists when tx is a contract call.
|
||||
PoseidonCodeHash *common.Hash `json:"poseidonCodeHash,omitempty"`
|
||||
// If it is a contract call, the contract code is returned.
|
||||
ByteCode string `json:"byteCode,omitempty"`
|
||||
StructLogs []*StructLogRes `json:"structLogs"`
|
||||
CallTrace json.RawMessage `json:"callTrace"`
|
||||
Prestate json.RawMessage `json:"prestate"`
|
||||
}
|
||||
|
||||
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
||||
|
|
@ -83,7 +87,6 @@ type StructLogRes struct {
|
|||
Memory []string `json:"memory,omitempty"`
|
||||
Storage map[string]string `json:"storage,omitempty"`
|
||||
RefundCounter uint64 `json:"refund,omitempty"`
|
||||
ExtraData *ExtraData `json:"extraData,omitempty"`
|
||||
}
|
||||
|
||||
// NewStructLogResBasic Basic StructLogRes skeleton, Stack&Memory&Storage&ExtraData are separated from it for GC optimization;
|
||||
|
|
@ -104,31 +107,6 @@ func NewStructLogResBasic(pc uint64, op string, gas, gasCost uint64, depth int,
|
|||
return logRes
|
||||
}
|
||||
|
||||
type ExtraData struct {
|
||||
// Indicate the call succeeds or not for CALL/CREATE op
|
||||
CallFailed bool `json:"callFailed,omitempty"`
|
||||
// CALL | CALLCODE | DELEGATECALL | STATICCALL: [tx.to address’s code, stack.nth_last(1) address’s code]
|
||||
// CREATE | CREATE2: [created contract’s code]
|
||||
// CODESIZE | CODECOPY: [contract’s code]
|
||||
// EXTCODESIZE | EXTCODECOPY: [stack.nth_last(0) address’s code]
|
||||
CodeList []string `json:"codeList,omitempty"`
|
||||
// SSTORE | SLOAD: [storageProof]
|
||||
// SELFDESTRUCT: [contract address’s account, stack.nth_last(0) address’s account]
|
||||
// SELFBALANCE: [contract address’s account]
|
||||
// BALANCE | EXTCODEHASH: [stack.nth_last(0) address’s account]
|
||||
// CREATE | CREATE2: [created contract address’s account (before constructed),
|
||||
// created contract address's account (after constructed)]
|
||||
// CALL | CALLCODE: [caller contract address’s account,
|
||||
// stack.nth_last(1) (i.e. callee) address’s account,
|
||||
// callee contract address's account (value updated, before called)]
|
||||
// STATICCALL: [stack.nth_last(1) (i.e. callee) address’s account,
|
||||
// callee contract address's account (before called)]
|
||||
StateList []*AccountWrapper `json:"proofList,omitempty"`
|
||||
// The status of caller, it would be captured twice:
|
||||
// 1. before execution and 2. updated in CaptureEnter (for CALL/CALLCODE it duplicated with StateList[0])
|
||||
Caller []*AccountWrapper `json:"caller,omitempty"`
|
||||
}
|
||||
|
||||
type AccountWrapper struct {
|
||||
Address common.Address `json:"address"`
|
||||
Nonce uint64 `json:"nonce"`
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ type StructLog struct {
|
|||
Storage map[common.Hash]common.Hash `json:"-"`
|
||||
Depth int `json:"depth"`
|
||||
RefundCounter uint64 `json:"refund"`
|
||||
ExtraData *types.ExtraData `json:"extraData"`
|
||||
Err error `json:"-"`
|
||||
}
|
||||
|
||||
|
|
@ -96,17 +95,9 @@ func (s *StructLog) clean() {
|
|||
s.Stack = s.Stack[:0]
|
||||
s.ReturnData.Reset()
|
||||
s.Storage = nil
|
||||
s.ExtraData = nil
|
||||
s.Err = nil
|
||||
}
|
||||
|
||||
func (s *StructLog) getOrInitExtraData() *types.ExtraData {
|
||||
if s.ExtraData == nil {
|
||||
s.ExtraData = &types.ExtraData{}
|
||||
}
|
||||
return s.ExtraData
|
||||
}
|
||||
|
||||
// overrides for gencodec
|
||||
type structLogMarshaling struct {
|
||||
Gas math.HexOrDecimal64
|
||||
|
|
@ -145,6 +136,13 @@ type EVMLogger interface {
|
|||
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
|
||||
}
|
||||
|
||||
type CodeInfo struct {
|
||||
CodeSize uint64
|
||||
KeccakCodeHash common.Hash
|
||||
PoseidonCodeHash common.Hash
|
||||
Code []byte
|
||||
}
|
||||
|
||||
// StructLogger is an EVM state logger and implements EVMLogger.
|
||||
//
|
||||
// StructLogger can capture state based on the given Log configuration and also keeps
|
||||
|
|
@ -154,6 +152,8 @@ type StructLogger struct {
|
|||
cfg LogConfig
|
||||
env *EVM
|
||||
|
||||
bytecodes map[common.Hash]CodeInfo
|
||||
|
||||
statesAffected map[common.Address]struct{}
|
||||
storage map[common.Address]Storage
|
||||
createdAccount *types.AccountWrapper
|
||||
|
|
@ -167,6 +167,7 @@ type StructLogger struct {
|
|||
// NewStructLogger returns a new logger
|
||||
func NewStructLogger(cfg *LogConfig) *StructLogger {
|
||||
logger := &StructLogger{
|
||||
bytecodes: make(map[common.Hash]CodeInfo),
|
||||
storage: make(map[common.Address]Storage),
|
||||
statesAffected: make(map[common.Address]struct{}),
|
||||
}
|
||||
|
|
@ -179,6 +180,7 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
|
|||
|
||||
// Reset clears the data held by the logger.
|
||||
func (l *StructLogger) Reset() {
|
||||
l.bytecodes = make(map[common.Hash]CodeInfo)
|
||||
l.storage = make(map[common.Address]Storage)
|
||||
l.statesAffected = make(map[common.Address]struct{})
|
||||
l.output = make([]byte, 0)
|
||||
|
|
@ -200,6 +202,8 @@ func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Add
|
|||
Nonce: env.StateDB.GetNonce(to),
|
||||
Balance: (*hexutil.Big)(value),
|
||||
}
|
||||
} else {
|
||||
traceCodeWithAddress(l, to)
|
||||
}
|
||||
|
||||
l.statesAffected[from] = struct{}{}
|
||||
|
|
@ -260,17 +264,11 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
|
|||
if ok {
|
||||
// execute trace func list.
|
||||
for _, exec := range execFuncList {
|
||||
if err := exec(l, scope, structLog.getOrInitExtraData()); err != nil {
|
||||
if err := exec(l, scope); err != nil {
|
||||
log.Error("Failed to trace data", "opcode", op.String(), "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// for each "calling" op, pick the caller's state
|
||||
switch op {
|
||||
case CALL, CALLCODE, STATICCALL, DELEGATECALL, CREATE, CREATE2:
|
||||
extraData := structLog.getOrInitExtraData()
|
||||
extraData.Caller = append(extraData.Caller, getWrappedAccountForAddr(l, scope.Contract.Address()))
|
||||
}
|
||||
|
||||
// in reality it is impossible for CREATE to trigger ErrContractAddressCollision
|
||||
if op == CREATE2 && opErr == nil {
|
||||
|
|
@ -288,9 +286,6 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
|
|||
|
||||
contractHash := l.env.StateDB.GetKeccakCodeHash(address)
|
||||
if l.env.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyKeccakCodeHash) {
|
||||
extraData := structLog.getOrInitExtraData()
|
||||
wrappedStatus := getWrappedAccountForAddr(l, address)
|
||||
extraData.StateList = append(extraData.StateList, wrappedStatus)
|
||||
l.statesAffected[address] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
|
@ -331,16 +326,7 @@ func (l *StructLogger) CaptureEnter(typ OpCode, from common.Address, to common.A
|
|||
panic("unexpected evm depth in capture enter")
|
||||
}
|
||||
l.statesAffected[to] = struct{}{}
|
||||
theLog := l.logs[lastLogPos]
|
||||
theLog.getOrInitExtraData()
|
||||
// handling additional updating for CALL/STATICCALL/CALLCODE/CREATE/CREATE2 only
|
||||
// append extraData part for the log, capture the account status (the nonce / balance has been updated in capture enter)
|
||||
wrappedStatus := getWrappedAccountForAddr(l, to)
|
||||
theLog.ExtraData.StateList = append(theLog.ExtraData.StateList, wrappedStatus)
|
||||
// finally we update the caller's status (it is possible that nonce and balance being updated)
|
||||
if len(theLog.ExtraData.Caller) == 1 {
|
||||
theLog.ExtraData.Caller = append(theLog.ExtraData.Caller, getWrappedAccountForAddr(l, from))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CaptureExit phase, a CREATE has its target address's code being set and queryable
|
||||
|
|
@ -350,32 +336,7 @@ func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
|
|||
panic("unexpected capture exit occur")
|
||||
}
|
||||
|
||||
theLogPos := l.callStackLogInd[stackH-1]
|
||||
l.callStackLogInd = l.callStackLogInd[:stackH-1]
|
||||
theLog := l.logs[theLogPos]
|
||||
// update "forecast" data
|
||||
if err != nil {
|
||||
theLog.ExtraData.CallFailed = true
|
||||
}
|
||||
|
||||
// handling updating for CREATE only
|
||||
switch theLog.Op {
|
||||
case CREATE, CREATE2:
|
||||
// append extraData part for the log whose op is CREATE(2), capture the account status (the codehash would be updated in capture exit)
|
||||
dataLen := len(theLog.ExtraData.StateList)
|
||||
if dataLen == 0 {
|
||||
panic("unexpected data capture for target op")
|
||||
}
|
||||
|
||||
lastAccData := theLog.ExtraData.StateList[dataLen-1]
|
||||
wrappedStatus := getWrappedAccountForAddr(l, lastAccData.Address)
|
||||
theLog.ExtraData.StateList = append(theLog.ExtraData.StateList, wrappedStatus)
|
||||
code := getCodeForAddr(l, lastAccData.Address)
|
||||
theLog.ExtraData.CodeList = append(theLog.ExtraData.CodeList, hexutil.Encode(code))
|
||||
default:
|
||||
//do nothing for other op code
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -389,6 +350,11 @@ func (l *StructLogger) UpdatedStorages() map[common.Address]Storage {
|
|||
return l.storage
|
||||
}
|
||||
|
||||
// TracedBytecodes is used to collect all "touched" bytecodes
|
||||
func (l *StructLogger) TracedBytecodes() map[common.Hash]CodeInfo {
|
||||
return l.bytecodes
|
||||
}
|
||||
|
||||
// CreatedAccount return the account data in case it is a create tx
|
||||
func (l *StructLogger) CreatedAccount() *types.AccountWrapper { return l.createdAccount }
|
||||
|
||||
|
|
@ -540,7 +506,6 @@ func FormatLogs(logs []*StructLog) []*types.StructLogRes {
|
|||
}
|
||||
logRes.Storage = storage
|
||||
}
|
||||
logRes.ExtraData = trace.ExtraData
|
||||
|
||||
formatted = append(formatted, logRes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ package vm
|
|||
|
||||
import (
|
||||
"github.com/scroll-tech/go-ethereum/common"
|
||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type traceFunc func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error
|
||||
type traceFunc func(l *StructLogger, scope *ScopeContext) error
|
||||
|
||||
var (
|
||||
// OpcodeExecs the map to load opcodes' trace funcs.
|
||||
|
|
@ -15,58 +13,53 @@ var (
|
|||
CALLCODE: {traceToAddressCode, traceLastNAddressCode(1), traceContractAccount, traceLastNAddressAccount(1)}, // contract account is the caller, stack.nth_last(1) is the callee's address
|
||||
DELEGATECALL: {traceToAddressCode, traceLastNAddressCode(1)},
|
||||
STATICCALL: {traceToAddressCode, traceLastNAddressCode(1), traceLastNAddressAccount(1)},
|
||||
CREATE: {}, // caller is already recorded in ExtraData.Caller, callee is recorded in CaptureEnter&CaptureExit
|
||||
CREATE2: {}, // caller is already recorded in ExtraData.Caller, callee is recorded in CaptureEnter&CaptureExit
|
||||
SLOAD: {}, // trace storage in `captureState` instead of here, to handle `l.cfg.DisableStorage` flag
|
||||
SSTORE: {}, // trace storage in `captureState` instead of here, to handle `l.cfg.DisableStorage` flag
|
||||
SELFDESTRUCT: {traceContractAccount, traceLastNAddressAccount(0)},
|
||||
SELFBALANCE: {traceContractAccount},
|
||||
BALANCE: {traceLastNAddressAccount(0)},
|
||||
EXTCODEHASH: {traceLastNAddressAccount(0)},
|
||||
CODESIZE: {traceContractCode},
|
||||
CODECOPY: {traceContractCode},
|
||||
EXTCODESIZE: {traceLastNAddressCode(0)},
|
||||
EXTCODESIZE: {traceLastNAddressAccount(0)},
|
||||
EXTCODECOPY: {traceLastNAddressCode(0)},
|
||||
}
|
||||
)
|
||||
|
||||
// traceToAddressCode gets tx.to address’s code
|
||||
func traceToAddressCode(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||
func traceToAddressCode(l *StructLogger, scope *ScopeContext) error {
|
||||
if l.env.To == nil {
|
||||
return nil
|
||||
}
|
||||
code := l.env.StateDB.GetCode(*l.env.To)
|
||||
extraData.CodeList = append(extraData.CodeList, hexutil.Encode(code))
|
||||
traceCodeWithAddress(l, *l.env.To)
|
||||
return nil
|
||||
}
|
||||
|
||||
// traceLastNAddressCode
|
||||
func traceLastNAddressCode(n int) traceFunc {
|
||||
return func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||
return func(l *StructLogger, scope *ScopeContext) error {
|
||||
stack := scope.Stack
|
||||
if stack.len() <= n {
|
||||
return nil
|
||||
}
|
||||
address := common.Address(stack.data[stack.len()-1-n].Bytes20())
|
||||
code := l.env.StateDB.GetCode(address)
|
||||
extraData.CodeList = append(extraData.CodeList, hexutil.Encode(code))
|
||||
traceCodeWithAddress(l, address)
|
||||
l.statesAffected[address] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// traceContractCode gets the contract's code
|
||||
func traceContractCode(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||
code := l.env.StateDB.GetCode(scope.Contract.Address())
|
||||
extraData.CodeList = append(extraData.CodeList, hexutil.Encode(code))
|
||||
return nil
|
||||
func traceCodeWithAddress(l *StructLogger, address common.Address) {
|
||||
code := l.env.StateDB.GetCode(address)
|
||||
keccakCodeHash := l.env.StateDB.GetKeccakCodeHash(address)
|
||||
poseidonCodeHash := l.env.StateDB.GetPoseidonCodeHash(address)
|
||||
codeSize := l.env.StateDB.GetCodeSize(address)
|
||||
l.bytecodes[poseidonCodeHash] = CodeInfo{
|
||||
codeSize,
|
||||
keccakCodeHash,
|
||||
poseidonCodeHash,
|
||||
code,
|
||||
}
|
||||
}
|
||||
|
||||
// traceContractAccount gets the contract's account
|
||||
func traceContractAccount(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||
// Get account state.
|
||||
state := getWrappedAccountForAddr(l, scope.Contract.Address())
|
||||
extraData.StateList = append(extraData.StateList, state)
|
||||
func traceContractAccount(l *StructLogger, scope *ScopeContext) error {
|
||||
l.statesAffected[scope.Contract.Address()] = struct{}{}
|
||||
|
||||
return nil
|
||||
|
|
@ -74,33 +67,15 @@ func traceContractAccount(l *StructLogger, scope *ScopeContext, extraData *types
|
|||
|
||||
// traceLastNAddressAccount returns func about the last N's address account.
|
||||
func traceLastNAddressAccount(n int) traceFunc {
|
||||
return func(l *StructLogger, scope *ScopeContext, extraData *types.ExtraData) error {
|
||||
return func(l *StructLogger, scope *ScopeContext) error {
|
||||
stack := scope.Stack
|
||||
if stack.len() <= n {
|
||||
return nil
|
||||
}
|
||||
|
||||
address := common.Address(stack.data[stack.len()-1-n].Bytes20())
|
||||
state := getWrappedAccountForAddr(l, address)
|
||||
extraData.StateList = append(extraData.StateList, state)
|
||||
l.statesAffected[address] = struct{}{}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// StorageWrapper will be empty
|
||||
func getWrappedAccountForAddr(l *StructLogger, address common.Address) *types.AccountWrapper {
|
||||
return &types.AccountWrapper{
|
||||
Address: address,
|
||||
Nonce: l.env.StateDB.GetNonce(address),
|
||||
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
|
||||
KeccakCodeHash: l.env.StateDB.GetKeccakCodeHash(address),
|
||||
PoseidonCodeHash: l.env.StateDB.GetPoseidonCodeHash(address),
|
||||
CodeSize: l.env.StateDB.GetCodeSize(address),
|
||||
}
|
||||
}
|
||||
|
||||
func getCodeForAddr(l *StructLogger, address common.Address) []byte {
|
||||
return l.env.StateDB.GetCode(address)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 5 // Major version component of the current release
|
||||
VersionMinor = 5 // Minor version component of the current release
|
||||
VersionPatch = 11 // Patch version component of the current release
|
||||
VersionPatch = 12 // Patch version component of the current release
|
||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/scroll-tech/go-ethereum/core/state"
|
||||
"github.com/scroll-tech/go-ethereum/core/types"
|
||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||
"github.com/scroll-tech/go-ethereum/crypto/codehash"
|
||||
"github.com/scroll-tech/go-ethereum/eth/tracers"
|
||||
_ "github.com/scroll-tech/go-ethereum/eth/tracers/native"
|
||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||
|
|
@ -61,18 +62,19 @@ type TraceEnv struct {
|
|||
|
||||
coinbase common.Address
|
||||
|
||||
// rMu lock is used to protect txs executed in parallel.
|
||||
signer types.Signer
|
||||
state *state.StateDB
|
||||
blockCtx vm.BlockContext
|
||||
|
||||
// pMu lock is used to protect Proofs' read and write mutual exclusion,
|
||||
// since txs are executed in parallel, so this lock is required.
|
||||
pMu sync.Mutex
|
||||
// sMu is required because of txs are executed in parallel,
|
||||
// this lock is used to protect StorageTrace's read and write mutual exclusion.
|
||||
sMu sync.Mutex
|
||||
// The following Mutexes are used to protect against parallel read/write,
|
||||
// since txs are executed in parallel.
|
||||
pMu sync.Mutex // for `TraceEnv.StorageTrace.Proofs`
|
||||
sMu sync.Mutex // for `TraceEnv.state``
|
||||
cMu sync.Mutex // for `TraceEnv.Codes`
|
||||
|
||||
*types.StorageTrace
|
||||
|
||||
Codes map[common.Hash]vm.CodeInfo
|
||||
TxStorageTraces []*types.StorageTrace
|
||||
// zktrie tracer is used for zktrie storage to build additional deletion proof
|
||||
ZkTrieTracer map[string]state.ZktrieProofTracer
|
||||
|
|
@ -112,6 +114,7 @@ func CreateTraceEnvHelper(chainConfig *params.ChainConfig, logConfig *vm.LogConf
|
|||
Proofs: make(map[string][]hexutil.Bytes),
|
||||
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
|
||||
},
|
||||
Codes: make(map[common.Hash]vm.CodeInfo),
|
||||
ZkTrieTracer: make(map[string]state.ZktrieProofTracer),
|
||||
ExecutionResults: make([]*types.ExecutionResult, block.Transactions().Len()),
|
||||
TxStorageTraces: make([]*types.StorageTrace, block.Transactions().Len()),
|
||||
|
|
@ -319,14 +322,10 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to create callTracer: %w", err)
|
||||
}
|
||||
prestateTracer, err := tracers.New("prestateTracer", &tracerContext)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create prestateTracer: %w", err)
|
||||
}
|
||||
|
||||
applyMessageStart := time.Now()
|
||||
structLogger := vm.NewStructLogger(env.logConfig)
|
||||
tracer := NewMuxTracer(structLogger, callTracer, prestateTracer)
|
||||
tracer := NewMuxTracer(structLogger, callTracer)
|
||||
// Run the transaction with tracing enabled.
|
||||
vmenv := vm.NewEVM(env.blockCtx, txContext, state, env.chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
||||
|
||||
|
|
@ -383,6 +382,15 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
|||
txStorageTrace.RootAfter = block.Root()
|
||||
}
|
||||
|
||||
// merge bytecodes
|
||||
env.cMu.Lock()
|
||||
for codeHash, codeInfo := range structLogger.TracedBytecodes() {
|
||||
if codeHash != (common.Hash{}) {
|
||||
env.Codes[codeHash] = codeInfo
|
||||
}
|
||||
}
|
||||
env.cMu.Unlock()
|
||||
|
||||
// merge required proof data
|
||||
proofAccounts := structLogger.UpdatedAccounts()
|
||||
proofAccounts[vmenv.FeeRecipient()] = struct{}{}
|
||||
|
|
@ -487,10 +495,6 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to get callTracer result: %w", err)
|
||||
}
|
||||
prestate, err := prestateTracer.GetResult()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get prestateTracer result: %w", err)
|
||||
}
|
||||
getTxResultTracerResultTimer.UpdateSince(tracerResultTimer)
|
||||
|
||||
env.ExecutionResults[index] = &types.ExecutionResult{
|
||||
|
|
@ -504,7 +508,6 @@ func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.B
|
|||
ReturnValue: fmt.Sprintf("%x", returnVal),
|
||||
StructLogs: vm.FormatLogs(structLogger.StructLogs()),
|
||||
CallTrace: callTrace,
|
||||
Prestate: prestate,
|
||||
}
|
||||
env.TxStorageTraces[index] = txStorageTrace
|
||||
|
||||
|
|
@ -579,6 +582,7 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro
|
|||
CodeSize: statedb.GetCodeSize(env.coinbase),
|
||||
},
|
||||
Header: block.Header(),
|
||||
Bytecodes: make([]*types.BytecodeTrace, 0, len(env.Codes)),
|
||||
StorageTrace: env.StorageTrace,
|
||||
ExecutionResults: env.ExecutionResults,
|
||||
TxStorageTraces: env.TxStorageTraces,
|
||||
|
|
@ -586,17 +590,19 @@ func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, erro
|
|||
StartL1QueueIndex: env.StartL1QueueIndex,
|
||||
}
|
||||
|
||||
for i, tx := range block.Transactions() {
|
||||
evmTrace := env.ExecutionResults[i]
|
||||
// Contract is created.
|
||||
if tx.To() == nil {
|
||||
evmTrace.ByteCode = hexutil.Encode(tx.Data())
|
||||
} else { // contract call be included at this case, specially fallback call's data is empty.
|
||||
evmTrace.ByteCode = hexutil.Encode(statedb.GetCode(*tx.To()))
|
||||
// Get tx.to address's code hash.
|
||||
codeHash := statedb.GetPoseidonCodeHash(*tx.To())
|
||||
evmTrace.PoseidonCodeHash = &codeHash
|
||||
}
|
||||
blockTrace.Bytecodes = append(blockTrace.Bytecodes, &types.BytecodeTrace{
|
||||
CodeSize: 0,
|
||||
KeccakCodeHash: codehash.EmptyKeccakCodeHash,
|
||||
PoseidonCodeHash: codehash.EmptyPoseidonCodeHash,
|
||||
Code: hexutil.Bytes{},
|
||||
})
|
||||
for _, codeInfo := range env.Codes {
|
||||
blockTrace.Bytecodes = append(blockTrace.Bytecodes, &types.BytecodeTrace{
|
||||
CodeSize: codeInfo.CodeSize,
|
||||
KeccakCodeHash: codeInfo.KeccakCodeHash,
|
||||
PoseidonCodeHash: codeInfo.PoseidonCodeHash,
|
||||
Code: codeInfo.Code,
|
||||
})
|
||||
}
|
||||
|
||||
blockTrace.WithdrawTrieRoot = withdrawtrie.ReadWTRSlot(rcfg.L2MessageQueueAddress, env.state)
|
||||
|
|
|
|||
Loading…
Reference in a new issue