The message commit new work on block is displayed by geth
when geth
(and ethminer
when GPU mining) is ready to start a new set of mining computations to find a nonce that matches the target.
When a new block is found by your miner, or another miner on the Ethereum network , geth
stops the current mining computations it is performing.
geth
then prepares a fresh new block, built upon the block hash of the newly received block (new parent) and the following data:
- Transactions from the transaction pool to be included in the new block
- Uncle block to be included in the new block
geth
then emits the message commit new work on block and starts the mining computation on this new block.
This procedure results in geth
always mining at the top of the blockchain.
commitNewWork()
The message comes from last few lines of Go Ethereum - miner/worker.go::commitNewWork()
, lines 439-559:
func (self *worker) commitNewWork() {
self.mu.Lock()
defer self.mu.Unlock()
self.uncleMu.Lock()
defer self.uncleMu.Unlock()
self.currentMu.Lock()
defer self.currentMu.Unlock()
tstart := time.Now()
parent := self.chain.CurrentBlock()
tstamp := tstart.Unix()
if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 {
tstamp = parent.Time().Int64() + 1
}
// this will ensure we're not going off too far in the future
if now := time.Now().Unix(); tstamp > now+4 {
wait := time.Duration(tstamp-now) * time.Second
glog.V(logger.Info).Infoln("We are too far in the future. Waiting for", wait)
time.Sleep(wait)
}
num := parent.Number()
header := &types.Header{
ParentHash: parent.Hash(),
Number: num.Add(num, common.Big1),
Difficulty: core.CalcDifficulty(self.config, uint64(tstamp), parent.Time().Uint64(), parent.Number(), parent.Difficulty()),
GasLimit: core.CalcGasLimit(parent),
GasUsed: new(big.Int),
Coinbase: self.coinbase,
Extra: self.extra,
Time: big.NewInt(tstamp),
}
previous := self.current
// Could potentially happen if starting to mine in an odd state.
err := self.makeCurrent(parent, header)
if err != nil {
glog.V(logger.Info).Infoln("Could not create new env for mining, retrying on next block.")
return
}
work := self.current
/* //approach 1
transactions := self.eth.TxPool().GetTransactions()
sort.Sort(types.TxByNonce(transactions))
*/
//approach 2
transactions := self.eth.TxPool().GetTransactions()
types.SortByPriceAndNonce(transactions)
/* // approach 3
// commit transactions for this run.
txPerOwner := make(map[common.Address]types.Transactions)
// Sort transactions by owner
for _, tx := range self.eth.TxPool().GetTransactions() {
from, _ := tx.From() // we can ignore the sender error
txPerOwner[from] = append(txPerOwner[from], tx)
}
var (
singleTxOwner types.Transactions
multiTxOwner types.Transactions
)
// Categorise transactions by
// 1. 1 owner tx per block
// 2. multi txs owner per block
for _, txs := range txPerOwner {
if len(txs) == 1 {
singleTxOwner = append(singleTxOwner, txs[0])
} else {
multiTxOwner = append(multiTxOwner, txs...)
}
}
sort.Sort(types.TxByPrice(singleTxOwner))
sort.Sort(types.TxByNonce(multiTxOwner))
transactions := append(singleTxOwner, multiTxOwner...)
*/
work.commitTransactions(self.mux, transactions, self.gasPrice, self.chain)
self.eth.TxPool().RemoveTransactions(work.lowGasTxs)
// compute uncles for the new block.
var (
uncles []*types.Header
badUncles []common.Hash
)
for hash, uncle := range self.possibleUncles {
if len(uncles) == 2 {
break
}
if err := self.commitUncle(work, uncle.Header()); err != nil {
if glog.V(logger.Ridiculousness) {
glog.V(logger.Detail).Infof("Bad uncle found and will be removed (%x)\n", hash[:4])
glog.V(logger.Detail).Infoln(uncle)
}
badUncles = append(badUncles, hash)
} else {
glog.V(logger.Debug).Infof("commiting %x as uncle\n", hash[:4])
uncles = append(uncles, uncle.Header())
}
}
for _, hash := range badUncles {
delete(self.possibleUncles, hash)
}
if atomic.LoadInt32(&self.mining) == 1 {
// commit state root after all state transitions.
core.AccumulateRewards(work.state, header, uncles)
header.Root = work.state.IntermediateRoot()
}
// create the new block whose nonce will be mined.
work.Block = types.NewBlock(header, work.txs, uncles, work.receipts)
// We only care about logging if we're actually mining.
if atomic.LoadInt32(&self.mining) == 1 {
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart))
self.logLocalMinedBlocks(work, previous)
}
self.push(work)
}