From 2ea4c632d1673b762c1af11582364d9faa08c413 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 21 Mar 2014 14:47:55 +0100 Subject: [PATCH] Closure return, arguments fixed. Added proper tests --- ethchain/address.go | 10 +++++--- ethchain/closure.go | 24 ++++++++++++------ ethchain/stack.go | 52 +++++++++++++++++++-------------------- ethchain/state_manager.go | 2 +- ethchain/vm.go | 33 +++++++++++++++++++++---- ethchain/vm_test.go | 3 +-- ethutil/parsing.go | 28 ++++++++++----------- 7 files changed, 92 insertions(+), 60 deletions(-) diff --git a/ethchain/address.go b/ethchain/address.go index 9c6acbe087..0b3ef7c057 100644 --- a/ethchain/address.go +++ b/ethchain/address.go @@ -6,7 +6,7 @@ import ( ) type Account struct { - Address []byte + address []byte Amount *big.Int Nonce uint64 } @@ -16,7 +16,7 @@ func NewAccount(address []byte, amount *big.Int) *Account { } func NewAccountFromData(address, data []byte) *Account { - account := &Account{Address: address} + account := &Account{address: address} account.RlpDecode(data) return account @@ -30,11 +30,15 @@ func (a *Account) AddFunds(funds *big.Int) { a.Amount.Add(a.Amount, funds) } +func (a *Account) Address() []byte { + return a.address +} + // Implements Callee func (a *Account) ReturnGas(value *big.Int, state *State) { // Return the value back to the sender a.AddFunds(value) - state.UpdateAccount(a.Address, a) + state.UpdateAccount(a.address, a) } func (a *Account) RlpEncode() []byte { diff --git a/ethchain/closure.go b/ethchain/closure.go index 0eef866d0b..f8e692f61c 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -9,13 +9,13 @@ import ( type Callee interface { ReturnGas(*big.Int, *State) + Address() []byte } type ClosureBody interface { Callee ethutil.RlpEncodable GetMem(int64) *ethutil.Value - Address() []byte } // Basic inline closure object which implement the 'closure' interface @@ -24,8 +24,8 @@ type Closure struct { object ClosureBody State *State - gas *big.Int - val *big.Int + Gas *big.Int + Value *big.Int Args []byte } @@ -45,6 +45,10 @@ func (c *Closure) GetMem(x int64) *ethutil.Value { return m } +func (c *Closure) Address() []byte { + return c.object.Address() +} + func (c *Closure) Call(vm *Vm, args []byte) []byte { c.Args = args @@ -56,9 +60,9 @@ func (c *Closure) Return(ret []byte) []byte { // If no callee is present return it to // the origin (i.e. contract or tx) if c.callee != nil { - c.callee.ReturnGas(c.gas, c.State) + c.callee.ReturnGas(c.Gas, c.State) } else { - c.object.ReturnGas(c.gas, c.State) + c.object.ReturnGas(c.Gas, c.State) // TODO incase it's a POST contract we gotta serialise the contract again. // But it's not yet defined } @@ -69,9 +73,13 @@ func (c *Closure) Return(ret []byte) []byte { // Implement the Callee interface func (c *Closure) ReturnGas(gas *big.Int, state *State) { // Return the gas to the closure - c.gas.Add(c.gas, gas) + c.Gas.Add(c.Gas, gas) +} + +func (c *Closure) Object() ClosureBody { + return c.object } -func (c *Closure) GetGas() *big.Int { - return c.gas +func (c *Closure) Callee() Callee { + return c.callee } diff --git a/ethchain/stack.go b/ethchain/stack.go index c75d02ddac..b64b759fda 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -36,24 +36,22 @@ const ( oSHA3 = 0x20 // 0x30 range - closure state - oADDRESS = 0x30 - oBALANCE = 0x31 - oORIGIN = 0x32 - oCALLER = 0x33 - oCALLVALUE = 0x34 - oCALLDATA = 0x35 - oCALLDATASIZE = 0x36 - oRETURNDATASIZE = 0x37 - oTXGASPRICE = 0x38 + oADDRESS = 0x30 + oBALANCE = 0x31 + oORIGIN = 0x32 + oCALLER = 0x33 + oCALLVALUE = 0x34 + oCALLDATA = 0x35 + oCALLDATASIZE = 0x36 + oGASPRICE = 0x37 // 0x40 range - block operations oPREVHASH = 0x40 - oPREVNONCE = 0x41 - oCOINBASE = 0x42 - oTIMESTAMP = 0x43 - oNUMBER = 0x44 - oDIFFICULTY = 0x45 - oGASLIMIT = 0x46 + oCOINBASE = 0x41 + oTIMESTAMP = 0x42 + oNUMBER = 0x43 + oDIFFICULTY = 0x44 + oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution oPUSH = 0x50 @@ -108,19 +106,17 @@ var opCodeToString = map[OpCode]string{ oSHA3: "SHA3", // 0x30 range - closure state - oADDRESS: "ADDRESS", - oBALANCE: "BALANCE", - oORIGIN: "ORIGIN", - oCALLER: "CALLER", - oCALLVALUE: "CALLVALUE", - oCALLDATA: "CALLDATA", - oCALLDATASIZE: "CALLDATASIZE", - oRETURNDATASIZE: "RETURNDATASIZE", - oTXGASPRICE: "TXGASPRICE", + oADDRESS: "ADDRESS", + oBALANCE: "BALANCE", + oORIGIN: "ORIGIN", + oCALLER: "CALLER", + oCALLVALUE: "CALLVALUE", + oCALLDATA: "CALLDATA", + oCALLDATASIZE: "CALLDATASIZE", + oGASPRICE: "TXGASPRICE", // 0x40 range - block operations oPREVHASH: "PREVHASH", - oPREVNONCE: "PREVNONCE", oCOINBASE: "COINBASE", oTIMESTAMP: "TIMESTAMP", oNUMBER: "NUMBER", @@ -244,7 +240,11 @@ func (m *Memory) Get(offset, size int64) []byte { func (m *Memory) Print() { fmt.Println("### MEM ###") if len(m.store) > 0 { - fmt.Println(m.store) + addr := 0 + for i := 0; i+32 < len(m.store); i += 32 { + fmt.Printf("%03d %v\n", addr, m.store[i:i+32]) + addr++ + } } else { fmt.Println("-- empty --") } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 50c7773497..3b55077405 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -308,7 +308,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo caller := sm.procState.GetAccount(tx.Sender()) closure := NewClosure(caller, contract, sm.procState, tx.Gas, tx.Value) vm := NewVm(sm.procState, RuntimeVars{ - origin: caller.Address, + origin: caller.Address(), blockNumber: block.BlockInfo().Number, prevHash: block.PrevHash, coinbase: block.Coinbase, diff --git a/ethchain/vm.go b/ethchain/vm.go index 3d2ee4c860..8b5bb93c0c 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -40,7 +40,7 @@ var Pow256 = ethutil.BigPow(2, 256) func (vm *Vm) RunClosure(closure *Closure) []byte { // If the amount of gas supplied is less equal to 0 - if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { + if closure.Gas.Cmp(big.NewInt(0)) <= 0 { // TODO Do something } @@ -73,7 +73,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { fee := new(big.Int) fee.Add(fee, big.NewInt(1000)) - if closure.GetGas().Cmp(fee) < 0 { + if closure.Gas.Cmp(fee) < 0 { return closure.Return(nil) } @@ -192,25 +192,37 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { // 0x30 range case oADDRESS: + stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: + stack.Push(closure.Value) case oORIGIN: + stack.Push(ethutil.BigD(vm.vars.origin)) case oCALLER: + stack.Push(ethutil.BigD(closure.Callee().Address())) case oCALLVALUE: + // FIXME: Original value of the call, not the current value + stack.Push(closure.Value) case oCALLDATA: offset := stack.Pop() mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) case oCALLDATASIZE: - case oRETURNDATASIZE: - case oTXGASPRICE: + stack.Push(big.NewInt(int64(len(closure.Args)))) + case oGASPRICE: + // TODO // 0x40 range case oPREVHASH: - case oPREVNONCE: + stack.Push(ethutil.BigD(vm.vars.prevHash)) case oCOINBASE: + stack.Push(ethutil.BigD(vm.vars.coinbase)) case oTIMESTAMP: + stack.Push(big.NewInt(vm.vars.time)) case oNUMBER: + stack.Push(big.NewInt(int64(vm.vars.blockNumber))) case oDIFFICULTY: + stack.Push(vm.vars.diff) case oGASLIMIT: + // TODO // 0x50 range case oPUSH: // Push PC+1 on to the stack @@ -218,8 +230,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val := closure.GetMem(pc).BigInt() stack.Push(val) case oPOP: + stack.Pop() case oDUP: + stack.Push(stack.Peek()) case oSWAP: + x, y := stack.Popn() + stack.Push(y) + stack.Push(x) case oMLOAD: offset := stack.Pop() stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) @@ -228,7 +245,13 @@ func (vm *Vm) RunClosure(closure *Closure) []byte { val, mStart := stack.Popn() mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) case oMSTORE8: + val, mStart := stack.Popn() + base.And(val, new(big.Int).SetInt64(0xff)) + mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) case oSLOAD: + loc := stack.Pop() + val := closure.GetMem(loc.Int64()) + stack.Push(val.BigInt()) case oSSTORE: case oJUMP: case oJUMPI: diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index ce8c7a4de3..16cbf51b7d 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -126,7 +126,6 @@ func TestRun3(t *testing.T) { "PUSH", "64", "PUSH", "0", - "LOG", "RETURN", }) tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script) @@ -159,7 +158,7 @@ func TestRun3(t *testing.T) { callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) vm := NewVm(state, RuntimeVars{ - origin: account.Address, + origin: account.Address(), blockNumber: 1, prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), diff --git a/ethutil/parsing.go b/ethutil/parsing.go index b2e9d9fee7..f244026230 100644 --- a/ethutil/parsing.go +++ b/ethutil/parsing.go @@ -33,24 +33,22 @@ var OpCodes = map[string]byte{ "SHA3": 0x20, // 0x30 range - closure state - "ADDRESS": 0x30, - "BALANCE": 0x31, - "ORIGIN": 0x32, - "CALLER": 0x33, - "CALLVALUE": 0x34, - "CALLDATA": 0x35, - "CALLDATASIZE": 0x36, - "RETURNDATASIZE": 0x37, - "TXGASPRICE": 0x38, + "ADDRESS": 0x30, + "BALANCE": 0x31, + "ORIGIN": 0x32, + "CALLER": 0x33, + "CALLVALUE": 0x34, + "CALLDATA": 0x35, + "CALLDATASIZE": 0x36, + "GASPRICE": 0x38, // 0x40 range - block operations "PREVHASH": 0x40, - "PREVNONCE": 0x41, - "COINBASE": 0x42, - "TIMESTAMP": 0x43, - "NUMBER": 0x44, - "DIFFICULTY": 0x45, - "GASLIMIT": 0x46, + "COINBASE": 0x41, + "TIMESTAMP": 0x42, + "NUMBER": 0x43, + "DIFFICULTY": 0x44, + "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution "PUSH": 0x50,