Just thinking about @LasseAztec’s proposal further.
A downside of it, is that it leaks which contract has just been executed (because the contract has to call a public function to lookup the last_updated
variable).
A very ugly solution (which build’s on Lasse’s, but seeks to hide which contract was executed), would be to write a SlowUpdates
contract, which would be shared by many contracts, as a way of reading historic state. The SlowUpdates
contract would hold state on behalf of other contracts (e.g. in a mapping(Address contract_address => Field[] storage_slots)
).
The SlowUpdates
contract could provide a guarantee that updates can only be made once every n
blocks. That way, for n-1
blocks, users would have an assurance that their historic reads will be valid, and it would also hide which contract actually made the read (amongst a smaller anonymity set of all contracts which make use of the SlowUpdates
contract).
Of course, it has major downsides:
- Apps would need to be sure that updates every
n
blocks would be acceptable. - There might be gas spikes every
n
blocks, as apps try to make updates in the onlyn
-thly permitted block. - Apps might fail to make an update (due to block space competition) for a long time.
- Users who are attempting to read a state at a time which is close to the
n
th block, might choose to wait until after the ‘update block’, in case their tx isn’t mined in time. - Apps which update their public state far less frequently than every
n
blocks would be causing unnecessary UX pain for their users (for the reason bullet-pointed immediately above).