Skip to content
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

Add action contracts for migrating live orbit chains to espresso #1

Merged
merged 28 commits into from
Sep 12, 2024

Conversation

zacshowa
Copy link
Member

This PR:

This PR adds action upgrade contracts to the orbit-action repo to upgrade orbit chains to be compatible with the espresso sequencing marketplace.

This PR does not:

Include scripts to deploy and perform these action upgrades. Set the chain config in the arbOS upgrade.

Key places to review:

EspressoOspMigrationAction.sol and EspressoMigrationAction.t.sol.

forge test in the repo's top level

EspressoOspMigrationAction.sol

@zacshowa zacshowa changed the title Add action contrats for migrating live orbit chains to espresso Add action contracts for migrating live orbit chains to espresso Aug 15, 2024
function perform() external {
ArbOwner arbOwner = ArbOwner(0x0000000000000000000000000000000000000070);
arbOwner.scheduleArbOSUpgrade({
newVersion: newArbOSVersion,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldnt the new version and timestamp be function arguments instead of constructor arguments? Then we can use the same script for multiple upgrade IMO

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I originally thought. However, per the governance action contract guidelines this seems to be the proper format to write these contracts for an eventual proposal to the Arbitrum DAO.
In theory this also allows us to create more specific proposals by writing more wrapper contracts like the EspressoArbOSUpgrade that utilizes the general

import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/utils/Address.sol";

error IncorrectWasmModuleRoot(bytes32 incorrectAddr);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The errors should be a part of the contract, so I think you should add them inside the contract object

revert IncorrectWasmModuleRoot(currentWasmModuleRoot);
}

if(Address.isContract(newOspEntry) == false){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we do if(!Address.isContract(newOspEntry))

revert AddressIsNotContract(newOspEntry);
}

if(Address.isContract(currentOspEntry) == false){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@@ -0,0 +1,6 @@
export NEW_OSP_ENTRY="0x7B5F0B437EE68A22992DdD629AA22525Fc5dfa9A"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I dont think you need export in front of the environment variables ( example here)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might just be from my lack of familiarity with forge and foundry. I couldn't get the env vars to be visible to the tests unless I exported them. Sourcing the file without exporting them doesn't propagate the vars to any child processes, e.g. forge test.
If there is a different way I'm supposed to supply forge with the env vars I would love to know about it!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the file is called .env exactly it is special and automatically picked up by foundry and many other tools. Unfortunately it has to be exactly .env in the case of foundry.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do source .env-espresso-osp-migration && forge test <> to be able to have a foundry script pick up env variables that's not in the expected .env file.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true but then breaks the ability of being able to override with env vars. So this can get messy when used in scripts if one expects environment variable that are already set to take precedence.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's true. we aren't using the .env file for secrets anymore but only for config (since that's how it's been set up historically). So should this go into the .env file?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be how existing orbit upgrades are configured in the orbit-actions repo. I think it's a good idea to stick to how things are done in that repo unless it really gets in our way.

@@ -0,0 +1 @@
export UPGRADE_TIMESTAMP = "1723664126"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here



/* solhint-disable func-name-mixedcase */
//create items needed for a rollup and deploy it. This code is lovingly borrowed from the rollupcreator.t.sol foundry test.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@alysiahuggins
Copy link

Hey @zacshowa, can you also add a readme that explains these code additions and how to run the scripts

contract EspressoArbOSUpgrade is UpgradeArbOSVersionAtTimestampAction, Script {
constructor()
UpgradeArbOSVersionAtTimestampAction(
35,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when is this called? curious about this hardcoded arbOsVersion

Copy link
Member Author

@zacshowa zacshowa Aug 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be called a decent amount of time before the network upgrade is supposed to take place. This will schedule a particular function inside the nodes of an orbit network to run at the given Unix timestamp.

The hardcoded 35 comes from a discussion I had with Mathis when we were first pursuing designating this as an ArbOS upgrade.

Basically, the way ArbOS upgrades are performed is via a switch statement that has some pre-defined gaps in version numbers left open for orbit chains. We chose 35 as it leaves some room for previous upgrades, as well as room for future upgrades in the most recent gap.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh interesting - let's add that in the comments then, and maybe leave instructions in the readme if it ever has to change

}

function perform() external {
ArbOwner arbOwner = ArbOwner(0x0000000000000000000000000000000000000070);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this address used?

Copy link
Member Author

@zacshowa zacshowa Aug 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This magic value is just the location of the ArbOwner precompile that lives on all arbitrum orbit chains at a specific address.

I'll leave a comment explaining it in the code.

uint64 public immutable newArbOSVersion;
uint64 public immutable upgradeTimestamp;

constructor(uint64 _newArbOSVersion, uint64 _upgradeTimestamp) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need uint64 for the arbOSVersion?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that most of the way this is done doesn't "need" to happen this way, but I wrote these contracts to broadly conform with the guidance in the arbitrum governance repo here

For the sake of time we aren't using address registries and are instead using env variables for the generic and proposal specific version of the contracts. I'm just doing it this way to minimize the amount of future work to convert this to a reasonable proposal for the Arbitrum DAO

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok great!

uint64 public immutable upgradeTimestamp;

constructor(uint64 _newArbOSVersion, uint64 _upgradeTimestamp) {
newArbOSVersion = _newArbOSVersion;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider adding error checking to ensure that the values passed here are valid

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure which license we'd want to use but we normally default to UNLICENSED

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill go ahead and add UNLICENSED to all of the files that require it.

@@ -0,0 +1,107 @@
pragma solidity ^0.8.9;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add the SPDX license identifier

);
address postUpgradeChalManAddr = ProxyAdmin(proxyAdmin).getProxyImplementation(challengeManager);

if(postUpgradeChalManAddr != chalManImpl){

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like this check!

address _rollup,
address _proxyAdmin
){
newOspEntry = _newOspEntry;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps add some error checking for these variables in the constructor

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add the checks in the perform function to the constructor we can, in theory, remove them from the perform function to avoid using extra gas correct?


address migration = address(new EspressoOspMigrationAction());

vm.prank(rollupOwner);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider adding more tests that check for negative scenarios e.g. expecting a revert of a non-rollup owner tries to execute the upgrade

migration/README.md Outdated Show resolved Hide resolved

#### A note on Upgrade Executors

This migration presumes there to be upgrade executor contracts that are chain/rollup owners on both the parent chain, as well as the child chain. If you do not have an upgrade executor on the child chain, the contract execution commands at the end of this guide will not work.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

The parent chain is where most of the contract deployments will happen for the migration to espresso. There are two forge scripts that you need to deploy on the parent chain. These scripts are located in the following directories:

```
orbit-actions/contracts/parent-chain/espresso-migration/DeployEspressoOsp.s.sol
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use markdown links relative to files in this repo.

https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#links

1. DeployEspressoOsp.s.sol
2. DeployEspressoOspMigrationAction.s.sol

In between these deployments you need to record the address of the newly deployed OneStepProverEntry contract and export it in the env var `NEW_OSP_ENTRY`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this obvious from the output? Or should we add a jq command here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the output of that command would be obvious if you're running the same verbosity level on the forge script. But I think it also makes sense to add the command anyways. as we know exactly how forge will output the broadcast file.

Copy link

@Sneh1999 Sneh1999 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: @zacshowa can you run forge fmt to format the contracts?

@sveitser sveitser changed the base branch from main to integration September 12, 2024 06:37
@zacshowa zacshowa merged commit 751be3f into integration Sep 12, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants