Commit 38c61f6f authored by obscuren's avatar obscuren

core, core/vm: added structure logging

This also reduces the time required spend in the VM
parent ff5b3ef0
...@@ -223,6 +223,10 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er ...@@ -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 { ...@@ -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 { ...@@ -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 ( ...@@ -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 ( ...@@ -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) { ...@@ -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 ...@@ -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
} }
This diff is collapsed.
...@@ -16,6 +16,8 @@ type VMEnv struct { ...@@ -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 { ...@@ -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. ...@@ -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)
}
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 { ...@@ -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 { ...@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment