Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: time library #11542

Merged
merged 1 commit into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/guides/developer_guides/js_apps/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ The [`CheatCodes`](../../../reference/developer_references/sandbox_reference/che
### Set next block timestamp

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

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

Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/ProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity >=0.8.27;

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
import {Timestamp} from "@aztec/core/libraries/TimeLib.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";

Expand Down
15 changes: 7 additions & 8 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
} from "@aztec/core/libraries/RollupLibs/ExtRollupLib.sol";
import {IntRollupLib, EpochProofQuote} from "@aztec/core/libraries/RollupLibs/IntRollupLib.sol";
import {ProposeArgs, ProposeLib} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol";
import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/TimeMath.sol";
import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
import {Inbox} from "@aztec/core/messagebridge/Inbox.sol";
import {Outbox} from "@aztec/core/messagebridge/Outbox.sol";
import {ProofCommitmentEscrow} from "@aztec/core/ProofCommitmentEscrow.sol";
Expand Down Expand Up @@ -63,8 +63,6 @@ struct Config {
* @dev WARNING: This contract is VERY close to the size limit (500B at time of writing).
*/
contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRollup, ITestRollup {
using SlotLib for Slot;
using EpochLib for Epoch;
using ProposeLib for ProposeArgs;
using IntRollupLib for uint256;
using IntRollupLib for ManaBaseFeeComponents;
Expand Down Expand Up @@ -662,7 +660,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo
rollupStore.blocks[blockOfInterest].feeHeader,
getL1FeesAt(_timestamp),
_inFeeAsset ? getFeeAssetPrice() : 1e9,
EPOCH_DURATION
TimeLib.getStorage().epochDuration
);
}

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

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

Slot currentSlot = getSlotAt(_ts);
Epoch oldestPendingEpoch = getEpochForBlock(rollupStore.tips.provenBlockNumber + 1);
Slot startSlotOfPendingEpoch = toSlots(oldestPendingEpoch);
Slot startSlotOfPendingEpoch = TimeLib.toSlots(oldestPendingEpoch);

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

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

Expand Down
42 changes: 25 additions & 17 deletions l1-contracts/src/core/ValidatorSelection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol";
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeFns
} from "@aztec/core/libraries/TimeMath.sol";
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib
} from "@aztec/core/libraries/TimeLib.sol";
import {ValidatorSelectionLib} from
"@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol";
import {Staking} from "@aztec/core/staking/Staking.sol";
Expand All @@ -27,19 +27,19 @@ import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
* It is a reference implementation, it is not optimized for gas.
*
*/
contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
contract ValidatorSelection is Staking, IValidatorSelection {
using EnumerableSet for EnumerableSet.AddressSet;

using SlotLib for Slot;
using EpochLib for Epoch;
using TimeLib for Timestamp;
using TimeLib for Slot;
using TimeLib for Epoch;

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

// The time that the contract was deployed
Timestamp public immutable GENESIS_TIME;

ValidatorSelectionStorage private validatorSelectionStore;

constructor(
Expand All @@ -50,14 +50,22 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
uint256 _slotDuration,
uint256 _epochDuration,
uint256 _targetCommitteeSize
)
Staking(_stakingAsset, _minimumStake, _slashingQuorum, _roundSize)
TimeFns(_slotDuration, _epochDuration)
{
GENESIS_TIME = Timestamp.wrap(block.timestamp);
SLOT_DURATION = _slotDuration;
EPOCH_DURATION = _epochDuration;
) Staking(_stakingAsset, _minimumStake, _slashingQuorum, _roundSize) {
TARGET_COMMITTEE_SIZE = _targetCommitteeSize;

TimeLib.initialize(block.timestamp, _slotDuration, _epochDuration);
}

function getGenesisTime() external view override(IValidatorSelection) returns (Timestamp) {
return Timestamp.wrap(TimeLib.getStorage().genesisTime);
}

function getSlotDuration() external view override(IValidatorSelection) returns (uint256) {
return TimeLib.getStorage().slotDuration;
}

function getEpochDuration() external view override(IValidatorSelection) returns (uint256) {
return TimeLib.getStorage().epochDuration;
}

/**
Expand Down Expand Up @@ -224,7 +232,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
override(IValidatorSelection)
returns (Timestamp)
{
return GENESIS_TIME + toTimestamp(_slotNumber);
return _slotNumber.toTimestamp();
}

/**
Expand Down Expand Up @@ -275,7 +283,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
* @return The computed epoch
*/
function getEpochAt(Timestamp _ts) public view override(IValidatorSelection) returns (Epoch) {
return _ts < GENESIS_TIME ? Epoch.wrap(0) : epochFromTimestamp(_ts - GENESIS_TIME);
return _ts.epochFromTimestamp();
}

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

/**
Expand All @@ -302,7 +310,7 @@ contract ValidatorSelection is Staking, TimeFns, IValidatorSelection {
override(IValidatorSelection)
returns (Epoch)
{
return Epoch.wrap(_slotNumber.unwrap() / EPOCH_DURATION);
return _slotNumber.epochFromSlot();
}

// Can be used to add validators without setting up the epoch, useful for the initial set.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

interface IProofCommitmentEscrow {
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
FeeHeader, L1FeeData, ManaBaseFeeComponents
} from "@aztec/core/libraries/RollupLibs/FeeMath.sol";
import {ProposeArgs} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";

struct SubmitEpochRootProofArgs {
uint256 epochSize;
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/interfaces/IStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

// None -> Does not exist in our setup
Expand Down
6 changes: 5 additions & 1 deletion l1-contracts/src/core/interfaces/IValidatorSelection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

/**
* @notice The data structure for an epoch
Expand Down Expand Up @@ -49,4 +49,8 @@ interface IValidatorSelection {
function getEpochAt(Timestamp _ts) external view returns (Epoch);
function getSlotAt(Timestamp _ts) external view returns (Slot);
function getEpochAtSlot(Slot _slotNumber) external view returns (Epoch);

function getGenesisTime() external view returns (Timestamp);
function getSlotDuration() external view returns (uint256);
function getEpochDuration() external view returns (uint256);
}
2 changes: 1 addition & 1 deletion l1-contracts/src/core/libraries/DataStructures.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

/**
* @title Data Structures Library
Expand Down
2 changes: 1 addition & 1 deletion l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

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

/**
* @title Errors Library
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@aztec/core/interfaces/IRollup.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Epoch} from "@aztec/core/libraries/TimeMath.sol";
import {Epoch} from "@aztec/core/libraries/TimeLib.sol";
import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pragma solidity >=0.8.27;

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

/**
* @notice Struct encompassing an epoch proof quote
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {BlockLog, RollupStore, SubmitEpochRootProofArgs} from "@aztec/core/inter
import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
import {DataStructures} from "./../DataStructures.sol";
import {Slot, Epoch} from "./../TimeMath.sol";
import {Slot, Epoch} from "./../TimeLib.sol";
import {BlobLib} from "./BlobLib.sol";
import {
EpochProofLib,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {BlockLog} from "@aztec/core/interfaces/IRollup.sol";
import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol";
import {DataStructures} from "./../DataStructures.sol";
import {Errors} from "./../Errors.sol";
import {Timestamp, Slot, Epoch} from "./../TimeMath.sol";
import {Timestamp, Slot, Epoch} from "./../TimeLib.sol";
import {SignedEpochProofQuote} from "./EpochProofQuoteLib.sol";
import {Header} from "./HeaderLib.sol";

Expand Down
63 changes: 63 additions & 0 deletions l1-contracts/src/core/libraries/TimeLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

// solhint-disable-next-line no-unused-import
import {Timestamp, Slot, Epoch, SlotLib, EpochLib} from "@aztec/core/libraries/TimeMath.sol";

struct TimeStorage {
uint256 genesisTime;
uint256 slotDuration; // Number of seconds in a slot
uint256 epochDuration; // Number of slots in an epoch
}

library TimeLib {
bytes32 private constant TIME_STORAGE_POSITION = keccak256("aztec.time.storage");

function initialize(uint256 _genesisTime, uint256 _slotDuration, uint256 _epochDuration) internal {
TimeStorage storage store = getStorage();
store.genesisTime = _genesisTime;
store.slotDuration = _slotDuration;
store.epochDuration = _epochDuration;
}

function toTimestamp(Slot _a) internal view returns (Timestamp) {
TimeStorage storage store = getStorage();
return Timestamp.wrap(store.genesisTime) + Timestamp.wrap(Slot.unwrap(_a) * store.slotDuration);
}

function slotFromTimestamp(Timestamp _a) internal view returns (Slot) {
TimeStorage storage store = getStorage();
return Slot.wrap((Timestamp.unwrap(_a) - store.genesisTime) / store.slotDuration);
}

function positionInEpoch(Slot _a) internal view returns (uint256) {
return Slot.unwrap(_a) % getStorage().epochDuration;
}

function toSlots(Epoch _a) internal view returns (Slot) {
return Slot.wrap(Epoch.unwrap(_a) * getStorage().epochDuration);
}

function toTimestamp(Epoch _a) internal view returns (Timestamp) {
return toTimestamp(toSlots(_a));
}

function epochFromTimestamp(Timestamp _a) internal view returns (Epoch) {
TimeStorage storage store = getStorage();
return Epoch.wrap(
(Timestamp.unwrap(_a) - store.genesisTime) / (store.epochDuration * store.slotDuration)
);
}

function epochFromSlot(Slot _a) internal view returns (Epoch) {
return Epoch.wrap(Slot.unwrap(_a) / getStorage().epochDuration);
}

function getStorage() internal pure returns (TimeStorage storage storageStruct) {
bytes32 position = TIME_STORAGE_POSITION;
assembly {
storageStruct.slot := position
}
}
}
47 changes: 0 additions & 47 deletions l1-contracts/src/core/libraries/TimeMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,6 @@ type Slot is uint256;

type Epoch is uint256;

abstract contract TimeFns {
// @note @LHerskind The multiple cause pain and suffering in the E2E tests as we introduce
// a timeliness requirement into the publication that did not exists before,
// and at the same time have a setup that will impact the time at every tx
// because of auto-mine. By using just 1, we can make our test work
// but anything using an actual working chain would eat dung as simulating
// transactions is slower than an actual ethereum slot.
//
// The value should be a higher multiple for any actual chain
// @todo #8019
uint256 public immutable SLOT_DURATION;

// The duration of an epoch in slots
// @todo @LHerskind - This value should be updated when we are not blind.
// @todo #8020
uint256 public immutable EPOCH_DURATION;

constructor(uint256 _slotDuration, uint256 _epochDuration) {
SLOT_DURATION = _slotDuration;
EPOCH_DURATION = _epochDuration;
}

function toTimestamp(Slot _a) internal view returns (Timestamp) {
return Timestamp.wrap(Slot.unwrap(_a) * SLOT_DURATION);
}

function slotFromTimestamp(Timestamp _a) internal view returns (Slot) {
return Slot.wrap(Timestamp.unwrap(_a) / SLOT_DURATION);
}

function positionInEpoch(Slot _a) internal view returns (uint256) {
return Slot.unwrap(_a) % EPOCH_DURATION;
}

function toSlots(Epoch _a) internal view returns (Slot) {
return Slot.wrap(Epoch.unwrap(_a) * EPOCH_DURATION);
}

function toTimestamp(Epoch _a) internal view returns (Timestamp) {
return toTimestamp(toSlots(_a));
}

function epochFromTimestamp(Timestamp _a) internal view returns (Epoch) {
return Epoch.wrap(Timestamp.unwrap(_a) / (EPOCH_DURATION * SLOT_DURATION));
}
}

library SlotLib {
function unwrap(Slot _a) internal pure returns (uint256) {
return Slot.unwrap(_a);
Expand Down
Loading