From fc8cc5673170cb1652bef46af78da587d835f5ee Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 09:52:29 +0800 Subject: [PATCH 01/11] Update PreconfWhitelist.sol --- .../contracts/layer1/preconf/impl/PreconfWhitelist.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index 8cd323e052d..435c1655a9e 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -209,12 +209,12 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - if (_epochTimestamp < LibPreconfConstants.SECONDS_IN_EPOCH) { + // Use the previous epoch's last slot timestamp as the random number, if it is not available + // (zero), return address(0) directly. + if (_epochTimestamp < LibPreconfConstants.SECONDS_IN_SLOT) { return address(0); } - // Use the previous epoch's start timestamp as the random number, if it is not available - // (zero), return address(0) directly. uint256 rand = uint256( LibPreconfUtils.getBeaconBlockRoot( _epochTimestamp - LibPreconfConstants.SECONDS_IN_SLOT From 65df2add9db5b38cc57f622d4adba09fc94f2eed Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 10:40:57 +0800 Subject: [PATCH 02/11] fix --- .../layer1/preconf/impl/PreconfWhitelist.sol | 14 ++++++++------ .../layer1/preconf/libs/LibPreconfUtils.sol | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index 435c1655a9e..9bf937ac654 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -10,6 +10,8 @@ import "src/shared/common/EssentialContract.sol"; /// @title PreconfWhitelist /// @custom:security-contact security@taiko.xyz contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { + uint256 internal constant TIME_SHIFT_FOR_RANDOMNESS = 3 * LibPreconfConstants.SECONDS_IN_EPOCH; + struct OperatorInfo { uint64 activeSince; // Epoch when the operator becomes active. uint64 inactiveSince; // Epoch when the operator is no longer active. @@ -209,16 +211,16 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - // Use the previous epoch's last slot timestamp as the random number, if it is not available - // (zero), return address(0) directly. - if (_epochTimestamp < LibPreconfConstants.SECONDS_IN_SLOT) { + // We use the beacon root at or after ` _epochTimestamp - TIME_SHIFT_FOR_RANDOMNESS` as the + // random number to select an operator. + // TIME_THIFT_FOR_RAND must be big enough to ensure a non-zero beacon root is available and + // immutable. + if (_epochTimestamp < TIME_SHIFT_FOR_RANDOMNESS) { return address(0); } uint256 rand = uint256( - LibPreconfUtils.getBeaconBlockRoot( - _epochTimestamp - LibPreconfConstants.SECONDS_IN_SLOT - ) + LibPreconfUtils.getBeaconBlockRootAtOrAfter(_epochTimestamp - TIME_SHIFT_FOR_RANDOMNESS) ); if (rand == 0) return address(0); diff --git a/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol b/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol index 82f921145a9..4c5bea5be06 100644 --- a/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol +++ b/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol @@ -17,7 +17,7 @@ library LibPreconfUtils { /// @dev Caller should verify the returned value is not 0. /// @param timestamp The timestamp for which the beacon block root is to be retrieved. /// @return The beacon block root as a bytes32 value. - function getBeaconBlockRoot(uint256 timestamp) internal view returns (bytes32) { + function getBeaconBlockRootAtOrAfter(uint256 timestamp) internal view returns (bytes32) { if (timestamp < LibPreconfConstants.getGenesisTimestamp(block.chainid)) { return bytes32(0); } From 81206b1e9f928a6b6af8935e9fa92c4ba833ed47 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 10:45:06 +0800 Subject: [PATCH 03/11] Update LibPreconfUtils.t.sol --- .../test/layer1/preconf/libs/LibPreconfUtils.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol b/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol index 8e1cf96ed57..08232fd2796 100644 --- a/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol +++ b/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol @@ -8,8 +8,8 @@ import "src/layer1/preconf/libs/LibPreconfUtils.sol"; /// @title LibBridgedToken /// @custom:security-contact security@taiko.xyz contract TestLibPreconfUtils is Test { - function test_getBeaconBlockRoot() public { - bytes32 root = LibPreconfUtils.getBeaconBlockRoot(block.timestamp); + function test_getBeaconBlockRootAtOrAfter() public { + bytes32 root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(block.timestamp); assertEq(root, bytes32(0)); vm.etch( @@ -20,13 +20,13 @@ contract TestLibPreconfUtils is Test { vm.warp(block.timestamp + 48); assertEq(block.timestamp, 49); - root = LibPreconfUtils.getBeaconBlockRoot(20); + root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(20); assertEq(root, bytes32(uint256(20))); - root = LibPreconfUtils.getBeaconBlockRoot(37); + root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(37); assertEq(root, bytes32(uint256(37))); - root = LibPreconfUtils.getBeaconBlockRoot(38); + root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(38); assertEq(root, 0); } } From bdad9ad67f78c3c8a7b7ee09cd28ca97505736d1 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 10:54:09 +0800 Subject: [PATCH 04/11] fix tests --- .../layer1/preconf/impl/PreconfWhitelist.sol | 11 ++++----- .../layer1/preconf/router/PreconfRouter.t.sol | 24 +++++++++---------- .../preconf/whitelist/PeconfWhitelist.t.sol | 3 +++ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index 9bf937ac654..dfcd247ee3f 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -10,7 +10,7 @@ import "src/shared/common/EssentialContract.sol"; /// @title PreconfWhitelist /// @custom:security-contact security@taiko.xyz contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { - uint256 internal constant TIME_SHIFT_FOR_RANDOMNESS = 3 * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 public constant MIN_TIMESTAMP = 3 * LibPreconfConstants.SECONDS_IN_EPOCH; struct OperatorInfo { uint64 activeSince; // Epoch when the operator becomes active. @@ -211,17 +211,16 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - // We use the beacon root at or after ` _epochTimestamp - TIME_SHIFT_FOR_RANDOMNESS` as the + // We use the beacon root at or after ` _epochTimestamp - MIN_TIMESTAMP` as the // random number to select an operator. // TIME_THIFT_FOR_RAND must be big enough to ensure a non-zero beacon root is available and // immutable. - if (_epochTimestamp < TIME_SHIFT_FOR_RANDOMNESS) { + if (_epochTimestamp < MIN_TIMESTAMP) { return address(0); } - uint256 rand = uint256( - LibPreconfUtils.getBeaconBlockRootAtOrAfter(_epochTimestamp - TIME_SHIFT_FOR_RANDOMNESS) - ); + uint256 rand = + uint256(LibPreconfUtils.getBeaconBlockRootAtOrAfter(_epochTimestamp - MIN_TIMESTAMP)); if (rand == 0) return address(0); diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol index 12acf8e8c9e..0a1386c0f2a 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol @@ -15,9 +15,9 @@ contract PreconfRouterTest is PreconfRouterTestBase { // Setup mock beacon for operator selection vm.chainId(1); - uint256 epochOneStart = LibPreconfConstants.getGenesisTimestamp(block.chainid); + uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epochTwoStart = epochOneStart + LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -25,7 +25,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { address beaconBlockRootContract = LibPreconfConstants.getBeaconBlockRootContract(); vm.etch(beaconBlockRootContract, address(mockBeacon).code); MockBeaconBlockRoot(payable(beaconBlockRootContract)).set( - epochOneStart + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot + epoch1Start + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot ); // Setup block params @@ -51,7 +51,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { }); // Warp to arbitrary slot in epoch 2 - vm.warp(epochTwoStart + 2 * LibPreconfConstants.SECONDS_IN_SLOT); + vm.warp(epoch4Start + 2 * LibPreconfConstants.SECONDS_IN_SLOT); // Prank as Carol (selected operator) and propose blocks vm.prank(Carol); @@ -70,21 +70,21 @@ contract PreconfRouterTest is PreconfRouterTestBase { // Setup mock beacon for operator selection vm.chainId(1); - uint256 epochOneStart = LibPreconfConstants.getGenesisTimestamp(block.chainid); + uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); // Current epoch - uint256 epochTwoStart = epochOneStart + LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol address beaconBlockRootContract = LibPreconfConstants.getBeaconBlockRootContract(); vm.etch(beaconBlockRootContract, address(mockBeacon).code); MockBeaconBlockRoot(payable(beaconBlockRootContract)).set( - epochOneStart + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot + epoch1Start + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot ); // Warp to arbitrary slot in epoch 2 - vm.warp(epochTwoStart + 2 * LibPreconfConstants.SECONDS_IN_SLOT); + vm.warp(epoch4Start + 2 * LibPreconfConstants.SECONDS_IN_SLOT); // Prank as David (not the selected operator) and propose blocks vm.prank(David); @@ -101,9 +101,9 @@ contract PreconfRouterTest is PreconfRouterTestBase { // Setup mock beacon for operator selection vm.chainId(1); - uint256 epochOneStart = LibPreconfConstants.getGenesisTimestamp(block.chainid); + uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epochTwoStart = epochOneStart + LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -111,7 +111,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { address beaconBlockRootContract = LibPreconfConstants.getBeaconBlockRootContract(); vm.etch(beaconBlockRootContract, address(mockBeacon).code); MockBeaconBlockRoot(payable(beaconBlockRootContract)).set( - epochOneStart + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot + epoch1Start + LibPreconfConstants.SECONDS_IN_SLOT, mockRoot ); // Setup block params @@ -137,7 +137,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { }); // Warp to arbitrary slot in epoch 2 - vm.warp(epochTwoStart + 2 * LibPreconfConstants.SECONDS_IN_SLOT); + vm.warp(epoch4Start + 2 * LibPreconfConstants.SECONDS_IN_SLOT); // Prank as Carol (selected operator) and propose blocks vm.prank(Carol); diff --git a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol index 3b77475a15a..56b93914e1d 100644 --- a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol +++ b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol @@ -276,6 +276,9 @@ contract TestPreconfWhitelist is Layer1Test { assertEq(inactiveSince, 0); assertEq(index, 0); + assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), address(0)); + + vm.warp(whitelistNoDelay.MIN_TIMESTAMP()); assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), Bob); assertEq(whitelistNoDelay.getOperatorForNextEpoch(), Bob); From 541f28562832cdb8c9f2cef302ac04f4562d30f6 Mon Sep 17 00:00:00 2001 From: dantaik <99078276+dantaik@users.noreply.github.com> Date: Thu, 24 Apr 2025 02:57:37 +0000 Subject: [PATCH 05/11] forge fmt & update contract layout tables --- packages/protocol/.gas-snapshot | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/protocol/.gas-snapshot b/packages/protocol/.gas-snapshot index 8262ae21a95..19e5160a1d4 100644 --- a/packages/protocol/.gas-snapshot +++ b/packages/protocol/.gas-snapshot @@ -70,9 +70,9 @@ InboxTest_ProposeAndProve:test_inbox_reprove_the_same_batch_with_same_transition InboxTest_ProposeAndProve:test_inbox_ring_buffer_will_be_reused() (gas: 14705853) InboxTest_ProposeAndProve:test_proposeBatch_reverts_for_invalid_proposer_and_operator() (gas: 165337) InboxTest_StopBatch:test_inbox_num_batches_verified() (gas: 8162653) -PreconfRouterTest:test_preconfRouter_proposeBatch() (gas: 374389) -PreconfRouterTest:test_preconfRouter_proposeBatch_notOperator() (gas: 325555) -PreconfRouterTest:test_preconfRouter_proposeBatch_proposerNotSender() (gas: 373120) +PreconfRouterTest:test_preconfRouter_proposeBatch() (gas: 374662) +PreconfRouterTest:test_preconfRouter_proposeBatch_notOperator() (gas: 325828) +PreconfRouterTest:test_preconfRouter_proposeBatch_proposerNotSender() (gas: 373393) SendMessageToDelegateOwner:testAddress1() (gas: 2391) TestAutomataDcapV3Attestation:testAttestation() (gas: 4848498) TestAutomataDcapV3Attestation:testParsedCustomQuoteBinAttestation() (gas: 4553350) @@ -90,7 +90,7 @@ TestAutomataDcapV3Attestation:testToggleCheckQuoteValidity() (gas: 21556) TestERC20Airdrop:test_erc20_airdrop_claim() (gas: 189244) TestForkRouter:test_ForkRouter_default_routing() (gas: 2461333) TestForkRouter:test_ForkRouter_routing_to_old_fork() (gas: 1734609) -TestLibPreconfUtils:test_getBeaconBlockRoot() (gas: 90446) +TestLibPreconfUtils:test_getBeaconBlockRootAtOrAfter() (gas: 90446) TestMerkleClaimable:test_verifyClaim_after_it_ends() (gas: 36877) TestMerkleClaimable:test_verifyClaim_before_it_starts() (gas: 36626) TestMerkleClaimable:test_verifyClaim_twice_while_its_ongoing() (gas: 66484) @@ -108,15 +108,15 @@ TestMinimalOwner:test_minimalOwner_TransferOwnership() (gas: 21879) TestMinimalOwner:test_minimalOwner_TransferOwnershipToSameAddress() (gas: 13832) TestMinimalOwner:test_minimalOwner_TransferOwnershipToZeroAddress() (gas: 13493) TestPreconfWhitelist:test_whitelistNoDelay_consolidationPreservesOrder() (gas: 252745) -TestPreconfWhitelist:test_whitelistNoDelay_consolidationWillNotChangeCurrentEpochOperator() (gas: 299356) +TestPreconfWhitelist:test_whitelistNoDelay_consolidationWillNotChangeCurrentEpochOperator() (gas: 291891) TestPreconfWhitelist:test_whitelist_addBackRemovedOperator() (gas: 106230) TestPreconfWhitelist:test_whitelist_addOrRemoveTheSameOperatorTwiceWillRevert() (gas: 83296) TestPreconfWhitelist:test_whitelist_consolidate_whenEmpty_not_revert() (gas: 19756) -TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveOneOperator() (gas: 257049) -TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveTwoOperators() (gas: 305557) -TestPreconfWhitelist:test_whitelist_noDelay_addThenRemoveOneOperator() (gas: 154524) +TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveOneOperator() (gas: 248398) +TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveTwoOperators() (gas: 296865) +TestPreconfWhitelist:test_whitelist_noDelay_addThenRemoveOneOperator() (gas: 159918) TestPreconfWhitelist:test_whitelist_removeNonExistingOperatorWillRevert() (gas: 25210) -TestPreconfWhitelist:test_whitelist_selfRemoval() (gas: 174701) +TestPreconfWhitelist:test_whitelist_selfRemoval() (gas: 139660) TestTaikoTreasuryVault:testForwardCallFailsOnError() (gas: 79082) TestTaikoTreasuryVault:testForwardCallToSelfShouldRevert() (gas: 26006) TestTaikoTreasuryVault:testNonOwnerCannotForwardCall() (gas: 28382) From 18a0b1a8ab5601d02a7ea928dc811ceb5aabeec5 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 11:07:36 +0800 Subject: [PATCH 06/11] more changes --- .../preconf/iface/IPreconfWhitelist.sol | 1 + .../layer1/preconf/impl/PreconfWhitelist.sol | 26 ++++++++++++------- .../layer1/preconf/libs/LibPreconfUtils.sol | 2 +- .../layer1/based/DeployProtocolOnL1.s.sol | 2 +- .../preconf/DeployPreconfContracts.s.sol | 2 +- .../layer1/preconf/libs/LibPreconfUtils.t.sol | 10 +++---- .../layer1/preconf/router/PreconfRouter.t.sol | 6 ++--- .../preconf/router/PreconfRouterTestBase.sol | 2 +- .../preconf/whitelist/PeconfWhitelist.t.sol | 6 ++--- 9 files changed, 32 insertions(+), 25 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol index d96dd460566..9525390e5fa 100644 --- a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol @@ -17,6 +17,7 @@ interface IPreconfWhitelist { error InvalidOperatorIndex(); error InvalidOperatorCount(); error InvalidOperatorAddress(); + error InvalidSelectorBeaconBlockOffset(); error OperatorAlreadyExists(); error OperatorAlreadyRemoved(); error OperatorNotAvailableYet(); diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index dfcd247ee3f..b5c37fd1768 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -10,8 +10,6 @@ import "src/shared/common/EssentialContract.sol"; /// @title PreconfWhitelist /// @custom:security-contact security@taiko.xyz contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { - uint256 public constant MIN_TIMESTAMP = 3 * LibPreconfConstants.SECONDS_IN_EPOCH; - struct OperatorInfo { uint64 activeSince; // Epoch when the operator becomes active. uint64 inactiveSince; // Epoch when the operator is no longer active. @@ -21,6 +19,8 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { event Consolidated(uint8 previousCount, uint8 newCount, bool havingPerfectOperators); event OperatorChangeDelaySet(uint8 delay); + uint256 public immutable selectorBeaconBlockOffset; + mapping(address operator => OperatorInfo info) public operators; mapping(uint256 index => address operator) public operatorMapping; uint8 public operatorCount; @@ -31,7 +31,14 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { uint256[47] private __gap; - constructor() EssentialContract(address(0)) { } + constructor(uint256 _selectorBeaconBlockOffset) EssentialContract(address(0)) { + require( + _selectorBeaconBlockOffset % LibPreconfConstants.SECONDS_IN_EPOCH == 0 + && _selectorBeaconBlockOffset / LibPreconfConstants.SECONDS_IN_EPOCH > 1, + InvalidSelectorBeaconBlockOffset() + ); + selectorBeaconBlockOffset = _selectorBeaconBlockOffset; + } function init(address _owner, uint8 _operatorChangeDelay) external initializer { __Essential_init(_owner); @@ -211,16 +218,15 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - // We use the beacon root at or after ` _epochTimestamp - MIN_TIMESTAMP` as the + // We use the beacon root at or after ` _epochTimestamp - selectorBeaconBlockOffset` as the // random number to select an operator. - // TIME_THIFT_FOR_RAND must be big enough to ensure a non-zero beacon root is available and - // immutable. - if (_epochTimestamp < MIN_TIMESTAMP) { - return address(0); - } + // selectorBeaconBlockOffset must be big enough to ensure a non-zero beacon root is + // available and immutable. + + if (_epochTimestamp < selectorBeaconBlockOffset) return address(0); uint256 rand = - uint256(LibPreconfUtils.getBeaconBlockRootAtOrAfter(_epochTimestamp - MIN_TIMESTAMP)); + uint256(LibPreconfUtils.getBeaconBlockRoot(_epochTimestamp - selectorBeaconBlockOffset)); if (rand == 0) return address(0); diff --git a/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol b/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol index 4c5bea5be06..82f921145a9 100644 --- a/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol +++ b/packages/protocol/contracts/layer1/preconf/libs/LibPreconfUtils.sol @@ -17,7 +17,7 @@ library LibPreconfUtils { /// @dev Caller should verify the returned value is not 0. /// @param timestamp The timestamp for which the beacon block root is to be retrieved. /// @return The beacon block root as a bytes32 value. - function getBeaconBlockRootAtOrAfter(uint256 timestamp) internal view returns (bytes32) { + function getBeaconBlockRoot(uint256 timestamp) internal view returns (bytes32) { if (timestamp < LibPreconfConstants.getGenesisTimestamp(block.chainid)) { return bytes32(0); } diff --git a/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol b/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol index b1dc0a11a52..e923725970d 100644 --- a/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol +++ b/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol @@ -528,7 +528,7 @@ contract DeployProtocolOnL1 is DeployCapability { { whitelist = deployProxy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist()), + impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), data: abi.encodeCall(PreconfWhitelist.init, (owner, 2)), registerTo: rollupResolver }); diff --git a/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol b/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol index 11c227d0d68..cbdf5a3ddf7 100644 --- a/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol +++ b/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol @@ -28,7 +28,7 @@ contract DeployPreconfContracts is BaseScript { // Deploy PreconfWhitelist deploy( LibStrings.B_PRECONF_WHITELIST, - address(new PreconfWhitelist()), + address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), abi.encodeCall(PreconfWhitelist.init, (contractOwner, 2)) ); diff --git a/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol b/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol index 08232fd2796..8e1cf96ed57 100644 --- a/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol +++ b/packages/protocol/test/layer1/preconf/libs/LibPreconfUtils.t.sol @@ -8,8 +8,8 @@ import "src/layer1/preconf/libs/LibPreconfUtils.sol"; /// @title LibBridgedToken /// @custom:security-contact security@taiko.xyz contract TestLibPreconfUtils is Test { - function test_getBeaconBlockRootAtOrAfter() public { - bytes32 root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(block.timestamp); + function test_getBeaconBlockRoot() public { + bytes32 root = LibPreconfUtils.getBeaconBlockRoot(block.timestamp); assertEq(root, bytes32(0)); vm.etch( @@ -20,13 +20,13 @@ contract TestLibPreconfUtils is Test { vm.warp(block.timestamp + 48); assertEq(block.timestamp, 49); - root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(20); + root = LibPreconfUtils.getBeaconBlockRoot(20); assertEq(root, bytes32(uint256(20))); - root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(37); + root = LibPreconfUtils.getBeaconBlockRoot(37); assertEq(root, bytes32(uint256(37))); - root = LibPreconfUtils.getBeaconBlockRootAtOrAfter(38); + root = LibPreconfUtils.getBeaconBlockRoot(38); assertEq(root, 0); } } diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol index 0a1386c0f2a..9df70bcadfb 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol @@ -17,7 +17,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -73,7 +73,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); // Current epoch - uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -103,7 +103,7 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start + 3 * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol index b2a0db0ef29..0b3833efc43 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol @@ -30,7 +30,7 @@ abstract contract PreconfRouterTestBase is Layer1Test { whitelist = PreconfWhitelist( deploy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist()), + impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 2)) }) ); diff --git a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol index 56b93914e1d..eaff41004b8 100644 --- a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol +++ b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol @@ -16,7 +16,7 @@ contract TestPreconfWhitelist is Layer1Test { whitelist = PreconfWhitelist( deploy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist()), + impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 2)) }) ); @@ -24,7 +24,7 @@ contract TestPreconfWhitelist is Layer1Test { whitelistNoDelay = PreconfWhitelist( deploy({ name: "preconf_whitelist_nodelay", - impl: address(new PreconfWhitelist()), + impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 0)) }) ); @@ -278,7 +278,7 @@ contract TestPreconfWhitelist is Layer1Test { assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), address(0)); - vm.warp(whitelistNoDelay.MIN_TIMESTAMP()); + vm.warp(whitelistNoDelay.selectorBeaconBlockOffset()); assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), Bob); assertEq(whitelistNoDelay.getOperatorForNextEpoch(), Bob); From 4a984b3c058dd918d53e91b0057ea21be499c7bc Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 11:17:08 +0800 Subject: [PATCH 07/11] more --- .../preconf/iface/IPreconfWhitelist.sol | 2 +- .../layer1/preconf/impl/PreconfWhitelist.sol | 46 +++++++++---------- .../layer1/based/DeployProtocolOnL1.s.sol | 4 +- .../preconf/DeployPreconfContracts.s.sol | 4 +- .../layer1/preconf/router/PreconfRouter.t.sol | 9 ++-- .../preconf/router/PreconfRouterTestBase.sol | 4 +- .../preconf/whitelist/PeconfWhitelist.t.sol | 10 ++-- 7 files changed, 41 insertions(+), 38 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol index 9525390e5fa..35486e09683 100644 --- a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol @@ -17,7 +17,7 @@ interface IPreconfWhitelist { error InvalidOperatorIndex(); error InvalidOperatorCount(); error InvalidOperatorAddress(); - error InvalidSelectorBeaconBlockOffset(); + error InvalidselectorBeaconEpochOffset(); error OperatorAlreadyExists(); error OperatorAlreadyRemoved(); error OperatorNotAvailableYet(); diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index b5c37fd1768..823cff64460 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -17,40 +17,40 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { } event Consolidated(uint8 previousCount, uint8 newCount, bool havingPerfectOperators); - event OperatorChangeDelaySet(uint8 delay); - uint256 public immutable selectorBeaconBlockOffset; + uint256 public immutable selectorBeaconEpochOffset; // in epochs + uint8 public immutable operatorChangeDelay; // in epochs + // Slot 1 mapping(address operator => OperatorInfo info) public operators; + + // Slot 2 mapping(uint256 index => address operator) public operatorMapping; + + // Slot 3 uint8 public operatorCount; - uint8 public operatorChangeDelay; // in epochs // all operators in operatorMapping are active and none of them is to be deactivated. bool public havingPerfectOperators; uint256[47] private __gap; - constructor(uint256 _selectorBeaconBlockOffset) EssentialContract(address(0)) { - require( - _selectorBeaconBlockOffset % LibPreconfConstants.SECONDS_IN_EPOCH == 0 - && _selectorBeaconBlockOffset / LibPreconfConstants.SECONDS_IN_EPOCH > 1, - InvalidSelectorBeaconBlockOffset() - ); - selectorBeaconBlockOffset = _selectorBeaconBlockOffset; + constructor( + uint8 _operatorChangeDelay, + uint256 _selectorBeaconEpochOffset + ) + EssentialContract(address(0)) + { + require(_selectorBeaconEpochOffset > 1, InvalidselectorBeaconEpochOffset()); + selectorBeaconEpochOffset = _selectorBeaconEpochOffset; + operatorChangeDelay = _operatorChangeDelay; } - function init(address _owner, uint8 _operatorChangeDelay) external initializer { + function init(address _owner) external initializer { __Essential_init(_owner); - operatorChangeDelay = _operatorChangeDelay; havingPerfectOperators = true; } - function setOperatorChangeDelay(uint8 _operatorChangeDelay) external onlyOwner { - operatorChangeDelay = _operatorChangeDelay; - emit OperatorChangeDelaySet(_operatorChangeDelay); - } - /// @inheritdoc IPreconfWhitelist function addOperator(address _operator) external onlyOwner { _addOperator(_operator, operatorChangeDelay); @@ -218,15 +218,15 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - // We use the beacon root at or after ` _epochTimestamp - selectorBeaconBlockOffset` as the - // random number to select an operator. - // selectorBeaconBlockOffset must be big enough to ensure a non-zero beacon root is + uint256 timeShift = selectorBeaconEpochOffset * LibPreconfConstants.SECONDS_IN_EPOCH; + // We use the beacon root at or after ` _epochTimestamp - timeShift` as the random number to + // select an operator. + // selectorBeaconEpochOffset must be big enough to ensure a non-zero beacon root is // available and immutable. - if (_epochTimestamp < selectorBeaconBlockOffset) return address(0); + if (_epochTimestamp < timeShift) return address(0); - uint256 rand = - uint256(LibPreconfUtils.getBeaconBlockRoot(_epochTimestamp - selectorBeaconBlockOffset)); + uint256 rand = uint256(LibPreconfUtils.getBeaconBlockRoot(_epochTimestamp - timeShift)); if (rand == 0) return address(0); diff --git a/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol b/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol index e923725970d..704986dd149 100644 --- a/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol +++ b/packages/protocol/script/layer1/based/DeployProtocolOnL1.s.sol @@ -528,8 +528,8 @@ contract DeployProtocolOnL1 is DeployCapability { { whitelist = deployProxy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), - data: abi.encodeCall(PreconfWhitelist.init, (owner, 2)), + impl: address(new PreconfWhitelist(2, 3)), + data: abi.encodeCall(PreconfWhitelist.init, (owner)), registerTo: rollupResolver }); diff --git a/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol b/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol index cbdf5a3ddf7..ed15a31009d 100644 --- a/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol +++ b/packages/protocol/script/layer1/preconf/DeployPreconfContracts.s.sol @@ -28,8 +28,8 @@ contract DeployPreconfContracts is BaseScript { // Deploy PreconfWhitelist deploy( LibStrings.B_PRECONF_WHITELIST, - address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), - abi.encodeCall(PreconfWhitelist.init, (contractOwner, 2)) + address(new PreconfWhitelist(2, 3)), + abi.encodeCall(PreconfWhitelist.init, (contractOwner)) ); // Deploy PreconfRouter diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol index 9df70bcadfb..8f0d6a5d7e6 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol @@ -17,7 +17,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); + uint256 epoch4Start = epoch1Start + + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -73,7 +74,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); // Current epoch - uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); + uint256 epoch4Start = epoch1Start + + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -103,7 +105,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start + whitelist.selectorBeaconBlockOffset(); + uint256 epoch4Start = epoch1Start + + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol index 0b3833efc43..6d8359697d6 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouterTestBase.sol @@ -30,8 +30,8 @@ abstract contract PreconfRouterTestBase is Layer1Test { whitelist = PreconfWhitelist( deploy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), - data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 2)) + impl: address(new PreconfWhitelist(2, 3)), + data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner)) }) ); diff --git a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol index eaff41004b8..2f9c7fdccdd 100644 --- a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol +++ b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol @@ -16,16 +16,16 @@ contract TestPreconfWhitelist is Layer1Test { whitelist = PreconfWhitelist( deploy({ name: "preconf_whitelist", - impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), - data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 2)) + impl: address(new PreconfWhitelist(2, 3)), + data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner)) }) ); whitelistNoDelay = PreconfWhitelist( deploy({ name: "preconf_whitelist_nodelay", - impl: address(new PreconfWhitelist(3 * LibPreconfConstants.SECONDS_IN_EPOCH)), - data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner, 0)) + impl: address(new PreconfWhitelist(0, 3)), + data: abi.encodeCall(PreconfWhitelist.init, (whitelistOwner)) }) ); @@ -278,7 +278,7 @@ contract TestPreconfWhitelist is Layer1Test { assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), address(0)); - vm.warp(whitelistNoDelay.selectorBeaconBlockOffset()); + vm.warp(whitelistNoDelay.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH); assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), Bob); assertEq(whitelistNoDelay.getOperatorForNextEpoch(), Bob); From 87387c349dad2fc4bf4f3a77252a6daa853a29d8 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 11:18:30 +0800 Subject: [PATCH 08/11] Update PreconfWhitelist.sol --- .../contracts/layer1/preconf/impl/PreconfWhitelist.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index 823cff64460..c768bb333fa 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -19,7 +19,7 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { event Consolidated(uint8 previousCount, uint8 newCount, bool havingPerfectOperators); uint256 public immutable selectorBeaconEpochOffset; // in epochs - uint8 public immutable operatorChangeDelay; // in epochs + uint256 public immutable operatorChangeDelay; // in epochs // Slot 1 mapping(address operator => OperatorInfo info) public operators; @@ -36,7 +36,7 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { uint256[47] private __gap; constructor( - uint8 _operatorChangeDelay, + uint256 _operatorChangeDelay, uint256 _selectorBeaconEpochOffset ) EssentialContract(address(0)) @@ -170,7 +170,7 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { ); } - function _addOperator(address _operator, uint8 _operatorChangeDelay) internal { + function _addOperator(address _operator, uint256 _operatorChangeDelay) internal { require(_operator != address(0), InvalidOperatorAddress()); require(operators[_operator].activeSince == 0, OperatorAlreadyExists()); @@ -193,7 +193,7 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { emit OperatorAdded(_operator, activeSince); } - function _removeOperator(address _operator, uint8 _operatorChangeDelay) internal { + function _removeOperator(address _operator, uint256 _operatorChangeDelay) internal { require(_operator != address(0), InvalidOperatorAddress()); OperatorInfo memory info = operators[_operator]; require(info.inactiveSince == 0, OperatorAlreadyRemoved()); From be2a27542ad065ffda3db4b42ea73e3c15e71fa9 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 11:19:40 +0800 Subject: [PATCH 09/11] rename --- .../layer1/preconf/iface/IPreconfWhitelist.sol | 2 +- .../layer1/preconf/impl/PreconfWhitelist.sol | 12 ++++++------ .../test/layer1/preconf/router/PreconfRouter.t.sol | 12 ++++++------ .../layer1/preconf/whitelist/PeconfWhitelist.t.sol | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol index 35486e09683..760e23619ff 100644 --- a/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/iface/IPreconfWhitelist.sol @@ -17,7 +17,7 @@ interface IPreconfWhitelist { error InvalidOperatorIndex(); error InvalidOperatorCount(); error InvalidOperatorAddress(); - error InvalidselectorBeaconEpochOffset(); + error SelectorEpochOffsetTooSmall(); error OperatorAlreadyExists(); error OperatorAlreadyRemoved(); error OperatorNotAvailableYet(); diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index c768bb333fa..08d56af66cd 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -18,7 +18,7 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { event Consolidated(uint8 previousCount, uint8 newCount, bool havingPerfectOperators); - uint256 public immutable selectorBeaconEpochOffset; // in epochs + uint256 public immutable selectorEpochOffset; // in epochs uint256 public immutable operatorChangeDelay; // in epochs // Slot 1 @@ -37,12 +37,12 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { constructor( uint256 _operatorChangeDelay, - uint256 _selectorBeaconEpochOffset + uint256 _selectorEpochOffset ) EssentialContract(address(0)) { - require(_selectorBeaconEpochOffset > 1, InvalidselectorBeaconEpochOffset()); - selectorBeaconEpochOffset = _selectorBeaconEpochOffset; + require(_selectorEpochOffset > 1, SelectorEpochOffsetTooSmall()); + selectorEpochOffset = _selectorEpochOffset; operatorChangeDelay = _operatorChangeDelay; } @@ -218,10 +218,10 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { /// @dev The cost of this function is primarily linear with respect to operatorCount. function _getOperatorForEpoch(uint64 _epochTimestamp) internal view returns (address) { - uint256 timeShift = selectorBeaconEpochOffset * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 timeShift = selectorEpochOffset * LibPreconfConstants.SECONDS_IN_EPOCH; // We use the beacon root at or after ` _epochTimestamp - timeShift` as the random number to // select an operator. - // selectorBeaconEpochOffset must be big enough to ensure a non-zero beacon root is + // selectorEpochOffset must be big enough to ensure a non-zero beacon root is // available and immutable. if (_epochTimestamp < timeShift) return address(0); diff --git a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol index 8f0d6a5d7e6..32c5e35448a 100644 --- a/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol +++ b/packages/protocol/test/layer1/preconf/router/PreconfRouter.t.sol @@ -17,8 +17,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start - + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = + epoch1Start + whitelist.selectorEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -74,8 +74,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); // Current epoch - uint256 epoch4Start = epoch1Start - + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = + epoch1Start + whitelist.selectorEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol @@ -105,8 +105,8 @@ contract PreconfRouterTest is PreconfRouterTestBase { vm.chainId(1); uint256 epoch1Start = LibPreconfConstants.getGenesisTimestamp(block.chainid); // Current epoch - uint256 epoch4Start = epoch1Start - + whitelist.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; + uint256 epoch4Start = + epoch1Start + whitelist.selectorEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH; MockBeaconBlockRoot mockBeacon = new MockBeaconBlockRoot(); bytes32 mockRoot = bytes32(uint256(1)); // This will select Carol diff --git a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol index 2f9c7fdccdd..27774243b8c 100644 --- a/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol +++ b/packages/protocol/test/layer1/preconf/whitelist/PeconfWhitelist.t.sol @@ -278,7 +278,7 @@ contract TestPreconfWhitelist is Layer1Test { assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), address(0)); - vm.warp(whitelistNoDelay.selectorBeaconEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH); + vm.warp(whitelistNoDelay.selectorEpochOffset() * LibPreconfConstants.SECONDS_IN_EPOCH); assertEq(whitelistNoDelay.getOperatorForCurrentEpoch(), Bob); assertEq(whitelistNoDelay.getOperatorForNextEpoch(), Bob); From 2612b1ec6a6cd19973d9c181f87e140f3c420df0 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 24 Apr 2025 11:21:06 +0800 Subject: [PATCH 10/11] Update PreconfWhitelist.sol --- .../contracts/layer1/preconf/impl/PreconfWhitelist.sol | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol index 08d56af66cd..b3f286a5523 100644 --- a/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol +++ b/packages/protocol/contracts/layer1/preconf/impl/PreconfWhitelist.sol @@ -226,7 +226,10 @@ contract PreconfWhitelist is EssentialContract, IPreconfWhitelist { if (_epochTimestamp < timeShift) return address(0); - uint256 rand = uint256(LibPreconfUtils.getBeaconBlockRoot(_epochTimestamp - timeShift)); + uint256 rand; + unchecked { + rand = uint256(LibPreconfUtils.getBeaconBlockRoot(_epochTimestamp - timeShift)); + } if (rand == 0) return address(0); From b78f33cb375fe677c8a675d25eef215740f23d24 Mon Sep 17 00:00:00 2001 From: dantaik <99078276+dantaik@users.noreply.github.com> Date: Thu, 24 Apr 2025 03:24:53 +0000 Subject: [PATCH 11/11] forge fmt & update contract layout tables --- packages/protocol/.gas-snapshot | 28 ++++++++++---------- packages/protocol/layout/layer1-contracts.md | 4 +-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/protocol/.gas-snapshot b/packages/protocol/.gas-snapshot index 19e5160a1d4..d2ed28e618e 100644 --- a/packages/protocol/.gas-snapshot +++ b/packages/protocol/.gas-snapshot @@ -70,9 +70,9 @@ InboxTest_ProposeAndProve:test_inbox_reprove_the_same_batch_with_same_transition InboxTest_ProposeAndProve:test_inbox_ring_buffer_will_be_reused() (gas: 14705853) InboxTest_ProposeAndProve:test_proposeBatch_reverts_for_invalid_proposer_and_operator() (gas: 165337) InboxTest_StopBatch:test_inbox_num_batches_verified() (gas: 8162653) -PreconfRouterTest:test_preconfRouter_proposeBatch() (gas: 374662) -PreconfRouterTest:test_preconfRouter_proposeBatch_notOperator() (gas: 325828) -PreconfRouterTest:test_preconfRouter_proposeBatch_proposerNotSender() (gas: 373393) +PreconfRouterTest:test_preconfRouter_proposeBatch() (gas: 375140) +PreconfRouterTest:test_preconfRouter_proposeBatch_notOperator() (gas: 326307) +PreconfRouterTest:test_preconfRouter_proposeBatch_proposerNotSender() (gas: 373872) SendMessageToDelegateOwner:testAddress1() (gas: 2391) TestAutomataDcapV3Attestation:testAttestation() (gas: 4848498) TestAutomataDcapV3Attestation:testParsedCustomQuoteBinAttestation() (gas: 4553350) @@ -90,7 +90,7 @@ TestAutomataDcapV3Attestation:testToggleCheckQuoteValidity() (gas: 21556) TestERC20Airdrop:test_erc20_airdrop_claim() (gas: 189244) TestForkRouter:test_ForkRouter_default_routing() (gas: 2461333) TestForkRouter:test_ForkRouter_routing_to_old_fork() (gas: 1734609) -TestLibPreconfUtils:test_getBeaconBlockRootAtOrAfter() (gas: 90446) +TestLibPreconfUtils:test_getBeaconBlockRoot() (gas: 90446) TestMerkleClaimable:test_verifyClaim_after_it_ends() (gas: 36877) TestMerkleClaimable:test_verifyClaim_before_it_starts() (gas: 36626) TestMerkleClaimable:test_verifyClaim_twice_while_its_ongoing() (gas: 66484) @@ -107,16 +107,16 @@ TestMinimalOwner:test_minimalOwner_InitialOwner() (gas: 13083) TestMinimalOwner:test_minimalOwner_TransferOwnership() (gas: 21879) TestMinimalOwner:test_minimalOwner_TransferOwnershipToSameAddress() (gas: 13832) TestMinimalOwner:test_minimalOwner_TransferOwnershipToZeroAddress() (gas: 13493) -TestPreconfWhitelist:test_whitelistNoDelay_consolidationPreservesOrder() (gas: 252745) -TestPreconfWhitelist:test_whitelistNoDelay_consolidationWillNotChangeCurrentEpochOperator() (gas: 291891) -TestPreconfWhitelist:test_whitelist_addBackRemovedOperator() (gas: 106230) -TestPreconfWhitelist:test_whitelist_addOrRemoveTheSameOperatorTwiceWillRevert() (gas: 83296) -TestPreconfWhitelist:test_whitelist_consolidate_whenEmpty_not_revert() (gas: 19756) -TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveOneOperator() (gas: 248398) -TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveTwoOperators() (gas: 296865) -TestPreconfWhitelist:test_whitelist_noDelay_addThenRemoveOneOperator() (gas: 159918) -TestPreconfWhitelist:test_whitelist_removeNonExistingOperatorWillRevert() (gas: 25210) -TestPreconfWhitelist:test_whitelist_selfRemoval() (gas: 139660) +TestPreconfWhitelist:test_whitelistNoDelay_consolidationPreservesOrder() (gas: 251985) +TestPreconfWhitelist:test_whitelistNoDelay_consolidationWillNotChangeCurrentEpochOperator() (gas: 291066) +TestPreconfWhitelist:test_whitelist_addBackRemovedOperator() (gas: 105759) +TestPreconfWhitelist:test_whitelist_addOrRemoveTheSameOperatorTwiceWillRevert() (gas: 82692) +TestPreconfWhitelist:test_whitelist_consolidate_whenEmpty_not_revert() (gas: 19712) +TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveOneOperator() (gas: 245550) +TestPreconfWhitelist:test_whitelist_delay2epoch_addThenRemoveTwoOperators() (gas: 294371) +TestPreconfWhitelist:test_whitelist_noDelay_addThenRemoveOneOperator() (gas: 158506) +TestPreconfWhitelist:test_whitelist_removeNonExistingOperatorWillRevert() (gas: 23065) +TestPreconfWhitelist:test_whitelist_selfRemoval() (gas: 139154) TestTaikoTreasuryVault:testForwardCallFailsOnError() (gas: 79082) TestTaikoTreasuryVault:testForwardCallToSelfShouldRevert() (gas: 26006) TestTaikoTreasuryVault:testNonOwnerCannotForwardCall() (gas: 28382) diff --git a/packages/protocol/layout/layer1-contracts.md b/packages/protocol/layout/layer1-contracts.md index b2b0d8eb4b2..52cdfaab7d3 100644 --- a/packages/protocol/layout/layer1-contracts.md +++ b/packages/protocol/layout/layer1-contracts.md @@ -1346,9 +1346,7 @@ | | operatorCount | uint8 | 253 | 0 | 1 | | -| operatorChangeDelay | uint8 | 253 | 1 | 1 | -| -| havingPerfectOperators | bool | 253 | 2 | 1 | +| havingPerfectOperators | bool | 253 | 1 | 1 | | | __gap | uint256[47] | 254 | 0 | 1504 | ╰-----------------------------+----------------------------------------------------------+------+--------+-------+---------------------------------------------------------------------╯