Ganache-cli: evm_mine arbitrarily increase latest block time

Created on 15 Jan 2018  路  8Comments  路  Source: trufflesuite/ganache-cli

  • I asked about this on gitter: [ ]
  • Link to my question on gitter:

Expected Behavior

get the current latest block's timestamp via

web3.eth.getBlock('latest').timestamp // 1516043000

then:

web3.currentProvider.sendAsync({
  jsonrpc: '2.0', 
  method: 'evm_increaseTime', 
  params: [5], 
  id: new Date().getMillseconds()
}, (err, resp) => {
    if (!err) {
      web3.currentProvider.send({
      jsonrpc: '2.0', 
      method: 'evm_mine', 
      params: [], 
      id: new Date().getMillseconds()
    }
  }
})

after mining new block get new timestamp - should see 1516043000 + 5 = 1516043005

Current Behavior

get the current latest block's timestamp via

web3.eth.getBlock('latest').timestamp // e.g 1516043000

then:

web3.currentProvider.sendAsync({
  jsonrpc: '2.0', 
  method: 'evm_increaseTime', 
  params: [5], 
  id: new Date().getMillseconds()
}, (err, resp) => {
    if (!err) {
      web3.currentProvider.send({
      jsonrpc: '2.0', 
      method: 'evm_mine', 
      params: [], 
      id: new Date().getMillseconds()
    }
  }
})

after mining new block get new timestamp - you get some arbitrary time added to the new timestamp + your added time.

When increasing by 5 from 1516043000 I get --> e.g 1516043037 NOT 1516043005

Mining on test network should be instantaneous no?

Possible Solution

Don't know

Steps to Reproduce (for bugs)

  1. start ganache-cli
  2. truffle console

get the current latest block's timestamp via

web3.eth.getBlock('latest').timestamp // e.g 1516043000

then:

web3.currentProvider.sendAsync({
  jsonrpc: '2.0', 
  method: 'evm_increaseTime', 
  params: [500], 
  id: new Date().getMillseconds()
}, (err, resp) => {
    if (!err) {
      web3.currentProvider.send({
      jsonrpc: '2.0', 
      method: 'evm_mine', 
      params: [], 
      id: new Date().getMillseconds()
    }
  }
})
  1. get blockTime again and should be 1516043000 + 5000 = 1516048000 exactly
    web3.eth.getBlock('latest').timestamp // I get non deterministic timestamp 1516048032

Context

  1. This is affecting our testing because we have time sensitive variables that can not be asserted/tested exactly due to the non-deterministic nature of the time needed to evm_mine
  2. Would just be nice to have it deterministic 馃槣

Your Environment

  • Version used:
Truffle v4.0.4 (core: 4.0.4) 
Solidity v0.4.18 (solc-js) 
Ganache CLI v.6.0.3 
ganache-core: 2.0.2
  • Version of Truffle/Remix/Other tools used: Truffle 4.0.4
  • NodeJS Version: [ ] 6.x, [ ] 7.x (unsupported), [x] 8.x, [ ] 9.x
  • Operating System and version (include distro if Linux): Windows 10 Home
  • Link to your project or repro gist:
  • Commit hash to use with above link for reproduction:
  • I intend to submit a pull request to fix this issue: [ ]

Most helpful comment

On this topic is there a way to increase the current block number more rapidly?

We're doing this right now in testing and to mine a lot of blocks take a lot of time!

const mineOneBlock = async () => {
  await web3.currentProvider.send({
    jsonrpc: '2.0',
    method: 'evm_mine',
    params: [],
    id: 0,
  })
}

const mineNBlocks = async n => {
  for (let i = 0; i < n; i++) {
    await mineOneBlock()
  }
}

All 8 comments

The intention behind evm_increaseTime is to set a fixed offset from the current (at time of mining) wall clock time. That is, it sets the clock skew.

This is affecting our testing because we have time sensitive variables that can not be asserted/tested exactly due to the non-deterministic nature of the time needed to evm_mine

There is an open PR (trufflesuite/ganache-core#13) for this change in behavior, with similar motivations to what you describe here, however I'm still on the fence about whether or not it's a good idea to accept this change.

My reasoning for not wanting to accept the change is that it shouldn't be important for you to be able to write tests which check a block timestamp down to the millisecond. If this is important for you, then you're likely introducing a major security flaw into your contract, as miners can manipulate block timestamps.

But perhaps I'm assuming too much about my users... If you're willing, could tell me a bit more about your use case? Does it fit this pattern, or are you doing something different which I haven't even thought of?

Also if you're using interval mining for your test suite (the -b flag), unless there's a big reason that you need it, I think your life will be much happier and more productive if you switch to instamining (drop the -b flag). You can still call evm_mine when you need arbitrary blocks created. Your test suite will certainly execute much faster as a result of this change.

@benjamincburns Thanks for the response and mind food.

I really just boils down to the fact that we'd like to have a deterministic testing environment. Maybe introducing a new flag for removing this time skew could keep default truffle like you originally intended and allow users like us to set the determinism.

Just as an example we are using pricing function sensitive to time that we would like to assert absolutely.

Cheers.

On this topic is there a way to increase the current block number more rapidly?

We're doing this right now in testing and to mine a lot of blocks take a lot of time!

const mineOneBlock = async () => {
  await web3.currentProvider.send({
    jsonrpc: '2.0',
    method: 'evm_mine',
    params: [],
    id: 0,
  })
}

const mineNBlocks = async n => {
  for (let i = 0; i < n; i++) {
    await mineOneBlock()
  }
}

@elie222 Did you solve this?

So I think in the end we used time rather than block number, but I'm trying to think if that actually helps in terms of making the simulation easier.
I don't think I had a good solution with block number, but with timestamp we had a more workable solution although I don't remember the details.

This issue costs me quite some time, because I was assuming it's a rounding error first. Then I saw the comments at https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/test/helpers/increaseTime.js#L28-L30 and changed my tests accordingly.

I think you are correct that a contract should not rely on anything down to a second. However, it makes testing a lot easier if ganache-cli is predictable.

https://github.com/trufflesuite/ganache-core/pull/13 has been merged, and the documentation on the ganache-cli repo was updated in https://github.com/trufflesuite/ganache-cli/commit/6c0d5820bc3634fa00cbeb2bd97ad721066761a5

You'll have the ability to specify a timestamp in the evm_mine call to mine exactly at. This should solve this issue. This will go into the next release (sometime this week is the goal). Thanks!

Was this page helpful?
0 / 5 - 0 ratings