mirror of
https://github.com/vacp2p/linea-monorepo.git
synced 2026-01-09 04:08:01 -05:00
feat: add e2e tests for LineaRollup contract upgrade (#339)
* feat: add test for LineaRollup contract upgrade * fix: add reinit event checks for the upgrade * feat: add new test for roles assignments * fix: add comment for fallback operator address
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { ethers } from "ethers";
|
||||
import { generateKeccak256 } from "./utils";
|
||||
|
||||
export const ROLLING_HASH_UPDATED_EVENT_SIGNATURE =
|
||||
"0xea3b023b4c8680d4b4824f0143132c95476359a2bb70a81d6c5a36f6918f6339";
|
||||
@@ -9,3 +10,59 @@ export const MESSAGE_SENT_EVENT_SIGNATURE = "0xe856c2b8bd4eb0027ce32eeaf595c21b0
|
||||
export const HASH_ZERO = ethers.ZeroHash;
|
||||
|
||||
export const TRANSACTION_CALLDATA_LIMIT = 30_000;
|
||||
|
||||
export const PAUSE_ALL_ROLE = generateKeccak256(["string"], ["PAUSE_ALL_ROLE"], true);
|
||||
export const UNPAUSE_ALL_ROLE = generateKeccak256(["string"], ["UNPAUSE_ALL_ROLE"], true);
|
||||
export const PAUSE_L1_L2_ROLE = generateKeccak256(["string"], ["PAUSE_L1_L2_ROLE"], true);
|
||||
export const UNPAUSE_L1_L2_ROLE = generateKeccak256(["string"], ["UNPAUSE_L1_L2_ROLE"], true);
|
||||
export const PAUSE_L2_L1_ROLE = generateKeccak256(["string"], ["PAUSE_L2_L1_ROLE"], true);
|
||||
export const UNPAUSE_L2_L1_ROLE = generateKeccak256(["string"], ["UNPAUSE_L2_L1_ROLE"], true);
|
||||
export const PAUSE_BLOB_SUBMISSION_ROLE = generateKeccak256(["string"], ["PAUSE_BLOB_SUBMISSION_ROLE"], true);
|
||||
export const UNPAUSE_BLOB_SUBMISSION_ROLE = generateKeccak256(["string"], ["UNPAUSE_BLOB_SUBMISSION_ROLE"], true);
|
||||
export const PAUSE_FINALIZATION_ROLE = generateKeccak256(["string"], ["PAUSE_FINALIZATION_ROLE"], true);
|
||||
export const UNPAUSE_FINALIZATION_ROLE = generateKeccak256(["string"], ["UNPAUSE_FINALIZATION_ROLE"], true);
|
||||
export const USED_RATE_LIMIT_RESETTER_ROLE = generateKeccak256(["string"], ["USED_RATE_LIMIT_RESETTER_ROLE"], true);
|
||||
export const VERIFIER_UNSETTER_ROLE = generateKeccak256(["string"], ["VERIFIER_UNSETTER_ROLE"], true);
|
||||
|
||||
export const LINEA_ROLLUP_V6_ROLES = [
|
||||
PAUSE_ALL_ROLE,
|
||||
PAUSE_L1_L2_ROLE,
|
||||
PAUSE_L2_L1_ROLE,
|
||||
UNPAUSE_ALL_ROLE,
|
||||
UNPAUSE_L1_L2_ROLE,
|
||||
UNPAUSE_L2_L1_ROLE,
|
||||
PAUSE_BLOB_SUBMISSION_ROLE,
|
||||
UNPAUSE_BLOB_SUBMISSION_ROLE,
|
||||
PAUSE_FINALIZATION_ROLE,
|
||||
UNPAUSE_FINALIZATION_ROLE,
|
||||
USED_RATE_LIMIT_RESETTER_ROLE,
|
||||
VERIFIER_UNSETTER_ROLE,
|
||||
];
|
||||
|
||||
export const GENERAL_PAUSE_TYPE = 1;
|
||||
export const L1_L2_PAUSE_TYPE = 2;
|
||||
export const L2_L1_PAUSE_TYPE = 3;
|
||||
export const BLOB_SUBMISSION_PAUSE_TYPE = 4;
|
||||
export const CALLDATA_SUBMISSION_PAUSE_TYPE = 5;
|
||||
export const FINALIZATION_PAUSE_TYPE = 6;
|
||||
|
||||
export const BASE_PAUSE_TYPES_ROLES = [{ pauseType: GENERAL_PAUSE_TYPE, role: PAUSE_ALL_ROLE }];
|
||||
export const BASE_UNPAUSE_TYPES_ROLES = [{ pauseType: GENERAL_PAUSE_TYPE, role: UNPAUSE_ALL_ROLE }];
|
||||
|
||||
export const LINEA_ROLLUP_PAUSE_TYPES_ROLES = [
|
||||
...BASE_PAUSE_TYPES_ROLES,
|
||||
{ pauseType: L1_L2_PAUSE_TYPE, role: PAUSE_L1_L2_ROLE },
|
||||
{ pauseType: L2_L1_PAUSE_TYPE, role: PAUSE_L2_L1_ROLE },
|
||||
{ pauseType: BLOB_SUBMISSION_PAUSE_TYPE, role: PAUSE_BLOB_SUBMISSION_ROLE },
|
||||
{ pauseType: CALLDATA_SUBMISSION_PAUSE_TYPE, role: PAUSE_BLOB_SUBMISSION_ROLE },
|
||||
{ pauseType: FINALIZATION_PAUSE_TYPE, role: PAUSE_FINALIZATION_ROLE },
|
||||
];
|
||||
|
||||
export const LINEA_ROLLUP_UNPAUSE_TYPES_ROLES = [
|
||||
...BASE_UNPAUSE_TYPES_ROLES,
|
||||
{ pauseType: L1_L2_PAUSE_TYPE, role: UNPAUSE_L1_L2_ROLE },
|
||||
{ pauseType: L2_L1_PAUSE_TYPE, role: UNPAUSE_L2_L1_ROLE },
|
||||
{ pauseType: BLOB_SUBMISSION_PAUSE_TYPE, role: UNPAUSE_BLOB_SUBMISSION_ROLE },
|
||||
{ pauseType: CALLDATA_SUBMISSION_PAUSE_TYPE, role: UNPAUSE_BLOB_SUBMISSION_ROLE },
|
||||
{ pauseType: FINALIZATION_PAUSE_TYPE, role: UNPAUSE_FINALIZATION_ROLE },
|
||||
];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ContractTransactionReceipt, Wallet, ethers } from "ethers";
|
||||
import { AbstractSigner, ContractTransactionReceipt, ethers } from "ethers";
|
||||
import { ProxyAdmin, ProxyAdmin__factory } from "../typechain";
|
||||
|
||||
export function getInitializerData(
|
||||
@@ -11,7 +11,7 @@ export function getInitializerData(
|
||||
}
|
||||
|
||||
export async function upgradeContractAndCall(
|
||||
deployer: Wallet,
|
||||
deployer: AbstractSigner,
|
||||
proxyAdminContractAddress: string,
|
||||
proxyContractAddress: string,
|
||||
implementationContractAddress: string,
|
||||
@@ -24,7 +24,7 @@ export async function upgradeContractAndCall(
|
||||
}
|
||||
|
||||
export async function upgradeContract(
|
||||
deployer: Wallet,
|
||||
deployer: AbstractSigner,
|
||||
proxyAdminContractAddress: string,
|
||||
proxyContractAddress: string,
|
||||
implementationContractAddress: string,
|
||||
|
||||
@@ -3,7 +3,7 @@ import assert from "assert";
|
||||
import { AbstractSigner, BaseContract, BlockTag, TransactionReceipt, TransactionRequest, Wallet, ethers } from "ethers";
|
||||
import path from "path";
|
||||
import { exec } from "child_process";
|
||||
import { L2MessageService, TokenBridge, LineaRollupV5 } from "../typechain";
|
||||
import { L2MessageService, TokenBridge, LineaRollupV5, LineaRollupV6 } from "../typechain";
|
||||
import { PayableOverrides, TypedContractEvent, TypedDeferredTopicFilter, TypedEventLog } from "../typechain/common";
|
||||
import { MessageEvent, SendMessageArgs } from "./types";
|
||||
|
||||
@@ -148,7 +148,7 @@ export async function getBlockByNumberOrBlockTag(rpcUrl: URL, blockTag: BlockTag
|
||||
}
|
||||
|
||||
export async function getEvents<
|
||||
TContract extends LineaRollupV5 | L2MessageService | TokenBridge,
|
||||
TContract extends LineaRollupV5 | LineaRollupV6 | L2MessageService | TokenBridge,
|
||||
TEvent extends TypedContractEvent,
|
||||
>(
|
||||
contract: TContract,
|
||||
@@ -171,7 +171,7 @@ export async function getEvents<
|
||||
}
|
||||
|
||||
export async function waitForEvents<
|
||||
TContract extends LineaRollupV5 | L2MessageService | TokenBridge,
|
||||
TContract extends LineaRollupV5 | LineaRollupV6 | L2MessageService | TokenBridge,
|
||||
TEvent extends TypedContractEvent,
|
||||
>(
|
||||
contract: TContract,
|
||||
@@ -332,3 +332,49 @@ export async function execDockerCommand(command: string, containerName: string):
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function generateRoleAssignments(
|
||||
roles: string[],
|
||||
defaultAddress: string,
|
||||
overrides: { role: string; addresses: string[] }[],
|
||||
): { role: string; addressWithRole: string }[] {
|
||||
const roleAssignments: { role: string; addressWithRole: string }[] = [];
|
||||
|
||||
const overridesMap = new Map<string, string[]>();
|
||||
for (const override of overrides) {
|
||||
overridesMap.set(override.role, override.addresses);
|
||||
}
|
||||
|
||||
const allRolesSet = new Set<string>(roles);
|
||||
for (const override of overrides) {
|
||||
allRolesSet.add(override.role);
|
||||
}
|
||||
|
||||
for (const role of allRolesSet) {
|
||||
if (overridesMap.has(role)) {
|
||||
const addresses = overridesMap.get(role);
|
||||
|
||||
if (addresses && addresses.length > 0) {
|
||||
for (const addressWithRole of addresses) {
|
||||
roleAssignments.push({ role, addressWithRole });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
roleAssignments.push({ role, addressWithRole: defaultAddress });
|
||||
}
|
||||
}
|
||||
|
||||
return roleAssignments;
|
||||
}
|
||||
|
||||
export function convertStringToPaddedHexBytes(strVal: string, paddedSize: number): string {
|
||||
if (strVal.length > paddedSize) {
|
||||
throw "Length is longer than padded size!";
|
||||
}
|
||||
|
||||
const strBytes = ethers.toUtf8Bytes(strVal);
|
||||
const bytes = ethers.zeroPadBytes(strBytes, paddedSize);
|
||||
const bytes8Hex = ethers.hexlify(bytes);
|
||||
|
||||
return bytes8Hex;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ const config: Config = {
|
||||
rpcUrl: L1_RPC_URL,
|
||||
chainId: L1_CHAIN_ID,
|
||||
lineaRollupAddress: "0x2A5CDCfc38856e2590E9Bd32F54Fa348e5De5f48",
|
||||
lineaRollupProxyAdminAddress: "0x10b7ef80D4bA8df6b4Daed7B7638cd88C6d52F02",
|
||||
tokenBridgeAddress: "",
|
||||
l1TokenAddress: "",
|
||||
accountManager: new EnvironmentBasedAccountManager(
|
||||
|
||||
@@ -16,6 +16,7 @@ const config: Config = {
|
||||
rpcUrl: L1_RPC_URL,
|
||||
chainId: 31648428,
|
||||
lineaRollupAddress: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
|
||||
lineaRollupProxyAdminAddress: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
|
||||
dummyContractAddress: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
|
||||
tokenBridgeAddress: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
|
||||
l1TokenAddress: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
|
||||
|
||||
@@ -25,6 +25,7 @@ const config: Config = {
|
||||
rpcUrl: L1_RPC_URL,
|
||||
chainId: L1_CHAIN_ID,
|
||||
lineaRollupAddress: "0xB218f8A4Bc926cF1cA7b3423c154a0D627Bdb7E5",
|
||||
lineaRollupProxyAdminAddress: "0xa89E358Ef34921ebA90f328901B7381F86b1db52",
|
||||
tokenBridgeAddress: "0x5A0a48389BB0f12E5e017116c1105da97E129142",
|
||||
l1TokenAddress: "",
|
||||
accountManager: new EnvironmentBasedAccountManager(
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
L2MessageService__factory,
|
||||
LineaRollupV5,
|
||||
LineaRollupV5__factory,
|
||||
ProxyAdmin,
|
||||
ProxyAdmin__factory,
|
||||
TestContract,
|
||||
TestContract__factory,
|
||||
TestERC20,
|
||||
@@ -92,6 +94,19 @@ export default class TestSetup {
|
||||
return lineaRollup;
|
||||
}
|
||||
|
||||
public getLineaRollupProxyAdminContract(signer?: AbstractSigner): ProxyAdmin {
|
||||
const proxyAdmin: ProxyAdmin = ProxyAdmin__factory.connect(
|
||||
this.config.L1.lineaRollupProxyAdminAddress,
|
||||
this.getL1Provider(),
|
||||
);
|
||||
|
||||
if (signer) {
|
||||
return proxyAdmin.connect(signer);
|
||||
}
|
||||
|
||||
return proxyAdmin;
|
||||
}
|
||||
|
||||
public getL2MessageServiceContract(signer?: Wallet): L2MessageService {
|
||||
const l2MessageService: L2MessageService = L2MessageService__factory.connect(
|
||||
this.config.L2.l2MessageServiceAddress,
|
||||
|
||||
@@ -9,6 +9,7 @@ export type BaseConfig = {
|
||||
|
||||
export type L1Config = BaseConfig & {
|
||||
lineaRollupAddress: string;
|
||||
lineaRollupProxyAdminAddress: string;
|
||||
tokenBridgeAddress: string;
|
||||
l1TokenAddress: string;
|
||||
};
|
||||
|
||||
@@ -7,8 +7,19 @@ import {
|
||||
wait,
|
||||
getBlockByNumberOrBlockTag,
|
||||
etherToWei,
|
||||
generateRoleAssignments,
|
||||
convertStringToPaddedHexBytes,
|
||||
getEvents,
|
||||
} from "./common/utils";
|
||||
import { config } from "./config/tests-config";
|
||||
import { deployContract } from "./common/deployments";
|
||||
import { LineaRollupV6__factory } from "./typechain";
|
||||
import { getInitializerData, upgradeContractAndCall } from "./common/upgrades";
|
||||
import {
|
||||
LINEA_ROLLUP_PAUSE_TYPES_ROLES,
|
||||
LINEA_ROLLUP_UNPAUSE_TYPES_ROLES,
|
||||
LINEA_ROLLUP_V6_ROLES,
|
||||
} from "./common/constants";
|
||||
|
||||
const l1AccountManager = config.getL1AccountManager();
|
||||
|
||||
@@ -53,110 +64,217 @@ describe("Submission and finalization test suite", () => {
|
||||
return { l1Messages, l1Receipts };
|
||||
};
|
||||
|
||||
it.concurrent(
|
||||
"Check L2 anchoring",
|
||||
async () => {
|
||||
const lineaRollup = config.getLineaRollupContract();
|
||||
const l2MessageService = config.getL2MessageServiceContract();
|
||||
describe("Contracts v5", () => {
|
||||
it.concurrent(
|
||||
"Check L2 anchoring",
|
||||
async () => {
|
||||
const lineaRollup = config.getLineaRollupContract();
|
||||
const l2MessageService = config.getL2MessageServiceContract();
|
||||
|
||||
const { l1Messages } = await sendMessages();
|
||||
const { l1Messages } = await sendMessages();
|
||||
|
||||
// Wait for the last L1->L2 message to be anchored on L2
|
||||
const lastNewL1MessageNumber = l1Messages.slice(-1)[0].messageNumber;
|
||||
// Wait for the last L1->L2 message to be anchored on L2
|
||||
const lastNewL1MessageNumber = l1Messages.slice(-1)[0].messageNumber;
|
||||
|
||||
console.log("Waiting for the anchoring using rolling hash...");
|
||||
const [rollingHashUpdatedEvent] = await waitForEvents(
|
||||
l2MessageService,
|
||||
l2MessageService.filters.RollingHashUpdated(),
|
||||
1_000,
|
||||
0,
|
||||
"latest",
|
||||
async (events) => events.filter((event) => event.args.messageNumber >= lastNewL1MessageNumber),
|
||||
console.log("Waiting for the anchoring using rolling hash...");
|
||||
const [rollingHashUpdatedEvent] = await waitForEvents(
|
||||
l2MessageService,
|
||||
l2MessageService.filters.RollingHashUpdated(),
|
||||
1_000,
|
||||
0,
|
||||
"latest",
|
||||
async (events) => events.filter((event) => event.args.messageNumber >= lastNewL1MessageNumber),
|
||||
);
|
||||
|
||||
const [lastNewMessageRollingHash, lastAnchoredL1MessageNumber] = await Promise.all([
|
||||
lineaRollup.rollingHashes(rollingHashUpdatedEvent.args.messageNumber),
|
||||
l2MessageService.lastAnchoredL1MessageNumber(),
|
||||
]);
|
||||
expect(lastNewMessageRollingHash).toEqual(rollingHashUpdatedEvent.args.rollingHash);
|
||||
expect(lastAnchoredL1MessageNumber).toEqual(rollingHashUpdatedEvent.args.messageNumber);
|
||||
|
||||
console.log("New anchoring using rolling hash done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
|
||||
it.concurrent(
|
||||
"Check L1 data submission and finalization",
|
||||
async () => {
|
||||
const lineaRollup = config.getLineaRollupContract();
|
||||
|
||||
const [currentL2BlockNumber, startingRootHash] = await Promise.all([
|
||||
lineaRollup.currentL2BlockNumber(),
|
||||
lineaRollup.stateRootHashes(await lineaRollup.currentL2BlockNumber()),
|
||||
]);
|
||||
|
||||
console.log("Waiting for data submission used to finalize with proof...");
|
||||
// Waiting for data submission starting from migration block number
|
||||
await waitForEvents(
|
||||
lineaRollup,
|
||||
lineaRollup.filters.DataSubmittedV2(undefined, currentL2BlockNumber + 1n),
|
||||
1_000,
|
||||
);
|
||||
|
||||
console.log("Waiting for the first DataFinalized event with proof...");
|
||||
// Waiting for first DataFinalized event with proof
|
||||
const [dataFinalizedEvent] = await waitForEvents(
|
||||
lineaRollup,
|
||||
lineaRollup.filters.DataFinalized(undefined, startingRootHash),
|
||||
1_000,
|
||||
);
|
||||
|
||||
const [lastBlockFinalized, newStateRootHash] = await Promise.all([
|
||||
lineaRollup.currentL2BlockNumber(),
|
||||
lineaRollup.stateRootHashes(dataFinalizedEvent.args.lastBlockFinalized),
|
||||
]);
|
||||
|
||||
expect(lastBlockFinalized).toBeGreaterThanOrEqual(dataFinalizedEvent.args.lastBlockFinalized);
|
||||
expect(newStateRootHash).toEqual(dataFinalizedEvent.args.finalRootHash);
|
||||
expect(dataFinalizedEvent.args.withProof).toBeTruthy();
|
||||
|
||||
console.log("Finalization with proof done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
|
||||
it.concurrent(
|
||||
"Check L2 safe/finalized tag update on sequencer",
|
||||
async () => {
|
||||
const sequencerEndpoint = config.getSequencerEndpoint();
|
||||
if (!sequencerEndpoint) {
|
||||
console.log('Skipped the "Check L2 safe/finalized tag update on sequencer" test');
|
||||
return;
|
||||
}
|
||||
|
||||
const lastFinalizedL2BlockNumberOnL1 = 0;
|
||||
console.log(`lastFinalizedL2BlockNumberOnL1=${lastFinalizedL2BlockNumberOnL1}`);
|
||||
|
||||
let safeL2BlockNumber = -1,
|
||||
finalizedL2BlockNumber = -1;
|
||||
while (
|
||||
safeL2BlockNumber < lastFinalizedL2BlockNumberOnL1 ||
|
||||
finalizedL2BlockNumber < lastFinalizedL2BlockNumberOnL1
|
||||
) {
|
||||
safeL2BlockNumber =
|
||||
(await getBlockByNumberOrBlockTag(sequencerEndpoint, "safe"))?.number || safeL2BlockNumber;
|
||||
finalizedL2BlockNumber =
|
||||
(await getBlockByNumberOrBlockTag(sequencerEndpoint, "finalized"))?.number || finalizedL2BlockNumber;
|
||||
await wait(1_000);
|
||||
}
|
||||
|
||||
console.log(`safeL2BlockNumber=${safeL2BlockNumber} finalizedL2BlockNumber=${finalizedL2BlockNumber}`);
|
||||
|
||||
expect(safeL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
|
||||
expect(finalizedL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
|
||||
|
||||
console.log("L2 safe/finalized tag update on sequencer done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
});
|
||||
|
||||
describe("LineaRollup v6 upgrade", () => {
|
||||
// note: we cannot move the chain forward by 6 months, so in theory, this could be any address for e2e test purposes
|
||||
const fallbackoperatorAddress = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
||||
|
||||
beforeAll(async () => {
|
||||
const l1DeployerAccount = l1AccountManager.whaleAccount(0);
|
||||
const l1SecurityCouncil = l1AccountManager.whaleAccount(3);
|
||||
const l1Provider = config.getL1Provider();
|
||||
const proxyAdmin = config.getLineaRollupProxyAdminContract(l1DeployerAccount);
|
||||
|
||||
console.log("Deploying LineaRollup v6 implementation contract...");
|
||||
const { maxFeePerGas, maxPriorityFeePerGas } = await l1Provider.getFeeData();
|
||||
|
||||
const lineaRollupV6Implementation = await deployContract(new LineaRollupV6__factory(), l1DeployerAccount, [
|
||||
{ maxPriorityFeePerGas, maxFeePerGas },
|
||||
]);
|
||||
|
||||
console.log("Upgrading LineaRollup contract to V6...");
|
||||
const newRoleAddresses = generateRoleAssignments(LINEA_ROLLUP_V6_ROLES, await l1SecurityCouncil.getAddress(), []);
|
||||
|
||||
const initializerData = getInitializerData(
|
||||
LineaRollupV6__factory.createInterface(),
|
||||
"reinitializeLineaRollupV6",
|
||||
[newRoleAddresses, LINEA_ROLLUP_PAUSE_TYPES_ROLES, LINEA_ROLLUP_UNPAUSE_TYPES_ROLES, fallbackoperatorAddress],
|
||||
);
|
||||
|
||||
const [lastNewMessageRollingHash, lastAnchoredL1MessageNumber] = await Promise.all([
|
||||
lineaRollup.rollingHashes(rollingHashUpdatedEvent.args.messageNumber),
|
||||
l2MessageService.lastAnchoredL1MessageNumber(),
|
||||
]);
|
||||
expect(lastNewMessageRollingHash).toEqual(rollingHashUpdatedEvent.args.rollingHash);
|
||||
expect(lastAnchoredL1MessageNumber).toEqual(rollingHashUpdatedEvent.args.messageNumber);
|
||||
await upgradeContractAndCall(
|
||||
l1DeployerAccount,
|
||||
await proxyAdmin.getAddress(),
|
||||
await config.getLineaRollupContract().getAddress(),
|
||||
await lineaRollupV6Implementation.getAddress(),
|
||||
initializerData,
|
||||
);
|
||||
});
|
||||
|
||||
console.log("New anchoring using rolling hash done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
it("Check LineaRollupVersionChanged and FallbackOperatorAddressSet events are emitted", async () => {
|
||||
const lineaRollupAddress = await config.getLineaRollupContract().getAddress();
|
||||
const lineaRollupV6 = LineaRollupV6__factory.connect(lineaRollupAddress, config.getL1Provider());
|
||||
|
||||
it.concurrent(
|
||||
"Check L1 data submission and finalization",
|
||||
async () => {
|
||||
const lineaRollup = config.getLineaRollupContract();
|
||||
|
||||
const [currentL2BlockNumber, startingRootHash] = await Promise.all([
|
||||
lineaRollup.currentL2BlockNumber(),
|
||||
lineaRollup.stateRootHashes(await lineaRollup.currentL2BlockNumber()),
|
||||
]);
|
||||
|
||||
console.log("Waiting for data submission used to finalize with proof...");
|
||||
// Waiting for data submission starting from migration block number
|
||||
console.log("Waiting for FallbackOperatorAddressSet event...");
|
||||
await waitForEvents(
|
||||
lineaRollup,
|
||||
lineaRollup.filters.DataSubmittedV2(undefined, currentL2BlockNumber + 1n),
|
||||
lineaRollupV6,
|
||||
lineaRollupV6.filters.FallbackOperatorAddressSet(undefined, fallbackoperatorAddress),
|
||||
1_000,
|
||||
);
|
||||
|
||||
console.log("Waiting for the first DataFinalized event with proof...");
|
||||
// Waiting for first DataFinalized event with proof
|
||||
console.log("Waiting for LineaRollupVersionChanged event...");
|
||||
const expectedVersion5Bytes8 = convertStringToPaddedHexBytes("5.0", 8);
|
||||
const expectedVersion6Bytes8 = convertStringToPaddedHexBytes("6.0", 8);
|
||||
await waitForEvents(
|
||||
lineaRollupV6,
|
||||
lineaRollupV6.filters.LineaRollupVersionChanged(expectedVersion5Bytes8, expectedVersion6Bytes8),
|
||||
1_000,
|
||||
);
|
||||
});
|
||||
|
||||
it("Check all new roles have been granted and pauseTypes/unpauseTypes are assigned to specific roles", async () => {
|
||||
const lineaRollupAddress = await config.getLineaRollupContract().getAddress();
|
||||
const l1SecurityCouncilAddress = await l1AccountManager.whaleAccount(3).getAddress();
|
||||
|
||||
const lineaRollupV6 = LineaRollupV6__factory.connect(lineaRollupAddress, config.getL1Provider());
|
||||
|
||||
for (const role of LINEA_ROLLUP_V6_ROLES) {
|
||||
const hasRole = await lineaRollupV6.hasRole(role, l1SecurityCouncilAddress);
|
||||
expect(hasRole).toBeTruthy();
|
||||
}
|
||||
|
||||
const [pauseTypeRoleSetEvents, unPauseTypeRoleSetEvents] = await Promise.all([
|
||||
getEvents(lineaRollupV6, lineaRollupV6.filters.PauseTypeRoleSet()),
|
||||
getEvents(lineaRollupV6, lineaRollupV6.filters.UnPauseTypeRoleSet()),
|
||||
]);
|
||||
|
||||
expect(pauseTypeRoleSetEvents.length).toEqual(LINEA_ROLLUP_PAUSE_TYPES_ROLES.length);
|
||||
expect(unPauseTypeRoleSetEvents.length).toEqual(LINEA_ROLLUP_UNPAUSE_TYPES_ROLES.length);
|
||||
});
|
||||
|
||||
it("Check L1 data submission and finalization", async () => {
|
||||
const lineaRollupAddress = await config.getLineaRollupContract().getAddress();
|
||||
const lineaRollupV6 = LineaRollupV6__factory.connect(lineaRollupAddress, config.getL1Provider());
|
||||
|
||||
const currentL2BlockNumber = await lineaRollupV6.currentL2BlockNumber();
|
||||
|
||||
console.log("Waiting for DataSubmittedV3 used to finalize with proof...");
|
||||
await waitForEvents(lineaRollupV6, lineaRollupV6.filters.DataSubmittedV3(), 1_000);
|
||||
|
||||
console.log("Waiting for the first DataFinalizedV3 event with proof...");
|
||||
const [dataFinalizedEvent] = await waitForEvents(
|
||||
lineaRollup,
|
||||
lineaRollup.filters.DataFinalized(undefined, startingRootHash),
|
||||
lineaRollupV6,
|
||||
lineaRollupV6.filters.DataFinalizedV3(currentL2BlockNumber + 1n),
|
||||
1_000,
|
||||
);
|
||||
|
||||
const [lastBlockFinalized, newStateRootHash] = await Promise.all([
|
||||
lineaRollup.currentL2BlockNumber(),
|
||||
lineaRollup.stateRootHashes(dataFinalizedEvent.args.lastBlockFinalized),
|
||||
lineaRollupV6.currentL2BlockNumber(),
|
||||
lineaRollupV6.stateRootHashes(dataFinalizedEvent.args.endBlockNumber),
|
||||
]);
|
||||
|
||||
expect(lastBlockFinalized).toBeGreaterThanOrEqual(dataFinalizedEvent.args.lastBlockFinalized);
|
||||
expect(newStateRootHash).toEqual(dataFinalizedEvent.args.finalRootHash);
|
||||
expect(dataFinalizedEvent.args.withProof).toBeTruthy();
|
||||
expect(lastBlockFinalized).toBeGreaterThanOrEqual(dataFinalizedEvent.args.endBlockNumber);
|
||||
expect(newStateRootHash).toEqual(dataFinalizedEvent.args.finalStateRootHash);
|
||||
|
||||
console.log("Finalization with proof done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
|
||||
it.concurrent(
|
||||
"Check L2 safe/finalized tag update on sequencer",
|
||||
async () => {
|
||||
const sequencerEndpoint = config.getSequencerEndpoint();
|
||||
if (!sequencerEndpoint) {
|
||||
console.log('Skipped the "Check L2 safe/finalized tag update on sequencer" test');
|
||||
return;
|
||||
}
|
||||
|
||||
const lastFinalizedL2BlockNumberOnL1 = 0;
|
||||
console.log(`lastFinalizedL2BlockNumberOnL1=${lastFinalizedL2BlockNumberOnL1}`);
|
||||
|
||||
let safeL2BlockNumber = -1,
|
||||
finalizedL2BlockNumber = -1;
|
||||
while (
|
||||
safeL2BlockNumber < lastFinalizedL2BlockNumberOnL1 ||
|
||||
finalizedL2BlockNumber < lastFinalizedL2BlockNumberOnL1
|
||||
) {
|
||||
safeL2BlockNumber = (await getBlockByNumberOrBlockTag(sequencerEndpoint, "safe"))?.number || safeL2BlockNumber;
|
||||
finalizedL2BlockNumber =
|
||||
(await getBlockByNumberOrBlockTag(sequencerEndpoint, "finalized"))?.number || finalizedL2BlockNumber;
|
||||
await wait(1_000);
|
||||
}
|
||||
|
||||
console.log(`safeL2BlockNumber=${safeL2BlockNumber} finalizedL2BlockNumber=${finalizedL2BlockNumber}`);
|
||||
|
||||
expect(safeL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
|
||||
expect(finalizedL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
|
||||
|
||||
console.log("L2 safe/finalized tag update on sequencer done.");
|
||||
},
|
||||
150_000,
|
||||
);
|
||||
}, 150_000);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user