core, core/vm: added structure logging
This also reduces the time required spend in the VM
This commit is contained in:
parent
ff5b3ef087
commit
38c61f6f25
|
@ -223,6 +223,10 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
|
||||||
return nil, nil, InvalidTxError(err)
|
return nil, nil, InvalidTxError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if vm.Debug {
|
||||||
|
VmStdErrFormat(vmenv.StructLogs())
|
||||||
|
}
|
||||||
|
|
||||||
self.refundGas()
|
self.refundGas()
|
||||||
self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ type Environment interface {
|
||||||
GasLimit() *big.Int
|
GasLimit() *big.Int
|
||||||
Transfer(from, to Account, amount *big.Int) error
|
Transfer(from, to Account, amount *big.Int) error
|
||||||
AddLog(*state.Log)
|
AddLog(*state.Log)
|
||||||
|
AddStructLog(StructLog)
|
||||||
|
StructLogs() []StructLog
|
||||||
|
|
||||||
VmType() Type
|
VmType() Type
|
||||||
|
|
||||||
|
@ -31,6 +33,14 @@ type Environment interface {
|
||||||
Create(me ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef)
|
Create(me ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, ContextRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StructLog struct {
|
||||||
|
Pc uint64
|
||||||
|
Op OpCode
|
||||||
|
Gas *big.Int
|
||||||
|
Memory []byte
|
||||||
|
Stack []*big.Int
|
||||||
|
}
|
||||||
|
|
||||||
type Account interface {
|
type Account interface {
|
||||||
SubBalance(amount *big.Int)
|
SubBalance(amount *big.Int)
|
||||||
AddBalance(amount *big.Int)
|
AddBalance(amount *big.Int)
|
||||||
|
|
|
@ -21,7 +21,7 @@ var (
|
||||||
GasContractByte = big.NewInt(200)
|
GasContractByte = big.NewInt(200)
|
||||||
)
|
)
|
||||||
|
|
||||||
func baseCheck(op OpCode, stack *stack, gas *big.Int) error {
|
func baseCheck(op OpCode, stack *Stack, gas *big.Int) error {
|
||||||
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
|
||||||
// PUSH is also allowed to calculate the same price for all PUSHes
|
// PUSH is also allowed to calculate the same price for all PUSHes
|
||||||
// DUP requirements are handled elsewhere (except for the stack limit check)
|
// DUP requirements are handled elsewhere (except for the stack limit check)
|
||||||
|
|
|
@ -5,16 +5,20 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newStack() *stack {
|
func newStack() *Stack {
|
||||||
return &stack{}
|
return &Stack{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stack struct {
|
type Stack struct {
|
||||||
data []*big.Int
|
data []*big.Int
|
||||||
ptr int
|
ptr int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) push(d *big.Int) {
|
func (st *Stack) Data() []*big.Int {
|
||||||
|
return st.data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *Stack) push(d *big.Int) {
|
||||||
// NOTE push limit (1024) is checked in baseCheck
|
// NOTE push limit (1024) is checked in baseCheck
|
||||||
stackItem := new(big.Int).Set(d)
|
stackItem := new(big.Int).Set(d)
|
||||||
if len(st.data) > st.ptr {
|
if len(st.data) > st.ptr {
|
||||||
|
@ -25,36 +29,36 @@ func (st *stack) push(d *big.Int) {
|
||||||
st.ptr++
|
st.ptr++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) pop() (ret *big.Int) {
|
func (st *Stack) pop() (ret *big.Int) {
|
||||||
st.ptr--
|
st.ptr--
|
||||||
ret = st.data[st.ptr]
|
ret = st.data[st.ptr]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) len() int {
|
func (st *Stack) len() int {
|
||||||
return st.ptr
|
return st.ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) swap(n int) {
|
func (st *Stack) swap(n int) {
|
||||||
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
|
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) dup(n int) {
|
func (st *Stack) dup(n int) {
|
||||||
st.push(st.data[st.len()-n])
|
st.push(st.data[st.len()-n])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) peek() *big.Int {
|
func (st *Stack) peek() *big.Int {
|
||||||
return st.data[st.len()-1]
|
return st.data[st.len()-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) require(n int) error {
|
func (st *Stack) require(n int) error {
|
||||||
if st.len() < n {
|
if st.len() < n {
|
||||||
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
|
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *stack) Print() {
|
func (st *Stack) Print() {
|
||||||
fmt.Println("### stack ###")
|
fmt.Println("### stack ###")
|
||||||
if len(st.data) > 0 {
|
if len(st.data) > 0 {
|
||||||
for i, val := range st.data {
|
for i, val := range st.data {
|
||||||
|
|
|
@ -3,6 +3,4 @@ package vm
|
||||||
type VirtualMachine interface {
|
type VirtualMachine interface {
|
||||||
Env() Environment
|
Env() Environment
|
||||||
Run(context *Context, data []byte) ([]byte, error)
|
Run(context *Context, data []byte) ([]byte, error)
|
||||||
Printf(string, ...interface{}) VirtualMachine
|
|
||||||
Endl() VirtualMachine
|
|
||||||
}
|
}
|
||||||
|
|
147
core/vm/vm.go
147
core/vm/vm.go
|
@ -7,24 +7,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
type log struct {
|
|
||||||
op OpCode
|
|
||||||
gas *big.Int
|
|
||||||
memory []byte
|
|
||||||
stack []*big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
env Environment
|
env Environment
|
||||||
|
|
||||||
// structured logging
|
|
||||||
Logs []log
|
|
||||||
logStr string
|
|
||||||
|
|
||||||
err error
|
err error
|
||||||
// For logging
|
// For logging
|
||||||
debug bool
|
debug bool
|
||||||
|
@ -40,7 +28,7 @@ type Vm struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(env Environment) *Vm {
|
func New(env Environment) *Vm {
|
||||||
return &Vm{env: env, Recoverable: true}
|
return &Vm{env: env, debug: Debug, Recoverable: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
@ -54,8 +42,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
price = context.Price
|
price = context.Price
|
||||||
)
|
)
|
||||||
|
|
||||||
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
|
|
||||||
|
|
||||||
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
|
||||||
defer func() {
|
defer func() {
|
||||||
if self.After != nil {
|
if self.After != nil {
|
||||||
|
@ -63,7 +49,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Printf(" %v", err).Endl()
|
|
||||||
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
|
||||||
context.UseGas(context.Gas)
|
context.UseGas(context.Gas)
|
||||||
|
|
||||||
|
@ -96,11 +82,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
|
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" ~> %v", to)
|
|
||||||
pc = to.Uint64()
|
pc = to.Uint64()
|
||||||
|
|
||||||
self.Endl()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -112,18 +95,14 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
// Get the memory location of pc
|
// Get the memory location of pc
|
||||||
op = context.GetOp(pc)
|
op = context.GetOp(pc)
|
||||||
|
|
||||||
self.Log(op, context.Gas, mem, stack)
|
self.log(pc, op, context.Gas, mem, stack)
|
||||||
|
|
||||||
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
|
|
||||||
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
|
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf("(g) %-3v (%v)", gas, context.Gas)
|
|
||||||
|
|
||||||
if !context.UseGas(gas) {
|
if !context.UseGas(gas) {
|
||||||
self.Endl()
|
|
||||||
|
|
||||||
tmp := new(big.Int).Set(context.Gas)
|
tmp := new(big.Int).Set(context.Gas)
|
||||||
|
|
||||||
|
@ -137,40 +116,33 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
switch op {
|
switch op {
|
||||||
case ADD:
|
case ADD:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v + %v", y, x)
|
|
||||||
|
|
||||||
base.Add(x, y)
|
base.Add(x, y)
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
// pop result back on the stack
|
// pop result back on the stack
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case SUB:
|
case SUB:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v - %v", x, y)
|
|
||||||
|
|
||||||
base.Sub(x, y)
|
base.Sub(x, y)
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
// pop result back on the stack
|
// pop result back on the stack
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case MUL:
|
case MUL:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v * %v", y, x)
|
|
||||||
|
|
||||||
base.Mul(x, y)
|
base.Mul(x, y)
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
// pop result back on the stack
|
// pop result back on the stack
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case DIV:
|
case DIV:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v / %v", x, y)
|
|
||||||
|
|
||||||
if y.Cmp(common.Big0) != 0 {
|
if y.Cmp(common.Big0) != 0 {
|
||||||
base.Div(x, y)
|
base.Div(x, y)
|
||||||
|
@ -178,14 +150,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
// pop result back on the stack
|
// pop result back on the stack
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case SDIV:
|
case SDIV:
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
|
|
||||||
self.Printf(" %v / %v", x, y)
|
|
||||||
|
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
base.Set(common.Big0)
|
base.Set(common.Big0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,13 +170,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
U256(base)
|
U256(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case MOD:
|
case MOD:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
|
|
||||||
self.Printf(" %v %% %v", x, y)
|
|
||||||
|
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
base.Set(common.Big0)
|
base.Set(common.Big0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,13 +182,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case SMOD:
|
case SMOD:
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
|
|
||||||
self.Printf(" %v %% %v", x, y)
|
|
||||||
|
|
||||||
if y.Cmp(common.Big0) == 0 {
|
if y.Cmp(common.Big0) == 0 {
|
||||||
base.Set(common.Big0)
|
base.Set(common.Big0)
|
||||||
} else {
|
} else {
|
||||||
|
@ -238,20 +201,15 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
U256(base)
|
U256(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
|
|
||||||
case EXP:
|
case EXP:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
|
|
||||||
self.Printf(" %v ** %v", x, y)
|
|
||||||
|
|
||||||
base.Exp(x, y, Pow256)
|
base.Exp(x, y, Pow256)
|
||||||
|
|
||||||
U256(base)
|
U256(base)
|
||||||
|
|
||||||
self.Printf(" = %v", base)
|
|
||||||
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case SIGNEXTEND:
|
case SIGNEXTEND:
|
||||||
back := stack.pop()
|
back := stack.pop()
|
||||||
|
@ -268,15 +226,13 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
num = U256(num)
|
num = U256(num)
|
||||||
|
|
||||||
self.Printf(" = %v", num)
|
|
||||||
|
|
||||||
stack.push(num)
|
stack.push(num)
|
||||||
}
|
}
|
||||||
case NOT:
|
case NOT:
|
||||||
stack.push(U256(new(big.Int).Not(stack.pop())))
|
stack.push(U256(new(big.Int).Not(stack.pop())))
|
||||||
case LT:
|
case LT:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v < %v", x, y)
|
|
||||||
// x < y
|
// x < y
|
||||||
if x.Cmp(y) < 0 {
|
if x.Cmp(y) < 0 {
|
||||||
stack.push(common.BigTrue)
|
stack.push(common.BigTrue)
|
||||||
|
@ -285,7 +241,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
case GT:
|
case GT:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v > %v", x, y)
|
|
||||||
|
|
||||||
// x > y
|
// x > y
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
|
@ -296,7 +251,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
case SLT:
|
case SLT:
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
self.Printf(" %v < %v", x, y)
|
|
||||||
// x < y
|
// x < y
|
||||||
if x.Cmp(S256(y)) < 0 {
|
if x.Cmp(S256(y)) < 0 {
|
||||||
stack.push(common.BigTrue)
|
stack.push(common.BigTrue)
|
||||||
|
@ -305,7 +260,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
}
|
}
|
||||||
case SGT:
|
case SGT:
|
||||||
x, y := S256(stack.pop()), S256(stack.pop())
|
x, y := S256(stack.pop()), S256(stack.pop())
|
||||||
self.Printf(" %v > %v", x, y)
|
|
||||||
|
|
||||||
// x > y
|
// x > y
|
||||||
if x.Cmp(y) > 0 {
|
if x.Cmp(y) > 0 {
|
||||||
|
@ -316,7 +270,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
case EQ:
|
case EQ:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v == %v", y, x)
|
|
||||||
|
|
||||||
// x == y
|
// x == y
|
||||||
if x.Cmp(y) == 0 {
|
if x.Cmp(y) == 0 {
|
||||||
|
@ -334,17 +287,14 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
case AND:
|
case AND:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v & %v", y, x)
|
|
||||||
|
|
||||||
stack.push(base.And(x, y))
|
stack.push(base.And(x, y))
|
||||||
case OR:
|
case OR:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v | %v", x, y)
|
|
||||||
|
|
||||||
stack.push(base.Or(x, y))
|
stack.push(base.Or(x, y))
|
||||||
case XOR:
|
case XOR:
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.pop()
|
||||||
self.Printf(" %v ^ %v", x, y)
|
|
||||||
|
|
||||||
stack.push(base.Xor(x, y))
|
stack.push(base.Xor(x, y))
|
||||||
case BYTE:
|
case BYTE:
|
||||||
|
@ -358,8 +308,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
base.Set(common.BigFalse)
|
base.Set(common.BigFalse)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" => 0x%x", base.Bytes())
|
|
||||||
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case ADDMOD:
|
case ADDMOD:
|
||||||
x := stack.pop()
|
x := stack.pop()
|
||||||
|
@ -373,8 +321,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
base = U256(base)
|
base = U256(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
|
|
||||||
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
case MULMOD:
|
case MULMOD:
|
||||||
x := stack.pop()
|
x := stack.pop()
|
||||||
|
@ -388,8 +334,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
U256(base)
|
U256(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
|
|
||||||
|
|
||||||
stack.push(base)
|
stack.push(base)
|
||||||
|
|
||||||
case SHA3:
|
case SHA3:
|
||||||
|
@ -398,44 +342,35 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
stack.push(common.BigD(data))
|
stack.push(common.BigD(data))
|
||||||
|
|
||||||
self.Printf(" => (%v) %x", size, data)
|
|
||||||
case ADDRESS:
|
case ADDRESS:
|
||||||
stack.push(common.Bytes2Big(context.Address().Bytes()))
|
stack.push(common.Bytes2Big(context.Address().Bytes()))
|
||||||
|
|
||||||
self.Printf(" => %x", context.Address())
|
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
addr := common.BigToAddress(stack.pop())
|
addr := common.BigToAddress(stack.pop())
|
||||||
balance := statedb.GetBalance(addr)
|
balance := statedb.GetBalance(addr)
|
||||||
|
|
||||||
stack.push(balance)
|
stack.push(balance)
|
||||||
|
|
||||||
self.Printf(" => %v (%x)", balance, addr)
|
|
||||||
case ORIGIN:
|
case ORIGIN:
|
||||||
origin := self.env.Origin()
|
origin := self.env.Origin()
|
||||||
|
|
||||||
stack.push(origin.Big())
|
stack.push(origin.Big())
|
||||||
|
|
||||||
self.Printf(" => %x", origin)
|
|
||||||
case CALLER:
|
case CALLER:
|
||||||
caller := context.caller.Address()
|
caller := context.caller.Address()
|
||||||
stack.push(common.Bytes2Big(caller.Bytes()))
|
stack.push(common.Bytes2Big(caller.Bytes()))
|
||||||
|
|
||||||
self.Printf(" => %x", caller)
|
|
||||||
case CALLVALUE:
|
case CALLVALUE:
|
||||||
stack.push(value)
|
stack.push(value)
|
||||||
|
|
||||||
self.Printf(" => %v", value)
|
|
||||||
case CALLDATALOAD:
|
case CALLDATALOAD:
|
||||||
data := getData(callData, stack.pop(), common.Big32)
|
data := getData(callData, stack.pop(), common.Big32)
|
||||||
|
|
||||||
self.Printf(" => 0x%x", data)
|
|
||||||
|
|
||||||
stack.push(common.Bytes2Big(data))
|
stack.push(common.Bytes2Big(data))
|
||||||
case CALLDATASIZE:
|
case CALLDATASIZE:
|
||||||
l := int64(len(callData))
|
l := int64(len(callData))
|
||||||
stack.push(big.NewInt(l))
|
stack.push(big.NewInt(l))
|
||||||
|
|
||||||
self.Printf(" => %d", l)
|
|
||||||
case CALLDATACOPY:
|
case CALLDATACOPY:
|
||||||
var (
|
var (
|
||||||
mOff = stack.pop()
|
mOff = stack.pop()
|
||||||
|
@ -446,7 +381,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
mem.Set(mOff.Uint64(), l.Uint64(), data)
|
mem.Set(mOff.Uint64(), l.Uint64(), data)
|
||||||
|
|
||||||
self.Printf(" => [%v, %v, %v]", mOff, cOff, l)
|
|
||||||
case CODESIZE, EXTCODESIZE:
|
case CODESIZE, EXTCODESIZE:
|
||||||
var code []byte
|
var code []byte
|
||||||
if op == EXTCODESIZE {
|
if op == EXTCODESIZE {
|
||||||
|
@ -460,7 +394,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
l := big.NewInt(int64(len(code)))
|
l := big.NewInt(int64(len(code)))
|
||||||
stack.push(l)
|
stack.push(l)
|
||||||
|
|
||||||
self.Printf(" => %d", l)
|
|
||||||
case CODECOPY, EXTCODECOPY:
|
case CODECOPY, EXTCODECOPY:
|
||||||
var code []byte
|
var code []byte
|
||||||
if op == EXTCODECOPY {
|
if op == EXTCODECOPY {
|
||||||
|
@ -480,12 +413,9 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||||||
|
|
||||||
self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
|
|
||||||
case GASPRICE:
|
case GASPRICE:
|
||||||
stack.push(context.Price)
|
stack.push(context.Price)
|
||||||
|
|
||||||
self.Printf(" => %x", context.Price)
|
|
||||||
|
|
||||||
case BLOCKHASH:
|
case BLOCKHASH:
|
||||||
num := stack.pop()
|
num := stack.pop()
|
||||||
|
|
||||||
|
@ -496,33 +426,27 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
stack.push(common.Big0)
|
stack.push(common.Big0)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" => 0x%x", stack.peek().Bytes())
|
|
||||||
case COINBASE:
|
case COINBASE:
|
||||||
coinbase := self.env.Coinbase()
|
coinbase := self.env.Coinbase()
|
||||||
|
|
||||||
stack.push(coinbase.Big())
|
stack.push(coinbase.Big())
|
||||||
|
|
||||||
self.Printf(" => 0x%x", coinbase)
|
|
||||||
case TIMESTAMP:
|
case TIMESTAMP:
|
||||||
time := self.env.Time()
|
time := self.env.Time()
|
||||||
|
|
||||||
stack.push(big.NewInt(time))
|
stack.push(big.NewInt(time))
|
||||||
|
|
||||||
self.Printf(" => 0x%x", time)
|
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
number := self.env.BlockNumber()
|
number := self.env.BlockNumber()
|
||||||
|
|
||||||
stack.push(U256(number))
|
stack.push(U256(number))
|
||||||
|
|
||||||
self.Printf(" => 0x%x", number.Bytes())
|
|
||||||
case DIFFICULTY:
|
case DIFFICULTY:
|
||||||
difficulty := self.env.Difficulty()
|
difficulty := self.env.Difficulty()
|
||||||
|
|
||||||
stack.push(difficulty)
|
stack.push(difficulty)
|
||||||
|
|
||||||
self.Printf(" => 0x%x", difficulty.Bytes())
|
|
||||||
case GASLIMIT:
|
case GASLIMIT:
|
||||||
self.Printf(" => %v", self.env.GasLimit())
|
|
||||||
|
|
||||||
stack.push(self.env.GasLimit())
|
stack.push(self.env.GasLimit())
|
||||||
|
|
||||||
|
@ -533,19 +457,16 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
stack.push(common.Bytes2Big(byts))
|
stack.push(common.Bytes2Big(byts))
|
||||||
pc += size
|
pc += size
|
||||||
|
|
||||||
self.Printf(" => 0x%x", byts)
|
|
||||||
case POP:
|
case POP:
|
||||||
stack.pop()
|
stack.pop()
|
||||||
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
|
||||||
n := int(op - DUP1 + 1)
|
n := int(op - DUP1 + 1)
|
||||||
stack.dup(n)
|
stack.dup(n)
|
||||||
|
|
||||||
self.Printf(" => [%d] 0x%x", n, stack.peek().Bytes())
|
|
||||||
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
|
||||||
n := int(op - SWAP1 + 2)
|
n := int(op - SWAP1 + 2)
|
||||||
stack.swap(n)
|
stack.swap(n)
|
||||||
|
|
||||||
self.Printf(" => [%d]", n)
|
|
||||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||||
n := int(op - LOG0)
|
n := int(op - LOG0)
|
||||||
topics := make([]common.Hash, n)
|
topics := make([]common.Hash, n)
|
||||||
|
@ -558,38 +479,32 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
|
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
|
||||||
self.env.AddLog(log)
|
self.env.AddLog(log)
|
||||||
|
|
||||||
self.Printf(" => %v", log)
|
|
||||||
case MLOAD:
|
case MLOAD:
|
||||||
offset := stack.pop()
|
offset := stack.pop()
|
||||||
val := common.BigD(mem.Get(offset.Int64(), 32))
|
val := common.BigD(mem.Get(offset.Int64(), 32))
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
|
|
||||||
self.Printf(" => 0x%x", val.Bytes())
|
|
||||||
case MSTORE:
|
case MSTORE:
|
||||||
// pop value of the stack
|
// pop value of the stack
|
||||||
mStart, val := stack.pop(), stack.pop()
|
mStart, val := stack.pop(), stack.pop()
|
||||||
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
||||||
|
|
||||||
self.Printf(" => 0x%x", val)
|
|
||||||
case MSTORE8:
|
case MSTORE8:
|
||||||
off, val := stack.pop().Int64(), stack.pop().Int64()
|
off, val := stack.pop().Int64(), stack.pop().Int64()
|
||||||
|
|
||||||
mem.store[off] = byte(val & 0xff)
|
mem.store[off] = byte(val & 0xff)
|
||||||
|
|
||||||
self.Printf(" => [%v] 0x%x", off, mem.store[off])
|
|
||||||
case SLOAD:
|
case SLOAD:
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := common.BigToHash(stack.pop())
|
||||||
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
|
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
|
||||||
stack.push(val)
|
stack.push(val)
|
||||||
|
|
||||||
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
|
||||||
case SSTORE:
|
case SSTORE:
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := common.BigToHash(stack.pop())
|
||||||
val := stack.pop()
|
val := stack.pop()
|
||||||
|
|
||||||
statedb.SetState(context.Address(), loc, val)
|
statedb.SetState(context.Address(), loc, val)
|
||||||
|
|
||||||
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
|
||||||
case JUMP:
|
case JUMP:
|
||||||
if err := jump(pc, stack.pop()); err != nil {
|
if err := jump(pc, stack.pop()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -607,8 +522,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
self.Printf(" ~> false")
|
|
||||||
|
|
||||||
case JUMPDEST:
|
case JUMPDEST:
|
||||||
case PC:
|
case PC:
|
||||||
stack.push(new(big.Int).SetUint64(pc))
|
stack.push(new(big.Int).SetUint64(pc))
|
||||||
|
@ -617,7 +530,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
case GAS:
|
case GAS:
|
||||||
stack.push(context.Gas)
|
stack.push(context.Gas)
|
||||||
|
|
||||||
self.Printf(" => %x", context.Gas)
|
|
||||||
case CREATE:
|
case CREATE:
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -627,14 +539,12 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
gas = new(big.Int).Set(context.Gas)
|
gas = new(big.Int).Set(context.Gas)
|
||||||
addr common.Address
|
addr common.Address
|
||||||
)
|
)
|
||||||
self.Endl()
|
|
||||||
|
|
||||||
context.UseGas(context.Gas)
|
context.UseGas(context.Gas)
|
||||||
ret, suberr, ref := self.env.Create(context, input, gas, price, value)
|
ret, suberr, ref := self.env.Create(context, input, gas, price, value)
|
||||||
if suberr != nil {
|
if suberr != nil {
|
||||||
stack.push(common.BigFalse)
|
stack.push(common.BigFalse)
|
||||||
|
|
||||||
self.Printf(" (*) 0x0 %v", suberr)
|
|
||||||
} else {
|
} else {
|
||||||
// gas < len(ret) * CreateDataGas == NO_CODE
|
// gas < len(ret) * CreateDataGas == NO_CODE
|
||||||
dataGas := big.NewInt(int64(len(ret)))
|
dataGas := big.NewInt(int64(len(ret)))
|
||||||
|
@ -659,7 +569,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
retOffset, retSize := stack.pop(), stack.pop()
|
retOffset, retSize := stack.pop(), stack.pop()
|
||||||
|
|
||||||
address := common.BigToAddress(addr)
|
address := common.BigToAddress(addr)
|
||||||
self.Printf(" => %x", address).Endl()
|
|
||||||
|
|
||||||
// Get the arguments from the memory
|
// Get the arguments from the memory
|
||||||
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||||||
|
@ -681,48 +590,40 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(common.BigFalse)
|
stack.push(common.BigFalse)
|
||||||
|
|
||||||
self.Printf("%v").Endl()
|
|
||||||
} else {
|
} else {
|
||||||
stack.push(common.BigTrue)
|
stack.push(common.BigTrue)
|
||||||
|
|
||||||
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
self.Printf("resume %x (%v)", context.Address(), context.Gas)
|
|
||||||
case RETURN:
|
case RETURN:
|
||||||
offset, size := stack.pop(), stack.pop()
|
offset, size := stack.pop(), stack.pop()
|
||||||
ret := mem.GetPtr(offset.Int64(), size.Int64())
|
ret := mem.GetPtr(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
|
|
||||||
|
|
||||||
return context.Return(ret), nil
|
return context.Return(ret), nil
|
||||||
case SUICIDE:
|
case SUICIDE:
|
||||||
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
|
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
|
||||||
balance := statedb.GetBalance(context.Address())
|
balance := statedb.GetBalance(context.Address())
|
||||||
|
|
||||||
self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance)
|
|
||||||
|
|
||||||
receiver.AddBalance(balance)
|
receiver.AddBalance(balance)
|
||||||
|
|
||||||
statedb.Delete(context.Address())
|
statedb.Delete(context.Address())
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case STOP: // Stop the context
|
case STOP: // Stop the context
|
||||||
self.Endl()
|
|
||||||
|
|
||||||
return context.Return(nil), nil
|
return context.Return(nil), nil
|
||||||
default:
|
default:
|
||||||
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("Invalid opcode %x", op)
|
return nil, fmt.Errorf("Invalid opcode %x", op)
|
||||||
}
|
}
|
||||||
|
|
||||||
pc++
|
pc++
|
||||||
|
|
||||||
self.Endl()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
|
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
|
||||||
var (
|
var (
|
||||||
gas = new(big.Int)
|
gas = new(big.Int)
|
||||||
newMemSize *big.Int = new(big.Int)
|
newMemSize *big.Int = new(big.Int)
|
||||||
|
@ -863,26 +764,13 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
|
||||||
return newMemSize, gas, nil
|
return newMemSize, gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *Vm) Log(op OpCode, gas *big.Int, memory *Memory, stack *stack) {
|
|
||||||
if vm.debug {
|
|
||||||
mem := make([]byte, len(memory.store))
|
|
||||||
copy(mem, memory.store)
|
|
||||||
stck := make([]*big.Int, len(stack.data))
|
|
||||||
copy(stck, stack.data)
|
|
||||||
vm.Logs = append(vm.Logs, log{op, new(big.Int).Set(gas), mem, stck})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
|
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
|
||||||
gas := p.Gas(len(callData))
|
gas := p.Gas(len(callData))
|
||||||
if context.UseGas(gas) {
|
if context.UseGas(gas) {
|
||||||
ret = p.Call(callData)
|
ret = p.Call(callData)
|
||||||
self.Printf("NATIVE_FUNC => %x", ret)
|
|
||||||
self.Endl()
|
|
||||||
|
|
||||||
return context.Return(ret), nil
|
return context.Return(ret), nil
|
||||||
} else {
|
} else {
|
||||||
self.Printf("NATIVE_FUNC => failed").Endl()
|
|
||||||
|
|
||||||
tmp := new(big.Int).Set(context.Gas)
|
tmp := new(big.Int).Set(context.Gas)
|
||||||
|
|
||||||
|
@ -890,21 +778,14 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
|
func (self *Vm) log(pc uint64, op OpCode, gas *big.Int, memory *Memory, stack *Stack) {
|
||||||
if self.debug {
|
if Debug {
|
||||||
self.logStr += fmt.Sprintf(format, v...)
|
mem := make([]byte, len(memory.Data()))
|
||||||
|
copy(mem, memory.Data())
|
||||||
|
stck := make([]*big.Int, len(stack.Data()))
|
||||||
|
copy(stck, stack.Data())
|
||||||
|
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), mem, stck})
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Vm) Endl() VirtualMachine {
|
|
||||||
if self.debug {
|
|
||||||
glog.V(0).Infoln(self.logStr)
|
|
||||||
self.logStr = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Vm) Env() Environment {
|
func (self *Vm) Env() Environment {
|
||||||
|
|
|
@ -16,6 +16,8 @@ type VMEnv struct {
|
||||||
depth int
|
depth int
|
||||||
chain *ChainManager
|
chain *ChainManager
|
||||||
typ vm.Type
|
typ vm.Type
|
||||||
|
// structured logging
|
||||||
|
logs []vm.StructLog
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
|
func NewEnv(state *state.StateDB, chain *ChainManager, msg Message, block *types.Block) *VMEnv {
|
||||||
|
@ -47,6 +49,7 @@ func (self *VMEnv) GetHash(n uint64) common.Hash {
|
||||||
|
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) AddLog(log *state.Log) {
|
func (self *VMEnv) AddLog(log *state.Log) {
|
||||||
self.state.AddLog(log)
|
self.state.AddLog(log)
|
||||||
}
|
}
|
||||||
|
@ -68,3 +71,11 @@ func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.
|
||||||
exe := NewExecution(self, nil, data, gas, price, value)
|
exe := NewExecution(self, nil, data, gas, price, value)
|
||||||
return exe.Create(me)
|
return exe.Create(me)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *VMEnv) StructLogs() []vm.StructLog {
|
||||||
|
return self.logs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *VMEnv) AddStructLog(log vm.StructLog) {
|
||||||
|
self.logs = append(self.logs, log)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VmStdErrFormat(logs []vm.StructLog) {
|
||||||
|
fmt.Fprintf(os.Stderr, "VM Stats %d ops\n", len(logs))
|
||||||
|
for _, log := range logs {
|
||||||
|
fmt.Fprintf(os.Stderr, "PC %-3d - %-14s\n", log.Pc, log.Op)
|
||||||
|
fmt.Fprintln(os.Stderr, "STACK =", len(log.Stack))
|
||||||
|
for i, item := range log.Stack {
|
||||||
|
fmt.Fprintf(os.Stderr, "%04d: %x\n", i, common.LeftPadBytes(item.Bytes(), 32))
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxMem = 10
|
||||||
|
addr := 0
|
||||||
|
fmt.Fprintln(os.Stderr, "MEM =", len(log.Memory))
|
||||||
|
for i := 0; i+16 <= len(log.Memory) && addr < maxMem; i += 16 {
|
||||||
|
data := log.Memory[i : i+16]
|
||||||
|
str := fmt.Sprintf("%04d: % x ", addr*16, data)
|
||||||
|
for _, r := range data {
|
||||||
|
if r == 0 {
|
||||||
|
str += "."
|
||||||
|
} else if utf8.ValidRune(rune(r)) {
|
||||||
|
str += fmt.Sprintf("%s", string(r))
|
||||||
|
} else {
|
||||||
|
str += "?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addr++
|
||||||
|
fmt.Fprintln(os.Stderr, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,9 +27,8 @@ type Env struct {
|
||||||
difficulty *big.Int
|
difficulty *big.Int
|
||||||
gasLimit *big.Int
|
gasLimit *big.Int
|
||||||
|
|
||||||
logs state.Logs
|
|
||||||
|
|
||||||
vmTest bool
|
vmTest bool
|
||||||
|
logs []vm.StructLog
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB) *Env {
|
func NewEnv(state *state.StateDB) *Env {
|
||||||
|
@ -38,6 +37,14 @@ func NewEnv(state *state.StateDB) *Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Env) StructLogs() []vm.StructLog {
|
||||||
|
return self.logs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Env) AddStructLog(log vm.StructLog) {
|
||||||
|
self.logs = append(self.logs, log)
|
||||||
|
}
|
||||||
|
|
||||||
func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
|
func NewEnvFromMap(state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
|
||||||
env := NewEnv(state)
|
env := NewEnv(state)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue