Skip to content

Commit

Permalink
feat(3921): Gateway Operator (#69)
Browse files Browse the repository at this point in the history
* feat/3921 Gateway Operator

* use last finalized state for gatewayOperator check

* adjusting natspec

* extend existing struct with gatewayoperator

* use  more explicit NatSpec

---------

Co-authored-by: thedarkjester <grant.southey@consensys.net>
Co-authored-by: Victorien Gauch <85494462+VGau@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent 39e0d76 commit 5256e04
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 6 deletions.
40 changes: 37 additions & 3 deletions contracts/contracts/LineaRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ contract LineaRollup is
uint256 internal constant POINT_EVALUATION_RETURN_DATA_LENGTH = 64;
uint256 internal constant POINT_EVALUATION_FIELD_ELEMENTS_LENGTH = 4096;

uint256 internal constant SIX_MONTHS_IN_SECONDS = 15768000; // 365 / 2 * 86400

/// @dev DEPRECATED in favor of the single shnarfFinalBlockNumbers mapping.
mapping(bytes32 dataHash => bytes32 finalStateRootHash) public dataFinalStateRootHashes;
/// @dev DEPRECATED in favor of the single shnarfFinalBlockNumbers mapping.
Expand All @@ -74,7 +76,11 @@ contract LineaRollup is
/// @dev Hash of the L2 computed L1 message number, rolling hash and finalized timestamp.
bytes32 public currentFinalizedState;

/// @dev Total contract storage is 10 slots.
/// @dev The address of the gateway operator.
/// @dev This address is granted the OPERATOR_ROLE after six months of finalization inactivity by the current operators.
address public gatewayOperator;

/// @dev Total contract storage is 11 slots.

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
Expand All @@ -101,6 +107,7 @@ contract LineaRollup is

verifiers[0] = _initializationData.defaultVerifier;

gatewayOperator = _initializationData.gatewayOperator;
currentL2BlockNumber = _initializationData.initialL2BlockNumber;
stateRootHashes[_initializationData.initialL2BlockNumber] = _initializationData.initialStateRootHash;

Expand All @@ -111,19 +118,22 @@ contract LineaRollup is
}

/**
* @notice Sets permissions for a list of addresses and their roles as well as initialises the PauseManager pauseType:role mappings.
* @notice Sets permissions for a list of addresses and their roles as well as initialises the PauseManager pauseType:role mappings and gateway operator.
* @dev This function is a reinitializer and can only be called once per version. Should be called using an upgradeAndCall transaction to the ProxyAdmin.
* @param _roleAddresses The list of addresses and their roles.
* @param _pauseTypeRoles The list of pause type roles.
* @param _unpauseTypeRoles The list of unpause type roles.
* @param _gatewayOperator The address of the gateway operator.
*/
function reinitializePauseTypesAndPermissions(
RoleAddress[] calldata _roleAddresses,
PauseTypeRole[] calldata _pauseTypeRoles,
PauseTypeRole[] calldata _unpauseTypeRoles
PauseTypeRole[] calldata _unpauseTypeRoles,
address _gatewayOperator
) external reinitializer(6) {
__Permissions_init(_roleAddresses);
__PauseManager_init(_pauseTypeRoles, _unpauseTypeRoles);
gatewayOperator = _gatewayOperator;
}

/**
Expand All @@ -142,6 +152,30 @@ contract LineaRollup is
verifiers[_proofType] = _newVerifierAddress;
}

/**
* @notice Sets the gateway operator role to the specified address if six months have passed since the last finalization.
* @dev Reverts if six months have not passed since the last finalization.
* @param _messageNumber Last finalized L1 message number as part of the feedback loop.
* @param _rollingHash Last finalized L1 rolling hash as part of the feedback loop.
* @param _lastFinalizedTimestamp Last finalized L2 block timestamp.
*/
function setGatewayOperator(uint256 _messageNumber, bytes32 _rollingHash, uint256 _lastFinalizedTimestamp) external {
if (block.timestamp < _lastFinalizedTimestamp + SIX_MONTHS_IN_SECONDS) {
revert LastFinalizationTimeNotLapsed();
}
if (currentFinalizedState != _computeLastFinalizedState(_messageNumber, _rollingHash, _lastFinalizedTimestamp)) {
revert FinalizationStateIncorrect(
currentFinalizedState,
_computeLastFinalizedState(_messageNumber, _rollingHash, _lastFinalizedTimestamp)
);
}

address gatewayOperatorAddress = gatewayOperator;

_grantRole(OPERATOR_ROLE, gatewayOperatorAddress);
emit GatewayOperatorRoleGranted(msg.sender, gatewayOperatorAddress);
}

/**
* @notice Unset the verifier contract address for a proof type.
* @dev VERIFIER_UNSETTER_ROLE is required to execute.
Expand Down
23 changes: 23 additions & 0 deletions contracts/contracts/interfaces/l1/ILineaRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ILineaRollup {
* @param roleAddresses The list of role addresses.
* @param pauseTypeRoles The list of pause type roles.
* @param unpauseTypeRoles The list of unpause type roles.
* @param gatewayOperator The account to be given OPERATOR_ROLE when.
*/
struct InitializationData {
bytes32 initialStateRootHash;
Expand All @@ -32,6 +33,7 @@ interface ILineaRollup {
IPermissionsManager.RoleAddress[] roleAddresses;
IPauseManager.PauseTypeRole[] pauseTypeRoles;
IPauseManager.PauseTypeRole[] unpauseTypeRoles;
address gatewayOperator;
}

/**
Expand Down Expand Up @@ -129,6 +131,13 @@ interface ILineaRollup {
bytes l2MessagingBlocksOffsets;
}

/**
* @notice Emitted when the gateway operator role is granted.
* @param caller The address that granted the role.
* @param gatewayOperatorAddress The gateway operator address that received the operator role.
*/
event GatewayOperatorRoleGranted(address indexed caller, address indexed gatewayOperatorAddress);

/**
* @notice Emitted when a verifier is set for a particular proof type.
* @param verifierAddress The indexed new verifier address being set.
Expand Down Expand Up @@ -168,6 +177,11 @@ interface ILineaRollup {
bool withProof
);

/**
* @dev Thrown when the last finalization time has not lapsed when trying to grant the OPERATOR_ROLE to the gateway operator address.
*/
error LastFinalizationTimeNotLapsed();

/**
* @dev Thrown when the point evaluation precompile call return data field(s) are wrong.
*/
Expand Down Expand Up @@ -307,6 +321,15 @@ interface ILineaRollup {
*/
function setVerifierAddress(address _newVerifierAddress, uint256 _proofType) external;

/**
* @notice Sets the gateway operator role to the specified address if six months have passed since the last finalization.
* @dev Reverts if six months have not passed since the last finalization.
* @param _messageNumber Last finalized L1 message number as part of the feedback loop.
* @param _rollingHash Last finalized L1 rolling hash as part of the feedback loop.
* @param _lastFinalizedTimestamp Last finalized L2 block timestamp.
*/
function setGatewayOperator(uint256 _messageNumber, bytes32 _rollingHash, uint256 _lastFinalizedTimestamp) external;

/**
* @notice Unset the verifier contract address for a proof type.
* @dev VERIFIER_SETTER_ROLE is required to execute.
Expand Down
5 changes: 5 additions & 0 deletions contracts/contracts/messageService/l2/L2MessageService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ contract L2MessageService is AccessControlUpgradeable, L2MessageServiceV1, L2Mes
/// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision.
uint256[50] private __gap_L2MessageService;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

/**
* @notice Initializes underlying message service dependencies.
* @param _rateLimitPeriod The period to rate limit against.
Expand Down
2 changes: 2 additions & 0 deletions contracts/deploy/03_deploy_LineaRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const LineaRollup_rateLimitPeriodInSeconds = requireEnv("LINEA_ROLLUP_RATE_LIMIT_PERIOD");
const LineaRollup_rateLimitAmountInWei = requireEnv("LINEA_ROLLUP_RATE_LIMIT_AMOUNT");
const LineaRollup_genesisTimestamp = requireEnv("LINEA_ROLLUP_GENESIS_TIMESTAMP");
const MultiCallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11";
const LineaRollup_roleAddresses = process.env["LINEA_ROLLUP_ROLE_ADDRESSES"];
const LineaRollup_pauseTypeRoles = process.env["LINEA_ROLLUP_PAUSE_TYPE_ROLES"];
const LineaRollup_unpauseTypeRoles = process.env["LINEA_ROLLUP_UNPAUSE_TYPE_ROLES"];
Expand Down Expand Up @@ -140,6 +141,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
roleAddresses: roleAddresses,
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: MultiCallAddress,
},
],
{
Expand Down
16 changes: 15 additions & 1 deletion contracts/test/LineaRollup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ describe("Linea Rollup contract", () => {
let operator: SignerWithAddress;
let nonAuthorizedAccount: SignerWithAddress;

const multiCallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11";

const { compressedData, prevShnarf, expectedShnarf, expectedX, expectedY, parentDataHash, parentStateRootHash } =
firstCompressedDataContent;
const { expectedShnarf: secondExpectedShnarf } = secondCompressedDataContent;
Expand Down Expand Up @@ -125,6 +127,7 @@ describe("Linea Rollup contract", () => {
roleAddresses: roleAddresses,
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const lineaRollup = (await deployUpgradableFromFactory("TestLineaRollup", [initializationData], {
Expand Down Expand Up @@ -178,6 +181,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const deployCall = deployUpgradableFromFactory("contracts/LineaRollup.sol:LineaRollup", [initializationData], {
Expand All @@ -203,6 +207,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const deployCall = deployUpgradableFromFactory("TestLineaRollup", [initializationData], {
Expand Down Expand Up @@ -247,6 +252,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const lineaRollup = await deployUpgradableFromFactory(
Expand Down Expand Up @@ -276,6 +282,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const lineaRollup = await deployUpgradableFromFactory(
Expand Down Expand Up @@ -306,6 +313,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
});

await expectRevertWithReason(initializeCall, INITIALIZED_ALREADY_MESSAGE);
Expand Down Expand Up @@ -2243,6 +2251,7 @@ describe("Linea Rollup contract", () => {
],
pauseTypeRoles,
unpauseTypeRoles,
multiCallAddress,
);

expect(await newLineaRollup.currentL2BlockNumber()).to.equal(0);
Expand All @@ -2261,7 +2270,12 @@ describe("Linea Rollup contract", () => {

await expectRevertWithCustomError(
newLineaRollup,
newLineaRollup.reinitializePauseTypesAndPermissions(roleAddresses, pauseTypeRoles, unpauseTypeRoles),
newLineaRollup.reinitializePauseTypesAndPermissions(
roleAddresses,
pauseTypeRoles,
unpauseTypeRoles,
multiCallAddress,
),
"ZeroAddressNotAllowed",
);
});
Expand Down
3 changes: 3 additions & 0 deletions contracts/test/LineaRollupInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ describe("LineaRollup Init contract", () => {
let securityCouncil: SignerWithAddress;
let operator: SignerWithAddress;

const multiCallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11";

const parentStateRootHash = generateRandomBytes(32);

const firstBlockNumber = 199;
Expand All @@ -52,6 +54,7 @@ describe("LineaRollup Init contract", () => {
],
pauseTypeRoles: pauseTypeRoles,
unpauseTypeRoles: unpauseTypeRoles,
gatewayOperator: multiCallAddress,
};

const LineaRollup = (await deployUpgradableFromFactory("TestLineaRollup", [genesisData], {
Expand Down
5 changes: 4 additions & 1 deletion contracts/test/LineaRollupNew.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ describe("Linea Rollup contract", () => {
let securityCouncil: SignerWithAddress;
let operator: SignerWithAddress;

const multiCallAddress = "0xcA11bde05977b3631167028862bE2a173976CA11";

async function deployLineaRollupFixture() {
const PlonkVerifierFactory = await ethers.getContractFactory("TestPlonkVerifierForDataAggregation");
const plonkVerifier = await PlonkVerifierFactory.deploy();
Expand All @@ -71,9 +73,10 @@ describe("Linea Rollup contract", () => {
ONE_DAY_IN_SECONDS,
INITIAL_WITHDRAW_LIMIT,
GENESIS_L2_TIMESTAMP,
multiCallAddress,
],
{
initializer: "initialize(bytes32,uint256,address,address,address[],uint256,uint256,uint256)",
initializer: "initialize(bytes32,uint256,address,address,address[],uint256,uint256,uint256,address)",
unsafeAllow: ["constructor"],
},
)) as unknown as TestLineaRollup;
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const ADDRESS_ZERO = ethers.ZeroAddress;
export const HASH_WITHOUT_ZERO_FIRST_BYTE = "0xf887bbc07b0e849fb625aafadf4cb6b65b98e492fbb689705312bf1db98ead7f";

export const LINEA_ROLLUP_INITIALIZE_SIGNATURE =
"initialize((bytes32,uint256,uint256,address,uint256,uint256,(address,bytes32)[],(uint8,bytes32)[],(uint8,bytes32)[]))";
"initialize((bytes32,uint256,uint256,address,uint256,uint256,(address,bytes32)[],(uint8,bytes32)[],(uint8,bytes32)[],address))";

// Linea XP Token roles
export const MINTER_ROLE = generateKeccak256(["string"], ["MINTER_ROLE"], true);
Expand Down

0 comments on commit 5256e04

Please sign in to comment.