4

How can we increase block.number on Ganache for testing purpose ? If not possible do you know an alternative like passing X fake transactions to artificially increase block.number.

Or if we have to use a private chain: is it possible to change the time between blocks for faster testing ?

Best regards

5 Answers 5

4

You can increase block.timestamp (aka now):

web3.currentProvider.send({method: "evm_increaseTime", params: [numOfSeconds]});

Note that this method is a Ganache-extension of the standard.

So do not count on it on other node types (Geth, Parity, etc).

Also note that the code above is valid for web3.js v0.x.

You might need to run it asynchronously in web3.js v1.x.

9
  • Hi thanks for reply, but I need to use block.number instead of block.timestamp for security reasons. Best regards
    – Kevin Wad
    May 12, 2019 at 9:55
  • @KevinWad: Well then I guess that you'll have to execute some "dummy" transactions (e.g., add a "dummy" state variable to your contract, and call a function which increments it). May 12, 2019 at 10:06
  • 3
    There's evm_mine that can be used to create an empty block and you can use similarly to evm_increaseTime.
    – Ismael
    May 13, 2019 at 15:26
  • @KevinWad: See Ismael's suggestion above. May 13, 2019 at 15:28
  • @Ismael Thanks very much ! Goodvibration thanks for letting me know !
    – Kevin Wad
    May 13, 2019 at 15:33
6

In addition to goodvibration's answer, OpenZeppelin recently released their openzeppelin-test-helpers package. This library contains all kinds of helpers for testing smart contracts, including methods to increase the block number or timestamp, such as:

async time.advanceBlock()
async time.increase(duration)
async time.increaseTo(target)

I haven't used the library myself, but it sounds like it might be useful for you.

2
  • 2
    This library looks cool, but note that it breaks compatibility with BigNumber.js, due to several imports that use BN.js. For instance, in my case, all tests that had "should.be.bignumber.equal" broke. Jul 24, 2019 at 21:01
  • @PaulBerg that's a very good point Jul 24, 2019 at 21:16
4

I needed a promise-based solution that didn't require installing a third-party library. Copy-pasting from Ethan Wessel's amazing article on truffle time testing:

advanceTime = (time) => {
  return new Promise((resolve, reject) => {
    web3.currentProvider.send({
      jsonrpc: '2.0',
      method: 'evm_increaseTime',
      params: [time],
      id: new Date().getTime()
    }, (err, result) => {
      if (err) { return reject(err) }
      return resolve(result)
    })
  })
}

advanceBlock = () => {
  return new Promise((resolve, reject) => {
    web3.currentProvider.send({
      jsonrpc: '2.0',
      method: 'evm_mine',
      id: new Date().getTime()
    }, (err, result) => {
      if (err) { return reject(err) }
      const newBlockHash = web3.eth.getBlock('latest').hash

      return resolve(newBlockHash)
    })
  })
}

takeSnapshot = () => {
  return new Promise((resolve, reject) => {
    web3.currentProvider.send({
      jsonrpc: '2.0',
      method: 'evm_snapshot',
      id: new Date().getTime()
    }, (err, snapshotId) => {
      if (err) { return reject(err) }
      return resolve(snapshotId)
    })
  })
}

revertToSnapShot = (id) => {
  return new Promise((resolve, reject) => {
    web3.currentProvider.send({
      jsonrpc: '2.0',
      method: 'evm_revert',
      params: [id],
      id: new Date().getTime()
    }, (err, result) => {
      if (err) { return reject(err) }
      return resolve(result)
    })
  })
}

advanceTimeAndBlock = async (time) => {
  await advanceTime(time)
  await advanceBlock()
  return Promise.resolve(web3.eth.getBlock('latest'))
}

module.exports = {
  advanceTime,
  advanceBlock,
  advanceTimeAndBlock,
  takeSnapshot,
  revertToSnapShot
}
1

As Rosco Kalis's suggestion of @openzeppelin/test-helpers

npm install --save-dev @openzeppelin/test-helpers

My Node.js code for contract testing:

const { time } = require("@openzeppelin/test-helpers");
require("@openzeppelin/test-helpers/configure")({
  provider: "http://localhost:7545",
});

async function main() {
  await time.advanceBlock();
  await myTimeRelatedContractMethodCall();
}
main()

Further reading : https://docs.openzeppelin.com/test-helpers/0.5/api#time

1

With ethers, you can increase the next block timestamp using:

await ethers.provider.send("evm_increaseTime", [numSecondsToIncreaseBy]);
await ethers.provider.send("evm_mine");

or you can choose the next block timestamp as follows (this may be important if you need exact block timestamps, since the above method may result in a timestamp larger than intended, if other blocks are mined before your next contract function call). The new timestamp must be greater than the current block timestamp:

  const currTimestamp =
          (await ethers.provider.getBlock(contract.deployTransaction.blockNumber))
          .timestamp;
  await ethers.provider.send("evm_setNextBlockTimestamp", [currTimestamp + 3600]);
  await ethers.provider.send("evm_mine");

You can also increase the block number by repeatedly sending an evm_mine transaction (but I don't know if there's a way to increase the block number by an arbitrary number of blocks with one call).

Your Answer

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

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