diff options
author | zelig <viktor.tron@gmail.com> | 2014-07-15 01:50:06 +0800 |
---|---|---|
committer | zelig <viktor.tron@gmail.com> | 2014-07-15 01:50:06 +0800 |
commit | 3d5db7288f134fef7e51b25776007705f6663654 (patch) | |
tree | edda6e8fd23584327473058411df9cd2c53241f4 /ethchain | |
parent | dc11b5c55e2888a7a3dac51fedc3864d112136ce (diff) | |
parent | 8845fb7eae3e51fd3e55c47c377bf1a9e0cfe2a9 (diff) | |
download | dexon-3d5db7288f134fef7e51b25776007705f6663654.tar dexon-3d5db7288f134fef7e51b25776007705f6663654.tar.gz dexon-3d5db7288f134fef7e51b25776007705f6663654.tar.bz2 dexon-3d5db7288f134fef7e51b25776007705f6663654.tar.lz dexon-3d5db7288f134fef7e51b25776007705f6663654.tar.xz dexon-3d5db7288f134fef7e51b25776007705f6663654.tar.zst dexon-3d5db7288f134fef7e51b25776007705f6663654.zip |
merge upstream
Diffstat (limited to 'ethchain')
-rw-r--r-- | ethchain/asm.go | 4 | ||||
-rw-r--r-- | ethchain/block_chain.go | 3 | ||||
-rw-r--r-- | ethchain/closure.go | 8 | ||||
-rw-r--r-- | ethchain/dagger.go | 5 | ||||
-rw-r--r-- | ethchain/state.go | 163 | ||||
-rw-r--r-- | ethchain/state_manager.go | 18 | ||||
-rw-r--r-- | ethchain/state_object.go | 54 | ||||
-rw-r--r-- | ethchain/state_transition.go | 24 | ||||
-rw-r--r-- | ethchain/vm.go | 109 |
9 files changed, 273 insertions, 115 deletions
diff --git a/ethchain/asm.go b/ethchain/asm.go index 09d6af56f..2697953fd 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -24,6 +24,10 @@ func Disassemble(script []byte) (asm []string) { 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} diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index df735d679..f72a77706 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -294,7 +294,6 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -309,7 +308,7 @@ func (bc *BlockChain) setLastBlock() { // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { diff --git a/ethchain/closure.go b/ethchain/closure.go index cc769de30..1f7f8d703 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -84,13 +84,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) { func (c *Closure) Return(ret []byte) []byte { // Return the remaining gas to the caller - // If no caller is present return it to - // the origin (i.e. contract or tx) - if c.caller != nil { - c.caller.ReturnGas(c.Gas, c.Price, c.State) - } else { - c.object.ReturnGas(c.Gas, c.Price, c.State) - } + c.caller.ReturnGas(c.Gas, c.Price, c.State) return ret } diff --git a/ethchain/dagger.go b/ethchain/dagger.go index adf1c2f05..4dda21ff5 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -3,7 +3,6 @@ package ethchain import ( "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" @@ -15,7 +14,7 @@ import ( var powlogger = ethlog.NewLogger("POW") type PoW interface { - Search(block *Block, reactChan chan ethreact.Event) []byte + Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool } @@ -23,7 +22,7 @@ type EasyPow struct { hash *big.Int } -func (pow *EasyPow) Search(block *Block, reactChan chan ethreact.Event) []byte { +func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty diff --git a/ethchain/state.go b/ethchain/state.go index 20af94fe8..8df79dcef 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" @@ -26,70 +27,36 @@ func NewState(trie *ethtrie.Trie) *State { return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, stateObject := range s.stateObjects { - if stateObject.state == nil { - continue - } - - stateObject.state.Reset() - } - - s.Empty() +// Iterate over each storage address and yield callback +func (s *State) EachStorage(cb ethtrie.EachCallback) { + it := s.trie.NewIterator() + it.Each(cb) } -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, stateObject := range s.stateObjects { - s.UpdateStateObject(stateObject) - - if stateObject.state == nil { - continue - } - - stateObject.state.Sync() +// Retrieve the balance from the given address or 0 if object not found +func (self *State) GetBalance(addr []byte) *big.Int { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Amount } - s.trie.Sync() - - s.Empty() -} - -func (self *State) Empty() { - self.stateObjects = make(map[string]*StateObject) + return ethutil.Big0 } -func (self *State) Update() { - for _, stateObject := range self.stateObjects { - if stateObject.remove { - self.trie.Delete(string(stateObject.Address())) - } else { - self.UpdateStateObject(stateObject) - } +func (self *State) GetNonce(addr []byte) uint64 { + stateObject := self.GetStateObject(addr) + if stateObject != nil { + return stateObject.Nonce } -} -// Purges the current trie. -func (s *State) Purge() int { - return s.trie.NewIterator().Purge() + return 0 } -func (s *State) EachStorage(cb ethtrie.EachCallback) { - it := s.trie.NewIterator() - it.Each(cb) -} - -func (self *State) ResetStateObject(stateObject *StateObject) { - delete(self.stateObjects, string(stateObject.Address())) - - stateObject.state.Reset() -} +// +// Setting, updating & deleting state object methods +// +// Update the given state object and apply it to state trie func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() @@ -100,6 +67,14 @@ func (self *State) UpdateStateObject(stateObject *StateObject) { self.manifest.AddObjectChange(stateObject) } +// Delete the given state object and delete it from the state trie +func (self *State) DeleteStateObject(stateObject *StateObject) { + self.trie.Delete(string(stateObject.Address())) + + delete(self.stateObjects, string(stateObject.Address())) +} + +// Retrieve a state object given my the address. Nil if not found func (self *State) GetStateObject(addr []byte) *StateObject { stateObject := self.stateObjects[string(addr)] if stateObject != nil { @@ -117,6 +92,7 @@ func (self *State) GetStateObject(addr []byte) *StateObject { return stateObject } +// Retrieve a state object or create a new state object if nil func (self *State) GetOrNewStateObject(addr []byte) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { @@ -126,6 +102,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { return stateObject } +// Create a state object whether it exist in the trie or not func (self *State) NewStateObject(addr []byte) *StateObject { statelogger.Infof("(+) %x\n", addr) @@ -135,10 +112,15 @@ func (self *State) NewStateObject(addr []byte) *StateObject { return stateObject } +// Deprecated func (self *State) GetAccount(addr []byte) *StateObject { return self.GetOrNewStateObject(addr) } +// +// Setting, copying of the state methods +// + func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } @@ -161,17 +143,82 @@ func (self *State) Set(state *State) { panic("Tried setting 'state' to nil through 'Set'") } - *self = *state -} - -func (s *State) Put(key, object []byte) { - s.trie.Update(string(key), string(object)) + self.trie = state.trie + self.stateObjects = state.stateObjects + //*self = *state } func (s *State) Root() interface{} { return s.trie.Root } +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + //stateObject.state.Reset() + stateObject.Reset() + } + + s.Empty() +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + s.UpdateStateObject(stateObject) + + if stateObject.state == nil { + continue + } + + stateObject.state.Sync() + } + + s.trie.Sync() + + s.Empty() +} + +func (self *State) Empty() { + self.stateObjects = make(map[string]*StateObject) +} + +func (self *State) Update() { + for _, stateObject := range self.stateObjects { + if stateObject.remove { + self.DeleteStateObject(stateObject) + } else { + stateObject.Sync() + + self.UpdateStateObject(stateObject) + } + } + + // FIXME trie delete is broken + valid, t2 := ethtrie.ParanoiaCheck(self.trie) + if !valid { + self.trie = t2 + } +} + +// Debug stuff +func (self *State) CreateOutputForDiff() { + for addr, stateObject := range self.stateObjects { + fmt.Printf("0x%x 0x%x 0x%x 0x%x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce) + stateObject.state.EachStorage(func(addr string, value *ethutil.Value) { + fmt.Printf("0x%x 0x%x\n", addr, value.Bytes()) + }) + } +} + // Object manifest // // The object manifest is used to keep changes to the state so we can keep track of the changes diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 52a73beb8..62fcda8a5 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethlog" - "github.com/ethereum/eth-go/ethreact" "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" @@ -37,7 +36,7 @@ type EthManager interface { BlockChain() *BlockChain TxPool() *TxPool Broadcast(msgType ethwire.MsgType, data []interface{}) - Reactor() *ethreact.ReactorEngine + Reactor() *ethutil.ReactorEngine PeerCount() int IsMining() bool IsListening() bool @@ -67,6 +66,11 @@ type StateManager struct { // Mining state. The mining state is used purely and solely by the mining // operation. miningState *State + + // The last attempted block is mainly used for debugging purposes + // This does not have to be a valid block and will be set during + // 'Process' & canonical validation. + lastAttemptedBlock *Block } func NewStateManager(ethereum EthManager) *StateManager { @@ -146,6 +150,10 @@ done: receipts = append(receipts, receipt) handled = append(handled, tx) + + if ethutil.Config.Diff { + state.CreateOutputForDiff() + } } parent.GasUsed = totalUsedGas @@ -166,6 +174,8 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { return ParentError(block.PrevHash) } + sm.lastAttemptedBlock = block + var ( parent = sm.bc.GetBlock(block.PrevHash) state = parent.State() @@ -177,6 +187,10 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // before that. defer state.Reset() + if ethutil.Config.Diff { + fmt.Printf("## 0x%x 0x%x ##\n", block.Hash(), block.Number) + } + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5a43de35c..ebc050863 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -27,6 +27,8 @@ type StateObject struct { script Code initScript Code + storage map[string]*ethutil.Value + // Total gas pool is the total amount of gas currently // left if this object is the coinbase. Gas is directly // purchased of the coinbase. @@ -38,6 +40,10 @@ type StateObject struct { remove bool } +func (self *StateObject) Reset() { + self.storage = make(map[string]*ethutil.Value) +} + // Converts an transaction in to a state object func MakeContract(tx *Transaction, state *State) *StateObject { // Create contract if there's no recipient @@ -55,14 +61,19 @@ func MakeContract(tx *Transaction, state *State) *StateObject { } func NewStateObject(addr []byte) *StateObject { - object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)} + // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter. + address := ethutil.LeftPadBytes(addr, 20) + + object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) + object.storage = make(map[string]*ethutil.Value) return object } func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { - contract := &StateObject{address: address, Amount: Amount, Nonce: 0} + contract := NewStateObject(address) + contract.Amount = Amount contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) return contract @@ -84,6 +95,7 @@ func NewStateObjectFromBytes(address, data []byte) *StateObject { func (self *StateObject) MarkForDeletion() { self.remove = true + statelogger.Infof("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount) } func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { @@ -94,24 +106,43 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) } -func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { - addr := ethutil.BigToBytes(num, 256) +func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value { + return self.getStorage(key.Bytes()) +} +func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) { + self.setStorage(key.Bytes(), value) +} - if val.BigInt().Cmp(ethutil.Big0) == 0 { - c.state.trie.Delete(string(addr)) +func (self *StateObject) getStorage(key []byte) *ethutil.Value { + k := ethutil.LeftPadBytes(key, 32) - return + value := self.storage[string(k)] + if value == nil { + value = self.GetAddr(k) + + self.storage[string(k)] = value } - c.SetAddr(addr, val) + return value } -func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { - nb := ethutil.BigToBytes(num, 256) +func (self *StateObject) setStorage(key []byte, value *ethutil.Value) { + k := ethutil.LeftPadBytes(key, 32) - return c.GetAddr(nb) + self.storage[string(k)] = value } +func (self *StateObject) Sync() { + for key, value := range self.storage { + if value.BigInt().Cmp(ethutil.Big0) == 0 { + self.state.trie.Delete(string(key)) + continue + } + + self.SetAddr([]byte(key), value) + + } +} func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) @@ -248,6 +279,7 @@ func (c *StateObject) RlpDecode(data []byte) { c.Nonce = decoder.Get(0).Uint() c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) + c.storage = make(map[string]*ethutil.Value) c.ScriptHash = decoder.Get(3).Bytes() diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ea9a837d..314d858f2 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -164,8 +164,6 @@ func (self *StateTransition) TransitionState() (err error) { // Increment the nonce for the next transaction sender.Nonce += 1 - receiver = self.Receiver() - // Transaction gas if err = self.UseGas(GasTx); err != nil { return @@ -178,13 +176,23 @@ func (self *StateTransition) TransitionState() (err error) { return } + /* FIXME + * If tx goes TO "0", goes OOG during init, reverse changes, but initial endowment should happen. The ether is lost forever + */ + var snapshot *State + // If the receiver is nil it's a contract (\0*32). - if receiver == nil { + if tx.CreatesContract() { + snapshot = self.state.Copy() + // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) + self.rec = receiver if receiver == nil { return fmt.Errorf("Unable to create contract") } + } else { + receiver = self.Receiver() } // Transfer value from sender to receiver @@ -192,7 +200,9 @@ func (self *StateTransition) TransitionState() (err error) { return } - //snapshot := self.state.Copy() + if snapshot == nil { + snapshot = self.state.Copy() + } // Process the init code and create 'valid' contract if IsContractAddr(self.receiver) { @@ -203,8 +213,7 @@ func (self *StateTransition) TransitionState() (err error) { code, err := self.Eval(receiver.Init(), receiver, "init") if err != nil { - //self.state.Set(snapshot) - self.state.ResetStateObject(receiver) + self.state.Set(snapshot) return fmt.Errorf("Error during init execution %v", err) } @@ -214,8 +223,7 @@ func (self *StateTransition) TransitionState() (err error) { if len(receiver.Script()) > 0 { _, err = self.Eval(receiver.Script(), receiver, "code") if err != nil { - //self.state.Set(snapshot) - self.state.ResetStateObject(receiver) + self.state.Set(snapshot) return fmt.Errorf("Error during code execution %v", err) } diff --git a/ethchain/vm.go b/ethchain/vm.go index 769333649..f1794ff77 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -22,12 +22,16 @@ var ( GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) + + LogTyPretty byte = 0x1 + LogTyDiff byte = 0x2 ) type Debugger interface { BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool BreakPoints() []int64 + SetCode(byteCode []byte) } type Vm struct { @@ -44,6 +48,7 @@ type Vm struct { Verbose bool + logTy byte logStr string err error @@ -69,7 +74,7 @@ type RuntimeVars struct { } func (self *Vm) Printf(format string, v ...interface{}) *Vm { - if self.Verbose { + if self.Verbose && self.logTy == LogTyPretty { self.logStr += fmt.Sprintf(format, v...) } @@ -77,7 +82,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { } func (self *Vm) Endl() *Vm { - if self.Verbose { + if self.Verbose && self.logTy == LogTyPretty { vmlogger.Debugln(self.logStr) self.logStr = "" } @@ -86,7 +91,12 @@ func (self *Vm) Endl() *Vm { } func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { - return &Vm{vars: vars, state: state, stateManager: stateManager} + lt := LogTyPretty + if ethutil.Config.Diff { + lt = LogTyDiff + } + + return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt} } var Pow256 = ethutil.BigPow(2, 256) @@ -103,7 +113,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } }() - vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.object.Address(), closure.Gas, closure.Args) + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } + + // Don't bother with the execution if there's no code. + if len(closure.Script) == 0 { + return closure.Return(nil), nil + } + + vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args) var ( op OpCode @@ -132,6 +152,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { // Get the opcode (it must be an opcode!) op = OpCode(val.Uint()) + // XXX Leave this Println intact. Don't change this to the log system. + // Used for creating diffs between implementations + if vm.logTy == LogTyDiff { + 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 { @@ -167,7 +198,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(2) newMemSize = stack.Peek().Uint64() + 32 case MLOAD: + require(1) + newMemSize = stack.Peek().Uint64() + 32 case MSTORE8: require(2) newMemSize = stack.Peek().Uint64() + 1 @@ -415,7 +448,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { require(2) val, th := stack.Popn() if th.Cmp(big.NewInt(32)) < 0 { - stack.Push(big.NewInt(int64(len(val.Bytes())-1) - th.Int64())) + byt := big.NewInt(int64(val.Bytes()[th.Int64()])) + stack.Push(byt) + + vm.Printf(" => 0x%x", byt.Bytes()) } else { stack.Push(ethutil.BigFalse) } @@ -427,13 +463,26 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64())) stack.Push(ethutil.BigD(data)) + + vm.Printf(" => %x", data) // 0x30 range case ADDRESS: - stack.Push(ethutil.BigD(closure.Object().Address())) + stack.Push(ethutil.BigD(closure.Address())) + + vm.Printf(" => %x", closure.Address()) case BALANCE: - stack.Push(closure.object.Amount) + require(1) + + addr := stack.Pop().Bytes() + balance := vm.state.GetBalance(addr) + + stack.Push(balance) + + vm.Printf(" => %v (%x)", balance, addr) case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) + + vm.Printf(" => %v", vm.vars.Origin) case CALLER: caller := closure.caller.Address() stack.Push(ethutil.BigD(caller)) @@ -441,6 +490,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf(" => %x", caller) case CALLVALUE: stack.Push(vm.vars.Value) + + vm.Printf(" => %v", vm.vars.Value) case CALLDATALOAD: require(1) offset := stack.Pop().Int64() @@ -499,8 +550,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { } code := closure.Script[cOff : cOff+l] + fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff) mem.Set(mOff, l, code) + fmt.Println(Code(mem.Get(mOff, l))) case GASPRICE: stack.Push(closure.Price) @@ -562,8 +615,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case MSTORE8: require(2) val, mStart := stack.Popn() - base.And(val, new(big.Int).SetInt64(0xff)) - mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + //base.And(val, new(big.Int).SetInt64(0xff)) + //mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) + mem.store[mStart.Int64()] = byte(val.Int64() & 0xff) vm.Printf(" => 0x%x", val) case SLOAD: @@ -623,9 +677,9 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { ) // Generate a new address - addr := ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce) + addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()) for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ { - ethcrypto.CreateAddress(closure.object.Address(), closure.object.Nonce+i) + ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i) } closure.object.Nonce++ @@ -638,14 +692,15 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { contract.AddAmount(value) // Set the init script - contract.initScript = mem.Get(offset.Int64(), size.Int64()) + initCode := mem.Get(offset.Int64(), size.Int64()) + //fmt.Printf("%x\n", initCode) // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) closure.UseGas(closure.Gas) // Create the closure - c := NewClosure(closure, contract, contract.initScript, vm.state, gas, closure.Price) + c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price) // Call the closure and set the return value as // main script. contract.script, err = Call(vm, c, nil) @@ -665,6 +720,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vm.Printf("CREATE success") } vm.Endl() + + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } case CALL: require(7) @@ -683,10 +743,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if closure.object.Amount.Cmp(value) < 0 { vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + closure.ReturnGas(gas, nil, nil) stack.Push(ethutil.BigFalse) } else { - //snapshot := vm.state.Copy() + snapshot := vm.state.Copy() stateObject := vm.state.GetOrNewStateObject(addr.Bytes()) @@ -702,13 +763,17 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { vmlogger.Debugf("Closure execution failed. %v\n", err) - //vm.state.Set(snapshot) - vm.state.ResetStateObject(stateObject) + vm.state.Set(snapshot) } else { stack.Push(ethutil.BigTrue) mem.Set(retOffset.Int64(), retSize.Int64(), ret) } + + // Debug hook + if vm.Dbg != nil { + vm.Dbg.SetCode(closure.Script) + } } case RETURN: require(2) @@ -721,18 +786,12 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { case SUICIDE: require(1) - receiver := vm.state.GetAccount(stack.Pop().Bytes()) + receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes()) + receiver.AddAmount(closure.object.Amount) closure.object.MarkForDeletion() - /* - trie := closure.object.state.trie - trie.NewIterator().Each(func(key string, v *ethutil.Value) { - trie.Delete(key) - }) - */ - fallthrough case STOP: // Stop the closure vm.Endl() @@ -752,6 +811,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) { if vm.Dbg != nil { for _, instrNo := range vm.Dbg.BreakPoints() { if pc.Cmp(big.NewInt(instrNo)) == 0 { + vm.Stepping = true + if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) { return nil, nil } |