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
return nil, nil, InvalidTxError(err)
}
if vm.Debug {
VmStdErrFormat(vmenv.StructLogs())
}
self.refundGas()
self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice))
......
......@@ -20,6 +20,8 @@ type Environment interface {
GasLimit() *big.Int
Transfer(from, to Account, amount *big.Int) error
AddLog(*state.Log)
AddStructLog(StructLog)
StructLogs() []StructLog
VmType() Type
......@@ -31,6 +33,14 @@ type Environment interface {
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 {
SubBalance(amount *big.Int)
AddBalance(amount *big.Int)
......
......@@ -21,7 +21,7 @@ var (
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 is also allowed to calculate the same price for all PUSHes
// DUP requirements are handled elsewhere (except for the stack limit check)
......
......@@ -5,16 +5,20 @@ import (
"math/big"
)
func newStack() *stack {
return &stack{}
func newStack() *Stack {
return &Stack{}
}
type stack struct {
type Stack struct {
data []*big.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
stackItem := new(big.Int).Set(d)
if len(st.data) > st.ptr {
......@@ -25,36 +29,36 @@ func (st *stack) push(d *big.Int) {
st.ptr++
}
func (st *stack) pop() (ret *big.Int) {
func (st *Stack) pop() (ret *big.Int) {
st.ptr--
ret = st.data[st.ptr]
return
}
func (st *stack) len() int {
func (st *Stack) len() int {
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]
}
func (st *stack) dup(n int) {
func (st *Stack) dup(n int) {
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]
}
func (st *stack) require(n int) error {
func (st *Stack) require(n int) error {
if st.len() < n {
return fmt.Errorf("stack underflow (%d <=> %d)", len(st.data), n)
}
return nil
}
func (st *stack) Print() {
func (st *Stack) Print() {
fmt.Println("### stack ###")
if len(st.data) > 0 {
for i, val := range st.data {
......
......@@ -3,6 +3,4 @@ package vm
type VirtualMachine interface {
Env() Environment
Run(context *Context, data []byte) ([]byte, error)
Printf(string, ...interface{}) VirtualMachine
Endl() VirtualMachine
}
This diff is collapsed.
......@@ -16,6 +16,8 @@ type VMEnv struct {
depth int
chain *ChainManager
typ vm.Type
// structured logging
logs []vm.StructLog
}
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{}
}
func (self *VMEnv) AddLog(log *state.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)
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 {
difficulty *big.Int
gasLimit *big.Int
logs state.Logs
vmTest bool
logs []vm.StructLog
}
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 {
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