-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
prune state history on LC contract #1670
prune state history on LC contract #1670
Conversation
… added two additional tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What confuses me is that why not just override the old values with the new values? Does that consume more gas?
contracts/src/LightClient.sol
Outdated
stateUpdateBlockNumbers.push(blockNumber); | ||
hotShotCommitments.push(HotShotCommitment(state.blockHeight, state.blockCommRoot)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we will just push the new elements into the array, why bother deleting the first one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so that the storage is emptied and interacting with the array will consume less gas.
The goal is to maintain a history that isn't larger than maxStateHistoryAllowed. So i delete the first element and increment stateHistoryFirstIndex, so that the history is kept within this bound. The amount if storage required is a predictable and we also get a gas refund with the delete
.
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
contracts/src/LightClient.sol
Outdated
function updateStateHistory(uint256 blockNumber, LightClientState memory state) internal { | ||
if (maxStateHistoryAllowed == 0) revert InvalidMaxStateHistory(); | ||
|
||
if (stateHistoryCount == maxStateHistoryAllowed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The maxStateHistoryAllowed
name is a bit misleading right now because if the setter setMaxStateHIstoryAllowed
is used to reduce it then size of the history that is currently larger it won't be reduced because we only ever remove an element if we also add one. Unless I'm misunderstanding something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really doubt we ever want to set a smaller state history after deployment though so because all that it allows us to do is reclaim some gas. So maybe we can "fix it" by not allowing setting a lower state history?
We could also have functionality to prune multiple entries but the problem with that is that we need to then have potential issues where calls can run out of gas if the iteration is too long.
One way to resolve this is also to allow for a few (at least 2) pruning operations during an update. This makes the gas usage bounded and still allows the history to shrink.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
your understanding is correct, it does not considering the reduction of the max state history allowed. Would you allow me to add the ability to prune +1 elements at the same time? and if so, I can make it so that the maxStateHistoryAllowed can be reduced. Otherwise, i can restrict modifications to only increasing the max state history allowed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think any changes here are somewhat problematic because it potentially affects the result of challenges in the rollups. Increasing the history size definitely seems less problematic though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah true - also this light client may be deployed on L2s to support L3s - Would there be a need to shorten the maxStateHistoryAllowed
in those instances?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently we hardcode the maxStateHistoryAllowed
in the _initializeState
method but considering that the light client would also deploy on L2s to support L3s. Should it be configurable at deployment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L2s are also a lot cheaper so I wonder if it would be acceptable to default to not pruning the history on L2s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another alternative would be to use block.timestamp
instead of block numbers. That way we could at least set a default that should keep working on L2s as long as their timestamps are correct. I'm currently not 100% clear on how trustworthy block.timestamp
is, especially on L2s. I would hope that validators would only tolerate small deviations though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the answer below it sounds like the timestamp is pretty safe to use on L1 after the merge. Wdyt @alysiahuggins ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this has been addressed in a previous commit
…ements-from-stateupdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
contracts/src/LightClient.sol
Outdated
/// @notice set Max Block States allowed | ||
/// @param historySeconds The maximum duration worth of state history updates to store based on | ||
/// the block timestamp | ||
function setMaxStateHistoryDuration(uint32 historySeconds) public onlyOwner { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I think we previously discussed I think we should not allow lowering the value here since we currently don't have code to actually reduce the size in that case and it might have unintended consequences for rollups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, do we want to provide the ability to lower the value or do we think there's a little chance that will be necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we spoke offline and agreed that it's out of scope for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorted here 703546f
contracts/src/LightClient.sol
Outdated
} | ||
|
||
// We don't consider the lag time for the first two updates | ||
if (i < 2) { | ||
break; | ||
} | ||
|
||
// We've reached the first recorded block | ||
// i >= 2 because we normally clear out the array from a FIFO approach |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated comments 7720ab0
…tract when interacting with the rust bindings
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
contracts/script/README.md
Outdated
@@ -232,8 +232,8 @@ Solution: `export FOUNDRY_PROFILE=default` | |||
## LightClient Contract Deployment | |||
|
|||
```bash | |||
forge script contracts/script/LightClient.s.sol:DeployLightClientContractScript $numBlocksPerEpoch $numInitValidators \ | |||
--sig 'run(uint32, uint32)' \ | |||
forge script contracts/script/LightClient.s.sol:DeployLightClientContractScript $numBlocksPerEpoch $numInitValidators $maxHistorySeconds \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still use the old name maxHistorySeconds
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
contracts/script/LightClient.s.sol
Outdated
@@ -7,7 +7,7 @@ import { LightClient as LC } from "../src/LightClient.sol"; | |||
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; | |||
|
|||
contract DeployLightClientContractScript is Script { | |||
function run(uint32 numBlocksPerEpoch, uint32 numInitValidators) | |||
function run(uint32 numBlocksPerEpoch, uint32 numInitValidators, uint32 maxHistorySeconds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function run(uint32 numBlocksPerEpoch, uint32 numInitValidators, uint32 maxHistorySeconds) | |
function run(uint32 numBlocksPerEpoch, uint32 numInitValidators, uint32 stateHistoryRetentionPeriod) |
Appears elsewhere too, need to do search/replace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, sorted 33663d7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM missing some renames.
…pdates-and-hotshotcommitments-arrays-once-it-has-over-10-days-of-worth-of-data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: instead of storing the timestamp for every update, why can't we simply store a single value oldest_timestamp
which gets updated whenever we evict an element from the FIFO queue?
optimizer = true | ||
optimizer_runs = 200 # Increasing the number of runs saves gas but increases the size of the contract | ||
viaIR = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this necessary? it's making the compilation really slow
IMO, we usually can resolve the "stack too deep" through some refactoring. e.g. various ways to reduce local variables on the stack.
struct StateHistoryCommitment { | ||
uint64 l1BlockHeight; | ||
uint64 l1BlockTimestamp; | ||
HotShotCommitment hotShotCommitment; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a benefit to declare this as a new struct rather than just modify the old HotShotCommitment
struct with two new fields?
more complicated nested structs lead to larger memory layout.
added functionality to prune the state history using a FIFO approach and added two additional tests
Closes #1541
This PR:
This PR does not:
Key places to review:
FIFO approach to pruning and the fact that the array continues to grow though one only ever interacts with the 10 days worth of state updates due to storing the stateHistory first index
How to test this PR:
forge test --match-contract LightClient_StateUpdatesTest --ffi -vvv
Things tested