From 6dc46d3341dc5fa25bd005f9606de258874139be Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 1 Dec 2014 20:18:09 +0100 Subject: [PATCH] Changed the way transactions are being added to the transaction pool --- block_pool.go | 38 +++++++++--- chain/block_manager.go | 2 +- chain/chain_manager.go | 21 +++++++ chain/transaction.go | 7 +-- chain/transaction_pool.go | 31 +++++++++- cmd/mist/bindings.go | 5 +- cmd/mist/ui_lib.go | 8 ++- ethutil/big.go | 10 ++++ miner/miner.go | 9 +-- peer.go | 8 ++- state/state.go | 3 +- state/state_object.go | 2 +- vm/vm_debug.go | 11 +++- xeth/hexface.go | 118 +++++++++++++++++++++++++------------- xeth/pipe.go | 64 +++++++++++---------- 15 files changed, 239 insertions(+), 98 deletions(-) diff --git a/block_pool.go b/block_pool.go index 090871fd38..69c7a54de6 100644 --- a/block_pool.go +++ b/block_pool.go @@ -314,11 +314,10 @@ out: // sm.eth.EventMux().Post(NewBlockEvent{block}) // otherwise process and don't emit anything if len(blocks) > 0 { - chainManager := self.eth.ChainManager() - // Test and import - bchain := chain.NewChain(blocks) - _, err := chainManager.TestChain(bchain) - if err != nil && !chain.IsTDError(err) { + chainman := self.eth.ChainManager() + + err := chainman.InsertChain(blocks) + if err != nil { poollogger.Debugln(err) self.Reset() @@ -332,12 +331,37 @@ out: self.peer.StopWithReason(DiscBadPeer) self.td = ethutil.Big0 self.peer = nil - } else { - chainManager.InsertChain(bchain) + for _, block := range blocks { self.Remove(block.Hash()) } } + + /* + // Test and import + bchain := chain.NewChain(blocks) + _, err := chainManager.TestChain(bchain) + if err != nil && !chain.IsTDError(err) { + poollogger.Debugln(err) + + self.Reset() + + if self.peer != nil && self.peer.conn != nil { + poollogger.Debugf("Punishing peer for supplying bad chain (%v)\n", self.peer.conn.RemoteAddr()) + } + + // This peer gave us bad hashes and made us fetch a bad chain, therefor he shall be punished. + self.eth.BlacklistPeer(self.peer) + self.peer.StopWithReason(DiscBadPeer) + self.td = ethutil.Big0 + self.peer = nil + } else { + chainManager.InsertChain(bchain) + for _, block := range blocks { + self.Remove(block.Hash()) + } + } + */ } } } diff --git a/chain/block_manager.go b/chain/block_manager.go index fdb221cc3a..4d8d8dae68 100644 --- a/chain/block_manager.go +++ b/chain/block_manager.go @@ -246,7 +246,7 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, me return } - state.Update(nil) + state.Update(ethutil.Big0) if !block.State().Cmp(state) { err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root()) diff --git a/chain/chain_manager.go b/chain/chain_manager.go index 0c3a7a9289..75c8b22a27 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -321,6 +321,24 @@ func NewChain(blocks Blocks) *BlockChain { return chain } +// This function assumes you've done your checking. No checking is done at this stage anymore +func (self *ChainManager) InsertChain(chain Blocks) error { + for _, block := range chain { + td, messages, err := self.Ethereum.BlockManager().Process(block) + if err != nil { + return err + } + + self.add(block) + self.SetTotalDifficulty(td) + self.Ethereum.EventMux().Post(NewBlockEvent{block}) + self.Ethereum.EventMux().Post(messages) + } + + return nil +} + +/* // This function assumes you've done your checking. No checking is done at this stage anymore func (self *ChainManager) InsertChain(chain *BlockChain) { for e := chain.Front(); e != nil; e = e.Next() { @@ -338,7 +356,9 @@ func (self *ChainManager) InsertChain(chain *BlockChain) { chainlogger.Infof("Imported %d blocks. #%v (%x) / %#v (%x)", chain.Len(), front.Number, front.Hash()[0:4], back.Number, back.Hash()[0:4]) } } +*/ +/* func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) { self.workingChain = chain defer func() { self.workingChain = nil }() @@ -381,3 +401,4 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) return } +*/ diff --git a/chain/transaction.go b/chain/transaction.go index d81a0ea1b6..47257a3f0e 100644 --- a/chain/transaction.go +++ b/chain/transaction.go @@ -79,12 +79,7 @@ func (tx *Transaction) IsContract() bool { func (tx *Transaction) CreationAddress(state *state.State) []byte { // Generate a new address - addr := crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] - //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { - // addr = crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] - //} - - return addr + return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } func (tx *Transaction) Signature(key []byte) []byte { diff --git a/chain/transaction_pool.go b/chain/transaction_pool.go index ff75089d65..fbf8821639 100644 --- a/chain/transaction_pool.go +++ b/chain/transaction_pool.go @@ -114,7 +114,6 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { } // Get the sender - //sender := pool.Ethereum.BlockManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender()) totAmount := new(big.Int).Set(tx.Value) @@ -136,6 +135,34 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return nil } +func (self *TxPool) Add(tx *Transaction) error { + hash := tx.Hash() + foundTx := FindTx(self.pool, func(tx *Transaction, e *list.Element) bool { + return bytes.Compare(tx.Hash(), hash) == 0 + }) + + if foundTx != nil { + return fmt.Errorf("Known transaction (%x)", hash[0:4]) + } + + err := self.ValidateTransaction(tx) + if err != nil { + return err + } + + self.addTransaction(tx) + + tmp := make([]byte, 4) + copy(tmp, tx.Recipient) + + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) + + // Notify the subscribers + self.Ethereum.EventMux().Post(TxPreEvent{tx}) + + return nil +} + func (pool *TxPool) queueHandler() { out: for { @@ -172,9 +199,11 @@ out: } } +/* func (pool *TxPool) QueueTransaction(tx *Transaction) { pool.queueChan <- tx } +*/ func (pool *TxPool) CurrentTransactions() []*Transaction { pool.mutex.Lock() diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index 480c38b2ef..cd139c67f8 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/xeth" ) type plugin struct { @@ -46,12 +45,12 @@ func (gui *Gui) LogPrint(level logger.LogLevel, msg string) { } */ } -func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (*xeth.JSReceipt, error) { +func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, error) { var data string if len(recipient) == 0 { code, err := ethutil.Compile(d, false) if err != nil { - return nil, err + return "", err } data = ethutil.Bytes2Hex(code) } else { diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index 4e480144f1..15799eb6a0 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -127,7 +127,11 @@ func (self *UiLib) PastPeers() *ethutil.List { func (self *UiLib) ImportTx(rlpTx string) { tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) - self.eth.TxPool().QueueTransaction(tx) + //self.eth.TxPool().QueueTransaction(tx) + err := self.eth.TxPool().Add(tx) + if err != nil { + guilogger.Infoln("import tx failed ", err) + } } func (self *UiLib) EvalJavascriptFile(path string) { @@ -305,7 +309,7 @@ func mapToTxParams(object map[string]interface{}) map[string]string { return conv } -func (self *UiLib) Transact(params map[string]interface{}) (*xeth.JSReceipt, error) { +func (self *UiLib) Transact(params map[string]interface{}) (string, error) { object := mapToTxParams(params) return self.JSXEth.Transact( diff --git a/ethutil/big.go b/ethutil/big.go index 07d1386e18..d4f6361e9a 100644 --- a/ethutil/big.go +++ b/ethutil/big.go @@ -62,6 +62,16 @@ func S256(x *big.Int) *big.Int { } } +func FirstBitSet(v *big.Int) *big.Int { + for i := 0; i < v.BitLen(); i++ { + if v.Bit(i) > 0 { + return big.NewInt(int64(i)) + } + } + + return big.NewInt(int64(v.BitLen())) +} + // Big to bytes // // Returns the bytes of a big integer with the size specified by **base** diff --git a/miner/miner.go b/miner/miner.go index 9152d532b2..6fe5a18ac0 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -203,7 +203,7 @@ func (self *Miner) mine() { // Accumulate the rewards included for this block blockManager.AccumelateRewards(block.State(), block, parent) - block.State().Update(nil) + block.State().Update(ethutil.Big0) minerlogger.Infof("Mining on block. Includes %v transactions", len(transactions)) @@ -211,12 +211,13 @@ func (self *Miner) mine() { nonce := self.pow.Search(block, self.powQuitCh) if nonce != nil { block.Nonce = nonce - lchain := chain.NewChain(chain.Blocks{block}) - _, err := chainMan.TestChain(lchain) + //lchain := chain.NewChain(chain.Blocks{block}) + //_, err := chainMan.TestChain(lchain) + err := chainMan.InsertChain(chain.Blocks{block}) if err != nil { minerlogger.Infoln(err) } else { - chainMan.InsertChain(lchain) + //chainMan.InsertChain(lchain) //self.eth.EventMux().Post(chain.NewBlockEvent{block}) self.eth.Broadcast(wire.MsgBlockTy, []interface{}{block.Value().Val}) diff --git a/peer.go b/peer.go index 86423c816d..1b5f47f115 100644 --- a/peer.go +++ b/peer.go @@ -430,7 +430,13 @@ func (p *Peer) HandleInbound() { // processing when a new block is found for i := 0; i < msg.Data.Len(); i++ { tx := chain.NewTransactionFromValue(msg.Data.Get(i)) - p.ethereum.TxPool().QueueTransaction(tx) + err := p.ethereum.TxPool().Add(tx) + if err != nil { + peerlogger.Infoln(err) + } else { + peerlogger.Infof("tx OK (%x)\n", tx.Hash()[0:4]) + } + //p.ethereum.TxPool().QueueTransaction(tx) } case wire.MsgGetPeersTy: // Peer asked for list of connected peers diff --git a/state/state.go b/state/state.go index 0a7f717fee..732a1192b4 100644 --- a/state/state.go +++ b/state/state.go @@ -249,7 +249,6 @@ func (s *State) Reset() { continue } - //stateObject.state.Reset() stateObject.Reset() } @@ -281,6 +280,7 @@ func (self *State) Update(gasUsed *big.Int) { var deleted bool // Refund any gas that's left + // XXX THIS WILL CHANGE IN POC8 uhalf := new(big.Int).Div(gasUsed, ethutil.Big2) for addr, refs := range self.refund { for _, ref := range refs { @@ -289,6 +289,7 @@ func (self *State) Update(gasUsed *big.Int) { self.GetStateObject([]byte(addr)).AddBalance(refund.Mul(refund, ref.price)) } } + self.refund = make(map[string][]refund) for _, stateObject := range self.stateObjects { if stateObject.remove { diff --git a/state/state_object.go b/state/state_object.go index 5ce74c434a..8aa1267859 100644 --- a/state/state_object.go +++ b/state/state_object.go @@ -214,7 +214,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool) + statelogger.Debugf("%x: gas (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { diff --git a/vm/vm_debug.go b/vm/vm_debug.go index ae5a201759..18d3018a0f 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -151,7 +151,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack checks only case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 require(1) - case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 + case ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) case ADDMOD, MULMOD: // 3 require(3) @@ -169,6 +169,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { gas.Set(GasLog) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Add(mSize, mStart)) + case EXP: + require(2) + + expGas := ethutil.FirstBitSet(stack.data[stack.Len()-2]) + expGas.Div(expGas, u256(8)) + expGas.Sub(u256(32), expGas) + expGas.Add(expGas, u256(1)) + + gas.Set(expGas) // Gas only case STOP: gas.Set(ethutil.Big0) diff --git a/xeth/hexface.go b/xeth/hexface.go index 5ef3eaf1a3..31685403de 100644 --- a/xeth/hexface.go +++ b/xeth/hexface.go @@ -177,19 +177,25 @@ func (self *JSXEth) FromNumber(str string) string { return ethutil.BigD(ethutil.Hex2Bytes(str)).String() } -func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (*JSReceipt, error) { - var hash []byte - var contractCreation bool - if len(toStr) == 0 { - contractCreation = true +func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { + var ( + to []byte + value = ethutil.NewValue(valueStr) + gas = ethutil.NewValue(gasStr) + gasPrice = ethutil.NewValue(gasPriceStr) + data []byte + ) + + if ethutil.IsHex(codeStr) { + data = ethutil.Hex2Bytes(codeStr[2:]) } else { - // Check if an address is stored by this address - addr := self.World().Config().Get("NameReg").StorageString(toStr).Bytes() - if len(addr) > 0 { - hash = addr - } else { - hash = ethutil.Hex2Bytes(toStr) - } + data = ethutil.Hex2Bytes(codeStr) + } + + if ethutil.IsHex(toStr) { + to = ethutil.Hex2Bytes(toStr[2:]) + } else { + to = ethutil.Hex2Bytes(toStr) } var keyPair *crypto.KeyPair @@ -201,47 +207,77 @@ func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr } if err != nil { - return nil, err + return "", err } - var ( - value = ethutil.Big(valueStr) - gas = ethutil.Big(gasStr) - gasPrice = ethutil.Big(gasPriceStr) - data []byte - tx *chain.Transaction - ) - - if ethutil.IsHex(codeStr) { - data = ethutil.Hex2Bytes(codeStr[2:]) - } else { - data = ethutil.Hex2Bytes(codeStr) + tx, err := self.XEth.Transact(keyPair, to, value, gas, gasPrice, data) + if err != nil { + return "", err } - - if contractCreation { - tx = chain.NewContractCreationTx(value, gas, gasPrice, data) - } else { - tx = chain.NewTransactionMessage(hash, value, gas, gasPrice, data) + if chain.IsContractAddr(to) { + return ethutil.Bytes2Hex(tx.CreationAddress(nil)), nil } - acc := self.obj.BlockManager().TransState().GetOrNewStateObject(keyPair.Address()) - tx.Nonce = acc.Nonce - acc.Nonce += 1 - self.obj.BlockManager().TransState().UpdateStateObject(acc) + return ethutil.Bytes2Hex(tx.Hash()), nil + + /* + var hash []byte + var contractCreation bool + if len(toStr) == 0 { + contractCreation = true + } else { + // Check if an address is stored by this address + addr := self.World().Config().Get("NameReg").StorageString(toStr).Bytes() + if len(addr) > 0 { + hash = addr + } else { + hash = ethutil.Hex2Bytes(toStr) + } + } + - tx.Sign(keyPair.PrivateKey) - self.obj.TxPool().QueueTransaction(tx) + var ( + value = ethutil.Big(valueStr) + gas = ethutil.Big(gasStr) + gasPrice = ethutil.Big(gasPriceStr) + data []byte + tx *chain.Transaction + ) - if contractCreation { - pipelogger.Infof("Contract addr %x", tx.CreationAddress(self.World().State())) - } + if ethutil.IsHex(codeStr) { + data = ethutil.Hex2Bytes(codeStr[2:]) + } else { + data = ethutil.Hex2Bytes(codeStr) + } - return NewJSReciept(contractCreation, tx.CreationAddress(self.World().State()), tx.Hash(), keyPair.Address()), nil + if contractCreation { + tx = chain.NewContractCreationTx(value, gas, gasPrice, data) + } else { + tx = chain.NewTransactionMessage(hash, value, gas, gasPrice, data) + } + + acc := self.obj.BlockManager().TransState().GetOrNewStateObject(keyPair.Address()) + tx.Nonce = acc.Nonce + acc.Nonce += 1 + self.obj.BlockManager().TransState().UpdateStateObject(acc) + + tx.Sign(keyPair.PrivateKey) + self.obj.TxPool().QueueTransaction(tx) + + if contractCreation { + pipelogger.Infof("Contract addr %x", tx.CreationAddress(self.World().State())) + } + + return NewJSReciept(contractCreation, tx.CreationAddress(self.World().State()), tx.Hash(), keyPair.Address()), nil + */ } func (self *JSXEth) PushTx(txStr string) (*JSReceipt, error) { tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) - self.obj.TxPool().QueueTransaction(tx) + err := self.obj.TxPool().Add(tx) + if err != nil { + return nil, err + } return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(self.World().State()), tx.Hash(), tx.Sender()), nil } diff --git a/xeth/pipe.go b/xeth/pipe.go index abed8ef9a9..6e2f325c5a 100644 --- a/xeth/pipe.go +++ b/xeth/pipe.go @@ -6,7 +6,6 @@ package xeth import ( "fmt" - "strings" "github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/crypto" @@ -93,7 +92,7 @@ func (self *XEth) Exists(addr []byte) bool { return self.World().Get(addr) != nil } -func (self *XEth) TransactString(key *crypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { +func (self *XEth) TransactString(key *crypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) (*chain.Transaction, error) { // Check if an address is stored by this address var hash []byte addr := self.World().Config().Get("NameReg").StorageString(rec).Bytes() @@ -108,55 +107,62 @@ func (self *XEth) TransactString(key *crypto.KeyPair, rec string, value, gas, pr return self.Transact(key, hash, value, gas, price, data) } -func (self *XEth) Transact(key *crypto.KeyPair, rec []byte, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { +func (self *XEth) Transact(key *crypto.KeyPair, to []byte, value, gas, price *ethutil.Value, data []byte) (*chain.Transaction, error) { var hash []byte var contractCreation bool - if rec == nil { + if chain.IsContractAddr(to) { contractCreation = true + } else { + // Check if an address is stored by this address + addr := self.World().Config().Get("NameReg").Storage(to).Bytes() + if len(addr) > 0 { + hash = addr + } else { + hash = to + } } var tx *chain.Transaction - // Compile and assemble the given data if contractCreation { - script, err := ethutil.Compile(string(data), false) - if err != nil { - return nil, err - } - - tx = chain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) + tx = chain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), data) } else { - data := ethutil.StringToByteFunc(string(data), func(s string) (ret []byte) { - slice := strings.Split(s, "\n") - for _, dataItem := range slice { - d := ethutil.FormatData(dataItem) - ret = append(ret, d...) - } - return - }) - tx = chain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data) } - acc := self.blockManager.TransState().GetOrNewStateObject(key.Address()) - tx.Nonce = acc.Nonce - acc.Nonce += 1 - self.blockManager.TransState().UpdateStateObject(acc) + state := self.blockManager.TransState() + nonce := state.GetNonce(key.Address()) + tx.Nonce = nonce tx.Sign(key.PrivateKey) - self.obj.TxPool().QueueTransaction(tx) + err := self.obj.TxPool().Add(tx) + if err != nil { + return nil, err + } + + state.SetNonce(key.Address(), nonce+1) if contractCreation { addr := tx.CreationAddress(self.World().State()) pipelogger.Infof("Contract addr %x\n", addr) - - return addr, nil } - return tx.Hash(), nil + return tx, nil + + //acc := self.blockManager.TransState().GetOrNewStateObject(key.Address()) + //self.obj.TxPool().QueueTransaction(tx) + + //acc.Nonce += 1 + //self.blockManager.TransState().UpdateStateObject(acc) + } func (self *XEth) PushTx(tx *chain.Transaction) ([]byte, error) { - self.obj.TxPool().QueueTransaction(tx) + err := self.obj.TxPool().Add(tx) + if err != nil { + return nil, err + } + + //self.obj.TxPool().QueueTransaction(tx) if tx.Recipient == nil { addr := tx.CreationAddress(self.World().State()) pipelogger.Infof("Contract addr %x\n", addr)