aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/execution.go27
-rw-r--r--core/vm/analysis.go24
-rw-r--r--core/vm/common.go11
-rw-r--r--core/vm/context.go34
-rw-r--r--core/vm/vm.go62
-rw-r--r--core/vm_env.go10
6 files changed, 84 insertions, 84 deletions
diff --git a/core/execution.go b/core/execution.go
index 72eb22bd5..24e085e6d 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -11,14 +11,18 @@ import (
)
type Execution struct {
- env vm.Environment
- address *common.Address
- input []byte
+ env vm.Environment
+ address *common.Address
+ input []byte
+ evm vm.VirtualMachine
+
Gas, price, value *big.Int
}
func NewExecution(env vm.Environment, address *common.Address, input []byte, gas, gasPrice, value *big.Int) *Execution {
- return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
+ exe := &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
+ exe.evm = vm.NewVm(env)
+ return exe
}
func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]byte, error) {
@@ -28,11 +32,17 @@ func (self *Execution) Call(codeAddr common.Address, caller vm.ContextRef) ([]by
return self.exec(&codeAddr, code, caller)
}
+func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
+ ret, err = self.exec(nil, self.input, caller)
+ account = self.env.State().GetStateObject(*self.address)
+ return
+}
+
func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.ContextRef) (ret []byte, err error) {
start := time.Now()
env := self.env
- evm := vm.NewVm(env)
+ evm := self.evm
if env.Depth() == vm.MaxCallDepth {
caller.ReturnGas(self.Gas, self.price)
@@ -70,10 +80,3 @@ func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.
return
}
-
-func (self *Execution) Create(caller vm.ContextRef) (ret []byte, err error, account *state.StateObject) {
- ret, err = self.exec(nil, self.input, caller)
- account = self.env.State().GetStateObject(*self.address)
-
- return
-}
diff --git a/core/vm/analysis.go b/core/vm/analysis.go
index 411df5686..264d55cb9 100644
--- a/core/vm/analysis.go
+++ b/core/vm/analysis.go
@@ -1,9 +1,25 @@
package vm
-import "gopkg.in/fatih/set.v0"
+import (
+ "math/big"
-func analyseJumpDests(code []byte) (dests *set.Set) {
- dests = set.New()
+ "gopkg.in/fatih/set.v0"
+)
+
+type destinations struct {
+ set *set.Set
+}
+
+func (d *destinations) Has(dest *big.Int) bool {
+ return d.set.Has(string(dest.Bytes()))
+}
+
+func (d *destinations) Add(dest *big.Int) {
+ d.set.Add(string(dest.Bytes()))
+}
+
+func analyseJumpDests(code []byte) (dests *destinations) {
+ dests = &destinations{set.New()}
for pc := uint64(0); pc < uint64(len(code)); pc++ {
var op OpCode = OpCode(code[pc])
@@ -13,7 +29,7 @@ func analyseJumpDests(code []byte) (dests *set.Set) {
pc += a
case JUMPDEST:
- dests.Add(pc)
+ dests.Add(big.NewInt(int64(pc)))
}
}
return
diff --git a/core/vm/common.go b/core/vm/common.go
index 8d8f4253f..5ff4e05f2 100644
--- a/core/vm/common.go
+++ b/core/vm/common.go
@@ -33,6 +33,7 @@ var (
S256 = common.S256
Zero = common.Big0
+ One = common.Big1
max = big.NewInt(math.MaxInt64)
)
@@ -80,3 +81,13 @@ func getData(data []byte, start, size *big.Int) []byte {
e := common.BigMin(new(big.Int).Add(s, size), dlen)
return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
}
+
+func UseGas(gas, amount *big.Int) bool {
+ if gas.Cmp(amount) < 0 {
+ return false
+ }
+
+ // Sub the amount of gas from the remaining
+ gas.Sub(gas, amount)
+ return true
+}
diff --git a/core/vm/context.go b/core/vm/context.go
index e73199b77..29bb9f74e 100644
--- a/core/vm/context.go
+++ b/core/vm/context.go
@@ -1,7 +1,6 @@
package vm
import (
- "math"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -41,29 +40,18 @@ func NewContext(caller ContextRef, object ContextRef, value, gas, price *big.Int
return c
}
-func (c *Context) GetOp(n uint64) OpCode {
+func (c *Context) GetOp(n *big.Int) OpCode {
return OpCode(c.GetByte(n))
}
-func (c *Context) GetByte(n uint64) byte {
- if n < uint64(len(c.Code)) {
- return c.Code[n]
+func (c *Context) GetByte(n *big.Int) byte {
+ if n.Cmp(big.NewInt(int64(len(c.Code)))) < 0 {
+ return c.Code[n.Int64()]
}
return 0
}
-func (c *Context) GetBytes(x, y int) []byte {
- return c.GetRangeValue(uint64(x), uint64(y))
-}
-
-func (c *Context) GetRangeValue(x, size uint64) []byte {
- x = uint64(math.Min(float64(x), float64(len(c.Code))))
- y := uint64(math.Min(float64(x+size), float64(len(c.Code))))
-
- return common.RightPadBytes(c.Code[x:y], int(size))
-}
-
func (c *Context) Return(ret []byte) []byte {
// Return the remaining gas to the caller
c.caller.ReturnGas(c.Gas, c.Price)
@@ -74,16 +62,12 @@ func (c *Context) Return(ret []byte) []byte {
/*
* Gas functions
*/
-func (c *Context) UseGas(gas *big.Int) bool {
- if c.Gas.Cmp(gas) < 0 {
- return false
+func (c *Context) UseGas(gas *big.Int) (ok bool) {
+ ok = UseGas(c.Gas, gas)
+ if ok {
+ c.UsedGas.Add(c.UsedGas, gas)
}
-
- // Sub the amount of gas from the remaining
- c.Gas.Sub(c.Gas, gas)
- c.UsedGas.Add(c.UsedGas, gas)
-
- return true
+ return
}
// Implement the caller interface
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 88fbdf763..6c3dd240a 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -24,6 +24,9 @@ type Vm struct {
Fn string
Recoverable bool
+
+ // Will be called before the vm returns
+ After func(*Context, error)
}
func New(env Environment) *Vm {
@@ -47,6 +50,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
defer func() {
+ if self.After != nil {
+ self.After(context, err)
+ }
+
if err != nil {
self.Printf(" %v", err).Endl()
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
@@ -65,23 +72,20 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
var (
op OpCode
- destinations = analyseJumpDests(context.Code)
- mem = NewMemory()
- stack = newStack()
- pc uint64 = 0
- step = 0
- statedb = self.env.State()
+ destinations = analyseJumpDests(context.Code)
+ mem = NewMemory()
+ stack = newStack()
+ pc = new(big.Int)
+ statedb = self.env.State()
- jump = func(from uint64, to *big.Int) error {
- p := to.Uint64()
-
- nop := context.GetOp(p)
- if !destinations.Has(p) {
- return fmt.Errorf("invalid jump destination (%v) %v", nop, p)
+ jump = func(from *big.Int, to *big.Int) error {
+ nop := context.GetOp(to)
+ if !destinations.Has(to) {
+ return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
}
self.Printf(" ~> %v", to)
- pc = to.Uint64()
+ pc = to
self.Endl()
@@ -98,7 +102,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
// The base for all big integer arithmetic
base := new(big.Int)
- step++
// Get the memory location of pc
op = context.GetOp(pc)
@@ -421,22 +424,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self.Printf(" => %v", value)
case CALLDATALOAD:
- var (
- offset = stack.pop()
- data = make([]byte, 32)
- lenData = big.NewInt(int64(len(callData)))
- )
-
- if lenData.Cmp(offset) >= 0 {
- length := new(big.Int).Add(offset, common.Big32)
- length = common.BigMin(length, lenData)
-
- copy(data, callData[offset.Int64():length.Int64()])
- }
+ data := getData(callData, stack.pop(), common.Big32)
self.Printf(" => 0x%x", data)
- stack.push(common.BigD(data))
+ stack.push(common.Bytes2Big(data))
case CALLDATASIZE:
l := int64(len(callData))
stack.push(big.NewInt(l))
@@ -535,13 +527,11 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
// 0x50 range
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
- a := uint64(op - PUSH1 + 1)
- byts := context.GetRangeValue(pc+1, a)
+ a := big.NewInt(int64(op - PUSH1 + 1))
+ byts := getData(code, new(big.Int).Add(pc, big.NewInt(1)), a)
// push value to stack
- stack.push(common.BigD(byts))
- pc += a
-
- step += int(op) - int(PUSH1) + 1
+ stack.push(common.Bytes2Big(byts))
+ pc.Add(pc, a)
self.Printf(" => 0x%x", byts)
case POP:
@@ -621,7 +611,8 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
case JUMPDEST:
case PC:
- stack.push(big.NewInt(int64(pc)))
+ //stack.push(big.NewInt(int64(pc)))
+ stack.push(pc)
case MSIZE:
stack.push(big.NewInt(int64(mem.Len())))
case GAS:
@@ -647,7 +638,6 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self.Printf(" (*) 0x0 %v", suberr)
} else {
-
// gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, GasCreateByte)
@@ -728,7 +718,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
return nil, fmt.Errorf("Invalid opcode %x", op)
}
- pc++
+ pc.Add(pc, One)
self.Endl()
}
diff --git a/core/vm_env.go b/core/vm_env.go
index 52e8b20a9..6a604fccd 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -54,21 +54,17 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
return vm.Transfer(from, to, amount)
}
-func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *Execution {
- return NewExecution(self, addr, data, gas, price, value)
-}
-
func (self *VMEnv) Call(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
- exe := self.vm(&addr, data, gas, price, value)
+ exe := NewExecution(self, &addr, data, gas, price, value)
return exe.Call(addr, me)
}
func (self *VMEnv) CallCode(me vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
maddr := me.Address()
- exe := self.vm(&maddr, data, gas, price, value)
+ exe := NewExecution(self, &maddr, data, gas, price, value)
return exe.Call(addr, me)
}
func (self *VMEnv) Create(me vm.ContextRef, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) {
- exe := self.vm(nil, data, gas, price, value)
+ exe := NewExecution(self, nil, data, gas, price, value)
return exe.Create(me)
}