aboutsummaryrefslogtreecommitdiffstats
path: root/ethvm
diff options
context:
space:
mode:
Diffstat (limited to 'ethvm')
-rw-r--r--ethvm/closure.go14
-rw-r--r--ethvm/stack.go2
-rw-r--r--ethvm/vm.go89
-rw-r--r--ethvm/vm_test.go10
4 files changed, 83 insertions, 32 deletions
diff --git a/ethvm/closure.go b/ethvm/closure.go
index 505fd43fb..54bfd05f4 100644
--- a/ethvm/closure.go
+++ b/ethvm/closure.go
@@ -3,9 +3,10 @@ package ethvm
// TODO Re write VM to use values instead of big integers?
import (
+ "math/big"
+
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
- "math/big"
)
type ClosureRef interface {
@@ -17,9 +18,10 @@ type ClosureRef interface {
// Basic inline closure object which implement the 'closure' interface
type Closure struct {
- caller ClosureRef
- object *ethstate.StateObject
- Code []byte
+ caller ClosureRef
+ object *ethstate.StateObject
+ Code []byte
+ message *ethstate.Message
Gas, UsedGas, Price *big.Int
@@ -27,8 +29,8 @@ type Closure struct {
}
// Create a new closure for the given data items
-func NewClosure(caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure {
- c := &Closure{caller: caller, object: object, Code: code, Args: nil}
+func NewClosure(msg *ethstate.Message, caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure {
+ c := &Closure{message: msg, caller: caller, object: object, Code: code, Args: nil}
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
diff --git a/ethvm/stack.go b/ethvm/stack.go
index c06d63652..f4b0be393 100644
--- a/ethvm/stack.go
+++ b/ethvm/stack.go
@@ -59,7 +59,7 @@ func (st *Stack) Peek() *big.Int {
}
func (st *Stack) Peekn() (*big.Int, *big.Int) {
- ints := st.data[:2]
+ ints := st.data[len(st.data)-2:]
return ints[0], ints[1]
}
diff --git a/ethvm/vm.go b/ethvm/vm.go
index a93b56e60..ddad0d366 100644
--- a/ethvm/vm.go
+++ b/ethvm/vm.go
@@ -2,11 +2,12 @@ package ethvm
import (
"fmt"
+ "math"
+ "math/big"
+
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
- "math"
- "math/big"
)
type Debugger interface {
@@ -51,6 +52,7 @@ type Environment interface {
Time() int64
Difficulty() *big.Int
Value() *big.Int
+ BlockHash() []byte
}
type Object interface {
@@ -128,14 +130,14 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes())
})
}
+ */
- b := pc.Bytes()
- if len(b) == 0 {
- b = []byte{0}
- }
+ b := pc.Bytes()
+ if len(b) == 0 {
+ b = []byte{0}
+ }
- fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
- */
+ fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
}
gas := new(big.Int)
@@ -244,6 +246,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Add(y, x)
+ ensure256(base)
+
self.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
@@ -254,6 +258,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Sub(y, x)
+ ensure256(base)
+
self.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
@@ -264,6 +270,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Mul(y, x)
+ ensure256(base)
+
self.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
@@ -276,6 +284,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Div(y, x)
}
+ ensure256(base)
+
self.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
@@ -288,6 +298,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Div(y, x)
}
+ ensure256(base)
+
self.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
@@ -299,6 +311,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Mod(y, x)
+ ensure256(base)
+
self.Printf(" = %v", base)
stack.Push(base)
case SMOD:
@@ -309,6 +323,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Mod(y, x)
+ ensure256(base)
+
self.Printf(" = %v", base)
stack.Push(base)
@@ -320,6 +336,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
base.Exp(y, x, Pow256)
+ ensure256(base)
+
self.Printf(" = %v", base)
stack.Push(base)
@@ -627,8 +645,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
val, loc := stack.Popn()
closure.SetStorage(loc, ethutil.NewValue(val))
- // Add the change to manifest
- self.env.State().Manifest().AddStorageChange(closure.Object(), loc.Bytes(), val)
+ closure.message.AddStorageChange(loc.Bytes())
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case JUMP:
@@ -679,27 +696,35 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf(" (*) %x", addr).Endl()
+ msg := self.env.State().Manifest().AddMessage(&ethstate.Message{
+ To: addr, From: closure.Address(),
+ Origin: self.env.Origin(),
+ Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
+ Value: value,
+ })
+
// Create a new contract
contract := self.env.State().NewStateObject(addr)
- if contract.Amount.Cmp(value) >= 0 {
+ if contract.Balance.Cmp(value) >= 0 {
closure.object.SubAmount(value)
contract.AddAmount(value)
// Set the init script
initCode := mem.Get(offset.Int64(), size.Int64())
- //fmt.Printf("%x\n", initCode)
+ msg.Input = initCode
+
// Transfer all remaining gas to the new
// contract so it may run the init script
gas := new(big.Int).Set(closure.Gas)
closure.UseGas(closure.Gas)
// Create the closure
- c := NewClosure(closure, contract, initCode, gas, closure.Price)
+ c := NewClosure(msg, closure, contract, initCode, gas, closure.Price)
// Call the closure and set the return value as
// main script.
contract.Code, _, err = c.Call(self, nil)
} else {
- err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
+ err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
}
if err != nil {
@@ -711,7 +736,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
self.Printf("CREATE err %v", err)
} else {
stack.Push(ethutil.BigD(addr))
- self.Printf("CREATE success")
+
+ msg.Output = contract.Code
}
self.Endl()
@@ -735,8 +761,16 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
- if closure.object.Amount.Cmp(value) < 0 {
- vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
+ msg := self.env.State().Manifest().AddMessage(&ethstate.Message{
+ To: addr.Bytes(), From: closure.Address(),
+ Input: args,
+ Origin: self.env.Origin(),
+ Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
+ Value: value,
+ })
+
+ if closure.object.Balance.Cmp(value) < 0 {
+ vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Balance)
closure.ReturnGas(gas, nil)
@@ -750,7 +784,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
stateObject.AddAmount(value)
// Create a new callable closure
- c := NewClosure(closure, stateObject, stateObject.Code, gas, closure.Price)
+ c := NewClosure(msg, closure, stateObject, stateObject.Code, gas, closure.Price)
// Executer the closure and get the return value (if any)
ret, _, err := c.Call(self, args)
if err != nil {
@@ -765,6 +799,8 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
}
+ msg.Output = ret
+
// Debug hook
if self.Dbg != nil {
self.Dbg.SetCode(closure.Code)
@@ -783,7 +819,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes())
- receiver.AddAmount(closure.object.Amount)
+ receiver.AddAmount(closure.object.Balance)
closure.object.MarkForDeletion()
@@ -837,3 +873,18 @@ func (self *Vm) Endl() *Vm {
return self
}
+
+func ensure256(x *big.Int) {
+ //max, _ := big.NewInt(0).SetString("115792089237316195423570985008687907853269984665640564039457584007913129639936", 0)
+ //if x.Cmp(max) >= 0 {
+ d := big.NewInt(1)
+ d.Lsh(d, 256).Sub(d, big.NewInt(1))
+ x.And(x, d)
+ //}
+
+ // Could have done this with an OR, but big ints are costly.
+
+ if x.Cmp(new(big.Int)) < 0 {
+ x.SetInt64(0)
+ }
+}
diff --git a/ethvm/vm_test.go b/ethvm/vm_test.go
index 501d0c284..5b3a9aef1 100644
--- a/ethvm/vm_test.go
+++ b/ethvm/vm_test.go
@@ -2,14 +2,14 @@ package ethvm
import (
"fmt"
- "github.com/ethereum/eth-go/ethdb"
- "github.com/ethereum/eth-go/ethlog"
- "github.com/ethereum/eth-go/ethstate"
- "github.com/ethereum/eth-go/ethutil"
"log"
"math/big"
"os"
"testing"
+
+ "github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethstate"
+ "github.com/ethereum/eth-go/ethutil"
)
type TestEnv struct {
@@ -27,9 +27,7 @@ func (self TestEnv) State() *ethstate.State { return nil }
func TestVm(t *testing.T) {
ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.LogLevel(4)))
- db, _ := ethdb.NewMemDatabase()
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
- ethutil.Config.Db = db
stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'})
callerClosure := NewClosure(stateObject, stateObject, []byte{0x60, 0x01}, big.NewInt(1000000), big.NewInt(0))