diff --git a/ethchain/asm.go b/ethchain/asm.go index 3194549ba..492be0999 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -21,9 +21,10 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("%v", op)) switch op { - case oPUSH: // Push PC+1 on to the stack + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+32] + a := int64(op) - int64(oPUSH1) + 1 + data := script[pc.Int64() : pc.Int64()+a] val := ethutil.BigD(data) var b []byte @@ -35,21 +36,7 @@ func Disassemble(script []byte) (asm []string) { asm = append(asm, fmt.Sprintf("0x%x", b)) - pc.Add(pc, big.NewInt(31)) - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := script[pc.Int64() : pc.Int64()+20] - val := ethutil.BigD(data) - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() - } - - asm = append(asm, fmt.Sprintf("0x%x", b)) - - pc.Add(pc, big.NewInt(19)) + pc.Add(pc, big.NewInt(a-1)) } pc.Add(pc, ethutil.Big1) diff --git a/ethchain/closure.go b/ethchain/closure.go index 7e911ad99..59194e4e8 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -11,7 +11,7 @@ type ClosureRef interface { ReturnGas(*big.Int, *big.Int, *State) Address() []byte GetMem(*big.Int) *ethutil.Value - SetMem(*big.Int, *ethutil.Value) + SetStore(*big.Int, *ethutil.Value) N() *big.Int } @@ -24,20 +24,18 @@ type Closure struct { Gas *big.Int Price *big.Int - Value *big.Int Args []byte } // Create a new closure for the given data items -func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { +func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} // In most cases gas, price and value are pointers to transaction objects // and we don't want the transaction's values to change. c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) - c.Value = new(big.Int).Set(val) return c } @@ -66,8 +64,8 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value { return ethutil.NewValue(partial) } -func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { - c.object.SetMem(x, val) +func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) { + c.object.SetStorage(x, val) } func (c *Closure) Address() []byte { diff --git a/ethchain/state.go b/ethchain/state.go index 1b5655d4c..d02584d67 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -15,11 +15,13 @@ type State struct { trie *ethutil.Trie // Nested states states map[string]*State + + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State)} + return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} } // Resets the trie and all siblings @@ -114,46 +116,6 @@ func (s *State) Copy() *State { return NewState(s.trie.Copy()) } -type ObjType byte - -const ( - NilTy ObjType = iota - AccountTy - ContractTy - - UnknownTy -) - -/* -// Returns the object stored at key and the type stored at key -// Returns nil if nothing is stored -func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) { - // Fetch data from the trie - data := s.trie.Get(string(key)) - // Returns the nil type, indicating nothing could be retrieved. - // Anything using this function should check for this ret val - if data == "" { - return nil, NilTy - } - - var typ ObjType - val := ethutil.NewValueFromBytes([]byte(data)) - // Check the length of the retrieved value. - // Len 2 = Account - // Len 3 = Contract - // Other = invalid for now. If other types emerge, add them here - if val.Len() == 2 { - typ = AccountTy - } else if val.Len() == 3 { - typ = ContractTy - } else { - typ = UnknownTy - } - - return val, typ -} -*/ - // Updates any given state object func (s *State) UpdateStateObject(object *StateObject) { addr := object.Address() @@ -163,6 +125,7 @@ func (s *State) UpdateStateObject(object *StateObject) { } s.trie.Update(string(addr), string(object.RlpEncode())) + s.manifest.AddObjectChange(object) } func (s *State) Put(key, object []byte) { @@ -172,3 +135,40 @@ func (s *State) Put(key, object []byte) { func (s *State) Root() interface{} { return s.trie.Root } + +// Object manifest +// +// The object manifest is used to keep changes to the state so we can keep track of the changes +// that occurred during a state transitioning phase. +type Manifest struct { + // XXX These will be handy in the future. Not important for now. + objectAddresses map[string]bool + storageAddresses map[string]map[string]bool + + objectChanges map[string]*StateObject + storageChanges map[string]map[string]*big.Int +} + +func NewManifest() *Manifest { + m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} + m.Reset() + + return m +} + +func (m *Manifest) Reset() { + m.objectChanges = make(map[string]*StateObject) + m.storageChanges = make(map[string]map[string]*big.Int) +} + +func (m *Manifest) AddObjectChange(stateObject *StateObject) { + m.objectChanges[string(stateObject.Address())] = stateObject +} + +func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { + if m.storageChanges[string(stateObject.Address())] == nil { + m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) + } + + m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage +} diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 501ec102b..dd21a31b1 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -25,24 +25,16 @@ type EthManager interface { type StateManager struct { // Mutex for locking the block processor. Blocks can only be handled one at a time mutex sync.Mutex - // Canonical block chain bc *BlockChain - // States for addresses. You can watch any address - // at any given time - stateObjectCache *StateObjectCache - // Stack for processing contracts stack *Stack // non-persistent key/value memory storage mem map[string]*big.Int - + // Proof of work used for validating Pow PoW - + // The ethereum manager interface Ethereum EthManager - - SecondaryBlockProcessor BlockProcessor - // The managed states // Processor state. Anything processed will be applied to this // state @@ -50,21 +42,28 @@ type StateManager struct { // Comparative state it used for comparing and validating end // results compState *State - - manifest *Manifest + // Transiently state. The trans state isn't ever saved, validated and + // it could be used for setting account nonces without effecting + // the main states. + transState *State + // Manifest for keeping changes regarding state objects. See `notify` + // XXX Should we move the manifest to the State object. Benefit: + // * All states can keep their own local changes + //manifest *Manifest } func NewStateManager(ethereum EthManager) *StateManager { sm := &StateManager{ - stack: NewStack(), - mem: make(map[string]*big.Int), - Pow: &EasyPow{}, - Ethereum: ethereum, - stateObjectCache: NewStateObjectCache(), - bc: ethereum.BlockChain(), - manifest: NewManifest(), + stack: NewStack(), + mem: make(map[string]*big.Int), + Pow: &EasyPow{}, + Ethereum: ethereum, + bc: ethereum.BlockChain(), + //manifest: NewManifest(), } sm.procState = ethereum.BlockChain().CurrentBlock.State() + sm.transState = sm.procState.Copy() + return sm } @@ -72,22 +71,8 @@ func (sm *StateManager) ProcState() *State { return sm.procState } -// Watches any given address and puts it in the address state store -func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { - //XXX account := sm.bc.CurrentBlock.state.GetAccount(addr) - account := sm.procState.GetAccount(addr) - - return sm.stateObjectCache.Add(addr, account) -} - -func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject { - account := sm.stateObjectCache.Get(addr) - if account == nil { - a := sm.procState.GetAccount(addr) - account = &CachedStateObject{Nonce: a.Nonce, Object: a} - } - - return account +func (sm *StateManager) TransState() *State { + return sm.transState } func (sm *StateManager) BlockChain() *BlockChain { @@ -201,19 +186,13 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { // Add the block to the chain sm.bc.Add(block) - // If there's a block processor present, pass in the block for further - // processing - if sm.SecondaryBlockProcessor != nil { - sm.SecondaryBlockProcessor.ProcessBlock(block) - } - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) sm.notifyChanges() - sm.manifest.Reset() + sm.procState.manifest.Reset() } } else { fmt.Println("total diff failed") @@ -323,7 +302,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans return } - closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) + closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) vm := NewVm(sm.procState, sm, RuntimeVars{ Origin: account.Address(), BlockNumber: block.BlockInfo().Number, @@ -331,59 +310,24 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans Coinbase: block.Coinbase, Time: block.Time, Diff: block.Difficulty, + Value: tx.Value, //Price: tx.GasPrice, }) closure.Call(vm, tx.Data, nil) // Update the account (refunds) sm.procState.UpdateStateObject(account) - sm.manifest.AddObjectChange(account) - sm.procState.UpdateStateObject(object) - sm.manifest.AddObjectChange(object) } func (sm *StateManager) notifyChanges() { - for addr, stateObject := range sm.manifest.objectChanges { + for addr, stateObject := range sm.procState.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) } - for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { + for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { for addr, value := range mappedObjects { sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) } } } - -type Manifest struct { - // XXX These will be handy in the future. Not important for now. - objectAddresses map[string]bool - storageAddresses map[string]map[string]bool - - objectChanges map[string]*StateObject - storageChanges map[string]map[string]*big.Int -} - -func NewManifest() *Manifest { - m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)} - m.Reset() - - return m -} - -func (m *Manifest) Reset() { - m.objectChanges = make(map[string]*StateObject) - m.storageChanges = make(map[string]map[string]*big.Int) -} - -func (m *Manifest) AddObjectChange(stateObject *StateObject) { - m.objectChanges[string(stateObject.Address())] = stateObject -} - -func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { - if m.storageChanges[string(stateObject.Address())] == nil { - m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) - } - - m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage -} diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 617646077..7a11a1152 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { +func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) c.SetAddr(addr, val) } @@ -160,33 +160,8 @@ func (c *StateObject) RlpDecode(data []byte) { c.script = decoder.Get(3).Bytes() } -// The cached state and state object cache are helpers which will give you somewhat -// control over the nonce. When creating new transactions you're interested in the 'next' -// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions. -type StateObjectCache struct { - cachedObjects map[string]*CachedStateObject -} - -func NewStateObjectCache() *StateObjectCache { - return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)} -} - -func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject { - state := &CachedStateObject{Nonce: object.Nonce, Object: object} - s.cachedObjects[string(addr)] = state - - return state -} - -func (s *StateObjectCache) Get(addr []byte) *CachedStateObject { - return s.cachedObjects[string(addr)] -} - -type CachedStateObject struct { - Nonce uint64 - Object *StateObject -} - +// Storage change object. Used by the manifest for notifying changes to +// the sub channels. type StorageState struct { StateAddress []byte Address []byte diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 72836d6cb..56deae0c6 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -148,8 +148,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) - sender := accountState.Object + sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) // Make sure there's enough in the sender's account. Having insufficient diff --git a/ethchain/types.go b/ethchain/types.go index 827d4f27f..9964bbe3b 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -48,8 +48,6 @@ const ( oGASLIMIT = 0x45 // 0x50 range - 'storage' and execution - oPUSH = 0x50 - oPUSH20 = 0x80 oPOP = 0x51 oDUP = 0x52 oSWAP = 0x53 @@ -63,14 +61,48 @@ const ( oPC = 0x5b oMSIZE = 0x5c - // 0x60 range - closures - oCREATE = 0x60 - oCALL = 0x61 - oRETURN = 0x62 + // 0x60 range + oPUSH1 = 0x60 + oPUSH2 = 0x61 + oPUSH3 = 0x62 + oPUSH4 = 0x63 + oPUSH5 = 0x64 + oPUSH6 = 0x65 + oPUSH7 = 0x66 + oPUSH8 = 0x67 + oPUSH9 = 0x68 + oPUSH10 = 0x69 + oPUSH11 = 0x6a + oPUSH12 = 0x6b + oPUSH13 = 0x6c + oPUSH14 = 0x6d + oPUSH15 = 0x6e + oPUSH16 = 0x6f + oPUSH17 = 0x70 + oPUSH18 = 0x71 + oPUSH19 = 0x72 + oPUSH20 = 0x73 + oPUSH21 = 0x74 + oPUSH22 = 0x75 + oPUSH23 = 0x76 + oPUSH24 = 0x77 + oPUSH25 = 0x78 + oPUSH26 = 0x79 + oPUSH27 = 0x7a + oPUSH28 = 0x7b + oPUSH29 = 0x7c + oPUSH30 = 0x7d + oPUSH31 = 0x7e + oPUSH32 = 0x7f + + // 0xf0 range - closures + oCREATE = 0xf0 + oCALL = 0xf1 + oRETURN = 0xf2 // 0x70 range - other - oLOG = 0x70 // XXX Unofficial - oSUICIDE = 0x7f + oLOG = 0xfe // XXX Unofficial + oSUICIDE = 0xff ) // Since the opcodes aren't all in order we can't use a regular slice @@ -119,8 +151,6 @@ var opCodeToString = map[OpCode]string{ oGASLIMIT: "GASLIMIT", // 0x50 range - 'storage' and execution - oPUSH: "PUSH", - oPOP: "POP", oDUP: "DUP", oSWAP: "SWAP", oMLOAD: "MLOAD", @@ -133,7 +163,41 @@ var opCodeToString = map[OpCode]string{ oPC: "PC", oMSIZE: "MSIZE", - // 0x60 range - closures + // 0x60 range - push + oPUSH1: "PUSH1", + oPUSH2: "PUSH2", + oPUSH3: "PUSH3", + oPUSH4: "PUSH4", + oPUSH5: "PUSH5", + oPUSH6: "PUSH6", + oPUSH7: "PUSH7", + oPUSH8: "PUSH8", + oPUSH9: "PUSH9", + oPUSH10: "PUSH10", + oPUSH11: "PUSH11", + oPUSH12: "PUSH12", + oPUSH13: "PUSH13", + oPUSH14: "PUSH14", + oPUSH15: "PUSH15", + oPUSH16: "PUSH16", + oPUSH17: "PUSH17", + oPUSH18: "PUSH18", + oPUSH19: "PUSH19", + oPUSH20: "PUSH20", + oPUSH21: "PUSH21", + oPUSH22: "PUSH22", + oPUSH23: "PUSH23", + oPUSH24: "PUSH24", + oPUSH25: "PUSH25", + oPUSH26: "PUSH26", + oPUSH27: "PUSH27", + oPUSH28: "PUSH28", + oPUSH29: "PUSH29", + oPUSH30: "PUSH30", + oPUSH31: "PUSH31", + oPUSH32: "PUSH32", + + // 0xf0 range oCREATE: "CREATE", oCALL: "CALL", oRETURN: "RETURN", @@ -193,10 +257,6 @@ var OpCodes = map[string]byte{ "GASLIMIT": 0x45, // 0x50 range - 'storage' and execution - "PUSH": 0x50, - - "PUSH20": 0x80, - "POP": 0x51, "DUP": 0x52, "SWAP": 0x53, @@ -210,13 +270,47 @@ var OpCodes = map[string]byte{ "PC": 0x5b, "MSIZE": 0x5c, - // 0x60 range - closures - "CREATE": 0x60, - "CALL": 0x61, - "RETURN": 0x62, + // 0x70 range - 'push' + "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": 0x70, + "PUSH27": 0x7a, + "PUSH28": 0x7b, + "PUSH29": 0x7c, + "PUSH30": 0x7d, + "PUSH31": 0x7e, + "PUSH32": 0x7f, + + // 0xf0 range - closures + "CREATE": 0xf0, + "CALL": 0xf1, + "RETURN": 0xf2, // 0x70 range - other - "LOG": 0x70, + "LOG": 0xfe, "SUICIDE": 0x7f, } diff --git a/ethchain/vm.go b/ethchain/vm.go index 3a3b3447a..584c66611 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -53,6 +53,7 @@ type RuntimeVars struct { Time int64 Diff *big.Int TxData []string + Value *big.Int } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { @@ -94,6 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if ethutil.Config.Debug { ethutil.Config.Log.Debugf("# op\n") } + fmt.Println(closure.Script) for { // The base for all big integer arithmetic @@ -104,11 +106,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro val := closure.Get(pc) // Get the opcode (it must be an opcode!) op := OpCode(val.Uint()) - /* - if ethutil.Config.Debug { - ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) - } - */ + if ethutil.Config.Debug { + ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) + } gas := new(big.Int) useGas := func(amount *big.Int) { @@ -318,14 +318,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oADDRESS: stack.Push(ethutil.BigD(closure.Object().Address())) case oBALANCE: - stack.Push(closure.Value) + stack.Push(closure.object.Amount) 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) + stack.Push(vm.vars.Value) case oCALLDATALOAD: require(1) offset := stack.Pop().Int64() @@ -352,27 +351,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // TODO stack.Push(big.NewInt(0)) - // 0x50 range - case oPUSH: // Push PC+1 on to the stack + // 0x50 range + case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32: + a := big.NewInt(int64(op) - int64(oPUSH1) + 1) pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(32)) + data := closure.Gets(pc, a) val := ethutil.BigD(data.Bytes()) - // Push value to stack stack.Push(val) - - pc.Add(pc, big.NewInt(31)) + pc.Add(pc, a.Sub(a, big.NewInt(1))) step++ - case oPUSH20: - pc.Add(pc, ethutil.Big1) - data := closure.Gets(pc, big.NewInt(20)) - val := ethutil.BigD(data.Bytes()) - // Push value to stack - stack.Push(val) - - pc.Add(pc, big.NewInt(19)) - step++ case oPOP: require(1) stack.Pop() @@ -406,21 +395,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case oSSTORE: require(2) val, loc := stack.Popn() - closure.SetMem(loc, ethutil.NewValue(val)) + closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest - vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) + vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) case oJUMP: require(1) pc = stack.Pop() // Reduce pc by one because of the increment that's at the end of this for loop - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue case oJUMPI: require(2) cond, pos := stack.Popn() if cond.Cmp(ethutil.BigTrue) == 0 { pc = pos - pc.Sub(pc, ethutil.Big1) + //pc.Sub(pc, ethutil.Big1) + continue } case oPC: stack.Push(pc) @@ -449,8 +440,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro contract.initScript, vm.state, gas, - closure.Price, - value) + closure.Price) // Call the closure and set the return value as // main script. closure.Script, err = closure.Call(vm, nil, hook) @@ -477,8 +467,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro break } + // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) + // Fetch the contract which will serve as the closure body contract := vm.state.GetContract(addr.Bytes()) @@ -490,8 +482,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas = new(big.Int).Set(closure.Gas) } closure.Gas.Sub(closure.Gas, gas) + + // Add the value to the state object + contract.AddAmount(value) + // Create a new callable closure - closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) + closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price) // Executer the closure and get the return value (if any) ret, err := closure.Call(vm, args, hook) if err != nil { @@ -500,10 +496,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //contract.State().Reset() } else { stack.Push(ethutil.BigTrue) - // Notify of the changes - vm.stateManager.manifest.AddObjectChange(contract) } + vm.state.SetStateObject(contract) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) @@ -520,8 +516,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver.AddAmount(closure.object.Amount) - - vm.stateManager.manifest.AddObjectChange(receiver) + vm.state.SetStateObject(receiver) closure.object.state.Purge() diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 35a7b2e3f..b919b496f 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -11,71 +11,6 @@ import ( "testing" ) -/* -func TestRun3(t *testing.T) { - ethutil.ReadConfig("") - - db, _ := ethdb.NewMemDatabase() - state := NewState(ethutil.NewTrie(db, "")) - - script := Compile([]string{ - "PUSH", "300", - "PUSH", "0", - "MSTORE", - - "PUSH", "32", - "CALLDATA", - - "PUSH", "64", - "PUSH", "0", - "RETURN", - }) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script) - addr := tx.Hash()[12:] - contract := MakeContract(tx, state) - state.UpdateContract(contract) - - callerScript := ethutil.Assemble( - "PUSH", 1337, // Argument - "PUSH", 65, // argument mem offset - "MSTORE", - "PUSH", 64, // ret size - "PUSH", 0, // ret offset - - "PUSH", 32, // arg size - "PUSH", 65, // arg offset - "PUSH", 1000, /// Gas - "PUSH", 0, /// value - "PUSH", addr, // Sender - "CALL", - "PUSH", 64, - "PUSH", 0, - "RETURN", - ) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript) - - // Contract addr as test address - account := NewAccount(ContractAddr, big.NewInt(10000000)) - callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) - - vm := NewVm(state, RuntimeVars{ - origin: account.Address(), - blockNumber: 1, - prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"), - coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"), - time: 1, - diff: big.NewInt(256), - // XXX Tx data? Could be just an argument to the closure instead - txData: nil, - }) - ret := callerClosure.Call(vm, nil) - - exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57} - if bytes.Compare(ret, exp) != 0 { - t.Errorf("expected return value to be %v, got %v", exp, ret) - } -}*/ - func TestRun4(t *testing.T) { ethutil.ReadConfig("") @@ -86,7 +21,7 @@ func TestRun4(t *testing.T) { int32 a = 10 int32 b = 20 if a > b { - int32 c = this.Caller() + int32 c = this.caller() } Exit() `), false) @@ -98,21 +33,21 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store - if store[1000] == 0 { - store[1000] = 10^20 + if this.store[1000] == 0 { + this.store[1000] = 10^20 } - store[1001] = this.Value() * 20 - store[this.Origin()] = store[this.Origin()] + 1000 + this.store[1001] = this.value() * 20 + this.store[this.origin()] = this.store[this.origin()] + 1000 - if store[1001] > 20 { - store[1001] = 10^50 + if this.store[1001] > 20 { + this.store[1001] = 10^50 } int8 ret = 0 int8 arg = 10 - Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) + call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) big t for int8 i = 0; i < 10; i++ { @@ -142,7 +77,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) + callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), diff --git a/ethereum.go b/ethereum.go index 707938639..e3140b5ce 100644 --- a/ethereum.go +++ b/ethereum.go @@ -253,7 +253,7 @@ func (s *Ethereum) ReapDeadPeerHandler() { } // Start the ethereum -func (s *Ethereum) Start() { +func (s *Ethereum) Start(seed bool) { // Bind to addr and port ln, err := net.Listen("tcp", ":"+s.Port) if err != nil { @@ -272,47 +272,51 @@ func (s *Ethereum) Start() { // Start the reaping processes go s.ReapDeadPeerHandler() - if ethutil.Config.Seed { - ethutil.Config.Log.Debugln("Seeding") - // DNS Bootstrapping - _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") - if err == nil { - peers := []string{} - // Iterate SRV nodes - for _, n := range nodes { - target := n.Target - port := strconv.Itoa(int(n.Port)) - // Resolve target to ip (Go returns list, so may resolve to multiple ips?) - addr, err := net.LookupHost(target) - if err == nil { - for _, a := range addr { - // Build string out of SRV port and Resolved IP - peer := net.JoinHostPort(a, port) - log.Println("Found DNS Bootstrap Peer:", peer) - peers = append(peers, peer) - } - } else { - log.Println("Couldn't resolve :", target) - } - } - // Connect to Peer list - s.ProcessPeerList(peers) - } else { - // Fallback to servers.poc3.txt - resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") - if err != nil { - log.Println("Fetching seed failed:", err) - return - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println("Reading seed failed:", err) - return - } + if seed { + s.Seed() + } +} - s.ConnectToPeer(string(body)) +func (s *Ethereum) Seed() { + ethutil.Config.Log.Debugln("Seeding") + // DNS Bootstrapping + _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") + if err == nil { + peers := []string{} + // Iterate SRV nodes + for _, n := range nodes { + target := n.Target + port := strconv.Itoa(int(n.Port)) + // Resolve target to ip (Go returns list, so may resolve to multiple ips?) + addr, err := net.LookupHost(target) + if err == nil { + for _, a := range addr { + // Build string out of SRV port and Resolved IP + peer := net.JoinHostPort(a, port) + log.Println("Found DNS Bootstrap Peer:", peer) + peers = append(peers, peer) + } + } else { + log.Println("Couldn't resolve :", target) + } } + // Connect to Peer list + s.ProcessPeerList(peers) + } else { + // Fallback to servers.poc3.txt + resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt") + if err != nil { + log.Println("Fetching seed failed:", err) + return + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Println("Reading seed failed:", err) + return + } + + s.ConnectToPeer(string(body)) } } @@ -339,7 +343,9 @@ func (s *Ethereum) Stop() { close(s.quit) - s.RpcServer.Stop() + if s.RpcServer != nil { + s.RpcServer.Stop() + } s.txPool.Stop() s.stateManager.Stop() diff --git a/ethpub/pub.go b/ethpub/pub.go index 5e7792a9f..f7e641b35 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -92,7 +92,14 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in hash = ethutil.FromHex(recipient) } - keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + var keyPair *ethchain.KeyPair + var err error + if key[0:2] == "0x" { + keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2]))) + } else { + keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) + } + if err != nil { return nil, err } @@ -132,8 +139,11 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) } - acc := lib.stateManager.GetAddrState(keyPair.Address()) + acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) + //acc := lib.stateManager.GetAddrState(keyPair.Address()) tx.Nonce = acc.Nonce + lib.stateManager.TransState().SetStateObject(acc) + tx.Sign(keyPair.PrivateKey) lib.txPool.QueueTransaction(tx) diff --git a/ethrpc/packages.go b/ethrpc/packages.go index b989a65cb..4ec2b4602 100644 --- a/ethrpc/packages.go +++ b/ethrpc/packages.go @@ -4,7 +4,8 @@ import ( "encoding/json" "errors" "github.com/ethereum/eth-go/ethpub" - _ "log" + "github.com/ethereum/eth-go/ethutil" + "math/big" ) type EthereumApi struct { @@ -173,7 +174,10 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { return err } state := p.ethp.GetStateObject(args.Address) - value := state.GetStorage(args.Key) + // Convert the incoming string (which is a bigint) into hex + i, _ := new(big.Int).SetString(args.Key, 10) + hx := ethutil.Hex(i.Bytes()) + value := state.GetStorage(hx) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) return nil } diff --git a/ethutil/common_test.go b/ethutil/common_test.go index b5c733ff3..8031f08ab 100644 --- a/ethutil/common_test.go +++ b/ethutil/common_test.go @@ -26,7 +26,7 @@ func TestCommon(t *testing.T) { t.Error("Got", szabo) } - if vito != "10 Vito" { + if vito != "10 Vita" { t.Error("Got", vito) } diff --git a/ethutil/config.go b/ethutil/config.go index 382396ceb..5e36b06d2 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -27,7 +27,6 @@ type config struct { Ver string ClientString string Pubkey []byte - Seed bool } var Config *config @@ -51,7 +50,7 @@ func ReadConfig(base string) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"} Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } diff --git a/ethutil/rlp_test.go b/ethutil/rlp_test.go index 9e8127aab..095c01ecc 100644 --- a/ethutil/rlp_test.go +++ b/ethutil/rlp_test.go @@ -2,7 +2,6 @@ package ethutil import ( "bytes" - "fmt" "math/big" "reflect" "testing" @@ -56,15 +55,6 @@ func TestValue(t *testing.T) { } } -func TestEncodeDecodeMaran(t *testing.T) { - b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"}) - a := b.Encode() - fmt.Println("voor maran", a) - f, i := Decode(a, 0) - fmt.Println("voor maran 2", f) - fmt.Println(i) -} - func TestEncode(t *testing.T) { strRes := "\x83dog" bytes := Encode("dog") @@ -131,7 +121,10 @@ func TestEncodeDecodeBytes(t *testing.T) { func TestEncodeZero(t *testing.T) { b := NewValue(0).Encode() - fmt.Println(b) + exp := []byte{0xc0} + if bytes.Compare(b, exp) == 0 { + t.Error("Expected", exp, "got", b) + } } func BenchmarkEncodeDecode(b *testing.B) {