mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
wip
This commit is contained in:
parent
f17ae6b256
commit
5027822bde
6 changed files with 77 additions and 66 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
105
core/vm/vm.go
105
core/vm/vm.go
|
|
@ -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})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue