Skip to content

Commit 0e1763f

Browse files
committed
Adapt value generation tracer to interface changes
1 parent a68363c commit 0e1763f

File tree

3 files changed

+72
-56
lines changed

3 files changed

+72
-56
lines changed

Diff for: fuzzing/executiontracer/execution_tracer.go

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66

77
"github.com/crytic/medusa/chain"
88
"github.com/crytic/medusa/fuzzing/contracts"
9-
"github.com/crytic/medusa/utils"
109
"github.com/ethereum/go-ethereum/common"
1110
"github.com/ethereum/go-ethereum/core"
1211
"github.com/ethereum/go-ethereum/core/state"

Diff for: fuzzing/fuzzer_worker.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ func (fw *FuzzerWorker) run(baseTestChain *chain.TestChain) (bool, error) {
578578
// execution and connect it to the chain
579579
if fw.fuzzer.config.Fuzzing.Testing.ExperimentalValueGenerationEnabled {
580580
fw.valueGenerationTracer = valuegenerationtracer.NewValueGenerationTracer(fw.fuzzer.contractDefinitions)
581-
initializedChain.AddTracer(fw.valueGenerationTracer, true, false)
581+
initializedChain.AddTracer(fw.valueGenerationTracer.NativeTracer(), true, false)
582582
}
583583
return nil
584584
})

Diff for: fuzzing/valuegenerationtracer/valuegeneration_tracer.go

+71-54
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package valuegenerationtracer
22

33
import (
4+
"github.com/crytic/medusa/chain"
45
"github.com/crytic/medusa/chain/types"
56
"github.com/crytic/medusa/compilation/abiutils"
67
"github.com/crytic/medusa/fuzzing/contracts"
78
"github.com/crytic/medusa/utils"
89
"github.com/ethereum/go-ethereum/accounts/abi"
910
"github.com/ethereum/go-ethereum/common"
1011
"github.com/ethereum/go-ethereum/core/state"
11-
coreTypes "github.com/ethereum/go-ethereum/core/types"
12+
"github.com/ethereum/go-ethereum/core/tracing"
13+
coretypes "github.com/ethereum/go-ethereum/core/types"
1214
"github.com/ethereum/go-ethereum/core/vm"
15+
"github.com/ethereum/go-ethereum/eth/tracers"
1316
"golang.org/x/exp/slices"
1417
"math/big"
1518
)
@@ -31,7 +34,7 @@ type ValueGenerationTrace struct {
3134

3235
type ValueGenerationTracer struct {
3336
// evm refers to the EVM instance last captured.
34-
evm *vm.EVM
37+
evmContext *tracing.VMContext
3538

3639
// trace represents the current execution trace captured by this tracer.
3740
trace *ValueGenerationTrace
@@ -47,39 +50,32 @@ type ValueGenerationTracer struct {
4750
// after some state is captured, on the next state capture (e.g. detecting a log instruction, but
4851
// using this structure to execute code later once the log is committed).
4952
onNextCaptureState []func()
53+
54+
// nativeTracer is the underlying tracer used to capture EVM execution.
55+
nativeTracer *chain.TestChainTracer
5056
}
5157

58+
// NativeTracer returns the underlying TestChainTracer.
59+
func (t *ValueGenerationTracer) NativeTracer() *chain.TestChainTracer {
60+
return t.nativeTracer
61+
}
5262
func NewValueGenerationTracer(contractDefinitions contracts.Contracts) *ValueGenerationTracer {
5363
tracer := &ValueGenerationTracer{
5464
contractDefinitions: contractDefinitions,
5565
}
56-
return tracer
57-
}
5866

59-
func (v *ValueGenerationTracer) CaptureTxStart(gasLimit uint64) {
60-
v.trace = newValueGenerationTrace(v.contractDefinitions)
61-
v.currentCallFrame = nil
62-
v.onNextCaptureState = nil
63-
}
64-
65-
func (v *ValueGenerationTracer) CaptureTxEnd(restGas uint64) {
66-
}
67-
68-
func (v *ValueGenerationTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
69-
v.evm = env
70-
v.captureEnteredCallFrame(from, to, input, create, value)
71-
}
72-
73-
func (v *ValueGenerationTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
74-
v.trace.transactionOutputValues = append(v.trace.transactionOutputValues, v.captureExitedCallFrame(output, err))
75-
}
76-
77-
func (v *ValueGenerationTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
78-
v.captureEnteredCallFrame(from, to, input, typ == vm.CREATE || typ == vm.CREATE2, value)
79-
}
80-
81-
func (v *ValueGenerationTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
82-
v.trace.transactionOutputValues = append(v.trace.transactionOutputValues, v.captureExitedCallFrame(output, err))
67+
innerTracer := &tracers.Tracer{
68+
Hooks: &tracing.Hooks{
69+
OnTxStart: tracer.OnTxStart,
70+
OnEnter: tracer.OnEnter,
71+
OnTxEnd: tracer.OnTxEnd,
72+
OnExit: tracer.OnExit,
73+
OnOpcode: tracer.OnOpcode,
74+
OnLog: tracer.OnLog,
75+
},
76+
}
77+
tracer.nativeTracer = &chain.TestChainTracer{Tracer: innerTracer, CaptureTxEndSetAdditionalResults: nil}
78+
return tracer
8379
}
8480

8581
func newValueGenerationTrace(contracts contracts.Contracts) *ValueGenerationTrace {
@@ -205,7 +201,7 @@ func (v *ValueGenerationTracer) captureExitedCallFrame(output []byte, err error)
205201
if v.currentCallFrame.ToRuntimeBytecode == nil {
206202
// As long as this isn't a failed contract creation, we should be able to fetch "to" byte code on exit.
207203
if !v.currentCallFrame.IsContractCreation() || err == nil {
208-
v.currentCallFrame.ToRuntimeBytecode = v.evm.StateDB.GetCode(v.currentCallFrame.ToAddress)
204+
v.currentCallFrame.ToRuntimeBytecode = v.evmContext.StateDB.GetCode(v.currentCallFrame.ToAddress)
209205
}
210206
}
211207
if v.currentCallFrame.CodeRuntimeBytecode == nil {
@@ -214,7 +210,7 @@ func (v *ValueGenerationTracer) captureExitedCallFrame(output []byte, err error)
214210
if v.currentCallFrame.CodeAddress == v.currentCallFrame.ToAddress {
215211
v.currentCallFrame.CodeRuntimeBytecode = v.currentCallFrame.ToRuntimeBytecode
216212
} else {
217-
v.currentCallFrame.CodeRuntimeBytecode = v.evm.StateDB.GetCode(v.currentCallFrame.CodeAddress)
213+
v.currentCallFrame.CodeRuntimeBytecode = v.evmContext.StateDB.GetCode(v.currentCallFrame.CodeAddress)
218214
}
219215
}
220216

@@ -237,28 +233,6 @@ func (v *ValueGenerationTracer) captureExitedCallFrame(output []byte, err error)
237233
return returnValue
238234
}
239235

240-
func (v *ValueGenerationTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
241-
// TODO: look for RET opcode (for now try getting them from currentCallFrame.ReturnData)
242-
// Execute all "on next capture state" events and clear them.
243-
for _, eventHandler := range v.onNextCaptureState {
244-
eventHandler()
245-
}
246-
v.onNextCaptureState = nil
247-
248-
// If a log operation occurred, add a deferred operation to capture it.
249-
if op == vm.LOG0 || op == vm.LOG1 || op == vm.LOG2 || op == vm.LOG3 || op == vm.LOG4 {
250-
v.onNextCaptureState = append(v.onNextCaptureState, func() {
251-
logs := v.evm.StateDB.(*state.StateDB).Logs()
252-
if len(logs) > 0 {
253-
v.currentCallFrame.Operations = append(v.currentCallFrame.Operations, logs[len(logs)-1])
254-
}
255-
})
256-
}
257-
}
258-
259-
func (v *ValueGenerationTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
260-
}
261-
262236
// CaptureTxEndSetAdditionalResults can be used to set additional results captured from execution tracing. If this
263237
// tracer is used during transaction execution (block creation), the results can later be queried from the block.
264238
// This method will only be called on the added tracer if it implements the extended TestChainTracer interface.
@@ -275,12 +249,55 @@ func (v *ValueGenerationTracer) CaptureTxEndSetAdditionalResults(results *types.
275249

276250
}
277251

252+
// OnTxStart is called upon the start of transaction execution, as defined by tracers.Tracer.
253+
func (t *ValueGenerationTracer) OnTxStart(vm *tracing.VMContext, tx *coretypes.Transaction, from common.Address) {
254+
t.trace = newValueGenerationTrace(t.contractDefinitions)
255+
t.currentCallFrame = nil
256+
t.onNextCaptureState = nil
257+
// Store our evm reference
258+
t.evmContext = vm
259+
}
260+
261+
func (t *ValueGenerationTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
262+
t.captureEnteredCallFrame(from, to, input, typ == byte(vm.CREATE) || typ == byte(vm.CREATE2), value)
263+
}
264+
265+
func (t *ValueGenerationTracer) OnTxEnd(receipt *coretypes.Receipt, err error) {
266+
267+
}
268+
269+
func (t *ValueGenerationTracer) OnExit(depth int, output []byte, used uint64, err error, reverted bool) {
270+
t.trace.transactionOutputValues = append(t.trace.transactionOutputValues, t.captureExitedCallFrame(output, err))
271+
}
272+
273+
func (t *ValueGenerationTracer) OnOpcode(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, data []byte, depth int, err error) {
274+
275+
// TODO: look for RET opcode (for now try getting them from currentCallFrame.ReturnData)
276+
// Execute all "on next capture state" events and clear them.
277+
for _, eventHandler := range t.onNextCaptureState {
278+
eventHandler()
279+
}
280+
t.onNextCaptureState = nil
281+
282+
}
283+
284+
func (t *ValueGenerationTracer) OnLog(log *coretypes.Log) {
285+
286+
// If a log operation occurred, add a deferred operation to capture it.
287+
t.onNextCaptureState = append(t.onNextCaptureState, func() {
288+
logs := t.evmContext.StateDB.(*state.StateDB).Logs()
289+
if len(logs) > 0 {
290+
t.currentCallFrame.Operations = append(t.currentCallFrame.Operations, logs[len(logs)-1])
291+
}
292+
})
293+
}
294+
278295
func (t *ValueGenerationTrace) generateEvents(currentCallFrame *utils.CallFrame, events []any) []any {
279296
for _, operation := range currentCallFrame.Operations {
280297
if childCallFrame, ok := operation.(*utils.CallFrame); ok {
281298
// If this is a call frame being entered, generate information recursively.
282299
t.generateEvents(childCallFrame, events)
283-
} else if eventLog, ok := operation.(*coreTypes.Log); ok {
300+
} else if eventLog, ok := operation.(*coretypes.Log); ok {
284301
// If an event log was emitted, add a message for it.
285302
events = append(events, t.getEventsGenerated(currentCallFrame, eventLog)...)
286303
//t.getEventsGenerated(currentCallFrame, eventLog)
@@ -290,7 +307,7 @@ func (t *ValueGenerationTrace) generateEvents(currentCallFrame *utils.CallFrame,
290307
return events
291308
}
292309

293-
func (t *ValueGenerationTrace) getEventsGenerated(callFrame *utils.CallFrame, eventLog *coreTypes.Log) []any {
310+
func (t *ValueGenerationTrace) getEventsGenerated(callFrame *utils.CallFrame, eventLog *coretypes.Log) []any {
294311
// Try to unpack our event data
295312
eventInputs := make([]any, 0)
296313
event, eventInputValues := abiutils.UnpackEventAndValues(callFrame.CodeContractAbi, eventLog)

0 commit comments

Comments
 (0)