Browse Source

Changed the way transactions are being added to the transaction pool

obscuren 11 years ago
parent
commit
6dc46d3341
15 changed files with 239 additions and 98 deletions
  1. 31 7
      block_pool.go
  2. 1 1
      chain/block_manager.go
  3. 21 0
      chain/chain_manager.go
  4. 1 6
      chain/transaction.go
  5. 30 1
      chain/transaction_pool.go
  6. 2 3
      cmd/mist/bindings.go
  7. 6 2
      cmd/mist/ui_lib.go
  8. 10 0
      ethutil/big.go
  9. 5 4
      miner/miner.go
  10. 7 1
      peer.go
  11. 2 1
      state/state.go
  12. 1 1
      state/state_object.go
  13. 10 1
      vm/vm_debug.go
  14. 77 41
      xeth/hexface.go
  15. 35 29
      xeth/pipe.go

+ 31 - 7
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())
+						}
+					}
+				*/
 			}
 		}
 	}

+ 1 - 1
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())

+ 21 - 0
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
 }
+*/

+ 1 - 6
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 {

+ 30 - 1
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()

+ 2 - 3
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 {

+ 6 - 2
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(

+ 10 - 0
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**

+ 5 - 4
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})
 

+ 7 - 1
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

+ 2 - 1
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 {

+ 1 - 1
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 {

+ 10 - 1
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)

+ 77 - 41
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
 }
 

+ 35 - 29
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)