specs
specs copied to clipboard
Potential Research Area: Separate Dynamic and Static L1 Attributes Values
As of Ecotone, the L1 Attributes transaction includes the following information:
- baseFeeScalar
- blobBaseFeeScalar
- sequenceNumber
- l1BlockTimestamp
- l1BlockNumber
- basefee
- blobBaseFee
- l1BlockHash
- batcherHash
Not all of this information changes every L2 block, which is the reasoning behind Diff Based L1 Attributes Transactions. Some fields are guaranteed to change every L2 block like the sequence number, some fields change every time the L1 origin updates (L1 blocknumber, L1 timestamp, etc) and some fields only change based on chain operator input (batcher hash).
For the fields that change automatically based on the L1 origin, we can call those dynamic values. For the values that only change based on chain operator input, we can call those static values.
The custom gas token spec adds a new static value which is the address of the ERC20 that represents the gas paying asset for the L2. A new design pattern is followed where the value is set in the system config and then it triggers a special deposit transaction that is able to set the address directly in the L2's L1Block predeploy. This pattern can be made more generic to work with all static values.
The next time that we need to add a static value to the L1 Attributes transaction, we should:
- Make a generic pipeline that is very similar to the way that custom gas token deposits its information into L2
- Remove all static values from the L1 attributes transaction and instead allow them to be configured "just in time" by the generic pipeline
This would allow us to easily allow for the configuration of the batch inbox for example
Much of the design has already been fleshed out for interop. The high level is there is a new setter function on the OptimismPortal for spoofing the depositor address via deposit txs that are able to call the L1Block contract to set important values. This could be "upstreamed" into the mainline contracts as part of holocene to reduce the diff for the interop contracts upgrade.
See the following links:
- https://github.com/ethereum-optimism/optimism/blob/5b7d2b98b109302b1356eee18ebf0dd970b47bb4/packages/contracts-bedrock/src/L2/L1BlockInterop.sol#L14
- https://github.com/ethereum-optimism/optimism/blob/5b7d2b98b109302b1356eee18ebf0dd970b47bb4/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol#L29
- https://github.com/ethereum-optimism/optimism/blob/5b7d2b98b109302b1356eee18ebf0dd970b47bb4/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol#L26
Simplification of the diff-based attribute proposal we discussed in discord:
If we remove all static attributes (e.g. the scalars), then as I understand it we're left only with L1 attributes that (for the vast majority of the cases) change with each L1 origin update, with the only exception being sequence number. So assuming we move out all the static attributes, we could, for each L2 block, include only the sequence number, except for L2 blocks with sequencer #0, and they'd have all the L1 origin related attributes following the 0 sequence number. No need for a bitmap - the sequence number itself could indicate whether more attributes need to be parsed.
@tynes added: and we could put the branching logic in the setL1BlockAttributesHolocene function, read u8 from calldata as sequence number, if non zero then return, otherwise read more from the calldata buffer i think that u8 is safe, can't imagine having that many blocks in an L2 epoch
The following mermaid diagram shows the control flow:
graph LR
subgraph L1
SystemConfig -- "setConfig(uint8)" --> OptimismPortal
end
subgraph L2
L1Block
end
OptimismPortal -- "setConfig(uint8)" --> L1Block
The argument to setConfig would be an enum, like so:
enum ConfigType {
SET_GAS_PAYING_TOKEN,
ADD_DEPENDENCY, // used in interop
REMOVE_DEPENDENCY, // used in interop
FEE_CONFIG, // replaces SystemConfig.UpdateType.GAS_CONFIG
BATCHER_HASH, // replaces SystemConfig.UpdateType.BATCHER
UNSAFE_BLOCK_SIGNER, // replaces SystemConfig.UpdateType.UNSAFE_BLOCK_SIGNER
GAS_LIMIT // replaces SystemConfig.UpdateType.GAS_LIMIT
}
The SystemConfig would have higher level setters that enable role based access control, an example in the interop contracts can be seen here.
The OptimismPortal would emit a TransactionDeposited event from the identity of an account with no known key, indicating that the deposit is coming from the system. See this example from the interop contracts.
It may be the case that some of the above config types are more difficult to implement, for example the batcher hash influences derivation. We would need to be mindful of code that tracks the SystemConfig representation within the derivation pipeline here. This would replace the need for ConfigUpdate events to be tracked within the derivation pipeline, making the fault proof program much cheaper, see https://github.com/ethereum-optimism/specs/issues/330
This PR serves as a first step for "Separate Dynamic and Static L1 Attributes Values", it migrates existing SystemConfig updates to follow the new pattern.
Relevant pr for tracking work: https://github.com/ethereum-optimism/optimism/pull/11600
We are going to punt this issue and remove it from the Holocene scope, since we plan to focus our on https://github.com/ethereum-optimism/specs/pull/358 changes only.
- As @tynes stated: "We are explicitly not scoping https://github.com/ethereum-optimism/specs/issues/122 because it will result in a large diff to the proofs. In the future we can work on proof optimizations"
The specific reason why this is being descoped is due to the way that it impacts proofs. With https://github.com/ethereum-optimism/specs/issues/122#issuecomment-2293704907 as context, the L1 attributes data is in history (transaction calldata) rather than storage. This means that during derivation, L2 history is able to be accessed arbitrarily. State is a bit trickier to access arbitrarily without archival state access. This proposal involved moving the L1 attributes data to storage by putting it into L2 state and deduplicating the data from being posted over and over again in each L1 attributes transaction.
This can be considered an optimization in the future. Perhaps the model that we want is in each epoch (where sequencer number is 0) we emit an event that includes the most recent L1 attributes data and then store the rest into storage. This gives a "snapshot" of the data over time so that only a small amount of reexecution is required to reproduce the state at a specific L2 blocknumber.
Achieving this will help to remove the need to iterate through all L1 logs searching for UpdateType events, making the derivation pipeline cheaper to execute.
We will still be following the architecture in https://github.com/ethereum-optimism/specs/issues/122#issuecomment-2308584680 but not including any UpdateType enum values
This can be considered an optimization in the future. Perhaps the model that we want is in each epoch (where sequencer number is 0) we emit an event that includes the most recent L1 attributes data and then store the rest into storage. This gives a "snapshot" of the data over time so that only a small amount of reexecution is required to reproduce the state at a specific L2 blocknumber.
I'm a bit confused by the purpose of "snapshot".
There're 3 typical cases to access SystemConfig:
- in
L1Traversal.AdvanceL1Block, where this component needs to know theSystemConfigfor a corresponding L1 block. This component should be able to computeSystemConfigsoly from L1 events. - in
L2Client.SystemConfigByL2Hash, where this component needs to know theSystemConfigfor a corresponding L2 block, mostly when reorganization.- I think the purpose of "snapshot" is to make it possible to compute the the
SystemConfigfor a corresponding L2 block bycalculate(snapshot, subsequent_system_config_updates_by_parsing_L2_tx)instead of from L2 history state, is it right? But it seems unnecessary since if you needs to reorg to a history L2 block, you must already have that L2 history state anyway..
- I think the purpose of "snapshot" is to make it possible to compute the the
- for DAPPs, where the user should query the
L1Blockcontract to know the latestSystemConfigin L2. TheSystemConfigmaintained byL1Blockcontract is a result of executing deposit transactions generated by L1.
Including historical context for the diff based L1 attributes tx as one attempt to deduplicate calldata from the L1 attributes tx: https://github.com/ethereum-optimism/specs/pull/375