Changed the way transactions are being added to the transaction pool

This commit is contained in:
obscuren 2014-12-01 20:18:09 +01:00
parent a3559c5e1b
commit 6dc46d3341
15 changed files with 239 additions and 98 deletions

View File

@ -314,7 +314,30 @@ out:
// sm.eth.EventMux().Post(NewBlockEvent{block}) // sm.eth.EventMux().Post(NewBlockEvent{block})
// otherwise process and don't emit anything // otherwise process and don't emit anything
if len(blocks) > 0 { if len(blocks) > 0 {
chainManager := self.eth.ChainManager() chainman := self.eth.ChainManager()
err := chainman.InsertChain(blocks)
if err != nil {
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
for _, block := range blocks {
self.Remove(block.Hash())
}
}
/*
// Test and import // Test and import
bchain := chain.NewChain(blocks) bchain := chain.NewChain(blocks)
_, err := chainManager.TestChain(bchain) _, err := chainManager.TestChain(bchain)
@ -338,6 +361,7 @@ out:
self.Remove(block.Hash()) self.Remove(block.Hash())
} }
} }
*/
} }
} }
} }

View File

@ -246,7 +246,7 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, me
return return
} }
state.Update(nil) state.Update(ethutil.Big0)
if !block.State().Cmp(state) { if !block.State().Cmp(state) {
err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root()) err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())

View File

@ -321,6 +321,24 @@ func NewChain(blocks Blocks) *BlockChain {
return chain 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 // This function assumes you've done your checking. No checking is done at this stage anymore
func (self *ChainManager) InsertChain(chain *BlockChain) { func (self *ChainManager) InsertChain(chain *BlockChain) {
for e := chain.Front(); e != nil; e = e.Next() { 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]) 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) { func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) {
self.workingChain = chain self.workingChain = chain
defer func() { self.workingChain = nil }() defer func() { self.workingChain = nil }()
@ -381,3 +401,4 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error)
return return
} }
*/

View File

@ -79,12 +79,7 @@ func (tx *Transaction) IsContract() bool {
func (tx *Transaction) CreationAddress(state *state.State) []byte { func (tx *Transaction) CreationAddress(state *state.State) []byte {
// Generate a new address // Generate a new address
addr := crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] return 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
} }
func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) Signature(key []byte) []byte {

View File

@ -114,7 +114,6 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
} }
// Get the sender // Get the sender
//sender := pool.Ethereum.BlockManager().procState.GetAccount(tx.Sender())
sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender()) sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender())
totAmount := new(big.Int).Set(tx.Value) totAmount := new(big.Int).Set(tx.Value)
@ -136,6 +135,34 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
return nil 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() { func (pool *TxPool) queueHandler() {
out: out:
for { for {
@ -172,9 +199,11 @@ out:
} }
} }
/*
func (pool *TxPool) QueueTransaction(tx *Transaction) { func (pool *TxPool) QueueTransaction(tx *Transaction) {
pool.queueChan <- tx pool.queueChan <- tx
} }
*/
func (pool *TxPool) CurrentTransactions() []*Transaction { func (pool *TxPool) CurrentTransactions() []*Transaction {
pool.mutex.Lock() pool.mutex.Lock()

View File

@ -26,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/xeth"
) )
type plugin struct { 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 var data string
if len(recipient) == 0 { if len(recipient) == 0 {
code, err := ethutil.Compile(d, false) code, err := ethutil.Compile(d, false)
if err != nil { if err != nil {
return nil, err return "", err
} }
data = ethutil.Bytes2Hex(code) data = ethutil.Bytes2Hex(code)
} else { } else {

View File

@ -127,7 +127,11 @@ func (self *UiLib) PastPeers() *ethutil.List {
func (self *UiLib) ImportTx(rlpTx string) { func (self *UiLib) ImportTx(rlpTx string) {
tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(rlpTx)) 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) { func (self *UiLib) EvalJavascriptFile(path string) {
@ -305,7 +309,7 @@ func mapToTxParams(object map[string]interface{}) map[string]string {
return conv 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) object := mapToTxParams(params)
return self.JSXEth.Transact( return self.JSXEth.Transact(

View File

@ -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 // Big to bytes
// //
// Returns the bytes of a big integer with the size specified by **base** // Returns the bytes of a big integer with the size specified by **base**

View File

@ -203,7 +203,7 @@ func (self *Miner) mine() {
// Accumulate the rewards included for this block // Accumulate the rewards included for this block
blockManager.AccumelateRewards(block.State(), block, parent) 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)) 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) nonce := self.pow.Search(block, self.powQuitCh)
if nonce != nil { if nonce != nil {
block.Nonce = nonce block.Nonce = nonce
lchain := chain.NewChain(chain.Blocks{block}) //lchain := chain.NewChain(chain.Blocks{block})
_, err := chainMan.TestChain(lchain) //_, err := chainMan.TestChain(lchain)
err := chainMan.InsertChain(chain.Blocks{block})
if err != nil { if err != nil {
minerlogger.Infoln(err) minerlogger.Infoln(err)
} else { } else {
chainMan.InsertChain(lchain) //chainMan.InsertChain(lchain)
//self.eth.EventMux().Post(chain.NewBlockEvent{block}) //self.eth.EventMux().Post(chain.NewBlockEvent{block})
self.eth.Broadcast(wire.MsgBlockTy, []interface{}{block.Value().Val}) self.eth.Broadcast(wire.MsgBlockTy, []interface{}{block.Value().Val})

View File

@ -430,7 +430,13 @@ func (p *Peer) HandleInbound() {
// processing when a new block is found // processing when a new block is found
for i := 0; i < msg.Data.Len(); i++ { for i := 0; i < msg.Data.Len(); i++ {
tx := chain.NewTransactionFromValue(msg.Data.Get(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: case wire.MsgGetPeersTy:
// Peer asked for list of connected peers // Peer asked for list of connected peers

View File

@ -249,7 +249,6 @@ func (s *State) Reset() {
continue continue
} }
//stateObject.state.Reset()
stateObject.Reset() stateObject.Reset()
} }
@ -281,6 +280,7 @@ func (self *State) Update(gasUsed *big.Int) {
var deleted bool var deleted bool
// Refund any gas that's left // Refund any gas that's left
// XXX THIS WILL CHANGE IN POC8
uhalf := new(big.Int).Div(gasUsed, ethutil.Big2) uhalf := new(big.Int).Div(gasUsed, ethutil.Big2)
for addr, refs := range self.refund { for addr, refs := range self.refund {
for _, ref := range refs { 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.GetStateObject([]byte(addr)).AddBalance(refund.Mul(refund, ref.price))
} }
} }
self.refund = make(map[string][]refund)
for _, stateObject := range self.stateObjects { for _, stateObject := range self.stateObjects {
if stateObject.remove { if stateObject.remove {

View File

@ -214,7 +214,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error {
func (self *StateObject) SetGasPool(gasLimit *big.Int) { func (self *StateObject) SetGasPool(gasLimit *big.Int) {
self.gasPool = new(big.Int).Set(gasLimit) 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 { func (self *StateObject) BuyGas(gas, price *big.Int) error {

View File

@ -151,7 +151,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) {
// Stack checks only // Stack checks only
case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1 case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1
require(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) require(2)
case ADDMOD, MULMOD: // 3 case ADDMOD, MULMOD: // 3
require(3) require(3)
@ -169,6 +169,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) {
gas.Set(GasLog) gas.Set(GasLog)
addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
addStepGasUsage(new(big.Int).Add(mSize, mStart)) 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 // Gas only
case STOP: case STOP:
gas.Set(ethutil.Big0) gas.Set(ethutil.Big0)

View File

@ -177,7 +177,50 @@ func (self *JSXEth) FromNumber(str string) string {
return ethutil.BigD(ethutil.Hex2Bytes(str)).String() return ethutil.BigD(ethutil.Hex2Bytes(str)).String()
} }
func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (*JSReceipt, error) { 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 {
data = ethutil.Hex2Bytes(codeStr)
}
if ethutil.IsHex(toStr) {
to = ethutil.Hex2Bytes(toStr[2:])
} else {
to = ethutil.Hex2Bytes(toStr)
}
var keyPair *crypto.KeyPair
var err error
if ethutil.IsHex(key) {
keyPair, err = crypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:])))
} else {
keyPair, err = crypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key)))
}
if err != nil {
return "", err
}
tx, err := self.XEth.Transact(keyPair, to, value, gas, gasPrice, data)
if err != nil {
return "", err
}
if chain.IsContractAddr(to) {
return ethutil.Bytes2Hex(tx.CreationAddress(nil)), nil
}
return ethutil.Bytes2Hex(tx.Hash()), nil
/*
var hash []byte var hash []byte
var contractCreation bool var contractCreation bool
if len(toStr) == 0 { if len(toStr) == 0 {
@ -192,17 +235,6 @@ func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr
} }
} }
var keyPair *crypto.KeyPair
var err error
if ethutil.IsHex(key) {
keyPair, err = crypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:])))
} else {
keyPair, err = crypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key)))
}
if err != nil {
return nil, err
}
var ( var (
value = ethutil.Big(valueStr) value = ethutil.Big(valueStr)
@ -237,11 +269,15 @@ func (self *JSXEth) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr
} }
return NewJSReciept(contractCreation, tx.CreationAddress(self.World().State()), tx.Hash(), keyPair.Address()), nil return NewJSReciept(contractCreation, tx.CreationAddress(self.World().State()), tx.Hash(), keyPair.Address()), nil
*/
} }
func (self *JSXEth) PushTx(txStr string) (*JSReceipt, error) { func (self *JSXEth) PushTx(txStr string) (*JSReceipt, error) {
tx := chain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) 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 return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(self.World().State()), tx.Hash(), tx.Sender()), nil
} }

View File

@ -6,7 +6,6 @@ package xeth
import ( import (
"fmt" "fmt"
"strings"
"github.com/ethereum/go-ethereum/chain" "github.com/ethereum/go-ethereum/chain"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -93,7 +92,7 @@ func (self *XEth) Exists(addr []byte) bool {
return self.World().Get(addr) != nil 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 // Check if an address is stored by this address
var hash []byte var hash []byte
addr := self.World().Config().Get("NameReg").StorageString(rec).Bytes() 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) 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 hash []byte
var contractCreation bool var contractCreation bool
if rec == nil { if chain.IsContractAddr(to) {
contractCreation = true 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 var tx *chain.Transaction
// Compile and assemble the given data
if contractCreation { if contractCreation {
script, err := ethutil.Compile(string(data), false) tx = chain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), data)
} else {
tx = chain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data)
}
state := self.blockManager.TransState()
nonce := state.GetNonce(key.Address())
tx.Nonce = nonce
tx.Sign(key.PrivateKey)
err := self.obj.TxPool().Add(tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tx = chain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) state.SetNonce(key.Address(), nonce+1)
} 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)
tx.Sign(key.PrivateKey)
self.obj.TxPool().QueueTransaction(tx)
if contractCreation { if contractCreation {
addr := tx.CreationAddress(self.World().State()) addr := tx.CreationAddress(self.World().State())
pipelogger.Infof("Contract addr %x\n", addr) 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) { 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 { if tx.Recipient == nil {
addr := tx.CreationAddress(self.World().State()) addr := tx.CreationAddress(self.World().State())
pipelogger.Infof("Contract addr %x\n", addr) pipelogger.Infof("Contract addr %x\n", addr)