First intuition was that it signals that there are transactions to be mined, but even without a tx on a private net sometimes I see it three times per block

I0604 10:00:49.877830 miner/worker.go:337] 🔨  Mined stale block (#233 / 52f98d53). 
I0604 10:00:49.898013 miner/worker.go:555] commit new work on block 234 with 0 txs & 2 uncles. Took 357.428µs
I0604 10:00:49.909992 miner/worker.go:555] commit new work on block 234 with 0 txs & 2 uncles. Took 334.166µs
I0604 10:00:49.960199 miner/worker.go:555] commit new work on block 234 with 0 txs & 2 uncles. Took 337.558µs

1 Answer 1


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.


The message comes from last few lines of Go Ethereum - miner/worker.go::commitNewWork(), lines 439-559:

func (self *worker) commitNewWork() {
    defer self.mu.Unlock()
    defer self.uncleMu.Unlock()
    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)

    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.")
    work := self.current

    /* //approach 1
    transactions := self.eth.TxPool().GetTransactions()

    //approach 2
    transactions := self.eth.TxPool().GetTransactions()

    /* // 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...)
    transactions := append(singleTxOwner, multiTxOwner...)

    work.commitTransactions(self.mux, transactions, self.gasPrice, self.chain)

    // compute uncles for the new block.
    var (
        uncles    []*types.Header
        badUncles []common.Hash
    for hash, uncle := range self.possibleUncles {
        if len(uncles) == 2 {
        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])
            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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.