Open 0xLaplace opened 2 years ago
Hey, thanks for opening this issue, and I'm sorry for the difficulty.
Ignoring the fact that the value of L1 block numbers is absolutely vital to so many contracts that depend on native access to a reliable time progression measure, and very different from the value of the L2 "block numbers", which is just a txs index whose rate of growth swings wildly based on the amount of traffic that the sequencer receives over time.
This is a pretty fair point that we certainly should consider carefully. In the meantime, could you use TIMESTAMP
if you are looking for a way to track the progression of time?
There are deeper reasons for this design decision that people should be aware of. The NUMBER
opcode was not designed as a time-keeping mechanism. NUMBER
has a very clear purpose: to return the chain's block number. Not maintaining this behavior is a bigger move away from EVM equivalence that would result in a significant amount of technical debt in the future. Furthermore, TIMESTAMP
is a much more reliable mechanism for keeping time on larger timescales.
For additional context on the logic behind this decision, you have to understand that if we have NUMBER
correspond to the L1 block number now then there's very little chance that we'll be able to change this behavior later. This is because contract states will become dependent on the current L1 block number.
The actual deviation from EVM equivalence here is the highly variable block time. We are fully aware of this discrepancy and intend to update the system in the future to have a short (but constant) block time. This will resolve the issue that you're describing and bring us even closer to the experience of developing applications on Ethereum. We're currently planning to make this upgrade in the next several months, although we have not specified a date yet.
So yes, this will be inconvenient for some developers over the next few months. But this inconvenience is part of a deliberate tradeoff that we made when thinking about the future of the protocol. I do, however, agree that this design decision and its consequences for developers in the short-term are not sufficiently documented.
And FWIW, regarding this statement:
Furthermore, instead of assurances about the future-proof nature of this special contract, I heard quite the opposite from the eng team, saying that it is likely to be changed again in the future.
I can 100% guarantee that this contract is NOT to be changed again in the future and that getL1BlockNumber()
will always return the last known L1 block number when querying that address.
Thank you very much for this detailed answer @smartcontracts, it makes me feel satisfied again to be building on Optimism; I guess I will transition to TIMESTAMP where applicable, but will likely wait for the release where there will be constant block times, do you think it can appear in the scheduled January regenesis?
On the other hand, does the special contract have some setters as well? Or something that could be impersonated with Hardhat to arbitrarily advance L1 blocks?
cc @0xLaplace
do you think it can appear in the scheduled January regenesis?
We don't know when the next major upgrade will take place yet. Unfortunately I can't give you any sort of timeline.
On the other hand, does the special contract have some setters as well?
If you're using Hardhat to test your contracts, you can make use of smock to mock the behavior of that contract and arbitrarily "set" the L1 block number that your contract sees. This may be sufficient for the sort of testing you're hoping to do. You can even create a fake contract that lives at a specific address (by setting the address
parameter in the initialization options). If you're interested in this, I can give you an example that explains how you would use this in your testing.
Transferring over to optimistic-specs where this will get more visibility. Current specified behavior for the Optimism Bedrock release is that blocks will be produced at a rate of 1 block every 2 seconds. Hopefully that solves this problem for the most part. L1 block number (and other L1 block content) will be accessible on L2.
Current plan is indeed fixed block time of 2s. Anything that relies on block being spaced ~13s apart will not work, some notes:
TIMESTAMP
should be used anyway — in theory, it can be manipulated by L1 miners, though not for long before a difficulty increase kicks in under PoW. I think this becomes impossible in Eth2 (given the slots, I would assume that timestamps become fixed to multiple of 12s, not entirely sure though).BLOCKNUMBER
return the L1 block height would break another assumption that contracts can make on L1, which is that there is a 1:1 mapping between blocknumber and blockhash. And pretty sure if we dig, there are other breaking assumptions.Imho, no chance for this to happen so I'm in favour of closing this issue.
OVM 2.0 introduced many breaking changes, most of which were meant and did improve EVM equivalence for Optimistic networks, however, there was an objective, major regression introduced with the new
block.number
opcode behavior.Quoting from the changeset docs page:
First of all, it is helpful to understand the team rationale for this particular change, and luckily we have it from the team:
This is a very superficial, and simplicistic reasoning that actually goes against EVM equivalence, and does so by ignoring the fact that the value of L1 block numbers is absolutely vital to so many contracts that depend on native access to a reliable time progression measure, and very different from the value of the L2 "block numbers", which is just a txs index whose rate of growth swings wildly based on the amount of traffic that the sequencer receives over time.
I cannot fathom being the only developer trying to build on the OVM that sees this as a colossal blocking issue, and a completely self-inflicted wound for EVM-equivalence.
First of all, this is a clear regression that should never have made it out of the drawing board, however, I think this issue carries such a high severity that should be rolled back in an emergency regenesis, before the scheduled updates in Q1 2022.
Possible solutions that were discussed in the Discord with some team members were:
block.number
to its previous, L1-equivalent behavior, along with the introduction of a separate opcode to query the latest L2 transactions index liketxs.index
orl2.block.number
orl2block.number
I have been trying to fallback on the official supported method to query the latest L1 block number, which is (the docs didn't even mention this) the special and unverified contract deployed at: 0x4200000000000000000000000000000000000013 that can be queried with
getL1BlockNumber()
.Furthermore, instead of assurances about the future-proof nature of this special contract, I heard quite the opposite from the eng team, saying that it is likely to be changed again in the future.
Needless to say, this requires mantaining a different codebase for the OVM 2.0, not to mention the incompatibilities in test suites and deployment operations with tooling such as Hardhat VM forking and block advancement features.