-
Notifications
You must be signed in to change notification settings - Fork 153
Use transient storage in Outbox and Bridge #260
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
Draft
gvladika
wants to merge
30
commits into
develop
Choose a base branch
from
t-store
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
e5e7595
Deprecate context storage var
gvladika fd53ccb
Remove unnecessary blocks
gvladika 25e7cf3
Use transient storage
gvladika 85b63dd
Make transient vars internal
gvladika c83abae
Use transient storage in bridge
gvladika f293f04
Update test
gvladika 628bfe5
Use evm version cancun
gvladika bae984d
Temporary exclude lint check
gvladika 3f2fa21
Storage files update with new var names for deprecated vars
gvladika 5a7bfb4
Temporary skip, plugins breaking
gvladika 6f7ce01
Audit ci exceptions
gvladika fe08cd8
Test transient activeOutbox
gvladika 39c3937
Make sure context is resetted
gvladika f1a667d
Pack transient storage vars
gvladika cf05177
Update slither db
gvladika b5a1ee3
Add post upgrade init to deprecate active outbox
gvladika 2af9b1f
Add postUpgradeInit to interface
gvladika 33e63ff
Update slither db
gvladika 62ed40c
Merge branch 'bold-merge' into t-store
gvladika 605778c
Disable another check until transient supoprt is added to tooling
gvladika 581229e
Use default getter
gvladika 9fda730
Do not pack transient storage context vars
gvladika 8f8dd16
Remove postUpgradeInit. Deprecated slots will stay dirty after upgrade
gvladika 2d78a1f
Update slither db
gvladika 3042055
Audit ci update
gvladika bf7ee00
Merge branch 'bold-merge' into t-store
gvladika 2f4dcf1
Update sigs to remove postUpgradeInit
gvladika a1ae965
Merge branch 't-store' of github.com:OffchainLabs/nitro-contracts int…
gvladika 9b916fa
Update comments for deprecated values
gvladika 49514a3
Slither update
gvladika File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
pragma solidity ^0.8.4; | ||
pragma solidity ^0.8.28; | ||
|
||
import { | ||
AlreadyInit, | ||
|
@@ -45,54 +45,33 @@ abstract contract AbsOutbox is DelegateCallAware, IOutbox { | |
uint256 withdrawalAmount; | ||
} | ||
|
||
// Note, these variables are set and then wiped during a single transaction. | ||
// Therefore their values don't need to be maintained, and their slots will | ||
// hold default values (which are interpreted as empty values) outside of transactions | ||
L2ToL1Context internal context; | ||
|
||
// default context values to be used in storage instead of zero, to save on storage refunds | ||
// it is assumed that arb-os never assigns these values to a valid leaf to be redeemed | ||
uint128 private constant L2BLOCK_DEFAULT_CONTEXT = type(uint128).max; | ||
uint96 private constant L1BLOCK_DEFAULT_CONTEXT = type(uint96).max; | ||
uint128 private constant TIMESTAMP_DEFAULT_CONTEXT = type(uint128).max; | ||
bytes32 private constant OUTPUTID_DEFAULT_CONTEXT = bytes32(type(uint256).max); | ||
address private constant SENDER_DEFAULT_CONTEXT = address(type(uint160).max); | ||
/// @dev Deprecated in place of transient storage | ||
/// @dev Due to how arb governance works, it is not possible to wipe out the content of these | ||
/// 4 storage slots during the upgrade. So after deprecation values in these slots will | ||
/// stay "dirty" with default values, but slots will not be used or accessible in any way. | ||
|
||
L2ToL1Context internal __context; | ||
|
||
uint128 public constant OUTBOX_VERSION = 2; | ||
|
||
// Transient storage vars for context | ||
// Using structs in transient storage is not supported in 0.8.28 | ||
uint256 public transient l2ToL1Block; | ||
uint256 public transient l2ToL1Timestamp; | ||
bytes32 public transient l2ToL1OutputId; | ||
address public transient l2ToL1Sender; | ||
uint256 public transient l2ToL1EthBlock; | ||
// exposed only in ERC20Outbox. In eth based chains withdrawal amount can be accessed via msg.value | ||
uint256 internal transient _l2ToL1WithdrawalAmount; | ||
|
||
function initialize( | ||
IBridge _bridge | ||
) external onlyDelegated { | ||
if (address(_bridge) == address(0)) revert HadZeroInit(); | ||
if (address(bridge) != address(0)) revert AlreadyInit(); | ||
// address zero is returned if no context is set, but the values used in storage | ||
// are non-zero to save users some gas (as storage refunds are usually maxed out) | ||
// EIP-1153 would help here | ||
context = L2ToL1Context({ | ||
l2Block: L2BLOCK_DEFAULT_CONTEXT, | ||
l1Block: L1BLOCK_DEFAULT_CONTEXT, | ||
timestamp: TIMESTAMP_DEFAULT_CONTEXT, | ||
outputId: OUTPUTID_DEFAULT_CONTEXT, | ||
sender: SENDER_DEFAULT_CONTEXT, | ||
withdrawalAmount: _defaultContextAmount() | ||
}); | ||
bridge = _bridge; | ||
rollup = address(_bridge.rollup()); | ||
} | ||
|
||
function postUpgradeInit() external onlyDelegated onlyProxyOwner { | ||
// prevent postUpgradeInit within a withdrawal | ||
if (context.l2Block != L2BLOCK_DEFAULT_CONTEXT) revert BadPostUpgradeInit(); | ||
context = L2ToL1Context({ | ||
l2Block: L2BLOCK_DEFAULT_CONTEXT, | ||
l1Block: L1BLOCK_DEFAULT_CONTEXT, | ||
timestamp: TIMESTAMP_DEFAULT_CONTEXT, | ||
outputId: OUTPUTID_DEFAULT_CONTEXT, | ||
sender: SENDER_DEFAULT_CONTEXT, | ||
withdrawalAmount: _defaultContextAmount() | ||
}); | ||
} | ||
|
||
/// @notice Allows the rollup owner to sync the rollup address | ||
function updateRollupAddress() external { | ||
if (msg.sender != IOwnable(rollup).owner()) { | ||
|
@@ -109,51 +88,11 @@ abstract contract AbsOutbox is DelegateCallAware, IOutbox { | |
emit SendRootUpdated(root, l2BlockHash); | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function l2ToL1Sender() external view returns (address) { | ||
address sender = context.sender; | ||
// we don't return the default context value to avoid a breaking change in the API | ||
if (sender == SENDER_DEFAULT_CONTEXT) return address(0); | ||
return sender; | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function l2ToL1Block() external view returns (uint256) { | ||
uint128 l2Block = context.l2Block; | ||
// we don't return the default context value to avoid a breaking change in the API | ||
if (l2Block == L2BLOCK_DEFAULT_CONTEXT) return uint256(0); | ||
return uint256(l2Block); | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function l2ToL1EthBlock() external view returns (uint256) { | ||
uint96 l1Block = context.l1Block; | ||
// we don't return the default context value to avoid a breaking change in the API | ||
if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0); | ||
return uint256(l1Block); | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function l2ToL1Timestamp() external view returns (uint256) { | ||
uint128 timestamp = context.timestamp; | ||
// we don't return the default context value to avoid a breaking change in the API | ||
if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0); | ||
return uint256(timestamp); | ||
} | ||
|
||
/// @notice batch number is deprecated and now always returns 0 | ||
function l2ToL1BatchNum() external pure returns (uint256) { | ||
return 0; | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function l2ToL1OutputId() external view returns (bytes32) { | ||
bytes32 outputId = context.outputId; | ||
// we don't return the default context value to avoid a breaking change in the API | ||
if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0); | ||
return outputId; | ||
} | ||
|
||
/// @inheritdoc IOutbox | ||
function executeTransaction( | ||
bytes32[] calldata proof, | ||
|
@@ -200,27 +139,37 @@ abstract contract AbsOutbox is DelegateCallAware, IOutbox { | |
) internal { | ||
emit OutBoxTransactionExecuted(to, l2Sender, 0, outputId); | ||
|
||
// we temporarily store the previous values so the outbox can naturally | ||
// unwind itself when there are nested calls to `executeTransaction` | ||
uint256 prevL2Block = l2ToL1Block; | ||
uint256 prevTimestamp = l2ToL1Timestamp; | ||
bytes32 prevOutputId = l2ToL1OutputId; | ||
address prevSender = l2ToL1Sender; | ||
uint256 prevL1Block = l2ToL1EthBlock; | ||
uint256 prevWithdrawalAmount = _l2ToL1WithdrawalAmount; | ||
|
||
// get amount to unlock based on provided value. It might differ in case | ||
// of native token which uses number of decimals different than 18 | ||
uint256 amountToUnlock = _getAmountToUnlock(value); | ||
|
||
// we temporarily store the previous values so the outbox can naturally | ||
// unwind itself when there are nested calls to `executeTransaction` | ||
L2ToL1Context memory prevContext = context; | ||
|
||
context = L2ToL1Context({ | ||
sender: l2Sender, | ||
l2Block: uint128(l2Block), | ||
l1Block: uint96(l1Block), | ||
timestamp: uint128(l2Timestamp), | ||
outputId: bytes32(outputId), | ||
withdrawalAmount: _amountToSetInContext(amountToUnlock) | ||
}); | ||
// store the new values into transient vars for the `executeTransaction` call | ||
l2ToL1Block = l2Block; | ||
l2ToL1Timestamp = l2Timestamp; | ||
l2ToL1OutputId = bytes32(outputId); | ||
l2ToL1Sender = l2Sender; | ||
l2ToL1EthBlock = l1Block; | ||
_l2ToL1WithdrawalAmount = _amountToSetInContext(amountToUnlock); | ||
|
||
// set and reset vars around execution so they remain valid during call | ||
executeBridgeCall(to, amountToUnlock, data); | ||
|
||
context = prevContext; | ||
// restore the previous values | ||
l2ToL1Block = prevL2Block; | ||
l2ToL1Timestamp = prevTimestamp; | ||
l2ToL1OutputId = prevOutputId; | ||
l2ToL1Sender = prevSender; | ||
l2ToL1EthBlock = prevL1Block; | ||
_l2ToL1WithdrawalAmount = prevWithdrawalAmount; | ||
} | ||
|
||
function _calcSpentIndexOffset( | ||
|
@@ -293,10 +242,6 @@ abstract contract AbsOutbox is DelegateCallAware, IOutbox { | |
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item))); | ||
} | ||
|
||
/// @notice default value to be used for 'amount' field in L2ToL1Context outside of transaction execution. | ||
/// @return default 'amount' in case of ERC20-based rollup is type(uint256).max, or 0 in case of ETH-based rollup | ||
function _defaultContextAmount() internal pure virtual returns (uint256); | ||
|
||
/// @notice based on provided value, get amount of ETH/token to unlock. In case of ETH-based rollup this amount | ||
/// will always equal the provided value. In case of ERC20-based rollup, amount will be re-adjusted to | ||
/// reflect the number of decimals used by native token, in case it is different than 18. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.