Skip to content

Commit

Permalink
modification towards the idea of "Separate Dynamic and Static L1 Attr…
Browse files Browse the repository at this point in the history
…ibutes"
  • Loading branch information
blockchaindevsh committed Aug 29, 2024
1 parent 5f6abbe commit f5b8178
Showing 1 changed file with 88 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@
- [Motivation](#motivation)
- [How It Works](#how-it-works)
- [Supporting Dynamic Updates to Inbox Address](#supporting-dynamic-updates-to-inbox-address)
- [SystemConfig](#systemconfig)
- [SystemConfigHolocene](#systemconfigholocene)
- [setBatchInbox](#setbatchinbox)
- [initialize](#initialize)
- [UpdateType](#updatetype)
- [L1 Info Deposit Transaction](#l1-info-deposit-transaction)
- [L1Block](#l1block)
- [L1BlockHolocene](#l1blockholocene)
- [batchInbox](#batchinbox)
- [setL1BlockValuesEcotone](#setl1blockvaluesecotone)
- [ConfigType](#configtype)
- [setConfig](#setconfig)
- [StaticConfig](#staticconfig)
- [encodeSetBatchInbox](#encodesetbatchinbox)
- [decodeSetBatchInbox](#decodesetbatchinbox)
- [L2Client.SystemConfigByL2Hash](#l2clientsystemconfigbyl2hash)
- [L1Traversal.AdvanceL1Block](#l1traversaladvancel1block)
- [How `op-node` knows the canonical batch inbox](#how-op-node-knows-the-canonical-batch-inbox)
- [How `op-batcher` knows canonical batch inbox](#how-op-batcher-knows-canonical-batch-inbox)
- [Upgrade](#upgrade)
- [L1Block Deployment](#l1block-deployment)
- [L1Block Proxy Update](#l1block-proxy-update)
- [SystemConfig Upgrade](#systemconfig-upgrade)
- [SystemConfigHolocene Upgrade](#systemconfigholocene-upgrade)
- [Security Considerations](#security-considerations)
- [Inbox Sender](#inbox-sender)
- [Reference Implementation](#reference-implementation)
Expand Down Expand Up @@ -55,188 +58,134 @@ These modifications aim to enhance the security and efficiency of the batch subm

## Supporting Dynamic Updates to Inbox Address

### SystemConfig
### SystemConfigHolocene

The `SystemConfig` is the source of truth for the address of inbox. It stores information about the inbox address and passes the information to L2 as well.
The `SystemConfigHolocene` is the source of truth for the address of inbox. It stores information about the inbox address and passes the information to L2 as well.


#### setBatchInbox

A new function `setBatchInbox` is introduced to the `SystemConfig` contract, enabling dynamic updates to the inbox:
A new function `setBatchInbox` is introduced to the `SystemConfigHolocene` contract, enabling dynamic updates to the inbox:

```solidity
/// @notice Updates the batch inbox address. Can only be called by the owner.
/// @param _batchInbox New batch inbox address.
function setBatchInbox(address _batchInbox) external onlyOwner {
_setBatchInbox(_batchInbox);
if (_batchInbox != batchInbox()) {
Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox);
OptimismPortal(payable(optimismPortal())).setConfig(
ConfigType.SET_BATCH_INBOX,
StaticConfig.encodeSetBatchInbox({
_batchInbox: _batchInbox,
})
);
}
}
```

/// @notice Updates the batch inbox address.
/// @param _batchInbox New batch inbox address.
function _setBatchInbox(address _batchInbox) internal {
Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox);

bytes memory data = abi.encode(_batchInbox);
emit ConfigUpdate(VERSION, UpdateType.BATCH_INBOX, data);
}

```
### L1BlockHolocene

The `L1BlockHolocene` stores Layer 1 (L1) related information on Layer 2 (L2). It is extended to store the dynamic inbox address.

#### initialize
#### batchInbox

The `SystemConfig` now emits an event when the inbox is initialized, while retaining its existing support for inbox configuration during initialization.
A new field `batchInbox` is added to the `L1BlockHolocene`:

```solidity
function initialize(
address _owner,
uint32 _basefeeScalar,
uint32 _blobbasefeeScalar,
bytes32 _batcherHash,
uint64 _gasLimit,
address _unsafeBlockSigner,
ResourceMetering.ResourceConfig memory _config,
address _batchInbox,
SystemConfig.Addresses memory _addresses
)
public
initializer
{
...
// Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox);
// initialize inbox by `_setBatchInbox` so that an event is emitted.
_setBatchInbox(_batchInbox);
...
}
/// @notice The canonical batch inbox.
bytes32 public batchInbox;
```

#### UpdateType
#### ConfigType

A new enum value `BATCH_INBOX` is added to the `UpdateType` enumeration.
A new enum value `SET_BATCH_INBOX` is added to the `ConfigType` enumeration.

```solidity
enum UpdateType {
BATCHER,
GAS_CONFIG,
GAS_LIMIT,
UNSAFE_BLOCK_SIGNER,
BATCH_INBOX
enum ConfigType {
SET_GAS_PAYING_TOKEN,
ADD_DEPENDENCY,
REMOVE_DEPENDENCY,
SET_BATCH_INBOX
}
```

### L1 Info Deposit Transaction

The [`L1InfoDeposit`](https://github.com/ethereum-optimism/optimism/blob/5e317379fae65b76f5a6ee27581f0e62d2fe017a/op-node/rollup/derive/l1_block_info.go#L264) function creates a L1 Info deposit transaction based on the L1 block. It is extended to add an additional `batchInbox` parameter for the [`setL1BlockValuesEcotone`](https://github.com/ethereum-optimism/optimism/blob/5e317379fae65b76f5a6ee27581f0e62d2fe017a/packages/contracts-bedrock/src/L2/L1Block.sol#L136) function after the inbox contract feature is activated.
#### setConfig

```golang
func L1InfoDeposit(rollupCfg *rollup.Config, sysCfg eth.SystemConfig, seqNumber uint64, block eth.BlockInfo, l2BlockTime uint64) (*types.DepositTx, error) {
...
if isInboxForkButNotFirstBlock(rollupCfg, l2BlockTime) {
l1BlockInfo.BatchInbox = sysCfg.BatchInbox
l1BlockInfo.BlobBaseFee = block.BlobBaseFee()
if l1BlockInfo.BlobBaseFee == nil {
// The L2 spec states to use the MIN_BLOB_GASPRICE from EIP-4844 if not yet active on L1.
l1BlockInfo.BlobBaseFee = big.NewInt(1)
}
scalars, err := sysCfg.EcotoneScalars()
if err != nil {
return nil, err
}
l1BlockInfo.BlobBaseFeeScalar = scalars.BlobBaseFeeScalar
l1BlockInfo.BaseFeeScalar = scalars.BaseFeeScalar
// marshalBinaryInboxFork adds an additional `batchInbox` parameter based on marshalBinaryEcotone.
out, err := l1BlockInfo.marshalBinaryInboxFork()
if err != nil {
return nil, fmt.Errorf("failed to marshal InboxFork l1 block info: %w", err)
}
data = out
} else if isEcotoneButNotFirstBlock(rollupCfg, l2BlockTime) {
This function stores Layer 1 (L1) system configs for Layer 2 (L2). It is extended to support the newly introduced `SET_BATCH_INBOX` ConfigType.

```solidity
function setConfig(ConfigType _type, bytes calldata _value) external {
...
else if (_type == ConfigType.SET_BATCH_INBOX) {
_setBatchInbox(_value);
}
}
```
The `marshalBinaryInboxFork` function is added to [`L1BlockInfo`](https://github.com/ethereum-optimism/optimism/blob/5e317379fae65b76f5a6ee27581f0e62d2fe017a/op-node/rollup/derive/l1_block_info.go#L41). This new function incorporates an additional `batchInbox` parameter for the [`setL1BlockValuesEcotone`](https://github.com/ethereum-optimism/optimism/blob/5e317379fae65b76f5a6ee27581f0e62d2fe017a/packages/contracts-bedrock/src/L2/L1Block.sol#L136) function:
```golang
func (info *L1BlockInfo) marshalBinaryInboxFork() ([]byte, error) {
w := bytes.NewBuffer(make([]byte, 0, L1InfoEcotoneLen))
if err := solabi.WriteSignature(w, L1InfoFuncEcotoneBytes4); err != nil {
return nil, err
}
if err := binary.Write(w, binary.BigEndian, info.BaseFeeScalar); err != nil {
return nil, err
}
if err := binary.Write(w, binary.BigEndian, info.BlobBaseFeeScalar); err != nil {
return nil, err
}
if err := binary.Write(w, binary.BigEndian, info.SequenceNumber); err != nil {
return nil, err
}
if err := binary.Write(w, binary.BigEndian, info.Time); err != nil {
return nil, err
}
if err := binary.Write(w, binary.BigEndian, info.Number); err != nil {
return nil, err
}
if err := solabi.WriteUint256(w, info.BaseFee); err != nil {
return nil, err
}
blobBasefee := info.BlobBaseFee
if blobBasefee == nil {
blobBasefee = big.NewInt(1) // set to 1, to match the min blob basefee as defined in EIP-4844
}
if err := solabi.WriteUint256(w, blobBasefee); err != nil {
return nil, err
}
if err := solabi.WriteHash(w, info.BlockHash); err != nil {
return nil, err
}
// ABI encoding will perform the left-padding with zeroes to 32 bytes, matching the "batcherHash" SystemConfig format and version 0 byte.
if err := solabi.WriteAddress(w, info.BatcherAddr); err != nil {
return nil, err
}
// This is where marshalBinaryInboxFork differs from marshalBinaryEcotone
if err := solabi.WriteAddress(w, info.BatchInbox); err != nil {
return nil, err
}
return w.Bytes(), nil
/// @notice Internal method to set the batch inbox address.
/// @param _value The encoded value with which to set the batch inbox address.
function _setBatchInbox(bytes calldata _value) internal {
batchInbox = StaticConfig.decodeSetBatchInbox(_value);
}
```

### L1Block
### StaticConfig

The `L1Block` stores Layer 1 (L1) related information on Layer 2 (L2). It is extended to store the dynamic inbox address.
The `StaticConfig` library is used for encoding and decoding static configuration data.

#### batchInbox
#### encodeSetBatchInbox

A new field `batchInbox` is added to the `L1Block`:
This function is used on L1 to encode the static configuration data for setting a batch inbox.

```solidity
/// @notice The canonical batch inbox.
bytes32 public batchInbox;
/// @notice Encodes the static configuration data for setting a batch inbox.
/// @param _batchInbox Address of the batch inbox.
/// @return Encoded static configuration data.
function encodeSetBatchInbox(address _batchInbox) internal pure returns (bytes memory) {
return abi.encode(_batchInbox);
}
```

#### setL1BlockValuesEcotone
#### decodeSetBatchInbox

This function stores Layer 1 (L1) block values for Layer 2 (L2) since the Ecotone upgrade of the OP Stack. It is enhanced to also store the inbox address.
This function is used on L2 to decode the static configuration data for setting a batch inbox.

```solidity
function setL1BlockValuesEcotone() external {
...
sstore(batchInbox.slot, calldataload(164)) // bytes32
/// @notice Decodes the static configuration data for setting a batch inbox.
/// @param _data Encoded static configuration data.
/// @return Decoded Address of the batch inbox.
function decodeSetBatchInbox(bytes memory _data) internal pure returns (address) {
return abi.decode(_data, (address));
}

```

### L2Client.SystemConfigByL2Hash

This function is used to retrieve the system configuration for a specific L2 block hash. Prior to the fork, this information was obtained from the deposit transaction. However, post-fork, it should be read from the L2 state instead, in accordance with the concepts outlined in [this issue](https://github.com/ethereum-optimism/specs/issues/122).

### L1Traversal.AdvanceL1Block

This function is used to fetch the next L1 block. It also caches the up-to-date `SystemConfig` by iteratively applying the `SystemConfig` updates in each L1 block. The way it retrieves the `SystemConfig` updates differs pre- and post-fork:

Pre-fork:
- It retrieves the `SystemConfig` updates by parsing the [`ConfigUpdate`](https://github.com/ethereum-optimism/optimism/blob/f20b92d3eb379355c876502c4f28e72a91ab902f/packages/contracts-bedrock/src/L1/SystemConfig.sol#L124) event.

Post-fork:
- It retrieves the `SystemConfig` updates by parsing the `TransactionDeposited` event emitted by [`OptimismPortalInterop.setConfig`](https://github.com/ethereum-optimism/optimism/blob/f20b92d3eb379355c876502c4f28e72a91ab902f/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol#L41) function.
- It needs to parse the `SystemConfig` values according to [`ConfigType`](https://github.com/ethereum-optimism/optimism/blob/f20b92d3eb379355c876502c4f28e72a91ab902f/packages/contracts-bedrock/src/L2/L1BlockInterop.sol#L14), similar to [`L1BlockInterop.setConfig`](https://github.com/ethereum-optimism/optimism/blob/f20b92d3eb379355c876502c4f28e72a91ab902f/packages/contracts-bedrock/src/L2/L1BlockInterop.sol#L59).



### How `op-node` knows the canonical batch inbox

We define that the canonical batch inbox at a specific L2 block is the batch inbox of `SystemConfig` of the origin of the L2 block.
We define that the canonical batch inbox at a specific L2 block is the batch inbox of `SystemConfig` for the origin of the L2 block.

Under normal conditions, `op-node` knows the canonical batch inbox through the derivation pipeline:
1. The `L1Traversal` component first identifies the L1 `SystemConfig` changes while traversing the L1 block, via [`UpdateSystemConfigWithL1Receipts`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/l1_traversal.go#L78).
1. The [`ProcessSystemConfigUpdateLogEvent`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/system_config.go#L59) function will be modified to parse the newly added inbox change.
1. The `L1Traversal` component first identifies the L1 `SystemConfig` updates and caches the up-to-date `SystemConfig` while traversing the L1 block, via [`UpdateSystemConfigWithL1Receipts`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/l1_traversal.go#L78).
2. The `L1Retrieval` component then fetches the canonical batch inbox from the `L1Traversal` componenet and [pass](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/l1_retrieval.go#L57) it to the `DataSourceFactory` component, via `OpenData` function, similar to how [`SystemConfig.BatcherAddr`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-service/eth/types.go#L382) is handled.
3. The `FetchingAttributesBuilder` component is updated to incorporate the canonical batch inbox into the `DepositTx`, via [`L1InfoDeposit`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/l1_block_info.go#L263). This modified `DepositTx` is subsequently used to obtain the `SystemConfig` during L2 chain reorganization.
3. The `FetchingAttributesBuilder` component will convert `SystemConfig` updates into deposit transactions via [`DeriveDeposits`](https://github.com/ethereum-optimism/optimism/blob/f20b92d3eb379355c876502c4f28e72a91ab902f/op-node/rollup/derive/attributes.go#L70). After the deposit transactions are executed, the `SystemConfig` will be persisted in L2 state.

During L2 reorganization, `op-node` knows the canonical batch inbox using the `SystemConfig` parameter of [`ResettableStage.Reset(context.Context, eth.L1BlockRef, eth.SystemConfig)`](https://github.com/ethereum-optimism/optimism/blob/71928829ca7ece48152159daa1d231eac2df03b3/op-node/rollup/derive/pipeline.go#L38) function, where `SystemConfig` is derived from the `DepositTx` of the corresponding L2 block.

Expand All @@ -246,7 +195,7 @@ Immediately before submitting a new batch, `op-batcher` fetches the current inbo

## Upgrade

The custom gas token upgrade is not yet defined to be part of a particular network upgrade, but it will be scheduled as part of a future hardfork. On the network upgrade block, a set of deposit transaction based upgrade transactions are deterministically generated by the derivation pipeline in the following order:
The inbox contract upgrade is not yet defined to be part of a particular network upgrade, but it will be scheduled as part of a future hardfork. On the network upgrade block, a set of deposit transaction based upgrade transactions are deterministically generated by the derivation pipeline in the following order:

- L1 Attributes Transaction calling `setL1BlockValuesEcotone`
- User deposits from L1
Expand Down Expand Up @@ -289,9 +238,9 @@ RPC access to the derivation pipeline and make the upgrade transactions non dete
- `data`: TODO
- `sourceHash`: TODO

### SystemConfig Upgrade
### SystemConfigHolocene Upgrade

Finally, to dynamically change the inbox address, `SystemConfig` on L1 will be upgraded to accept a new inbox address.
Finally, to dynamically change the inbox address, `SystemConfigHolocene` on L1 will be upgraded to accept a new inbox address.

Note that according to the [Optimism Style Guide](https://github.com/ethereum-optimism/optimism/blob/9d31040ecf8590423adf267ad24b03bc1bf7273b/packages/contracts-bedrock/STYLE_GUIDE.md), The process for upgrading the implementation is as follows:
1. Upgrade the implementation to the `StorageSetter` contract.
Expand Down

0 comments on commit f5b8178

Please sign in to comment.