EIP-1985: Sane limits for certain EVM parameters

That would be great, thanks!

Yes, I think all of this enforced via gas limits already. Would be nice if we could enforce it prior to gas calculation.

There is really only one thing which may cause problems here, afaict (and this issue might need to be included in ‘Security Considerations’ for this EIP).

Currently geth and parity allows a full uint64 as an uncle timestamp. This means that someone can intentionally mine an uncle U with timestamp 2^64-1 , and then mine a regular block within 7 blocks, and include U in the uncle set.

If we redefine the allowed timestamp as max 2^ 63-1, then we’re open for a consensus-attack between updated and non-updated clients.

There are two ways out from this dilemma

  1. Use 2^ 64-1 (uint64) as max timestamp, not 2^ 63-1 (int64)
  2. Ensure that we implement the change at a particular block B (hard fork). Later, if we see that nobody did ever execute this attack prior to B, we can “undo” the hardfork and retroactively apply the fork – basically pretending that the rule was always there.

I personally think option 1 is the best route, but I’m not really up to speed with what kinds of problems that leads to on platforms without native support for uint64

Here’s how it is in geth right now:

Already enforced

Not enforced

  • tx.gasLimit is defined as uint64 in geth. Can be safely capped as EIP suggests.
  • block.number is defined as a big.Int, but validation checks that it is only 1 away from the parent: here. Can be safely capped at like EIP suggests.
  • block.timestamp – see comment above, cannot be safely capped like EIP suggests.

Other

  • buffer size has no constraints, but practically I don’t see any possible realistic impact of changing this to max at int32. Can be safely capped like EIP suggests.

I think it would be acceptable given we do not need to represent timestamps prior to 1970 in the block headers.

However, for best standards compatibility I’d be in favor of striving for int64.

Isn’t this an issue already if someone mines an uncle block with timestamp 2^64?

We are investigating possibility of applying this retroactively.

The remaining 2 comments have been addressed in https://github.com/ethereum/EIPs/pull/2153.

As you can guess, I’m very much in favor of int64 limit for timestamp.

Third option to go here is to allow negative values for int64 timestamps in EVM execution. This will allow executing EVM code by mapping values above 2^63-1 to negative numbers (they are binary equivalent anyway).
Can you create uncle blocks with negative timestamps in current implementations?

Thinking about this more, I really hope we can do it retroactively to reap the benefits for evm2wasm or in the proposed Eth1 EE on Eth2.

Well, if they do, it’s not an ‘issue’ now. However, if some clients cap it lower, then we will have an issue. So there’s no ‘safe’ rollout of that change, other than hardfork-then-retroactive, because going full retroactive means there a window where it can be used as an attack

Can you create uncle blocks with negative timestamps in current implementations?

RLP has no ‘native’ support for negative integers, and geth defines timestamps as unsigned. So basically there’s no way geth (nor parity afaict) would interpret a timestamp as negative.

I think the best way to ensure clients deal with it is to have some reference test cases where the relevant numbers are unit64 but not int64. So some timestamp after 2038 should do that.

To that end we should also see if test cases can be written where the first “insane” value is tested. This would only work if clients fail in a sensible fashion that the harness can detect.

I think you meant the year 292277026596.

I have changed my mind on this. Actually, what the EIP proposes is only from the viewpoint of the EVM. And from the perspective of the EVM, a timestamp will always safely fit within int64. Because the EVM knows nothing about uncles, and we never execute transactions within an uncle.

So I think it would be fine to say that

  • The EVM can/should consider TIMESTAMP as fitting inside an int64.

The little devil in the details for node implementors to remember, however, is that the same rule cannot be applied to block header (uncle) validation, where timestamp can be uint64.

I actually thought uncles are also fully verified.

Anyway, we intentionally assigned the limits to the EVM only, but consequences of these are also outside of EVM because a node will have to make sure the numbers being passed can fit.

That’s easy to think, and normally they would be, as an uncle generally exists as a head somewhere before it becomes uncled. However, on the blockchain, uncles are only headers without bodies, so it’s impossible to actually execute transactions in an uncle given only the chain of canon blocks – the transactions are missing (hashes too, only the combined txhash remain).

And it would be a problem of recursion. In order to validate a block, you’d need to validate the uncles. In order to validate an uncle, you’d neeed to validate it’s uncles, and so on indefinitely.

Right, but that’s a simpler thing to fix within the node, just to make sure that whatever environment struct that’s passed to the evm uses only 63 bits. Just as long as the node does not enforce that for uncle timestamps we’re fine.

Cannot we just go with this to simplify everyone’s life in the long term (while making it worse in the short term)?

Side-note: @winsvega called for a similar clarification https://github.com/ethereum/EIPs/issues/604

In 2016, EIP-92 by @chfast proposed a similar limit. There is a long discussion there about other limits, all of which (with the exception of balance/values) are covered.

I updated EIP-1985 with PC: https://github.com/ethereum/EIPs/pull/2179

It has been also suggested that the buffer limit (2^32 - 1) should also cap the EVM memory.

Although not strictly related to EVM semantics, it seems reasonable to include clarifying the range of other transaction related parameters in this EIP.
There is currently a discrepancy in what geth does and what the TransactionTests enforce when it comes to nonce and gasPrice:
geth uses uint64 for transaction nonces while the TransactionTests use uint256
geth uses uint256 for gas price while the TransactionTests use uint64.

It seems reasonable to me to restrict both nonce and gasPrice to uint64 for transactions.

This EIP originally aimed to describe these restrictions throughout the systems, but we’ve decided to focus on the EVM only to make the EIP simpler to argue about (change was made here).

I’m open to making it more comprehensive as long as we can get it accepted and implemented by clients (hopefully without a “hard fork” aka. enforcing it starting from genesis).

1 Like