diff options
Diffstat (limited to 'ethchain')
-rw-r--r-- | ethchain/asm.go | 4 | ||||
-rw-r--r-- | ethchain/block_chain.go | 41 | ||||
-rw-r--r-- | ethchain/dagger.go | 9 | ||||
-rw-r--r-- | ethchain/state.go | 2 | ||||
-rw-r--r-- | ethchain/state_manager.go | 73 | ||||
-rw-r--r-- | ethchain/state_object.go | 14 | ||||
-rw-r--r-- | ethchain/state_transition.go | 7 | ||||
-rw-r--r-- | ethchain/transaction.go | 12 | ||||
-rw-r--r-- | ethchain/transaction_pool.go | 20 | ||||
-rw-r--r-- | ethchain/vm.go | 114 |
10 files changed, 168 insertions, 128 deletions
diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff9..09d6af56f 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -18,7 +18,7 @@ func Disassemble(script []byte) (asm []string) { // Get the opcode (it must be an opcode!) op := OpCode(val) - asm = append(asm, fmt.Sprintf("%v", op)) + asm = append(asm, fmt.Sprintf("%04v: %v", pc, 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: @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%04v: 0x%x", pc, data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 19b5248d7..d0fea6641 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -2,13 +2,15 @@ package ethchain import ( "bytes" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" - "log" "math" "math/big" ) +var chainlogger = ethlog.NewLogger("CHAIN") + type BlockChain struct { Ethereum EthManager // The famous, the fabulous Mister GENESIIIIIIS (block) @@ -129,38 +131,38 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte // Start with the newest block we got, all the way back to the common block we both know for _, block := range blocks { if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("[CHAIN] We have found the common parent block, breaking") break } chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Incoming chain difficulty:", chainDifficulty) + chainlogger.Infoln("Incoming chain difficulty:", chainDifficulty) curChainDifficulty := new(big.Int) block := bc.CurrentBlock for i := 0; block != nil; block = bc.GetBlock(block.PrevHash) { i++ if bytes.Compare(block.Hash(), commonBlockHash) == 0 { - log.Println("[CHAIN] We have found the common parent block, breaking") + chainlogger.Infoln("We have found the common parent block, breaking") break } anOtherBlock := bc.GetBlock(block.PrevHash) if anOtherBlock == nil { // We do not want to count the genesis block for difficulty since that's not being sent - log.Println("[CHAIN] At genesis block, breaking") + chainlogger.Infoln("At genesis block, breaking") break } curChainDifficulty.Add(curChainDifficulty, bc.CalculateBlockTD(block)) } - log.Println("[CHAIN] Current chain difficulty:", curChainDifficulty) + chainlogger.Infoln("Current chain difficulty:", curChainDifficulty) if chainDifficulty.Cmp(curChainDifficulty) == 1 { - log.Printf("[CHAIN] The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) + chainlogger.Infof("The incoming Chain beat our asses, resetting to block: %x", commonBlockHash) bc.ResetTillBlockHash(commonBlockHash) return false } else { - log.Println("[CHAIN] Our chain showed the incoming chain who is boss. Ignoring.") + chainlogger.Infoln("Our chain showed the incoming chain who is boss. Ignoring.") return true } } @@ -174,18 +176,12 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { bc.LastBlockHash = bc.genesisBlock.Hash() bc.LastBlockNumber = 1 } else { - // TODO: Somehow this doesn't really give the right numbers, double check. - // TODO: Change logs into debug lines returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - //info := bc.BlockInfo(returnTo) bc.LastBlockNumber = returnTo.Number.Uint64() } - // XXX Why are we resetting? This is the block chain, it has nothing to do with states - //bc.Ethereum.StateManager().PrepareDefault(returnTo) - // Manually reset the last sync block err := ethutil.Config.Db.Delete(lastBlock.Hash()) if err != nil { @@ -195,7 +191,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { var block *Block for ; block != nil; block = bc.GetBlock(block.PrevHash) { if bytes.Compare(block.Hash(), hash) == 0 { - log.Println("[CHAIN] We have arrived at the the common parent block, breaking") + chainlogger.Infoln("We have arrived at the the common parent block, breaking") break } err = ethutil.Config.Db.Delete(block.Hash()) @@ -203,7 +199,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { return err } } - log.Println("[CHAIN] Split chain deleted and reverted to common parent block.") + chainlogger.Infoln("Split chain deleted and reverted to common parent block.") return nil } @@ -231,6 +227,11 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { for i := uint64(0); bytes.Compare(currentHash, hash) != 0 && num >= parentNumber && i < count; i++ { // Get the block of the chain block := bc.GetBlock(currentHash) + if block == nil { + chainlogger.Debugf("Unexpected error during GetChainFromHash: Unable to find %x\n", currentHash) + break + } + currentHash = block.PrevHash chain = append(chain, block.Value().Val) @@ -286,7 +287,7 @@ func (bc *BlockChain) setLastBlock() { bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() - ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) + chainlogger.Infof("Last known block height #%d\n", bc.LastBlockNumber) } else { AddTestNetFunds(bc.genesisBlock) @@ -294,14 +295,14 @@ func (bc *BlockChain) setLastBlock() { // Prepare the genesis block bc.Add(bc.genesisBlock) - //log.Printf("root %x\n", bm.bc.genesisBlock.State().Root) + //chainlogger.Infof("root %x\n", bm.bc.genesisBlock.State().Root) //bm.bc.genesisBlock.PrintHash() } // Set the last know difficulty (might be 0x0 as initial value, Genesis) bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) + chainlogger.Infof("Last block: %x\n", bc.CurrentBlock.Hash()) } func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { @@ -358,6 +359,6 @@ func (bc *BlockChain) writeBlockInfo(block *Block) { func (bc *BlockChain) Stop() { if bc.CurrentBlock != nil { - log.Println("[CHAIN] Stopped") + chainlogger.Infoln("Stopped") } } diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 565e1e447..08c4826db 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -1,15 +1,17 @@ package ethchain import ( + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/sha3" "hash" - "log" "math/big" "math/rand" "time" ) +var powlogger = ethlog.NewLogger("POW") + type PoW interface { Search(block *Block, reactChan chan ethutil.React) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool @@ -29,14 +31,13 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte { for { select { case <-reactChan: - //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ if i%1234567 == 0 { elapsed := time.Now().UnixNano() - start hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash") + powlogger.Infoln("Hashing @", int64(hashes), "khash") } sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) @@ -81,7 +82,7 @@ func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { rnd := r.Int63() res := dag.Eval(big.NewInt(rnd)) - log.Printf("rnd %v\nres %v\nobj %v\n", rnd, res, obj) + powlogger.Infof("rnd %v\nres %v\nobj %v\n", rnd, res, obj) if res.Cmp(obj) < 0 { // Post back result on the channel resChan <- rnd diff --git a/ethchain/state.go b/ethchain/state.go index a08dfac83..e28b91909 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -125,7 +125,7 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { } func (self *State) NewStateObject(addr []byte) *StateObject { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(+) %x\n", addr) + statelogger.Infof("(+) %x\n", addr) stateObject := NewStateObject(addr) self.stateObjects[string(addr)] = stateObject diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 36ba1731c..312ba3084 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -3,7 +3,7 @@ package ethchain import ( "bytes" "container/list" - "fmt" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethwire" "math/big" @@ -11,6 +11,8 @@ import ( "time" ) +var statelogger = ethlog.NewLogger("STATE") + type BlockProcessor interface { ProcessBlock(block *Block) } @@ -120,7 +122,7 @@ done: break done default: - ethutil.Config.Log.Infoln(err) + statelogger.Infoln(err) } } @@ -143,72 +145,62 @@ done: return receipts, handled, unhandled, err } -func (sm *StateManager) Process(block *Block, dontReact bool) error { - if !sm.bc.HasBlock(block.PrevHash) { - return ParentError(block.PrevHash) - } - - parent := sm.bc.GetBlock(block.PrevHash) - - return sm.ProcessBlock(parent.State(), parent, block, dontReact) - -} - -// Block processing and validating with a given (temporarily) state -func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) (err error) { +func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() - hash := block.Hash() - if sm.bc.HasBlock(hash) { + if sm.bc.HasBlock(block.Hash()) { return nil } + if !sm.bc.HasBlock(block.PrevHash) { + return ParentError(block.PrevHash) + } + + var ( + parent = sm.bc.GetBlock(block.PrevHash) + state = parent.State() + ) + // Defer the Undo on the Trie. If the block processing happened // we don't want to undo but since undo only happens on dirty // nodes this won't happen because Commit would have been called // before that. defer state.Reset() - // Check if we have the parent hash, if it isn't known we discard it - // Reasons might be catching up or simply an invalid block - if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { - return ParentError(block.PrevHash) - } - - coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.SetGasPool(block.CalcGasLimit(parent)) - - // Process the transactions on to current block - receipts, _, _, _ := sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + receipts, err := sm.ApplyDiff(state, parent, block) defer func() { if err != nil { if len(receipts) == len(block.Receipts()) { for i, receipt := range block.Receipts() { - ethutil.Config.Log.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) + statelogger.Debugf("diff (r) %v ~ %x <=> (c) %v ~ %x (%x)\n", receipt.CumulativeGasUsed, receipt.PostState[0:4], receipts[i].CumulativeGasUsed, receipts[i].PostState[0:4], receipt.Tx.Hash()) } } else { - ethutil.Config.Log.Debugln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) + statelogger.Warnln("Unable to print receipt diff. Length didn't match", len(receipts), "for", len(block.Receipts())) } } }() + if err != nil { + return err + } + // Block validation if err = sm.ValidateBlock(block); err != nil { - fmt.Println("[SM] Error validating block:", err) + statelogger.Errorln("Error validating block:", err) return err } // I'm not sure, but I don't know if there should be thrown // any errors at this time. if err = sm.AccumelateRewards(state, block); err != nil { - fmt.Println("[SM] Error accumulating reward", err) + statelogger.Errorln("Error accumulating reward", err) return err } if !block.State().Cmp(state) { - err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) + statelogger.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) return } @@ -221,7 +213,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) + statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) @@ -232,11 +224,22 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea sm.Ethereum.TxPool().RemoveInvalid(state) } else { - fmt.Println("total diff failed") + statelogger.Errorln("total diff failed") } return nil } + +func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.SetGasPool(block.CalcGasLimit(parent)) + + // Process the transactions on to current block + receipts, _, _, _ = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) + + return receipts, nil +} + func (sm *StateManager) CalculateTD(block *Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 5b64c3b37..480b4055d 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -90,7 +90,13 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - //fmt.Printf("sstore %x => %v\n", addr, val) + + if val.BigInt().Cmp(ethutil.Big0) == 0 { + c.state.trie.Delete(string(addr)) + + return + } + c.SetAddr(addr, val) } @@ -124,13 +130,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) + statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -151,7 +157,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1f5b4f959..f84c3486b 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -2,7 +2,6 @@ package ethchain import ( "fmt" - "github.com/ethereum/eth-go/ethutil" "math/big" ) @@ -135,12 +134,12 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", self.tx.Hash()) + statelogger.Infof("(~) %x\n", self.tx.Hash()) /* defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + logger.Infoln(r) err = fmt.Errorf("state transition err %v", r) } }() @@ -231,7 +230,7 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(self.value) - //ethutil.Config.Log.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) + //statelogger.Debugf("%x => %x (%v)\n", sender.Address()[:4], receiver.Address()[:4], self.value) //} return nil diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 34ab357a1..2ab681030 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -89,11 +89,12 @@ func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) PublicKey() []byte { hash := tx.Hash() - // If we don't make a copy we will overwrite the existing underlying array - dst := make([]byte, len(tx.r)) - copy(dst, tx.r) + r := make([]byte, 32-len(tx.r)) + s := make([]byte, 32-len(tx.s)) + r = append(r, ethutil.CopyBytes(tx.r)...) + s = append(s, ethutil.CopyBytes(tx.s)...) - sig := append(dst, tx.s...) + sig := append(r, s...) sig = append(sig, tx.v-27) pubkey, _ := secp256k1.RecoverPubkey(hash, sig) @@ -127,6 +128,8 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + // TODO Remove prefixing zero's + return append(data, tx.v, tx.r, tx.s) } @@ -150,6 +153,7 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 24836222a..6ab8d83d9 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -3,15 +3,15 @@ package ethchain import ( "bytes" "container/list" - "errors" "fmt" - "github.com/ethereum/eth-go/ethutil" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethwire" - "log" "math/big" "sync" ) +var txplogger = ethlog.NewLogger("TXP") + const ( txPoolQueueSize = 50 ) @@ -97,7 +97,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) + txplogger.Infoln(r) err = fmt.Errorf("%v", r) } }() @@ -156,7 +156,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract fmt.Printf("state root after receiver update %x\n", state.Root()) } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + txplogger.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) return } @@ -168,7 +168,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { block := pool.Ethereum.BlockChain().CurrentBlock // Something has gone horribly wrong if this happens if block == nil { - return errors.New("[TXPL] No last block on the block chain") + return fmt.Errorf("[TXPL] No last block on the block chain") } if len(tx.Recipient) != 20 { @@ -188,7 +188,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { if tx.IsContract() { if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { - return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + return fmt.Errorf("[TXPL] Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) } } @@ -215,12 +215,12 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - ethutil.Config.Log.Debugln("Validating Tx failed", err) + txplogger.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) @@ -282,5 +282,5 @@ func (pool *TxPool) Stop() { pool.Flush() - log.Println("[TXP] Stopped") + txplogger.Infoln("Stopped") } diff --git a/ethchain/vm.go b/ethchain/vm.go index fc3c37dc1..82591e274 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -2,11 +2,14 @@ package ethchain import ( "fmt" + "github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethutil" "math" "math/big" ) +var vmlogger = ethlog.NewLogger("VM") + var ( GasStep = big.NewInt(1) GasSha = big.NewInt(20) @@ -72,7 +75,7 @@ func (self *Vm) Printf(format string, v ...interface{}) *Vm { func (self *Vm) Endl() *Vm { if self.Verbose { - ethutil.Config.Log.Infoln(self.logStr) + vmlogger.Infoln(self.logStr) self.logStr = "" } @@ -93,28 +96,27 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if r := recover(); r != nil { ret = closure.Return(nil) err = fmt.Errorf("%v", r) - fmt.Println("vm err", err) + vmlogger.Errorln("vm err", err) } }() - ethutil.Config.Log.Debugf("[VM] (~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) + vmlogger.Debugf("(~) %x gas: %v (d) %x\n", closure.object.Address(), closure.Gas, closure.Args) - // Memory for the current closure - mem := &Memory{} - // New stack (should this be shared?) - stack := NewStack() - require := func(m int) { - if stack.Len() < m { - isRequireError = true - panic(fmt.Sprintf("stack = %d, req = %d", stack.Len(), m)) - } - } + var ( + op OpCode - // Instruction pointer - pc := big.NewInt(0) - // Current step count - step := 0 - prevStep := 0 + mem = &Memory{} + stack = NewStack() + pc = big.NewInt(0) + step = 0 + prevStep = 0 + require = func(m int) { + if stack.Len() < m { + isRequireError = true + panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m)) + } + } + ) for { prevStep = step @@ -125,7 +127,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Get the memory location of pc val := closure.Get(pc) // Get the opcode (it must be an opcode!) - op := OpCode(val.Uint()) + op = OpCode(val.Uint()) gas := new(big.Int) addStepGasUsage := func(amount *big.Int) { @@ -325,21 +327,21 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(base) case LT: require(2) - y, x := stack.Popn() - vm.Printf(" %v < %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v < %v", y, x) // x < y - if x.Cmp(y) < 0 { + if y.Cmp(x) < 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) } case GT: require(2) - y, x := stack.Popn() - vm.Printf(" %v > %v", x, y) + x, y := stack.Popn() + vm.Printf(" %v > %v", y, x) // x > y - if x.Cmp(y) > 0 { + if y.Cmp(x) > 0 { stack.Push(ethutil.BigTrue) } else { stack.Push(ethutil.BigFalse) @@ -358,10 +360,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case NOT: require(1) x := stack.Pop() - if x.Cmp(ethutil.BigFalse) == 0 { - stack.Push(ethutil.BigTrue) - } else { + if x.Cmp(ethutil.BigFalse) > 0 { stack.Push(ethutil.BigFalse) + } else { + stack.Push(ethutil.BigTrue) } // 0x10 range @@ -433,9 +435,28 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.Printf(" => %d", l) case CALLDATACOPY: - panic("not implemented") + 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: - stack.Push(big.NewInt(int64(len(closure.Script)))) + l := big.NewInt(int64(len(closure.Script))) + stack.Push(l) + + vm.Printf(" => %d", l) case CODECOPY: var ( size = int64(len(closure.Script)) @@ -501,7 +522,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case MLOAD: require(1) offset := stack.Pop() - stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) + val := ethutil.BigD(mem.Get(offset.Int64(), 32)) + stack.Push(val) + + vm.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 @@ -520,17 +544,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + stack.Push(val.BigInt()) - vm.Printf(" {} 0x%x", val) + vm.Printf(" {0x%x} 0x%x", loc.Bytes(), val.Bytes()) case SSTORE: require(2) val, loc := stack.Popn() - - // FIXME This should be handled in the Trie it self - if val.Cmp(big.NewInt(0)) != 0 { - closure.SetStorage(loc, ethutil.NewValue(val)) - } + closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) @@ -574,14 +595,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Generate a new address addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) + + vm.Printf(" (*) %x", addr).Endl() + // Create a new contract - contract := NewContract(addr, value, []byte("")) + contract := vm.state.NewStateObject(addr) + contract.Amount = value + // Set the init script - contract.initScript = mem.Get(offset.Int64(), size.Int64()) + contract.initScript = ethutil.BigD(mem.Get(offset.Int64(), size.Int64())).Bytes() // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - //closure.UseGas(gas) // Create the closure c := NewClosure(closure.caller, @@ -592,6 +617,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Price) // Call the closure and set the return value as // main script. + var err error c.Script, gas, err = c.Call(vm, nil, hook) if err != nil { @@ -619,7 +645,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro args := mem.Get(inOffset.Int64(), inSize.Int64()) if closure.object.Amount.Cmp(value) < 0 { - ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) + vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) stack.Push(ethutil.BigFalse) } else { @@ -638,7 +664,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) - ethutil.Config.Log.Debugf("Closure execution failed. %v\n", err) + vmlogger.Debugf("Closure execution failed. %v\n", err) vm.err = err vm.state.Set(snapshot) @@ -669,11 +695,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro fallthrough case STOP: // Stop the closure - vm.Printf(" (g) %v", closure.Gas).Endl() + vm.Endl() return closure.Return(nil), nil default: - ethutil.Config.Log.Debugf("Invalid opcode %x\n", op) + vmlogger.Debugf("Invalid opcode %x\n", op) return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op) } |