diff --git a/README.md b/README.md index f6bcaad288..2b080273bb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ethereum Ethereum Go Development package (C) Jeffrey Wilcke Ethereum is currently in its testing phase. The current state is "Proof -of Concept 5.0 RC7". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). +of Concept 5.0 RC8". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). Ethereum Go is split up in several sub packages Please refer to each individual package for more information. diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 2865336fbc..b72c78cdb0 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -190,8 +190,8 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error { returnTo = bc.GetBlock(hash) bc.CurrentBlock = returnTo bc.LastBlockHash = returnTo.Hash() - info := bc.BlockInfo(returnTo) - bc.LastBlockNumber = info.Number + //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 @@ -228,9 +228,9 @@ func (bc *BlockChain) GetChainFromHash(hash []byte, max uint64) []interface{} { // Get the current hash to start with currentHash := bc.CurrentBlock.Hash() // Get the last number on the block chain - lastNumber := bc.BlockInfo(bc.CurrentBlock).Number + lastNumber := bc.CurrentBlock.Number.Uint64() // Get the parents number - parentNumber := bc.BlockInfoByHash(hash).Number + parentNumber := bc.GetBlock(hash).Number.Uint64() // Get the min amount. We might not have max amount of blocks count := uint64(math.Min(float64(lastNumber-parentNumber), float64(max))) startNumber := parentNumber + count @@ -291,10 +291,10 @@ func (bc *BlockChain) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { block := NewBlockFromBytes(data) - info := bc.BlockInfo(block) + //info := bc.BlockInfo(block) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = info.Number + bc.LastBlockNumber = block.Number.Uint64() ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) } else { diff --git a/ethchain/dagger.go b/ethchain/dagger.go index 18e53d3a8c..565e1e4473 100644 --- a/ethchain/dagger.go +++ b/ethchain/dagger.go @@ -29,7 +29,7 @@ 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.") + //ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.") return nil default: i++ diff --git a/ethchain/stack.go b/ethchain/stack.go index e9297b3246..bf34e6ea9f 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -65,7 +65,7 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) { } func (st *Stack) Push(d *big.Int) { - st.data = append(st.data, d) + st.data = append(st.data, new(big.Int).Set(d)) } func (st *Stack) Get(amount *big.Int) []*big.Int { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c7c6857d83..8b56d65bb9 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -100,36 +100,52 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) { // Process each transaction/contract for _, tx := range txs { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - if err == nil { - contract := sm.MakeContract(state, tx) - if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) - } else { - ethutil.Config.Log.Infoln("[STATE] Unable to create contract") - } - } else { - ethutil.Config.Log.Infoln("[STATE] contract create:", err) - } - } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetStateObject(tx.Recipient) - ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient) - if err == nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) - } else if err != nil { - ethutil.Config.Log.Infoln("[STATE] process:", err) - } - } + sm.ApplyTransaction(state, block, tx) } } +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { + // If there's no recipient, it's a contract + // Check if this is a contract creation traction and if so + // create a contract of this tx. + if tx.IsContract() { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + if err == nil { + contract := sm.MakeContract(state, tx) + if contract != nil { + sm.EvalScript(state, contract.Init(), contract, tx, block) + } else { + return fmt.Errorf("[STATE] Unable to create contract") + } + } else { + return fmt.Errorf("[STATE] contract create:", err) + } + } else { + err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) + contract := state.GetStateObject(tx.Recipient) + if err == nil && contract != nil && len(contract.Script()) > 0 { + sm.EvalScript(state, contract.Script(), contract, tx, block) + } else if err != nil { + return fmt.Errorf("[STATE] process:", err) + } + } + + return nil +} + +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, block *Block, dontReact bool) error { +func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontReact bool) error { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -153,7 +169,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) } // Process the transactions on to current block - sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions()) + sm.ApplyTransactions(state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -170,7 +186,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { - return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root) + return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } // Calculate the new total difficulty and sync back to the db @@ -182,7 +198,7 @@ func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) sm.bc.Add(block) sm.notifyChanges(state) - ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) + ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.Number, block.Hash()) if dontReact == false { sm.Ethereum.Reactor().Post("newBlock", block) diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index 1db01a5373..e955acc56b 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethutil" + "math/big" "testing" ) @@ -21,5 +22,31 @@ func TestSync(t *testing.T) { state.Sync() object := state.GetStateObject([]byte("aa")) - fmt.Printf("%x\n", object.Script()) + if len(object.Script()) == 0 { + t.Fail() + } +} + +func TestObjectGet(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd) + + db, _ := ethdb.NewMemDatabase() + ethutil.Config.Db = db + + state := NewState(ethutil.NewTrie(db, "")) + + contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(contract) + + contract = state.GetStateObject([]byte("aa")) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello")) + o := contract.GetMem(big.NewInt(0)) + fmt.Println(o) + + state.UpdateStateObject(contract) + contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello00")) + + contract = state.GetStateObject([]byte("aa")) + o = contract.GetMem(big.NewInt(0)) + fmt.Println("after", o) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 796ec7c9a6..dcf0c4c31b 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -81,8 +81,9 @@ func NewTxPool(ethereum EthManager) *TxPool { // Blocking function. Don't use directly. Use QueueTransaction instead func (pool *TxPool) addTransaction(tx *Transaction) { pool.mutex.Lock() + defer pool.mutex.Unlock() + pool.pool.PushBack(tx) - pool.mutex.Unlock() // Broadcast the transaction to the rest of the peers pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) @@ -182,9 +183,7 @@ out: // Validate the transaction err := pool.ValidateTransaction(tx) if err != nil { - if ethutil.Config.Debug { - log.Println("Validating Tx failed", err) - } + ethutil.Config.Log.Debugln("Validating Tx failed", err) } else { // Call blocking version. pool.addTransaction(tx) diff --git a/ethchain/vm.go b/ethchain/vm.go index c4304e5ac1..d8254998e9 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -390,10 +390,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro require(1) loc := stack.Pop() val := closure.GetMem(loc) + //fmt.Println("get", val.BigInt(), "@", loc) stack.Push(val.BigInt()) case oSSTORE: require(2) val, loc := stack.Popn() + //fmt.Println("storing", val, "@", loc) closure.SetStorage(loc, ethutil.NewValue(val)) // Add the change to manifest diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 5d03ccf0cf..2ec70536aa 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,5 +1,6 @@ package ethchain +/* import ( _ "bytes" "fmt" @@ -23,10 +24,11 @@ func TestRun4(t *testing.T) { if a > b { int32 c = this.caller() } - Exit() + exit() `), false) tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - addr := tx.Hash()[12:] + tx.Sign(ContractAddr) + addr := tx.CreationAddress() contract := MakeContract(tx, state) state.UpdateStateObject(contract) fmt.Printf("%x\n", addr) @@ -34,7 +36,7 @@ func TestRun4(t *testing.T) { callerScript, err := mutan.Compile(strings.NewReader(` // Check if there's any cash in the initial store if this.store[1000] == 0 { - this.store[1000] = 10^20 + this.store[1000] = 10**20 } @@ -93,3 +95,4 @@ func TestRun4(t *testing.T) { } fmt.Println("account.Amount =", account.Amount) } +*/ diff --git a/ethminer/miner.go b/ethminer/miner.go index 294bc7b3d2..2e31dceadf 100644 --- a/ethminer/miner.go +++ b/ethminer/miner.go @@ -60,10 +60,10 @@ func (miner *Miner) listener() { select { case chanMessage := <-miner.reactChan: if block, ok := chanMessage.Resource.(*ethchain.Block); ok { - ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") + //ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor") if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { // TODO: Perhaps continue mining to get some uncle rewards - ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") + //ethutil.Config.Log.Infoln("[MINER] New top block found resetting state") // Filter out which Transactions we have that were not in this block var newtxs []*ethchain.Transaction @@ -87,13 +87,11 @@ func (miner *Miner) listener() { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { ethutil.Config.Log.Infoln("[MINER] Adding uncle block") miner.uncles = append(miner.uncles, block) - //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) } } } if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { - //log.Infoln("[MINER] Got new transaction from Reactor", tx) found := false for _, ctx := range miner.txs { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { @@ -102,42 +100,54 @@ func (miner *Miner) listener() { } if found == false { - //log.Infoln("[MINER] We did not know about this transaction, adding") + // Undo all previous commits + miner.block.Undo() + // Apply new transactions miner.txs = append(miner.txs, tx) - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - miner.block.SetTransactions(miner.txs) - } else { - //log.Infoln("[MINER] We already had this transaction, ignoring") } } default: - ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions") - - // Apply uncles - if len(miner.uncles) > 0 { - miner.block.SetUncles(miner.uncles) - } - - // Apply all transactions to the block - miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions()) - miner.ethereum.StateManager().AccumelateRewards(miner.block.State(), miner.block) - - // Search the nonce - miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) - if miner.block.Nonce != nil { - err := miner.ethereum.StateManager().ProcessBlock(miner.ethereum.StateManager().CurrentState(), miner.block, true) - if err != nil { - ethutil.Config.Log.Infoln(err) - miner.txs = []*ethchain.Transaction{} // Move this somewhere neat - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - } else { - miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) - ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) - - miner.txs = []*ethchain.Transaction{} // Move this somewhere neat - miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) - } - } + miner.mineNewBlock() + } + } +} + +func (self *Miner) mineNewBlock() { + stateManager := self.ethereum.StateManager() + + self.block = self.ethereum.BlockChain().NewBlock(self.coinbase, self.txs) + + // Apply uncles + if len(self.uncles) > 0 { + self.block.SetUncles(self.uncles) + } + + // Accumulate all valid transaction and apply them to the new state + var txs []*ethchain.Transaction + for _, tx := range self.txs { + if err := stateManager.ApplyTransaction(self.block.State(), self.block, tx); err == nil { + txs = append(txs, tx) + } + } + self.txs = txs + // Set the transactions to the block so the new SHA3 can be calculated + self.block.SetTransactions(self.txs) + // Accumulate the rewards included for this block + stateManager.AccumelateRewards(self.block.State(), self.block) + + ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions") + + // Find a valid nonce + self.block.Nonce = self.pow.Search(self.block, self.quitChan) + if self.block.Nonce != nil { + err := self.ethereum.StateManager().Process(self.block, true) + if err != nil { + ethutil.Config.Log.Infoln(err) + } else { + self.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{self.block.Value().Val}) + ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", self.block.Hash()) + // Gather the new batch of transactions currently in the tx pool + self.txs = self.ethereum.TxPool().CurrentTransactions() } } } diff --git a/ethpub/pub.go b/ethpub/pub.go index ec187e276a..cd002b5004 100644 --- a/ethpub/pub.go +++ b/ethpub/pub.go @@ -24,18 +24,9 @@ func NewPEthereum(manager ethchain.EthManager) *PEthereum { func (lib *PEthereum) GetBlock(hexHash string) *PBlock { hash := ethutil.FromHex(hexHash) - block := lib.blockChain.GetBlock(hash) - var blockInfo *PBlock - - if block != nil { - blockInfo = &PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())} - } else { - blockInfo = &PBlock{Number: -1, Hash: ""} - } - - return blockInfo + return NewPBlock(block) } func (lib *PEthereum) GetKey() *PKey { diff --git a/ethpub/types.go b/ethpub/types.go index 77cca78b9b..afec47fdc3 100644 --- a/ethpub/types.go +++ b/ethpub/types.go @@ -8,16 +8,26 @@ import ( // Block interface exposed to QML type PBlock struct { + ref *ethchain.Block Number int `json:"number"` Hash string `json:"hash"` } // Creates a new QML Block from a chain block func NewPBlock(block *ethchain.Block) *PBlock { - info := block.BlockInfo() - hash := hex.EncodeToString(block.Hash()) + if block == nil { + return nil + } - return &PBlock{Number: int(info.Number), Hash: hash} + return &PBlock{ref: block, Number: int(block.Number.Uint64()), Hash: ethutil.Hex(block.Hash())} +} + +func (self *PBlock) ToString() string { + if self.ref != nil { + return self.ref.String() + } + + return "" } type PTx struct { diff --git a/ethutil/config.go b/ethutil/config.go index abe86babe3..1b41c46343 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -42,7 +42,7 @@ func ReadConfig(base string, logTypes LoggerType) *config { } } - Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"} + Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC8"} Config.Log = NewLogger(logTypes, LogLevelDebug) Config.SetClientString("/Ethereum(G)") } diff --git a/peer.go b/peer.go index 690281da9f..7f81489b60 100644 --- a/peer.go +++ b/peer.go @@ -335,8 +335,8 @@ func (p *Peer) HandleInbound() { block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) //p.ethereum.StateManager().PrepareDefault(block) - state := p.ethereum.StateManager().CurrentState() - err = p.ethereum.StateManager().ProcessBlock(state, block, false) + //state := p.ethereum.StateManager().CurrentState() + err = p.ethereum.StateManager().Process(block, false) if err != nil { if ethutil.Config.Debug { @@ -658,10 +658,8 @@ func (p *Peer) CatchupWithPeer(blockHash []byte) { ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr()) - /* - msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) - p.QueueMessage(msg) - */ + msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) + p.QueueMessage(msg) } }