From 20c742e47406c13ebc6427951f6fcf1b0056ea26 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 18 Oct 2014 13:31:20 +0200 Subject: Moved ethvm => vm --- vm/.ethtest | 0 vm/address.go | 42 +++ vm/asm.go | 45 +++ vm/closure.go | 140 ++++++++ vm/common.go | 66 ++++ vm/debugger.go | 10 + vm/environment.go | 26 ++ vm/execution.go | 93 +++++ vm/stack.go | 162 +++++++++ vm/types.go | 314 +++++++++++++++++ vm/virtual_machine.go | 9 + vm/vm.go | 724 +++++++++++++++++++++++++++++++++++++++ vm/vm_debug.go | 922 ++++++++++++++++++++++++++++++++++++++++++++++++++ vm/vm_test.go | 155 +++++++++ 14 files changed, 2708 insertions(+) create mode 100644 vm/.ethtest create mode 100644 vm/address.go create mode 100644 vm/asm.go create mode 100644 vm/closure.go create mode 100644 vm/common.go create mode 100644 vm/debugger.go create mode 100644 vm/environment.go create mode 100644 vm/execution.go create mode 100644 vm/stack.go create mode 100644 vm/types.go create mode 100644 vm/virtual_machine.go create mode 100644 vm/vm.go create mode 100644 vm/vm_debug.go create mode 100644 vm/vm_test.go (limited to 'vm') diff --git a/vm/.ethtest b/vm/.ethtest new file mode 100644 index 000000000..e69de29bb diff --git a/vm/address.go b/vm/address.go new file mode 100644 index 000000000..cfb7f36d9 --- /dev/null +++ b/vm/address.go @@ -0,0 +1,42 @@ +package vm + +import ( + "math/big" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" +) + +type Address interface { + Call(in []byte) []byte +} + +type PrecompiledAddress struct { + Gas *big.Int + fn func(in []byte) []byte +} + +func (self PrecompiledAddress) Call(in []byte) []byte { + return self.fn(in) +} + +var Precompiled = map[uint64]*PrecompiledAddress{ + 1: &PrecompiledAddress{big.NewInt(500), ecrecoverFunc}, + 2: &PrecompiledAddress{big.NewInt(100), sha256Func}, + 3: &PrecompiledAddress{big.NewInt(100), ripemd160Func}, +} + +func sha256Func(in []byte) []byte { + return ethcrypto.Sha256(in) +} + +func ripemd160Func(in []byte) []byte { + return ethutil.RightPadBytes(ethcrypto.Ripemd160(in), 32) +} + +func ecrecoverFunc(in []byte) []byte { + // In case of an invalid sig. Defaults to return nil + defer func() { recover() }() + + return ethcrypto.Ecrecover(in) +} diff --git a/vm/asm.go b/vm/asm.go new file mode 100644 index 000000000..d081e2b09 --- /dev/null +++ b/vm/asm.go @@ -0,0 +1,45 @@ +package vm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethutil" +) + +func Disassemble(script []byte) (asm []string) { + pc := new(big.Int) + for { + if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 { + return + } + + // Get the memory location of pc + val := script[pc.Int64()] + // Get the opcode (it must be an opcode!) + op := OpCode(val) + + asm = append(asm, fmt.Sprintf("%v", op)) + + switch op { + 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: + pc.Add(pc, ethutil.Big1) + a := int64(op) - int64(PUSH1) + 1 + if int(pc.Int64()+a) > len(script) { + return nil + } + + data := script[pc.Int64() : pc.Int64()+a] + if len(data) == 0 { + data = []byte{0} + } + asm = append(asm, fmt.Sprintf("0x%x", data)) + + pc.Add(pc, big.NewInt(a-1)) + } + + pc.Add(pc, ethutil.Big1) + } + + return +} diff --git a/vm/closure.go b/vm/closure.go new file mode 100644 index 000000000..5a1e1d4d5 --- /dev/null +++ b/vm/closure.go @@ -0,0 +1,140 @@ +package vm + +// 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" +) + +type ClosureRef interface { + ReturnGas(*big.Int, *big.Int) + Address() []byte + Object() *ethstate.StateObject + GetStorage(*big.Int) *ethutil.Value + SetStorage(*big.Int, *ethutil.Value) +} + +// Basic inline closure object which implement the 'closure' interface +type Closure struct { + caller ClosureRef + object *ethstate.StateObject + Code []byte + message *ethstate.Message + exe *Execution + + Gas, UsedGas, Price *big.Int + + Args []byte +} + +// Create a new closure for the given data items +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 + c.Gas = gas //new(big.Int).Set(gas) + // In most cases price and value are pointers to transaction objects + // and we don't want the transaction's values to change. + c.Price = new(big.Int).Set(price) + c.UsedGas = new(big.Int) + + return c +} + +// Retuns the x element in data slice +func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { + m := c.object.GetStorage(x) + if m == nil { + return ethutil.EmptyValue() + } + + return m +} + +func (c *Closure) Get(x *big.Int) *ethutil.Value { + return c.Gets(x, big.NewInt(1)) +} + +func (c *Closure) GetOp(x int) OpCode { + return OpCode(c.GetByte(x)) +} + +func (c *Closure) GetByte(x int) byte { + if x < len(c.Code) { + return c.Code[x] + } + + return 0 +} + +func (c *Closure) GetBytes(x, y int) []byte { + if x >= len(c.Code) || y >= len(c.Code) { + return nil + } + + return c.Code[x : x+y] +} + +func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { + if x.Int64() >= int64(len(c.Code)) || y.Int64() >= int64(len(c.Code)) { + return ethutil.NewValue(0) + } + + partial := c.Code[x.Int64() : x.Int64()+y.Int64()] + + return ethutil.NewValue(partial) +} + +func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { + c.object.SetStorage(x, val) +} + +func (c *Closure) Address() []byte { + return c.object.Address() +} + +func (c *Closure) Call(vm VirtualMachine, args []byte) ([]byte, *big.Int, error) { + c.Args = args + + ret, err := vm.RunClosure(c) + + return ret, c.UsedGas, err +} + +func (c *Closure) Return(ret []byte) []byte { + // Return the remaining gas to the caller + c.caller.ReturnGas(c.Gas, c.Price) + + return ret +} + +func (c *Closure) UseGas(gas *big.Int) bool { + if c.Gas.Cmp(gas) < 0 { + return false + } + + // Sub the amount of gas from the remaining + c.Gas.Sub(c.Gas, gas) + c.UsedGas.Add(c.UsedGas, gas) + + return true +} + +// Implement the caller interface +func (c *Closure) ReturnGas(gas, price *big.Int) { + // Return the gas to the closure + c.Gas.Add(c.Gas, gas) + c.UsedGas.Sub(c.UsedGas, gas) +} + +func (c *Closure) Object() *ethstate.StateObject { + return c.object +} + +func (c *Closure) Caller() ClosureRef { + return c.caller +} diff --git a/vm/common.go b/vm/common.go new file mode 100644 index 000000000..6921b38ff --- /dev/null +++ b/vm/common.go @@ -0,0 +1,66 @@ +package vm + +import ( + "math/big" + + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethutil" +) + +var vmlogger = ethlog.NewLogger("VM") + +type Type int + +const ( + StandardVmTy Type = iota + DebugVmTy + + MaxVmTy +) + +var ( + GasStep = big.NewInt(1) + GasSha = big.NewInt(20) + GasSLoad = big.NewInt(20) + GasSStore = big.NewInt(100) + GasBalance = big.NewInt(20) + GasCreate = big.NewInt(100) + GasCall = big.NewInt(20) + GasMemory = big.NewInt(1) + GasData = big.NewInt(5) + GasTx = big.NewInt(500) + + Pow256 = ethutil.BigPow(2, 256) + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 + + U256 = ethutil.U256 + S256 = ethutil.S256 +) + +const MaxCallDepth = 1024 + +func calcMemSize(off, l *big.Int) *big.Int { + if l.Cmp(ethutil.Big0) == 0 { + return ethutil.Big0 + } + + return new(big.Int).Add(off, l) +} + +// Simple helper +func u256(n int64) *big.Int { + return big.NewInt(n) +} + +// Mainly used for print variables and passing to Print* +func toValue(val *big.Int) interface{} { + // Let's assume a string on right padded zero's + b := val.Bytes() + if b[0] != 0 && b[len(b)-1] == 0x0 && b[len(b)-2] == 0x0 { + return string(b) + } + + return val +} diff --git a/vm/debugger.go b/vm/debugger.go new file mode 100644 index 000000000..fdd5e34e2 --- /dev/null +++ b/vm/debugger.go @@ -0,0 +1,10 @@ +package vm + +import "github.com/ethereum/eth-go/ethstate" + +type Debugger interface { + BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool + StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool + BreakPoints() []int64 + SetCode(byteCode []byte) +} diff --git a/vm/environment.go b/vm/environment.go new file mode 100644 index 000000000..2d933b65c --- /dev/null +++ b/vm/environment.go @@ -0,0 +1,26 @@ +package vm + +import ( + "math/big" + + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +type Environment interface { + State() *ethstate.State + + Origin() []byte + BlockNumber() *big.Int + PrevHash() []byte + Coinbase() []byte + Time() int64 + Difficulty() *big.Int + BlockHash() []byte + GasLimit() *big.Int +} + +type Object interface { + GetStorage(key *big.Int) *ethutil.Value + SetStorage(key *big.Int, value *ethutil.Value) +} diff --git a/vm/execution.go b/vm/execution.go new file mode 100644 index 000000000..6bed43026 --- /dev/null +++ b/vm/execution.go @@ -0,0 +1,93 @@ +package vm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethutil" +) + +type Execution struct { + vm VirtualMachine + address, input []byte + Gas, price, value *big.Int + object *ethstate.StateObject +} + +func NewExecution(vm VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { + return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value} +} + +func (self *Execution) Addr() []byte { + return self.address +} + +func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) { + // Retrieve the executing code + code := self.vm.Env().State().GetCode(codeAddr) + + return self.exec(code, codeAddr, caller) +} + +func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, err error) { + env := self.vm.Env() + + snapshot := env.State().Copy() + defer func() { + if err != nil { + env.State().Set(snapshot) + } + }() + + msg := env.State().Manifest().AddMessage(ðstate.Message{ + To: self.address, From: caller.Address(), + Input: self.input, + Origin: env.Origin(), + Block: env.BlockHash(), Timestamp: env.Time(), Coinbase: env.Coinbase(), Number: env.BlockNumber(), + Value: self.value, + }) + + object := caller.Object() + if object.Balance.Cmp(self.value) < 0 { + caller.ReturnGas(self.Gas, self.price) + + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance) + } else { + stateObject := env.State().GetOrNewStateObject(self.address) + self.object = stateObject + + caller.Object().SubAmount(self.value) + stateObject.AddAmount(self.value) + + // Pre-compiled contracts (address.go) 1, 2 & 3. + naddr := ethutil.BigD(caddr).Uint64() + if p := Precompiled[naddr]; p != nil { + if self.Gas.Cmp(p.Gas) >= 0 { + ret = p.Call(self.input) + self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) + } + } else { + // Create a new callable closure + c := NewClosure(msg, caller, stateObject, code, self.Gas, self.price) + c.exe = self + + if self.vm.Depth() == MaxCallDepth { + c.UseGas(c.Gas) + + return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) + } + + // Executer the closure and get the return value (if any) + ret, _, err = c.Call(self.vm, self.input) + + msg.Output = ret + } + } + + return +} + +func (self *Execution) Create(caller ClosureRef) (ret []byte, err error) { + return self.exec(self.input, nil, caller) +} diff --git a/vm/stack.go b/vm/stack.go new file mode 100644 index 000000000..55fdb6d15 --- /dev/null +++ b/vm/stack.go @@ -0,0 +1,162 @@ +package vm + +import ( + "fmt" + "math" + "math/big" +) + +type OpType int + +const ( + tNorm = iota + tData + tExtro + tCrypto +) + +type TxCallback func(opType OpType) bool + +// Simple push/pop stack mechanism +type Stack struct { + data []*big.Int +} + +func NewStack() *Stack { + return &Stack{} +} + +func (st *Stack) Data() []*big.Int { + return st.data +} + +func (st *Stack) Len() int { + return len(st.data) +} + +func (st *Stack) Pop() *big.Int { + str := st.data[len(st.data)-1] + + copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1]) + st.data = st.data[:len(st.data)-1] + + return str +} + +func (st *Stack) Popn() (*big.Int, *big.Int) { + ints := st.data[len(st.data)-2:] + + copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2]) + st.data = st.data[:len(st.data)-2] + + return ints[0], ints[1] +} + +func (st *Stack) Peek() *big.Int { + str := st.data[len(st.data)-1] + + return str +} + +func (st *Stack) Peekn() (*big.Int, *big.Int) { + ints := st.data[len(st.data)-2:] + + return ints[0], ints[1] +} + +func (st *Stack) Swapn(n int) (*big.Int, *big.Int) { + st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n] + + return st.data[len(st.data)-n], st.data[len(st.data)-1] +} + +func (st *Stack) Dupn(n int) *big.Int { + st.Push(st.data[len(st.data)-n]) + + return st.Peek() +} + +func (st *Stack) Push(d *big.Int) { + st.data = append(st.data, new(big.Int).Set(d)) +} + +func (st *Stack) Get(amount *big.Int) []*big.Int { + // offset + size <= len(data) + length := big.NewInt(int64(len(st.data))) + if amount.Cmp(length) <= 0 { + start := new(big.Int).Sub(length, amount) + return st.data[start.Int64():length.Int64()] + } + + return nil +} + +func (st *Stack) Print() { + fmt.Println("### stack ###") + if len(st.data) > 0 { + for i, val := range st.data { + fmt.Printf("%-3d %v\n", i, val) + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("#############") +} + +type Memory struct { + store []byte +} + +func (m *Memory) Set(offset, size int64, value []byte) { + totSize := offset + size + lenSize := int64(len(m.store) - 1) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff-1) + // Resize slice + m.store = append(m.store, newSlice...) + } + } + copy(m.store[offset:offset+size], value) +} + +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + +func (m *Memory) Get(offset, size int64) []byte { + if len(m.store) > int(offset) { + end := int(math.Min(float64(len(m.store)), float64(offset+size))) + + return m.store[offset:end] + } + + return nil +} + +func (m *Memory) Len() int { + return len(m.store) +} + +func (m *Memory) Data() []byte { + return m.store +} + +func (m *Memory) Print() { + fmt.Printf("### mem %d bytes ###\n", len(m.store)) + if len(m.store) > 0 { + addr := 0 + for i := 0; i+32 <= len(m.store); i += 32 { + fmt.Printf("%03d: % x\n", addr, m.store[i:i+32]) + addr++ + } + } else { + fmt.Println("-- empty --") + } + fmt.Println("####################") +} diff --git a/vm/types.go b/vm/types.go new file mode 100644 index 000000000..5fd92052b --- /dev/null +++ b/vm/types.go @@ -0,0 +1,314 @@ +package vm + +import ( + "fmt" +) + +type OpCode byte + +// Op codes +const ( + // 0x0 range - arithmetic ops + STOP = 0x00 + ADD = 0x01 + MUL = 0x02 + SUB = 0x03 + DIV = 0x04 + SDIV = 0x05 + MOD = 0x06 + SMOD = 0x07 + EXP = 0x08 + NEG = 0x09 + LT = 0x0a + GT = 0x0b + SLT = 0x0c + SGT = 0x0d + EQ = 0x0e + NOT = 0x0f + + // 0x10 range - bit ops + AND = 0x10 + OR = 0x11 + XOR = 0x12 + BYTE = 0x13 + ADDMOD = 0x14 + MULMOD = 0x15 + + // 0x20 range - crypto + SHA3 = 0x20 + + // 0x30 range - closure state + ADDRESS = 0x30 + BALANCE = 0x31 + ORIGIN = 0x32 + CALLER = 0x33 + CALLVALUE = 0x34 + CALLDATALOAD = 0x35 + CALLDATASIZE = 0x36 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3a + EXTCODESIZE = 0x3b + EXTCODECOPY = 0x3c + + // 0x40 range - block operations + PREVHASH = 0x40 + COINBASE = 0x41 + TIMESTAMP = 0x42 + NUMBER = 0x43 + DIFFICULTY = 0x44 + GASLIMIT = 0x45 + + // 0x50 range - 'storage' and execution + POP = 0x50 + //DUP = 0x51 + //SWAP = 0x52 + MLOAD = 0x53 + MSTORE = 0x54 + MSTORE8 = 0x55 + SLOAD = 0x56 + SSTORE = 0x57 + JUMP = 0x58 + JUMPI = 0x59 + PC = 0x5a + MSIZE = 0x5b + GAS = 0x5c + JUMPDEST = 0x5d + + // 0x60 range + PUSH1 = 0x60 + PUSH2 = 0x61 + PUSH3 = 0x62 + PUSH4 = 0x63 + PUSH5 = 0x64 + PUSH6 = 0x65 + PUSH7 = 0x66 + PUSH8 = 0x67 + PUSH9 = 0x68 + PUSH10 = 0x69 + PUSH11 = 0x6a + PUSH12 = 0x6b + PUSH13 = 0x6c + PUSH14 = 0x6d + PUSH15 = 0x6e + PUSH16 = 0x6f + PUSH17 = 0x70 + PUSH18 = 0x71 + PUSH19 = 0x72 + PUSH20 = 0x73 + PUSH21 = 0x74 + PUSH22 = 0x75 + PUSH23 = 0x76 + PUSH24 = 0x77 + PUSH25 = 0x78 + PUSH26 = 0x79 + PUSH27 = 0x7a + PUSH28 = 0x7b + PUSH29 = 0x7c + PUSH30 = 0x7d + PUSH31 = 0x7e + PUSH32 = 0x7f + + DUP1 = 0x80 + DUP2 = 0x81 + DUP3 = 0x82 + DUP4 = 0x83 + DUP5 = 0x84 + DUP6 = 0x85 + DUP7 = 0x86 + DUP8 = 0x87 + DUP9 = 0x88 + DUP10 = 0x89 + DUP11 = 0x8a + DUP12 = 0x8b + DUP13 = 0x8c + DUP14 = 0x8d + DUP15 = 0x8e + DUP16 = 0x8f + + SWAP1 = 0x90 + SWAP2 = 0x91 + SWAP3 = 0x92 + SWAP4 = 0x93 + SWAP5 = 0x94 + SWAP6 = 0x95 + SWAP7 = 0x96 + SWAP8 = 0x97 + SWAP9 = 0x98 + SWAP10 = 0x99 + SWAP11 = 0x9a + SWAP12 = 0x9b + SWAP13 = 0x9c + SWAP14 = 0x9d + SWAP15 = 0x9e + SWAP16 = 0x9f + + // 0xf0 range - closures + CREATE = 0xf0 + CALL = 0xf1 + RETURN = 0xf2 + CALLCODE = 0xf3 + + // 0x70 range - other + LOG = 0xfe // XXX Unofficial + SUICIDE = 0xff +) + +// Since the opcodes aren't all in order we can't use a regular slice +var opCodeToString = map[OpCode]string{ + // 0x0 range - arithmetic ops + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NEG: "NEG", + LT: "LT", + GT: "GT", + SLT: "SLT", + SGT: "SGT", + EQ: "EQ", + NOT: "NOT", + + // 0x10 range - bit ops + AND: "AND", + OR: "OR", + XOR: "XOR", + BYTE: "BYTE", + ADDMOD: "ADDMOD", + MULMOD: "MULMOD", + + // 0x20 range - crypto + SHA3: "SHA3", + + // 0x30 range - closure state + ADDRESS: "ADDRESS", + BALANCE: "BALANCE", + ORIGIN: "ORIGIN", + CALLER: "CALLER", + CALLVALUE: "CALLVALUE", + CALLDATALOAD: "CALLDATALOAD", + CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", + GASPRICE: "TXGASPRICE", + + // 0x40 range - block operations + PREVHASH: "PREVHASH", + COINBASE: "COINBASE", + TIMESTAMP: "TIMESTAMP", + NUMBER: "NUMBER", + DIFFICULTY: "DIFFICULTY", + GASLIMIT: "GASLIMIT", + EXTCODESIZE: "EXTCODESIZE", + EXTCODECOPY: "EXTCODECOPY", + + // 0x50 range - 'storage' and execution + POP: "POP", + //DUP: "DUP", + //SWAP: "SWAP", + MLOAD: "MLOAD", + MSTORE: "MSTORE", + MSTORE8: "MSTORE8", + SLOAD: "SLOAD", + SSTORE: "SSTORE", + JUMP: "JUMP", + JUMPI: "JUMPI", + PC: "PC", + MSIZE: "MSIZE", + GAS: "GAS", + JUMPDEST: "JUMPDEST", + + // 0x60 range - push + PUSH1: "PUSH1", + PUSH2: "PUSH2", + PUSH3: "PUSH3", + PUSH4: "PUSH4", + PUSH5: "PUSH5", + PUSH6: "PUSH6", + PUSH7: "PUSH7", + PUSH8: "PUSH8", + PUSH9: "PUSH9", + PUSH10: "PUSH10", + PUSH11: "PUSH11", + PUSH12: "PUSH12", + PUSH13: "PUSH13", + PUSH14: "PUSH14", + PUSH15: "PUSH15", + PUSH16: "PUSH16", + PUSH17: "PUSH17", + PUSH18: "PUSH18", + PUSH19: "PUSH19", + PUSH20: "PUSH20", + PUSH21: "PUSH21", + PUSH22: "PUSH22", + PUSH23: "PUSH23", + PUSH24: "PUSH24", + PUSH25: "PUSH25", + PUSH26: "PUSH26", + PUSH27: "PUSH27", + PUSH28: "PUSH28", + PUSH29: "PUSH29", + PUSH30: "PUSH30", + PUSH31: "PUSH31", + PUSH32: "PUSH32", + + DUP1: "DUP1", + DUP2: "DUP2", + DUP3: "DUP3", + DUP4: "DUP4", + DUP5: "DUP5", + DUP6: "DUP6", + DUP7: "DUP7", + DUP8: "DUP8", + DUP9: "DUP9", + DUP10: "DUP10", + DUP11: "DUP11", + DUP12: "DUP12", + DUP13: "DUP13", + DUP14: "DUP14", + DUP15: "DUP15", + DUP16: "DUP16", + + SWAP1: "SWAP1", + SWAP2: "SWAP2", + SWAP3: "SWAP3", + SWAP4: "SWAP4", + SWAP5: "SWAP5", + SWAP6: "SWAP6", + SWAP7: "SWAP7", + SWAP8: "SWAP8", + SWAP9: "SWAP9", + SWAP10: "SWAP10", + SWAP11: "SWAP11", + SWAP12: "SWAP12", + SWAP13: "SWAP13", + SWAP14: "SWAP14", + SWAP15: "SWAP15", + SWAP16: "SWAP16", + + // 0xf0 range + CREATE: "CREATE", + CALL: "CALL", + RETURN: "RETURN", + CALLCODE: "CALLCODE", + + // 0x70 range - other + LOG: "LOG", + SUICIDE: "SUICIDE", +} + +func (o OpCode) String() string { + str := opCodeToString[o] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(o)) + } + + return str +} diff --git a/vm/virtual_machine.go b/vm/virtual_machine.go new file mode 100644 index 000000000..cc8cd39a9 --- /dev/null +++ b/vm/virtual_machine.go @@ -0,0 +1,9 @@ +package vm + +type VirtualMachine interface { + Env() Environment + RunClosure(*Closure) ([]byte, error) + Depth() int + Printf(string, ...interface{}) VirtualMachine + Endl() VirtualMachine +} diff --git a/vm/vm.go b/vm/vm.go new file mode 100644 index 000000000..72d4f7131 --- /dev/null +++ b/vm/vm.go @@ -0,0 +1,724 @@ +package vm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" +) + +// BIG FAT WARNING. THIS VM IS NOT YET IS USE! +// I want to get all VM tests pass first before updating this VM + +type Vm struct { + env Environment + err error + depth int +} + +func New(env Environment, typ Type) VirtualMachine { + switch typ { + case DebugVmTy: + return NewDebugVm(env) + default: + return &Vm{env: env} + } +} + +func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { + self.depth++ + + // Recover from any require exception + defer func() { + if r := recover(); r != nil { + ret = closure.Return(nil) + err = fmt.Errorf("%v", r) + } + }() + + // Don't bother with the execution if there's no code. + if len(closure.Code) == 0 { + return closure.Return(nil), nil + } + + var ( + op OpCode + + mem = &Memory{} + stack = NewStack() + pc = 0 + step = 0 + require = func(m int) { + if stack.Len() < m { + panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) + } + } + ) + + for { + // The base for all big integer arithmetic + base := new(big.Int) + + step++ + // Get the memory location of pc + op := closure.GetOp(pc) + + gas := new(big.Int) + addStepGasUsage := func(amount *big.Int) { + gas.Add(gas, amount) + } + + addStepGasUsage(GasStep) + + var newMemSize *big.Int = ethutil.Big0 + switch op { + case STOP: + gas.Set(ethutil.Big0) + case SUICIDE: + gas.Set(ethutil.Big0) + case SLOAD: + gas.Set(GasSLoad) + case SSTORE: + var mult *big.Int + y, x := stack.Peekn() + val := closure.GetStorage(x) + if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { + mult = ethutil.Big2 + } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { + mult = ethutil.Big0 + } else { + mult = ethutil.Big1 + } + gas = new(big.Int).Mul(mult, GasSStore) + case BALANCE: + gas.Set(GasBalance) + case MSTORE: + require(2) + newMemSize = calcMemSize(stack.Peek(), u256(32)) + case MLOAD: + require(1) + + newMemSize = calcMemSize(stack.Peek(), u256(32)) + case MSTORE8: + require(2) + newMemSize = calcMemSize(stack.Peek(), u256(1)) + case RETURN: + require(2) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + case SHA3: + require(2) + + gas.Set(GasSha) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + case CALLDATACOPY: + require(2) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + case CODECOPY: + require(3) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + case EXTCODECOPY: + require(4) + + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) + case CALL, CALLCODE: + require(7) + gas.Set(GasCall) + addStepGasUsage(stack.data[stack.Len()-1]) + + x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) + y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5]) + + newMemSize = ethutil.BigMax(x, y) + case CREATE: + require(3) + gas.Set(GasCreate) + + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) + } + + if newMemSize.Cmp(ethutil.Big0) > 0 { + newMemSize.Add(newMemSize, u256(31)) + newMemSize.Div(newMemSize, u256(32)) + newMemSize.Mul(newMemSize, u256(32)) + + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { + memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) + memGasUsage.Mul(GasMemory, memGasUsage) + memGasUsage.Div(memGasUsage, u256(32)) + + addStepGasUsage(memGasUsage) + } + } + + if !closure.UseGas(gas) { + err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) + + closure.UseGas(closure.Gas) + + return closure.Return(nil), err + } + + mem.Resize(newMemSize.Uint64()) + + switch op { + // 0x20 range + case ADD: + require(2) + x, y := stack.Popn() + + base.Add(y, x) + + U256(base) + + // Pop result back on the stack + stack.Push(base) + case SUB: + require(2) + x, y := stack.Popn() + + base.Sub(y, x) + + U256(base) + + // Pop result back on the stack + stack.Push(base) + case MUL: + require(2) + x, y := stack.Popn() + + base.Mul(y, x) + + U256(base) + + // Pop result back on the stack + stack.Push(base) + case DIV: + require(2) + x, y := stack.Popn() + + if x.Cmp(ethutil.Big0) != 0 { + base.Div(y, x) + } + + U256(base) + + // Pop result back on the stack + stack.Push(base) + case SDIV: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + + if x.Cmp(ethutil.Big0) == 0 { + base.Set(ethutil.Big0) + } else { + n := new(big.Int) + if new(big.Int).Mul(y, x).Cmp(ethutil.Big0) < 0 { + n.SetInt64(-1) + } else { + n.SetInt64(1) + } + + base.Div(y.Abs(y), x.Mul(x.Abs(x), n)) + + U256(base) + } + + stack.Push(base) + case MOD: + require(2) + x, y := stack.Popn() + + base.Mod(y, x) + + U256(base) + + stack.Push(base) + case SMOD: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + + if x.Cmp(ethutil.Big0) == 0 { + base.Set(ethutil.Big0) + } else { + n := new(big.Int) + if y.Cmp(ethutil.Big0) < 0 { + n.SetInt64(-1) + } else { + n.SetInt64(1) + } + + base.Mod(y.Abs(y), x.Mul(x.Abs(x), n)) + + U256(base) + } + + stack.Push(base) + + case EXP: + require(2) + x, y := stack.Popn() + + base.Exp(y, x, Pow256) + + U256(base) + + stack.Push(base) + case NEG: + require(1) + base.Sub(Pow256, stack.Pop()) + + base = U256(base) + + stack.Push(base) + case LT: + require(2) + x, y := stack.Popn() + // x < y + if y.Cmp(x) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case GT: + require(2) + x, y := stack.Popn() + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + case SLT: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + // x < y + if y.Cmp(S256(x)) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case SGT: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + case EQ: + require(2) + x, y := stack.Popn() + + // x == y + if x.Cmp(y) == 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case NOT: + require(1) + x := stack.Pop() + if x.Cmp(ethutil.BigFalse) > 0 { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } + + // 0x10 range + case AND: + require(2) + x, y := stack.Popn() + + stack.Push(base.And(y, x)) + case OR: + require(2) + x, y := stack.Popn() + + stack.Push(base.Or(y, x)) + case XOR: + require(2) + x, y := stack.Popn() + + stack.Push(base.Xor(y, x)) + case BYTE: + require(2) + val, th := stack.Popn() + if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { + byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) + stack.Push(byt) + + } else { + stack.Push(ethutil.BigFalse) + } + case ADDMOD: + require(3) + + x := stack.Pop() + y := stack.Pop() + z := stack.Pop() + + base.Add(x, y) + base.Mod(base, z) + + U256(base) + + stack.Push(base) + case MULMOD: + require(3) + + x := stack.Pop() + y := stack.Pop() + z := stack.Pop() + + base.Mul(x, y) + base.Mod(base, z) + + U256(base) + + stack.Push(base) + + // 0x20 range + case SHA3: + require(2) + size, offset := stack.Popn() + data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64())) + + stack.Push(ethutil.BigD(data)) + + // 0x30 range + case ADDRESS: + stack.Push(ethutil.BigD(closure.Address())) + + case BALANCE: + require(1) + + addr := stack.Pop().Bytes() + balance := self.env.State().GetBalance(addr) + + stack.Push(balance) + + case ORIGIN: + origin := self.env.Origin() + + stack.Push(ethutil.BigD(origin)) + + case CALLER: + caller := closure.caller.Address() + stack.Push(ethutil.BigD(caller)) + + case CALLVALUE: + value := closure.exe.value + + stack.Push(value) + + case CALLDATALOAD: + require(1) + var ( + offset = stack.Pop() + data = make([]byte, 32) + lenData = big.NewInt(int64(len(closure.Args))) + ) + + if lenData.Cmp(offset) >= 0 { + length := new(big.Int).Add(offset, ethutil.Big32) + length = ethutil.BigMin(length, lenData) + + copy(data, closure.Args[offset.Int64():length.Int64()]) + } + + stack.Push(ethutil.BigD(data)) + case CALLDATASIZE: + l := int64(len(closure.Args)) + stack.Push(big.NewInt(l)) + + case CALLDATACOPY: + var ( + size = int64(len(closure.Args)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Args[cOff : cOff+l] + + mem.Set(mOff, l, code) + case CODESIZE, EXTCODESIZE: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + + l := big.NewInt(int64(len(code))) + stack.Push(l) + + case CODECOPY, EXTCODECOPY: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = self.env.State().GetCode(addr) + } else { + code = closure.Code + } + + var ( + size = int64(len(code)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + codeCopy := code[cOff : cOff+l] + + mem.Set(mOff, l, codeCopy) + case GASPRICE: + stack.Push(closure.Price) + + // 0x40 range + case PREVHASH: + prevHash := self.env.PrevHash() + + stack.Push(ethutil.BigD(prevHash)) + + case COINBASE: + coinbase := self.env.Coinbase() + + stack.Push(ethutil.BigD(coinbase)) + + case TIMESTAMP: + time := self.env.Time() + + stack.Push(big.NewInt(time)) + + case NUMBER: + number := self.env.BlockNumber() + + stack.Push(number) + + case DIFFICULTY: + difficulty := self.env.Difficulty() + + stack.Push(difficulty) + + case GASLIMIT: + // TODO + stack.Push(big.NewInt(0)) + + // 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 := int(op - PUSH1 + 1) + val := ethutil.BigD(closure.GetBytes(int(pc+1), a)) + // Push value to stack + stack.Push(val) + + pc += a + + step += int(op) - int(PUSH1) + 1 + case POP: + require(1) + stack.Pop() + case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: + n := int(op - DUP1 + 1) + stack.Dupn(n) + case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: + n := int(op - SWAP1 + 2) + stack.Swapn(n) + + case MLOAD: + require(1) + offset := stack.Pop() + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + case MSTORE: // Store the value at stack top-1 in to memory at location stack top + require(2) + // Pop value of the stack + val, mStart := stack.Popn() + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + case MSTORE8: + require(2) + off := stack.Pop() + val := stack.Pop() + + mem.store[off.Int64()] = byte(val.Int64() & 0xff) + + case SLOAD: + require(1) + loc := stack.Pop() + val := closure.GetStorage(loc) + + stack.Push(val.BigInt()) + + case SSTORE: + require(2) + val, loc := stack.Popn() + closure.SetStorage(loc, ethutil.NewValue(val)) + + closure.message.AddStorageChange(loc.Bytes()) + + case JUMP: + require(1) + pc = int(stack.Pop().Int64()) + // Reduce pc by one because of the increment that's at the end of this for loop + + continue + case JUMPI: + require(2) + cond, pos := stack.Popn() + if cond.Cmp(ethutil.BigTrue) >= 0 { + pc = int(pos.Int64()) + + if closure.GetOp(int(pc)) != JUMPDEST { + return closure.Return(nil), fmt.Errorf("JUMP missed JUMPDEST %v", pc) + } + + continue + } + case JUMPDEST: + case PC: + stack.Push(u256(int64(pc))) + case MSIZE: + stack.Push(big.NewInt(int64(mem.Len()))) + case GAS: + stack.Push(closure.Gas) + // 0x60 range + case CREATE: + require(3) + + var ( + err error + value = stack.Pop() + size, offset = stack.Popn() + input = mem.Get(offset.Int64(), size.Int64()) + gas = new(big.Int).Set(closure.Gas) + + // Snapshot the current stack so we are able to + // revert back to it later. + //snapshot = self.env.State().Copy() + ) + + // Generate a new address + addr := ethcrypto.CreateAddress(closure.Address(), closure.object.Nonce) + closure.object.Nonce++ + + closure.UseGas(closure.Gas) + + msg := NewExecution(self, addr, input, gas, closure.Price, value) + ret, err := msg.Exec(addr, closure) + if err != nil { + stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + //self.env.State().Set(snapshot) + + } else { + msg.object.Code = ret + + stack.Push(ethutil.BigD(addr)) + } + + case CALL, CALLCODE: + require(7) + + gas := stack.Pop() + // Pop gas and value of the stack. + value, addr := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // Pop return size and offset + retSize, retOffset := stack.Popn() + + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) + + //snapshot := self.env.State().Copy() + + var executeAddr []byte + if op == CALLCODE { + executeAddr = closure.Address() + } else { + executeAddr = addr.Bytes() + } + + msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) + ret, err := msg.Exec(addr.Bytes(), closure) + if err != nil { + stack.Push(ethutil.BigFalse) + + //self.env.State().Set(snapshot) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } + + case RETURN: + require(2) + size, offset := stack.Popn() + ret := mem.Get(offset.Int64(), size.Int64()) + + return closure.Return(ret), nil + case SUICIDE: + require(1) + + receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes()) + + receiver.AddAmount(closure.object.Balance) + + closure.object.MarkForDeletion() + + fallthrough + case STOP: // Stop the closure + + return closure.Return(nil), nil + default: + vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) + + //panic(fmt.Sprintf("Invalid opcode %x", op)) + + return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) + } + + pc++ + } +} + +func (self *Vm) Env() Environment { + return self.env +} + +func (self *Vm) Depth() int { + return self.depth +} + +func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine { return self } +func (self *Vm) Endl() VirtualMachine { return self } diff --git a/vm/vm_debug.go b/vm/vm_debug.go new file mode 100644 index 000000000..785e699c7 --- /dev/null +++ b/vm/vm_debug.go @@ -0,0 +1,922 @@ +package vm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethutil" +) + +type DebugVm struct { + env Environment + + logTy byte + logStr string + + err error + + // Debugging + Dbg Debugger + + BreakPoints []int64 + Stepping bool + Fn string + + Recoverable bool + + depth int +} + +func NewDebugVm(env Environment) *DebugVm { + lt := LogTyPretty + if ethutil.Config.Diff { + lt = LogTyDiff + } + + return &DebugVm{env: env, logTy: lt, Recoverable: true} +} + +func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { + self.depth++ + + var ( + op OpCode + + mem = &Memory{} + stack = NewStack() + pc = big.NewInt(0) + step = 0 + prevStep = 0 + state = self.env.State() + require = func(m int) { + if stack.Len() < m { + panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) + } + } + + jump = func(pos *big.Int) { + p := int(pos.Int64()) + + self.Printf(" ~> %v", pos) + // Return to start + if p == 0 { + pc = big.NewInt(0) + } else { + nop := OpCode(closure.GetOp(p - 1)) + if nop != JUMPDEST { + panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) + } + + pc = pos + } + + self.Endl() + } + ) + + if self.Recoverable { + // Recover from any require exception + defer func() { + if r := recover(); r != nil { + self.Endl() + + ret = closure.Return(nil) + err = fmt.Errorf("%v", r) + } + }() + } + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + + // Don't bother with the execution if there's no code. + if len(closure.Code) == 0 { + return closure.Return(nil), nil + } + + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", self.Fn, closure.Address(), closure.Gas, closure.Args) + + for { + prevStep = step + // The base for all big integer arithmetic + base := new(big.Int) + + step++ + // Get the memory location of pc + op := OpCode(closure.Get(pc).Uint()) + + // XXX Leave this Println intact. Don't change this to the log system. + // Used for creating diffs between implementations + if self.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + state.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } + + 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()) + } + + gas := new(big.Int) + addStepGasUsage := func(amount *big.Int) { + if amount.Cmp(ethutil.Big0) >= 0 { + gas.Add(gas, amount) + } + } + + addStepGasUsage(GasStep) + + var newMemSize *big.Int = ethutil.Big0 + switch op { + case STOP: + gas.Set(ethutil.Big0) + case SUICIDE: + gas.Set(ethutil.Big0) + case SLOAD: + gas.Set(GasSLoad) + case SSTORE: + var mult *big.Int + y, x := stack.Peekn() + val := closure.GetStorage(x) + if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { + mult = ethutil.Big2 + } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { + mult = ethutil.Big0 + } else { + mult = ethutil.Big1 + } + gas = new(big.Int).Mul(mult, GasSStore) + case BALANCE: + gas.Set(GasBalance) + case MSTORE: + require(2) + newMemSize = calcMemSize(stack.Peek(), u256(32)) + case MLOAD: + require(1) + + newMemSize = calcMemSize(stack.Peek(), u256(32)) + case MSTORE8: + require(2) + newMemSize = calcMemSize(stack.Peek(), u256(1)) + case RETURN: + require(2) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + case SHA3: + require(2) + + gas.Set(GasSha) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + case CALLDATACOPY: + require(2) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + case CODECOPY: + require(3) + + newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + case EXTCODECOPY: + require(4) + + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) + case CALL, CALLCODE: + require(7) + gas.Set(GasCall) + addStepGasUsage(stack.data[stack.Len()-1]) + + x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) + y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5]) + + newMemSize = ethutil.BigMax(x, y) + case CREATE: + require(3) + gas.Set(GasCreate) + + newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) + } + + if newMemSize.Cmp(ethutil.Big0) > 0 { + newMemSize.Add(newMemSize, u256(31)) + newMemSize.Div(newMemSize, u256(32)) + newMemSize.Mul(newMemSize, u256(32)) + + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { + memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) + memGasUsage.Mul(GasMemory, memGasUsage) + memGasUsage.Div(memGasUsage, u256(32)) + + addStepGasUsage(memGasUsage) + } + } + + self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) + self.Printf(" (g) %-3v (%v)", gas, closure.Gas) + + if !closure.UseGas(gas) { + self.Endl() + + err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) + + closure.UseGas(closure.Gas) + + return closure.Return(nil), err + } + + mem.Resize(newMemSize.Uint64()) + + switch op { + case LOG: + stack.Print() + mem.Print() + // 0x20 range + case ADD: + require(2) + x, y := stack.Popn() + self.Printf(" %v + %v", y, x) + + base.Add(y, x) + + U256(base) + + self.Printf(" = %v", base) + // Pop result back on the stack + stack.Push(base) + case SUB: + require(2) + x, y := stack.Popn() + self.Printf(" %v - %v", y, x) + + base.Sub(y, x) + + U256(base) + + self.Printf(" = %v", base) + // Pop result back on the stack + stack.Push(base) + case MUL: + require(2) + x, y := stack.Popn() + self.Printf(" %v * %v", y, x) + + base.Mul(y, x) + + U256(base) + + self.Printf(" = %v", base) + // Pop result back on the stack + stack.Push(base) + case DIV: + require(2) + x, y := stack.Pop(), stack.Pop() + self.Printf(" %v / %v", x, y) + + if y.Cmp(ethutil.Big0) != 0 { + base.Div(x, y) + } + + U256(base) + + self.Printf(" = %v", base) + // Pop result back on the stack + stack.Push(base) + case SDIV: + require(2) + x, y := S256(stack.Pop()), S256(stack.Pop()) + + self.Printf(" %v / %v", x, y) + + if y.Cmp(ethutil.Big0) == 0 { + base.Set(ethutil.Big0) + } else { + n := new(big.Int) + if new(big.Int).Mul(x, y).Cmp(ethutil.Big0) < 0 { + n.SetInt64(-1) + } else { + n.SetInt64(1) + } + + base.Div(x.Abs(x), y.Abs(y)).Mul(base, n) + + U256(base) + } + + self.Printf(" = %v", base) + stack.Push(base) + case MOD: + require(2) + x, y := stack.Pop(), stack.Pop() + + self.Printf(" %v %% %v", x, y) + + if y.Cmp(ethutil.Big0) == 0 { + base.Set(ethutil.Big0) + } else { + base.Mod(x, y) + } + + U256(base) + + self.Printf(" = %v", base) + stack.Push(base) + case SMOD: + require(2) + x, y := S256(stack.Pop()), S256(stack.Pop()) + + self.Printf(" %v %% %v", x, y) + + if y.Cmp(ethutil.Big0) == 0 { + base.Set(ethutil.Big0) + } else { + n := new(big.Int) + if x.Cmp(ethutil.Big0) < 0 { + n.SetInt64(-1) + } else { + n.SetInt64(1) + } + + base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n) + + U256(base) + } + + self.Printf(" = %v", base) + stack.Push(base) + + case EXP: + require(2) + x, y := stack.Popn() + + self.Printf(" %v ** %v", y, x) + + base.Exp(y, x, Pow256) + + U256(base) + + self.Printf(" = %v", base) + + stack.Push(base) + case NEG: + require(1) + base.Sub(Pow256, stack.Pop()) + + base = U256(base) + + stack.Push(base) + case LT: + require(2) + x, y := stack.Popn() + self.Printf(" %v < %v", y, x) + // x < y + if y.Cmp(x) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case GT: + require(2) + x, y := stack.Popn() + self.Printf(" %v > %v", y, x) + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + case SLT: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + self.Printf(" %v < %v", y, x) + // x < y + if y.Cmp(S256(x)) < 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case SGT: + require(2) + y, x := S256(stack.Pop()), S256(stack.Pop()) + self.Printf(" %v > %v", y, x) + + // x > y + if y.Cmp(x) > 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + + case EQ: + require(2) + x, y := stack.Popn() + self.Printf(" %v == %v", y, x) + + // x == y + if x.Cmp(y) == 0 { + stack.Push(ethutil.BigTrue) + } else { + stack.Push(ethutil.BigFalse) + } + case NOT: + require(1) + x := stack.Pop() + if x.Cmp(ethutil.BigFalse) > 0 { + stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) + } + + // 0x10 range + case AND: + require(2) + x, y := stack.Popn() + self.Printf(" %v & %v", y, x) + + stack.Push(base.And(y, x)) + case OR: + require(2) + x, y := stack.Popn() + self.Printf(" %v | %v", y, x) + + stack.Push(base.Or(y, x)) + case XOR: + require(2) + x, y := stack.Popn() + self.Printf(" %v ^ %v", y, x) + + stack.Push(base.Xor(y, x)) + case BYTE: + require(2) + val, th := stack.Popn() + + if th.Cmp(big.NewInt(32)) < 0 { + byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) + + base.Set(byt) + } else { + base.Set(ethutil.BigFalse) + } + + self.Printf(" => 0x%x", base.Bytes()) + + stack.Push(base) + case ADDMOD: + require(3) + + x := stack.Pop() + y := stack.Pop() + z := stack.Pop() + + base.Add(x, y) + base.Mod(base, z) + + U256(base) + + self.Printf(" = %v", base) + + stack.Push(base) + case MULMOD: + require(3) + + x := stack.Pop() + y := stack.Pop() + z := stack.Pop() + + base.Mul(x, y) + base.Mod(base, z) + + U256(base) + + self.Printf(" = %v", base) + + stack.Push(base) + + // 0x20 range + case SHA3: + require(2) + size, offset := stack.Popn() + data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64())) + + stack.Push(ethutil.BigD(data)) + + self.Printf(" => %x", data) + // 0x30 range + case ADDRESS: + stack.Push(ethutil.BigD(closure.Address())) + + self.Printf(" => %x", closure.Address()) + case BALANCE: + require(1) + + addr := stack.Pop().Bytes() + balance := state.GetBalance(addr) + + stack.Push(balance) + + self.Printf(" => %v (%x)", balance, addr) + case ORIGIN: + origin := self.env.Origin() + + stack.Push(ethutil.BigD(origin)) + + self.Printf(" => %x", origin) + case CALLER: + caller := closure.caller.Address() + stack.Push(ethutil.BigD(caller)) + + self.Printf(" => %x", caller) + case CALLVALUE: + value := closure.exe.value + + stack.Push(value) + + self.Printf(" => %v", value) + case CALLDATALOAD: + require(1) + var ( + offset = stack.Pop() + data = make([]byte, 32) + lenData = big.NewInt(int64(len(closure.Args))) + ) + + if lenData.Cmp(offset) >= 0 { + length := new(big.Int).Add(offset, ethutil.Big32) + length = ethutil.BigMin(length, lenData) + + copy(data, closure.Args[offset.Int64():length.Int64()]) + } + + self.Printf(" => 0x%x", data) + + stack.Push(ethutil.BigD(data)) + case CALLDATASIZE: + l := int64(len(closure.Args)) + stack.Push(big.NewInt(l)) + + self.Printf(" => %d", l) + case CALLDATACOPY: + var ( + size = int64(len(closure.Args)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Args[cOff : cOff+l] + + mem.Set(mOff, l, code) + case CODESIZE, EXTCODESIZE: + var code []byte + if op == EXTCODESIZE { + addr := stack.Pop().Bytes() + + code = state.GetCode(addr) + } else { + code = closure.Code + } + + l := big.NewInt(int64(len(code))) + stack.Push(l) + + self.Printf(" => %d", l) + case CODECOPY, EXTCODECOPY: + var code []byte + if op == EXTCODECOPY { + addr := stack.Pop().Bytes() + + code = state.GetCode(addr) + } else { + code = closure.Code + } + + var ( + size = int64(len(code)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + codeCopy := code[cOff : cOff+l] + + mem.Set(mOff, l, codeCopy) + case GASPRICE: + stack.Push(closure.Price) + + self.Printf(" => %v", closure.Price) + + // 0x40 range + case PREVHASH: + prevHash := self.env.PrevHash() + + stack.Push(ethutil.BigD(prevHash)) + + self.Printf(" => 0x%x", prevHash) + case COINBASE: + coinbase := self.env.Coinbase() + + stack.Push(ethutil.BigD(coinbase)) + + self.Printf(" => 0x%x", coinbase) + case TIMESTAMP: + time := self.env.Time() + + stack.Push(big.NewInt(time)) + + self.Printf(" => 0x%x", time) + case NUMBER: + number := self.env.BlockNumber() + + stack.Push(number) + + self.Printf(" => 0x%x", number.Bytes()) + case DIFFICULTY: + difficulty := self.env.Difficulty() + + stack.Push(difficulty) + + self.Printf(" => 0x%x", difficulty.Bytes()) + case GASLIMIT: + stack.Push(self.env.GasLimit()) + + // 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 := big.NewInt(int64(op) - int64(PUSH1) + 1) + pc.Add(pc, ethutil.Big1) + data := closure.Gets(pc, a) + val := ethutil.BigD(data.Bytes()) + // Push value to stack + stack.Push(val) + pc.Add(pc, a.Sub(a, big.NewInt(1))) + + step += int(op) - int(PUSH1) + 1 + + self.Printf(" => 0x%x", data.Bytes()) + case POP: + require(1) + stack.Pop() + case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: + n := int(op - DUP1 + 1) + v := stack.Dupn(n) + + self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) + + if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { + fmt.Println(toValue(v)) + } + case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: + n := int(op - SWAP1 + 2) + x, y := stack.Swapn(n) + + self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) + case MLOAD: + require(1) + offset := stack.Pop() + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + self.Printf(" => 0x%x", val.Bytes()) + case MSTORE: // Store the value at stack top-1 in to memory at location stack top + require(2) + // Pop value of the stack + val, mStart := stack.Popn() + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + + self.Printf(" => 0x%x", val) + case MSTORE8: + require(2) + off := stack.Pop() + val := stack.Pop() + + mem.store[off.Int64()] = byte(val.Int64() & 0xff) + + self.Printf(" => [%v] 0x%x", off, val) + case SLOAD: + require(1) + loc := stack.Pop() + val := ethutil.BigD(state.GetState(closure.Address(), loc.Bytes())) + stack.Push(val) + + self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + case SSTORE: + require(2) + val, loc := stack.Popn() + state.SetState(closure.Address(), loc.Bytes(), val) + + // Debug sessions are allowed to run without message + if closure.message != nil { + closure.message.AddStorageChange(loc.Bytes()) + } + + self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) + case JUMP: + require(1) + + jump(stack.Pop()) + + continue + case JUMPI: + require(2) + cond, pos := stack.Popn() + + if cond.Cmp(ethutil.BigTrue) >= 0 { + jump(pos) + + continue + } + + case JUMPDEST: + case PC: + stack.Push(pc) + case MSIZE: + stack.Push(big.NewInt(int64(mem.Len()))) + case GAS: + stack.Push(closure.Gas) + // 0x60 range + case CREATE: + require(3) + + var ( + err error + value = stack.Pop() + size, offset = stack.Popn() + input = mem.Get(offset.Int64(), size.Int64()) + gas = new(big.Int).Set(closure.Gas) + + // Snapshot the current stack so we are able to + // revert back to it later. + //snapshot = self.env.State().Copy() + ) + + // Generate a new address + n := state.GetNonce(closure.Address()) + addr := ethcrypto.CreateAddress(closure.Address(), n) + state.SetNonce(closure.Address(), n+1) + + self.Printf(" (*) %x", addr).Endl() + + closure.UseGas(closure.Gas) + + msg := NewExecution(self, addr, input, gas, closure.Price, value) + ret, err := msg.Create(closure) + if err != nil { + stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + //self.env.State().Set(snapshot) + + self.Printf("CREATE err %v", err) + } else { + msg.object.Code = ret + + stack.Push(ethutil.BigD(addr)) + } + + self.Endl() + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + case CALL, CALLCODE: + require(7) + + self.Endl() + + gas := stack.Pop() + // Pop gas and value of the stack. + value, addr := stack.Popn() + // Pop input size and offset + inSize, inOffset := stack.Popn() + // Pop return size and offset + retSize, retOffset := stack.Popn() + + // Get the arguments from the memory + args := mem.Get(inOffset.Int64(), inSize.Int64()) + + var executeAddr []byte + if op == CALLCODE { + executeAddr = closure.Address() + } else { + executeAddr = addr.Bytes() + } + + msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) + ret, err := msg.Exec(addr.Bytes(), closure) + if err != nil { + stack.Push(ethutil.BigFalse) + + vmlogger.Debugln(err) + } else { + stack.Push(ethutil.BigTrue) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } + self.Printf("resume %x", closure.Address()) + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + + case RETURN: + require(2) + size, offset := stack.Popn() + ret := mem.Get(offset.Int64(), size.Int64()) + + self.Printf(" => (%d) 0x%x", len(ret), ret).Endl() + + return closure.Return(ret), nil + case SUICIDE: + require(1) + + receiver := state.GetOrNewStateObject(stack.Pop().Bytes()) + + receiver.AddAmount(state.GetBalance(closure.Address())) + state.Delete(closure.Address()) + + fallthrough + case STOP: // Stop the closure + self.Endl() + + return closure.Return(nil), nil + default: + vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) + + //panic(fmt.Sprintf("Invalid opcode %x", op)) + closure.ReturnGas(big.NewInt(1), nil) + + return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) + } + + pc.Add(pc, ethutil.Big1) + + self.Endl() + + if self.Dbg != nil { + for _, instrNo := range self.Dbg.BreakPoints() { + if pc.Cmp(big.NewInt(instrNo)) == 0 { + self.Stepping = true + + if !self.Dbg.BreakHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) { + return nil, nil + } + } else if self.Stepping { + if !self.Dbg.StepHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) { + return nil, nil + } + } + } + } + + } +} + +func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine { + if self.logTy == LogTyPretty { + self.logStr += fmt.Sprintf(format, v...) + } + + return self +} + +func (self *DebugVm) Endl() VirtualMachine { + if self.logTy == LogTyPretty { + vmlogger.Debugln(self.logStr) + self.logStr = "" + } + + return self +} + +func (self *DebugVm) Env() Environment { + return self.env +} + +func (self *DebugVm) Depth() int { + return self.depth +} diff --git a/vm/vm_test.go b/vm/vm_test.go new file mode 100644 index 000000000..047b76121 --- /dev/null +++ b/vm/vm_test.go @@ -0,0 +1,155 @@ +package vm + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "math/big" + "os" + "testing" + + "github.com/ethereum/eth-go/ethcrypto" + "github.com/ethereum/eth-go/ethlog" + "github.com/ethereum/eth-go/ethstate" + "github.com/ethereum/eth-go/ethtrie" + "github.com/ethereum/eth-go/ethutil" +) + +type TestEnv struct { +} + +func (self TestEnv) Origin() []byte { return nil } +func (self TestEnv) BlockNumber() *big.Int { return nil } +func (self TestEnv) BlockHash() []byte { return nil } +func (self TestEnv) PrevHash() []byte { return nil } +func (self TestEnv) Coinbase() []byte { return nil } +func (self TestEnv) Time() int64 { return 0 } +func (self TestEnv) Difficulty() *big.Int { return nil } +func (self TestEnv) Value() *big.Int { return nil } + +// This is likely to fail if anything ever gets looked up in the state trie :-) +func (self TestEnv) State() *ethstate.State { return ethstate.New(ethtrie.New(nil, "")) } + +const mutcode = ` +var x = 0; +for i := 0; i < 10; i++ { + x = i +} + +return x` + +func setup(level ethlog.LogLevel, typ Type) (*Closure, VirtualMachine) { + code, err := ethutil.Compile(mutcode, true) + if err != nil { + log.Fatal(err) + } + + // Pipe output to /dev/null + ethlog.AddLogSystem(ethlog.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) + + return callerClosure, New(TestEnv{}, typ) +} + +func TestDebugVm(t *testing.T) { + closure, vm := setup(ethlog.DebugLevel, DebugVmTy) + ret, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println("error", e) + } + + if ret[len(ret)-1] != 9 { + t.Errorf("Expected VM to return 9, got", ret, "instead.") + } +} + +func TestVm(t *testing.T) { + closure, vm := setup(ethlog.DebugLevel, StandardVmTy) + ret, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println("error", e) + } + + if ret[len(ret)-1] != 9 { + t.Errorf("Expected VM to return 9, got", ret, "instead.") + } +} + +func BenchmarkDebugVm(b *testing.B) { + closure, vm := setup(ethlog.InfoLevel, DebugVmTy) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + closure.Call(vm, nil) + } +} + +func BenchmarkVm(b *testing.B) { + closure, vm := setup(ethlog.InfoLevel, StandardVmTy) + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + closure.Call(vm, nil) + } +} + +func RunCode(mutCode string, typ Type) []byte { + code, err := ethutil.Compile(mutCode, true) + if err != nil { + log.Fatal(err) + } + + ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.InfoLevel)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) + + vm := New(TestEnv{}, typ) + ret, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println(e) + } + + return ret +} + +func TestBuildInSha256(t *testing.T) { + ret := RunCode(` + var in = 42 + var out = 0 + + call(0x2, 0, 10000, in, out) + + return out + `, DebugVmTy) + + exp := ethcrypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) + if bytes.Compare(ret, exp) != 0 { + t.Errorf("Expected %x, got %x", exp, ret) + } +} + +func TestBuildInRipemd(t *testing.T) { + ret := RunCode(` + var in = 42 + var out = 0 + + call(0x3, 0, 10000, in, out) + + return out + `, DebugVmTy) + + exp := ethutil.RightPadBytes(ethcrypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) + if bytes.Compare(ret, exp) != 0 { + t.Errorf("Expected %x, got %x", exp, ret) + } +} -- cgit v1.2.3 From 097ba56df59293f9225a8ecdc9e1c43a5ad891bb Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 20 Oct 2014 11:53:11 +0200 Subject: Renamed block_chain to chain_manager --- vm/vm_debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 785e699c7..8773df087 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -97,7 +97,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(nil), nil } - vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", self.Fn, closure.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, closure.Args) for { prevStep = step -- cgit v1.2.3 From b5beb1aac11af92bfe0f3ed7560b9eb08495ed09 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 22 Oct 2014 15:22:21 +0200 Subject: added a transfer method to vm env --- vm/environment.go | 20 ++++++++++++++++++++ vm/execution.go | 16 ++++++++-------- vm/vm.go | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index 2d933b65c..23b46c5df 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -1,6 +1,7 @@ package vm import ( + "errors" "math/big" "github.com/ethereum/eth-go/ethstate" @@ -18,9 +19,28 @@ type Environment interface { Difficulty() *big.Int BlockHash() []byte GasLimit() *big.Int + Transfer(from, to Account, amount *big.Int) error } type Object interface { GetStorage(key *big.Int) *ethutil.Value SetStorage(key *big.Int, value *ethutil.Value) } + +type Account interface { + SubBalance(amount *big.Int) + AddBalance(amount *big.Int) + Balance() *big.Int +} + +// generic transfer method +func Transfer(from, to Account, amount *big.Int) error { + if from.Balance().Cmp(amount) < 0 { + return errors.New("Insufficient balance in account") + } + + from.SubBalance(amount) + to.AddBalance(amount) + + return nil +} diff --git a/vm/execution.go b/vm/execution.go index 6bed43026..4c4bd1e3c 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -48,17 +48,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, Value: self.value, }) - object := caller.Object() - if object.Balance.Cmp(self.value) < 0 { + from, to := caller.Object(), env.State().GetOrNewStateObject(self.address) + err = env.Transfer(from, to, self.value) + if err != nil { caller.ReturnGas(self.Gas, self.price) - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, object.Balance) + err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) } else { - stateObject := env.State().GetOrNewStateObject(self.address) - self.object = stateObject + self.object = to - caller.Object().SubAmount(self.value) - stateObject.AddAmount(self.value) + //caller.Object().SubAmount(self.value) + //stateObject.AddAmount(self.value) // Pre-compiled contracts (address.go) 1, 2 & 3. naddr := ethutil.BigD(caddr).Uint64() @@ -69,7 +69,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, } } else { // Create a new callable closure - c := NewClosure(msg, caller, stateObject, code, self.Gas, self.price) + c := NewClosure(msg, caller, to, code, self.Gas, self.price) c.exe = self if self.vm.Depth() == MaxCallDepth { diff --git a/vm/vm.go b/vm/vm.go index 72d4f7131..b5c7c0e21 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -692,7 +692,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes()) - receiver.AddAmount(closure.object.Balance) + receiver.AddAmount(closure.object.Balance()) closure.object.MarkForDeletion() -- cgit v1.2.3 From 51ecab6967a15b82f9285cd0ffd3352607dc8612 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 22 Oct 2014 23:39:15 +0200 Subject: Do not set error on recover --- vm/vm_debug.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 8773df087..acdeb4be9 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -82,7 +82,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Endl() ret = closure.Return(nil) - err = fmt.Errorf("%v", r) + // No error should be set. Recover is used with require + // Is this too error prone? } }() } @@ -106,7 +107,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { step++ // Get the memory location of pc - op := OpCode(closure.Get(pc).Uint()) + op = OpCode(closure.Get(pc).Uint()) // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations -- cgit v1.2.3 From 29b8a0bc5ffa7a674a06a211e1c8bdd1b6ed07b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 01:01:26 +0200 Subject: Updated the VM & VM tests * Stack Error shouldn't revert to previous state * Updated VM Test tool * Added Transfer method to VM Env --- vm/common.go | 2 +- vm/execution.go | 14 +++++++------- vm/types.go | 2 -- vm/vm.go | 4 ---- vm/vm_debug.go | 5 +---- 5 files changed, 9 insertions(+), 18 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 6921b38ff..3d9f57290 100644 --- a/vm/common.go +++ b/vm/common.go @@ -39,7 +39,7 @@ var ( S256 = ethutil.S256 ) -const MaxCallDepth = 1024 +const MaxCallDepth = 1025 func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(ethutil.Big0) == 0 { diff --git a/vm/execution.go b/vm/execution.go index 4c4bd1e3c..bd174d64e 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -13,6 +13,7 @@ type Execution struct { address, input []byte Gas, price, value *big.Int object *ethstate.StateObject + SkipTransfer bool } func NewExecution(vm VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { @@ -49,17 +50,17 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, }) from, to := caller.Object(), env.State().GetOrNewStateObject(self.address) - err = env.Transfer(from, to, self.value) + // Skipping transfer is used on testing for the initial call + if !self.SkipTransfer { + err = env.Transfer(from, to, self.value) + } + if err != nil { caller.ReturnGas(self.Gas, self.price) err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) } else { self.object = to - - //caller.Object().SubAmount(self.value) - //stateObject.AddAmount(self.value) - // Pre-compiled contracts (address.go) 1, 2 & 3. naddr := ethutil.BigD(caddr).Uint64() if p := Precompiled[naddr]; p != nil { @@ -73,14 +74,13 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, c.exe = self if self.vm.Depth() == MaxCallDepth { - c.UseGas(c.Gas) + c.UseGas(self.Gas) return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) } // Executer the closure and get the return value (if any) ret, _, err = c.Call(self.vm, self.input) - msg.Output = ret } } diff --git a/vm/types.go b/vm/types.go index 5fd92052b..6fb9a5c95 100644 --- a/vm/types.go +++ b/vm/types.go @@ -151,7 +151,6 @@ const ( CALLCODE = 0xf3 // 0x70 range - other - LOG = 0xfe // XXX Unofficial SUICIDE = 0xff ) @@ -300,7 +299,6 @@ var opCodeToString = map[OpCode]string{ CALLCODE: "CALLCODE", // 0x70 range - other - LOG: "LOG", SUICIDE: "SUICIDE", } diff --git a/vm/vm.go b/vm/vm.go index b5c7c0e21..1a7a40a36 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -660,8 +660,6 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - //snapshot := self.env.State().Copy() - var executeAddr []byte if op == CALLCODE { executeAddr = closure.Address() @@ -673,8 +671,6 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) - - //self.env.State().Set(snapshot) } else { stack.Push(ethutil.BigTrue) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index acdeb4be9..ba1781109 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -237,10 +237,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { mem.Resize(newMemSize.Uint64()) switch op { - case LOG: - stack.Print() - mem.Print() - // 0x20 range + // 0x20 range case ADD: require(2) x, y := stack.Popn() -- cgit v1.2.3 From 06aa74e7df49969fc181ecfcf5652263d74624f5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 10:14:55 +0200 Subject: All Stack requirements are now checked prior to reduring gas. --- vm/vm_debug.go | 56 +++++++++++++++++++------------------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ba1781109..fe004046c 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -138,13 +138,31 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { addStepGasUsage(GasStep) var newMemSize *big.Int = ethutil.Big0 + // Stack Check, memory resize & gas phase switch op { + // Stack checks only + case NOT, CALLDATALOAD, POP, JUMP, NEG: // 1 + require(1) + case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 + require(2) + case ADDMOD, MULMOD: // 3 + require(3) + case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: + n := int(op - SWAP1 + 2) + require(n) + case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: + n := int(op - DUP1 + 1) + require(n) + // Gas only case STOP: gas.Set(ethutil.Big0) case SUICIDE: + require(1) + gas.Set(ethutil.Big0) case SLOAD: gas.Set(GasSLoad) + // Memory resize & Gas case SSTORE: var mult *big.Int y, x := stack.Peekn() @@ -158,6 +176,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } gas = new(big.Int).Mul(mult, GasSStore) case BALANCE: + require(1) gas.Set(GasBalance) case MSTORE: require(2) @@ -239,7 +258,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { switch op { // 0x20 range case ADD: - require(2) x, y := stack.Popn() self.Printf(" %v + %v", y, x) @@ -251,7 +269,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Pop result back on the stack stack.Push(base) case SUB: - require(2) x, y := stack.Popn() self.Printf(" %v - %v", y, x) @@ -263,7 +280,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Pop result back on the stack stack.Push(base) case MUL: - require(2) x, y := stack.Popn() self.Printf(" %v * %v", y, x) @@ -275,7 +291,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Pop result back on the stack stack.Push(base) case DIV: - require(2) x, y := stack.Pop(), stack.Pop() self.Printf(" %v / %v", x, y) @@ -289,7 +304,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Pop result back on the stack stack.Push(base) case SDIV: - require(2) x, y := S256(stack.Pop()), S256(stack.Pop()) self.Printf(" %v / %v", x, y) @@ -312,7 +326,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) case MOD: - require(2) x, y := stack.Pop(), stack.Pop() self.Printf(" %v %% %v", x, y) @@ -328,7 +341,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) case SMOD: - require(2) x, y := S256(stack.Pop()), S256(stack.Pop()) self.Printf(" %v %% %v", x, y) @@ -352,7 +364,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(base) case EXP: - require(2) x, y := stack.Popn() self.Printf(" %v ** %v", y, x) @@ -365,14 +376,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(base) case NEG: - require(1) base.Sub(Pow256, stack.Pop()) base = U256(base) stack.Push(base) case LT: - require(2) x, y := stack.Popn() self.Printf(" %v < %v", y, x) // x < y @@ -382,7 +391,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } case GT: - require(2) x, y := stack.Popn() self.Printf(" %v > %v", y, x) @@ -394,7 +402,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } case SLT: - require(2) y, x := S256(stack.Pop()), S256(stack.Pop()) self.Printf(" %v < %v", y, x) // x < y @@ -404,7 +411,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } case SGT: - require(2) y, x := S256(stack.Pop()), S256(stack.Pop()) self.Printf(" %v > %v", y, x) @@ -416,7 +422,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } case EQ: - require(2) x, y := stack.Popn() self.Printf(" %v == %v", y, x) @@ -427,7 +432,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigFalse) } case NOT: - require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) @@ -437,25 +441,21 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0x10 range case AND: - require(2) x, y := stack.Popn() self.Printf(" %v & %v", y, x) stack.Push(base.And(y, x)) case OR: - require(2) x, y := stack.Popn() self.Printf(" %v | %v", y, x) stack.Push(base.Or(y, x)) case XOR: - require(2) x, y := stack.Popn() self.Printf(" %v ^ %v", y, x) stack.Push(base.Xor(y, x)) case BYTE: - require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { @@ -470,7 +470,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(base) case ADDMOD: - require(3) x := stack.Pop() y := stack.Pop() @@ -485,7 +484,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(base) case MULMOD: - require(3) x := stack.Pop() y := stack.Pop() @@ -502,7 +500,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0x20 range case SHA3: - require(2) size, offset := stack.Popn() data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64())) @@ -515,7 +512,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %x", closure.Address()) case BALANCE: - require(1) addr := stack.Pop().Bytes() balance := state.GetBalance(addr) @@ -541,7 +537,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %v", value) case CALLDATALOAD: - require(1) var ( offset = stack.Pop() data = make([]byte, 32) @@ -675,7 +670,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => 0x%x", data.Bytes()) case POP: - require(1) stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) @@ -692,21 +686,18 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) case MLOAD: - require(1) offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) stack.Push(val) self.Printf(" => 0x%x", val.Bytes()) case MSTORE: // Store the value at stack top-1 in to memory at location stack top - require(2) // Pop value of the stack val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) self.Printf(" => 0x%x", val) case MSTORE8: - require(2) off := stack.Pop() val := stack.Pop() @@ -714,14 +705,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: - require(1) loc := stack.Pop() val := ethutil.BigD(state.GetState(closure.Address(), loc.Bytes())) stack.Push(val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: - require(2) val, loc := stack.Popn() state.SetState(closure.Address(), loc.Bytes(), val) @@ -732,13 +721,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: - require(1) jump(stack.Pop()) continue case JUMPI: - require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) >= 0 { @@ -756,7 +743,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(closure.Gas) // 0x60 range case CREATE: - require(3) var ( err error @@ -801,8 +787,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Dbg.SetCode(closure.Code) } case CALL, CALLCODE: - require(7) - self.Endl() gas := stack.Pop() @@ -842,7 +826,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } case RETURN: - require(2) size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) @@ -850,7 +833,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(ret), nil case SUICIDE: - require(1) receiver := state.GetOrNewStateObject(stack.Pop().Bytes()) -- cgit v1.2.3 From feef194829b07570e91873ed5d1e8cc51e8fa430 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 23 Oct 2014 14:04:00 +0200 Subject: Chnged to use GetOp instead & added error + checking --- vm/errors.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ vm/execution.go | 4 ++-- vm/vm_debug.go | 6 +++--- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 vm/errors.go (limited to 'vm') diff --git a/vm/errors.go b/vm/errors.go new file mode 100644 index 000000000..ab011bd62 --- /dev/null +++ b/vm/errors.go @@ -0,0 +1,51 @@ +package vm + +import ( + "fmt" + "math/big" +) + +type OutOfGasError struct { + req, has *big.Int +} + +func OOG(req, has *big.Int) OutOfGasError { + return OutOfGasError{req, has} +} + +func (self OutOfGasError) Error() string { + return fmt.Sprintf("out of gas! require %v, have %v", self.req, self.has) +} + +func IsOOGErr(err error) bool { + _, ok := err.(OutOfGasError) + return ok +} + +type StackError struct { + req, has int +} + +func StackErr(req, has int) StackError { + return StackError{req, has} +} + +func (self StackError) Error() string { + return fmt.Sprintf("stack error! require %v, have %v", self.req, self.has) +} + +func IsStack(err error) bool { + _, ok := err.(StackError) + return ok +} + +type DepthError struct{} + +func (self DepthError) Error() string { + return fmt.Sprintf("Max call depth exceeded (%d)", MaxCallDepth) +} + +func IsDepthErr(err error) bool { + _, ok := err.(DepthError) + return ok +} diff --git a/vm/execution.go b/vm/execution.go index bd174d64e..c518c4b57 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -36,7 +36,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, snapshot := env.State().Copy() defer func() { - if err != nil { + if IsDepthErr(err) || IsOOGErr(err) { env.State().Set(snapshot) } }() @@ -76,7 +76,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, if self.vm.Depth() == MaxCallDepth { c.UseGas(self.Gas) - return c.Return(nil), fmt.Errorf("Max call depth exceeded (%d)", MaxCallDepth) + return c.Return(nil), DepthError{} } // Executer the closure and get the return value (if any) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index fe004046c..b44604121 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -107,7 +107,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { step++ // Get the memory location of pc - op = OpCode(closure.Get(pc).Uint()) + op = closure.GetOp(int(pc.Uint64())) // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations @@ -246,11 +246,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if !closure.UseGas(gas) { self.Endl() - err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) + tmp := new(big.Int).Set(closure.Gas) closure.UseGas(closure.Gas) - return closure.Return(nil), err + return closure.Return(nil), OOG(gas, tmp) } mem.Resize(newMemSize.Uint64()) -- cgit v1.2.3 From 272d58662c885ab1cef8930e96fb832ae5377d96 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 27 Oct 2014 11:44:16 +0100 Subject: Implemented LOG. Closes #159 --- vm/common.go | 1 + vm/environment.go | 1 + vm/log.go | 9 +++++++++ vm/stack.go | 12 ++++++++++++ vm/types.go | 10 ++++++++-- vm/vm.go | 2 +- vm/vm_debug.go | 33 +++++++++++++++++++++++++++------ 7 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 vm/log.go (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 3b0d735ba..c73744506 100644 --- a/vm/common.go +++ b/vm/common.go @@ -29,6 +29,7 @@ var ( GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) + GasLog = big.NewInt(32) Pow256 = ethutil.BigPow(2, 256) diff --git a/vm/environment.go b/vm/environment.go index af67c4179..b8013856e 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,6 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error + AddLog(Log) } type Object interface { diff --git a/vm/log.go b/vm/log.go new file mode 100644 index 000000000..954d2ec91 --- /dev/null +++ b/vm/log.go @@ -0,0 +1,9 @@ +package vm + +import "math/big" + +type Log struct { + Address []byte + Topics []*big.Int + Data []byte +} diff --git a/vm/stack.go b/vm/stack.go index 55fdb6d15..69ded6562 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -139,6 +139,18 @@ func (m *Memory) Get(offset, size int64) []byte { return nil } +func (self *Memory) Geti(offset, size int64) (cpy []byte) { + if len(self.store) > int(offset) { + s := int64(math.Min(float64(len(self.store)), float64(offset+size))) + cpy = make([]byte, size) + copy(cpy, self.store[offset:offset+s]) + + return + } + + return +} + func (m *Memory) Len() int { return len(m.store) } diff --git a/vm/types.go b/vm/types.go index 6fb9a5c95..53178fa43 100644 --- a/vm/types.go +++ b/vm/types.go @@ -18,7 +18,7 @@ const ( MOD = 0x06 SMOD = 0x07 EXP = 0x08 - NEG = 0x09 + BNOT = 0x09 LT = 0x0a GT = 0x0b SLT = 0x0c @@ -144,6 +144,12 @@ const ( SWAP15 = 0x9e SWAP16 = 0x9f + LOG0 = 0xa0 + LOG1 = 0xa1 + LOG2 = 0xa2 + LOG3 = 0xa3 + LOG4 = 0xa4 + // 0xf0 range - closures CREATE = 0xf0 CALL = 0xf1 @@ -166,7 +172,7 @@ var opCodeToString = map[OpCode]string{ MOD: "MOD", SMOD: "SMOD", EXP: "EXP", - NEG: "NEG", + BNOT: "BNOT", LT: "LT", GT: "GT", SLT: "SLT", diff --git a/vm/vm.go b/vm/vm.go index 291f1cda4..599c8ca41 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -268,7 +268,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { U256(base) stack.Push(base) - case NEG: + case BNOT: require(1) base.Sub(Pow256, stack.Pop()) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index a30339e2b..13446d6c0 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -141,7 +141,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack Check, memory resize & gas phase switch op { // Stack checks only - case NOT, CALLDATALOAD, POP, JUMP, NEG: // 1 + case NOT, CALLDATALOAD, POP, JUMP, BNOT: // 1 require(1) case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) @@ -153,6 +153,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) require(n) + case LOG0, LOG1, LOG2, LOG3, LOG4: + n := int(op - LOG0) + require(n + 2) + + mSize, mStart := stack.Peekn() + gas.Set(GasLog) + addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) + addStepGasUsage(new(big.Int).Add(mSize, mStart)) // Gas only case STOP: gas.Set(ethutil.Big0) @@ -168,13 +176,16 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { y, x := stack.Peekn() val := closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { - mult = ethutil.Big2 + // 0 => non 0 + mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { + //state.AddBalance(closure.caller.Address(), new(big.Int).Mul(big.NewInt(100), closure.Price)) mult = ethutil.Big0 } else { + // non 0 => non 0 mult = ethutil.Big1 } - gas = new(big.Int).Mul(mult, GasSStore) + gas.Set(new(big.Int).Mul(mult, GasSStore)) case BALANCE: require(1) gas.Set(GasBalance) @@ -375,10 +386,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) - case NEG: - base.Sub(Pow256, stack.Pop()) + case BNOT: + base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) - base = U256(base) + // Not needed + //base = U256(base) stack.Push(base) case LT: @@ -685,6 +697,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { x, y := stack.Swapn(n) self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) + case LOG0, LOG1, LOG2, LOG3, LOG4: + n := int(op - LOG0) + topics := make([]*big.Int, n) + mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() + data := mem.Geti(mStart, mSize) + for i := 0; i < n; i++ { + topics[i] = stack.Pop() + } + self.env.AddLog(Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) -- cgit v1.2.3 From 7849b7e97873ea443b480f45aa4fe6ffbb41cdb0 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Oct 2014 13:22:04 +0100 Subject: Refund SSTORE properly --- vm/vm_debug.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 13446d6c0..d38373411 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -179,7 +179,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - //state.AddBalance(closure.caller.Address(), new(big.Int).Mul(big.NewInt(100), closure.Price)) + state.Refund(closure.caller.Address(), big.NewInt(100), closure.Price) + mult = ethutil.Big0 } else { // non 0 => non 0 -- cgit v1.2.3 From 48125a25eb9f4ece2613559ced5075bde1c75c7a Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Oct 2014 13:26:30 +0100 Subject: Added missing requires on SSTORE SLOAD --- vm/common.go | 23 ++++++++++++----------- vm/vm_debug.go | 6 +++++- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index c73744506..16a0b5523 100644 --- a/vm/common.go +++ b/vm/common.go @@ -19,17 +19,18 @@ const ( ) var ( - GasStep = big.NewInt(1) - GasSha = big.NewInt(20) - GasSLoad = big.NewInt(20) - GasSStore = big.NewInt(100) - GasBalance = big.NewInt(20) - GasCreate = big.NewInt(100) - GasCall = big.NewInt(20) - GasMemory = big.NewInt(1) - GasData = big.NewInt(5) - GasTx = big.NewInt(500) - GasLog = big.NewInt(32) + GasStep = big.NewInt(1) + GasSha = big.NewInt(20) + GasSLoad = big.NewInt(20) + GasSStore = big.NewInt(100) + GasSStoreRefund = big.NewInt(100) + GasBalance = big.NewInt(20) + GasCreate = big.NewInt(100) + GasCall = big.NewInt(20) + GasMemory = big.NewInt(1) + GasData = big.NewInt(5) + GasTx = big.NewInt(500) + GasLog = big.NewInt(32) Pow256 = ethutil.BigPow(2, 256) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index d38373411..1e45813bc 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -169,9 +169,13 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(ethutil.Big0) case SLOAD: + require(1) + gas.Set(GasSLoad) // Memory resize & Gas case SSTORE: + require(2) + var mult *big.Int y, x := stack.Peekn() val := closure.GetStorage(x) @@ -179,7 +183,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - state.Refund(closure.caller.Address(), big.NewInt(100), closure.Price) + state.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) mult = ethutil.Big0 } else { -- cgit v1.2.3 From fb4113dab4df8480c77bdcb707fa6b5408755b79 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 29 Oct 2014 10:34:40 +0100 Subject: PoC 7 updates * Bloom * Block restructure * Receipts --- vm/log.go | 33 +++++++++++++++++++++++++++++++-- vm/vm_debug.go | 4 ++-- 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'vm') diff --git a/vm/log.go b/vm/log.go index 954d2ec91..bc72a0423 100644 --- a/vm/log.go +++ b/vm/log.go @@ -1,9 +1,38 @@ package vm -import "math/big" +import "github.com/ethereum/go-ethereum/ethutil" type Log struct { Address []byte - Topics []*big.Int + Topics [][]byte Data []byte } + +func NewLogFromValue(decoder *ethutil.Value) Log { + log := Log{ + Address: decoder.Get(0).Bytes(), + Data: decoder.Get(2).Bytes(), + } + + it := decoder.Get(1).NewIterator() + for it.Next() { + log.Topics = append(log.Topics, it.Value().Bytes()) + } + + return log +} + +func (self Log) RlpData() interface{} { + return []interface{}{self.Address, ethutil.ByteSliceToInterface(self.Topics), self.Data} +} + +type Logs []Log + +func (self Logs) RlpData() interface{} { + data := make([]interface{}, len(self)) + for i, log := range self { + data[i] = log.RlpData() + } + + return data +} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 1e45813bc..b3fbfe341 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -704,11 +704,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) - topics := make([]*big.Int, n) + topics := make([][]byte, n) mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() data := mem.Geti(mStart, mSize) for i := 0; i < n; i++ { - topics[i] = stack.Pop() + topics[i] = stack.Pop().Bytes() } self.env.AddLog(Log{closure.Address(), topics, data}) case MLOAD: -- cgit v1.2.3 From 4cf69d7cd34394fa7408bb5a6e152610a9daa81c Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 Oct 2014 18:40:18 +0100 Subject: vm: fix basic VM tests The tests now compile and won't panic for unexpected return values. We need a recent-enough version of the mutan compiler because of the new JUMPDEST requirements. Skip some tests if the installed mutan version is too old. The debug VM test still fails, probably because of an implementation bug. --- vm/vm_test.go | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 84cca3a9d..8818cc8ec 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -14,22 +14,30 @@ import ( "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethtrie" "github.com/ethereum/go-ethereum/ethutil" + "github.com/obscuren/mutan" ) -type TestEnv struct { +type TestEnv struct{} + +func (TestEnv) Origin() []byte { return nil } +func (TestEnv) BlockNumber() *big.Int { return nil } +func (TestEnv) BlockHash() []byte { return nil } +func (TestEnv) PrevHash() []byte { return nil } +func (TestEnv) Coinbase() []byte { return nil } +func (TestEnv) Time() int64 { return 0 } +func (TestEnv) GasLimit() *big.Int { return nil } +func (TestEnv) Difficulty() *big.Int { return nil } +func (TestEnv) Value() *big.Int { return nil } +func (TestEnv) AddLog(Log) {} + +func (TestEnv) Transfer(from, to Account, amount *big.Int) error { + return nil } -func (self TestEnv) Origin() []byte { return nil } -func (self TestEnv) BlockNumber() *big.Int { return nil } -func (self TestEnv) BlockHash() []byte { return nil } -func (self TestEnv) PrevHash() []byte { return nil } -func (self TestEnv) Coinbase() []byte { return nil } -func (self TestEnv) Time() int64 { return 0 } -func (self TestEnv) Difficulty() *big.Int { return nil } -func (self TestEnv) Value() *big.Int { return nil } - // This is likely to fail if anything ever gets looked up in the state trie :-) -func (self TestEnv) State() *ethstate.State { return ethstate.New(ethtrie.New(nil, "")) } +func (TestEnv) State() *ethstate.State { + return ethstate.New(ethtrie.New(nil, "")) +} const mutcode = ` var x = 0; @@ -56,27 +64,35 @@ func setup(level ethlog.LogLevel, typ Type) (*Closure, VirtualMachine) { return callerClosure, New(TestEnv{}, typ) } +var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") + func TestDebugVm(t *testing.T) { + if mutan.Version < "0.6" { + t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + } + closure, vm := setup(ethlog.DebugLevel, DebugVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { - fmt.Println("error", e) + t.Fatalf("Call returned error: %v", e) } - - if ret[len(ret)-1] != 9 { - t.Errorf("Expected VM to return 9, got", ret, "instead.") + if !bytes.Equal(ret, big9) { + t.Errorf("Wrong return value '%x', want '%x'", ret, big9) } } func TestVm(t *testing.T) { + if mutan.Version < "0.6" { + t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + } + closure, vm := setup(ethlog.DebugLevel, StandardVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { - fmt.Println("error", e) + t.Fatalf("Call returned error: %v", e) } - - if ret[len(ret)-1] != 9 { - t.Errorf("Expected VM to return 9, got", ret, "instead.") + if !bytes.Equal(ret, big9) { + t.Errorf("Wrong return value '%x', want '%x'", ret, big9) } } -- cgit v1.2.3 From df5603de0a34e80a1af6ad03e37ce43728baad35 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 30 Oct 2014 13:32:50 +0100 Subject: Moved logging to state, proper structured block * Moved logs to state so it's subject to snapshotting * Split up block header * Removed logs from transactions and made them receipts only --- vm/environment.go | 6 +++++- vm/log.go | 38 -------------------------------------- vm/vm_debug.go | 3 ++- 3 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 vm/log.go (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index b8013856e..deb46b77f 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,7 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error - AddLog(Log) + AddLog(ethstate.Log) } type Object interface { @@ -43,5 +43,9 @@ func Transfer(from, to Account, amount *big.Int) error { from.SubBalance(amount) to.AddBalance(amount) + // Add default LOG. Default = big(sender.addr) + 1 + //addr := ethutil.BigD(receiver.Address()) + //tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) + return nil } diff --git a/vm/log.go b/vm/log.go deleted file mode 100644 index bc72a0423..000000000 --- a/vm/log.go +++ /dev/null @@ -1,38 +0,0 @@ -package vm - -import "github.com/ethereum/go-ethereum/ethutil" - -type Log struct { - Address []byte - Topics [][]byte - Data []byte -} - -func NewLogFromValue(decoder *ethutil.Value) Log { - log := Log{ - Address: decoder.Get(0).Bytes(), - Data: decoder.Get(2).Bytes(), - } - - it := decoder.Get(1).NewIterator() - for it.Next() { - log.Topics = append(log.Topics, it.Value().Bytes()) - } - - return log -} - -func (self Log) RlpData() interface{} { - return []interface{}{self.Address, ethutil.ByteSliceToInterface(self.Topics), self.Data} -} - -type Logs []Log - -func (self Logs) RlpData() interface{} { - data := make([]interface{}, len(self)) - for i, log := range self { - data[i] = log.RlpData() - } - - return data -} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index b3fbfe341..7afc7e79a 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" ) @@ -710,7 +711,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { for i := 0; i < n; i++ { topics[i] = stack.Pop().Bytes() } - self.env.AddLog(Log{closure.Address(), topics, data}) + self.env.AddLog(ethstate.Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) -- cgit v1.2.3 From fd9da72536b73351bbcdc1e9dbbbb8c0e4bfb21b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Oct 2014 12:37:43 +0100 Subject: ethcrypto => crypto --- vm/address.go | 8 ++++---- vm/vm.go | 6 +++--- vm/vm_debug.go | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'vm') diff --git a/vm/address.go b/vm/address.go index c4aa1eb7c..235143b34 100644 --- a/vm/address.go +++ b/vm/address.go @@ -3,7 +3,7 @@ package vm import ( "math/big" - "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" ) @@ -27,16 +27,16 @@ var Precompiled = map[uint64]*PrecompiledAddress{ } func sha256Func(in []byte) []byte { - return ethcrypto.Sha256(in) + return crypto.Sha256(in) } func ripemd160Func(in []byte) []byte { - return ethutil.RightPadBytes(ethcrypto.Ripemd160(in), 32) + return ethutil.RightPadBytes(crypto.Ripemd160(in), 32) } func ecrecoverFunc(in []byte) []byte { // In case of an invalid sig. Defaults to return nil defer func() { recover() }() - return ethcrypto.Ecrecover(in) + return crypto.Ecrecover(in) } diff --git a/vm/vm.go b/vm/vm.go index 599c8ca41..28df832d3 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" ) @@ -391,7 +391,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case SHA3: require(2) size, offset := stack.Popn() - data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64())) + data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) @@ -627,7 +627,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - addr := ethcrypto.CreateAddress(closure.Address(), closure.object.Nonce) + addr := crypto.CreateAddress(closure.Address(), closure.object.Nonce) closure.object.Nonce++ closure.UseGas(closure.Gas) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 7afc7e79a..1cf243e16 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" ) @@ -519,7 +519,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0x20 range case SHA3: size, offset := stack.Popn() - data := ethcrypto.Sha3(mem.Get(offset.Int64(), size.Int64())) + data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) @@ -785,7 +785,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Generate a new address n := state.GetNonce(closure.Address()) - addr := ethcrypto.CreateAddress(closure.Address(), n) + addr := crypto.CreateAddress(closure.Address(), n) state.SetNonce(closure.Address(), n+1) self.Printf(" (*) %x", addr).Endl() -- cgit v1.2.3 From b1c247231b11f313ca0eedff75ea563926d23f68 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Oct 2014 12:56:05 +0100 Subject: ethlog => logger --- vm/common.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 16a0b5523..9514ff6d3 100644 --- a/vm/common.go +++ b/vm/common.go @@ -3,11 +3,11 @@ package vm import ( "math/big" - "github.com/ethereum/go-ethereum/ethlog" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/logger" ) -var vmlogger = ethlog.NewLogger("VM") +var vmlogger = logger.NewLogger("VM") type Type int -- cgit v1.2.3 From af8f5f0b69f1c359991d12c7708804fe8dd1f944 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 31 Oct 2014 14:43:14 +0100 Subject: ethstate => state --- vm/closure.go | 12 ++++++------ vm/debugger.go | 6 +++--- vm/environment.go | 6 +++--- vm/execution.go | 6 +++--- vm/vm_debug.go | 34 +++++++++++++++++----------------- 5 files changed, 32 insertions(+), 32 deletions(-) (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index b556bc03d..8e54e9ce6 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -5,14 +5,14 @@ package vm import ( "math/big" - "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type ClosureRef interface { ReturnGas(*big.Int, *big.Int) Address() []byte - Object() *ethstate.StateObject + Object() *state.StateObject GetStorage(*big.Int) *ethutil.Value SetStorage(*big.Int, *ethutil.Value) } @@ -20,9 +20,9 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { caller ClosureRef - object *ethstate.StateObject + object *state.StateObject Code []byte - message *ethstate.Message + message *state.Message exe *Execution Gas, UsedGas, Price *big.Int @@ -31,7 +31,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(msg *ethstate.Message, caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure { +func NewClosure(msg *state.Message, caller ClosureRef, object *state.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 @@ -131,7 +131,7 @@ func (c *Closure) ReturnGas(gas, price *big.Int) { c.UsedGas.Sub(c.UsedGas, gas) } -func (c *Closure) Object() *ethstate.StateObject { +func (c *Closure) Object() *state.StateObject { return c.object } diff --git a/vm/debugger.go b/vm/debugger.go index b0d0e545d..9b08634c6 100644 --- a/vm/debugger.go +++ b/vm/debugger.go @@ -1,10 +1,10 @@ package vm -import "github.com/ethereum/go-ethereum/ethstate" +import "github.com/ethereum/go-ethereum/state" type Debugger interface { - BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool - StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool + BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool + StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *state.StateObject) bool BreakPoints() []int64 SetCode(byteCode []byte) } diff --git a/vm/environment.go b/vm/environment.go index deb46b77f..dea86c66c 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -4,12 +4,12 @@ import ( "errors" "math/big" - "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type Environment interface { - State() *ethstate.State + State() *state.State Origin() []byte BlockNumber() *big.Int @@ -20,7 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error - AddLog(ethstate.Log) + AddLog(state.Log) } type Object interface { diff --git a/vm/execution.go b/vm/execution.go index 8da0469de..401157808 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -4,15 +4,15 @@ import ( "fmt" "math/big" - "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type Execution struct { vm VirtualMachine address, input []byte Gas, price, value *big.Int - object *ethstate.StateObject + object *state.StateObject SkipTransfer bool } @@ -41,7 +41,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, } }() - msg := env.State().Manifest().AddMessage(ðstate.Message{ + msg := env.State().Manifest().AddMessage(&state.Message{ To: self.address, From: caller.Address(), Input: self.input, Origin: env.Origin(), diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 1cf243e16..0942636d6 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -5,8 +5,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type DebugVm struct { @@ -49,7 +49,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { pc = big.NewInt(0) step = 0 prevStep = 0 - state = self.env.State() + statedb = self.env.State() require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) @@ -115,7 +115,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if self.logTy == LogTyDiff { switch op { case STOP, RETURN, SUICIDE: - state.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { + statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { value.Decode() fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) }) @@ -184,7 +184,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - state.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) mult = ethutil.Big0 } else { @@ -532,7 +532,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case BALANCE: addr := stack.Pop().Bytes() - balance := state.GetBalance(addr) + balance := statedb.GetBalance(addr) stack.Push(balance) @@ -599,7 +599,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if op == EXTCODESIZE { addr := stack.Pop().Bytes() - code = state.GetCode(addr) + code = statedb.GetCode(addr) } else { code = closure.Code } @@ -613,7 +613,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if op == EXTCODECOPY { addr := stack.Pop().Bytes() - code = state.GetCode(addr) + code = statedb.GetCode(addr) } else { code = closure.Code } @@ -711,7 +711,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { for i := 0; i < n; i++ { topics[i] = stack.Pop().Bytes() } - self.env.AddLog(ethstate.Log{closure.Address(), topics, data}) + self.env.AddLog(state.Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) @@ -733,13 +733,13 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: loc := stack.Pop() - val := ethutil.BigD(state.GetState(closure.Address(), loc.Bytes())) + val := ethutil.BigD(statedb.GetState(closure.Address(), loc.Bytes())) stack.Push(val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: val, loc := stack.Popn() - state.SetState(closure.Address(), loc.Bytes(), val) + statedb.SetState(closure.Address(), loc.Bytes(), val) // Debug sessions are allowed to run without message if closure.message != nil { @@ -784,9 +784,9 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - n := state.GetNonce(closure.Address()) + n := statedb.GetNonce(closure.Address()) addr := crypto.CreateAddress(closure.Address(), n) - state.SetNonce(closure.Address(), n+1) + statedb.SetNonce(closure.Address(), n+1) self.Printf(" (*) %x", addr).Endl() @@ -861,10 +861,10 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(ret), nil case SUICIDE: - receiver := state.GetOrNewStateObject(stack.Pop().Bytes()) + receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) - receiver.AddAmount(state.GetBalance(closure.Address())) - state.Delete(closure.Address()) + receiver.AddAmount(statedb.GetBalance(closure.Address())) + statedb.Delete(closure.Address()) fallthrough case STOP: // Stop the closure @@ -889,11 +889,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if pc.Cmp(big.NewInt(instrNo)) == 0 { self.Stepping = true - if !self.Dbg.BreakHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) { + if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { return nil, nil } } else if self.Stepping { - if !self.Dbg.StepHook(prevStep, op, mem, stack, state.GetStateObject(closure.Address())) { + if !self.Dbg.StepHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { return nil, nil } } -- cgit v1.2.3 From f3473312ba90b37b9a4100592a8c4d5d5bf245b7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 31 Oct 2014 18:40:32 +0100 Subject: all: fix rename breakage --- vm/vm_test.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 8818cc8ec..3599b694a 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -9,11 +9,11 @@ import ( "os" "testing" - "github.com/ethereum/go-ethereum/ethcrypto" - "github.com/ethereum/go-ethereum/ethlog" - "github.com/ethereum/go-ethereum/ethstate" - "github.com/ethereum/go-ethereum/ethtrie" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/trie" "github.com/obscuren/mutan" ) @@ -35,8 +35,8 @@ func (TestEnv) Transfer(from, to Account, amount *big.Int) error { } // This is likely to fail if anything ever gets looked up in the state trie :-) -func (TestEnv) State() *ethstate.State { - return ethstate.New(ethtrie.New(nil, "")) +func (TestEnv) State() *state.State { + return state.New(trie.New(nil, "")) } const mutcode = ` @@ -47,18 +47,18 @@ for i := 0; i < 10; i++ { return x` -func setup(level ethlog.LogLevel, typ Type) (*Closure, VirtualMachine) { +func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { code, err := ethutil.Compile(mutcode, true) if err != nil { log.Fatal(err) } // Pipe output to /dev/null - ethlog.AddLogSystem(ethlog.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) + logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) return callerClosure, New(TestEnv{}, typ) @@ -71,7 +71,7 @@ func TestDebugVm(t *testing.T) { t.Skip("skipping for mutan version", mutan.Version, " < 0.6") } - closure, vm := setup(ethlog.DebugLevel, DebugVmTy) + closure, vm := setup(logger.DebugLevel, DebugVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { t.Fatalf("Call returned error: %v", e) @@ -86,7 +86,7 @@ func TestVm(t *testing.T) { t.Skip("skipping for mutan version", mutan.Version, " < 0.6") } - closure, vm := setup(ethlog.DebugLevel, StandardVmTy) + closure, vm := setup(logger.DebugLevel, StandardVmTy) ret, _, e := closure.Call(vm, nil) if e != nil { t.Fatalf("Call returned error: %v", e) @@ -97,7 +97,7 @@ func TestVm(t *testing.T) { } func BenchmarkDebugVm(b *testing.B) { - closure, vm := setup(ethlog.InfoLevel, DebugVmTy) + closure, vm := setup(logger.InfoLevel, DebugVmTy) b.ResetTimer() @@ -107,7 +107,7 @@ func BenchmarkDebugVm(b *testing.B) { } func BenchmarkVm(b *testing.B) { - closure, vm := setup(ethlog.InfoLevel, StandardVmTy) + closure, vm := setup(logger.InfoLevel, StandardVmTy) b.ResetTimer() @@ -122,11 +122,11 @@ func RunCode(mutCode string, typ Type) []byte { log.Fatal(err) } - ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.InfoLevel)) + logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) vm := New(TestEnv{}, typ) @@ -148,7 +148,7 @@ func TestBuildInSha256(t *testing.T) { return out `, DebugVmTy) - exp := ethcrypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) + exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) if bytes.Compare(ret, exp) != 0 { t.Errorf("Expected %x, got %x", exp, ret) } @@ -164,7 +164,7 @@ func TestBuildInRipemd(t *testing.T) { return out `, DebugVmTy) - exp := ethutil.RightPadBytes(ethcrypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) + exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) if bytes.Compare(ret, exp) != 0 { t.Errorf("Expected %x, got %x", exp, ret) } -- cgit v1.2.3 From 394e0f60c20206c7f7c4c76551d11a2b14b23a4d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 31 Oct 2014 18:56:25 +0100 Subject: chain, tests/helper, vm: make tests compile They were broken by df5603de0a34e80a1, when vm.Log became ethstate.Log. --- vm/vm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 3599b694a..f5d77cbff 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -28,7 +28,7 @@ func (TestEnv) Time() int64 { return 0 } func (TestEnv) GasLimit() *big.Int { return nil } func (TestEnv) Difficulty() *big.Int { return nil } func (TestEnv) Value() *big.Int { return nil } -func (TestEnv) AddLog(Log) {} +func (TestEnv) AddLog(state.Log) {} func (TestEnv) Transfer(from, to Account, amount *big.Int) error { return nil -- cgit v1.2.3 From 141d3caabbfbebbbecac455462a40b6056aa3821 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 1 Nov 2014 01:18:03 +0100 Subject: Re-org op codes --- vm/types.go | 306 +++++++++++++++++++++++++++++---------------------------- vm/vm.go | 4 +- vm/vm_debug.go | 6 +- 3 files changed, 163 insertions(+), 153 deletions(-) (limited to 'vm') diff --git a/vm/types.go b/vm/types.go index 53178fa43..580c517d6 100644 --- a/vm/types.go +++ b/vm/types.go @@ -9,152 +9,162 @@ type OpCode byte // Op codes const ( // 0x0 range - arithmetic ops - STOP = 0x00 - ADD = 0x01 - MUL = 0x02 - SUB = 0x03 - DIV = 0x04 - SDIV = 0x05 - MOD = 0x06 - SMOD = 0x07 - EXP = 0x08 - BNOT = 0x09 - LT = 0x0a - GT = 0x0b - SLT = 0x0c - SGT = 0x0d - EQ = 0x0e - NOT = 0x0f + STOP OpCode = iota + ADD + MUL + SUB + DIV + SDIV + MOD + SMOD + ADDMOD + MULMOD + EXP + SIGNEXTEND +) - // 0x10 range - bit ops - AND = 0x10 - OR = 0x11 - XOR = 0x12 - BYTE = 0x13 - ADDMOD = 0x14 - MULMOD = 0x15 +const ( + LT OpCode = iota + 0x10 + GT + SLT + SGT + EQ + ISZERO + AND + OR + XOR + NOT + BYTE - // 0x20 range - crypto SHA3 = 0x20 +) +const ( // 0x30 range - closure state - ADDRESS = 0x30 - BALANCE = 0x31 - ORIGIN = 0x32 - CALLER = 0x33 - CALLVALUE = 0x34 - CALLDATALOAD = 0x35 - CALLDATASIZE = 0x36 - CALLDATACOPY = 0x37 - CODESIZE = 0x38 - CODECOPY = 0x39 - GASPRICE = 0x3a - EXTCODESIZE = 0x3b - EXTCODECOPY = 0x3c + ADDRESS OpCode = 0x30 + iota + BALANCE + ORIGIN + CALLER + CALLVALUE + CALLDATALOAD + CALLDATASIZE + CALLDATACOPY + CODESIZE + CODECOPY + GASPRICE + EXTCODESIZE + EXTCODECOPY +) + +const ( // 0x40 range - block operations - PREVHASH = 0x40 - COINBASE = 0x41 - TIMESTAMP = 0x42 - NUMBER = 0x43 - DIFFICULTY = 0x44 - GASLIMIT = 0x45 + PREVHASH OpCode = 0x40 + iota + COINBASE + TIMESTAMP + NUMBER + DIFFICULTY + GASLIMIT +) +const ( // 0x50 range - 'storage' and execution - POP = 0x50 - //DUP = 0x51 - //SWAP = 0x52 - MLOAD = 0x53 - MSTORE = 0x54 - MSTORE8 = 0x55 - SLOAD = 0x56 - SSTORE = 0x57 - JUMP = 0x58 - JUMPI = 0x59 - PC = 0x5a - MSIZE = 0x5b - GAS = 0x5c - JUMPDEST = 0x5d + POP OpCode = 0x50 + iota + MLOAD + MSTORE + MSTORE8 + SLOAD + SSTORE + JUMP + JUMPI + PC + MSIZE + GAS + JUMPDEST +) +const ( // 0x60 range - PUSH1 = 0x60 - PUSH2 = 0x61 - PUSH3 = 0x62 - PUSH4 = 0x63 - PUSH5 = 0x64 - PUSH6 = 0x65 - PUSH7 = 0x66 - PUSH8 = 0x67 - PUSH9 = 0x68 - PUSH10 = 0x69 - PUSH11 = 0x6a - PUSH12 = 0x6b - PUSH13 = 0x6c - PUSH14 = 0x6d - PUSH15 = 0x6e - PUSH16 = 0x6f - PUSH17 = 0x70 - PUSH18 = 0x71 - PUSH19 = 0x72 - PUSH20 = 0x73 - PUSH21 = 0x74 - PUSH22 = 0x75 - PUSH23 = 0x76 - PUSH24 = 0x77 - PUSH25 = 0x78 - PUSH26 = 0x79 - PUSH27 = 0x7a - PUSH28 = 0x7b - PUSH29 = 0x7c - PUSH30 = 0x7d - PUSH31 = 0x7e - PUSH32 = 0x7f - - DUP1 = 0x80 - DUP2 = 0x81 - DUP3 = 0x82 - DUP4 = 0x83 - DUP5 = 0x84 - DUP6 = 0x85 - DUP7 = 0x86 - DUP8 = 0x87 - DUP9 = 0x88 - DUP10 = 0x89 - DUP11 = 0x8a - DUP12 = 0x8b - DUP13 = 0x8c - DUP14 = 0x8d - DUP15 = 0x8e - DUP16 = 0x8f - - SWAP1 = 0x90 - SWAP2 = 0x91 - SWAP3 = 0x92 - SWAP4 = 0x93 - SWAP5 = 0x94 - SWAP6 = 0x95 - SWAP7 = 0x96 - SWAP8 = 0x97 - SWAP9 = 0x98 - SWAP10 = 0x99 - SWAP11 = 0x9a - SWAP12 = 0x9b - SWAP13 = 0x9c - SWAP14 = 0x9d - SWAP15 = 0x9e - SWAP16 = 0x9f + PUSH1 OpCode = 0x60 + iota + 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 + DUP1 + DUP2 + DUP3 + DUP4 + DUP5 + DUP6 + DUP7 + DUP8 + DUP9 + DUP10 + DUP11 + DUP12 + DUP13 + DUP14 + DUP15 + DUP16 + SWAP1 + SWAP2 + SWAP3 + SWAP4 + SWAP5 + SWAP6 + SWAP7 + SWAP8 + SWAP9 + SWAP10 + SWAP11 + SWAP12 + SWAP13 + SWAP14 + SWAP15 + SWAP16 +) - LOG0 = 0xa0 - LOG1 = 0xa1 - LOG2 = 0xa2 - LOG3 = 0xa3 - LOG4 = 0xa4 +const ( + LOG0 OpCode = 0xa0 + iota + LOG1 + LOG2 + LOG3 + LOG4 +) +const ( // 0xf0 range - closures - CREATE = 0xf0 - CALL = 0xf1 - RETURN = 0xf2 - CALLCODE = 0xf3 + CREATE OpCode = 0xf0 + iota + CALL + RETURN + CALLCODE // 0x70 range - other SUICIDE = 0xff @@ -163,22 +173,22 @@ const ( // Since the opcodes aren't all in order we can't use a regular slice var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops - STOP: "STOP", - ADD: "ADD", - MUL: "MUL", - SUB: "SUB", - DIV: "DIV", - SDIV: "SDIV", - MOD: "MOD", - SMOD: "SMOD", - EXP: "EXP", - BNOT: "BNOT", - LT: "LT", - GT: "GT", - SLT: "SLT", - SGT: "SGT", - EQ: "EQ", - NOT: "NOT", + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NOT: "NOT", + LT: "LT", + GT: "GT", + SLT: "SLT", + SGT: "SGT", + EQ: "EQ", + ISZERO: "ISZERO", // 0x10 range - bit ops AND: "AND", diff --git a/vm/vm.go b/vm/vm.go index 28df832d3..e1c2d9c14 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -268,7 +268,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { U256(base) stack.Push(base) - case BNOT: + case NOT: require(1) base.Sub(Pow256, stack.Pop()) @@ -325,7 +325,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } else { stack.Push(ethutil.BigFalse) } - case NOT: + case ISZERO: require(1) x := stack.Pop() if x.Cmp(ethutil.BigFalse) > 0 { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 0942636d6..0abfa098d 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -142,7 +142,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack Check, memory resize & gas phase switch op { // Stack checks only - case NOT, CALLDATALOAD, POP, JUMP, BNOT: // 1 + case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 require(1) case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) @@ -392,7 +392,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) - case BNOT: + case NOT: base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) // Not needed @@ -449,7 +449,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } else { stack.Push(ethutil.BigFalse) } - case NOT: + case ISZERO: x := stack.Pop() if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) -- cgit v1.2.3 From 3f90f7c89856f5d024eec1df535a4fc2871214c2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 1 Nov 2014 02:14:55 +0100 Subject: Signextend --- vm/vm_debug.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 0abfa098d..129ea1a59 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -392,6 +392,20 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) + case SIGNEXTEND: + back := stack.Pop().Uint64() + if back.Cmp(big.NewInt(31)) < 0 { + bit := uint(back*8 + 7) + num := stack.Pop() + mask := new(big.Int).Lsh(ethutil.Big1, bit) + mask.Sub(mask, ethutil.Big1) + if ethutil.BitTest(num, int(bit)) { + num.Or(num, mask.Not(mask)) + } else { + num.And(num, mask) + } + stack.Push(num) + } case NOT: base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) -- cgit v1.2.3 From 1bb398f4e22feef8f83fedd8a525e4da5b627773 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 2 Nov 2014 19:39:45 +0100 Subject: Sign ext --- vm/vm_debug.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 129ea1a59..05ae347f6 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -394,7 +394,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(base) case SIGNEXTEND: back := stack.Pop().Uint64() - if back.Cmp(big.NewInt(31)) < 0 { + if back < 31 { bit := uint(back*8 + 7) num := stack.Pop() mask := new(big.Int).Lsh(ethutil.Big1, bit) -- cgit v1.2.3 From 78fb2af6f17a1636f5f12856e8e39114915f0d56 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 4 Nov 2014 17:11:19 +0100 Subject: Squashed commit of the following: commit 79d7cbfc4a9cf3d70ae01dea8ee76c770af33211 Merge: 9120274 1c1ba8d Author: Christoph Jentzsch Date: Tue Nov 4 13:32:11 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 9120274a46d696cda6d595b2ec5acc2947eb2b46 Author: Christoph Jentzsch Date: Tue Nov 4 13:31:27 2014 +0100 Update tests to latest protocol changes (PoC7) commit 1c1ba8d161817b391ea296391ad3ede3e71c0aa1 Merge: 014d370 3aebe53 Author: Christoph Jentzsch Date: Tue Nov 4 13:30:52 2014 +0100 Merge pull request #31 from CJentzsch/develop Restructered tests in folders in accordance to test suites commit 3aebe532e536eb6f6766ccac456c07023ab822e1 Author: Christoph Jentzsch Date: Mon Nov 3 13:58:21 2014 +0100 Updated vmNamecoin.json to new sstore prices commit 8a0be21839cf8bb7d3d80a2b61c8433b5d3a8bfd Author: Christoph Jentzsch Date: Mon Nov 3 13:53:00 2014 +0100 Added example state test commit 83643addbc3d50c6a79611a5d8700aad5fb1df16 Author: Christoph Jentzsch Date: Mon Nov 3 13:36:25 2014 +0100 removed systemoperationstests commit 3930ca3a9a377107d5792b3e7202f79c688f1a67 Author: Christoph Jentzsch Date: Mon Nov 3 13:22:15 2014 +0100 Restructered tests in folders in accordance to test suites commit 014d370b5d5d0a807cc31a2fc3a8c5313ccd7ea4 Author: Christoph Jentzsch Date: Wed Oct 29 21:23:56 2014 +0100 New SIGNEXTEND tets commit 155d449be206f5276f689770006ecbbb203dd6ad Author: Christoph Jentzsch Date: Wed Oct 29 20:59:05 2014 +0100 New tests for BNOT and SIGNEXTEND commit c9eae764b8921a5d6c929b8544cb9acdb920453c Author: Christoph Jentzsch Date: Tue Oct 28 12:58:27 2014 +0100 Update SSTORE gas cost and BNOT instead of NEG commit ad2a75ac58ddcb06316f68d0fdaa8e80828a990c Author: Christoph Jentzsch Date: Thu Oct 23 16:05:49 2014 +0200 Added new recursive bombs commit 834c52af6406b9af429104408ca7bcbc525efe5c Author: Christoph Jentzsch Date: Thu Oct 23 12:01:05 2014 +0200 Changing gas cost to zero at stackunderflow commit c73a8a89d23cbdaf80875667437d57c3ee32f08a Author: Jeffrey Wilcke Date: Wed Oct 22 13:04:45 2014 +0200 Reverted back to original value. commit b9a8c924227996ef281d44ccfcc72c7618027f91 Author: martin becze Date: Tue Oct 21 17:02:52 2014 -0400 fix spelling error commit b48ae74af441c00cdce487416be448b0df3d4323 Author: Christoph Jentzsch Date: Tue Oct 21 17:26:26 2014 +0200 Added failing random tests commit bee0a4100c69cabfa361e36831ec0f64187188f3 Merge: 5050d20 b315da6 Author: Christoph Jentzsch Date: Tue Oct 21 17:15:05 2014 +0200 Merge remote-tracking branch 'origin/master' into develop commit 5050d20b4d0321e3e4ea2f118781c7bb96a3d7b5 Merge: 7516685 ba35362 Author: Christoph Jentzsch Date: Mon Oct 20 20:18:20 2014 +0200 Merge pull request #26 from wanderer/develop Add a package.json for node.js commit ba35362876caa03b11c7ce777d959b99accbcfb0 Author: wanderer Date: Sun Oct 19 23:59:47 2014 -0400 turned tests into a node module commit 751668571e390e6bceb515d082222aa31b5e5b14 Author: ethers Date: Thu Oct 16 17:08:20 2014 -0700 json was invalid and missing quotes commit 0e687cee479acfd82861e13d2022ad430fc78d78 Author: Jeffrey Wilcke Date: Thu Oct 16 17:13:24 2014 +0200 Update vmEnvironmentalInfoTest.json commit 78a78e2e6cffb9357f2281070d83bf869ab8b2f4 Author: Christoph Jentzsch Date: Wed Oct 15 14:19:11 2014 +0200 updated genesis_hash commit b315da618b55b581ba8e87f83b2ab5175841392e Merge: 7a7e198 0a76a3a Author: Christoph Jentzsch Date: Tue Oct 14 10:33:26 2014 +0200 Merge pull request #23 from ethers/fix22 numbers should be strings #22 commit 0a76a3a312951e852509e2b378b2b5b3f87135b0 Author: ethers Date: Mon Oct 13 14:45:30 2014 -0700 numbers should be strings #22 commit 1f67385f130422588f92341fe82c2435b160fe84 Author: Christoph Jentzsch Date: Sat Oct 11 13:18:00 2014 +0200 Added some MUL tests commit 7a7e198395f776d0a95d252ddc3b30492b9d3cff Author: Christoph Jentzsch Date: Sat Oct 11 13:11:59 2014 +0200 Added some MUL tests commit 46eb6283ae6c147f7efa910dadc18a504b6725ed Author: Christoph Jentzsch Date: Sat Oct 11 12:18:13 2014 +0200 tested new opcodes (JUMPDEST,CALLCODE) and created test for CALL/CREATE depth commit 8d38d62d1053ed7552211105e26b2e248a3db747 Author: Nick Savers Date: Fri Oct 10 18:09:41 2014 +0200 INVALID stops the operation and doesn't cost gas commit ed6eba7c8ebc0cbb65ccd45b047823f9acc1471b Author: Christoph Jentzsch Date: Wed Oct 8 19:08:48 2014 +0200 Update + ABA recursive bomb which needs maximum recursion limit of 1024 commit 2d72050db1c67d9d6912ce6ade80dbe5685749ff Author: Christoph Jentzsch Date: Wed Oct 8 14:37:18 2014 +0200 Applied recent protocol changes (PoC7) to existin tests commit dfe66cab3fb533003ddaec7250d8fffbf3fbad65 Merge: 4513623 1a67a96 Author: Christoph Jentzsch Date: Wed Oct 8 11:05:51 2014 +0200 Merge remote-tracking branch 'origin/develop' Conflicts: genesishashestest.json commit 1a67a96cff2fba02e57a82d65007cec99dcc313c Merge: a4f5f45 ffd6bc9 Author: vbuterin Date: Tue Oct 7 15:10:23 2014 +0100 Merge pull request #18 from CJentzsch/develop CallToNameRegistratorOutOfGas balance correction commit ffd6bc97adfbc83b6e0c50cdf072fd58f94ace69 Merge: a4f5f45 9779d67 Author: Christoph Jentzsch Date: Tue Oct 7 15:47:34 2014 +0200 Merge remote-tracking branch 'origin/develop' into develop commit 9779d67b8cdf4e99818a5eeadbc3aebd7527b1a9 Author: Christoph Jentzsch Date: Tue Oct 7 15:45:53 2014 +0200 CallToNameRegistratorOutOfGas balance correction Even if execution fails, the value gets transferred. commit a4f5f45228b6f3ebf8ea77c47515149a3df2bc24 Merge: 49a9f47 b6d7cba Author: vbuterin Date: Tue Oct 7 14:13:12 2014 +0100 Merge pull request #17 from CJentzsch/develop Added A calls B calls A contracts commit b6d7cba49914362297c0fcac48d868ffe3bdf06a Merge: 865cb40 49a9f47 Author: Christoph Jentzsch Date: Tue Oct 7 15:02:51 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 865cb4083d33de2a9115ee39c73aea56b0c34fe8 Author: Christoph Jentzsch Date: Tue Oct 7 15:02:36 2014 +0200 Added A calls B calls A contracts commit 49a9f47aec2dbd6e321298947929b3d0b5abc280 Merge: 3b0ec43 94a493b Author: Jeffrey Wilcke Date: Tue Oct 7 10:56:17 2014 +0200 Merge pull request #16 from CJentzsch/develop corrected amount of used gas for CallToNameRegistratorOutOfGas commit 94a493b0d94163e3de96e1c4bb389ef745756f30 Merge: 72853c4 3b0ec43 Author: Christoph Jentzsch Date: Tue Oct 7 10:51:32 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 72853c4382fa1b51e384223da34427d3579fe48a Author: Christoph Jentzsch Date: Tue Oct 7 10:51:07 2014 +0200 corrected amount of used gas for CallToNameRegistratorOutOfGas commit 3b0ec436e4c6808f98f1bc5bb5c66b4d2be4b4be Merge: aec3252 222068b Author: vbuterin Date: Tue Oct 7 05:52:43 2014 +0100 Merge pull request #15 from CJentzsch/develop corrected tests and different style for storage commit 222068b9bac6c386e499cb6b0fc2af562fcd309e Merge: c169653 aec3252 Author: Christoph Jentzsch Date: Mon Oct 6 21:17:28 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit c1696531a646309b2b286abb7552eb05f1278cd1 Author: Christoph Jentzsch Date: Mon Oct 6 21:17:09 2014 +0200 corrected tests and different style for storage commit aec3252b8e9f6d37b5cf3dbe0c1678e08929d291 Merge: 25f9fd5 e17a909 Author: vbuterin Date: Mon Oct 6 09:39:46 2014 +0100 Merge pull request #14 from CJentzsch/develop corrected gas limit in vmSystemOperationsTest commit e17a909f70af18fbfc0216c061a663e8778e7d5c Merge: 33fcab5 25f9fd5 Author: Christoph Jentzsch Date: Mon Oct 6 10:31:51 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 33fcab57273731f449e9504d15c5d22cbe773e2a Author: Christoph Jentzsch Date: Mon Oct 6 10:30:04 2014 +0200 Bug fix, corrected gasLimit in vmSystemOperationsTest commit 25f9fd542a4ab27a5a66668a72b84d4bf7c292e6 Author: Vitalik Buterin Date: Sat Oct 4 15:47:00 2014 -0400 one more vm test commit 2d561a5373faf392e51f8c579c936549db2966d3 Author: Vitalik Buterin Date: Sat Oct 4 15:15:37 2014 -0400 separated out vmtests commit b0c48fa8d69ae02e01931a5675fc58ff9e84aba3 Merge: cb8261a 6cae166 Author: vbuterin Date: Sat Oct 4 17:18:02 2014 +0100 Merge pull request #13 from CJentzsch/develop Added comprehensive EVM test suite. All commands are tested. commit 6cae166f6f1e3f4eaaef6a9036c597b6064b263a Author: Christoph Jentzsch Date: Wed Oct 1 15:34:23 2014 +0200 Delete tmp.json commit 4ff906fbc271ee3aee3eb5db135e591eb187793a Author: Christoph Jentzsch Date: Wed Oct 1 14:06:32 2014 +0200 corrected CALLSTATELESS tests commit 5b3fee6806a69545e572725add73c297e9473eee Author: Christoph Jentzsch Date: Mon Sep 29 13:08:44 2014 +0200 Completed vm tests. Added ADDMOD, MULMOD, POST, CALLSTATELESS commit 9cdd2180833d98cf967929e07cab6638c2e933d0 Author: Christoph Jentzsch Date: Sat Sep 27 21:48:09 2014 +0200 Added IOandFlowOperation-, PushDupSwap- and SystemOperations- tests. Removed empty storage from adresses. commit 28ed968b46590bd8f3e5bb25606e8f83e0ee9b9e Author: Christoph Jentzsch Date: Tue Sep 23 15:49:22 2014 +0200 Added blockInfoTest commit ffbd5a35b597d2908fa0fa37d9b2aeaf30aee155 Author: Christoph Jentzsch Date: Tue Sep 23 15:37:52 2014 +0200 Added environmentalInfo- and sha3- test commit 54c14f1ff3f7ec66d755181be32a13e0404110d9 Author: Christoph Jentzsch Date: Mon Sep 22 13:06:57 2014 +0200 Added bitwise logic operation test commit d0af113aab3991fecbde29933f4a77884fafdf60 Author: Christoph Jentzsch Date: Sat Sep 20 01:42:51 2014 +0200 Added vm arithmetic test commit cb8261a78b56197e421bce5ac2afb7147f5acb45 Author: Jeffrey Wilcke Date: Fri Sep 19 13:15:44 2014 +0200 Update genesishashestest.json commit 4513623da1110e74a236abf0357ad00ff7a38126 Author: Maran Date: Tue Jul 22 12:24:46 2014 +0200 Update keyaddrtest to be valid JSON commit e8cb5c221d4763c8c26ac73f99609b64a595f4b3 Author: Vitalik Buterin Date: Mon Jul 21 23:30:33 2014 -0400 Added next/prev trie test commit 98823c04b30ef0be478c69a11edc3f9f6dff567e Author: Vitalik Buterin Date: Mon Jul 14 02:51:31 2014 -0400 Replaced with deterministic test commit 357eb21e4d5d9d6713ba7c63a76bd597a57d6a0e Author: Vitalik Buterin Date: Sun Jul 13 16:12:56 2014 -0400 Added my own random and namecoin tests (pyethereum) commit 00cd0cce8f0fc0ca8aa2c8ca424954d4932672f2 Author: Gav Wood Date: Sat Jul 12 21:20:04 2014 +0200 Output hex strings. commit ddfa3af45da9d5d81da38745ae23ee93ce390c2b Author: Gav Wood Date: Thu Jul 10 11:28:35 2014 +0100 Everything a string. commit d659f469a9ddcdd144a332da64b826908b0f7872 Author: Gav Wood Date: Thu Jul 10 10:16:25 2014 +0100 Code fixes. commit 5e83ea82283f042df384d7ff20183ba51760d893 Author: Gav Wood Date: Sun Jul 6 16:17:12 2014 +0200 Prettier VM tests. commit a09aae0efe9a1cb94be3e0386532c532262956ec Author: Gav Wood Date: Sun Jul 6 15:46:01 2014 +0200 Fix VM tests. commit ec9a044a17779f0b3814bffa8c058b4091d6d13d Merge: 4bb6461 5e0123f Author: Jeffrey Wilcke Date: Fri Jul 4 15:56:52 2014 +0200 Merge pull request #10 from romanman/patch-1 Update vmtests.json commit 5e0123fbe1573dcf8157995f3ef2f7ce625235a4 Author: romanman Date: Fri Jul 4 10:23:04 2014 +0100 Update vmtests.json commit 2b6da2f5f21b60ebca44a5866888b00f736f92b2 Author: romanman Date: Thu Jul 3 17:45:04 2014 +0100 Update vmtests.json arith testcase updated commit 4bb646117d0034fb459c07e6955b1c9cca802fa9 Merge: bba3898 a33b309 Author: Gav Wood Date: Wed Jul 2 19:43:22 2014 +0200 Merge branch 'develop' of github.com:/ethereum/tests into develop commit bba38980bdfa6ba6fddf0419479ad2405a3cb079 Author: Gav Wood Date: Wed Jul 2 19:43:06 2014 +0200 New tests. commit a33b309d99b36c4c57083d5e77422c3f2bba4bbe Author: Vitalik Buterin Date: Wed Jul 2 10:14:05 2014 -0400 Testing submodules commit 50318217ca875d23147eddfa7cc0326242db90bf Author: Vitalik Buterin Date: Wed Jul 2 10:10:46 2014 -0400 Testing submodules commit 57fa655522fc9696adcc7a6a25b64afd569b0758 Author: Vitalik Buterin Date: Wed Jul 2 10:09:08 2014 -0400 Testing submodules commit ea0eb0a8c82521322bd0359d1c42fc013c433d2e Author: Gav Wood Date: Tue Jul 1 15:19:34 2014 +0200 Latest genesis block. commit 25bb76b69c90ebd44a271d7c180a4a4b86845018 Author: Jeffrey Wilcke Date: Mon Jun 30 13:25:04 2014 +0200 Reset commit 74c6d8424e7d91ccd592c179794bc74e63c0d8c0 Author: Jeffrey Wilcke Date: Mon Jun 30 12:10:06 2014 +0200 Updated wrong test commit 9ea3a60291f2ca68a54198d53e4c40fffb09f6b3 Author: Jeffrey Wilcke Date: Sat Jun 28 18:48:28 2014 +0200 Fixed roots commit 5fc3ac0e925cdfe95632024f574fb945558491b8 Author: Gav Wood Date: Sat Jun 28 18:40:06 2014 +0200 Simple hex test. commit edd3a00c2a8d78867d8bb1557697455729a03027 Author: Gav Wood Date: Sat Jun 28 18:22:18 2014 +0200 Additional test for jeff. Now use the 0x... notation. commit 5021e0dd83bdb8b23ca3dcc72293c6737e8165a8 Author: Gav Wood Date: Fri Jun 27 21:35:26 2014 +0200 VM test framework updated. commit c818d132022c228c5b04ab82871f5971049b0c6d Author: Gav Wood Date: Fri Jun 27 18:18:24 2014 +0200 Removed arrays from Trie tests JSON as per conformance guide and changed vocabulary to match other tests. VM test updates. commit 714770ffb3bb037e2daeaa37a6f4f4066387abe3 Author: Gav Wood Date: Wed Jun 11 11:32:42 2014 +0100 Added Gav's new address. commit 9345bc13d40e6d288c37b650ace1db0c41a89d84 Merge: a2257f3 78576dd Author: Gav Wood Date: Fri May 30 17:50:38 2014 +0200 Merge branch 'master' of github.com:ethereum/tests into develop commit a2257f3471dd4b472bc156be4575ea0f26a8a046 Author: Gav Wood Date: Fri May 30 17:50:18 2014 +0200 VM tests. commit 78576dd3d3d4bf46af19d703affdd42f221e49c9 Author: Heiko Heiko Date: Fri May 30 17:19:09 2014 +0200 changes based on new account structure nonce, balance, storage, code commit 125839e84833ec25e0fdd4fbd545772ba706fe6b Merge: 42e14ec 356a329 Author: Jeffrey Wilcke Date: Thu May 22 09:58:45 2014 +0200 Merge pull request #5 from bkirwi/master Fix invalid JSON (removed trailing comma) and add test names commit 356a3296bc7eeac8b1b65aa843b5856cd786c4cf Author: Ben Kirwin Date: Thu May 22 00:20:48 2014 -0400 Add some arbitrary test names This should now conform to the format specified in the README. commit 42e14ec54fa57c2373625d21e5b47f597c748bf5 Author: Chen Houwu Date: Wed May 21 23:27:40 2014 +0800 revert to correct data commit 4300197a748de29cc5c93fd77f13cae029dad49e Author: Chen Houwu Date: Wed May 21 22:42:23 2014 +0800 fix: wrong sha3 hash because of the wrong rlp hex commit a0d01b1a0b59555e38ea694ff864f2aa25a0d953 Author: Chen Houwu Date: Wed May 21 22:29:53 2014 +0800 fix: wrong rlp hex commit 6bc2fc74054a418e7cfca9cf9144237a5e4fa65f Merge: 66bc366 c31a93c Author: Jeffrey Wilcke Date: Wed May 21 14:11:37 2014 +0200 Merge pull request #4 from ethers/master fix file name that seems to have been a typo commit c31a93c27a9048df92fcf53a2201c6e3737a40fd Author: ethers Date: Tue May 20 15:42:39 2014 -0700 fix file name that seems to have been a typo commit 66bc3665c17e1eec309e5a40b2a9c74273fb639a Author: Heiko Heiko Date: Tue May 20 17:36:35 2014 +0200 fix: represent integers as strings commit ede5499da624d95db1cad63939be56f7bdaa6389 Author: Heiko Heiko Date: Tue May 20 17:21:09 2014 +0200 add: current initial alloc and genesis hashes commit 5131429abbe6d2636064e17b45c99827a904c345 Author: Ben Kirwin Date: Mon May 19 11:18:31 2014 -0400 Delete a comma This should now be parseable as JSON. commit f44a85933110dd3ef362090f512678e99ae80256 Author: Chen Houwu Date: Sun May 18 15:04:42 2014 +0800 add: case when value is long, ensure it's not get rlp encoded as node commit e1ae4ad4495dd13fba6346274971a8871cb32607 Author: Gav Wood Date: Mon May 12 14:40:47 2014 +0100 PoC-5 VM tests. commit 2b6c136dda0d55a0ebd228bff029d97411c9cec6 Author: Vitalik Buterin Date: Sun May 11 21:42:41 2014 -0400 Moved txt to json commit cbccbf977ca7bde15a661a4b453ea062e62ac856 Merge: edbb8d4 45a0974 Author: Vitalik Buterin Date: Thu May 8 21:54:48 2014 -0400 New commit commit edbb8d407ecfbcbb6504659cbd9bdabdb93369e3 Author: Vitalik Buterin Date: Tue May 6 16:53:43 2014 -0400 Removed unneeded test, added new tests commit 45a0974f6f32511119e40a27042fdd571fe47a16 Merge: 15dd8fd 5fd2a98 Author: Gav Wood Date: Sun Apr 27 12:53:47 2014 +0100 Merge pull request #3 from autolycus/develop Fixed formatting and added test cases commit 5fd2a98fcb4f6a648160204d1b20b0f980d55b9d Author: Carl Allendorph Date: Sat Apr 19 13:26:14 2014 -0700 Added some new test cases for the rlp encoding. commit 4ba150954ef8ac72416a35f06fdad9c6d7ed461d Author: Carl Allendorph Date: Sat Apr 19 12:48:42 2014 -0700 Converted spaces to tabs to be compliant with the coding standards defined in cpp-ethereum commit 15dd8fd794a0dc305ef7696d0c2a68e032bc9759 Author: Gav Wood Date: Fri Feb 28 12:54:47 2014 +0000 RLP tests and Trie updates. commit 33f80fef211c2d51162c1856e50448be3d90c214 Author: Gav Wood Date: Fri Feb 28 11:39:35 2014 +0000 Hex encode tests done. commit e1f5e12abb38f8cedb4a589b1347fb01c3da902a Author: Gav Wood Date: Fri Feb 28 11:22:49 2014 +0000 Fix RLP tests. commit f87ce15ad201a6d97e2654e5dc5a3181873d1719 Author: Gav Wood Date: Thu Feb 27 13:28:11 2014 +0000 Fix empty string. commit c006ed4ffd7d00124dbcb44d4e7ca05d6d9ddc12 Author: Gav Wood Date: Mon Feb 24 10:24:39 2014 +0000 Tests fix. commit 510ff563639e71224306d9af0e50a28a9d624b8f Author: Gav Wood Date: Fri Feb 21 18:54:08 2014 +0000 Updated the tests. commit a0ec84383218ea80b4c0b99e09710fae182a2379 Author: Gav Wood Date: Fri Feb 21 18:49:24 2014 +0000 Moved over to new format, but RLP tests still need updating. commit 660cd26f31b3979149950c1fdea995b85a774c1c Author: Gav Wood Date: Fri Feb 21 18:35:51 2014 +0000 More docs. commit 6ad14c1a157e707fd15c87816e8ad872f69790db Author: Gav Wood Date: Fri Feb 21 18:33:39 2014 +0000 Added VM test suite. Added TODO. Renamed old files. commit f91ad7b3857ec9157e7df7f315d942afb7594da0 Author: Vitalik Buterin Date: Wed Jan 8 11:26:58 2014 -0500 update trie algorithm commit 6da295446203889ac5a4a365b397bb45766c9ad8 Merge: cc42246 131c610 Author: Vitalik Buterin Date: Wed Jan 8 08:15:38 2014 -0500 merge commit cc4224675f1f70242f91ee7d2d1295bed6f0dc01 Author: Vitalik Buterin Date: Tue Jan 7 14:35:26 2014 -0500 Updated trie test commit 131c610da66203f708391485aa42fc7a81f01ef7 Merge: 121632b 7613302 Author: vbuterin Date: Wed Jan 1 06:40:54 2014 -0800 Merge pull request #1 from obscuren/master Update trietest.txt commit 7613302b491b3f6406b1ea3c8292adf6d41860d0 Author: obscuren Date: Wed Jan 1 15:25:21 2014 +0100 Update trietest.txt New proposed explanatory format commit 121632bedd1c84a0af847b923aa4b803556722c0 Author: Vitalik Buterin Date: Wed Jan 1 08:26:18 2014 -0500 Added obscure's tests commit ef6c5506c3fcdecf779184ad81d92db9315c2488 Author: Vitalik Buterin Date: Tue Dec 31 19:04:48 2013 -0500 Fixed tests a bit commit 345e4bcfefb45a66a09b1761570405a03c67b9d2 Merge: 2c81698 e4bbea4 Author: Vitalik Buterin Date: Tue Dec 31 15:52:46 2013 -0500 Merge branch 'master' of github.com:ethereum/tests commit 2c81698f31e7e579335a2ab8706f96397a68f018 Author: Vitalik Buterin Date: Mon Dec 30 21:09:40 2013 -0500 Added first three tests commit e4bbea400f7df275faf47ea643256d68495b35aa Author: vbuterin Date: Mon Dec 30 18:09:03 2013 -0800 Initial commit --- vm/vm_debug.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 05ae347f6..b53949493 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -41,6 +41,21 @@ func NewDebugVm(env Environment) *DebugVm { func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.depth++ + if self.Recoverable { + // Recover from any require exception + defer func() { + if r := recover(); r != nil { + self.Endl() + + ret = closure.Return(nil) + + err = fmt.Errorf("%v", r) + // No error should be set. Recover is used with require + // Is this too error prone? + } + }() + } + var ( op OpCode @@ -76,19 +91,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } ) - if self.Recoverable { - // Recover from any require exception - defer func() { - if r := recover(); r != nil { - self.Endl() - - ret = closure.Return(nil) - // No error should be set. Recover is used with require - // Is this too error prone? - } - }() - } - // Debug hook if self.Dbg != nil { self.Dbg.SetCode(closure.Code) -- cgit v1.2.3 From 8cfbf1836d68c49242703e3f59e4d0a06754c02b Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 4 Nov 2014 18:17:38 +0100 Subject: Added JUMP analysis (WIP) --- vm/analysis.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 vm/analysis.go (limited to 'vm') diff --git a/vm/analysis.go b/vm/analysis.go new file mode 100644 index 000000000..784b55459 --- /dev/null +++ b/vm/analysis.go @@ -0,0 +1,35 @@ +package vm + +import ( + "math/big" + + "github.com/ethgo.old/ethutil" +) + +func analyseJumpDests(code []byte) (dests map[int64]*big.Int) { + dests = make(map[int64]*big.Int) + + lp := false + var lpv *big.Int + for pc := int64(0); pc < int64(len(code)); pc++ { + var op OpCode = OpCode(code[pc]) + switch op { + 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 := int64(op) - int64(PUSH1) + 1 + if int64(len(code)) > pc+1+a { + lpv = ethutil.BigD(code[pc+1 : pc+1+a]) + } + + pc += a + lp = true + case JUMP, JUMPI: + if lp { + dests[pc] = lpv + } + + default: + lp = false + } + } + return +} -- cgit v1.2.3 From 1b1fa049fa483b3996d3582ad247638045657282 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 4 Nov 2014 18:18:57 +0100 Subject: Fixed VM and added static analysis for EVM jumps --- vm/types.go | 33 +++++++++++++++++---------------- vm/vm_debug.go | 37 ++++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 31 deletions(-) (limited to 'vm') diff --git a/vm/types.go b/vm/types.go index 580c517d6..7dd167e0c 100644 --- a/vm/types.go +++ b/vm/types.go @@ -173,22 +173,23 @@ const ( // Since the opcodes aren't all in order we can't use a regular slice var opCodeToString = map[OpCode]string{ // 0x0 range - arithmetic ops - STOP: "STOP", - ADD: "ADD", - MUL: "MUL", - SUB: "SUB", - DIV: "DIV", - SDIV: "SDIV", - MOD: "MOD", - SMOD: "SMOD", - EXP: "EXP", - NOT: "NOT", - LT: "LT", - GT: "GT", - SLT: "SLT", - SGT: "SGT", - EQ: "EQ", - ISZERO: "ISZERO", + STOP: "STOP", + ADD: "ADD", + MUL: "MUL", + SUB: "SUB", + DIV: "DIV", + SDIV: "SDIV", + MOD: "MOD", + SMOD: "SMOD", + EXP: "EXP", + NOT: "NOT", + LT: "LT", + GT: "GT", + SLT: "SLT", + SGT: "SGT", + EQ: "EQ", + ISZERO: "ISZERO", + SIGNEXTEND: "SIGNEXTEND", // 0x10 range - bit ops AND: "AND", diff --git a/vm/vm_debug.go b/vm/vm_debug.go index b53949493..df5d7e346 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -59,32 +59,34 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var ( op OpCode - mem = &Memory{} - stack = NewStack() - pc = big.NewInt(0) - step = 0 - prevStep = 0 - statedb = self.env.State() - require = func(m int) { + destinations = analyseJumpDests(closure.Code) + mem = &Memory{} + stack = NewStack() + pc = big.NewInt(0) + step = 0 + prevStep = 0 + statedb = self.env.State() + require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) } } - jump = func(pos *big.Int) { - p := int(pos.Int64()) + jump = func(from, to *big.Int) { + p := int(to.Int64()) - self.Printf(" ~> %v", pos) + self.Printf(" ~> %v", to) // Return to start if p == 0 { pc = big.NewInt(0) } else { - nop := OpCode(closure.GetOp(p - 1)) - if nop != JUMPDEST { + nop := OpCode(closure.GetOp(p)) + if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) } - pc = pos + pc = to + } self.Endl() @@ -406,6 +408,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } else { num.And(num, mask) } + + num = U256(num) + + self.Printf(" = %v", num) + stack.Push(num) } case NOT: @@ -765,14 +772,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: - jump(stack.Pop()) + jump(pc, stack.Pop()) continue case JUMPI: cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) >= 0 { - jump(pos) + jump(pc, pos) continue } -- cgit v1.2.3 From 99d5769c2b966a2d6858b888bcb9e41cb6a87255 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 4 Nov 2014 18:38:19 +0100 Subject: There'll be jumping in to jumps --- vm/vm_debug.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index df5d7e346..ce7a29f99 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -83,6 +83,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { nop := OpCode(closure.GetOp(p)) if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) + } else if nop == JUMP || nop == JUMPI { + panic(fmt.Sprintf("not allowed to JUMP(I) in to JUMP")) } pc = to -- cgit v1.2.3 From b4da085a9fa0b578c7e91a9606a15a018b340d95 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Nov 2014 00:34:04 +0100 Subject: Accidental packages --- vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/analysis.go b/vm/analysis.go index 784b55459..22feb4c94 100644 --- a/vm/analysis.go +++ b/vm/analysis.go @@ -3,7 +3,7 @@ package vm import ( "math/big" - "github.com/ethgo.old/ethutil" + "github.com/ethereum/ethutil" ) func analyseJumpDests(code []byte) (dests map[int64]*big.Int) { -- cgit v1.2.3 From 48488017e498916c81122c01cfe1880afdd00d48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 5 Nov 2014 00:34:59 +0100 Subject: Proper packages --- vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/analysis.go b/vm/analysis.go index 22feb4c94..52c7143e0 100644 --- a/vm/analysis.go +++ b/vm/analysis.go @@ -3,7 +3,7 @@ package vm import ( "math/big" - "github.com/ethereum/ethutil" + "github.com/ethereum/go-ethereum/ethutil" ) func analyseJumpDests(code []byte) (dests map[int64]*big.Int) { -- cgit v1.2.3 From d30571a7a84de5a1a3287e764210a3803d7a307f Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 10 Nov 2014 11:47:37 +0100 Subject: Added VM testing tool --- vm/vm_debug.go | 3 +-- vm/vm_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ce7a29f99..2d34758f5 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -50,8 +50,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - // No error should be set. Recover is used with require - // Is this too error prone? + } }() } diff --git a/vm/vm_test.go b/vm/vm_test.go index f5d77cbff..948dd835f 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -169,3 +169,21 @@ func TestBuildInRipemd(t *testing.T) { t.Errorf("Expected %x, got %x", exp, ret) } } + +func TestOog(t *testing.T) { + // This tests takes a long time and will eventually run out of gas + //t.Skip() + + logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) + + vm := New(TestEnv{}, DebugVmTy) + _, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println(e) + } +} -- cgit v1.2.3 From 6c9e503eb8d41d331d6a74e69539a06590072190 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 11 Nov 2014 22:51:26 +0100 Subject: Removed all implicit logging. Fixed gas issues and jump errors --- vm/environment.go | 2 +- vm/vm_debug.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index dea86c66c..5604989e1 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,7 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error - AddLog(state.Log) + AddLog(*state.Log) } type Object interface { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 2d34758f5..290eddda4 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -47,6 +47,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if r := recover(); r != nil { self.Endl() + closure.UseGas(closure.Gas) + ret = closure.Return(nil) err = fmt.Errorf("%v", r) @@ -735,7 +737,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { for i := 0; i < n; i++ { topics[i] = stack.Pop().Bytes() } - self.env.AddLog(state.Log{closure.Address(), topics, data}) + self.env.AddLog(&state.Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) -- cgit v1.2.3 From 60cdb1148c404218846fd39331690658168f4e04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 12 Nov 2014 01:36:36 +0100 Subject: Transaction execution fixes --- vm/closure.go | 4 ++++ vm/types.go | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index 8e54e9ce6..ef9bbca93 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -138,3 +138,7 @@ func (c *Closure) Object() *state.StateObject { func (c *Closure) Caller() ClosureRef { return c.caller } + +func (self *Closure) SetExecution(exe *Execution) { + self.exe = exe +} diff --git a/vm/types.go b/vm/types.go index 7dd167e0c..0b20fb655 100644 --- a/vm/types.go +++ b/vm/types.go @@ -309,6 +309,12 @@ var opCodeToString = map[OpCode]string{ SWAP15: "SWAP15", SWAP16: "SWAP16", + LOG0: "LOG0", + LOG1: "LOG1", + LOG2: "LOG2", + LOG3: "LOG3", + LOG4: "LOG4", + // 0xf0 range CREATE: "CREATE", CALL: "CALL", -- cgit v1.2.3 From 20d518ee959f1621a5accf1f3432282a6c0d6c3c Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 13 Nov 2014 18:12:12 +0100 Subject: Numerous fixes for consensus. * Removed (buged) C++ specific gas specification for LOG* * Fixed LOG* where mstart went after msize * --- vm/vm_debug.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 290eddda4..37ad7620e 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -169,6 +169,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Add(mSize, mStart)) + // BUG in C++ + //gas.Set(ethutil.Big1) // Gas only case STOP: gas.Set(ethutil.Big0) @@ -732,12 +734,16 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) topics := make([][]byte, n) - mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() + mStart, mSize := stack.Pop().Int64(), stack.Pop().Int64() data := mem.Geti(mStart, mSize) for i := 0; i < n; i++ { topics[i] = stack.Pop().Bytes() } - self.env.AddLog(&state.Log{closure.Address(), topics, data}) + + log := &state.Log{closure.Address(), topics, data} + self.env.AddLog(log) + + self.Printf(" => %v", log) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32)) -- cgit v1.2.3 From f6e55962a8cadfb440dd03467017941b96838362 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 14 Nov 2014 13:47:12 +0100 Subject: Fixes for PV41/42 * Don't expand mem on empty value * Removed all coinbase logs for PV42 * Removed C++ bug stuff for LOG* --- vm/execution.go | 2 ++ vm/stack.go | 28 +++++++++++++++++----------- vm/vm_debug.go | 15 +++++++++------ 3 files changed, 28 insertions(+), 17 deletions(-) (limited to 'vm') diff --git a/vm/execution.go b/vm/execution.go index 401157808..c23164f82 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -34,11 +34,13 @@ func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, err error) { env := self.vm.Env() + vmlogger.Debugf("pre state %x\n", env.State().Root()) snapshot := env.State().Copy() defer func() { if IsDepthErr(err) || IsOOGErr(err) { env.State().Set(snapshot) } + vmlogger.Debugf("post state %x\n", env.State().Root()) }() msg := env.State().Manifest().AddMessage(&state.Message{ diff --git a/vm/stack.go b/vm/stack.go index 69ded6562..2eca60ad1 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -107,20 +107,26 @@ type Memory struct { store []byte } +func NewMemory() *Memory { + return &Memory{nil} +} + func (m *Memory) Set(offset, size int64, value []byte) { - totSize := offset + size - lenSize := int64(len(m.store) - 1) - if totSize > lenSize { - // Calculate the diff between the sizes - diff := totSize - lenSize - if diff > 0 { - // Create a new empty slice and append it - newSlice := make([]byte, diff-1) - // Resize slice - m.store = append(m.store, newSlice...) + if len(value) > 0 { + totSize := offset + size + lenSize := int64(len(m.store) - 1) + if totSize > lenSize { + // Calculate the diff between the sizes + diff := totSize - lenSize + if diff > 0 { + // Create a new empty slice and append it + newSlice := make([]byte, diff-1) + // Resize slice + m.store = append(m.store, newSlice...) + } } + copy(m.store[offset:offset+size], value) } - copy(m.store[offset:offset+size], value) } func (m *Memory) Resize(size uint64) { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 37ad7620e..ae5a20175 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -61,7 +61,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { op OpCode destinations = analyseJumpDests(closure.Code) - mem = &Memory{} + mem = NewMemory() stack = NewStack() pc = big.NewInt(0) step = 0 @@ -169,8 +169,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Add(mSize, mStart)) - // BUG in C++ - //gas.Set(ethutil.Big1) // Gas only case STOP: gas.Set(ethutil.Big0) @@ -263,11 +261,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { memGasUsage.Div(memGasUsage, u256(32)) addStepGasUsage(memGasUsage) + + mem.Resize(newMemSize.Uint64()) } + } self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - self.Printf(" (g) %-3v (%v)", gas, closure.Gas) + self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), gas, closure.Gas) if !closure.UseGas(gas) { self.Endl() @@ -279,8 +280,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(nil), OOG(gas, tmp) } - mem.Resize(newMemSize.Uint64()) - switch op { // 0x20 range case ADD: @@ -622,6 +621,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { code := closure.Args[cOff : cOff+l] mem.Set(mOff, l, code) + + self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { @@ -663,6 +664,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { codeCopy := code[cOff : cOff+l] mem.Set(mOff, l, codeCopy) + + self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) case GASPRICE: stack.Push(closure.Price) -- cgit v1.2.3 From 2a9fc7baa908d64ff1ddae44641024114d3ec88d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Fri, 14 Nov 2014 15:01:52 -0600 Subject: Merge branch 'develop' of https://github.com/tgerring/go-ethereum --- vm/vm_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 948dd835f..ed05cddfb 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/trie" - "github.com/obscuren/mutan" + // "github.com/obscuren/mutan" ) type TestEnv struct{} @@ -67,9 +67,9 @@ func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") func TestDebugVm(t *testing.T) { - if mutan.Version < "0.6" { - t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - } + // if mutan.Version < "0.6" { + // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + // } closure, vm := setup(logger.DebugLevel, DebugVmTy) ret, _, e := closure.Call(vm, nil) @@ -82,9 +82,9 @@ func TestDebugVm(t *testing.T) { } func TestVm(t *testing.T) { - if mutan.Version < "0.6" { - t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - } + // if mutan.Version < "0.6" { + // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + // } closure, vm := setup(logger.DebugLevel, StandardVmTy) ret, _, e := closure.Call(vm, nil) -- cgit v1.2.3 From dd9e99a418be6cde1a99a04659493edddeb6d455 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Fri, 14 Nov 2014 20:58:09 -0600 Subject: try to get full coverage report on travis --- vm/vm_test.go | 358 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 179 insertions(+), 179 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index ed05cddfb..d9e2a3295 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -1,189 +1,189 @@ package vm -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "math/big" - "os" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/trie" - // "github.com/obscuren/mutan" -) - -type TestEnv struct{} - -func (TestEnv) Origin() []byte { return nil } -func (TestEnv) BlockNumber() *big.Int { return nil } -func (TestEnv) BlockHash() []byte { return nil } -func (TestEnv) PrevHash() []byte { return nil } -func (TestEnv) Coinbase() []byte { return nil } -func (TestEnv) Time() int64 { return 0 } -func (TestEnv) GasLimit() *big.Int { return nil } -func (TestEnv) Difficulty() *big.Int { return nil } -func (TestEnv) Value() *big.Int { return nil } -func (TestEnv) AddLog(state.Log) {} - -func (TestEnv) Transfer(from, to Account, amount *big.Int) error { - return nil -} - -// This is likely to fail if anything ever gets looked up in the state trie :-) -func (TestEnv) State() *state.State { - return state.New(trie.New(nil, "")) -} - -const mutcode = ` -var x = 0; -for i := 0; i < 10; i++ { - x = i -} - -return x` - -func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { - code, err := ethutil.Compile(mutcode, true) - if err != nil { - log.Fatal(err) - } - - // Pipe output to /dev/null - logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) - - return callerClosure, New(TestEnv{}, typ) -} - -var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") - -func TestDebugVm(t *testing.T) { - // if mutan.Version < "0.6" { - // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - // } - - closure, vm := setup(logger.DebugLevel, DebugVmTy) - ret, _, e := closure.Call(vm, nil) - if e != nil { - t.Fatalf("Call returned error: %v", e) - } - if !bytes.Equal(ret, big9) { - t.Errorf("Wrong return value '%x', want '%x'", ret, big9) - } -} - -func TestVm(t *testing.T) { - // if mutan.Version < "0.6" { - // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - // } - - closure, vm := setup(logger.DebugLevel, StandardVmTy) - ret, _, e := closure.Call(vm, nil) - if e != nil { - t.Fatalf("Call returned error: %v", e) - } - if !bytes.Equal(ret, big9) { - t.Errorf("Wrong return value '%x', want '%x'", ret, big9) - } -} - -func BenchmarkDebugVm(b *testing.B) { - closure, vm := setup(logger.InfoLevel, DebugVmTy) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - closure.Call(vm, nil) - } -} - -func BenchmarkVm(b *testing.B) { - closure, vm := setup(logger.InfoLevel, StandardVmTy) - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - closure.Call(vm, nil) - } -} - -func RunCode(mutCode string, typ Type) []byte { - code, err := ethutil.Compile(mutCode, true) - if err != nil { - log.Fatal(err) - } - - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) +// import ( +// "bytes" +// "fmt" +// "io/ioutil" +// "log" +// "math/big" +// "os" +// "testing" + +// "github.com/ethereum/go-ethereum/crypto" +// "github.com/ethereum/go-ethereum/ethutil" +// "github.com/ethereum/go-ethereum/logger" +// "github.com/ethereum/go-ethereum/state" +// "github.com/ethereum/go-ethereum/trie" +// // "github.com/obscuren/mutan" +// ) + +// type TestEnv struct{} + +// func (TestEnv) Origin() []byte { return nil } +// func (TestEnv) BlockNumber() *big.Int { return nil } +// func (TestEnv) BlockHash() []byte { return nil } +// func (TestEnv) PrevHash() []byte { return nil } +// func (TestEnv) Coinbase() []byte { return nil } +// func (TestEnv) Time() int64 { return 0 } +// func (TestEnv) GasLimit() *big.Int { return nil } +// func (TestEnv) Difficulty() *big.Int { return nil } +// func (TestEnv) Value() *big.Int { return nil } +// func (TestEnv) AddLog(state.Log) {} + +// func (TestEnv) Transfer(from, to Account, amount *big.Int) error { +// return nil +// } + +// // This is likely to fail if anything ever gets looked up in the state trie :-) +// func (TestEnv) State() *state.State { +// return state.New(trie.New(nil, "")) +// } + +// const mutcode = ` +// var x = 0; +// for i := 0; i < 10; i++ { +// x = i +// } + +// return x` + +// func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { +// code, err := ethutil.Compile(mutcode, true) +// if err != nil { +// log.Fatal(err) +// } + +// // Pipe output to /dev/null +// logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) + +// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + +// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) +// callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) + +// return callerClosure, New(TestEnv{}, typ) +// } + +// var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") + +// func TestDebugVm(t *testing.T) { +// // if mutan.Version < "0.6" { +// // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") +// // } + +// closure, vm := setup(logger.DebugLevel, DebugVmTy) +// ret, _, e := closure.Call(vm, nil) +// if e != nil { +// t.Fatalf("Call returned error: %v", e) +// } +// if !bytes.Equal(ret, big9) { +// t.Errorf("Wrong return value '%x', want '%x'", ret, big9) +// } +// } + +// func TestVm(t *testing.T) { +// // if mutan.Version < "0.6" { +// // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") +// // } + +// closure, vm := setup(logger.DebugLevel, StandardVmTy) +// ret, _, e := closure.Call(vm, nil) +// if e != nil { +// t.Fatalf("Call returned error: %v", e) +// } +// if !bytes.Equal(ret, big9) { +// t.Errorf("Wrong return value '%x', want '%x'", ret, big9) +// } +// } + +// func BenchmarkDebugVm(b *testing.B) { +// closure, vm := setup(logger.InfoLevel, DebugVmTy) + +// b.ResetTimer() + +// for i := 0; i < b.N; i++ { +// closure.Call(vm, nil) +// } +// } + +// func BenchmarkVm(b *testing.B) { +// closure, vm := setup(logger.InfoLevel, StandardVmTy) + +// b.ResetTimer() + +// for i := 0; i < b.N; i++ { +// closure.Call(vm, nil) +// } +// } + +// func RunCode(mutCode string, typ Type) []byte { +// code, err := ethutil.Compile(mutCode, true) +// if err != nil { +// log.Fatal(err) +// } + +// logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) + +// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + +// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) +// closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) - vm := New(TestEnv{}, typ) - ret, _, e := closure.Call(vm, nil) - if e != nil { - fmt.Println(e) - } - - return ret -} +// vm := New(TestEnv{}, typ) +// ret, _, e := closure.Call(vm, nil) +// if e != nil { +// fmt.Println(e) +// } + +// return ret +// } -func TestBuildInSha256(t *testing.T) { - ret := RunCode(` - var in = 42 - var out = 0 +// func TestBuildInSha256(t *testing.T) { +// ret := RunCode(` +// var in = 42 +// var out = 0 - call(0x2, 0, 10000, in, out) +// call(0x2, 0, 10000, in, out) - return out - `, DebugVmTy) - - exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) - if bytes.Compare(ret, exp) != 0 { - t.Errorf("Expected %x, got %x", exp, ret) - } -} +// return out +// `, DebugVmTy) + +// exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) +// if bytes.Compare(ret, exp) != 0 { +// t.Errorf("Expected %x, got %x", exp, ret) +// } +// } -func TestBuildInRipemd(t *testing.T) { - ret := RunCode(` - var in = 42 - var out = 0 - - call(0x3, 0, 10000, in, out) +// func TestBuildInRipemd(t *testing.T) { +// ret := RunCode(` +// var in = 42 +// var out = 0 + +// call(0x3, 0, 10000, in, out) - return out - `, DebugVmTy) - - exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) - if bytes.Compare(ret, exp) != 0 { - t.Errorf("Expected %x, got %x", exp, ret) - } -} - -func TestOog(t *testing.T) { - // This tests takes a long time and will eventually run out of gas - //t.Skip() - - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") +// return out +// `, DebugVmTy) + +// exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) +// if bytes.Compare(ret, exp) != 0 { +// t.Errorf("Expected %x, got %x", exp, ret) +// } +// } + +// func TestOog(t *testing.T) { +// // This tests takes a long time and will eventually run out of gas +// // t.Skip() + +// logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) + +// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) +// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) +// closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) - vm := New(TestEnv{}, DebugVmTy) - _, _, e := closure.Call(vm, nil) - if e != nil { - fmt.Println(e) - } -} +// vm := New(TestEnv{}, DebugVmTy) +// _, _, e := closure.Call(vm, nil) +// if e != nil { +// fmt.Println(e) +// } +// } -- cgit v1.2.3 From 9095b37343c5149c84433841599ca13327219422 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Sun, 16 Nov 2014 13:45:46 -0600 Subject: Convert vm test to checker Tests are skipped due to reliance on deprecated mutan --- vm/main_test.go | 9 ++ vm/vm_test.go | 358 +++++++++++++++++++++++++++----------------------------- 2 files changed, 184 insertions(+), 183 deletions(-) create mode 100644 vm/main_test.go (limited to 'vm') diff --git a/vm/main_test.go b/vm/main_test.go new file mode 100644 index 000000000..0ae03bf6a --- /dev/null +++ b/vm/main_test.go @@ -0,0 +1,9 @@ +package vm + +import ( + "testing" + + checker "gopkg.in/check.v1" +) + +func Test(t *testing.T) { checker.TestingT(t) } diff --git a/vm/vm_test.go b/vm/vm_test.go index d9e2a3295..19aa171a6 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -1,189 +1,181 @@ package vm -// import ( -// "bytes" -// "fmt" -// "io/ioutil" -// "log" -// "math/big" -// "os" -// "testing" - -// "github.com/ethereum/go-ethereum/crypto" -// "github.com/ethereum/go-ethereum/ethutil" -// "github.com/ethereum/go-ethereum/logger" -// "github.com/ethereum/go-ethereum/state" -// "github.com/ethereum/go-ethereum/trie" -// // "github.com/obscuren/mutan" -// ) - -// type TestEnv struct{} - -// func (TestEnv) Origin() []byte { return nil } -// func (TestEnv) BlockNumber() *big.Int { return nil } -// func (TestEnv) BlockHash() []byte { return nil } -// func (TestEnv) PrevHash() []byte { return nil } -// func (TestEnv) Coinbase() []byte { return nil } -// func (TestEnv) Time() int64 { return 0 } -// func (TestEnv) GasLimit() *big.Int { return nil } -// func (TestEnv) Difficulty() *big.Int { return nil } -// func (TestEnv) Value() *big.Int { return nil } -// func (TestEnv) AddLog(state.Log) {} - -// func (TestEnv) Transfer(from, to Account, amount *big.Int) error { -// return nil -// } - -// // This is likely to fail if anything ever gets looked up in the state trie :-) -// func (TestEnv) State() *state.State { -// return state.New(trie.New(nil, "")) -// } - -// const mutcode = ` -// var x = 0; -// for i := 0; i < 10; i++ { -// x = i -// } - -// return x` - -// func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { -// code, err := ethutil.Compile(mutcode, true) -// if err != nil { -// log.Fatal(err) -// } - -// // Pipe output to /dev/null -// logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) - -// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - -// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) -// callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) - -// return callerClosure, New(TestEnv{}, typ) -// } - -// var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") - -// func TestDebugVm(t *testing.T) { -// // if mutan.Version < "0.6" { -// // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") -// // } - -// closure, vm := setup(logger.DebugLevel, DebugVmTy) -// ret, _, e := closure.Call(vm, nil) -// if e != nil { -// t.Fatalf("Call returned error: %v", e) -// } -// if !bytes.Equal(ret, big9) { -// t.Errorf("Wrong return value '%x', want '%x'", ret, big9) -// } -// } - -// func TestVm(t *testing.T) { -// // if mutan.Version < "0.6" { -// // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") -// // } - -// closure, vm := setup(logger.DebugLevel, StandardVmTy) -// ret, _, e := closure.Call(vm, nil) -// if e != nil { -// t.Fatalf("Call returned error: %v", e) -// } -// if !bytes.Equal(ret, big9) { -// t.Errorf("Wrong return value '%x', want '%x'", ret, big9) -// } -// } - -// func BenchmarkDebugVm(b *testing.B) { -// closure, vm := setup(logger.InfoLevel, DebugVmTy) - -// b.ResetTimer() - -// for i := 0; i < b.N; i++ { -// closure.Call(vm, nil) -// } -// } - -// func BenchmarkVm(b *testing.B) { -// closure, vm := setup(logger.InfoLevel, StandardVmTy) - -// b.ResetTimer() - -// for i := 0; i < b.N; i++ { -// closure.Call(vm, nil) -// } -// } - -// func RunCode(mutCode string, typ Type) []byte { -// code, err := ethutil.Compile(mutCode, true) -// if err != nil { -// log.Fatal(err) -// } - -// logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - -// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - -// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) -// closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) +import ( + "fmt" + "io/ioutil" + "log" + "math/big" + "os" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/trie" + checker "gopkg.in/check.v1" + // "github.com/obscuren/mutan" +) + +type VmSuite struct{} + +var _ = checker.Suite(&VmSuite{}) +var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") + +const mutcode = ` +var x = 0; +for i := 0; i < 10; i++ { + x = i +} + +return x` + +type TestEnv struct{} + +func (TestEnv) Origin() []byte { return nil } +func (TestEnv) BlockNumber() *big.Int { return nil } +func (TestEnv) BlockHash() []byte { return nil } +func (TestEnv) PrevHash() []byte { return nil } +func (TestEnv) Coinbase() []byte { return nil } +func (TestEnv) Time() int64 { return 0 } +func (TestEnv) GasLimit() *big.Int { return nil } +func (TestEnv) Difficulty() *big.Int { return nil } +func (TestEnv) Value() *big.Int { return nil } +func (TestEnv) AddLog(*state.Log) {} +func (TestEnv) Transfer(from, to Account, amount *big.Int) error { + return nil +} + +// This is likely to fail if anything ever gets looked up in the state trie :-) +func (TestEnv) State() *state.State { + return state.New(trie.New(nil, "")) +} + +func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { + code, err := ethutil.Compile(mutcode, true) + if err != nil { + log.Fatal(err) + } + + // Pipe output to /dev/null + logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) + + return callerClosure, New(TestEnv{}, typ) +} + +func (s *VmSuite) TestDebugVm(c *checker.C) { + // if mutan.Version < "0.6" { + // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + // } + closure, vm := setup(logger.DebugLevel, DebugVmTy) + ret, _, e := closure.Call(vm, nil) + c.Assert(e, checker.NotNil) + c.Skip("Depends on mutan") + c.Assert(ret, checker.DeepEquals, big9) +} + +func (s *VmSuite) TestVm(c *checker.C) { + // if mutan.Version < "0.6" { + // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") + // } + closure, vm := setup(logger.DebugLevel, StandardVmTy) + ret, _, e := closure.Call(vm, nil) + c.Assert(e, checker.NotNil) + c.Skip("Depends on mutan") + c.Assert(ret, checker.DeepEquals, big9) +} + +func (s *VmSuite) BenchmarkDebugVm(c *checker.C) { + closure, vm := setup(logger.InfoLevel, StandardVmTy) + + c.ResetTimer() + + for i := 0; i < c.N; i++ { + closure.Call(vm, nil) + } +} + +func (s *VmSuite) BenchmarkVm(c *checker.C) { + closure, vm := setup(logger.InfoLevel, DebugVmTy) + + c.ResetTimer() + + for i := 0; i < c.N; i++ { + closure.Call(vm, nil) + } +} + +func RunCode(mutCode string, typ Type) []byte { + code, err := ethutil.Compile(mutCode, true) + if err != nil { + log.Fatal(err) + } + + logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) + + vm := New(TestEnv{}, typ) + ret, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println(e) + } + + return ret +} + +func (s *VmSuite) TestBuildInSha256(c *checker.C) { + ret := RunCode(` + var in = 42 + var out = 0 + + call(0x2, 0, 10000, in, out) + + return out + `, DebugVmTy) + + exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) + c.Skip("Depends on mutan") + c.Assert(ret, checker.DeepEquals, exp) +} + +func (s *VmSuite) TestBuildInRipemd(c *checker.C) { + ret := RunCode(` + var in = 42 + var out = 0 + + call(0x3, 0, 10000, in, out) -// vm := New(TestEnv{}, typ) -// ret, _, e := closure.Call(vm, nil) -// if e != nil { -// fmt.Println(e) -// } - -// return ret -// } + return out + `, DebugVmTy) -// func TestBuildInSha256(t *testing.T) { -// ret := RunCode(` -// var in = 42 -// var out = 0 + exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) + c.Skip("Depends on mutan") + c.Assert(ret, checker.DeepEquals, exp) +} -// call(0x2, 0, 10000, in, out) +func (s *VmSuite) TestOog(c *checker.C) { + // This tests takes a long time and will eventually run out of gas + // t.Skip() + c.Skip("This tests takes a long time and will eventually run out of gas") + + logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + + stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) + closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) -// return out -// `, DebugVmTy) - -// exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) -// if bytes.Compare(ret, exp) != 0 { -// t.Errorf("Expected %x, got %x", exp, ret) -// } -// } - -// func TestBuildInRipemd(t *testing.T) { -// ret := RunCode(` -// var in = 42 -// var out = 0 - -// call(0x3, 0, 10000, in, out) - -// return out -// `, DebugVmTy) - -// exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) -// if bytes.Compare(ret, exp) != 0 { -// t.Errorf("Expected %x, got %x", exp, ret) -// } -// } - -// func TestOog(t *testing.T) { -// // This tests takes a long time and will eventually run out of gas -// // t.Skip() - -// logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - -// ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - -// stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) -// closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) - -// vm := New(TestEnv{}, DebugVmTy) -// _, _, e := closure.Call(vm, nil) -// if e != nil { -// fmt.Println(e) -// } -// } + vm := New(TestEnv{}, DebugVmTy) + _, _, e := closure.Call(vm, nil) + if e != nil { + fmt.Println(e) + } +} -- cgit v1.2.3 From 34f29d57b6790a38019a8bcef51a6e91d2945cbe Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Nov 2014 12:03:51 +0100 Subject: Update vm_debug.go --- vm/vm_debug.go | 1 - 1 file changed, 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ae5a20175..544e04a5f 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -805,7 +805,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(closure.Gas) // 0x60 range case CREATE: - var ( err error value = stack.Pop() -- cgit v1.2.3 From 616066a598933df7ef126186eb9c647094f665ca Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 30 Nov 2014 21:02:59 +0100 Subject: rework vm --- vm/environment.go | 17 ++-- vm/execution.go | 2 +- vm/vm_debug.go | 267 ++++++++++++++++++++++++++---------------------------- 3 files changed, 141 insertions(+), 145 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index 5604989e1..bf773b5d6 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -5,11 +5,10 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" ) type Environment interface { - State() *state.State + //State() *state.State Origin() []byte BlockNumber() *big.Int @@ -19,8 +18,16 @@ type Environment interface { Difficulty() *big.Int BlockHash() []byte GasLimit() *big.Int + Transfer(from, to Account, amount *big.Int) error - AddLog(*state.Log) + AddLog(addr []byte, topics [][]byte, data []byte) + DeleteAccount(addr []byte) + SetState(addr, key, value []byte) + GetState(addr, key []byte) []byte + Balance(addr []byte) *big.Int + AddBalance(addr []byte, balance *big.Int) + GetCode(addr []byte) []byte + Refund(addr []byte, gas, price *big.Int) } type Object interface { @@ -43,9 +50,5 @@ func Transfer(from, to Account, amount *big.Int) error { from.SubBalance(amount) to.AddBalance(amount) - // Add default LOG. Default = big(sender.addr) + 1 - //addr := ethutil.BigD(receiver.Address()) - //tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) - return nil } diff --git a/vm/execution.go b/vm/execution.go index c23164f82..514405215 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -90,6 +90,6 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, return } -func (self *Execution) Create(caller ClosureRef) (ret []byte, err error) { +func (self *Execution) Create(caller []byte) (ret []byte, err error) { return self.exec(self.input, nil, caller) } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 544e04a5f..ce1f31b44 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" ) type DebugVm struct { @@ -29,6 +28,13 @@ type DebugVm struct { depth int } +type Options struct { + Address, Caller []byte + Data []byte + Code []byte + Value, Gas, Price *big.Int +} + func NewDebugVm(env Environment) *DebugVm { lt := LogTyPretty if ethutil.Config.Diff { @@ -38,7 +44,13 @@ func NewDebugVm(env Environment) *DebugVm { return &DebugVm{env: env, logTy: lt, Recoverable: true} } -func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { +//func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { +func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { + // Don't bother with the execution if there's no code. + if len(call.Code) == 0 { + return nil, new(big.Int), nil + } + self.depth++ if self.Recoverable { @@ -47,41 +59,49 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if r := recover(); r != nil { self.Endl() - closure.UseGas(closure.Gas) - - ret = closure.Return(nil) - + gas = new(big.Int) err = fmt.Errorf("%v", r) } }() } + gas = new(big.Int).Set(opt.Gas) var ( op OpCode - destinations = analyseJumpDests(closure.Code) + destinations = analyseJumpDests(call.Code) mem = NewMemory() stack = NewStack() pc = big.NewInt(0) step = 0 prevStep = 0 - statedb = self.env.State() - require = func(m int) { + //statedb = self.env.State() + require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) } } + useGas = func(amount *big.Int) bool { + if amount.Cmp(gas) > 0 { + return false + } + + gas.Sub(gas, amount) + + return true + } + jump = func(from, to *big.Int) { - p := int(to.Int64()) + p := to.Uint64() self.Printf(" ~> %v", to) // Return to start if p == 0 { pc = big.NewInt(0) } else { - nop := OpCode(closure.GetOp(p)) + nop := OpCode(call.GetOp(p)) if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) } else if nop == JUMP || nop == JUMPI { @@ -96,17 +116,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } ) - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } - - // Don't bother with the execution if there's no code. - if len(closure.Code) == 0 { - return closure.Return(nil), nil - } - - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, call.Address, gas, call.Data) for { prevStep = step @@ -115,31 +125,33 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { step++ // Get the memory location of pc - op = closure.GetOp(int(pc.Uint64())) + op = call.GetOp(pc.Uint64()) // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations - if self.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } + /* + if self.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + 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) + reqGas := new(big.Int) addStepGasUsage := func(amount *big.Int) { if amount.Cmp(ethutil.Big0) >= 0 { - gas.Add(gas, amount) + reqGas.Add(reqGas, amount) } } @@ -166,42 +178,43 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { require(n + 2) mSize, mStart := stack.Peekn() - gas.Set(GasLog) + reqGs.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Add(mSize, mStart)) // Gas only case STOP: - gas.Set(ethutil.Big0) + reqGas.Set(ethutil.Big0) case SUICIDE: require(1) - gas.Set(ethutil.Big0) + reqGas.Set(ethutil.Big0) case SLOAD: require(1) - gas.Set(GasSLoad) + reqGas.Set(GasSLoad) // Memory resize & Gas case SSTORE: require(2) var mult *big.Int y, x := stack.Peekn() - val := closure.GetStorage(x) + val := ethutil.BigD(self.env.GetState(x.Bytes())) //closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + //statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + self.env.Refund(call.Caller, GasSStoreRefund, call.Price) mult = ethutil.Big0 } else { // non 0 => non 0 mult = ethutil.Big1 } - gas.Set(new(big.Int).Mul(mult, GasSStore)) + reqGas.Set(new(big.Int).Mul(mult, GasSStore)) case BALANCE: require(1) - gas.Set(GasBalance) + reqGas.Set(GasBalance) case MSTORE: require(2) newMemSize = calcMemSize(stack.Peek(), u256(32)) @@ -219,7 +232,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case SHA3: require(2) - gas.Set(GasSha) + reqGas.Set(GasSha) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case CALLDATACOPY: @@ -236,7 +249,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) case CALL, CALLCODE: require(7) - gas.Set(GasCall) + reqGas.Set(GasCall) addStepGasUsage(stack.data[stack.Len()-1]) x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) @@ -245,7 +258,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize = ethutil.BigMax(x, y) case CREATE: require(3) - gas.Set(GasCreate) + reqGas.Set(GasCreate) newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) } @@ -255,6 +268,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize.Div(newMemSize, u256(32)) newMemSize.Mul(newMemSize, u256(32)) + switch op { + // Additional gas usage on *CODPY + case CALLDATACOPY, CODECOPY, EXTCODECOPY: + addStepGasUsage(new(big.Int).Div(newMemSize, u256(32))) + } + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) memGasUsage.Mul(GasMemory, memGasUsage) @@ -268,16 +287,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), gas, closure.Gas) + self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), reqGas, gas) - if !closure.UseGas(gas) { + if !useGas(regGas) { self.Endl() - tmp := new(big.Int).Set(closure.Gas) - - closure.UseGas(closure.Gas) - - return closure.Return(nil), OOG(gas, tmp) + return nil, new(big.Int), OOG(reqGas, gas) } switch op { @@ -553,13 +568,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %x", data) // 0x30 range case ADDRESS: - stack.Push(ethutil.BigD(closure.Address())) + //stack.Push(ethutil.BigD(closure.Address())) + stack.Push(ethutil.BigD(call.Address)) - self.Printf(" => %x", closure.Address()) + self.Printf(" => %x", call.Address) case BALANCE: addr := stack.Pop().Bytes() - balance := statedb.GetBalance(addr) + //balance := statedb.GetBalance(addr) + balance := self.env.GetBalance(addr) stack.Push(balance) @@ -571,41 +588,42 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %x", origin) case CALLER: - caller := closure.caller.Address() - stack.Push(ethutil.BigD(caller)) + //caller := closure.caller.Address() + //stack.Push(ethutil.BigD(caller)) + stack.Push(call.Caller) - self.Printf(" => %x", caller) + self.Printf(" => %x", call.Caller) case CALLVALUE: - value := closure.exe.value + //value := closure.exe.value - stack.Push(value) + stack.Push(call.Value) - self.Printf(" => %v", value) + self.Printf(" => %v", call.Value) case CALLDATALOAD: var ( offset = stack.Pop() data = make([]byte, 32) - lenData = big.NewInt(int64(len(closure.Args))) + lenData = big.NewInt(int64(len(call.Data))) ) if lenData.Cmp(offset) >= 0 { length := new(big.Int).Add(offset, ethutil.Big32) length = ethutil.BigMin(length, lenData) - copy(data, closure.Args[offset.Int64():length.Int64()]) + copy(data, call.Data[offset.Int64():length.Int64()]) } self.Printf(" => 0x%x", data) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - l := int64(len(closure.Args)) + l := int64(len(call.Data)) stack.Push(big.NewInt(l)) self.Printf(" => %d", l) case CALLDATACOPY: var ( - size = int64(len(closure.Args)) + size = int64(len(call.Data)) mOff = stack.Pop().Int64() cOff = stack.Pop().Int64() l = stack.Pop().Int64() @@ -618,7 +636,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { l = 0 } - code := closure.Args[cOff : cOff+l] + code := call.Data[cOff : cOff+l] mem.Set(mOff, l, code) @@ -628,9 +646,9 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if op == EXTCODESIZE { addr := stack.Pop().Bytes() - code = statedb.GetCode(addr) + self.env.GetCode(addr) } else { - code = closure.Code + code = call.Code } l := big.NewInt(int64(len(code))) @@ -642,9 +660,9 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { if op == EXTCODECOPY { addr := stack.Pop().Bytes() - code = statedb.GetCode(addr) + code = self.env.GetCode(addr) } else { - code = closure.Code + code = call.Code } var ( @@ -667,9 +685,9 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) case GASPRICE: - stack.Push(closure.Price) + stack.Push(call.Price) - self.Printf(" => %v", closure.Price) + self.Printf(" => %v", call.Price) // 0x40 range case PREVHASH: @@ -707,17 +725,17 @@ func (self *DebugVm) RunClosure(closure *Closure) (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 := big.NewInt(int64(op) - int64(PUSH1) + 1) + a := uint64(op) - uint64(PUSH1) + 1 pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, a) - val := ethutil.BigD(data.Bytes()) + data := call.Get(pc.Uint64(), a) //closure.Gets(pc, a) + val := ethutil.BigD(data) // Push value to stack stack.Push(val) - pc.Add(pc, a.Sub(a, big.NewInt(1))) + pc.Add(pc, big.NewInt(int64(a)-1)) - step += int(op) - int(PUSH1) + 1 + step += uint64(op) - uint64(PUSH1) + 1 - self.Printf(" => 0x%x", data.Bytes()) + self.Printf(" => 0x%x", data) case POP: stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: @@ -725,10 +743,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { v := stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) - - if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { - fmt.Println(toValue(v)) - } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) @@ -743,8 +757,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { topics[i] = stack.Pop().Bytes() } - log := &state.Log{closure.Address(), topics, data} - self.env.AddLog(log) + //log := &state.Log{closure.Address(), topics, data} + self.env.AddLog(call.Address, topics, data) self.Printf(" => %v", log) case MLOAD: @@ -768,18 +782,16 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: loc := stack.Pop() - val := ethutil.BigD(statedb.GetState(closure.Address(), loc.Bytes())) + val := ethutil.BigD(self.env.GetState(call.Address, loc.Bytes())) stack.Push(val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: val, loc := stack.Popn() - statedb.SetState(closure.Address(), loc.Bytes(), val) + self.env.SetState(call.Address, loc.Bytes(), val.Bytes()) + //statedb.SetState(closure.Address(), loc.Bytes(), val) - // Debug sessions are allowed to run without message - if closure.message != nil { - closure.message.AddStorageChange(loc.Bytes()) - } + //closure.message.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: @@ -802,7 +814,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) case GAS: - stack.Push(closure.Gas) + stack.Push(call.Gas) // 0x60 range case CREATE: var ( @@ -810,7 +822,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { value = stack.Pop() size, offset = stack.Popn() input = mem.Get(offset.Int64(), size.Int64()) - gas = new(big.Int).Set(closure.Gas) + gas = new(big.Int).Set(call.Gas) // Snapshot the current stack so we are able to // revert back to it later. @@ -818,16 +830,19 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - n := statedb.GetNonce(closure.Address()) - addr := crypto.CreateAddress(closure.Address(), n) - statedb.SetNonce(closure.Address(), n+1) + //n := statedb.GetNonce(closure.Address()) + //addr := crypto.CreateAddress(closure.Address(), n) + //statedb.SetNonce(closure.Address(), n+1) + n := self.env.GetNonce(call.Address) + addr := crypto.CreateAddress(call.Address, n) + self.env.SetNonce(call.Address, n+1) self.Printf(" (*) %x", addr).Endl() - closure.UseGas(closure.Gas) + //closure.UseGas(closure.Gas) - msg := NewExecution(self, addr, input, gas, closure.Price, value) - ret, err := msg.Create(closure) + msg := NewExecution(self, addr, input, gas, call.Price, value) + ret, lgas, err := msg.Create(call.Address) if err != nil { stack.Push(ethutil.BigFalse) @@ -841,12 +856,9 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { stack.Push(ethutil.BigD(addr)) } - self.Endl() + gas = lgas - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } + self.Endl() case CALL, CALLCODE: self.Endl() @@ -863,12 +875,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var executeAddr []byte if op == CALLCODE { - executeAddr = closure.Address() + executeAddr = call.Address //closure.Address() } else { executeAddr = addr.Bytes() } - msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) + msg := NewExecution(self, executeAddr, args, gas, call.Price, value) ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -881,24 +893,22 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } self.Printf("resume %x", closure.Address()) - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } - case RETURN: size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) self.Printf(" => (%d) 0x%x", len(ret), ret).Endl() - return closure.Return(ret), nil - case SUICIDE: + return ret, gas, nil - receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + //return closure.Return(ret), gas, nil + case SUICIDE: + //receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + //receiver.AddAmount(statedb.GetBalance(closure.Address())) + //statedb.Delete(closure.Address()) - receiver.AddAmount(statedb.GetBalance(closure.Address())) - statedb.Delete(closure.Address()) + self.env.AddBalance(stack.Pop().Bytes(), self.env.Balance(call.Address)) + self.env.DeleteAccount(call.Address) fallthrough case STOP: // Stop the closure @@ -917,23 +927,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { pc.Add(pc, ethutil.Big1) self.Endl() - - if self.Dbg != nil { - for _, instrNo := range self.Dbg.BreakPoints() { - if pc.Cmp(big.NewInt(instrNo)) == 0 { - self.Stepping = true - - if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { - return nil, nil - } - } else if self.Stepping { - if !self.Dbg.StepHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { - return nil, nil - } - } - } - } - } } -- cgit v1.2.3 From 6dc46d3341dc5fa25bd005f9606de258874139be Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 1 Dec 2014 20:18:09 +0100 Subject: Changed the way transactions are being added to the transaction pool --- vm/vm_debug.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ae5a20175..18d3018a0 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -151,7 +151,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack checks only case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 require(1) - case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 + case ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) case ADDMOD, MULMOD: // 3 require(3) @@ -169,6 +169,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Add(mSize, mStart)) + case EXP: + require(2) + + expGas := ethutil.FirstBitSet(stack.data[stack.Len()-2]) + expGas.Div(expGas, u256(8)) + expGas.Sub(u256(32), expGas) + expGas.Add(expGas, u256(1)) + + gas.Set(expGas) // Gas only case STOP: gas.Set(ethutil.Big0) -- cgit v1.2.3 From d33987cb44529db4f3e117d4b242b1796d41520d Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 1 Dec 2014 20:20:55 +0100 Subject: Additional fees for *COPY --- vm/vm_debug.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 18d3018a0..b9c1d4bc6 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -264,6 +264,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { newMemSize.Div(newMemSize, u256(32)) newMemSize.Mul(newMemSize, u256(32)) + switch op { + // Additional gas usage on *CODPY + case CALLDATACOPY, CODECOPY, EXTCODECOPY: + addStepGasUsage(new(big.Int).Div(newMemSize, u256(32))) + } + if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) memGasUsage.Mul(GasMemory, memGasUsage) -- cgit v1.2.3 From a22056db5988bfa2b1354e0092eabb734c30701c Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 1 Dec 2014 20:49:56 +0100 Subject: Make an attempt to pay for the gas prior to expanding the mem. --- vm/closure.go | 2 +- vm/vm_debug.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index ef9bbca93..5bd8c1bb8 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -64,7 +64,7 @@ func (c *Closure) GetOp(x int) OpCode { } func (c *Closure) GetByte(x int) byte { - if x < len(c.Code) { + if x > -1 && x < len(c.Code) { return c.Code[x] } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index b9c1d4bc6..4daa3ab5b 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -277,7 +277,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { addStepGasUsage(memGasUsage) - mem.Resize(newMemSize.Uint64()) } } @@ -295,6 +294,8 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { return closure.Return(nil), OOG(gas, tmp) } + mem.Resize(newMemSize.Uint64()) + switch op { // 0x20 range case ADD: -- cgit v1.2.3 From a052357872217d5e99e7ee1a7a4b524b53addcdd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 1 Dec 2014 22:05:38 +0100 Subject: Fixed EXP gas --- vm/vm_debug.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 4daa3ab5b..ea94987d1 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -172,12 +172,13 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case EXP: require(2) - expGas := ethutil.FirstBitSet(stack.data[stack.Len()-2]) - expGas.Div(expGas, u256(8)) - expGas.Sub(u256(32), expGas) - expGas.Add(expGas, u256(1)) - - gas.Set(expGas) + exp := new(big.Int).Set(stack.data[stack.Len()-2]) + nbytes := 0 + for exp.Cmp(ethutil.Big0) > 0 { + nbytes += 1 + exp.Rsh(exp, 8) + } + gas.Set(big.NewInt(int64(nbytes + 1))) // Gas only case STOP: gas.Set(ethutil.Big0) -- cgit v1.2.3 From 2df8ad6307d741d0a6d2f746d53f97c7b27ad796 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 2 Dec 2014 00:03:53 +0100 Subject: Added state tests --- vm/address.go | 8 ++++++-- vm/execution.go | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/address.go b/vm/address.go index 235143b34..86ae705bc 100644 --- a/vm/address.go +++ b/vm/address.go @@ -31,12 +31,16 @@ func sha256Func(in []byte) []byte { } func ripemd160Func(in []byte) []byte { - return ethutil.RightPadBytes(crypto.Ripemd160(in), 32) + return ethutil.LeftPadBytes(crypto.Ripemd160(in), 32) } func ecrecoverFunc(in []byte) []byte { // In case of an invalid sig. Defaults to return nil defer func() { recover() }() - return crypto.Ecrecover(in) + hash := in[:32] + v := ethutil.BigD(in[32:64]).Bytes()[0] - 27 + sig := append(in[64:], v) + + return crypto.Sha3(crypto.Ecrecover(append(hash, sig...))[1:]) } diff --git a/vm/execution.go b/vm/execution.go index c23164f82..8c04cf536 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -69,6 +69,7 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, if self.Gas.Cmp(p.Gas) >= 0 { ret = p.Call(self.input) self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) + self.vm.Endl() } } else { // Create a new callable closure -- cgit v1.2.3 From 99481a245adc2c4814ab6b38d94d63114f7bbb15 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 2 Dec 2014 11:37:33 +0100 Subject: Check for known block err and ignore --- vm/address.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/address.go b/vm/address.go index 86ae705bc..06bd35f6b 100644 --- a/vm/address.go +++ b/vm/address.go @@ -42,5 +42,5 @@ func ecrecoverFunc(in []byte) []byte { v := ethutil.BigD(in[32:64]).Bytes()[0] - 27 sig := append(in[64:], v) - return crypto.Sha3(crypto.Ecrecover(append(hash, sig...))[1:]) + return ethutil.LeftPadBytes(crypto.Sha3(crypto.Ecrecover(append(hash, sig...))[1:])[12:], 32) } -- cgit v1.2.3 From cb4d168ecc9f6c2ecdb1a8f3308f8f3eb9f02376 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 2 Dec 2014 17:22:33 +0100 Subject: Updated LOG to match proper gas in all cases --- vm/types.go | 8 +------- vm/vm_debug.go | 5 +++-- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'vm') diff --git a/vm/types.go b/vm/types.go index 0b20fb655..530dbf400 100644 --- a/vm/types.go +++ b/vm/types.go @@ -163,8 +163,8 @@ const ( // 0xf0 range - closures CREATE OpCode = 0xf0 + iota CALL - RETURN CALLCODE + RETURN // 0x70 range - other SUICIDE = 0xff @@ -309,12 +309,6 @@ var opCodeToString = map[OpCode]string{ SWAP15: "SWAP15", SWAP16: "SWAP16", - LOG0: "LOG0", - LOG1: "LOG1", - LOG2: "LOG2", - LOG3: "LOG3", - LOG4: "LOG4", - // 0xf0 range CREATE: "CREATE", CALL: "CALL", diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ea94987d1..dbab8fbcb 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -165,10 +165,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { n := int(op - LOG0) require(n + 2) - mSize, mStart := stack.Peekn() gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) - addStepGasUsage(new(big.Int).Add(mSize, mStart)) + + mSize, _ := stack.Peekn() + addStepGasUsage(mSize) case EXP: require(2) -- cgit v1.2.3 From 3d9a4e7084c33cb28a2265c0dd232a0ea3871c92 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 3 Dec 2014 12:21:12 +0100 Subject: Fixed mem error in vm. Fixed logs tests --- vm/stack.go | 3 +-- vm/types.go | 5 +++++ vm/vm_debug.go | 10 ++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'vm') diff --git a/vm/stack.go b/vm/stack.go index 2eca60ad1..98795cc03 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -147,9 +147,8 @@ func (m *Memory) Get(offset, size int64) []byte { func (self *Memory) Geti(offset, size int64) (cpy []byte) { if len(self.store) > int(offset) { - s := int64(math.Min(float64(len(self.store)), float64(offset+size))) cpy = make([]byte, size) - copy(cpy, self.store[offset:offset+s]) + copy(cpy, self.store[offset:offset+size]) return } diff --git a/vm/types.go b/vm/types.go index 530dbf400..ec9c7e74e 100644 --- a/vm/types.go +++ b/vm/types.go @@ -308,6 +308,11 @@ var opCodeToString = map[OpCode]string{ SWAP14: "SWAP14", SWAP15: "SWAP15", SWAP16: "SWAP16", + LOG0: "LOG0", + LOG1: "LOG1", + LOG2: "LOG2", + LOG3: "LOG3", + LOG4: "LOG4", // 0xf0 range CREATE: "CREATE", diff --git a/vm/vm_debug.go b/vm/vm_debug.go index dbab8fbcb..91d3c55c1 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -35,7 +35,7 @@ func NewDebugVm(env Environment) *DebugVm { lt = LogTyDiff } - return &DebugVm{env: env, logTy: lt, Recoverable: true} + return &DebugVm{env: env, logTy: lt, Recoverable: false} } func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { @@ -168,8 +168,10 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) - mSize, _ := stack.Peekn() + mSize, mStart := stack.Peekn() addStepGasUsage(mSize) + + newMemSize = calcMemSize(mStart, mSize) case EXP: require(2) @@ -755,10 +757,10 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) topics := make([][]byte, n) - mStart, mSize := stack.Pop().Int64(), stack.Pop().Int64() + mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() data := mem.Geti(mStart, mSize) for i := 0; i < n; i++ { - topics[i] = stack.Pop().Bytes() + topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) } log := &state.Log{closure.Address(), topics, data} -- cgit v1.2.3 From 6212175be3a5a06099413f4a393df316c5be5752 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 3 Dec 2014 13:52:13 +0100 Subject: reverted vm back --- vm/environment.go | 17 ++-- vm/execution.go | 6 +- vm/vm_debug.go | 260 ++++++++++++++++++++++++++++-------------------------- 3 files changed, 148 insertions(+), 135 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index bf773b5d6..5604989e1 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -5,10 +5,11 @@ import ( "math/big" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type Environment interface { - //State() *state.State + State() *state.State Origin() []byte BlockNumber() *big.Int @@ -18,16 +19,8 @@ type Environment interface { Difficulty() *big.Int BlockHash() []byte GasLimit() *big.Int - Transfer(from, to Account, amount *big.Int) error - AddLog(addr []byte, topics [][]byte, data []byte) - DeleteAccount(addr []byte) - SetState(addr, key, value []byte) - GetState(addr, key []byte) []byte - Balance(addr []byte) *big.Int - AddBalance(addr []byte, balance *big.Int) - GetCode(addr []byte) []byte - Refund(addr []byte, gas, price *big.Int) + AddLog(*state.Log) } type Object interface { @@ -50,5 +43,9 @@ func Transfer(from, to Account, amount *big.Int) error { from.SubBalance(amount) to.AddBalance(amount) + // Add default LOG. Default = big(sender.addr) + 1 + //addr := ethutil.BigD(receiver.Address()) + //tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) + return nil } diff --git a/vm/execution.go b/vm/execution.go index 4df77729e..8c04cf536 100644 --- a/vm/execution.go +++ b/vm/execution.go @@ -26,7 +26,7 @@ func (self *Execution) Addr() []byte { func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) { // Retrieve the executing code - code := self.vm.Env().GetCode(codeAddr) + code := self.vm.Env().State().GetCode(codeAddr) return self.exec(code, codeAddr, caller) } @@ -34,11 +34,13 @@ func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, err error) { env := self.vm.Env() + vmlogger.Debugf("pre state %x\n", env.State().Root()) snapshot := env.State().Copy() defer func() { if IsDepthErr(err) || IsOOGErr(err) { env.State().Set(snapshot) } + vmlogger.Debugf("post state %x\n", env.State().Root()) }() msg := env.State().Manifest().AddMessage(&state.Message{ @@ -89,6 +91,6 @@ func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, return } -func (self *Execution) Create(caller []byte) (ret []byte, err error) { +func (self *Execution) Create(caller ClosureRef) (ret []byte, err error) { return self.exec(self.input, nil, caller) } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 31345c555..91d3c55c1 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" ) type DebugVm struct { @@ -28,13 +29,6 @@ type DebugVm struct { depth int } -type Options struct { - Address, Caller []byte - Data []byte - Code []byte - Value, Gas, Price *big.Int -} - func NewDebugVm(env Environment) *DebugVm { lt := LogTyPretty if ethutil.Config.Diff { @@ -44,13 +38,7 @@ func NewDebugVm(env Environment) *DebugVm { return &DebugVm{env: env, logTy: lt, Recoverable: false} } -//func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { -func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { - // Don't bother with the execution if there's no code. - if len(call.Code) == 0 { - return nil, new(big.Int), nil - } - +func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.depth++ if self.Recoverable { @@ -59,49 +47,41 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { if r := recover(); r != nil { self.Endl() - gas = new(big.Int) + closure.UseGas(closure.Gas) + + ret = closure.Return(nil) + err = fmt.Errorf("%v", r) } }() } - gas = new(big.Int).Set(opt.Gas) var ( op OpCode - destinations = analyseJumpDests(call.Code) + destinations = analyseJumpDests(closure.Code) mem = NewMemory() stack = NewStack() pc = big.NewInt(0) step = 0 prevStep = 0 - //statedb = self.env.State() - require = func(m int) { + statedb = self.env.State() + require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) } } - useGas = func(amount *big.Int) bool { - if amount.Cmp(gas) > 0 { - return false - } - - gas.Sub(gas, amount) - - return true - } - jump = func(from, to *big.Int) { - p := to.Uint64() + p := int(to.Int64()) self.Printf(" ~> %v", to) // Return to start if p == 0 { pc = big.NewInt(0) } else { - nop := OpCode(call.GetOp(p)) + nop := OpCode(closure.GetOp(p)) if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) } else if nop == JUMP || nop == JUMPI { @@ -116,7 +96,17 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { } ) - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, call.Address, gas, call.Data) + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + + // Don't bother with the execution if there's no code. + if len(closure.Code) == 0 { + return closure.Return(nil), nil + } + + vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, closure.Args) for { prevStep = step @@ -125,33 +115,31 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { step++ // Get the memory location of pc - op = call.GetOp(pc.Uint64()) + op = closure.GetOp(int(pc.Uint64())) // XXX Leave this Println intact. Don't change this to the log system. // Used for creating diffs between implementations - /* - if self.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } - - b := pc.Bytes() - if len(b) == 0 { - b = []byte{0} - } + if self.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } - fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + b := pc.Bytes() + if len(b) == 0 { + b = []byte{0} } - */ - reqGas := new(big.Int) + fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes()) + } + + gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { if amount.Cmp(ethutil.Big0) >= 0 { - reqGas.Add(reqGas, amount) + gas.Add(gas, amount) } } @@ -196,38 +184,37 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { gas.Set(big.NewInt(int64(nbytes + 1))) // Gas only case STOP: - reqGas.Set(ethutil.Big0) + gas.Set(ethutil.Big0) case SUICIDE: require(1) - reqGas.Set(ethutil.Big0) + gas.Set(ethutil.Big0) case SLOAD: require(1) - reqGas.Set(GasSLoad) + gas.Set(GasSLoad) // Memory resize & Gas case SSTORE: require(2) var mult *big.Int y, x := stack.Peekn() - val := ethutil.BigD(self.env.GetState(x.Bytes())) //closure.GetStorage(x) + val := closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - //statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) - self.env.Refund(call.Caller, GasSStoreRefund, call.Price) + statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) mult = ethutil.Big0 } else { // non 0 => non 0 mult = ethutil.Big1 } - reqGas.Set(new(big.Int).Mul(mult, GasSStore)) + gas.Set(new(big.Int).Mul(mult, GasSStore)) case BALANCE: require(1) - reqGas.Set(GasBalance) + gas.Set(GasBalance) case MSTORE: require(2) newMemSize = calcMemSize(stack.Peek(), u256(32)) @@ -245,7 +232,7 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { case SHA3: require(2) - reqGas.Set(GasSha) + gas.Set(GasSha) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case CALLDATACOPY: @@ -262,7 +249,7 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) case CALL, CALLCODE: require(7) - reqGas.Set(GasCall) + gas.Set(GasCall) addStepGasUsage(stack.data[stack.Len()-1]) x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) @@ -271,7 +258,7 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { newMemSize = ethutil.BigMax(x, y) case CREATE: require(3) - reqGas.Set(GasCreate) + gas.Set(GasCreate) newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) } @@ -299,12 +286,16 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { } self.Printf("(pc) %-3d -o- %-14s", pc, op.String()) - self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), reqGas, gas) + self.Printf(" (m) %-4d (s) %-4d (g) %-3v (%v)", mem.Len(), stack.Len(), gas, closure.Gas) - if !useGas(regGas) { + if !closure.UseGas(gas) { self.Endl() - return nil, new(big.Int), OOG(reqGas, gas) + tmp := new(big.Int).Set(closure.Gas) + + closure.UseGas(closure.Gas) + + return closure.Return(nil), OOG(gas, tmp) } mem.Resize(newMemSize.Uint64()) @@ -582,15 +573,13 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { self.Printf(" => %x", data) // 0x30 range case ADDRESS: - //stack.Push(ethutil.BigD(closure.Address())) - stack.Push(ethutil.BigD(call.Address)) + stack.Push(ethutil.BigD(closure.Address())) - self.Printf(" => %x", call.Address) + self.Printf(" => %x", closure.Address()) case BALANCE: addr := stack.Pop().Bytes() - //balance := statedb.GetBalance(addr) - balance := self.env.GetBalance(addr) + balance := statedb.GetBalance(addr) stack.Push(balance) @@ -602,42 +591,41 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { self.Printf(" => %x", origin) case CALLER: - //caller := closure.caller.Address() - //stack.Push(ethutil.BigD(caller)) - stack.Push(call.Caller) + caller := closure.caller.Address() + stack.Push(ethutil.BigD(caller)) - self.Printf(" => %x", call.Caller) + self.Printf(" => %x", caller) case CALLVALUE: - //value := closure.exe.value + value := closure.exe.value - stack.Push(call.Value) + stack.Push(value) - self.Printf(" => %v", call.Value) + self.Printf(" => %v", value) case CALLDATALOAD: var ( offset = stack.Pop() data = make([]byte, 32) - lenData = big.NewInt(int64(len(call.Data))) + lenData = big.NewInt(int64(len(closure.Args))) ) if lenData.Cmp(offset) >= 0 { length := new(big.Int).Add(offset, ethutil.Big32) length = ethutil.BigMin(length, lenData) - copy(data, call.Data[offset.Int64():length.Int64()]) + copy(data, closure.Args[offset.Int64():length.Int64()]) } self.Printf(" => 0x%x", data) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - l := int64(len(call.Data)) + l := int64(len(closure.Args)) stack.Push(big.NewInt(l)) self.Printf(" => %d", l) case CALLDATACOPY: var ( - size = int64(len(call.Data)) + size = int64(len(closure.Args)) mOff = stack.Pop().Int64() cOff = stack.Pop().Int64() l = stack.Pop().Int64() @@ -650,7 +638,7 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { l = 0 } - code := call.Data[cOff : cOff+l] + code := closure.Args[cOff : cOff+l] mem.Set(mOff, l, code) @@ -660,9 +648,9 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { if op == EXTCODESIZE { addr := stack.Pop().Bytes() - self.env.GetCode(addr) + code = statedb.GetCode(addr) } else { - code = call.Code + code = closure.Code } l := big.NewInt(int64(len(code))) @@ -674,9 +662,9 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { if op == EXTCODECOPY { addr := stack.Pop().Bytes() - code = self.env.GetCode(addr) + code = statedb.GetCode(addr) } else { - code = call.Code + code = closure.Code } var ( @@ -699,9 +687,9 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) case GASPRICE: - stack.Push(call.Price) + stack.Push(closure.Price) - self.Printf(" => %v", call.Price) + self.Printf(" => %v", closure.Price) // 0x40 range case PREVHASH: @@ -739,17 +727,17 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, 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) - uint64(PUSH1) + 1 + a := big.NewInt(int64(op) - int64(PUSH1) + 1) pc.Add(pc, ethutil.Big1) - data := call.Get(pc.Uint64(), a) //closure.Gets(pc, a) - val := ethutil.BigD(data) + data := closure.Gets(pc, a) + val := ethutil.BigD(data.Bytes()) // Push value to stack stack.Push(val) - pc.Add(pc, big.NewInt(int64(a)-1)) + pc.Add(pc, a.Sub(a, big.NewInt(1))) - step += uint64(op) - uint64(PUSH1) + 1 + step += int(op) - int(PUSH1) + 1 - self.Printf(" => 0x%x", data) + self.Printf(" => 0x%x", data.Bytes()) case POP: stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: @@ -757,6 +745,10 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { v := stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) + + if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { + fmt.Println(toValue(v)) + } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) @@ -771,8 +763,8 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) } - //log := &state.Log{closure.Address(), topics, data} - self.env.AddLog(call.Address, topics, data) + log := &state.Log{closure.Address(), topics, data} + self.env.AddLog(log) self.Printf(" => %v", log) case MLOAD: @@ -796,16 +788,18 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { self.Printf(" => [%v] 0x%x", off, val) case SLOAD: loc := stack.Pop() - val := ethutil.BigD(self.env.GetState(call.Address, loc.Bytes())) + val := ethutil.BigD(statedb.GetState(closure.Address(), loc.Bytes())) stack.Push(val) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case SSTORE: val, loc := stack.Popn() - self.env.SetState(call.Address, loc.Bytes(), val.Bytes()) - //statedb.SetState(closure.Address(), loc.Bytes(), val) + statedb.SetState(closure.Address(), loc.Bytes(), val) - //closure.message.AddStorageChange(loc.Bytes()) + // Debug sessions are allowed to run without message + if closure.message != nil { + closure.message.AddStorageChange(loc.Bytes()) + } self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: @@ -828,15 +822,16 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) case GAS: - stack.Push(call.Gas) + stack.Push(closure.Gas) // 0x60 range case CREATE: + var ( err error value = stack.Pop() size, offset = stack.Popn() input = mem.Get(offset.Int64(), size.Int64()) - gas = new(big.Int).Set(call.Gas) + gas = new(big.Int).Set(closure.Gas) // Snapshot the current stack so we are able to // revert back to it later. @@ -844,19 +839,16 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { ) // Generate a new address - //n := statedb.GetNonce(closure.Address()) - //addr := crypto.CreateAddress(closure.Address(), n) - //statedb.SetNonce(closure.Address(), n+1) - n := self.env.GetNonce(call.Address) - addr := crypto.CreateAddress(call.Address, n) - self.env.SetNonce(call.Address, n+1) + n := statedb.GetNonce(closure.Address()) + addr := crypto.CreateAddress(closure.Address(), n) + statedb.SetNonce(closure.Address(), n+1) self.Printf(" (*) %x", addr).Endl() - //closure.UseGas(closure.Gas) + closure.UseGas(closure.Gas) - msg := NewExecution(self, addr, input, gas, call.Price, value) - ret, lgas, err := msg.Create(call.Address) + msg := NewExecution(self, addr, input, gas, closure.Price, value) + ret, err := msg.Create(closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -870,9 +862,12 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { stack.Push(ethutil.BigD(addr)) } - gas = lgas - self.Endl() + + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } case CALL, CALLCODE: self.Endl() @@ -889,12 +884,12 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { var executeAddr []byte if op == CALLCODE { - executeAddr = call.Address //closure.Address() + executeAddr = closure.Address() } else { executeAddr = addr.Bytes() } - msg := NewExecution(self, executeAddr, args, gas, call.Price, value) + msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) ret, err := msg.Exec(addr.Bytes(), closure) if err != nil { stack.Push(ethutil.BigFalse) @@ -907,22 +902,24 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { } self.Printf("resume %x", closure.Address()) + // Debug hook + if self.Dbg != nil { + self.Dbg.SetCode(closure.Code) + } + case RETURN: size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) self.Printf(" => (%d) 0x%x", len(ret), ret).Endl() - return ret, gas, nil - - //return closure.Return(ret), gas, nil + return closure.Return(ret), nil case SUICIDE: - //receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) - //receiver.AddAmount(statedb.GetBalance(closure.Address())) - //statedb.Delete(closure.Address()) - self.env.AddBalance(stack.Pop().Bytes(), self.env.Balance(call.Address)) - self.env.DeleteAccount(call.Address) + receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + + receiver.AddAmount(statedb.GetBalance(closure.Address())) + statedb.Delete(closure.Address()) fallthrough case STOP: // Stop the closure @@ -941,6 +938,23 @@ func (self *DebugVm) Run(call Options) (ret []byte, gas *big.Int, err error) { pc.Add(pc, ethutil.Big1) self.Endl() + + if self.Dbg != nil { + for _, instrNo := range self.Dbg.BreakPoints() { + if pc.Cmp(big.NewInt(instrNo)) == 0 { + self.Stepping = true + + if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { + return nil, nil + } + } else if self.Stepping { + if !self.Dbg.StepHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { + return nil, nil + } + } + } + } + } } -- cgit v1.2.3 From 99853ac3ce57807deb4822dd324186e1d2ee0821 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 3 Dec 2014 17:06:54 +0100 Subject: Moved execution from vm to chain. This moves call and create to the specified environments. Vms are no longer re-used. Vm uses environment's Call(Code) and Create in order to execute new contracts or transfer value between accounts. State transition now uses the same mechanism described above. --- vm/closure.go | 21 +- vm/environment.go | 11 +- vm/execution.go | 96 ------- vm/virtual_machine.go | 4 +- vm/vm.go | 690 +------------------------------------------------- vm/vm_debug.go | 55 ++-- 6 files changed, 52 insertions(+), 825 deletions(-) delete mode 100644 vm/execution.go (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index 5bd8c1bb8..2263236e7 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -12,7 +12,7 @@ import ( type ClosureRef interface { ReturnGas(*big.Int, *big.Int) Address() []byte - Object() *state.StateObject + SetCode([]byte) GetStorage(*big.Int) *ethutil.Value SetStorage(*big.Int, *ethutil.Value) } @@ -20,10 +20,9 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { caller ClosureRef - object *state.StateObject + object ClosureRef Code []byte message *state.Message - exe *Execution Gas, UsedGas, Price *big.Int @@ -31,7 +30,7 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(msg *state.Message, caller ClosureRef, object *state.StateObject, code []byte, gas, price *big.Int) *Closure { +func NewClosure(msg *state.Message, caller ClosureRef, object ClosureRef, 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 @@ -89,6 +88,10 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { return ethutil.NewValue(partial) } +func (self *Closure) SetCode(code []byte) { + self.Code = code +} + func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { c.object.SetStorage(x, val) } @@ -97,6 +100,7 @@ func (c *Closure) Address() []byte { return c.object.Address() } +/* func (c *Closure) Call(vm VirtualMachine, args []byte) ([]byte, *big.Int, error) { c.Args = args @@ -104,6 +108,7 @@ func (c *Closure) Call(vm VirtualMachine, args []byte) ([]byte, *big.Int, error) return ret, c.UsedGas, err } +*/ func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the caller @@ -131,14 +136,6 @@ func (c *Closure) ReturnGas(gas, price *big.Int) { c.UsedGas.Sub(c.UsedGas, gas) } -func (c *Closure) Object() *state.StateObject { - return c.object -} - func (c *Closure) Caller() ClosureRef { return c.caller } - -func (self *Closure) SetExecution(exe *Execution) { - self.exe = exe -} diff --git a/vm/environment.go b/vm/environment.go index 5604989e1..3d75d05b9 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -21,6 +21,13 @@ type Environment interface { GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error AddLog(*state.Log) + + Depth() int + SetDepth(i int) + + Call(me ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) + CallCode(me ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) + Create(me ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, ClosureRef) } type Object interface { @@ -43,9 +50,5 @@ func Transfer(from, to Account, amount *big.Int) error { from.SubBalance(amount) to.AddBalance(amount) - // Add default LOG. Default = big(sender.addr) + 1 - //addr := ethutil.BigD(receiver.Address()) - //tx.addLog(vm.Log{sender.Address(), [][]byte{ethutil.U256(addr.Add(addr, ethutil.Big1)).Bytes()}, nil}) - return nil } diff --git a/vm/execution.go b/vm/execution.go deleted file mode 100644 index 8c04cf536..000000000 --- a/vm/execution.go +++ /dev/null @@ -1,96 +0,0 @@ -package vm - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" -) - -type Execution struct { - vm VirtualMachine - address, input []byte - Gas, price, value *big.Int - object *state.StateObject - SkipTransfer bool -} - -func NewExecution(vm VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution { - return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value} -} - -func (self *Execution) Addr() []byte { - return self.address -} - -func (self *Execution) Exec(codeAddr []byte, caller ClosureRef) ([]byte, error) { - // Retrieve the executing code - code := self.vm.Env().State().GetCode(codeAddr) - - return self.exec(code, codeAddr, caller) -} - -func (self *Execution) exec(code, caddr []byte, caller ClosureRef) (ret []byte, err error) { - env := self.vm.Env() - - vmlogger.Debugf("pre state %x\n", env.State().Root()) - snapshot := env.State().Copy() - defer func() { - if IsDepthErr(err) || IsOOGErr(err) { - env.State().Set(snapshot) - } - vmlogger.Debugf("post state %x\n", env.State().Root()) - }() - - msg := env.State().Manifest().AddMessage(&state.Message{ - To: self.address, From: caller.Address(), - Input: self.input, - Origin: env.Origin(), - Block: env.BlockHash(), Timestamp: env.Time(), Coinbase: env.Coinbase(), Number: env.BlockNumber(), - Value: self.value, - }) - - from, to := caller.Object(), env.State().GetOrNewStateObject(self.address) - // Skipping transfer is used on testing for the initial call - if !self.SkipTransfer { - err = env.Transfer(from, to, self.value) - } - - if err != nil { - caller.ReturnGas(self.Gas, self.price) - - err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance) - } else { - self.object = to - // Pre-compiled contracts (address.go) 1, 2 & 3. - naddr := ethutil.BigD(caddr).Uint64() - if p := Precompiled[naddr]; p != nil { - if self.Gas.Cmp(p.Gas) >= 0 { - ret = p.Call(self.input) - self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret) - self.vm.Endl() - } - } else { - // Create a new callable closure - c := NewClosure(msg, caller, to, code, self.Gas, self.price) - c.exe = self - - if self.vm.Depth() == MaxCallDepth { - c.UseGas(self.Gas) - - return c.Return(nil), DepthError{} - } - - // Executer the closure and get the return value (if any) - ret, _, err = c.Call(self.vm, self.input) - msg.Output = ret - } - } - - return -} - -func (self *Execution) Create(caller ClosureRef) (ret []byte, err error) { - return self.exec(self.input, nil, caller) -} diff --git a/vm/virtual_machine.go b/vm/virtual_machine.go index cc8cd39a9..5738075fb 100644 --- a/vm/virtual_machine.go +++ b/vm/virtual_machine.go @@ -1,8 +1,10 @@ package vm +import "math/big" + type VirtualMachine interface { Env() Environment - RunClosure(*Closure) ([]byte, error) + Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, data []byte) ([]byte, error) Depth() int Printf(string, ...interface{}) VirtualMachine Endl() VirtualMachine diff --git a/vm/vm.go b/vm/vm.go index e1c2d9c14..968ca10fa 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -1,12 +1,6 @@ package vm -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" -) +import "math/big" // BIG FAT WARNING. THIS VM IS NOT YET IS USE! // I want to get all VM tests pass first before updating this VM @@ -26,686 +20,8 @@ func New(env Environment, typ Type) VirtualMachine { } } -func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { - self.depth++ - - // Recover from any require exception - defer func() { - if r := recover(); r != nil { - ret = closure.Return(nil) - err = fmt.Errorf("%v", r) - } - }() - - // Don't bother with the execution if there's no code. - if len(closure.Code) == 0 { - return closure.Return(nil), nil - } - - var ( - op OpCode - - mem = &Memory{} - stack = NewStack() - pc = 0 - step = 0 - require = func(m int) { - if stack.Len() < m { - panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) - } - } - ) - - for { - // The base for all big integer arithmetic - base := new(big.Int) - - step++ - // Get the memory location of pc - op := closure.GetOp(pc) - - gas := new(big.Int) - addStepGasUsage := func(amount *big.Int) { - gas.Add(gas, amount) - } - - addStepGasUsage(GasStep) - - var newMemSize *big.Int = ethutil.Big0 - switch op { - case STOP: - gas.Set(ethutil.Big0) - case SUICIDE: - gas.Set(ethutil.Big0) - case SLOAD: - gas.Set(GasSLoad) - case SSTORE: - var mult *big.Int - y, x := stack.Peekn() - val := closure.GetStorage(x) - if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { - mult = ethutil.Big2 - } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - mult = ethutil.Big0 - } else { - mult = ethutil.Big1 - } - gas = new(big.Int).Mul(mult, GasSStore) - case BALANCE: - gas.Set(GasBalance) - case MSTORE: - require(2) - newMemSize = calcMemSize(stack.Peek(), u256(32)) - case MLOAD: - require(1) - - newMemSize = calcMemSize(stack.Peek(), u256(32)) - case MSTORE8: - require(2) - newMemSize = calcMemSize(stack.Peek(), u256(1)) - case RETURN: - require(2) - - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) - case SHA3: - require(2) - - gas.Set(GasSha) - - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) - case CALLDATACOPY: - require(2) - - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) - case CODECOPY: - require(3) - - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) - case EXTCODECOPY: - require(4) - - newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) - case CALL, CALLCODE: - require(7) - gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-1]) - - x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7]) - y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5]) - - newMemSize = ethutil.BigMax(x, y) - case CREATE: - require(3) - gas.Set(GasCreate) - - newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) - } - - if newMemSize.Cmp(ethutil.Big0) > 0 { - newMemSize.Add(newMemSize, u256(31)) - newMemSize.Div(newMemSize, u256(32)) - newMemSize.Mul(newMemSize, u256(32)) - - if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { - memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) - memGasUsage.Mul(GasMemory, memGasUsage) - memGasUsage.Div(memGasUsage, u256(32)) - - addStepGasUsage(memGasUsage) - } - } - - if !closure.UseGas(gas) { - err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas) - - closure.UseGas(closure.Gas) - - return closure.Return(nil), err - } - - mem.Resize(newMemSize.Uint64()) - - switch op { - // 0x20 range - case ADD: - require(2) - x, y := stack.Popn() - - base.Add(y, x) - - U256(base) - - // Pop result back on the stack - stack.Push(base) - case SUB: - require(2) - x, y := stack.Popn() - - base.Sub(y, x) - - U256(base) - - // Pop result back on the stack - stack.Push(base) - case MUL: - require(2) - x, y := stack.Popn() - - base.Mul(y, x) - - U256(base) - - // Pop result back on the stack - stack.Push(base) - case DIV: - require(2) - x, y := stack.Popn() - - if x.Cmp(ethutil.Big0) != 0 { - base.Div(y, x) - } - - U256(base) - - // Pop result back on the stack - stack.Push(base) - case SDIV: - require(2) - y, x := S256(stack.Pop()), S256(stack.Pop()) - - if x.Cmp(ethutil.Big0) == 0 { - base.Set(ethutil.Big0) - } else { - n := new(big.Int) - if new(big.Int).Mul(y, x).Cmp(ethutil.Big0) < 0 { - n.SetInt64(-1) - } else { - n.SetInt64(1) - } - - base.Div(y.Abs(y), x.Mul(x.Abs(x), n)) - - U256(base) - } - - stack.Push(base) - case MOD: - require(2) - x, y := stack.Popn() - - base.Mod(y, x) - - U256(base) - - stack.Push(base) - case SMOD: - require(2) - y, x := S256(stack.Pop()), S256(stack.Pop()) - - if x.Cmp(ethutil.Big0) == 0 { - base.Set(ethutil.Big0) - } else { - n := new(big.Int) - if y.Cmp(ethutil.Big0) < 0 { - n.SetInt64(-1) - } else { - n.SetInt64(1) - } - - base.Mod(y.Abs(y), x.Mul(x.Abs(x), n)) - - U256(base) - } - - stack.Push(base) - - case EXP: - require(2) - x, y := stack.Popn() - - base.Exp(y, x, Pow256) - - U256(base) - - stack.Push(base) - case NOT: - require(1) - base.Sub(Pow256, stack.Pop()) - - base = U256(base) - - stack.Push(base) - case LT: - require(2) - x, y := stack.Popn() - // x < y - if y.Cmp(x) < 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case GT: - require(2) - x, y := stack.Popn() - - // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - - case SLT: - require(2) - y, x := S256(stack.Pop()), S256(stack.Pop()) - // x < y - if y.Cmp(S256(x)) < 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case SGT: - require(2) - y, x := S256(stack.Pop()), S256(stack.Pop()) - - // x > y - if y.Cmp(x) > 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - - case EQ: - require(2) - x, y := stack.Popn() - - // x == y - if x.Cmp(y) == 0 { - stack.Push(ethutil.BigTrue) - } else { - stack.Push(ethutil.BigFalse) - } - case ISZERO: - require(1) - x := stack.Pop() - if x.Cmp(ethutil.BigFalse) > 0 { - stack.Push(ethutil.BigFalse) - } else { - stack.Push(ethutil.BigTrue) - } - - // 0x10 range - case AND: - require(2) - x, y := stack.Popn() - - stack.Push(base.And(y, x)) - case OR: - require(2) - x, y := stack.Popn() - - stack.Push(base.Or(y, x)) - case XOR: - require(2) - x, y := stack.Popn() - - stack.Push(base.Xor(y, x)) - case BYTE: - require(2) - val, th := stack.Popn() - if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 { - byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) - stack.Push(byt) - - } else { - stack.Push(ethutil.BigFalse) - } - case ADDMOD: - require(3) - - x := stack.Pop() - y := stack.Pop() - z := stack.Pop() - - base.Add(x, y) - base.Mod(base, z) - - U256(base) - - stack.Push(base) - case MULMOD: - require(3) - - x := stack.Pop() - y := stack.Pop() - z := stack.Pop() - - base.Mul(x, y) - base.Mod(base, z) - - U256(base) - - stack.Push(base) - - // 0x20 range - case SHA3: - require(2) - size, offset := stack.Popn() - data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64())) - - stack.Push(ethutil.BigD(data)) - - // 0x30 range - case ADDRESS: - stack.Push(ethutil.BigD(closure.Address())) - - case BALANCE: - require(1) - - addr := stack.Pop().Bytes() - balance := self.env.State().GetBalance(addr) - - stack.Push(balance) - - case ORIGIN: - origin := self.env.Origin() - - stack.Push(ethutil.BigD(origin)) - - case CALLER: - caller := closure.caller.Address() - stack.Push(ethutil.BigD(caller)) - - case CALLVALUE: - value := closure.exe.value - - stack.Push(value) - - case CALLDATALOAD: - require(1) - var ( - offset = stack.Pop() - data = make([]byte, 32) - lenData = big.NewInt(int64(len(closure.Args))) - ) - - if lenData.Cmp(offset) >= 0 { - length := new(big.Int).Add(offset, ethutil.Big32) - length = ethutil.BigMin(length, lenData) - - copy(data, closure.Args[offset.Int64():length.Int64()]) - } - - stack.Push(ethutil.BigD(data)) - case CALLDATASIZE: - l := int64(len(closure.Args)) - stack.Push(big.NewInt(l)) - - case CALLDATACOPY: - var ( - size = int64(len(closure.Args)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() - ) - - if cOff > size { - cOff = 0 - l = 0 - } else if cOff+l > size { - l = 0 - } - - code := closure.Args[cOff : cOff+l] - - mem.Set(mOff, l, code) - case CODESIZE, EXTCODESIZE: - var code []byte - if op == EXTCODECOPY { - addr := stack.Pop().Bytes() - - code = self.env.State().GetCode(addr) - } else { - code = closure.Code - } - - l := big.NewInt(int64(len(code))) - stack.Push(l) - - case CODECOPY, EXTCODECOPY: - var code []byte - if op == EXTCODECOPY { - addr := stack.Pop().Bytes() - - code = self.env.State().GetCode(addr) - } else { - code = closure.Code - } - - var ( - size = int64(len(code)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() - ) - - if cOff > size { - cOff = 0 - l = 0 - } else if cOff+l > size { - l = 0 - } - - codeCopy := code[cOff : cOff+l] - - mem.Set(mOff, l, codeCopy) - case GASPRICE: - stack.Push(closure.Price) - - // 0x40 range - case PREVHASH: - prevHash := self.env.PrevHash() - - stack.Push(ethutil.BigD(prevHash)) - - case COINBASE: - coinbase := self.env.Coinbase() - - stack.Push(ethutil.BigD(coinbase)) - - case TIMESTAMP: - time := self.env.Time() - - stack.Push(big.NewInt(time)) - - case NUMBER: - number := self.env.BlockNumber() - - stack.Push(number) - - case DIFFICULTY: - difficulty := self.env.Difficulty() - - stack.Push(difficulty) - - case GASLIMIT: - // TODO - stack.Push(big.NewInt(0)) - - // 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 := int(op - PUSH1 + 1) - val := ethutil.BigD(closure.GetBytes(int(pc+1), a)) - // Push value to stack - stack.Push(val) - - pc += a - - step += int(op) - int(PUSH1) + 1 - case POP: - require(1) - stack.Pop() - case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: - n := int(op - DUP1 + 1) - stack.Dupn(n) - case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: - n := int(op - SWAP1 + 2) - stack.Swapn(n) - - case MLOAD: - require(1) - offset := stack.Pop() - val := ethutil.BigD(mem.Get(offset.Int64(), 32)) - stack.Push(val) - - case MSTORE: // Store the value at stack top-1 in to memory at location stack top - require(2) - // Pop value of the stack - val, mStart := stack.Popn() - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) - - case MSTORE8: - require(2) - off := stack.Pop() - val := stack.Pop() - - mem.store[off.Int64()] = byte(val.Int64() & 0xff) - - case SLOAD: - require(1) - loc := stack.Pop() - val := closure.GetStorage(loc) - - stack.Push(val.BigInt()) - - case SSTORE: - require(2) - val, loc := stack.Popn() - closure.SetStorage(loc, ethutil.NewValue(val)) - - closure.message.AddStorageChange(loc.Bytes()) - - case JUMP: - require(1) - pc = int(stack.Pop().Int64()) - // Reduce pc by one because of the increment that's at the end of this for loop - - continue - case JUMPI: - require(2) - cond, pos := stack.Popn() - if cond.Cmp(ethutil.BigTrue) >= 0 { - pc = int(pos.Int64()) - - if closure.GetOp(int(pc)) != JUMPDEST { - return closure.Return(nil), fmt.Errorf("JUMP missed JUMPDEST %v", pc) - } - - continue - } - case JUMPDEST: - case PC: - stack.Push(u256(int64(pc))) - case MSIZE: - stack.Push(big.NewInt(int64(mem.Len()))) - case GAS: - stack.Push(closure.Gas) - // 0x60 range - case CREATE: - require(3) - - var ( - err error - value = stack.Pop() - size, offset = stack.Popn() - input = mem.Get(offset.Int64(), size.Int64()) - gas = new(big.Int).Set(closure.Gas) - - // Snapshot the current stack so we are able to - // revert back to it later. - //snapshot = self.env.State().Copy() - ) - - // Generate a new address - addr := crypto.CreateAddress(closure.Address(), closure.object.Nonce) - closure.object.Nonce++ - - closure.UseGas(closure.Gas) - - msg := NewExecution(self, addr, input, gas, closure.Price, value) - ret, err := msg.Exec(addr, closure) - if err != nil { - stack.Push(ethutil.BigFalse) - - // Revert the state as it was before. - //self.env.State().Set(snapshot) - - } else { - msg.object.Code = ret - - stack.Push(ethutil.BigD(addr)) - } - - case CALL, CALLCODE: - require(7) - - gas := stack.Pop() - // Pop gas and value of the stack. - value, addr := stack.Popn() - // Pop input size and offset - inSize, inOffset := stack.Popn() - // Pop return size and offset - retSize, retOffset := stack.Popn() - - // Get the arguments from the memory - args := mem.Get(inOffset.Int64(), inSize.Int64()) - - var executeAddr []byte - if op == CALLCODE { - executeAddr = closure.Address() - } else { - executeAddr = addr.Bytes() - } - - msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) - ret, err := msg.Exec(addr.Bytes(), closure) - if err != nil { - stack.Push(ethutil.BigFalse) - } else { - stack.Push(ethutil.BigTrue) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) - } - - case RETURN: - require(2) - size, offset := stack.Popn() - ret := mem.Get(offset.Int64(), size.Int64()) - - return closure.Return(ret), nil - case SUICIDE: - require(1) - - receiver := self.env.State().GetOrNewStateObject(stack.Pop().Bytes()) - - receiver.AddAmount(closure.object.Balance()) - - closure.object.MarkForDeletion() - - fallthrough - case STOP: // Stop the closure - - return closure.Return(nil), nil - default: - vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) - - //panic(fmt.Sprintf("Invalid opcode %x", op)) - - return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) - } - - pc++ - } +func (self *Vm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, data []byte) (ret []byte, err error) { + return nil, nil } func (self *Vm) Env() Environment { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 91d3c55c1..26756fceb 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -35,11 +35,26 @@ func NewDebugVm(env Environment) *DebugVm { lt = LogTyDiff } - return &DebugVm{env: env, logTy: lt, Recoverable: false} + return &DebugVm{env: env, logTy: lt, Recoverable: true} } -func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { - self.depth++ +func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { + self.env.SetDepth(self.env.Depth() + 1) + + msg := self.env.State().Manifest().AddMessage(&state.Message{ + To: me.Address(), From: caller.Address(), + Input: callData, + Origin: self.env.Origin(), + Block: self.env.BlockHash(), Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(), + Value: value, + }) + closure := NewClosure(msg, caller, me, code, gas, price) + + if self.env.Depth() == MaxCallDepth { + closure.UseGas(gas) + + return closure.Return(nil), DepthError{} + } if self.Recoverable { // Recover from any require exception @@ -96,17 +111,12 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { } ) - // Debug hook - if self.Dbg != nil { - self.Dbg.SetCode(closure.Code) - } - // Don't bother with the execution if there's no code. - if len(closure.Code) == 0 { + if len(code) == 0 { return closure.Return(nil), nil } - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, callData) for { prevStep = step @@ -596,8 +606,6 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" => %x", caller) case CALLVALUE: - value := closure.exe.value - stack.Push(value) self.Printf(" => %v", value) @@ -605,27 +613,27 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { var ( offset = stack.Pop() data = make([]byte, 32) - lenData = big.NewInt(int64(len(closure.Args))) + lenData = big.NewInt(int64(len(callData))) ) if lenData.Cmp(offset) >= 0 { length := new(big.Int).Add(offset, ethutil.Big32) length = ethutil.BigMin(length, lenData) - copy(data, closure.Args[offset.Int64():length.Int64()]) + copy(data, callData[offset.Int64():length.Int64()]) } self.Printf(" => 0x%x", data) stack.Push(ethutil.BigD(data)) case CALLDATASIZE: - l := int64(len(closure.Args)) + l := int64(len(callData)) stack.Push(big.NewInt(l)) self.Printf(" => %d", l) case CALLDATACOPY: var ( - size = int64(len(closure.Args)) + size = int64(len(callData)) mOff = stack.Pop().Int64() cOff = stack.Pop().Int64() l = stack.Pop().Int64() @@ -638,7 +646,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { l = 0 } - code := closure.Args[cOff : cOff+l] + code := callData[cOff : cOff+l] mem.Set(mOff, l, code) @@ -847,17 +855,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { closure.UseGas(closure.Gas) - msg := NewExecution(self, addr, input, gas, closure.Price, value) - ret, err := msg.Create(closure) + ret, err, ref := self.env.Create(closure, addr, input, gas, price, value) if err != nil { stack.Push(ethutil.BigFalse) - // Revert the state as it was before. - //self.env.State().Set(snapshot) - self.Printf("CREATE err %v", err) } else { - msg.object.Code = ret + ref.SetCode(ret) + msg.Output = ret stack.Push(ethutil.BigD(addr)) } @@ -889,14 +894,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { executeAddr = addr.Bytes() } - msg := NewExecution(self, executeAddr, args, gas, closure.Price, value) - ret, err := msg.Exec(addr.Bytes(), closure) + ret, err := self.env.Call(closure, executeAddr, args, gas, price, value) if err != nil { stack.Push(ethutil.BigFalse) vmlogger.Debugln(err) } else { stack.Push(ethutil.BigTrue) + msg.Output = ret mem.Set(retOffset.Int64(), retSize.Int64(), ret) } -- cgit v1.2.3 From b6cb5272de96185b424d5c6c4a817d99f536d29b Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 3 Dec 2014 17:35:57 +0100 Subject: Descriptive function names for closure getters --- vm/closure.go | 57 ++++++++++++++++++++++++++------------------------------- vm/vm_debug.go | 4 ++-- 2 files changed, 28 insertions(+), 33 deletions(-) (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index 2263236e7..5324ee1ec 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -1,7 +1,5 @@ package vm -// TODO Re write VM to use values instead of big integers? - import ( "math/big" @@ -17,7 +15,6 @@ type ClosureRef interface { SetStorage(*big.Int, *ethutil.Value) } -// Basic inline closure object which implement the 'closure' interface type Closure struct { caller ClosureRef object ClosureRef @@ -44,18 +41,8 @@ func NewClosure(msg *state.Message, caller ClosureRef, object ClosureRef, code [ return c } -// Retuns the x element in data slice -func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { - m := c.object.GetStorage(x) - if m == nil { - return ethutil.EmptyValue() - } - - return m -} - -func (c *Closure) Get(x *big.Int) *ethutil.Value { - return c.Gets(x, big.NewInt(1)) +func (c *Closure) GetValue(x *big.Int) *ethutil.Value { + return c.GetRangeValue(x, big.NewInt(1)) } func (c *Closure) GetOp(x int) OpCode { @@ -78,7 +65,7 @@ func (c *Closure) GetBytes(x, y int) []byte { return c.Code[x : x+y] } -func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { +func (c *Closure) GetRangeValue(x, y *big.Int) *ethutil.Value { if x.Int64() >= int64(len(c.Code)) || y.Int64() >= int64(len(c.Code)) { return ethutil.NewValue(0) } @@ -88,27 +75,21 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { return ethutil.NewValue(partial) } -func (self *Closure) SetCode(code []byte) { - self.Code = code -} - +/* + * State storage functions + */ func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { c.object.SetStorage(x, val) } -func (c *Closure) Address() []byte { - return c.object.Address() -} - -/* -func (c *Closure) Call(vm VirtualMachine, args []byte) ([]byte, *big.Int, error) { - c.Args = args - - ret, err := vm.RunClosure(c) +func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { + m := c.object.GetStorage(x) + if m == nil { + return ethutil.EmptyValue() + } - return ret, c.UsedGas, err + return m } -*/ func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the caller @@ -117,6 +98,9 @@ func (c *Closure) Return(ret []byte) []byte { return ret } +/* + * Gas functions + */ func (c *Closure) UseGas(gas *big.Int) bool { if c.Gas.Cmp(gas) < 0 { return false @@ -136,6 +120,17 @@ func (c *Closure) ReturnGas(gas, price *big.Int) { c.UsedGas.Sub(c.UsedGas, gas) } +/* + * Set / Get + */ func (c *Closure) Caller() ClosureRef { return c.caller } + +func (c *Closure) Address() []byte { + return c.object.Address() +} + +func (self *Closure) SetCode(code []byte) { + self.Code = code +} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 26756fceb..cf234c412 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -737,7 +737,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * 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 := big.NewInt(int64(op) - int64(PUSH1) + 1) pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, a) + data := closure.GetRangeValue(pc, a) val := ethutil.BigD(data.Bytes()) // Push value to stack stack.Push(val) @@ -754,7 +754,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) - if OpCode(closure.Get(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.Get(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { + if OpCode(closure.GetValue(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.GetValue(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { fmt.Println(toValue(v)) } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: -- cgit v1.2.3 From 83663ed4b01480c628ce2c849e4e881ac04b5120 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 10:53:49 +0100 Subject: Renames for chain, updated VM, moved methods * Renamed a couple more chain => core * Updated VM `pc` to be uint64 rather than big int * XEth interface cleanup --- vm/analysis.go | 10 +++---- vm/closure.go | 16 +++++------ vm/vm_debug.go | 85 +++++++++++++++++++++++++++++----------------------------- 3 files changed, 55 insertions(+), 56 deletions(-) (limited to 'vm') diff --git a/vm/analysis.go b/vm/analysis.go index 52c7143e0..fef448b7b 100644 --- a/vm/analysis.go +++ b/vm/analysis.go @@ -6,17 +6,17 @@ import ( "github.com/ethereum/go-ethereum/ethutil" ) -func analyseJumpDests(code []byte) (dests map[int64]*big.Int) { - dests = make(map[int64]*big.Int) +func analyseJumpDests(code []byte) (dests map[uint64]*big.Int) { + dests = make(map[uint64]*big.Int) lp := false var lpv *big.Int - for pc := int64(0); pc < int64(len(code)); pc++ { + for pc := uint64(0); pc < uint64(len(code)); pc++ { var op OpCode = OpCode(code[pc]) switch op { 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 := int64(op) - int64(PUSH1) + 1 - if int64(len(code)) > pc+1+a { + a := uint64(op) - uint64(PUSH1) + 1 + if uint64(len(code)) > pc+1+a { lpv = ethutil.BigD(code[pc+1 : pc+1+a]) } diff --git a/vm/closure.go b/vm/closure.go index 5324ee1ec..bd5268f96 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -41,16 +41,16 @@ func NewClosure(msg *state.Message, caller ClosureRef, object ClosureRef, code [ return c } -func (c *Closure) GetValue(x *big.Int) *ethutil.Value { - return c.GetRangeValue(x, big.NewInt(1)) +func (c *Closure) GetValue(x uint64) *ethutil.Value { + return c.GetRangeValue(x, 1) } -func (c *Closure) GetOp(x int) OpCode { +func (c *Closure) GetOp(x uint64) OpCode { return OpCode(c.GetByte(x)) } -func (c *Closure) GetByte(x int) byte { - if x > -1 && x < len(c.Code) { +func (c *Closure) GetByte(x uint64) byte { + if x < uint64(len(c.Code)) { return c.Code[x] } @@ -65,12 +65,12 @@ func (c *Closure) GetBytes(x, y int) []byte { return c.Code[x : x+y] } -func (c *Closure) GetRangeValue(x, y *big.Int) *ethutil.Value { - if x.Int64() >= int64(len(c.Code)) || y.Int64() >= int64(len(c.Code)) { +func (c *Closure) GetRangeValue(x, y uint64) *ethutil.Value { + if x >= uint64(len(c.Code)) || y >= uint64(len(c.Code)) { return ethutil.NewValue(0) } - partial := c.Code[x.Int64() : x.Int64()+y.Int64()] + partial := c.Code[x : x+y] return ethutil.NewValue(partial) } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index cf234c412..712af55fa 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -75,35 +75,35 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * var ( op OpCode - destinations = analyseJumpDests(closure.Code) - mem = NewMemory() - stack = NewStack() - pc = big.NewInt(0) - step = 0 - prevStep = 0 - statedb = self.env.State() - require = func(m int) { + destinations = analyseJumpDests(closure.Code) + mem = NewMemory() + stack = NewStack() + pc uint64 = 0 + step = 0 + prevStep = 0 + statedb = self.env.State() + require = func(m int) { if stack.Len() < m { panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) } } - jump = func(from, to *big.Int) { - p := int(to.Int64()) + jump = func(from uint64, to *big.Int) { + p := to.Uint64() self.Printf(" ~> %v", to) // Return to start if p == 0 { - pc = big.NewInt(0) + pc = 0 } else { nop := OpCode(closure.GetOp(p)) - if !(nop == JUMPDEST || destinations[from.Int64()] != nil) { + if !(nop == JUMPDEST || destinations[from] != nil) { panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) } else if nop == JUMP || nop == JUMPI { panic(fmt.Sprintf("not allowed to JUMP(I) in to JUMP")) } - pc = to + pc = to.Uint64() } @@ -125,26 +125,28 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * step++ // Get the memory location of pc - op = closure.GetOp(int(pc.Uint64())) + op = closure.GetOp(pc) + + /* + // XXX Leave this Println intact. Don't change this to the log system. + // Used for creating diffs between implementations + if self.logTy == LogTyDiff { + switch op { + case STOP, RETURN, SUICIDE: + statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { + value.Decode() + fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) + }) + } - // XXX Leave this Println intact. Don't change this to the log system. - // Used for creating diffs between implementations - if self.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - 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) addStepGasUsage := func(amount *big.Int) { @@ -735,13 +737,15 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * // 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 := big.NewInt(int64(op) - int64(PUSH1) + 1) - pc.Add(pc, ethutil.Big1) - data := closure.GetRangeValue(pc, a) + //a := big.NewInt(int64(op) - int64(PUSH1) + 1) + a := uint64(op - PUSH1 + 1) + //pc.Add(pc, ethutil.Big1) + data := closure.GetRangeValue(pc+1, a) val := ethutil.BigD(data.Bytes()) // Push value to stack stack.Push(val) - pc.Add(pc, a.Sub(a, big.NewInt(1))) + pc += a + //pc.Add(pc, a.Sub(a, big.NewInt(1))) step += int(op) - int(PUSH1) + 1 @@ -750,13 +754,9 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) - v := stack.Dupn(n) + stack.Dupn(n) self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes()) - - if OpCode(closure.GetValue(new(big.Int).Add(pc, ethutil.Big1)).Uint()) == POP && OpCode(closure.GetValue(new(big.Int).Add(pc, big.NewInt(2))).Uint()) == POP { - fmt.Println(toValue(v)) - } case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: n := int(op - SWAP1 + 2) x, y := stack.Swapn(n) @@ -811,7 +811,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: - jump(pc, stack.Pop()) continue @@ -826,7 +825,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * case JUMPDEST: case PC: - stack.Push(pc) + stack.Push(big.NewInt(int64(pc))) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) case GAS: @@ -940,13 +939,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } - pc.Add(pc, ethutil.Big1) + pc++ self.Endl() if self.Dbg != nil { for _, instrNo := range self.Dbg.BreakPoints() { - if pc.Cmp(big.NewInt(instrNo)) == 0 { + if pc == uint64(instrNo) { self.Stepping = true if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(closure.Address())) { -- cgit v1.2.3 From 491edc16e778e3d232f643a4b4155c4f71ef27cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 10:57:09 +0100 Subject: Fixes #189 --- vm/vm_debug.go | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 712af55fa..b189a1cd1 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -127,27 +127,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * // Get the memory location of pc op = closure.GetOp(pc) - /* - // XXX Leave this Println intact. Don't change this to the log system. - // Used for creating diffs between implementations - if self.logTy == LogTyDiff { - switch op { - case STOP, RETURN, SUICIDE: - statedb.GetStateObject(closure.Address()).EachStorage(func(key string, value *ethutil.Value) { - value.Decode() - fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes()) - }) - } - - 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()) - } - */ - gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { if amount.Cmp(ethutil.Big0) >= 0 { -- cgit v1.2.3 From f298ffdbb8ec2b14f254e880a65f22f4d7c66305 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 11:40:20 +0100 Subject: Renamed State => StateDB --- vm/environment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index 3d75d05b9..9e129b6ee 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -9,7 +9,7 @@ import ( ) type Environment interface { - State() *state.State + State() *state.StateDB Origin() []byte BlockNumber() *big.Int -- cgit v1.2.3 From bff5999efaaa0aa7a2b6518b58d489ad4be9e4ff Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 12:09:22 +0100 Subject: sort tests for evm --- vm/vm_debug.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index b189a1cd1..62b1f121c 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -35,7 +35,7 @@ func NewDebugVm(env Environment) *DebugVm { lt = LogTyDiff } - return &DebugVm{env: env, logTy: lt, Recoverable: true} + return &DebugVm{env: env, logTy: lt, Recoverable: false} } func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { @@ -631,7 +631,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * mem.Set(mOff, l, code) - self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) + self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, callData[cOff:cOff+l]) case CODESIZE, EXTCODESIZE: var code []byte if op == EXTCODESIZE { -- cgit v1.2.3 From 3043b233ea4df9b630638d75f3589b94653ccfa9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 12:35:23 +0100 Subject: Log is now interface --- vm/environment.go | 24 +++++++++++++++++++++++- vm/vm_debug.go | 4 ++-- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index 9e129b6ee..d77fb1419 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,7 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error - AddLog(*state.Log) + AddLog(state.Log) Depth() int SetDepth(i int) @@ -52,3 +52,25 @@ func Transfer(from, to Account, amount *big.Int) error { return nil } + +type Log struct { + address []byte + topics [][]byte + data []byte +} + +func (self *Log) Address() []byte { + return self.address +} + +func (self *Log) Topics() [][]byte { + return self.topics +} + +func (self *Log) Data() []byte { + return self.data +} + +func (self *Log) RlpData() interface{} { + return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data} +} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 62b1f121c..0a541a769 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -35,7 +35,7 @@ func NewDebugVm(env Environment) *DebugVm { lt = LogTyDiff } - return &DebugVm{env: env, logTy: lt, Recoverable: false} + return &DebugVm{env: env, logTy: lt, Recoverable: true} } func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { @@ -750,7 +750,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) } - log := &state.Log{closure.Address(), topics, data} + log := &Log{closure.Address(), topics, data} self.env.AddLog(log) self.Printf(" => %v", log) -- cgit v1.2.3 From 3db9c8007086e0735695a6477c21056737519db9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 4 Dec 2014 17:13:23 +0100 Subject: Removed mutan. Closes #183 --- vm/vm_test.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 19aa171a6..84ebf378f 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/trie" checker "gopkg.in/check.v1" - // "github.com/obscuren/mutan" ) type VmSuite struct{} @@ -68,24 +67,18 @@ func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { } func (s *VmSuite) TestDebugVm(c *checker.C) { - // if mutan.Version < "0.6" { - // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - // } closure, vm := setup(logger.DebugLevel, DebugVmTy) ret, _, e := closure.Call(vm, nil) c.Assert(e, checker.NotNil) - c.Skip("Depends on mutan") + c.Skip("Depends on mutan. Requires serpent implementation") c.Assert(ret, checker.DeepEquals, big9) } func (s *VmSuite) TestVm(c *checker.C) { - // if mutan.Version < "0.6" { - // t.Skip("skipping for mutan version", mutan.Version, " < 0.6") - // } closure, vm := setup(logger.DebugLevel, StandardVmTy) ret, _, e := closure.Call(vm, nil) c.Assert(e, checker.NotNil) - c.Skip("Depends on mutan") + c.Skip("Depends on mutan. Requires serpent implementation") c.Assert(ret, checker.DeepEquals, big9) } @@ -142,7 +135,7 @@ func (s *VmSuite) TestBuildInSha256(c *checker.C) { `, DebugVmTy) exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) - c.Skip("Depends on mutan") + c.Skip("Depends on mutan. Requires serpent implementation") c.Assert(ret, checker.DeepEquals, exp) } @@ -157,7 +150,7 @@ func (s *VmSuite) TestBuildInRipemd(c *checker.C) { `, DebugVmTy) exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) - c.Skip("Depends on mutan") + c.Skip("Depends on mutan. Requires serpent implementation") c.Assert(ret, checker.DeepEquals, exp) } -- cgit v1.2.3 From d80f8bda940a8ae8f6dab1502a46054c06cee5cc Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 5 Dec 2014 12:32:47 +0100 Subject: Fixed issue in VM where LOG didn't pop anything of the stack --- vm/vm_debug.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 0a541a769..956a16da2 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -744,12 +744,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * case LOG0, LOG1, LOG2, LOG3, LOG4: n := int(op - LOG0) topics := make([][]byte, n) - mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() - data := mem.Geti(mStart, mSize) + mSize, mStart := stack.Popn() for i := 0; i < n; i++ { topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32) } + data := mem.Geti(mStart.Int64(), mSize.Int64()) log := &Log{closure.Address(), topics, data} self.env.AddLog(log) -- cgit v1.2.3 From 095cb976758e942b7beba8231686a7738a283e19 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 5 Dec 2014 14:52:36 +0100 Subject: EXP simplified --- vm/vm_debug.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 956a16da2..be1c59339 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -166,13 +166,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * case EXP: require(2) - exp := new(big.Int).Set(stack.data[stack.Len()-2]) - nbytes := 0 - for exp.Cmp(ethutil.Big0) > 0 { - nbytes += 1 - exp.Rsh(exp, 8) - } - gas.Set(big.NewInt(int64(nbytes + 1))) + gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1))) // Gas only case STOP: gas.Set(ethutil.Big0) -- cgit v1.2.3 From acf4b5753fd473f048176a12c42e1b8209035b57 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 9 Dec 2014 20:27:57 +0100 Subject: Core changes * Code = '' if gas < len(D) * 5 * Sha3 gas 10 + 10 * len(D), rounding up 32 bytes * Sha256 gas 50 + 50 * len(D), rounding up 32 bytes * Ripmed gas 50 + 50 * len(D), rounding up 32 bytes * Accounts and value transfers no longer reverted --- vm/address.go | 18 ++++++++++++++---- vm/common.go | 7 +++++++ vm/vm_debug.go | 14 +++++++++++--- 3 files changed, 32 insertions(+), 7 deletions(-) (limited to 'vm') diff --git a/vm/address.go b/vm/address.go index 06bd35f6b..be8921a3b 100644 --- a/vm/address.go +++ b/vm/address.go @@ -12,7 +12,7 @@ type Address interface { } type PrecompiledAddress struct { - Gas *big.Int + Gas func(l int) *big.Int fn func(in []byte) []byte } @@ -21,9 +21,19 @@ func (self PrecompiledAddress) Call(in []byte) []byte { } var Precompiled = map[uint64]*PrecompiledAddress{ - 1: &PrecompiledAddress{big.NewInt(500), ecrecoverFunc}, - 2: &PrecompiledAddress{big.NewInt(100), sha256Func}, - 3: &PrecompiledAddress{big.NewInt(100), ripemd160Func}, + 1: &PrecompiledAddress{func(l int) *big.Int { + return GasEcrecover + }, ecrecoverFunc}, + 2: &PrecompiledAddress{func(l int) *big.Int { + n := big.NewInt(int64(l+31)/32 + 1) + n.Mul(n, GasSha256) + return n + }, sha256Func}, + 3: &PrecompiledAddress{func(l int) *big.Int { + n := big.NewInt(int64(l+31)/32 + 1) + n.Mul(n, GasRipemd) + return n + }, ripemd160Func}, } func sha256Func(in []byte) []byte { diff --git a/vm/common.go b/vm/common.go index 9514ff6d3..5fd512687 100644 --- a/vm/common.go +++ b/vm/common.go @@ -27,10 +27,17 @@ var ( GasBalance = big.NewInt(20) GasCreate = big.NewInt(100) GasCall = big.NewInt(20) + GasCreateByte = big.NewInt(5) + GasSha3Byte = big.NewInt(10) + GasSha256Byte = big.NewInt(50) + GasRipemdByte = big.NewInt(50) GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) GasLog = big.NewInt(32) + GasSha256 = big.NewInt(50) + GasRipemd = big.NewInt(50) + GasEcrecover = big.NewInt(100) Pow256 = ethutil.BigPow(2, 256) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index be1c59339..c0a2d6d98 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -254,9 +254,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * newMemSize.Mul(newMemSize, u256(32)) switch op { - // Additional gas usage on *CODPY case CALLDATACOPY, CODECOPY, EXTCODECOPY: addStepGasUsage(new(big.Int).Div(newMemSize, u256(32))) + case SHA3: + g := new(big.Int).Div(newMemSize, u256(32)) + g.Mul(g, GasSha3Byte) + addStepGasUsage(g) } if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { @@ -833,8 +836,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * self.Printf("CREATE err %v", err) } else { - ref.SetCode(ret) - msg.Output = ret + // gas < len(ret) * CreateDataGas == NO_CODE + dataGas := big.NewInt(int64(len(ret))) + dataGas.Mul(dataGas, GasCreateByte) + if closure.UseGas(dataGas) { + ref.SetCode(ret) + msg.Output = ret + } stack.Push(ethutil.BigD(addr)) } -- cgit v1.2.3 From 1fb84d3c5f486ef0d42a21f3cd8416d6ef211604 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Dec 2014 10:57:19 +0100 Subject: Fixed tests --- vm/vm_test.go | 173 +--------------------------------------------------------- 1 file changed, 1 insertion(+), 172 deletions(-) (limited to 'vm') diff --git a/vm/vm_test.go b/vm/vm_test.go index 84ebf378f..9bd147a72 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -1,174 +1,3 @@ package vm -import ( - "fmt" - "io/ioutil" - "log" - "math/big" - "os" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/trie" - checker "gopkg.in/check.v1" -) - -type VmSuite struct{} - -var _ = checker.Suite(&VmSuite{}) -var big9 = ethutil.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009") - -const mutcode = ` -var x = 0; -for i := 0; i < 10; i++ { - x = i -} - -return x` - -type TestEnv struct{} - -func (TestEnv) Origin() []byte { return nil } -func (TestEnv) BlockNumber() *big.Int { return nil } -func (TestEnv) BlockHash() []byte { return nil } -func (TestEnv) PrevHash() []byte { return nil } -func (TestEnv) Coinbase() []byte { return nil } -func (TestEnv) Time() int64 { return 0 } -func (TestEnv) GasLimit() *big.Int { return nil } -func (TestEnv) Difficulty() *big.Int { return nil } -func (TestEnv) Value() *big.Int { return nil } -func (TestEnv) AddLog(*state.Log) {} -func (TestEnv) Transfer(from, to Account, amount *big.Int) error { - return nil -} - -// This is likely to fail if anything ever gets looked up in the state trie :-) -func (TestEnv) State() *state.State { - return state.New(trie.New(nil, "")) -} - -func setup(level logger.LogLevel, typ Type) (*Closure, VirtualMachine) { - code, err := ethutil.Compile(mutcode, true) - if err != nil { - log.Fatal(err) - } - - // Pipe output to /dev/null - logger.AddLogSystem(logger.NewStdLogSystem(ioutil.Discard, log.LstdFlags, level)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - callerClosure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) - - return callerClosure, New(TestEnv{}, typ) -} - -func (s *VmSuite) TestDebugVm(c *checker.C) { - closure, vm := setup(logger.DebugLevel, DebugVmTy) - ret, _, e := closure.Call(vm, nil) - c.Assert(e, checker.NotNil) - c.Skip("Depends on mutan. Requires serpent implementation") - c.Assert(ret, checker.DeepEquals, big9) -} - -func (s *VmSuite) TestVm(c *checker.C) { - closure, vm := setup(logger.DebugLevel, StandardVmTy) - ret, _, e := closure.Call(vm, nil) - c.Assert(e, checker.NotNil) - c.Skip("Depends on mutan. Requires serpent implementation") - c.Assert(ret, checker.DeepEquals, big9) -} - -func (s *VmSuite) BenchmarkDebugVm(c *checker.C) { - closure, vm := setup(logger.InfoLevel, StandardVmTy) - - c.ResetTimer() - - for i := 0; i < c.N; i++ { - closure.Call(vm, nil) - } -} - -func (s *VmSuite) BenchmarkVm(c *checker.C) { - closure, vm := setup(logger.InfoLevel, DebugVmTy) - - c.ResetTimer() - - for i := 0; i < c.N; i++ { - closure.Call(vm, nil) - } -} - -func RunCode(mutCode string, typ Type) []byte { - code, err := ethutil.Compile(mutCode, true) - if err != nil { - log.Fatal(err) - } - - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - closure := NewClosure(nil, stateObject, stateObject, code, big.NewInt(1000000), big.NewInt(0)) - - vm := New(TestEnv{}, typ) - ret, _, e := closure.Call(vm, nil) - if e != nil { - fmt.Println(e) - } - - return ret -} - -func (s *VmSuite) TestBuildInSha256(c *checker.C) { - ret := RunCode(` - var in = 42 - var out = 0 - - call(0x2, 0, 10000, in, out) - - return out - `, DebugVmTy) - - exp := crypto.Sha256(ethutil.LeftPadBytes([]byte{42}, 32)) - c.Skip("Depends on mutan. Requires serpent implementation") - c.Assert(ret, checker.DeepEquals, exp) -} - -func (s *VmSuite) TestBuildInRipemd(c *checker.C) { - ret := RunCode(` - var in = 42 - var out = 0 - - call(0x3, 0, 10000, in, out) - - return out - `, DebugVmTy) - - exp := ethutil.RightPadBytes(crypto.Ripemd160(ethutil.LeftPadBytes([]byte{42}, 32)), 32) - c.Skip("Depends on mutan. Requires serpent implementation") - c.Assert(ret, checker.DeepEquals, exp) -} - -func (s *VmSuite) TestOog(c *checker.C) { - // This tests takes a long time and will eventually run out of gas - // t.Skip() - c.Skip("This tests takes a long time and will eventually run out of gas") - - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.InfoLevel)) - - ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") - - stateObject := state.NewStateObject([]byte{'j', 'e', 'f', 'f'}) - closure := NewClosure(nil, stateObject, stateObject, ethutil.Hex2Bytes("60ff60ff600057"), big.NewInt(1000000), big.NewInt(0)) - - vm := New(TestEnv{}, DebugVmTy) - _, _, e := closure.Call(vm, nil) - if e != nil { - fmt.Println(e) - } -} +// Tests have been removed in favour of general tests. If anything implementation specific needs testing, put it here -- cgit v1.2.3 From 186948da22feeca138ffb976fbf96033045ad350 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 10 Dec 2014 11:27:10 +0100 Subject: changed to unsigned integers --- vm/stack.go | 4 ++-- vm/vm_debug.go | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'vm') diff --git a/vm/stack.go b/vm/stack.go index 98795cc03..6091479cb 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -111,10 +111,10 @@ func NewMemory() *Memory { return &Memory{nil} } -func (m *Memory) Set(offset, size int64, value []byte) { +func (m *Memory) Set(offset, size uint64, value []byte) { if len(value) > 0 { totSize := offset + size - lenSize := int64(len(m.store) - 1) + lenSize := uint64(len(m.store) - 1) if totSize > lenSize { // Calculate the diff between the sizes diff := totSize - lenSize diff --git a/vm/vm_debug.go b/vm/vm_debug.go index c0a2d6d98..5b7258cc5 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -98,7 +98,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * } else { nop := OpCode(closure.GetOp(p)) if !(nop == JUMPDEST || destinations[from] != nil) { - panic(fmt.Sprintf("JUMP missed JUMPDEST (%v) %v", nop, p)) + panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p)) } else if nop == JUMP || nop == JUMPI { panic(fmt.Sprintf("not allowed to JUMP(I) in to JUMP")) } @@ -611,10 +611,10 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * self.Printf(" => %d", l) case CALLDATACOPY: var ( - size = int64(len(callData)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() + size = uint64(len(callData)) + mOff = stack.Pop().Uint64() + cOff = stack.Pop().Uint64() + l = stack.Pop().Uint64() ) if cOff > size { @@ -654,10 +654,10 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * } var ( - size = int64(len(code)) - mOff = stack.Pop().Int64() - cOff = stack.Pop().Int64() - l = stack.Pop().Int64() + size = uint64(len(code)) + mOff = stack.Pop().Uint64() + cOff = stack.Pop().Uint64() + l = stack.Pop().Uint64() ) if cOff > size { @@ -760,7 +760,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * case MSTORE: // Store the value at stack top-1 in to memory at location stack top // Pop value of the stack val, mStart := stack.Popn() - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) + mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256)) self.Printf(" => 0x%x", val) case MSTORE8: @@ -883,7 +883,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * stack.Push(ethutil.BigTrue) msg.Output = ret - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + mem.Set(retOffset.Uint64(), retSize.Uint64(), ret) } self.Printf("resume %x", closure.Address()) -- cgit v1.2.3 From 0d57ca486a4db9f2488df5f6be47eb9b09df2004 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 12 Dec 2014 11:34:27 +0100 Subject: Squashed commit of the following: commit 779f25d36c770fcc0bdf135c8baf13be9b0a77b9 Author: CJentzsch Date: Thu Dec 11 22:59:56 2014 +0100 first random test commit 68175386c0606a824686606e992c2544775ef6c9 Author: CJentzsch Date: Thu Dec 11 21:34:50 2014 +0100 update gas prices commit ad322fbb58e87ee5175cfaf4b8f9650675660e08 Author: CJentzsch Date: Mon Dec 8 06:01:17 2014 +0100 Log as array commit f989f42618ffdaeb004c2c99007189b4739c8fad Author: CJentzsch Date: Fri Dec 5 15:12:12 2014 +0100 state log tests commit 4bc65d1129efa36eae3c83fa8f11bb7df9bcaea5 Author: CJentzsch Date: Thu Dec 4 18:18:49 2014 +0100 add calldataload, codecopy, extcodecopy tests commit 12cfae18e3e5250cca9af0932bd4178cf190b794 Author: CJentzsch Date: Thu Dec 4 15:57:56 2014 +0100 add calldataload test commit 086caf37011478ec847c7a9071f057832ad3be3e Author: CJentzsch Date: Wed Dec 3 08:31:03 2014 +0100 protocol update (CALLCODE <-> RETURN), topics in log are arrays not sets commit e6c92673b9cee6146a89e0eb28894620fe5ac035 Author: CJentzsch Date: Mon Dec 1 21:14:08 2014 +0100 update state tests with logs commit 4089b809fb9b5daea24ab88ad3e3e3947b3ff6d7 Author: CJentzsch Date: Mon Dec 1 18:19:40 2014 +0100 update gas costs commit cfdca6227716b66bd64b64c6aab864fde69336d3 Merge: 2e5175e f59f89d Author: Christoph Jentzsch Date: Mon Dec 1 18:04:51 2014 +0100 Merge pull request #42 from negedzuregal/fix vmTest fix commit f59f89d876c0e44d88b3daa4f0d26e6764ccbe0b Author: alon muroch Date: Mon Dec 1 16:18:12 2014 +0100 vmEnvironmentalInfoTest CALLDATACOPY, CODECOPY, EXTCODECOPY fix commit 68da13fe3e2efe85898e8a4ffeb99e2a8f8c103d Author: alon muroch Date: Mon Dec 1 11:10:57 2014 +0100 vmArithmeticTest exp fix commit 2e5175e818d817cda4607f9e731632393e2eb93e Author: ethers Date: Sun Nov 30 19:55:51 2014 +0100 add vmLogTest commit b5b9408e641031ded31a87792c4ec613c8afabbf Author: Heiko Heiko Date: Sun Nov 30 16:27:27 2014 +0100 updated genesis to new header w/o min_gas_price commit 8e69fbfa98d95116734f2349f6d90fbd479b694a Author: ethers Date: Fri Nov 21 17:42:05 2014 -0800 add special tests commit 90f4f942e68f38e833a727214d5810be3f8f6cf5 Author: ethers Date: Thu Nov 20 19:01:09 2014 -0800 typo commit c5e5228e0d47ec237ef6a28e696dda47a4a3a85e Author: Christoph Jentzsch Date: Thu Nov 20 17:04:06 2014 +0100 Removed log,post,out,gas,callcreates if exception occured commit 9c0232a2b995bd608f5f541e6f607d373797641d Author: Christoph Jentzsch Date: Wed Nov 19 18:19:05 2014 +0100 MakeMoney test commit 3ba0007e868e9cfc802443d6f5d42ba35a4209cb Author: Christoph Jentzsch Date: Wed Nov 19 16:23:04 2014 +0100 Added log sections in all vmtests + log tests commit d84be4fe07bb240c1ae56f63580e0e4655611e62 Merge: c8497ab 76d2542 Author: Christoph Jentzsch Date: Wed Nov 19 10:00:24 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit c8497ab25724bb6aed40fcd0462f3789380848a1 Author: Christoph Jentzsch Date: Wed Nov 19 10:00:02 2014 +0100 new push32 test and renaming commit 76d25420e153e18c667aa4991dcacf12e8f4fb5c Author: ethers Date: Mon Nov 17 18:59:30 2014 -0800 adding test commit 0be275e757744de496a80525ad8aa153def89fd3 Merge: 1d42d1d d90868c Author: Christoph Jentzsch Date: Mon Nov 17 22:47:34 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 1d42d1d7c620fb3e6d0e284697d5041226567af9 Author: Christoph Jentzsch Date: Mon Nov 17 22:46:51 2014 +0100 fix ecrecover2 commit d90868c3070624bc38668a0f3ceef3e3806d9f00 Merge: 1f38c8c 6dbcf6b Author: Christoph Jentzsch Date: Mon Nov 17 20:26:59 2014 +0100 Merge pull request #39 from wanderer/develop added test for max call depth on creation commit 6dbcf6b0d6bb68ceaa743e18a52ac815f495d408 Author: wanderer Date: Mon Nov 17 14:06:43 2014 -0500 spelling fix commit 6fc07a7f81408308e56db105afcad191f81c43bc Author: wanderer Date: Sat Nov 15 21:39:16 2014 -0500 added test for max call depth on creation commit 1f38c8c0a2e306fa95e8332c03a02e72fe26f9be Merge: 279b284 cd85ca1 Author: martin becze Date: Fri Nov 14 20:10:21 2014 -0500 Merge pull request #38 from wanderer/develop updated test 'jeff' in trietest.json commit cd85ca17edd314b3744c46573f1d5093e9be2db3 Author: martin becze Date: Fri Nov 14 19:59:34 2014 -0500 Update trietest.json commit 279b284c0d03737360ae36ce2c0da06d70e91c2c Merge: 89675a7 6cae937 Author: martin becze Date: Fri Nov 14 17:43:49 2014 -0500 Merge pull request #37 from wanderer/develop Update trietest.json commit 6cae937e5eee1c904b636440653b6157359c0963 Author: martin becze Date: Fri Nov 14 17:20:03 2014 -0500 Update trietest.json 'emptyValues' should have the same root as 'puppy' commit 89675a71537e6a386f97a9190db40276b388d692 Merge: f1de1cc 32f0c47 Author: Christoph Jentzsch Date: Thu Nov 13 23:17:49 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit f1de1cc97a556adad8a4a864267150c39bef4d85 Author: Christoph Jentzsch Date: Thu Nov 13 23:17:13 2014 +0100 Fix CallRecursiveBomb2 commit 32f0c47c6801974c210c3b93792105a9183f9e7b Merge: ab50e76 3da90d0 Author: martin becze Date: Thu Nov 13 15:26:49 2014 -0500 Merge pull request #36 from wanderer/develop converted back to arrary format commit ab50e766521ca31febe21677909a665043937488 Merge: d06b792 78f1e4a Author: Christoph Jentzsch Date: Thu Nov 13 07:52:35 2014 +0100 Merge pull request #35 from ethers/delOld rename tests since they are valid opcodes that exist commit 3da90d01f6f9e79190ebcd3a6513f481eacbbae2 Author: wanderer Date: Wed Nov 12 22:22:47 2014 -0500 converted back to arrary format commit 78f1e4a9452566f5645a7f5ade6aad79901d5f98 Author: ethers Date: Wed Nov 12 19:11:06 2014 -0800 rename tests since they are valid opcodes that exist commit d06b792cd0c80d48aa206dd9126b515e4fb1d606 Author: Christoph Jentzsch Date: Wed Nov 12 07:00:17 2014 +0100 minor change in CallSha256_1_nonzeroValue test commit d434ecdcc37af4bb53058a43884df8085c5efe73 Author: Christoph Jentzsch Date: Wed Nov 12 06:56:31 2014 +0100 Added CallSha256_1_nonzeroValue test commit 2c06f34cc00e6c41dc0c68d3e99825731e0603ab Author: Christoph Jentzsch Date: Tue Nov 11 18:10:26 2014 +0100 Store return value of call to precompiled contracts commit 4b0c3b29ae5b8807d7d244340a625c6144320df0 Author: Christoph Jentzsch Date: Tue Nov 11 17:51:14 2014 +0100 Fix gas cost for OOG calls commit 63bcca7604dce4f912776f4e2e9954ceca02dfcf Author: Heiko Heiko Date: Tue Nov 11 08:59:19 2014 +0100 fix: genesis test commit 6e0310c1ea7b0f8af7a337df93b3b83591a6e647 Merge: 30c266c 2927763 Author: Christoph Jentzsch Date: Tue Nov 11 08:34:36 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 30c266caff8c253438e542a81501a313c3c06eaf Author: Christoph Jentzsch Date: Tue Nov 11 08:33:59 2014 +0100 jump to position outside code stops execution commit 2927763d68df91c16a4a463a3fbb91a2e67e22e9 Author: ethers Date: Mon Nov 10 14:10:22 2014 -0800 RandomTests were removed commit a0fa91b2b82c2a4b97e08d7e9b32abc1188d0ce0 Merge: 6092484 fcba866 Author: Christoph Jentzsch Date: Mon Nov 10 22:22:05 2014 +0100 Merge branch 'develop' of https://github.com/ethereum/tests into develop commit 60924843f07f394c8e95782ab52d56ef27d5e642 Author: Christoph Jentzsch Date: Mon Nov 10 22:21:37 2014 +0100 Unintended Exceptions work like OOG commit fcba86672193d6bd19ab2104432348eff3f353f2 Author: ethers Date: Thu Nov 6 14:19:59 2014 -0800 add StateTests commit a441074ba4b057e2918735f7427841b92aa3c16e Author: Christoph Jentzsch Date: Thu Nov 6 17:54:36 2014 +0100 Updated precompiled contracts test commit 0afa72c82be2f4996d1662dfbf9e019c5267c6b1 Author: Christoph Jentzsch Date: Thu Nov 6 15:27:45 2014 +0100 Added precompiledContracts tests commit 6be83dd5a185048cfdb8ec29659f14abaeab0c42 Author: Christoph Jentzsch Date: Thu Nov 6 13:31:34 2014 +0100 Update gas cost for PoC7 commit c18b8ab2d3462e813b731e525afc9ea414d8d136 Merge: 66c2e1f 9a93258 Author: Christoph Jentzsch Date: Thu Nov 6 09:19:53 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 66c2e1f642a7b37d9f3631e4573100b0cdc36cef Author: Christoph Jentzsch Date: Thu Nov 6 09:19:22 2014 +0100 Updated SIGNEXTEND tests commit 9a9325822e756dafce8d7418bd4fda63acf84d2d Author: ethers Date: Wed Nov 5 16:20:26 2014 -0800 part of 9b4e768 - Delete vmNamecoin.json commit e229374f467452bf82fd0cc86b18f224dabfadfa Merge: 189527e 9b4e768 Author: Christoph Jentzsch Date: Wed Nov 5 20:59:49 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 189527e563a6e7a39654a9544a2b0d873be7176f Author: Christoph Jentzsch Date: Wed Nov 5 20:59:20 2014 +0100 added dynamic jump out of code commit 9b4e7689951e50c7de3bd945784b92242ed8fd63 Author: Christoph Jentzsch Date: Wed Nov 5 20:41:54 2014 +0100 Delete vmNamecoin.json commit 4669b5694b9dc7bdf9e6f527323dff612b65634d Merge: a567fed aaba185 Author: Christoph Jentzsch Date: Wed Nov 5 15:00:12 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit a567fedaa7f8ff8904bd90447fc4b68685bf2af9 Author: Christoph Jentzsch Date: Wed Nov 5 14:59:08 2014 +0100 added state systemOperationsTest commit aaba185ceb0e4c37151134f3e1ded9714d6b7685 Merge: 79d7cbf fa782ae Author: ethers Date: Tue Nov 4 12:15:40 2014 -0800 Merge pull request #32 from ethers/indexjs updates needed per restructure commit fa782aed93934eb51347d08facea838bb4262b1b Author: ethers Date: Tue Nov 4 11:28:56 2014 -0800 updates needed per restructure commit 79d7cbfc4a9cf3d70ae01dea8ee76c770af33211 Merge: 9120274 1c1ba8d Author: Christoph Jentzsch Date: Tue Nov 4 13:32:11 2014 +0100 Merge remote-tracking branch 'origin/develop' into develop commit 9120274a46d696cda6d595b2ec5acc2947eb2b46 Author: Christoph Jentzsch Date: Tue Nov 4 13:31:27 2014 +0100 Update tests to latest protocol changes (PoC7) commit 1c1ba8d161817b391ea296391ad3ede3e71c0aa1 Merge: 014d370 3aebe53 Author: Christoph Jentzsch Date: Tue Nov 4 13:30:52 2014 +0100 Merge pull request #31 from CJentzsch/develop Restructered tests in folders in accordance to test suites commit 3aebe532e536eb6f6766ccac456c07023ab822e1 Author: Christoph Jentzsch Date: Mon Nov 3 13:58:21 2014 +0100 Updated vmNamecoin.json to new sstore prices commit 8a0be21839cf8bb7d3d80a2b61c8433b5d3a8bfd Author: Christoph Jentzsch Date: Mon Nov 3 13:53:00 2014 +0100 Added example state test commit 83643addbc3d50c6a79611a5d8700aad5fb1df16 Author: Christoph Jentzsch Date: Mon Nov 3 13:36:25 2014 +0100 removed systemoperationstests commit 3930ca3a9a377107d5792b3e7202f79c688f1a67 Author: Christoph Jentzsch Date: Mon Nov 3 13:22:15 2014 +0100 Restructered tests in folders in accordance to test suites commit 014d370b5d5d0a807cc31a2fc3a8c5313ccd7ea4 Author: Christoph Jentzsch Date: Wed Oct 29 21:23:56 2014 +0100 New SIGNEXTEND tets commit 155d449be206f5276f689770006ecbbb203dd6ad Author: Christoph Jentzsch Date: Wed Oct 29 20:59:05 2014 +0100 New tests for BNOT and SIGNEXTEND commit c9eae764b8921a5d6c929b8544cb9acdb920453c Author: Christoph Jentzsch Date: Tue Oct 28 12:58:27 2014 +0100 Update SSTORE gas cost and BNOT instead of NEG commit ad2a75ac58ddcb06316f68d0fdaa8e80828a990c Author: Christoph Jentzsch Date: Thu Oct 23 16:05:49 2014 +0200 Added new recursive bombs commit 834c52af6406b9af429104408ca7bcbc525efe5c Author: Christoph Jentzsch Date: Thu Oct 23 12:01:05 2014 +0200 Changing gas cost to zero at stackunderflow commit c73a8a89d23cbdaf80875667437d57c3ee32f08a Author: Jeffrey Wilcke Date: Wed Oct 22 13:04:45 2014 +0200 Reverted back to original value. commit b9a8c924227996ef281d44ccfcc72c7618027f91 Author: martin becze Date: Tue Oct 21 17:02:52 2014 -0400 fix spelling error commit b48ae74af441c00cdce487416be448b0df3d4323 Author: Christoph Jentzsch Date: Tue Oct 21 17:26:26 2014 +0200 Added failing random tests commit bee0a4100c69cabfa361e36831ec0f64187188f3 Merge: 5050d20 b315da6 Author: Christoph Jentzsch Date: Tue Oct 21 17:15:05 2014 +0200 Merge remote-tracking branch 'origin/master' into develop commit 5050d20b4d0321e3e4ea2f118781c7bb96a3d7b5 Merge: 7516685 ba35362 Author: Christoph Jentzsch Date: Mon Oct 20 20:18:20 2014 +0200 Merge pull request #26 from wanderer/develop Add a package.json for node.js commit ba35362876caa03b11c7ce777d959b99accbcfb0 Author: wanderer Date: Sun Oct 19 23:59:47 2014 -0400 turned tests into a node module commit 751668571e390e6bceb515d082222aa31b5e5b14 Author: ethers Date: Thu Oct 16 17:08:20 2014 -0700 json was invalid and missing quotes commit 0e687cee479acfd82861e13d2022ad430fc78d78 Author: Jeffrey Wilcke Date: Thu Oct 16 17:13:24 2014 +0200 Update vmEnvironmentalInfoTest.json commit 78a78e2e6cffb9357f2281070d83bf869ab8b2f4 Author: Christoph Jentzsch Date: Wed Oct 15 14:19:11 2014 +0200 updated genesis_hash commit b315da618b55b581ba8e87f83b2ab5175841392e Merge: 7a7e198 0a76a3a Author: Christoph Jentzsch Date: Tue Oct 14 10:33:26 2014 +0200 Merge pull request #23 from ethers/fix22 numbers should be strings #22 commit 0a76a3a312951e852509e2b378b2b5b3f87135b0 Author: ethers Date: Mon Oct 13 14:45:30 2014 -0700 numbers should be strings #22 commit 1f67385f130422588f92341fe82c2435b160fe84 Author: Christoph Jentzsch Date: Sat Oct 11 13:18:00 2014 +0200 Added some MUL tests commit 7a7e198395f776d0a95d252ddc3b30492b9d3cff Author: Christoph Jentzsch Date: Sat Oct 11 13:11:59 2014 +0200 Added some MUL tests commit 46eb6283ae6c147f7efa910dadc18a504b6725ed Author: Christoph Jentzsch Date: Sat Oct 11 12:18:13 2014 +0200 tested new opcodes (JUMPDEST,CALLCODE) and created test for CALL/CREATE depth commit 8d38d62d1053ed7552211105e26b2e248a3db747 Author: Nick Savers Date: Fri Oct 10 18:09:41 2014 +0200 INVALID stops the operation and doesn't cost gas commit ed6eba7c8ebc0cbb65ccd45b047823f9acc1471b Author: Christoph Jentzsch Date: Wed Oct 8 19:08:48 2014 +0200 Update + ABA recursive bomb which needs maximum recursion limit of 1024 commit 2d72050db1c67d9d6912ce6ade80dbe5685749ff Author: Christoph Jentzsch Date: Wed Oct 8 14:37:18 2014 +0200 Applied recent protocol changes (PoC7) to existin tests commit dfe66cab3fb533003ddaec7250d8fffbf3fbad65 Merge: 4513623 1a67a96 Author: Christoph Jentzsch Date: Wed Oct 8 11:05:51 2014 +0200 Merge remote-tracking branch 'origin/develop' Conflicts: genesishashestest.json commit 1a67a96cff2fba02e57a82d65007cec99dcc313c Merge: a4f5f45 ffd6bc9 Author: vbuterin Date: Tue Oct 7 15:10:23 2014 +0100 Merge pull request #18 from CJentzsch/develop CallToNameRegistratorOutOfGas balance correction commit ffd6bc97adfbc83b6e0c50cdf072fd58f94ace69 Merge: a4f5f45 9779d67 Author: Christoph Jentzsch Date: Tue Oct 7 15:47:34 2014 +0200 Merge remote-tracking branch 'origin/develop' into develop commit 9779d67b8cdf4e99818a5eeadbc3aebd7527b1a9 Author: Christoph Jentzsch Date: Tue Oct 7 15:45:53 2014 +0200 CallToNameRegistratorOutOfGas balance correction Even if execution fails, the value gets transferred. commit a4f5f45228b6f3ebf8ea77c47515149a3df2bc24 Merge: 49a9f47 b6d7cba Author: vbuterin Date: Tue Oct 7 14:13:12 2014 +0100 Merge pull request #17 from CJentzsch/develop Added A calls B calls A contracts commit b6d7cba49914362297c0fcac48d868ffe3bdf06a Merge: 865cb40 49a9f47 Author: Christoph Jentzsch Date: Tue Oct 7 15:02:51 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 865cb4083d33de2a9115ee39c73aea56b0c34fe8 Author: Christoph Jentzsch Date: Tue Oct 7 15:02:36 2014 +0200 Added A calls B calls A contracts commit 49a9f47aec2dbd6e321298947929b3d0b5abc280 Merge: 3b0ec43 94a493b Author: Jeffrey Wilcke Date: Tue Oct 7 10:56:17 2014 +0200 Merge pull request #16 from CJentzsch/develop corrected amount of used gas for CallToNameRegistratorOutOfGas commit 94a493b0d94163e3de96e1c4bb389ef745756f30 Merge: 72853c4 3b0ec43 Author: Christoph Jentzsch Date: Tue Oct 7 10:51:32 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 72853c4382fa1b51e384223da34427d3579fe48a Author: Christoph Jentzsch Date: Tue Oct 7 10:51:07 2014 +0200 corrected amount of used gas for CallToNameRegistratorOutOfGas commit 3b0ec436e4c6808f98f1bc5bb5c66b4d2be4b4be Merge: aec3252 222068b Author: vbuterin Date: Tue Oct 7 05:52:43 2014 +0100 Merge pull request #15 from CJentzsch/develop corrected tests and different style for storage commit 222068b9bac6c386e499cb6b0fc2af562fcd309e Merge: c169653 aec3252 Author: Christoph Jentzsch Date: Mon Oct 6 21:17:28 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit c1696531a646309b2b286abb7552eb05f1278cd1 Author: Christoph Jentzsch Date: Mon Oct 6 21:17:09 2014 +0200 corrected tests and different style for storage commit aec3252b8e9f6d37b5cf3dbe0c1678e08929d291 Merge: 25f9fd5 e17a909 Author: vbuterin Date: Mon Oct 6 09:39:46 2014 +0100 Merge pull request #14 from CJentzsch/develop corrected gas limit in vmSystemOperationsTest commit e17a909f70af18fbfc0216c061a663e8778e7d5c Merge: 33fcab5 25f9fd5 Author: Christoph Jentzsch Date: Mon Oct 6 10:31:51 2014 +0200 Merge remote-tracking branch 'upstream/develop' into develop commit 33fcab57273731f449e9504d15c5d22cbe773e2a Author: Christoph Jentzsch Date: Mon Oct 6 10:30:04 2014 +0200 Bug fix, corrected gasLimit in vmSystemOperationsTest commit 25f9fd542a4ab27a5a66668a72b84d4bf7c292e6 Author: Vitalik Buterin Date: Sat Oct 4 15:47:00 2014 -0400 one more vm test commit 2d561a5373faf392e51f8c579c936549db2966d3 Author: Vitalik Buterin Date: Sat Oct 4 15:15:37 2014 -0400 separated out vmtests commit b0c48fa8d69ae02e01931a5675fc58ff9e84aba3 Merge: cb8261a 6cae166 Author: vbuterin Date: Sat Oct 4 17:18:02 2014 +0100 Merge pull request #13 from CJentzsch/develop Added comprehensive EVM test suite. All commands are tested. commit 6cae166f6f1e3f4eaaef6a9036c597b6064b263a Author: Christoph Jentzsch Date: Wed Oct 1 15:34:23 2014 +0200 Delete tmp.json commit 4ff906fbc271ee3aee3eb5db135e591eb187793a Author: Christoph Jentzsch Date: Wed Oct 1 14:06:32 2014 +0200 corrected CALLSTATELESS tests commit 5b3fee6806a69545e572725add73c297e9473eee Author: Christoph Jentzsch Date: Mon Sep 29 13:08:44 2014 +0200 Completed vm tests. Added ADDMOD, MULMOD, POST, CALLSTATELESS commit 9cdd2180833d98cf967929e07cab6638c2e933d0 Author: Christoph Jentzsch Date: Sat Sep 27 21:48:09 2014 +0200 Added IOandFlowOperation-, PushDupSwap- and SystemOperations- tests. Removed empty storage from adresses. commit 28ed968b46590bd8f3e5bb25606e8f83e0ee9b9e Author: Christoph Jentzsch Date: Tue Sep 23 15:49:22 2014 +0200 Added blockInfoTest commit ffbd5a35b597d2908fa0fa37d9b2aeaf30aee155 Author: Christoph Jentzsch Date: Tue Sep 23 15:37:52 2014 +0200 Added environmentalInfo- and sha3- test commit 54c14f1ff3f7ec66d755181be32a13e0404110d9 Author: Christoph Jentzsch Date: Mon Sep 22 13:06:57 2014 +0200 Added bitwise logic operation test commit d0af113aab3991fecbde29933f4a77884fafdf60 Author: Christoph Jentzsch Date: Sat Sep 20 01:42:51 2014 +0200 Added vm arithmetic test commit cb8261a78b56197e421bce5ac2afb7147f5acb45 Author: Jeffrey Wilcke Date: Fri Sep 19 13:15:44 2014 +0200 Update genesishashestest.json commit 4513623da1110e74a236abf0357ad00ff7a38126 Author: Maran Date: Tue Jul 22 12:24:46 2014 +0200 Update keyaddrtest to be valid JSON commit e8cb5c221d4763c8c26ac73f99609b64a595f4b3 Author: Vitalik Buterin Date: Mon Jul 21 23:30:33 2014 -0400 Added next/prev trie test commit 98823c04b30ef0be478c69a11edc3f9f6dff567e Author: Vitalik Buterin Date: Mon Jul 14 02:51:31 2014 -0400 Replaced with deterministic test commit 357eb21e4d5d9d6713ba7c63a76bd597a57d6a0e Author: Vitalik Buterin Date: Sun Jul 13 16:12:56 2014 -0400 Added my own random and namecoin tests (pyethereum) commit 00cd0cce8f0fc0ca8aa2c8ca424954d4932672f2 Author: Gav Wood Date: Sat Jul 12 21:20:04 2014 +0200 Output hex strings. commit ddfa3af45da9d5d81da38745ae23ee93ce390c2b Author: Gav Wood Date: Thu Jul 10 11:28:35 2014 +0100 Everything a string. commit d659f469a9ddcdd144a332da64b826908b0f7872 Author: Gav Wood Date: Thu Jul 10 10:16:25 2014 +0100 Code fixes. commit 5e83ea82283f042df384d7ff20183ba51760d893 Author: Gav Wood Date: Sun Jul 6 16:17:12 2014 +0200 Prettier VM tests. commit a09aae0efe9a1cb94be3e0386532c532262956ec Author: Gav Wood Date: Sun Jul 6 15:46:01 2014 +0200 Fix VM tests. commit ec9a044a17779f0b3814bffa8c058b4091d6d13d Merge: 4bb6461 5e0123f Author: Jeffrey Wilcke Date: Fri Jul 4 15:56:52 2014 +0200 Merge pull request #10 from romanman/patch-1 Update vmtests.json commit 5e0123fbe1573dcf8157995f3ef2f7ce625235a4 Author: romanman Date: Fri Jul 4 10:23:04 2014 +0100 Update vmtests.json commit 2b6da2f5f21b60ebca44a5866888b00f736f92b2 Author: romanman Date: Thu Jul 3 17:45:04 2014 +0100 Update vmtests.json arith testcase updated commit 4bb646117d0034fb459c07e6955b1c9cca802fa9 Merge: bba3898 a33b309 Author: Gav Wood Date: Wed Jul 2 19:43:22 2014 +0200 Merge branch 'develop' of github.com:/ethereum/tests into develop commit bba38980bdfa6ba6fddf0419479ad2405a3cb079 Author: Gav Wood Date: Wed Jul 2 19:43:06 2014 +0200 New tests. commit a33b309d99b36c4c57083d5e77422c3f2bba4bbe Author: Vitalik Buterin Date: Wed Jul 2 10:14:05 2014 -0400 Testing submodules commit 50318217ca875d23147eddfa7cc0326242db90bf Author: Vitalik Buterin Date: Wed Jul 2 10:10:46 2014 -0400 Testing submodules commit 57fa655522fc9696adcc7a6a25b64afd569b0758 Author: Vitalik Buterin Date: Wed Jul 2 10:09:08 2014 -0400 Testing submodules commit ea0eb0a8c82521322bd0359d1c42fc013c433d2e Author: Gav Wood Date: Tue Jul 1 15:19:34 2014 +0200 Latest genesis block. commit 25bb76b69c90ebd44a271d7c180a4a4b86845018 Author: Jeffrey Wilcke Date: Mon Jun 30 13:25:04 2014 +0200 Reset commit 74c6d8424e7d91ccd592c179794bc74e63c0d8c0 Author: Jeffrey Wilcke Date: Mon Jun 30 12:10:06 2014 +0200 Updated wrong test commit 9ea3a60291f2ca68a54198d53e4c40fffb09f6b3 Author: Jeffrey Wilcke Date: Sat Jun 28 18:48:28 2014 +0200 Fixed roots commit 5fc3ac0e925cdfe95632024f574fb945558491b8 Author: Gav Wood Date: Sat Jun 28 18:40:06 2014 +0200 Simple hex test. commit edd3a00c2a8d78867d8bb1557697455729a03027 Author: Gav Wood Date: Sat Jun 28 18:22:18 2014 +0200 Additional test for jeff. Now use the 0x... notation. commit 5021e0dd83bdb8b23ca3dcc72293c6737e8165a8 Author: Gav Wood Date: Fri Jun 27 21:35:26 2014 +0200 VM test framework updated. commit c818d132022c228c5b04ab82871f5971049b0c6d Author: Gav Wood Date: Fri Jun 27 18:18:24 2014 +0200 Removed arrays from Trie tests JSON as per conformance guide and changed vocabulary to match other tests. VM test updates. commit 714770ffb3bb037e2daeaa37a6f4f4066387abe3 Author: Gav Wood Date: Wed Jun 11 11:32:42 2014 +0100 Added Gav's new address. commit 9345bc13d40e6d288c37b650ace1db0c41a89d84 Merge: a2257f3 78576dd Author: Gav Wood Date: Fri May 30 17:50:38 2014 +0200 Merge branch 'master' of github.com:ethereum/tests into develop commit a2257f3471dd4b472bc156be4575ea0f26a8a046 Author: Gav Wood Date: Fri May 30 17:50:18 2014 +0200 VM tests. commit 78576dd3d3d4bf46af19d703affdd42f221e49c9 Author: Heiko Heiko Date: Fri May 30 17:19:09 2014 +0200 changes based on new account structure nonce, balance, storage, code commit 125839e84833ec25e0fdd4fbd545772ba706fe6b Merge: 42e14ec 356a329 Author: Jeffrey Wilcke Date: Thu May 22 09:58:45 2014 +0200 Merge pull request #5 from bkirwi/master Fix invalid JSON (removed trailing comma) and add test names commit 356a3296bc7eeac8b1b65aa843b5856cd786c4cf Author: Ben Kirwin Date: Thu May 22 00:20:48 2014 -0400 Add some arbitrary test names This should now conform to the format specified in the README. commit 42e14ec54fa57c2373625d21e5b47f597c748bf5 Author: Chen Houwu Date: Wed May 21 23:27:40 2014 +0800 revert to correct data commit 4300197a748de29cc5c93fd77f13cae029dad49e Author: Chen Houwu Date: Wed May 21 22:42:23 2014 +0800 fix: wrong sha3 hash because of the wrong rlp hex commit a0d01b1a0b59555e38ea694ff864f2aa25a0d953 Author: Chen Houwu Date: Wed May 21 22:29:53 2014 +0800 fix: wrong rlp hex commit 6bc2fc74054a418e7cfca9cf9144237a5e4fa65f Merge: 66bc366 c31a93c Author: Jeffrey Wilcke Date: Wed May 21 14:11:37 2014 +0200 Merge pull request #4 from ethers/master fix file name that seems to have been a typo commit c31a93c27a9048df92fcf53a2201c6e3737a40fd Author: ethers Date: Tue May 20 15:42:39 2014 -0700 fix file name that seems to have been a typo commit 66bc3665c17e1eec309e5a40b2a9c74273fb639a Author: Heiko Heiko Date: Tue May 20 17:36:35 2014 +0200 fix: represent integers as strings commit ede5499da624d95db1cad63939be56f7bdaa6389 Author: Heiko Heiko Date: Tue May 20 17:21:09 2014 +0200 add: current initial alloc and genesis hashes commit 5131429abbe6d2636064e17b45c99827a904c345 Author: Ben Kirwin Date: Mon May 19 11:18:31 2014 -0400 Delete a comma This should now be parseable as JSON. commit f44a85933110dd3ef362090f512678e99ae80256 Author: Chen Houwu Date: Sun May 18 15:04:42 2014 +0800 add: case when value is long, ensure it's not get rlp encoded as node commit e1ae4ad4495dd13fba6346274971a8871cb32607 Author: Gav Wood Date: Mon May 12 14:40:47 2014 +0100 PoC-5 VM tests. commit 2b6c136dda0d55a0ebd228bff029d97411c9cec6 Author: Vitalik Buterin Date: Sun May 11 21:42:41 2014 -0400 Moved txt to json commit cbccbf977ca7bde15a661a4b453ea062e62ac856 Merge: edbb8d4 45a0974 Author: Vitalik Buterin Date: Thu May 8 21:54:48 2014 -0400 New commit commit edbb8d407ecfbcbb6504659cbd9bdabdb93369e3 Author: Vitalik Buterin Date: Tue May 6 16:53:43 2014 -0400 Removed unneeded test, added new tests commit 45a0974f6f32511119e40a27042fdd571fe47a16 Merge: 15dd8fd 5fd2a98 Author: Gav Wood Date: Sun Apr 27 12:53:47 2014 +0100 Merge pull request #3 from autolycus/develop Fixed formatting and added test cases commit 5fd2a98fcb4f6a648160204d1b20b0f980d55b9d Author: Carl Allendorph Date: Sat Apr 19 13:26:14 2014 -0700 Added some new test cases for the rlp encoding. commit 4ba150954ef8ac72416a35f06fdad9c6d7ed461d Author: Carl Allendorph Date: Sat Apr 19 12:48:42 2014 -0700 Converted spaces to tabs to be compliant with the coding standards defined in cpp-ethereum commit 15dd8fd794a0dc305ef7696d0c2a68e032bc9759 Author: Gav Wood Date: Fri Feb 28 12:54:47 2014 +0000 RLP tests and Trie updates. commit 33f80fef211c2d51162c1856e50448be3d90c214 Author: Gav Wood Date: Fri Feb 28 11:39:35 2014 +0000 Hex encode tests done. commit e1f5e12abb38f8cedb4a589b1347fb01c3da902a Author: Gav Wood Date: Fri Feb 28 11:22:49 2014 +0000 Fix RLP tests. commit f87ce15ad201a6d97e2654e5dc5a3181873d1719 Author: Gav Wood Date: Thu Feb 27 13:28:11 2014 +0000 Fix empty string. commit c006ed4ffd7d00124dbcb44d4e7ca05d6d9ddc12 Author: Gav Wood Date: Mon Feb 24 10:24:39 2014 +0000 Tests fix. commit 510ff563639e71224306d9af0e50a28a9d624b8f Author: Gav Wood Date: Fri Feb 21 18:54:08 2014 +0000 Updated the tests. commit a0ec84383218ea80b4c0b99e09710fae182a2379 Author: Gav Wood Date: Fri Feb 21 18:49:24 2014 +0000 Moved over to new format, but RLP tests still need updating. commit 660cd26f31b3979149950c1fdea995b85a774c1c Author: Gav Wood Date: Fri Feb 21 18:35:51 2014 +0000 More docs. commit 6ad14c1a157e707fd15c87816e8ad872f69790db Author: Gav Wood Date: Fri Feb 21 18:33:39 2014 +0000 Added VM test suite. Added TODO. Renamed old files. commit f91ad7b3857ec9157e7df7f315d942afb7594da0 Author: Vitalik Buterin Date: Wed Jan 8 11:26:58 2014 -0500 update trie algorithm commit 6da295446203889ac5a4a365b397bb45766c9ad8 Merge: cc42246 131c610 Author: Vitalik Buterin Date: Wed Jan 8 08:15:38 2014 -0500 merge commit cc4224675f1f70242f91ee7d2d1295bed6f0dc01 Author: Vitalik Buterin Date: Tue Jan 7 14:35:26 2014 -0500 Updated trie test commit 131c610da66203f708391485aa42fc7a81f01ef7 Merge: 121632b 7613302 Author: vbuterin Date: Wed Jan 1 06:40:54 2014 -0800 Merge pull request #1 from obscuren/master Update trietest.txt commit 7613302b491b3f6406b1ea3c8292adf6d41860d0 Author: obscuren Date: Wed Jan 1 15:25:21 2014 +0100 Update trietest.txt New proposed explanatory format commit 121632bedd1c84a0af847b923aa4b803556722c0 Author: Vitalik Buterin Date: Wed Jan 1 08:26:18 2014 -0500 Added obscure's tests commit ef6c5506c3fcdecf779184ad81d92db9315c2488 Author: Vitalik Buterin Date: Tue Dec 31 19:04:48 2013 -0500 Fixed tests a bit commit 345e4bcfefb45a66a09b1761570405a03c67b9d2 Merge: 2c81698 e4bbea4 Author: Vitalik Buterin Date: Tue Dec 31 15:52:46 2013 -0500 Merge branch 'master' of github.com:ethereum/tests commit 2c81698f31e7e579335a2ab8706f96397a68f018 Author: Vitalik Buterin Date: Mon Dec 30 21:09:40 2013 -0500 Added first three tests commit e4bbea400f7df275faf47ea643256d68495b35aa Author: vbuterin Date: Mon Dec 30 18:09:03 2013 -0800 Initial commit --- vm/common.go | 2 +- vm/virtual_machine.go | 1 - vm/vm_debug.go | 19 +++++++------------ 3 files changed, 8 insertions(+), 14 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 5fd512687..592d44ccd 100644 --- a/vm/common.go +++ b/vm/common.go @@ -20,7 +20,7 @@ const ( var ( GasStep = big.NewInt(1) - GasSha = big.NewInt(20) + GasSha = big.NewInt(10) GasSLoad = big.NewInt(20) GasSStore = big.NewInt(100) GasSStoreRefund = big.NewInt(100) diff --git a/vm/virtual_machine.go b/vm/virtual_machine.go index 5738075fb..3b6f98ab2 100644 --- a/vm/virtual_machine.go +++ b/vm/virtual_machine.go @@ -5,7 +5,6 @@ import "math/big" type VirtualMachine interface { Env() Environment Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, data []byte) ([]byte, error) - Depth() int Printf(string, ...interface{}) VirtualMachine Endl() VirtualMachine } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 5b7258cc5..e9139ae19 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -25,8 +25,6 @@ type DebugVm struct { Fn string Recoverable bool - - depth int } func NewDebugVm(env Environment) *DebugVm { @@ -116,7 +114,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * return closure.Return(nil), nil } - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.depth, closure.Address(), closure.Gas, callData) + vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.env.Depth(), closure.Address(), closure.Gas, callData) for { prevStep = step @@ -867,14 +865,16 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) - var executeAddr []byte + var ( + ret []byte + err error + ) if op == CALLCODE { - executeAddr = closure.Address() + ret, err = self.env.CallCode(closure, addr.Bytes(), args, gas, price, value) } else { - executeAddr = addr.Bytes() + ret, err = self.env.Call(closure, addr.Bytes(), args, gas, price, value) } - ret, err := self.env.Call(closure, executeAddr, args, gas, price, value) if err != nil { stack.Push(ethutil.BigFalse) @@ -914,7 +914,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * default: vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op) - //panic(fmt.Sprintf("Invalid opcode %x", op)) closure.ReturnGas(big.NewInt(1), nil) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) @@ -963,7 +962,3 @@ func (self *DebugVm) Endl() VirtualMachine { func (self *DebugVm) Env() Environment { return self.env } - -func (self *DebugVm) Depth() int { - return self.depth -} -- cgit v1.2.3 From 05fd1dafe2c90d2acec4c2ea8619d8f656934a77 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 12 Dec 2014 13:26:01 +0100 Subject: additional log --- vm/common.go | 2 +- vm/vm_debug.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 592d44ccd..3d6d377ca 100644 --- a/vm/common.go +++ b/vm/common.go @@ -48,7 +48,7 @@ var ( S256 = ethutil.S256 ) -const MaxCallDepth = 1025 +const MaxCallDepth = 1024 func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(ethutil.Big0) == 0 { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index e9139ae19..8af1979b1 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -49,8 +49,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * closure := NewClosure(msg, caller, me, code, gas, price) if self.env.Depth() == MaxCallDepth { - closure.UseGas(gas) - + //closure.UseGas(gas) return closure.Return(nil), DepthError{} } @@ -885,7 +884,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * mem.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - self.Printf("resume %x", closure.Address()) + self.Printf("resume %x (%v)", closure.Address(), closure.Gas) // Debug hook if self.Dbg != nil { -- cgit v1.2.3 From 25cf0c440c5659c27474bc7b87aebcdcca1e4f48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 12 Dec 2014 15:25:21 +0100 Subject: Accidentally changed max depth during testing & committed --- vm/common.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 3d6d377ca..592d44ccd 100644 --- a/vm/common.go +++ b/vm/common.go @@ -48,7 +48,7 @@ var ( S256 = ethutil.S256 ) -const MaxCallDepth = 1024 +const MaxCallDepth = 1025 func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(ethutil.Big0) == 0 { -- cgit v1.2.3 From 8577e4171ae594c722bad4e034e2b87f15986be3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 12 Dec 2014 22:24:27 +0100 Subject: Panic for "Vm" --- vm/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vm') diff --git a/vm/vm.go b/vm/vm.go index 968ca10fa..22172cb3a 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -21,7 +21,7 @@ func New(env Environment, typ Type) VirtualMachine { } func (self *Vm) Run(me, caller ClosureRef, code []byte, value, gas, price *big.Int, data []byte) (ret []byte, err error) { - return nil, nil + panic("not implemented") } func (self *Vm) Env() Environment { -- cgit v1.2.3 From 4dbdcaecb117d7e1fcaf0869f5d4602312552991 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 17 Dec 2014 23:58:52 +0100 Subject: Moved pre-compiled, moved depth check * Depth check has been moved to the execution * Pre compiled execution has been moved to the VM * PrecompiledAddress has been renamed to PrecompiledAccount --- vm/address.go | 12 ++++++------ vm/common.go | 2 +- vm/vm_debug.go | 24 +++++++++++++++++++++--- 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'vm') diff --git a/vm/address.go b/vm/address.go index be8921a3b..611979c94 100644 --- a/vm/address.go +++ b/vm/address.go @@ -11,25 +11,25 @@ type Address interface { Call(in []byte) []byte } -type PrecompiledAddress struct { +type PrecompiledAccount struct { Gas func(l int) *big.Int fn func(in []byte) []byte } -func (self PrecompiledAddress) Call(in []byte) []byte { +func (self PrecompiledAccount) Call(in []byte) []byte { return self.fn(in) } -var Precompiled = map[uint64]*PrecompiledAddress{ - 1: &PrecompiledAddress{func(l int) *big.Int { +var Precompiled = map[string]*PrecompiledAccount{ + string(ethutil.LeftPadBytes([]byte{1}, 20)): &PrecompiledAccount{func(l int) *big.Int { return GasEcrecover }, ecrecoverFunc}, - 2: &PrecompiledAddress{func(l int) *big.Int { + string(ethutil.LeftPadBytes([]byte{2}, 20)): &PrecompiledAccount{func(l int) *big.Int { n := big.NewInt(int64(l+31)/32 + 1) n.Mul(n, GasSha256) return n }, sha256Func}, - 3: &PrecompiledAddress{func(l int) *big.Int { + string(ethutil.LeftPadBytes([]byte{3}, 20)): &PrecompiledAccount{func(l int) *big.Int { n := big.NewInt(int64(l+31)/32 + 1) n.Mul(n, GasRipemd) return n diff --git a/vm/common.go b/vm/common.go index 592d44ccd..3d6d377ca 100644 --- a/vm/common.go +++ b/vm/common.go @@ -48,7 +48,7 @@ var ( S256 = ethutil.S256 ) -const MaxCallDepth = 1025 +const MaxCallDepth = 1024 func calcMemSize(off, l *big.Int) *big.Int { if l.Cmp(ethutil.Big0) == 0 { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 8af1979b1..9da832a79 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -48,9 +48,8 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * }) closure := NewClosure(msg, caller, me, code, gas, price) - if self.env.Depth() == MaxCallDepth { - //closure.UseGas(gas) - return closure.Return(nil), DepthError{} + if p := Precompiled[string(me.Address())]; p != nil { + return self.RunPrecompiled(p, callData, closure) } if self.Recoverable { @@ -941,6 +940,25 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * } } +func (self *DebugVm) RunPrecompiled(p *PrecompiledAccount, callData []byte, closure *Closure) (ret []byte, err error) { + gas := p.Gas(len(callData)) + if closure.UseGas(gas) { + ret = p.Call(callData) + self.Printf("NATIVE_FUNC => %x", ret) + self.Endl() + + return closure.Return(ret), nil + } else { + self.Endl() + + tmp := new(big.Int).Set(closure.Gas) + + closure.UseGas(closure.Gas) + + return closure.Return(nil), OOG(gas, tmp) + } +} + func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine { if self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) -- cgit v1.2.3 From 198cc69357a0f25ae486a041786e1239c6f5ab0f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Dec 2014 21:58:26 +0100 Subject: Gas corrections and vm fixes --- vm/common.go | 2 +- vm/vm_debug.go | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'vm') diff --git a/vm/common.go b/vm/common.go index 3d6d377ca..529bbdeb1 100644 --- a/vm/common.go +++ b/vm/common.go @@ -37,7 +37,7 @@ var ( GasLog = big.NewInt(32) GasSha256 = big.NewInt(50) GasRipemd = big.NewInt(50) - GasEcrecover = big.NewInt(100) + GasEcrecover = big.NewInt(500) Pow256 = ethutil.BigPow(2, 256) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 9da832a79..d78aff4ce 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "math" "math/big" "github.com/ethereum/go-ethereum/crypto" @@ -112,7 +113,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * return closure.Return(nil), nil } - vmlogger.Debugf("(%d) %x gas: %v (d) %x\n", self.env.Depth(), closure.Address(), closure.Gas, callData) + vmlogger.Debugf("(%d) (%x) %x gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], closure.Address(), closure.Gas, callData) for { prevStep = step @@ -185,11 +186,11 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * // 0 => non 0 mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { - statedb.Refund(closure.caller.Address(), GasSStoreRefund, closure.Price) + statedb.Refund(caller.Address(), GasSStoreRefund) mult = ethutil.Big0 } else { - // non 0 => non 0 + // non 0 => non 0 (or 0 => 0) mult = ethutil.Big1 } gas.Set(new(big.Int).Mul(mult, GasSStore)) @@ -660,7 +661,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * cOff = 0 l = 0 } else if cOff+l > size { - l = 0 + l = uint64(math.Min(float64(cOff+l), float64(size))) } codeCopy := code[cOff : cOff+l] @@ -776,10 +777,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * val, loc := stack.Popn() statedb.SetState(closure.Address(), loc.Bytes(), val) - // Debug sessions are allowed to run without message - if closure.message != nil { - closure.message.AddStorageChange(loc.Bytes()) - } + closure.message.AddStorageChange(loc.Bytes()) self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes()) case JUMP: @@ -898,10 +896,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * return closure.Return(ret), nil case SUICIDE: - receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes()) + balance := statedb.GetBalance(closure.Address()) + + self.Printf(" => (%x) %v", receiver.Address()[:4], balance) - receiver.AddAmount(statedb.GetBalance(closure.Address())) + receiver.AddAmount(balance) statedb.Delete(closure.Address()) fallthrough -- cgit v1.2.3 From 1e985f986569a68601b052c8949fc6f360e139d9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Dec 2014 23:59:40 +0100 Subject: Fixed casting error * big(bytes) == 0 when len(bytes) > 0 --- vm/vm_debug.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'vm') diff --git a/vm/vm_debug.go b/vm/vm_debug.go index d78aff4ce..708aada5b 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -181,11 +181,12 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * var mult *big.Int y, x := stack.Peekn() - val := closure.GetStorage(x) - if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { + //val := closure.GetStorage(x) + val := statedb.GetState(closure.Address(), x.Bytes()) + if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 mult = ethutil.Big3 - } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { + } else if len(val) > 0 && len(y.Bytes()) == 0 { statedb.Refund(caller.Address(), GasSStoreRefund) mult = ethutil.Big0 -- cgit v1.2.3 From 59ef6e36931c980ba15babfb3680514635faebf6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 19 Dec 2014 00:18:52 +0100 Subject: Cleaned up objects --- vm/closure.go | 35 +++-------------------------------- vm/vm_debug.go | 6 ++---- 2 files changed, 5 insertions(+), 36 deletions(-) (limited to 'vm') diff --git a/vm/closure.go b/vm/closure.go index bd5268f96..97b31ada0 100644 --- a/vm/closure.go +++ b/vm/closure.go @@ -3,7 +3,6 @@ package vm import ( "math/big" - "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" ) @@ -11,8 +10,6 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int) Address() []byte SetCode([]byte) - GetStorage(*big.Int) *ethutil.Value - SetStorage(*big.Int, *ethutil.Value) } type Closure struct { @@ -41,10 +38,6 @@ func NewClosure(msg *state.Message, caller ClosureRef, object ClosureRef, code [ return c } -func (c *Closure) GetValue(x uint64) *ethutil.Value { - return c.GetRangeValue(x, 1) -} - func (c *Closure) GetOp(x uint64) OpCode { return OpCode(c.GetByte(x)) } @@ -65,30 +58,12 @@ func (c *Closure) GetBytes(x, y int) []byte { return c.Code[x : x+y] } -func (c *Closure) GetRangeValue(x, y uint64) *ethutil.Value { +func (c *Closure) GetRangeValue(x, y uint64) []byte { if x >= uint64(len(c.Code)) || y >= uint64(len(c.Code)) { - return ethutil.NewValue(0) - } - - partial := c.Code[x : x+y] - - return ethutil.NewValue(partial) -} - -/* - * State storage functions - */ -func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { - c.object.SetStorage(x, val) -} - -func (c *Closure) GetStorage(x *big.Int) *ethutil.Value { - m := c.object.GetStorage(x) - if m == nil { - return ethutil.EmptyValue() + return nil } - return m + return c.Code[x : x+y] } func (c *Closure) Return(ret []byte) []byte { @@ -123,10 +98,6 @@ func (c *Closure) ReturnGas(gas, price *big.Int) { /* * Set / Get */ -func (c *Closure) Caller() ClosureRef { - return c.caller -} - func (c *Closure) Address() []byte { return c.object.Address() } diff --git a/vm/vm_debug.go b/vm/vm_debug.go index 708aada5b..fd16a3895 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -181,7 +181,6 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * var mult *big.Int y, x := stack.Peekn() - //val := closure.GetStorage(x) val := statedb.GetState(closure.Address(), x.Bytes()) if len(val) == 0 && len(y.Bytes()) > 0 { // 0 => non 0 @@ -714,8 +713,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * //a := big.NewInt(int64(op) - int64(PUSH1) + 1) a := uint64(op - PUSH1 + 1) //pc.Add(pc, ethutil.Big1) - data := closure.GetRangeValue(pc+1, a) - val := ethutil.BigD(data.Bytes()) + val := ethutil.BigD(closure.GetRangeValue(pc+1, a)) // Push value to stack stack.Push(val) pc += a @@ -723,7 +721,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * step += int(op) - int(PUSH1) + 1 - self.Printf(" => 0x%x", data.Bytes()) + self.Printf(" => 0x%x", val.Bytes()) case POP: stack.Pop() case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: -- cgit v1.2.3 From 1508a23a6fe3cc50f718bfd6c62caae056534c09 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 20 Dec 2014 02:21:13 +0100 Subject: Minor updates on gas and removed/refactored old code. --- vm/environment.go | 5 +++++ vm/vm_debug.go | 41 ++++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 19 deletions(-) (limited to 'vm') diff --git a/vm/environment.go b/vm/environment.go index d77fb1419..969bc5e43 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -2,6 +2,7 @@ package vm import ( "errors" + "fmt" "math/big" "github.com/ethereum/go-ethereum/ethutil" @@ -74,3 +75,7 @@ func (self *Log) Data() []byte { func (self *Log) RlpData() interface{} { return []interface{}{self.address, ethutil.ByteSliceToInterface(self.topics), self.data} } + +func (self *Log) String() string { + return fmt.Sprintf("[A=%x T=%x D=%x]", self.address, self.topics, self.data) +} diff --git a/vm/vm_debug.go b/vm/vm_debug.go index fd16a3895..aa3291e66 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -108,13 +108,13 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * } ) + vmlogger.Debugf("(%d) (%x) %x (code=%d) gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], closure.Address(), len(code), closure.Gas, callData) + // Don't bother with the execution if there's no code. if len(code) == 0 { return closure.Return(nil), nil } - vmlogger.Debugf("(%d) (%x) %x gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], closure.Address(), closure.Gas, callData) - for { prevStep = step // The base for all big integer arithmetic @@ -134,6 +134,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * addStepGasUsage(GasStep) var newMemSize *big.Int = ethutil.Big0 + var additionalGas *big.Int = new(big.Int) // Stack Check, memory resize & gas phase switch op { // Stack checks only @@ -213,22 +214,24 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) case SHA3: require(2) - gas.Set(GasSha) - newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2]) + additionalGas.Set(stack.data[stack.Len()-2]) case CALLDATACOPY: require(2) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + additionalGas.Set(stack.data[stack.Len()-3]) case CODECOPY: require(3) newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3]) + additionalGas.Set(stack.data[stack.Len()-3]) case EXTCODECOPY: require(4) newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4]) + additionalGas.Set(stack.data[stack.Len()-4]) case CALL, CALLCODE: require(7) gas.Set(GasCall) @@ -245,20 +248,23 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3]) } + switch op { + case CALLDATACOPY, CODECOPY, EXTCODECOPY: + additionalGas.Add(additionalGas, u256(31)) + additionalGas.Div(additionalGas, u256(32)) + addStepGasUsage(additionalGas) + case SHA3: + additionalGas.Add(additionalGas, u256(31)) + additionalGas.Div(additionalGas, u256(32)) + additionalGas.Mul(additionalGas, GasSha3Byte) + addStepGasUsage(additionalGas) + } + if newMemSize.Cmp(ethutil.Big0) > 0 { newMemSize.Add(newMemSize, u256(31)) newMemSize.Div(newMemSize, u256(32)) newMemSize.Mul(newMemSize, u256(32)) - switch op { - case CALLDATACOPY, CODECOPY, EXTCODECOPY: - addStepGasUsage(new(big.Int).Div(newMemSize, u256(32))) - case SHA3: - g := new(big.Int).Div(newMemSize, u256(32)) - g.Mul(g, GasSha3Byte) - addStepGasUsage(g) - } - if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 { memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len()))) memGasUsage.Mul(GasMemory, memGasUsage) @@ -643,9 +649,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * case CODECOPY, EXTCODECOPY: var code []byte if op == EXTCODECOPY { - addr := stack.Pop().Bytes() - - code = statedb.GetCode(addr) + code = statedb.GetCode(stack.Pop().Bytes()) } else { code = closure.Code } @@ -663,12 +667,11 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * } else if cOff+l > size { l = uint64(math.Min(float64(cOff+l), float64(size))) } - codeCopy := code[cOff : cOff+l] mem.Set(mOff, l, codeCopy) - self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, code[cOff:cOff+l]) + self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy) case GASPRICE: stack.Push(closure.Price) @@ -891,7 +894,7 @@ func (self *DebugVm) Run(me, caller ClosureRef, code []byte, value, gas, price * size, offset := stack.Popn() ret := mem.Get(offset.Int64(), size.Int64()) - self.Printf(" => (%d) 0x%x", len(ret), ret).Endl() + self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl() return closure.Return(ret), nil case SUICIDE: -- cgit v1.2.3