This commit is contained in:
Jeffrey Wilcke 2015-06-25 13:27:24 +02:00
parent f17ae6b256
commit 5027822bde
6 changed files with 77 additions and 66 deletions

View file

@ -110,8 +110,6 @@ func run(ctx *cli.Context) {
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name))) vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)))
tstart := time.Now() tstart := time.Now()
vmstart := time.Now()
ret, e := vmenv.Call( ret, e := vmenv.Call(
sender, sender,
receiver.Address(), receiver.Address(),
@ -120,32 +118,12 @@ func run(ctx *cli.Context) {
common.Big(ctx.GlobalString(PriceFlag.Name)), common.Big(ctx.GlobalString(PriceFlag.Name)),
common.Big(ctx.GlobalString(ValueFlag.Name)), common.Big(ctx.GlobalString(ValueFlag.Name)),
) )
vmdone := time.Since(tstart)
if e != nil { if e != nil {
fmt.Println(e) fmt.Println(e)
os.Exit(1) os.Exit(1)
} }
fmt.Println("no segmentation", time.Since(vmstart))
fmt.Println()
if !vm.DisableSegmentation {
vmstart = time.Now()
ret, e = vmenv.Call(
sender,
receiver.Address(),
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
common.Big(ctx.GlobalString(GasFlag.Name)),
common.Big(ctx.GlobalString(PriceFlag.Name)),
common.Big(ctx.GlobalString(ValueFlag.Name)),
)
if e != nil {
fmt.Println(e)
os.Exit(1)
}
fmt.Println("with segmentation", time.Since(vmstart))
}
if ctx.GlobalBool(DumpFlag.Name) { if ctx.GlobalBool(DumpFlag.Name) {
fmt.Println(string(statedb.Dump())) fmt.Println(string(statedb.Dump()))
@ -155,7 +133,7 @@ func run(ctx *cli.Context) {
if ctx.GlobalBool(SysStatFlag.Name) { if ctx.GlobalBool(SysStatFlag.Name) {
var mem runtime.MemStats var mem runtime.MemStats
runtime.ReadMemStats(&mem) runtime.ReadMemStats(&mem)
fmt.Printf("vm took %v\n", time.Since(tstart)) fmt.Printf("vm took %v\n", vmdone)
fmt.Printf(`alloc: %d fmt.Printf(`alloc: %d
tot alloc: %d tot alloc: %d
no. malloc: %d no. malloc: %d

View file

@ -9,7 +9,6 @@ import (
) )
func StdErrFormat(logs []StructLog) { func StdErrFormat(logs []StructLog) {
fmt.Fprintf(os.Stderr, "VM STAT %d OPs\n", len(logs))
for _, log := range logs { for _, log := range logs {
fmt.Fprintf(os.Stderr, "PC %08d: %s GAS: %v COST: %v", log.Pc, log.Op, log.Gas, log.GasCost) fmt.Fprintf(os.Stderr, "PC %08d: %s GAS: %v COST: %v", log.Pc, log.Op, log.Gas, log.GasCost)
if log.Err != nil { if log.Err != nil {

View file

@ -36,7 +36,7 @@ type segment struct {
} }
func (c *segment) String() string { func (c *segment) String() string {
return fmt.Sprintf("{%d %d %d %v}", c.cstart, c.cend, c.msize, c.gas) return fmt.Sprintf("{start: %d end: %d ssize: %d gas: %v}", c.cstart, c.cend, c.ssize, c.gas)
} }
// native operations // native operations

View file

@ -335,7 +335,7 @@ func (o OpCode) String() string {
func isDynamic(op OpCode) bool { func isDynamic(op OpCode) bool {
switch op { switch op {
case CREATE, CALL, CALLCODE, JUMP, JUMPI, SUICIDE, STOP, RETURN, EXTCODECOPY, CODECOPY, MSTORE, MSTORE8, SSTORE: case CREATE, CALL, CALLCODE, CALLDATACOPY, GAS, MLOAD, JUMP, JUMPI, SUICIDE, STOP, RETURN, EXTCODECOPY, CODECOPY, MSTORE, MSTORE8, SSTORE:
return true return true
} }
if _, ok := opCodeToString[op]; !ok { if _, ok := opCodeToString[op]; !ok {

View file

@ -11,6 +11,8 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
var t int
// Vm implements VirtualMachine // Vm implements VirtualMachine
type Vm struct { type Vm struct {
env Environment env Environment
@ -38,6 +40,13 @@ func New(env Environment) *Vm {
func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) { func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
self.env.SetDepth(self.env.Depth() + 1) self.env.SetDepth(self.env.Depth() + 1)
defer self.env.SetDepth(self.env.Depth() - 1) defer self.env.SetDepth(self.env.Depth() - 1)
defer func() {
if r := recover(); r != nil {
StdErrFormat(self.env.StructLogs())
ret = nil
err = fmt.Errorf("%v", r)
}
}()
var ( var (
caller = context.caller caller = context.caller
@ -98,17 +107,14 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
ret = context.Return(nil) ret = context.Return(nil)
} }
if csegment != nil && err != nil && csegment.cend == 0 { if !DisableSegmentation && csegment != nil && csegment.cend == 0 {
// delete this tracking segment. We couldn't fully determine the stats if err != nil {
delete(csegments, csegment.cstart) // delete this tracking segment. We couldn't fully determine the stats
} else if csegment != nil && err == nil && csegment.cend == 0 { delete(csegments, csegment.cstart)
csegment.cend = pc } else {
csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0))) csegment.cend = pc
} csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0)))
}
t, _ := segments.Get(codehash)
for _, segment := range t.(codeSegments) {
fmt.Println(segment)
} }
}() }()
@ -124,27 +130,34 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
} }
for { for {
cost = new(big.Int)
// Get the current operation location of pc // Get the current operation location of pc
op = context.GetOp(pc) op = context.GetOp(pc)
if !DisableSegmentation { if !DisableSegmentation {
if isDynamic(op) && csegment != nil { if isDynamic(op) {
// end of segment bound //fmt.Println("encountered dyn")
csegment.cend = ppc if csegment != nil && csegment.cend == 0 {
csegment.next = pc //fmt.Println("closing segment with", op, "@", ppc, csegment.gas)
// write out the required required elements on the stack. i.e. the amount of items // mark end of segment bound
// required outside of the segment itself. csegment.cend = ppc
// 0: P, 1 // set the next op for continuation
// 1: J, 2 csegment.next = pc
// 2: D -+ // write out the required required elements on the stack. i.e. the amount of items
// 3: P, 2 |- M,0 = M,0 pushes 1. Requires 2. 1 outside bounds of M,0 // required outside of the segment itself.
// 4: ADD -+ // 0: P, 1
// 5: J, 2 // 1: J, 2
csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0))) // 2: D -+
// 3: P, 2 |- M,0 = M,0 pushes 1. Requires 2. 1 outside bounds of M,0
// 4: ADD -+
// 5: J, 2
csegment.ssize = int(math.Abs(math.Min(float64(stack.len()-csegment.ssize), 0)))
}
csegment = nil csegment = nil
nopay = 0 nopay = 0
} else if csegment == nil && pc != 0 { } else if csegment == nil && pc != 0 {
// check if a segment is available to us and set it. // check if a segment is available to us and set it.
if seg, ok := csegments[pc]; ok { if seg, ok := csegments[pc]; ok {
//fmt.Println(pc, "using seg", seg)
nopay = seg.cend nopay = seg.cend
// make sure there's enough stack items to complete the segment // make sure there's enough stack items to complete the segment
@ -152,27 +165,36 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
return context.Return(nil), err return context.Return(nil), err
} }
cost.Set(seg.gas)
// use required gas for this segment // use required gas for this segment
if !context.UseGas(seg.gas) { if !context.UseGas(seg.gas) {
context.UseGas(context.Gas) context.UseGas(context.Gas)
return context.Return(nil), OutOfGasError{} return context.Return(nil), OutOfGasError{}
} }
csegment = seg
for _, operation := range seg.ops { /*
operation.fn(stack, operation.data) for _, operation := range seg.ops {
} operation.fn(stack, operation.data)
}
pc = seg.next pc = seg.next
continue continue
*/
} else { } else {
//fmt.Println("creating", pc)
// allocate a new segment for tracking information // allocate a new segment for tracking information
csegment = &segment{pc, 0, 0, 0, new(big.Int), stack.len(), nil} csegment = &segment{pc, 0, 0, 0, new(big.Int), stack.len(), nil}
csegments[pc] = csegment csegments[pc] = csegment
nopay = 0
} }
} }
} }
// set previous program counter
ppc = pc
//fmt.Println(pc, nopay, pc > nopay, pc == 0)
if pc > nopay || pc == 0 || DisableSegmentation { if pc > nopay || pc == 0 || DisableSegmentation {
// calculate the new memory size and gas price for the current executing opcode // calculate the new memory size and gas price for the current executing opcode
newMemSize, cost, err = self.calculateGasAndSize(context, caller, op, statedb, mem, stack) newMemSize, cost, err = self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
@ -180,6 +202,10 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
return nil, err return nil, err
} }
if csegment != nil {
csegment.gas.Add(csegment.gas, cost)
}
// Use the calculated gas. When insufficient gas is present, use all gas and return an // Use the calculated gas. When insufficient gas is present, use all gas and return an
// Out Of Gas error // Out Of Gas error
if !context.UseGas(cost) { if !context.UseGas(cost) {
@ -191,15 +217,10 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
// Resize the memory calculated previously // Resize the memory calculated previously
mem.Resize(newMemSize.Uint64()) mem.Resize(newMemSize.Uint64())
if csegment != nil {
csegment.msize = uint64(len(mem.store))
csegment.gas.Add(csegment.gas, cost)
}
} }
// Add a log message // Add a log message
self.log(pc, op, context.Gas, cost, mem, stack, context, nil) self.log(pc, op, context.Gas, cost, mem, stack, context, nil)
ppc = pc
// The base for all big integer arithmetic // The base for all big integer arithmetic
base := new(big.Int) base := new(big.Int)
@ -227,12 +248,12 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case MUL: case MUL:
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.pop()
base.Mul(x, y) res := new(big.Int).Mul(x, y)
U256(base) U256(res)
// pop result back on the stack // pop result back on the stack
stack.push(base) stack.push(res)
case DIV: case DIV:
x, y := stack.pop(), stack.pop() x, y := stack.pop(), stack.pop()
@ -625,6 +646,10 @@ func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
case MSIZE: case MSIZE:
stack.push(big.NewInt(int64(mem.Len()))) stack.push(big.NewInt(int64(mem.Len())))
case GAS: case GAS:
if t > 1 {
//return context.Return(nil), nil
}
t++
stack.push(context.Gas) stack.push(context.Gas)
case CREATE: case CREATE:
@ -887,7 +912,9 @@ func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, st
mem := make([]byte, len(memory.Data())) mem := make([]byte, len(memory.Data()))
copy(mem, memory.Data()) copy(mem, memory.Data())
stck := make([]*big.Int, len(stack.Data())) stck := make([]*big.Int, len(stack.Data()))
copy(stck, stack.Data()) for i, item := range stack.Data() {
stck[i] = new(big.Int).Set(item)
}
object := context.self.(*state.StateObject) object := context.self.(*state.StateObject)
storage := make(map[common.Hash][]byte) storage := make(map[common.Hash][]byte)
@ -895,7 +922,7 @@ func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, st
storage[common.BytesToHash(k)] = v storage[common.BytesToHash(k)] = v
}) })
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, err}) self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), new(big.Int).Set(cost), mem, stck, storage, err})
} }
} }

View file

@ -50,6 +50,13 @@ func runStateTests(tests map[string]VmTest, skipTests []string) error {
} }
for name, test := range tests { for name, test := range tests {
//vm.Debug = true
//vm.DisableSegmentation = true
/*
if name != "Call10" {
continue
}
*/
if skipTest[name] { if skipTest[name] {
glog.Infoln("Skipping state test", name) glog.Infoln("Skipping state test", name)
return nil return nil