From 59d3cbd929a49b57635c9d39268d8725429809b0 Mon Sep 17 00:00:00 2001 From: gzeon Date: Thu, 21 Nov 2024 19:57:18 +0800 Subject: [PATCH] refactor: simplify BOLDUpgradeAction (#266) * chore: use 2.1.0 for OldRollup * fix: wait for deployment * feat: allow excessStakeReceiver to be eoa * wip: print action calldata * wip: show executor perform call data * fix: testnode master rollup addr * wip: add local testnode executor * wip: testnode validator * wip: testnode validator wallet * fix: small range lookup * chore: sample env for testnode * feat: bold upgrade execute and improved logging * fix: use nextInboxPosition at upgrade to verify * Revert "fix: use nextInboxPosition at upgrade to verify" This reverts commit 69488237e466df2a52138837e906c327e3f70864. * fix: getlog range * fix: nextInboxPosition * chore: print bold addresses * chore: log more stuffs * chore: use 1000 range when searching log * fix: parse event to get nextInboxPosition and more logging * feat: allow ROLLUP_ADDRESS override in bold upgrade * refactor: remove rollup reader * format: fix * refactor: do not upgrade old rollup * fix: format again * fix: typo * fix: min version required * chore: warn if old rollup is old * feat: make bold rollup address predictable easily * fix: expectedRollupAddress * feat: isRollupDeployedAtAddress * feat: validateRollupDeployedAtAddress * fix: squeeze within size limit * chore: whitelist npm audit issue * chore: remove excessStakeReceiver check * chore: revert typo --- package.json | 1 - scripts/boldUpgradeCommon.ts | 2 - scripts/boldUpgradeFunctions.ts | 42 ++------- scripts/executeBoldUpgrade.ts | 152 ++++++++++++++++++++++--------- scripts/populateLookup.ts | 3 +- src/rollup/BOLDUpgradeAction.sol | 137 ++++++++++------------------ yarn.lock | 21 ----- 7 files changed, 166 insertions(+), 192 deletions(-) diff --git a/package.json b/package.json index 08ae365f5..7688ad40e 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,6 @@ }, "private": false, "devDependencies": { - "@arbitrum/nitro-contracts-2.1.0": "npm:@arbitrum/nitro-contracts@2.1.0", "@arbitrum/sdk": "^3.4.1", "@ethersproject/providers": "^5.7.2", "@nomicfoundation/hardhat-verify": "^2.0.9", diff --git a/scripts/boldUpgradeCommon.ts b/scripts/boldUpgradeCommon.ts index abe2bd1ac..a9c538a53 100644 --- a/scripts/boldUpgradeCommon.ts +++ b/scripts/boldUpgradeCommon.ts @@ -10,12 +10,10 @@ export interface DeployedContracts { rei: string outbox: string inbox: string - oldRollupUser: string newRollupUser: string newRollupAdmin: string challengeManager: string boldAction: string - rollupReader: string preImageHashLookup: string prover0: string proverMem: string diff --git a/scripts/boldUpgradeFunctions.ts b/scripts/boldUpgradeFunctions.ts index 474272735..ad37db808 100644 --- a/scripts/boldUpgradeFunctions.ts +++ b/scripts/boldUpgradeFunctions.ts @@ -11,21 +11,16 @@ import { Outbox__factory, RollupAdminLogic__factory, RollupEventInbox__factory, - RollupReader__factory, RollupUserLogic__factory, SequencerInbox__factory, Inbox__factory, StateHashPreImageLookup__factory, IReader4844__factory, + IOldRollup__factory, } from '../build/types' import { bytecode as Reader4844Bytecode } from '../out/yul/Reader4844.yul/Reader4844.json' import { DeployedContracts, Config } from './boldUpgradeCommon' import { AssertionStateStruct } from '../build/types/src/challengeV2/IAssertionChain' -// taken from https://github.com/OffchainLabs/nitro-contracts/blob/210e5b3bc96a513d276deaba90399130a60131d5/src/rollup/RollupUserLogic.sol -import { - abi as OldRollupAbi, - bytecode as OldRollupBytecode, -} from '@arbitrum/nitro-contracts-2.1.0/build/contracts/src/rollup/RollupUserLogic.sol/RollupUserLogic.json' import { verifyContract } from './deploymentUtils' export const deployDependencies = async ( @@ -35,9 +30,7 @@ export const deployDependencies = async ( isDelayBufferable: boolean, log: boolean = false, verify: boolean = true -): Promise< - Omit -> => { +): Promise> => { const bridgeFac = new Bridge__factory(signer) const bridge = await bridgeFac.deploy() await bridge.deployed() @@ -119,21 +112,6 @@ export const deployDependencies = async ( await verifyContract('Inbox', inbox.address, [maxDataSize]) } - const oldRollupUserFac = new ContractFactory( - OldRollupAbi, - OldRollupBytecode, - signer - ) - const oldRollupUser = await oldRollupUserFac.deploy() - await oldRollupUser.deployed() - if (log) { - console.log(`Old rollup user logic deployed at: ${oldRollupUser.address}`) - } - if (verify) { - await oldRollupUser.deployTransaction.wait(5) - await verifyContract('OldRollupUserLogic', oldRollupUser.address, []) - } - const newRollupUserFac = new RollupUserLogic__factory(signer) const newRollupUser = await newRollupUserFac.deploy() await newRollupUser.deployed() @@ -238,7 +216,6 @@ export const deployDependencies = async ( rei: rei.address, outbox: outbox.address, inbox: inbox.address, - oldRollupUser: oldRollupUser.address, newRollupUser: newRollupUser.address, newRollupAdmin: newRollupAdmin.address, challengeManager: challengeManager.address, @@ -291,7 +268,6 @@ export const deployBoldUpgrade = async ( const deployedAndBold = { ...deployed, boldAction: boldUpgradeAction.address, - rollupReader: await boldUpgradeAction.ROLLUP_READER(), preImageHashLookup: await boldUpgradeAction.PREIMAGE_LOOKUP(), } @@ -301,12 +277,11 @@ export const deployBoldUpgrade = async ( export const populateLookup = async ( wallet: Signer, rollupAddr: string, - preImageHashLookupAddr: string, - rollupReaderAddr: string + preImageHashLookupAddr: string ) => { - const oldRollup = new Contract(rollupAddr, OldRollupAbi, wallet.provider) - const latestConfirmed: number = await oldRollup.latestConfirmed() + const oldRollup = IOldRollup__factory.connect(rollupAddr, wallet) + const latestConfirmed = await oldRollup.latestConfirmed() let latestConfirmedLog let toBlock = await wallet.provider!.getBlockNumber() for (let i = 0; i < 100; i++) { @@ -343,11 +318,8 @@ export const populateLookup = async ( preImageHashLookupAddr, wallet ) - const oldRollupReader = RollupReader__factory.connect( - rollupReaderAddr, - wallet - ) - const node = await oldRollupReader.getNode(latestConfirmed) + + const node = await oldRollup.getNode(latestConfirmed) const stateHash = await lookup.stateHash(afterState, inboxCount) if (node.stateHash != stateHash) { throw new Error(`State hash mismatch ${node.stateHash} != ${stateHash}}`) diff --git a/scripts/executeBoldUpgrade.ts b/scripts/executeBoldUpgrade.ts index 7f4cb8188..41e2c64e5 100644 --- a/scripts/executeBoldUpgrade.ts +++ b/scripts/executeBoldUpgrade.ts @@ -1,4 +1,10 @@ -import { BigNumberish, Contract, ContractReceipt, Wallet } from 'ethers' +import { + BigNumber, + BigNumberish, + Contract, + ContractReceipt, + Wallet, +} from 'ethers' import { ethers } from 'hardhat' import { Config, @@ -12,9 +18,9 @@ import { Bridge__factory, EdgeChallengeManager, EdgeChallengeManager__factory, + IOldRollup__factory, Outbox__factory, RollupEventInbox__factory, - RollupReader__factory, RollupUserLogic, RollupUserLogic__factory, SequencerInbox__factory, @@ -22,7 +28,6 @@ import { import { abi as UpgradeExecutorAbi } from '@offchainlabs/upgrade-executor/build/contracts/src/UpgradeExecutor.sol/UpgradeExecutor.json' import dotenv from 'dotenv' import { RollupMigratedEvent } from '../build/types/src/rollup/BOLDUpgradeAction.sol/BOLDUpgradeAction' -import { abi as OldRollupAbi } from '@arbitrum/nitro-contracts-2.1.0/build/contracts/src/rollup/RollupUserLogic.sol/RollupUserLogic.json' import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers' import { getAddress } from 'ethers/lib/utils' import path from 'path' @@ -45,20 +50,19 @@ const executors: { [key: string]: string } = { arb1: '0xE6841D92B0C345144506576eC13ECf5103aC7f49', nova: '0xE6841D92B0C345144506576eC13ECf5103aC7f49', sepolia: '0x6EC62D826aDc24AeA360be9cF2647c42b9Cdb19b', - local: '0x5E1497dD1f08C87b2d8FE23e9AAB6c1De833D927' + local: '0x5E1497dD1f08C87b2d8FE23e9AAB6c1De833D927', } async function getPreUpgradeState(l1Rpc: JsonRpcProvider, config: Config) { - const oldRollupContract = new Contract( + const oldRollupContract = IOldRollup__factory.connect( config.contracts.rollup, - OldRollupAbi, l1Rpc ) const stakerCount = await oldRollupContract.stakerCount() const stakers: string[] = [] - for (let i = 0; i < stakerCount; i++) { + for (let i = BigNumber.from(0); i.lt(stakerCount); i = i.add(1)) { stakers.push(await oldRollupContract.getStakerAddress(i)) } @@ -91,7 +95,7 @@ async function perform( if (!l1PrivKey) { throw new Error('L1_PRIV_KEY env variable not set') } - let timelockSigner = (new Wallet(l1PrivKey, l1Rpc)) as unknown as JsonRpcSigner + let timelockSigner = new Wallet(l1PrivKey, l1Rpc) as unknown as JsonRpcSigner if (process.env.ANVILFORK === 'true') { timelockSigner = await l1Rpc.getSigner(executor) await l1Rpc.send('hardhat_impersonateAccount', [executor]) @@ -121,7 +125,7 @@ async function perform( console.log('eoa with executor role:', executor) console.log('upgrade executor:', config.contracts.upgradeExecutor) - console.log("execute(...) call to upgrade executor:", performCallData) + console.log('execute(...) call to upgrade executor:', performCallData) console.log('executing the upgrade...') const receipt = (await ( @@ -133,52 +137,97 @@ async function perform( async function verifyPostUpgrade(params: VerificationParams) { console.log('verifying the upgrade...') - const { l1Rpc, deployedContracts, receipt } = params + const { l1Rpc, deployedContracts, config, receipt } = params const boldAction = BOLDUpgradeAction__factory.connect( deployedContracts.boldAction, l1Rpc ) - const rollupMigratedLogs = receipt.events!.filter((event) => event.topics[0] === boldAction.interface.getEventTopic('RollupMigrated')) + const rollupMigratedLogs = receipt.events!.filter( + event => + event.topics[0] === boldAction.interface.getEventTopic('RollupMigrated') + ) if (rollupMigratedLogs.length !== 1) { console.log(rollupMigratedLogs) throw new Error('RollupMigratedEvent not found or have multiple') } - const rollupMigratedLog = boldAction.interface.parseLog(rollupMigratedLogs[0]).args as RollupMigratedEvent['args'] + const rollupMigratedLog = boldAction.interface.parseLog(rollupMigratedLogs[0]) + .args as RollupMigratedEvent['args'] + + await boldAction.validateRollupDeployedAtAddress( + rollupMigratedLog.rollup, + config.contracts.upgradeExecutor, + config.settings.chainId + ) const boldRollup = RollupUserLogic__factory.connect( rollupMigratedLog.rollup, l1Rpc ) - const assertionCreatedLogs = receipt.events!.filter((event) => event.topics[0] === boldRollup.interface.getEventTopic('AssertionCreated')) + const assertionCreatedLogs = receipt.events!.filter( + event => + event.topics[0] === boldRollup.interface.getEventTopic('AssertionCreated') + ) if (assertionCreatedLogs.length !== 1) { console.log(assertionCreatedLogs) throw new Error('AssertionCreatedEvent not found or have multiple') } - const assertionCreatedLog = boldRollup.interface.parseLog(assertionCreatedLogs[0]).args as AssertionCreatedEvent['args'] + const assertionCreatedLog = boldRollup.interface.parseLog( + assertionCreatedLogs[0] + ).args as AssertionCreatedEvent['args'] console.log('Old Rollup:', params.config.contracts.rollup) console.log('BOLD Rollup:', rollupMigratedLog.rollup) console.log('BOLD Challenge Manager:', rollupMigratedLog.challengeManager) - console.log('BOLD AssertionCreated assertionHash:', assertionCreatedLog.assertionHash) - console.log('BOLD AssertionCreated parentAssertionHash:', assertionCreatedLog.parentAssertionHash) - console.log('BOLD AssertionCreated assertion:', JSON.stringify(assertionCreatedLog.assertion)) - console.log('BOLD AssertionCreated afterInboxBatchAcc:', assertionCreatedLog.afterInboxBatchAcc) - console.log('BOLD AssertionCreated inboxMaxCount:', assertionCreatedLog.inboxMaxCount) - console.log('BOLD AssertionCreated wasmModuleRoot:', assertionCreatedLog.wasmModuleRoot) - console.log('BOLD AssertionCreated requiredStake:', assertionCreatedLog.requiredStake) - console.log('BOLD AssertionCreated challengeManager:', assertionCreatedLog.challengeManager) - console.log('BOLD AssertionCreated confirmPeriodBlocks:', assertionCreatedLog.confirmPeriodBlocks) + console.log( + 'BOLD AssertionCreated assertionHash:', + assertionCreatedLog.assertionHash + ) + console.log( + 'BOLD AssertionCreated parentAssertionHash:', + assertionCreatedLog.parentAssertionHash + ) + console.log( + 'BOLD AssertionCreated assertion:', + JSON.stringify(assertionCreatedLog.assertion) + ) + console.log( + 'BOLD AssertionCreated afterInboxBatchAcc:', + assertionCreatedLog.afterInboxBatchAcc + ) + console.log( + 'BOLD AssertionCreated inboxMaxCount:', + assertionCreatedLog.inboxMaxCount + ) + console.log( + 'BOLD AssertionCreated wasmModuleRoot:', + assertionCreatedLog.wasmModuleRoot + ) + console.log( + 'BOLD AssertionCreated requiredStake:', + assertionCreatedLog.requiredStake + ) + console.log( + 'BOLD AssertionCreated challengeManager:', + assertionCreatedLog.challengeManager + ) + console.log( + 'BOLD AssertionCreated confirmPeriodBlocks:', + assertionCreatedLog.confirmPeriodBlocks + ) const edgeChallengeManager = EdgeChallengeManager__factory.connect( rollupMigratedLog.challengeManager, l1Rpc ) - const newRollup = RollupUserLogic__factory.connect(rollupMigratedLog.rollup, l1Rpc) + const newRollup = RollupUserLogic__factory.connect( + rollupMigratedLog.rollup, + l1Rpc + ) await checkSequencerInbox(params, newRollup) await checkInbox(params) @@ -187,7 +236,12 @@ async function verifyPostUpgrade(params: VerificationParams) { await checkOutbox(params, newRollup) const { oldLatestConfirmedStateHash } = await checkOldRollup(params) console.log('oldLatestConfirmedStateHash', oldLatestConfirmedStateHash) - await checkNewRollup(params, newRollup, edgeChallengeManager, assertionCreatedLog.inboxMaxCount) + await checkNewRollup( + params, + newRollup, + edgeChallengeManager, + assertionCreatedLog.inboxMaxCount + ) await checkNewChallengeManager(params, newRollup, edgeChallengeManager) console.log('upgrade verified') @@ -336,12 +390,13 @@ async function checkBridge( } } -async function checkOldRollup(params: VerificationParams): Promise<{oldLatestConfirmedStateHash: string}> { - const { l1Rpc, config, deployedContracts, preUpgradeState } = params +async function checkOldRollup( + params: VerificationParams +): Promise<{ oldLatestConfirmedStateHash: string }> { + const { l1Rpc, config, preUpgradeState } = params - const oldRollupContract = new Contract( + const oldRollupContract = IOldRollup__factory.connect( config.contracts.rollup, - OldRollupAbi, l1Rpc ) @@ -362,18 +417,26 @@ async function checkOldRollup(params: VerificationParams): Promise<{oldLatestCon } } - // ensure old rollup was upgraded - if ( - (await getProxyImpl(l1Rpc, config.contracts.rollup, true)) !== - getAddress(deployedContracts.oldRollupUser) - ) { - throw new Error('Old rollup was not upgraded') + if (preUpgradeState.stakers.length > 0) { + try { + await oldRollupContract.callStatic.withdrawStakerFunds({ + from: preUpgradeState.stakers[0], + }) + } catch (e) { + if (e instanceof Error && e.message.includes('Pausable: paused')) { + console.warn( + '!!!!! Withdraw staker funds FAILED, old rollup need to be upgraded to enable withdrawals !!!!!' + ) + } else { + throw e + } + } } - // using the reader factory here for typing - const rollupReaderContract = RollupReader__factory.connect(config.contracts.rollup, l1Rpc) - const latestConfirmed = await rollupReaderContract.latestConfirmed() - const latestConfirmedStateHash = (await rollupReaderContract.getNode(latestConfirmed)).stateHash + const latestConfirmed = await oldRollupContract.latestConfirmed() + const latestConfirmedStateHash = ( + await oldRollupContract.getNode(latestConfirmed) + ).stateHash return { oldLatestConfirmedStateHash: latestConfirmedStateHash, } @@ -384,7 +447,7 @@ async function checkInitialAssertion( newRollup: RollupUserLogic, newEdgeChallengeManager: EdgeChallengeManager, currentInboxCount: BigNumberish -): Promise<{latestConfirmed: string}> { +): Promise<{ latestConfirmed: string }> { const { config, l1Rpc } = params const latestConfirmed = await newRollup.latestConfirmed() @@ -398,7 +461,7 @@ async function checkInitialAssertion( }) return { - latestConfirmed + latestConfirmed, } } @@ -475,7 +538,12 @@ async function checkNewRollup( } // check initial assertion - const { latestConfirmed } = await checkInitialAssertion(params, newRollup, newEdgeChallengeManager, currentInboxCount) + const { latestConfirmed } = await checkInitialAssertion( + params, + newRollup, + newEdgeChallengeManager, + currentInboxCount + ) console.log('BOLD latest confirmed:', latestConfirmed) // check validator whitelist disabled diff --git a/scripts/populateLookup.ts b/scripts/populateLookup.ts index 414b7b55f..9f48da08f 100644 --- a/scripts/populateLookup.ts +++ b/scripts/populateLookup.ts @@ -45,8 +45,7 @@ async function main() { await populateLookup( wallet, config.contracts.rollup, - deployedContracts.preImageHashLookup, - deployedContracts.rollupReader + deployedContracts.preImageHashLookup ) } diff --git a/src/rollup/BOLDUpgradeAction.sol b/src/rollup/BOLDUpgradeAction.sol index 2af1e91f7..f908120b0 100644 --- a/src/rollup/BOLDUpgradeAction.sol +++ b/src/rollup/BOLDUpgradeAction.sol @@ -64,6 +64,12 @@ interface IOldRollup { uint256 inboxMaxCount ); + function paused() external view returns (bool); + function isZombie( + address staker + ) external view returns (bool); + function withdrawStakerFunds() external returns (uint256); + function wasmModuleRoot() external view returns (bytes32); function latestConfirmed() external view returns (uint64); function getNode( @@ -136,65 +142,6 @@ contract StateHashPreImageLookup { } } -/// @title Forwards calls to the rollup so that they can be interpreted as a user -/// @notice In the upgrade executor we need to access functions on the rollup -/// but since the upgrade executor is the admin it will always be forwarded to the -/// rollup admin logic. We create a separate forwarder contract here that just relays -/// information, since it's not the admin it can access rollup user logic. -contract RollupReader is IOldRollup { - IOldRollup public immutable rollup; - - constructor( - IOldRollup _rollup - ) { - rollup = _rollup; - } - - function wasmModuleRoot() external view returns (bytes32) { - return rollup.wasmModuleRoot(); - } - - function latestConfirmed() external view returns (uint64) { - return rollup.latestConfirmed(); - } - - function getNode( - uint64 nodeNum - ) external view returns (Node memory) { - return rollup.getNode(nodeNum); - } - - function getStakerAddress( - uint64 stakerNum - ) external view returns (address) { - return rollup.getStakerAddress(stakerNum); - } - - function stakerCount() external view returns (uint64) { - return rollup.stakerCount(); - } - - function getStaker( - address staker - ) external view returns (OldStaker memory) { - return rollup.getStaker(staker); - } - - function isValidator( - address validator - ) external view returns (bool) { - return rollup.isValidator(validator); - } - - function validatorWalletCreator() external view returns (address) { - return rollup.validatorWalletCreator(); - } - - function anyTrustFastConfirmer() external view returns (address) { - return rollup.anyTrustFastConfirmer(); - } -} - /// @notice Stores an array specified during construction. /// Since the BOLDUpgradeAction is not allowed to have storage, /// we use this contract so it can keep an immutable pointer to an array. @@ -216,6 +163,7 @@ contract ConstantArrayStorage { /// @notice Requires implementation contracts to be pre-deployed and provided in the constructor /// Also requires a lookup contract to be provided that contains the pre-image of the state hash /// that is in the latest confirmed assertion in the current rollup. +/// The old rollup should be on v1.1.0 or later to allow stake withdrawals after the upgrade contract BOLDUpgradeAction { using AssertionStateLib for AssertionState; @@ -255,7 +203,6 @@ contract BOLDUpgradeAction { ProxyAdmin public immutable PROXY_ADMIN_SEQUENCER_INBOX; ProxyAdmin public immutable PROXY_ADMIN_INBOX; StateHashPreImageLookup public immutable PREIMAGE_LOOKUP; - RollupReader public immutable ROLLUP_READER; // new contract implementations address public immutable IMPL_BRIDGE; @@ -263,8 +210,6 @@ contract BOLDUpgradeAction { address public immutable IMPL_INBOX; address public immutable IMPL_REI; address public immutable IMPL_OUTBOX; - // the old rollup, but with whenNotPaused protection removed from stake withdrawal functions - address public immutable IMPL_PATCHED_OLD_ROLLUP_USER; address public immutable IMPL_NEW_ROLLUP_USER; address public immutable IMPL_NEW_ROLLUP_ADMIN; address public immutable IMPL_CHALLENGE_MANAGER; @@ -303,7 +248,6 @@ contract BOLDUpgradeAction { address inbox; address rei; address outbox; - address oldRollupUser; address newRollupUser; address newRollupAdmin; address challengeManager; @@ -341,14 +285,12 @@ contract BOLDUpgradeAction { PROXY_ADMIN_SEQUENCER_INBOX = ProxyAdmin(proxyAdmins.seqInbox); PROXY_ADMIN_INBOX = ProxyAdmin(proxyAdmins.inbox); PREIMAGE_LOOKUP = new StateHashPreImageLookup(); - ROLLUP_READER = new RollupReader(contracts.rollup); IMPL_BRIDGE = implementations.bridge; IMPL_SEQUENCER_INBOX = implementations.seqInbox; IMPL_INBOX = implementations.inbox; IMPL_REI = implementations.rei; IMPL_OUTBOX = implementations.outbox; - IMPL_PATCHED_OLD_ROLLUP_USER = implementations.oldRollupUser; IMPL_NEW_ROLLUP_USER = implementations.newRollupUser; IMPL_NEW_ROLLUP_ADMIN = implementations.newRollupAdmin; IMPL_CHALLENGE_MANAGER = implementations.challengeManager; @@ -376,15 +318,15 @@ contract BOLDUpgradeAction { function cleanupOldRollup() private { IOldRollupAdmin(address(OLD_ROLLUP)).pause(); - uint64 stakerCount = ROLLUP_READER.stakerCount(); + uint64 stakerCount = OLD_ROLLUP.stakerCount(); // since we for-loop these stakers we set an arbitrary limit - we dont // expect any instances to have close to this number of stakers if (stakerCount > 50) { stakerCount = 50; } for (uint64 i = 0; i < stakerCount;) { - address stakerAddr = ROLLUP_READER.getStakerAddress(i); - OldStaker memory staker = ROLLUP_READER.getStaker(stakerAddr); + address stakerAddr = OLD_ROLLUP.getStakerAddress(i); + OldStaker memory staker = OLD_ROLLUP.getStaker(stakerAddr); if (staker.isStaked && staker.currentChallenge == 0) { address[] memory stakersToRefund = new address[](1); stakersToRefund[0] = stakerAddr; @@ -395,11 +337,6 @@ contract BOLDUpgradeAction { i++; } } - - // upgrade the rollup to one that allows validators to withdraw even whilst paused - DoubleLogicUUPSUpgradeable(address(OLD_ROLLUP)).upgradeSecondaryTo( - IMPL_PATCHED_OLD_ROLLUP_USER - ); } /// @dev Create a config for the new rollup - fetches the latest confirmed @@ -407,7 +344,7 @@ contract BOLDUpgradeAction { function createConfig() private view returns (Config memory) { // fetch the assertion associated with the latest confirmed state bytes32 latestConfirmedStateHash = - ROLLUP_READER.getNode(ROLLUP_READER.latestConfirmed()).stateHash; + OLD_ROLLUP.getNode(OLD_ROLLUP.latestConfirmed()).stateHash; (ExecutionState memory genesisExecState, uint256 inboxMaxCount) = PREIMAGE_LOOKUP.get(latestConfirmedStateHash); @@ -431,7 +368,7 @@ contract BOLDUpgradeAction { confirmPeriodBlocks: CONFIRM_PERIOD_BLOCKS, stakeToken: STAKE_TOKEN, baseStake: STAKE_AMOUNT, - wasmModuleRoot: ROLLUP_READER.wasmModuleRoot(), + wasmModuleRoot: OLD_ROLLUP.wasmModuleRoot(), owner: address(this), // upgrade executor is the owner loserStakeEscrow: EXCESS_STAKE_RECEIVER, // additional funds get sent to the l1 timelock chainId: CHAIN_ID, @@ -531,14 +468,36 @@ contract BOLDUpgradeAction { // verify (uint256 _delayBlocks, uint256 _futureBlocks, uint256 _delaySeconds, uint256 _futureSeconds) = ISequencerInbox(SEQ_INBOX).maxTimeVariation(); - require(_delayBlocks == delayBlocks, "DelayBuffer: delayBlocks not set"); - require(_delaySeconds == delaySeconds, "DelayBuffer: delaySeconds not set"); - require(_futureBlocks == futureBlocks, "DelayBuffer: futureBlocks not set"); - require(_futureSeconds == futureSeconds, "DelayBuffer: futureSeconds not set"); + require(_delayBlocks == delayBlocks, "DelayBuffer: delayBlocks"); + require(_delaySeconds == delaySeconds, "DelayBuffer: delaySeconds"); + require(_futureBlocks == futureBlocks, "DelayBuffer: futureBlocks"); + require(_futureSeconds == futureSeconds, "DelayBuffer: futureSeconds"); ISequencerInbox(SEQ_INBOX).updateRollupAddress(); } + function expectedRollupAddress( + address deployer, + uint256 chainId + ) public pure returns (address) { + bytes32 rollupSalt = keccak256(abi.encode(chainId)); + return Create2Upgradeable.computeAddress( + rollupSalt, keccak256(type(RollupProxy).creationCode), deployer + ); + } + + function validateRollupDeployedAtAddress( + address rollupAddress, + address deployer, + uint256 chainId + ) external view { + require( + (rollupAddress.code.length > 0) + && expectedRollupAddress(deployer, chainId) == rollupAddress, + "ADDR_MISMATCH" + ); + } + function perform( address[] memory validators ) external { @@ -570,18 +529,18 @@ contract BOLDUpgradeAction { challengeManager: challengeManager, rollupAdminLogic: IMPL_NEW_ROLLUP_ADMIN, rollupUserLogic: IRollupUser(IMPL_NEW_ROLLUP_USER), - validatorWalletCreator: ROLLUP_READER.validatorWalletCreator() + validatorWalletCreator: OLD_ROLLUP.validatorWalletCreator() }); // upgrade the surrounding contracts eg bridge, outbox, seq inbox, rollup event inbox // to set of the new rollup address - bytes32 rollupSalt = keccak256(abi.encode(config)); - address expectedRollupAddress = - Create2Upgradeable.computeAddress(rollupSalt, keccak256(type(RollupProxy).creationCode)); - upgradeSurroundingContracts(expectedRollupAddress); + // this is different from the typical salt, it is ok because the caller should deploy the upgrade only once for each chainid + bytes32 rollupSalt = keccak256(abi.encode(config.chainId)); + address _expectedRollupAddress = expectedRollupAddress(address(this), config.chainId); + upgradeSurroundingContracts(_expectedRollupAddress); challengeManager.initialize({ - _assertionChain: IAssertionChain(expectedRollupAddress), + _assertionChain: IAssertionChain(_expectedRollupAddress), _challengePeriodBlocks: CHALLENGE_PERIOD_BLOCKS, _oneStepProofEntry: OSP, layerZeroBlockEdgeHeight: config.layerZeroBlockEdgeHeight, @@ -594,7 +553,7 @@ contract BOLDUpgradeAction { }); RollupProxy rollup = new RollupProxy{salt: rollupSalt}(); - require(address(rollup) == expectedRollupAddress, "UNEXPCTED_ROLLUP_ADDR"); + require(address(rollup) == _expectedRollupAddress, "UNEXPCTED_ROLLUP_ADDR"); // initialize the rollup with this contract as owner to set batch poster and validators // it will transfer the ownership back to the actual owner later @@ -606,7 +565,7 @@ contract BOLDUpgradeAction { if (validators.length != 0) { bool[] memory _vals = new bool[](validators.length); for (uint256 i = 0; i < validators.length; i++) { - require(ROLLUP_READER.isValidator(validators[i]), "UNEXPECTED_NEW_VALIDATOR"); + require(OLD_ROLLUP.isValidator(validators[i]), "UNEXPECTED_NEW_VALIDATOR"); _vals[i] = true; } IRollupAdmin(address(rollup)).setValidator(validators, _vals); @@ -616,7 +575,7 @@ contract BOLDUpgradeAction { } // anyTrustFastConfirmer only exists since v2.0.0, but the old rollup can be on an older version - try ROLLUP_READER.anyTrustFastConfirmer() returns (address anyTrustFastConfirmer) { + try OLD_ROLLUP.anyTrustFastConfirmer() returns (address anyTrustFastConfirmer) { if (anyTrustFastConfirmer != address(0)) { IRollupAdmin(address(rollup)).setAnyTrustFastConfirmer(anyTrustFastConfirmer); } @@ -626,6 +585,6 @@ contract BOLDUpgradeAction { IRollupAdmin(address(rollup)).setOwner(actualOwner); - emit RollupMigrated(expectedRollupAddress, address(challengeManager)); + emit RollupMigrated(_expectedRollupAddress, address(challengeManager)); } } diff --git a/yarn.lock b/yarn.lock index b0378ee3f..e1c492b7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,17 +2,6 @@ # yarn lockfile v1 -"@arbitrum/nitro-contracts-2.1.0@npm:@arbitrum/nitro-contracts@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@arbitrum/nitro-contracts/-/nitro-contracts-2.1.0.tgz#b2900c0b9fad38716dce29c2b3cc96eb35611b55" - integrity sha512-Bh89H5/ihWVcAI2eNBc1McybZAmpTHJ5eFLauLz8bjicZTOD545vSYAreJN41Uo+AlHKVAMtODUQdoP0NVtg3Q== - dependencies: - "@offchainlabs/upgrade-executor" "1.1.0-beta.0" - "@openzeppelin/contracts" "4.5.0" - "@openzeppelin/contracts-upgradeable" "4.5.2" - patch-package "^6.4.7" - solady "0.0.182" - "@arbitrum/sdk@^3.4.1": version "3.6.0" resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.6.0.tgz#b5c6ec56fe4d95c7e865bb4f0e8a4c7b327ae6f8" @@ -905,21 +894,11 @@ "@openzeppelin/contracts" "4.7.3" "@openzeppelin/contracts-upgradeable" "4.7.3" -"@openzeppelin/contracts-upgradeable@4.5.2": - version "4.5.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.5.2.tgz#90d9e47bacfd8693bfad0ac8a394645575528d05" - integrity sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA== - "@openzeppelin/contracts-upgradeable@4.7.3": version "4.7.3" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.7.3.tgz#f1d606e2827d409053f3e908ba4eb8adb1dd6995" integrity sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A== -"@openzeppelin/contracts@4.5.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.5.0.tgz#3fd75d57de172b3743cdfc1206883f56430409cc" - integrity sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA== - "@openzeppelin/contracts@4.7.3": version "4.7.3" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.3.tgz#939534757a81f8d69cc854c7692805684ff3111e"