Skip to content

Commit 3b463f9

Browse files
authored
feat!: time library (#11542)
Fixed #11520
1 parent 65a3f11 commit 3b463f9

File tree

68 files changed

+209
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+209
-176
lines changed

docs/docs/guides/developer_guides/js_apps/test.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ The [`CheatCodes`](../../../reference/developer_references/sandbox_reference/che
134134
### Set next block timestamp
135135

136136
Since the rollup time is dependent on what "slot" the block is included in, time can be progressed by progressing slots.
137-
The duration of a slot is available by calling `SLOT_DURATION()` on the Rollup (code in Leonidas.sol).
137+
The duration of a slot is available by calling `getSlotDuration()` on the Rollup (code in Leonidas.sol).
138138

139139
You can then use the `warp` function on the EthCheatCodes to progress the underlying chain.
140140

l1-contracts/src/core/ProofCommitmentEscrow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity >=0.8.27;
44

55
import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
66
import {Errors} from "@aztec/core/libraries/Errors.sol";
7-
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
7+
import {Timestamp} from "@aztec/core/libraries/TimeLib.sol";
88
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
99
import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";
1010

l1-contracts/src/core/Rollup.sol

+7-8
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
} from "@aztec/core/libraries/RollupLibs/ExtRollupLib.sol";
3535
import {IntRollupLib, EpochProofQuote} from "@aztec/core/libraries/RollupLibs/IntRollupLib.sol";
3636
import {ProposeArgs, ProposeLib} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol";
37-
import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/TimeMath.sol";
37+
import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
3838
import {Inbox} from "@aztec/core/messagebridge/Inbox.sol";
3939
import {Outbox} from "@aztec/core/messagebridge/Outbox.sol";
4040
import {ProofCommitmentEscrow} from "@aztec/core/ProofCommitmentEscrow.sol";
@@ -63,8 +63,6 @@ struct Config {
6363
* @dev WARNING: This contract is VERY close to the size limit (500B at time of writing).
6464
*/
6565
contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRollup, ITestRollup {
66-
using SlotLib for Slot;
67-
using EpochLib for Epoch;
6866
using ProposeLib for ProposeArgs;
6967
using IntRollupLib for uint256;
7068
using IntRollupLib for ManaBaseFeeComponents;
@@ -662,7 +660,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo
662660
rollupStore.blocks[blockOfInterest].feeHeader,
663661
getL1FeesAt(_timestamp),
664662
_inFeeAsset ? getFeeAssetPrice() : 1e9,
665-
EPOCH_DURATION
663+
TimeLib.getStorage().epochDuration
666664
);
667665
}
668666

@@ -683,7 +681,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo
683681
Slot currentSlot = getSlotAt(_ts);
684682
address currentProposer = getProposerAt(_ts);
685683
Epoch epochToProve = getEpochToProve();
686-
uint256 posInEpoch = positionInEpoch(currentSlot);
684+
uint256 posInEpoch = TimeLib.positionInEpoch(currentSlot);
687685
bytes32 digest = quoteToDigest(_quote.quote);
688686

689687
ExtRollupLib.validateEpochProofRightClaimAtTime(
@@ -786,16 +784,17 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo
786784

787785
Slot currentSlot = getSlotAt(_ts);
788786
Epoch oldestPendingEpoch = getEpochForBlock(rollupStore.tips.provenBlockNumber + 1);
789-
Slot startSlotOfPendingEpoch = toSlots(oldestPendingEpoch);
787+
Slot startSlotOfPendingEpoch = TimeLib.toSlots(oldestPendingEpoch);
790788

791789
// suppose epoch 1 is proven, epoch 2 is pending, epoch 3 is the current epoch.
792790
// we prune the pending chain back to the end of epoch 1 if:
793791
// - the proof claim phase of epoch 3 has ended without a claim to prove epoch 2 (or proof of epoch 2)
794792
// - we reach epoch 4 without a proof of epoch 2 (regardless of whether a proof claim was submitted)
795793
bool inClaimPhase = currentSlot
796-
< startSlotOfPendingEpoch + toSlots(Epoch.wrap(1)) + Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS);
794+
< startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(1))
795+
+ Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS);
797796

798-
bool claimExists = currentSlot < startSlotOfPendingEpoch + toSlots(Epoch.wrap(2))
797+
bool claimExists = currentSlot < startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(2))
799798
&& rollupStore.proofClaim.epochToProve == oldestPendingEpoch
800799
&& rollupStore.proofClaim.proposerClaimant != address(0);
801800

l1-contracts/src/core/ValidatorSelection.sol

+25-17
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol";
1111
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
1212
import {Errors} from "@aztec/core/libraries/Errors.sol";
1313
import {
14-
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeFns
15-
} from "@aztec/core/libraries/TimeMath.sol";
14+
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib
15+
} from "@aztec/core/libraries/TimeLib.sol";
1616
import {ValidatorSelectionLib} from
1717
"@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol";
1818
import {Staking} from "@aztec/core/staking/Staking.sol";
@@ -27,19 +27,19 @@ import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
2727
* It is a reference implementation, it is not optimized for gas.
2828
*
2929
*/
30-
contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
30+
contract ValidatorSelection is Staking, IValidatorSelection {
3131
using EnumerableSet for EnumerableSet.AddressSet;
3232

3333
using SlotLib for Slot;
3434
using EpochLib for Epoch;
35+
using TimeLib for Timestamp;
36+
using TimeLib for Slot;
37+
using TimeLib for Epoch;
3538

3639
// The target number of validators in a committee
3740
// @todo #8021
3841
uint256 public immutable TARGET_COMMITTEE_SIZE;
3942

40-
// The time that the contract was deployed
41-
Timestamp public immutable GENESIS_TIME;
42-
4343
ValidatorSelectionStorage private validatorSelectionStore;
4444

4545
constructor(
@@ -50,14 +50,22 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
5050
uint256 _slotDuration,
5151
uint256 _epochDuration,
5252
uint256 _targetCommitteeSize
53-
)
54-
Staking(_stakingAsset, _minimumStake, _slashingQuorum, _roundSize)
55-
TimeFns(_slotDuration, _epochDuration)
56-
{
57-
GENESIS_TIME = Timestamp.wrap(block.timestamp);
58-
SLOT_DURATION = _slotDuration;
59-
EPOCH_DURATION = _epochDuration;
53+
) Staking(_stakingAsset, _minimumStake, _slashingQuorum, _roundSize) {
6054
TARGET_COMMITTEE_SIZE = _targetCommitteeSize;
55+
56+
TimeLib.initialize(block.timestamp, _slotDuration, _epochDuration);
57+
}
58+
59+
function getGenesisTime() external view override(IValidatorSelection) returns (Timestamp) {
60+
return Timestamp.wrap(TimeLib.getStorage().genesisTime);
61+
}
62+
63+
function getSlotDuration() external view override(IValidatorSelection) returns (uint256) {
64+
return TimeLib.getStorage().slotDuration;
65+
}
66+
67+
function getEpochDuration() external view override(IValidatorSelection) returns (uint256) {
68+
return TimeLib.getStorage().epochDuration;
6169
}
6270

6371
/**
@@ -224,7 +232,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
224232
override(IValidatorSelection)
225233
returns (Timestamp)
226234
{
227-
return GENESIS_TIME + toTimestamp(_slotNumber);
235+
return _slotNumber.toTimestamp();
228236
}
229237

230238
/**
@@ -275,7 +283,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
275283
* @return The computed epoch
276284
*/
277285
function getEpochAt(Timestamp _ts) public view override(IValidatorSelection) returns (Epoch) {
278-
return _ts < GENESIS_TIME ? Epoch.wrap(0) : epochFromTimestamp(_ts - GENESIS_TIME);
286+
return _ts.epochFromTimestamp();
279287
}
280288

281289
/**
@@ -286,7 +294,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
286294
* @return The computed slot
287295
*/
288296
function getSlotAt(Timestamp _ts) public view override(IValidatorSelection) returns (Slot) {
289-
return _ts < GENESIS_TIME ? Slot.wrap(0) : slotFromTimestamp(_ts - GENESIS_TIME);
297+
return _ts.slotFromTimestamp();
290298
}
291299

292300
/**
@@ -302,7 +310,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
302310
override(IValidatorSelection)
303311
returns (Epoch)
304312
{
305-
return Epoch.wrap(_slotNumber.unwrap() / EPOCH_DURATION);
313+
return _slotNumber.epochFromSlot();
306314
}
307315

308316
// Can be used to add validators without setting up the epoch, useful for the initial set.

l1-contracts/src/core/interfaces/IProofCommitmentEscrow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright 2024 Aztec Labs.
33
pragma solidity >=0.8.27;
44

5-
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
5+
import {Timestamp} from "@aztec/core/libraries/TimeLib.sol";
66
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
77

88
interface IProofCommitmentEscrow {

l1-contracts/src/core/interfaces/IRollup.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
FeeHeader, L1FeeData, ManaBaseFeeComponents
1616
} from "@aztec/core/libraries/RollupLibs/FeeMath.sol";
1717
import {ProposeArgs} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol";
18-
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
18+
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
1919

2020
struct SubmitEpochRootProofArgs {
2121
uint256 epochSize;

l1-contracts/src/core/interfaces/IStaking.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright 2024 Aztec Labs.
33
pragma solidity >=0.8.27;
44

5-
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
5+
import {Timestamp} from "@aztec/core/libraries/TimeLib.sol";
66
import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
77

88
// None -> Does not exist in our setup

l1-contracts/src/core/interfaces/IValidatorSelection.sol

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright 2024 Aztec Labs.
33
pragma solidity >=0.8.27;
44

5-
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
5+
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
66

77
/**
88
* @notice The data structure for an epoch
@@ -49,4 +49,8 @@ interface IValidatorSelection {
4949
function getEpochAt(Timestamp _ts) external view returns (Epoch);
5050
function getSlotAt(Timestamp _ts) external view returns (Slot);
5151
function getEpochAtSlot(Slot _slotNumber) external view returns (Epoch);
52+
53+
function getGenesisTime() external view returns (Timestamp);
54+
function getSlotDuration() external view returns (uint256);
55+
function getEpochDuration() external view returns (uint256);
5256
}

l1-contracts/src/core/libraries/DataStructures.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright 2024 Aztec Labs.
33
pragma solidity >=0.8.27;
44

5-
import {Epoch} from "@aztec/core/libraries/TimeMath.sol";
5+
import {Epoch} from "@aztec/core/libraries/TimeLib.sol";
66

77
/**
88
* @title Data Structures Library

l1-contracts/src/core/libraries/Errors.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Copyright 2024 Aztec Labs.
33
pragma solidity >=0.8.27;
44

5-
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
5+
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
66

77
/**
88
* @title Errors Library

l1-contracts/src/core/libraries/RollupLibs/EpochProofLib.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from "@aztec/core/interfaces/IRollup.sol";
1010
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
1111
import {Errors} from "@aztec/core/libraries/Errors.sol";
12-
import {Epoch} from "@aztec/core/libraries/TimeMath.sol";
12+
import {Epoch} from "@aztec/core/libraries/TimeLib.sol";
1313
import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol";
1414
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
1515
import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";

l1-contracts/src/core/libraries/RollupLibs/EpochProofQuoteLib.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pragma solidity >=0.8.27;
44

55
import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol";
6-
import {Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
6+
import {Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
77

88
/**
99
* @notice Struct encompassing an epoch proof quote

l1-contracts/src/core/libraries/RollupLibs/ExtRollupLib.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {BlockLog, RollupStore, SubmitEpochRootProofArgs} from "@aztec/core/inter
99
import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol";
1010
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
1111
import {DataStructures} from "./../DataStructures.sol";
12-
import {Slot, Epoch} from "./../TimeMath.sol";
12+
import {Slot, Epoch} from "./../TimeLib.sol";
1313
import {BlobLib} from "./BlobLib.sol";
1414
import {
1515
EpochProofLib,

l1-contracts/src/core/libraries/RollupLibs/ValidationLib.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {BlockLog} from "@aztec/core/interfaces/IRollup.sol";
88
import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol";
99
import {DataStructures} from "./../DataStructures.sol";
1010
import {Errors} from "./../Errors.sol";
11-
import {Timestamp, Slot, Epoch} from "./../TimeMath.sol";
11+
import {Timestamp, Slot, Epoch} from "./../TimeLib.sol";
1212
import {SignedEpochProofQuote} from "./EpochProofQuoteLib.sol";
1313
import {Header} from "./HeaderLib.sol";
1414

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright 2024 Aztec Labs.
3+
pragma solidity >=0.8.27;
4+
5+
// solhint-disable-next-line no-unused-import
6+
import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/TimeMath.sol";
7+
8+
struct TimeStorage {
9+
uint256 genesisTime;
10+
uint256 slotDuration; // Number of seconds in a slot
11+
uint256 epochDuration; // Number of slots in an epoch
12+
}
13+
14+
library TimeLib {
15+
bytes32 private constant TIME_STORAGE_POSITION = keccak256("aztec.time.storage");
16+
17+
function initialize(uint256 _genesisTime, uint256 _slotDuration, uint256 _epochDuration) internal {
18+
TimeStorage storage store = getStorage();
19+
store.genesisTime = _genesisTime;
20+
store.slotDuration = _slotDuration;
21+
store.epochDuration = _epochDuration;
22+
}
23+
24+
function toTimestamp(Slot _a) internal view returns (Timestamp) {
25+
TimeStorage storage store = getStorage();
26+
return Timestamp.wrap(store.genesisTime) + Timestamp.wrap(Slot.unwrap(_a) * store.slotDuration);
27+
}
28+
29+
function slotFromTimestamp(Timestamp _a) internal view returns (Slot) {
30+
TimeStorage storage store = getStorage();
31+
return Slot.wrap((Timestamp.unwrap(_a) - store.genesisTime) / store.slotDuration);
32+
}
33+
34+
function positionInEpoch(Slot _a) internal view returns (uint256) {
35+
return Slot.unwrap(_a) % getStorage().epochDuration;
36+
}
37+
38+
function toSlots(Epoch _a) internal view returns (Slot) {
39+
return Slot.wrap(Epoch.unwrap(_a) * getStorage().epochDuration);
40+
}
41+
42+
function toTimestamp(Epoch _a) internal view returns (Timestamp) {
43+
return toTimestamp(toSlots(_a));
44+
}
45+
46+
function epochFromTimestamp(Timestamp _a) internal view returns (Epoch) {
47+
TimeStorage storage store = getStorage();
48+
return Epoch.wrap(
49+
(Timestamp.unwrap(_a) - store.genesisTime) / (store.epochDuration * store.slotDuration)
50+
);
51+
}
52+
53+
function epochFromSlot(Slot _a) internal view returns (Epoch) {
54+
return Epoch.wrap(Slot.unwrap(_a) / getStorage().epochDuration);
55+
}
56+
57+
function getStorage() internal pure returns (TimeStorage storage storageStruct) {
58+
bytes32 position = TIME_STORAGE_POSITION;
59+
assembly {
60+
storageStruct.slot := position
61+
}
62+
}
63+
}

l1-contracts/src/core/libraries/TimeMath.sol

-47
Original file line numberDiff line numberDiff line change
@@ -8,53 +8,6 @@ type Slot is uint256;
88

99
type Epoch is uint256;
1010

11-
abstract contract TimeFns {
12-
// @note @LHerskind The multiple cause pain and suffering in the E2E tests as we introduce
13-
// a timeliness requirement into the publication that did not exists before,
14-
// and at the same time have a setup that will impact the time at every tx
15-
// because of auto-mine. By using just 1, we can make our test work
16-
// but anything using an actual working chain would eat dung as simulating
17-
// transactions is slower than an actual ethereum slot.
18-
//
19-
// The value should be a higher multiple for any actual chain
20-
// @todo #8019
21-
uint256 public immutable SLOT_DURATION;
22-
23-
// The duration of an epoch in slots
24-
// @todo @LHerskind - This value should be updated when we are not blind.
25-
// @todo #8020
26-
uint256 public immutable EPOCH_DURATION;
27-
28-
constructor(uint256 _slotDuration, uint256 _epochDuration) {
29-
SLOT_DURATION = _slotDuration;
30-
EPOCH_DURATION = _epochDuration;
31-
}
32-
33-
function toTimestamp(Slot _a) internal view returns (Timestamp) {
34-
return Timestamp.wrap(Slot.unwrap(_a) * SLOT_DURATION);
35-
}
36-
37-
function slotFromTimestamp(Timestamp _a) internal view returns (Slot) {
38-
return Slot.wrap(Timestamp.unwrap(_a) / SLOT_DURATION);
39-
}
40-
41-
function positionInEpoch(Slot _a) internal view returns (uint256) {
42-
return Slot.unwrap(_a) % EPOCH_DURATION;
43-
}
44-
45-
function toSlots(Epoch _a) internal view returns (Slot) {
46-
return Slot.wrap(Epoch.unwrap(_a) * EPOCH_DURATION);
47-
}
48-
49-
function toTimestamp(Epoch _a) internal view returns (Timestamp) {
50-
return toTimestamp(toSlots(_a));
51-
}
52-
53-
function epochFromTimestamp(Timestamp _a) internal view returns (Epoch) {
54-
return Epoch.wrap(Timestamp.unwrap(_a) / (EPOCH_DURATION * SLOT_DURATION));
55-
}
56-
}
57-
5811
library SlotLib {
5912
function unwrap(Slot _a) internal pure returns (uint256) {
6013
return Slot.unwrap(_a);

0 commit comments

Comments
 (0)