Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
bd10a31d
Commit
bd10a31d
authored
Oct 12, 2021
by
George Hotz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
adding logger allows interpreter to be stock
parent
920aa20b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
348 additions
and
35 deletions
+348
-35
files_minigeth
files_minigeth
+2
-1
interpreter.go
minigeth/core/vm/interpreter.go
+2
-34
logger.go
minigeth/core/vm/logger.go
+344
-0
No files found.
files_minigeth
View file @
bd10a31d
...
...
@@ -43,8 +43,9 @@ core/vm/gas_table.go
core/vm/gas.go
core/vm/instructions.go
core/vm/interface.go
#
core/vm/interpreter.go
core/vm/interpreter.go
core/vm/jump_table.go
core/vm/logger.go
core/vm/memory_table.go
core/vm/memory.go
core/vm/opcodes.go
...
...
minigeth/core/vm/interpreter.go
View file @
bd10a31d
...
...
@@ -18,41 +18,13 @@ package vm
import
(
"hash"
"math/big"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
//
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
)
// **** stub Tracer ****
type
Tracer
interface
{
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
}
/*type StubTracer struct{}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func (jst *StubTracer) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
func (jst *StubTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
}
// CaptureFault implements the Tracer interface to trace an execution fault
func (jst *StubTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func (jst *StubTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
}*/
// Config are the configuration options for the Interpreter
type
Config
struct
{
Debug
bool
// Enables debugging
...
...
@@ -125,7 +97,7 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if
err
:=
EnableEIP
(
eip
,
&
jt
);
err
!=
nil
{
// Disable it, so caller can check if it's activated or not
cfg
.
ExtraEips
=
append
(
cfg
.
ExtraEips
[
:
i
],
cfg
.
ExtraEips
[
i
+
1
:
]
...
)
//
log.Error("EIP activation failed", "eip", eip, "error", err)
log
.
Error
(
"EIP activation failed"
,
"eip"
,
eip
,
"error"
,
err
)
}
}
cfg
.
JumpTable
=
jt
...
...
@@ -137,10 +109,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
}
}
func
(
in
*
EVMInterpreter
)
GetCfg
()
*
Config
{
return
&
in
.
cfg
}
// Run loops and evaluates the contract's code with the given input data and returns
// the return byte-slice and an error if one occurred.
//
...
...
minigeth/core/vm/logger.go
0 → 100644
View file @
bd10a31d
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
vm
import
(
"encoding/hex"
"fmt"
"io"
"math/big"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// Storage represents a contract's storage.
type
Storage
map
[
common
.
Hash
]
common
.
Hash
// Copy duplicates the current storage.
func
(
s
Storage
)
Copy
()
Storage
{
cpy
:=
make
(
Storage
)
for
key
,
value
:=
range
s
{
cpy
[
key
]
=
value
}
return
cpy
}
// LogConfig are the configuration options for structured logger the EVM
type
LogConfig
struct
{
DisableMemory
bool
// disable memory capture
DisableStack
bool
// disable stack capture
DisableStorage
bool
// disable storage capture
DisableReturnData
bool
// disable return data capture
Debug
bool
// print output during capture end
Limit
int
// maximum length of output, but zero means unlimited
// Chain overrides, can be used to execute a trace using future fork rules
Overrides
*
params
.
ChainConfig
`json:"overrides,omitempty"`
}
//go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
// StructLog is emitted to the EVM each cycle and lists information about the current internal state
// prior to the execution of the statement.
type
StructLog
struct
{
Pc
uint64
`json:"pc"`
Op
OpCode
`json:"op"`
Gas
uint64
`json:"gas"`
GasCost
uint64
`json:"gasCost"`
Memory
[]
byte
`json:"memory"`
MemorySize
int
`json:"memSize"`
Stack
[]
uint256
.
Int
`json:"stack"`
ReturnData
[]
byte
`json:"returnData"`
Storage
map
[
common
.
Hash
]
common
.
Hash
`json:"-"`
Depth
int
`json:"depth"`
RefundCounter
uint64
`json:"refund"`
Err
error
`json:"-"`
}
// overrides for gencodec
type
structLogMarshaling
struct
{
Gas
math
.
HexOrDecimal64
GasCost
math
.
HexOrDecimal64
Memory
hexutil
.
Bytes
ReturnData
hexutil
.
Bytes
OpName
string
`json:"opName"`
// adds call to OpName() in MarshalJSON
ErrorString
string
`json:"error"`
// adds call to ErrorString() in MarshalJSON
}
// OpName formats the operand name in a human-readable format.
func
(
s
*
StructLog
)
OpName
()
string
{
return
s
.
Op
.
String
()
}
// ErrorString formats the log's error as a string.
func
(
s
*
StructLog
)
ErrorString
()
string
{
if
s
.
Err
!=
nil
{
return
s
.
Err
.
Error
()
}
return
""
}
// Tracer is used to collect execution traces from an EVM transaction
// execution. CaptureState is called for each step of the VM with the
// current VM state.
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type
Tracer
interface
{
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
}
// StructLogger is an EVM state logger and implements Tracer.
//
// StructLogger can capture state based on the given Log configuration and also keeps
// a track record of modified storage which is used in reporting snapshots of the
// contract their storage.
type
StructLogger
struct
{
cfg
LogConfig
storage
map
[
common
.
Address
]
Storage
logs
[]
StructLog
output
[]
byte
err
error
}
// NewStructLogger returns a new logger
func
NewStructLogger
(
cfg
*
LogConfig
)
*
StructLogger
{
logger
:=
&
StructLogger
{
storage
:
make
(
map
[
common
.
Address
]
Storage
),
}
if
cfg
!=
nil
{
logger
.
cfg
=
*
cfg
}
return
logger
}
// Reset clears the data held by the logger.
func
(
l
*
StructLogger
)
Reset
()
{
l
.
storage
=
make
(
map
[
common
.
Address
]
Storage
)
l
.
output
=
make
([]
byte
,
0
)
l
.
logs
=
l
.
logs
[
:
0
]
l
.
err
=
nil
}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func
(
l
*
StructLogger
)
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
}
// CaptureState logs a new structured log message and pushes it out to the environment
//
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
func
(
l
*
StructLogger
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
{
memory
:=
scope
.
Memory
stack
:=
scope
.
Stack
contract
:=
scope
.
Contract
// check if already accumulated the specified number of logs
if
l
.
cfg
.
Limit
!=
0
&&
l
.
cfg
.
Limit
<=
len
(
l
.
logs
)
{
return
}
// Copy a snapshot of the current memory state to a new buffer
var
mem
[]
byte
if
!
l
.
cfg
.
DisableMemory
{
mem
=
make
([]
byte
,
len
(
memory
.
Data
()))
copy
(
mem
,
memory
.
Data
())
}
// Copy a snapshot of the current stack state to a new buffer
var
stck
[]
uint256
.
Int
if
!
l
.
cfg
.
DisableStack
{
stck
=
make
([]
uint256
.
Int
,
len
(
stack
.
Data
()))
for
i
,
item
:=
range
stack
.
Data
()
{
stck
[
i
]
=
item
}
}
// Copy a snapshot of the current storage to a new container
var
storage
Storage
if
!
l
.
cfg
.
DisableStorage
&&
(
op
==
SLOAD
||
op
==
SSTORE
)
{
// initialise new changed values storage container for this contract
// if not present.
if
l
.
storage
[
contract
.
Address
()]
==
nil
{
l
.
storage
[
contract
.
Address
()]
=
make
(
Storage
)
}
// capture SLOAD opcodes and record the read entry in the local storage
if
op
==
SLOAD
&&
stack
.
len
()
>=
1
{
var
(
address
=
common
.
Hash
(
stack
.
data
[
stack
.
len
()
-
1
]
.
Bytes32
())
value
=
env
.
StateDB
.
GetState
(
contract
.
Address
(),
address
)
)
l
.
storage
[
contract
.
Address
()][
address
]
=
value
storage
=
l
.
storage
[
contract
.
Address
()]
.
Copy
()
}
else
if
op
==
SSTORE
&&
stack
.
len
()
>=
2
{
// capture SSTORE opcodes and record the written entry in the local storage.
var
(
value
=
common
.
Hash
(
stack
.
data
[
stack
.
len
()
-
2
]
.
Bytes32
())
address
=
common
.
Hash
(
stack
.
data
[
stack
.
len
()
-
1
]
.
Bytes32
())
)
l
.
storage
[
contract
.
Address
()][
address
]
=
value
storage
=
l
.
storage
[
contract
.
Address
()]
.
Copy
()
}
}
var
rdata
[]
byte
if
!
l
.
cfg
.
DisableReturnData
{
rdata
=
make
([]
byte
,
len
(
rData
))
copy
(
rdata
,
rData
)
}
// create a new snapshot of the EVM.
log
:=
StructLog
{
pc
,
op
,
gas
,
cost
,
mem
,
memory
.
Len
(),
stck
,
rdata
,
storage
,
depth
,
env
.
StateDB
.
GetRefund
(),
err
}
l
.
logs
=
append
(
l
.
logs
,
log
)
}
// CaptureFault implements the Tracer interface to trace an execution fault
// while running an opcode.
func
(
l
*
StructLogger
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
{
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func
(
l
*
StructLogger
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
{
l
.
output
=
output
l
.
err
=
err
if
l
.
cfg
.
Debug
{
fmt
.
Printf
(
"0x%x
\n
"
,
output
)
if
err
!=
nil
{
fmt
.
Printf
(
" error: %v
\n
"
,
err
)
}
}
}
// StructLogs returns the captured log entries.
func
(
l
*
StructLogger
)
StructLogs
()
[]
StructLog
{
return
l
.
logs
}
// Error returns the VM error captured by the trace.
func
(
l
*
StructLogger
)
Error
()
error
{
return
l
.
err
}
// Output returns the VM return value captured by the trace.
func
(
l
*
StructLogger
)
Output
()
[]
byte
{
return
l
.
output
}
// WriteTrace writes a formatted trace to the given writer
func
WriteTrace
(
writer
io
.
Writer
,
logs
[]
StructLog
)
{
for
_
,
log
:=
range
logs
{
fmt
.
Fprintf
(
writer
,
"%-16spc=%08d gas=%v cost=%v"
,
log
.
Op
,
log
.
Pc
,
log
.
Gas
,
log
.
GasCost
)
if
log
.
Err
!=
nil
{
fmt
.
Fprintf
(
writer
,
" ERROR: %v"
,
log
.
Err
)
}
fmt
.
Fprintln
(
writer
)
if
len
(
log
.
Stack
)
>
0
{
fmt
.
Fprintln
(
writer
,
"Stack:"
)
for
i
:=
len
(
log
.
Stack
)
-
1
;
i
>=
0
;
i
--
{
fmt
.
Fprintf
(
writer
,
"%08d %s
\n
"
,
len
(
log
.
Stack
)
-
i
-
1
,
log
.
Stack
[
i
]
.
Hex
())
}
}
if
len
(
log
.
Memory
)
>
0
{
fmt
.
Fprintln
(
writer
,
"Memory:"
)
fmt
.
Fprint
(
writer
,
hex
.
Dump
(
log
.
Memory
))
}
if
len
(
log
.
Storage
)
>
0
{
fmt
.
Fprintln
(
writer
,
"Storage:"
)
for
h
,
item
:=
range
log
.
Storage
{
fmt
.
Fprintf
(
writer
,
"%x: %x
\n
"
,
h
,
item
)
}
}
if
len
(
log
.
ReturnData
)
>
0
{
fmt
.
Fprintln
(
writer
,
"ReturnData:"
)
fmt
.
Fprint
(
writer
,
hex
.
Dump
(
log
.
ReturnData
))
}
fmt
.
Fprintln
(
writer
)
}
}
// WriteLogs writes vm logs in a readable format to the given writer
func
WriteLogs
(
writer
io
.
Writer
,
logs
[]
*
types
.
Log
)
{
for
_
,
log
:=
range
logs
{
fmt
.
Fprintf
(
writer
,
"LOG%d: %x bn=%d txi=%x
\n
"
,
len
(
log
.
Topics
),
log
.
Address
,
log
.
BlockNumber
,
log
.
TxIndex
)
for
i
,
topic
:=
range
log
.
Topics
{
fmt
.
Fprintf
(
writer
,
"%08d %x
\n
"
,
i
,
topic
)
}
fmt
.
Fprint
(
writer
,
hex
.
Dump
(
log
.
Data
))
fmt
.
Fprintln
(
writer
)
}
}
type
mdLogger
struct
{
out
io
.
Writer
cfg
*
LogConfig
}
// NewMarkdownLogger creates a logger which outputs information in a format adapted
// for human readability, and is also a valid markdown table
func
NewMarkdownLogger
(
cfg
*
LogConfig
,
writer
io
.
Writer
)
*
mdLogger
{
l
:=
&
mdLogger
{
writer
,
cfg
}
if
l
.
cfg
==
nil
{
l
.
cfg
=
&
LogConfig
{}
}
return
l
}
func
(
t
*
mdLogger
)
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
if
!
create
{
fmt
.
Fprintf
(
t
.
out
,
"From: `%v`
\n
To: `%v`
\n
Data: `0x%x`
\n
Gas: `%d`
\n
Value `%v` wei
\n
"
,
from
.
String
(),
to
.
String
(),
input
,
gas
,
value
)
}
else
{
fmt
.
Fprintf
(
t
.
out
,
"From: `%v`
\n
Create at: `%v`
\n
Data: `0x%x`
\n
Gas: `%d`
\n
Value `%v` wei
\n
"
,
from
.
String
(),
to
.
String
(),
input
,
gas
,
value
)
}
fmt
.
Fprintf
(
t
.
out
,
`
| Pc | Op | Cost | Stack | RStack | Refund |
|-------|-------------|------|-----------|-----------|---------|
`
)
}
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
func
(
t
*
mdLogger
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
{
stack
:=
scope
.
Stack
fmt
.
Fprintf
(
t
.
out
,
"| %4d | %10v | %3d |"
,
pc
,
op
,
cost
)
if
!
t
.
cfg
.
DisableStack
{
// format stack
var
a
[]
string
for
_
,
elem
:=
range
stack
.
data
{
a
=
append
(
a
,
elem
.
Hex
())
}
b
:=
fmt
.
Sprintf
(
"[%v]"
,
strings
.
Join
(
a
,
","
))
fmt
.
Fprintf
(
t
.
out
,
"%10v |"
,
b
)
}
fmt
.
Fprintf
(
t
.
out
,
"%10v |"
,
env
.
StateDB
.
GetRefund
())
fmt
.
Fprintln
(
t
.
out
,
""
)
if
err
!=
nil
{
fmt
.
Fprintf
(
t
.
out
,
"Error: %v
\n
"
,
err
)
}
}
func
(
t
*
mdLogger
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
{
fmt
.
Fprintf
(
t
.
out
,
"
\n
Error: at pc=%d, op=%v: %v
\n
"
,
pc
,
op
,
err
)
}
func
(
t
*
mdLogger
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
tm
time
.
Duration
,
err
error
)
{
fmt
.
Fprintf
(
t
.
out
,
"
\n
Output: `0x%x`
\n
Consumed gas: `%d`
\n
Error: `%v`
\n
"
,
output
,
gasUsed
,
err
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment