30

As of now the geth miner running on my system mines even empty blocks. All i wanted is miner should mine only when there are Transactions to mine, after mining the miner should immediately sleep.

How to achieve this?

6 Answers 6

36

You can load this script to your geth console

Mine only when there are transactions!

var mining_threads = 1

function checkWork() {
    if (eth.getBlock("pending").transactions.length > 0) {
        if (eth.mining) return;
        console.log("== Pending transactions! Mining...");
        miner.start(mining_threads);
    } else {
        miner.stop();
        console.log("== No transactions! Mining stopped.");
    }
}

eth.filter("latest", function(err, block) { checkWork(); });
eth.filter("pending", function(err, block) { checkWork(); });

checkWork();

See other useful snippets here

Mining until x confirmations have been achieved

This question is particularly relevant to private chains where transactions may be more sporadic than on public chains. In some applications it may be beneficial to continue mining for a set number of blocks after the latest transaction to ensure adequate confirmations are reached before mining stops and avoiding the latest transaction only receiving one confirmation (e.g. when using mist on private networks it likes to see 12 confirmations):

var mining_threads = 1
var txBlock = 0

function checkWork() {
if (eth.getBlock("pending").transactions.length > 0) {
    txBlock = eth.getBlock("pending").number
    if (eth.mining) return;
    console.log("  Transactions pending. Mining...");
    miner.start(mining_threads)
    while (eth.getBlock("latest").number < txBlock + 12) {
      if (eth.getBlock("pending").transactions.length > 0) txBlock = eth.getBlock("pending").number;
        }
    console.log("  12 confirmations achieved; mining stopped.");
    miner.stop()
}
else {
    miner.stop()
     }
}

eth.filter("latest", function(err, block) { checkWork(); });
eth.filter("pending", function(err, block) { checkWork(); });

checkWork();

This can also be saved as a .js script and preloaded using the --preload function when starting geth:

geth --preload "/path/to/mineWhenNeeded.js"
7
  • This answer can be improved by listing the source (the link to the other SE answer isn't the original source).
    – Jeffrey W.
    Commented Apr 18, 2016 at 8:34
  • 1
    @JeffreyW. feel free to edit and add source.
    – niksmac
    Commented Apr 20, 2016 at 0:48
  • to clear/stop auto-mining script checkWork=null
    – Subhod I
    Commented Nov 15, 2017 at 6:43
  • How can I edit the first script in a way that it waits for a defined period when a transaction is pending before it mines the transactions? I tried admin.sleep() but this seems not to work. Mining is done instantly.
    – Tobias
    Commented Feb 27, 2019 at 14:55
  • @Tobias consider adding an issue here and I will try to get it done for you
    – niksmac
    Commented Feb 27, 2019 at 16:58
3

If you're using geth POA, you can set block sealing period to 0 in genesis file, this will automatically force geth to only create new block whenever there is a transaction in network.

For 0-period chains, refuse to seal empty blocks

2
  • Unfortunately this does only work for the first block (on my try). So if I initialize a new chain and send the first transaction, this transaction is directly mined but if I send a new transaction it will be pending forever, mining does not work. Any idea why this could be? Anyway, with the above script provided by @niksmac it works.
    – Tobias
    Commented Feb 27, 2019 at 15:01
  • @Tobias These transactions are from truffle or directly from web3? It would if you share geth logs when transactions are pending. Commented Mar 6, 2019 at 12:28
3

In POA, In continuation to @jadd22 answer, during the truffle migrate we face the below issue.

https://github.com/trufflesuite/truffle/issues/853

To overcome this, we can run enough number dummy transactions asynchronously, {from:"0xAcc1",to:"0xAcc1",value:0} to ensure the deployment success.

After deployment all other operations are happening as required, i.e., mining happens only when there are pending transactions. No unnecessary empty block generation.

We can use " clique.period " inside genesis.json file to zero, as given below, to ensure mining only when ever required with out empty block generation. ( Only for POA )

clique": {
        "period": 0,
        "epoch": 30000
    }, 

Only we need to handle the truffle migration with some dummy transactions, Hope this is not required if the deployment of the contracts are done programatically using web3 and solc compilers.

1
  • Sorry @M.Gupal, on a second read I deleted the flag. Commented Nov 22, 2018 at 8:47
3

If you use PoW you can modify the Go code under

consensus/ethash/sealer.go

and add a condition to refuse seal if there are no transactions:

// Seal implements consensus.Engine, attempting to find a nonce that satisfies
// the block's difficulty requirements.
func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
.....
if len(block.Transactions()) == 0 {
    log.Info("Sealing paused, waiting for transactions")
    return nil, nil
}
.....

After that, run make geth to regenerate the executables with the new code.

2

I was using @niksmac answer for mining until n confirmations are achieved but the while loop caused a very high CPU usage (above 110%). I changed it for an interval and now the CPU usage is below 5%. I check every 600ms, but any number that is < block time would work.

var minimum_confirmations = 3;
var mining_threads = 1
var txBlock = 0
function checkWork() {
    if (eth.getBlock("pending").transactions.length > 0) {
        txBlock = eth.getBlock("pending").number
        if (eth.mining) return;
        console.log("  Transactions pending. Mining...");
        miner.start(mining_threads)
        interval = setInterval(function () {
            if (eth.getBlock("latest").number < txBlock + minimum_confirmations) {
                if (eth.getBlock("pending").transactions.length > 0) txBlock = eth.getBlock("pending").number;
            } else {
                console.log(minimum_confirmations + " confirmations achieved; mining stopped.");
                miner.stop()
                clearInterval(interval);
            }
        }, 600)
    }
}

eth.filter("latest", function (err, block) { checkWork(); });
eth.filter("pending", function (err, block) { checkWork(); });

checkWork();
2
  • Can also do admin.sleep(1) to sleep for 1 second
    – rustyx
    Commented Apr 8, 2018 at 20:05
  • @rustyx I will have to try that because my proposed solution sometimes does not work as expected.
    – facumedica
    Commented Apr 9, 2018 at 18:57
1

You may install eth-mine-when-need. Which starts a web3 client and listens for events. When there are pending transactions or transactions yet to be confirmed, it will start the miner until they are confirmed. It functions same as @niksmac 's answer. But, you don't have to execute the script every time you start eth and it allows you to specify the number of threads for mining and the number of blocks that is needed to say a transaction is confirmed by passing those values as arguments (for detail you can see the readme at npm).

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