diff options
Diffstat (limited to 'ethvm')
-rw-r--r-- | ethvm/closure.go | 14 | ||||
-rw-r--r-- | ethvm/stack.go | 2 | ||||
-rw-r--r-- | ethvm/vm.go | 89 | ||||
-rw-r--r-- | ethvm/vm_test.go | 10 |
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(ðstate.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(ðstate.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)) |