40

How safe is it to use block.timestamp as contract expiration time? If a miner provides an incorrect timestamp in a block header, how much can it be off before it is rejected by other nodes? Is there a strategy to make a contract more robust to this?

3 Answers 3

44

Not especially, but it depends on what the use case is.

Block times are subject to the following constraints:

  • If you stamp your block with a time too far in the future, no one else will build on it (miners will not build on a block timestamped "from the future").
  • Your block time cannot be stamped with an earlier time than its parent.
  • Difficulty is kept lowest (best deal for miners) by not stamping blocks as earlier than they actually occur.

Taken together, these factors suggest that most blocks produced by small hashrate miners who are not trying to manipulate anything will be pretty close to accurate. However, it is trivial for a more powerful miner to manipulate timestamps over short periods, especially if there is something to be gained by doing this.

Ultimate, there is no cryptographic way to verify the timestamp itself--only the ordering of certain cryptographic structures. Therefore block.timestamp needs to be supplemented with some other strategy in the case of high-value/risk applications.

17

First, a basic: using strict equality == block.timestamp would not be safe, since a block with that exact timestamp may never get mined. So use >= block.timestamp

Now it depends on what happens when the contract "expiration time" is reached. For reasons similar to the safe use of BLOCKHASH, block.timestamp should only be safely used if the total amount of value resting on what the contract does at "expiration time", is lower than what a miner earns by mining a single block. If the outcome of a lottery worth millions depends on block.timestamp, the timestamp will probably be manipulated.

The Yellow Paper does not have any answer to "how much can it be off before it is rejected by other nodes". If block.timestamp is used, the only guarantee (equation 43) is that block.timestamp is greater than that of its parent. But there are game theoretic reasons why block.timestamp won't be significantly wrong.

From the Solidity docs another thing to watch for is: You publish a transaction at a time X, this transaction contains some code that calls block.timestamp and is included in a block whose timestamp is Y and this block is included into the canonical chain (published) at a time Z. The value of block.timestamp will be identical to Y, and X <= Y <= Z

2
  • Maybe I should elaborate more in my answer: there are ways for larger miners to manipulate timestamps while incurring lower costs than the value of a single block reward. So the use of block.timestamp cannot be made strictly safe by only using low values the way BLOCKHASH randomness can be. Commented Jan 23, 2016 at 0:19
  • I can edit or strikethrough my answer and refer to the ways larger miners can manipulate timestamps with low costs... what should I refer to?
    – eth
    Commented Jan 23, 2016 at 0:50
1

A more secure solution would be to rely on block.number and an estimated time per block increment. Let's say you wanted to create a lease for a contract with a specific end date. You could calculate the approximate time with:

estimated_time_in_blocks = lease_length_in_seconds / average_block_time_in_seconds
lease_end_block_number = current_block + estimated_time_in_blocks

In your contract you can then check:

block.number <= lease_end_block_number

The example in Mastering Ethereum is:

with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable easily to manipulate the block number.

The BAT ICO contract uses this approach

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.