aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaran <maran.hidskes@gmail.com>2014-03-20 18:20:29 +0800
committerMaran <maran.hidskes@gmail.com>2014-03-20 18:20:29 +0800
commitae837c4719855384921fcaadb1a575942dc9833d (patch)
tree3981f671c02ac6874c849cab7186cecf80d24e2f
parent2be2fc79740d942f9690268352465d117930f081 (diff)
downloadgo-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar.gz
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar.bz2
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar.lz
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar.xz
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.tar.zst
go-tangerine-ae837c4719855384921fcaadb1a575942dc9833d.zip
More mining rework
-rw-r--r--ethchain/block.go3
-rw-r--r--ethchain/block_chain.go3
-rw-r--r--ethchain/dagger.go16
-rw-r--r--ethchain/state_manager.go28
-rw-r--r--ethchain/transaction_pool.go9
-rw-r--r--ethminer/miner.go149
-rw-r--r--peer.go2
7 files changed, 171 insertions, 39 deletions
diff --git a/ethchain/block.go b/ethchain/block.go
index 20af73ba2..d42aa7d83 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -304,6 +304,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
func (block *Block) String() string {
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}
+func (block *Block) GetRoot() interface{} {
+ return block.state.trie.Root
+}
//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} {
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
index 93970a2c5..90ad4516a 100644
--- a/ethchain/block_chain.go
+++ b/ethchain/block_chain.go
@@ -44,7 +44,6 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
hash = bc.LastBlockHash
lastBlockTime = bc.CurrentBlock.Time
}
-
block := CreateBlock(
root,
hash,
@@ -181,8 +180,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
// Add a block to the chain and record addition information
func (bc *BlockChain) Add(block *Block) {
bc.writeBlockInfo(block)
-
// Prepare the genesis block
+
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
diff --git a/ethchain/dagger.go b/ethchain/dagger.go
index 4d2034e20..a80a9d421 100644
--- a/ethchain/dagger.go
+++ b/ethchain/dagger.go
@@ -11,7 +11,7 @@ import (
)
type PoW interface {
- Search(block *Block, minerChan chan ethutil.React) []byte
+ Search(block *Block, reactChan chan ethutil.React) []byte
Verify(hash []byte, diff *big.Int, nonce []byte) bool
}
@@ -19,7 +19,7 @@ type EasyPow struct {
hash *big.Int
}
-func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte {
+func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
hash := block.HashNoNonce()
diff := block.Difficulty
@@ -28,15 +28,9 @@ func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte {
for {
select {
- case chanMessage := <-minerChan:
- if _, ok := chanMessage.Resource.(*Block); ok {
- log.Println("BREAKING OUT: BLOCK")
- return nil
- }
- if _, ok := chanMessage.Resource.(*Transaction); ok {
- log.Println("BREAKING OUT: TX")
- return nil
- }
+ case <-reactChan:
+ log.Println("[pow] Received reactor event; breaking out.")
+ return nil
default:
i++
if i%1234567 == 0 {
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 3be940745..46d8228d9 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -50,9 +50,6 @@ type StateManager struct {
// Comparative state it used for comparing and validating end
// results
compState *State
-
- // Mining state, solely used for mining
- miningState *State
}
func NewStateManager(ethereum EthManager) *StateManager {
@@ -65,7 +62,6 @@ func NewStateManager(ethereum EthManager) *StateManager {
bc: ethereum.BlockChain(),
}
sm.procState = ethereum.BlockChain().CurrentBlock.State()
-
return sm
}
@@ -73,10 +69,6 @@ func (sm *StateManager) ProcState() *State {
return sm.procState
}
-func (sm *StateManager) MiningState() *State {
- return sm.miningState
-}
-
// Watches any given address and puts it in the address state store
func (sm *StateManager) WatchAddr(addr []byte) *AccountState {
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
@@ -105,8 +97,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) {
sm.procState.states[string(tx.Hash()[12:])] = contract.state
}
}
-func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) {
-}
func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
// Process each transaction/contract
@@ -136,17 +126,13 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) {
sm.procState = processer
}
-func (sm *StateManager) PrepareMiningState() {
- sm.miningState = sm.BlockChain().CurrentBlock.State()
-}
-
// Default prepare function
func (sm *StateManager) PrepareDefault(block *Block) {
sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State())
}
// Block processing and validating with a given (temporarily) state
-func (sm *StateManager) ProcessBlock(block *Block) error {
+func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
defer sm.mutex.Unlock()
@@ -155,7 +141,6 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
// nodes this won't happen because Commit would have been called
// before that.
defer sm.bc.CurrentBlock.Undo()
-
hash := block.Hash()
if sm.bc.HasBlock(hash) {
@@ -207,7 +192,9 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
}
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
- sm.Ethereum.Reactor().Post("newBlock", block)
+ if dontReact == false {
+ sm.Ethereum.Reactor().Post("newBlock", block)
+ }
} else {
fmt.Println("total diff failed")
}
@@ -285,15 +272,16 @@ func CalculateUncleReward(block *Block) *big.Int {
}
func (sm *StateManager) AccumelateRewards(block *Block) error {
+
// Get the coinbase rlp data
//XXX addr := processor.state.GetAccount(block.Coinbase)
addr := sm.procState.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
-
//XXX processor.state.UpdateAccount(block.Coinbase, addr)
- sm.procState.UpdateAccount(block.Coinbase, addr)
-
+ var acc []byte
+ copy(acc, block.Coinbase)
+ sm.procState.UpdateAccount(acc, addr)
for _, uncle := range block.Uncles {
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
uncleAddr.AddFee(CalculateUncleReward(uncle))
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
index b0df1b6c0..26827c289 100644
--- a/ethchain/transaction_pool.go
+++ b/ethchain/transaction_pool.go
@@ -91,7 +91,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
// Process transaction validates the Tx and processes funds from the
// sender to the recipient.
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
- log.Println("Processing TX")
defer func() {
if r := recover(); r != nil {
log.Println(r)
@@ -105,11 +104,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
if sender.Amount.Cmp(totAmount) < 0 {
- return errors.New("Insufficient amount in sender's account")
+ return errors.New("[TXPL] Insufficient amount in sender's account")
}
if sender.Nonce != tx.Nonce {
- return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce)
+ return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce)
}
// Get the receiver
@@ -145,7 +144,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("No last block on the block chain")
+ return errors.New("[TXPL] No last block on the block chain")
}
// Get the sender
@@ -156,7 +155,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
if sender.Amount.Cmp(totAmount) < 0 {
- return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
+ return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
}
// Increment the nonce making each tx valid only once to prevent replay
diff --git a/ethminer/miner.go b/ethminer/miner.go
new file mode 100644
index 000000000..f4f697aba
--- /dev/null
+++ b/ethminer/miner.go
@@ -0,0 +1,149 @@
+package ethminer
+
+import (
+ "bytes"
+ "github.com/ethereum/eth-go/ethchain"
+ "github.com/ethereum/eth-go/ethutil"
+ "github.com/ethereum/eth-go/ethwire"
+ "log"
+)
+
+type Miner struct {
+ pow ethchain.PoW
+ ethereum ethchain.EthManager
+ coinbase []byte
+ reactChan chan ethutil.React
+ txs []*ethchain.Transaction
+ uncles []*ethchain.Block
+ block *ethchain.Block
+ powChan chan []byte
+ quitChan chan ethutil.React
+}
+
+func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
+ reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
+ powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
+ quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
+
+ ethereum.Reactor().Subscribe("newBlock", reactChan)
+ ethereum.Reactor().Subscribe("newTx", reactChan)
+
+ // We need the quit chan to be a Reactor event.
+ // The POW search method is actually blocking and if we don't
+ // listen to the reactor events inside of the pow itself
+ // The miner overseer will never get the reactor events themselves
+ // Only after the miner will find the sha
+ ethereum.Reactor().Subscribe("newBlock", quitChan)
+ ethereum.Reactor().Subscribe("newTx", quitChan)
+
+ miner := Miner{
+ pow: &ethchain.EasyPow{},
+ ethereum: ethereum,
+ coinbase: coinbase,
+ reactChan: reactChan,
+ powChan: powChan,
+ quitChan: quitChan,
+ }
+
+ // Insert initial TXs in our little miner 'pool'
+ miner.txs = ethereum.TxPool().Flush()
+ miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+
+ return miner
+}
+func (miner *Miner) Start() {
+ // Prepare inital block
+ miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
+ go func() { miner.listener() }()
+}
+func (miner *Miner) listener() {
+ for {
+ select {
+ case chanMessage := <-miner.reactChan:
+ if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
+ log.Println("[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
+ log.Println("[miner] New top block found resetting state")
+
+ // Filter out which Transactions we have that were not in this block
+ var newtxs []*ethchain.Transaction
+ for _, tx := range miner.txs {
+ found := false
+ for _, othertx := range block.Transactions() {
+ if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
+ found = true
+ }
+ }
+ if found == false {
+ newtxs = append(newtxs, tx)
+ }
+ }
+ miner.txs = newtxs
+
+ // Setup a fresh state to mine on
+ miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+
+ } else {
+ if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
+ log.Println("[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.Println("[miner] Got new transaction from Reactor", tx)
+ found := false
+ for _, ctx := range miner.txs {
+ if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
+ break
+ }
+
+ }
+ if found == false {
+ log.Println("[miner] We did not know about this transaction, adding")
+ miner.txs = append(miner.txs, tx)
+ miner.block.SetTransactions(miner.txs)
+ } else {
+ log.Println("[miner] We already had this transaction, ignoring")
+ }
+ }
+ default:
+ log.Println("[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, miner.block.Transactions())
+ miner.ethereum.StateManager().AccumelateRewards(miner.block)
+
+ // Search the nonce
+ log.Println("[miner] Initialision complete, starting mining")
+ miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
+ if miner.block.Nonce != nil {
+ miner.ethereum.StateManager().PrepareDefault(miner.block)
+ err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
+ if err != nil {
+ log.Println("Error result from process block:", err)
+ log.Println(miner.block)
+ } else {
+
+ if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
+ log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
+ }
+ miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
+ log.Printf("[miner] 🔨 Mined block %x\n", miner.block.Hash())
+ log.Println(miner.block)
+
+ miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
+ miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
+ }
+ }
+ }
+ }
+}
diff --git a/peer.go b/peer.go
index 4e927ada4..6b914710d 100644
--- a/peer.go
+++ b/peer.go
@@ -295,7 +295,7 @@ func (p *Peer) HandleInbound() {
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
p.ethereum.StateManager().PrepareDefault(block)
- err = p.ethereum.StateManager().ProcessBlock(block)
+ err = p.ethereum.StateManager().ProcessBlock(block, true)
if err != nil {
if ethutil.Config.Debug {