mirror of https://github.com/ethereum/go-ethereum
parent
2be2fc7974
commit
ae837c4719
@ -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: ðchain.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) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue