Skip to content
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

feat: support cancun fork #397

Merged
merged 15 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version: "^1.18.1"
go-version: "^1.22"
# disable caching during release (tag) builds
cache: ${{ !startsWith(github.ref, 'refs/tags/') }}

Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version: "^1.18.1"
go-version: "^1.22"

- name: Actionlint
run: |
Expand Down Expand Up @@ -197,7 +197,7 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version: "^1.18.1"
go-version: "^1.22"

- uses: actions/setup-node@v4
with:
Expand Down
130 changes: 64 additions & 66 deletions chain/cheat_code_tracer.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package chain

import (
"math/big"

"github.com/crytic/medusa/chain/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing"
coretypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"math/big"
"github.com/ethereum/go-ethereum/eth/tracers"
)

// cheatCodeTracer represents an EVM.Logger which tracks and patches EVM execution state to enable extended
Expand All @@ -18,13 +22,15 @@ type cheatCodeTracer struct {
callDepth uint64

// evm refers to the EVM instance last captured.
evm *vm.EVM
evmContext *tracing.VMContext

// callFrames represents per-call-frame data deployment information being captured by the tracer.
callFrames []*cheatCodeTracerCallFrame

// results stores the tracer output after a transaction has concluded.
results *cheatCodeTracerResults

nativeTracer *TestChainTracer
}

// cheatCodeTracerCallFrame represents per-call-frame data traced by a cheatCodeTracer.
Expand Down Expand Up @@ -57,7 +63,7 @@ type cheatCodeTracerCallFrame struct {
// vmOp describes the current call frame's last instruction executed.
vmOp vm.OpCode
// vmScope describes the current call frame's scope context.
vmScope *vm.ScopeContext
vmScope tracing.OpContext
// vmReturnData describes the current call frame's return data (set on exit).
vmReturnData []byte
// vmErr describes the current call frame's returned error (set on exit), nil if no error.
Expand All @@ -72,9 +78,25 @@ type cheatCodeTracerResults struct {
// newCheatCodeTracer creates a cheatCodeTracer and returns it.
func newCheatCodeTracer() *cheatCodeTracer {
tracer := &cheatCodeTracer{}
innerTracer := &tracers.Tracer{
Hooks: &tracing.Hooks{
OnTxStart: tracer.OnTxStart,
OnTxEnd: tracer.OnTxEnd,
OnEnter: tracer.OnEnter,
OnExit: tracer.OnExit,
OnOpcode: tracer.OnOpcode,
},
}
tracer.nativeTracer = &TestChainTracer{Tracer: innerTracer, CaptureTxEndSetAdditionalResults: tracer.CaptureTxEndSetAdditionalResults}

return tracer
}

// NativeTracer returns the underlying TestChainTracer.
func (t *cheatCodeTracer) NativeTracer() *TestChainTracer {
return t.nativeTracer
}

// bindToChain is called by the TestChain which created the tracer to set its reference.
// Note: This is done because of the cheat code system's dependency on the genesis block, as well as chain's dependency
// on it, which prevents the chain being set in the tracer on initialization.
Expand All @@ -84,7 +106,7 @@ func (t *cheatCodeTracer) bindToChain(chain *TestChain) {

// PreviousCallFrame returns the previous call frame of the current EVM execution, or nil if there is no previous.
func (t *cheatCodeTracer) PreviousCallFrame() *cheatCodeTracerCallFrame {
if len(t.callFrames) < 2 {
if len(t.callFrames) < 1 {
0xalpharush marked this conversation as resolved.
Show resolved Hide resolved
return nil
}
return t.callFrames[t.callDepth-1]
Expand All @@ -98,82 +120,63 @@ func (t *cheatCodeTracer) CurrentCallFrame() *cheatCodeTracerCallFrame {
return t.callFrames[t.callDepth]
}

// CaptureTxStart is called upon the start of transaction execution, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureTxStart(gasLimit uint64) {
// OnTxStart is called upon the start of transaction execution, as defined by tracers.Tracer.
func (t *cheatCodeTracer) OnTxStart(vm *tracing.VMContext, tx *coretypes.Transaction, from common.Address) {
// Reset our capture state
t.callDepth = 0
t.callFrames = make([]*cheatCodeTracerCallFrame, 0)
t.results = &cheatCodeTracerResults{
onChainRevertHooks: nil,
}
}

// CaptureTxEnd is called upon the end of transaction execution, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureTxEnd(restGas uint64) {

}

// CaptureStart initializes the tracing operation for the top of a call frame, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
// Store our evm reference
t.evm = env

// Create our call frame struct to track data for this initial entry call frame.
callFrameData := &cheatCodeTracerCallFrame{}
t.callFrames = append(t.callFrames, callFrameData)
t.evmContext = vm
}
func (t *cheatCodeTracer) OnTxEnd(*coretypes.Receipt, error) {
// Execute our top frame exit hooks.
t.callFrames[0].onTopFrameExitRestoreHooks.Execute(false, true)
}

// CaptureEnd is called after a call to finalize tracing completes for the top of a call frame, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
// Execute all current call frame exit hooks
exitingCallFrame := t.callFrames[t.callDepth]
exitingCallFrame.onFrameExitRestoreHooks.Execute(false, true)
exitingCallFrame.onTopFrameExitRestoreHooks.Execute(false, true)
anishnaik marked this conversation as resolved.
Show resolved Hide resolved
// OnEnter initializes the tracing operation for the top of a call frame, as defined by tracers.Tracer.
func (t *cheatCodeTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {

// If we didn't encounter an error in this call frame, we push our upward propagating revert events up one frame.
if err == nil {
// Store these revert hooks in our results.
t.results.onChainRevertHooks = append(t.results.onChainRevertHooks, exitingCallFrame.onChainRevertRestoreHooks...)
isTopLevelFrame := depth == 0
var callFrameData *cheatCodeTracerCallFrame
if isTopLevelFrame {
// Create our call frame struct to track data for this initial entry call frame.
callFrameData = &cheatCodeTracerCallFrame{}
} else {
// We hit an error, so a revert occurred before this tx was committed.
exitingCallFrame.onChainRevertRestoreHooks.Execute(false, true)
// Create our call frame struct to track data for this initial entry call frame.
// We forward our "next frame hooks" to this frame, then clear them from the previous frame.
previousCallFrame := t.CurrentCallFrame()
callFrameData = &cheatCodeTracerCallFrame{
onFrameExitRestoreHooks: previousCallFrame.onNextFrameExitRestoreHooks,
}
previousCallFrame.onNextFrameExitRestoreHooks = nil
// Increase our call depth now that we're entering a new call frame.
t.callDepth++
}

// We're exiting the current frame, so remove our frame data.
t.callFrames = t.callFrames[:t.callDepth]
}

// CaptureEnter is called upon entering of the call frame, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
// We haven't updated our call depth yet, so obtain the "previous" call frame (current for now)
previousCallFrame := t.CurrentCallFrame()

// Increase our call depth now that we're entering a new call frame.
t.callDepth++

// Create our call frame struct to track data for this initial entry call frame.
// We forward our "next frame hooks" to this frame, then clear them from the previous frame.
callFrameData := &cheatCodeTracerCallFrame{
onFrameExitRestoreHooks: previousCallFrame.onNextFrameExitRestoreHooks,
}
previousCallFrame.onNextFrameExitRestoreHooks = nil
t.callFrames = append(t.callFrames, callFrameData)

// Note: We do not execute events for "next frame enter" here, as we do not yet have scope information.
// Those events are executed when the first EVM instruction is executed in the new scope.
}

// CaptureExit is called upon exiting of the call frame, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
// Execute all current call frame exit hooks
// OnExit is called after a call to finalize tracing completes for the top of a call frame, as defined by tracers.Tracer.
func (t *cheatCodeTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
// Top level does not have a parent.
if depth == 0 {
return
}
// Execute frame exit hooks for children.
exitingCallFrame := t.callFrames[t.callDepth]
exitingCallFrame.onFrameExitRestoreHooks.Execute(false, true)

parentCallFrame := t.callFrames[t.callDepth-1]
parentCallFrame.onTopFrameExitRestoreHooks = append(parentCallFrame.onTopFrameExitRestoreHooks, exitingCallFrame.onTopFrameExitRestoreHooks...)

// If we didn't encounter an error in this call frame, we push our upward propagating revert events up one frame.
if err == nil {
parentCallFrame.onTopFrameExitRestoreHooks = append(parentCallFrame.onTopFrameExitRestoreHooks, exitingCallFrame.onTopFrameExitRestoreHooks...)
parentCallFrame.onChainRevertRestoreHooks = append(parentCallFrame.onChainRevertRestoreHooks, exitingCallFrame.onChainRevertRestoreHooks...)
0xalpharush marked this conversation as resolved.
Show resolved Hide resolved
// Store these revert hooks in our results.
t.results.onChainRevertHooks = append(t.results.onChainRevertHooks, exitingCallFrame.onChainRevertRestoreHooks...)
} else {
// We hit an error, so a revert occurred before this tx was committed.
exitingCallFrame.onChainRevertRestoreHooks.Execute(false, true)
Expand All @@ -186,27 +189,22 @@ func (t *cheatCodeTracer) CaptureExit(output []byte, gasUsed uint64, err error)
t.callDepth--
}

// CaptureState records data from an EVM state update, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, vmErr error) {
// OnOpcode records data from an EVM state update, as defined by tracers.Tracer.
func (t *cheatCodeTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
// Set our current frame information.
currentCallFrame := t.CurrentCallFrame()
currentCallFrame.vmPc = pc
currentCallFrame.vmOp = op
currentCallFrame.vmOp = vm.OpCode(op)
currentCallFrame.vmScope = scope
currentCallFrame.vmReturnData = rData
currentCallFrame.vmErr = vmErr
currentCallFrame.vmErr = err

// We execute our entered next frame hooks here (from our previous call frame), as we now have scope information.
if t.callDepth > 0 {
t.callFrames[t.callDepth-1].onNextFrameEnterHooks.Execute(true, true)
}
}

// CaptureFault records an execution fault, as defined by vm.EVMLogger.
func (t *cheatCodeTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {

}

// CaptureTxEndSetAdditionalResults can be used to set additional results captured from execution tracing. If this
// tracer is used during transaction execution (block creation), the results can later be queried from the block.
// This method will only be called on the added tracer if it implements the extended TestChainTracer interface.
Expand Down
3 changes: 2 additions & 1 deletion chain/console_log_cheat_code_contract.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package chain

import (
"strconv"

"github.com/crytic/medusa/utils"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"strconv"
)

// ConsoleLogContractAddress is the address for the console.log precompile contract
Expand Down
Loading
Loading