Skip to content

Commit

Permalink
chore: Move epoch and slot durations to config
Browse files Browse the repository at this point in the history
De-enshrines the following constants and turns them into config:

```
ETHEREUM_SLOT_DURATION = 12;
AZTEC_SLOT_DURATION = 24;
AZTEC_EPOCH_DURATION = 16;
AZTEC_TARGET_COMMITTEE_SIZE = 48;
AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS = 13;
```

These can now be set via env vars. On L1, they are set as immutable
variables across all contracts that require them. As for circuits, none
of them was needed, except for the epoch duration to be able to
dimension the fees array. This was handled by introducing a new
MAX_EPOCH_DURATION constant (32) which sets the max length of the array.

This is a prerequisite to #9809
  • Loading branch information
spalladino committed Nov 8, 2024
1 parent 23c122d commit eca6507
Show file tree
Hide file tree
Showing 68 changed files with 664 additions and 429 deletions.
43 changes: 18 additions & 25 deletions l1-contracts/src/core/Leonidas.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
pragma solidity >=0.8.27;

import {ILeonidas} from "@aztec/core/interfaces/ILeonidas.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {SampleLib} from "@aztec/core/libraries/crypto/SampleLib.sol";
import {SignatureLib} 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} from "@aztec/core/libraries/TimeMath.sol";
import {
Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeFns
} from "@aztec/core/libraries/TimeMath.sol";
import {Ownable} from "@oz/access/Ownable.sol";
import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol";
import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
Expand All @@ -27,7 +28,7 @@ import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol";
* It will be the duty of his successor (Pleistarchus) to optimize the costs with same functionality.
*
*/
contract Leonidas is Ownable, ILeonidas {
contract Leonidas is Ownable, TimeFns, ILeonidas {
using EnumerableSet for EnumerableSet.AddressSet;
using SignatureLib for SignatureLib.Signature;
using MessageHashUtils for bytes32;
Expand All @@ -47,25 +48,9 @@ contract Leonidas is Ownable, ILeonidas {
uint256 nextSeed;
}

// @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 constant SLOT_DURATION = Constants.AZTEC_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 constant EPOCH_DURATION = Constants.AZTEC_EPOCH_DURATION;

// The target number of validators in a committee
// @todo #8021
uint256 public constant TARGET_COMMITTEE_SIZE = Constants.AZTEC_TARGET_COMMITTEE_SIZE;
uint256 public immutable TARGET_COMMITTEE_SIZE;

// The time that the contract was deployed
Timestamp public immutable GENESIS_TIME;
Expand All @@ -79,8 +64,16 @@ contract Leonidas is Ownable, ILeonidas {
// The last stored randao value, same value as `seed` in the last inserted epoch
uint256 private lastSeed;

constructor(address _ares) Ownable(_ares) {
constructor(
address _ares,
uint256 _slotDuration,
uint256 _epochDuration,
uint256 _targetCommitteeSize
) Ownable(_ares) TimeFns(_slotDuration, _epochDuration) {
GENESIS_TIME = Timestamp.wrap(block.timestamp);
SLOT_DURATION = _slotDuration;
EPOCH_DURATION = _epochDuration;
TARGET_COMMITTEE_SIZE = _targetCommitteeSize;
}

/**
Expand Down Expand Up @@ -232,7 +225,7 @@ contract Leonidas is Ownable, ILeonidas {
override(ILeonidas)
returns (Timestamp)
{
return GENESIS_TIME + _slotNumber.toTimestamp();
return GENESIS_TIME + toTimestamp(_slotNumber);
}

/**
Expand Down Expand Up @@ -303,7 +296,7 @@ contract Leonidas is Ownable, ILeonidas {
* @return The computed epoch
*/
function getEpochAt(Timestamp _ts) public view override(ILeonidas) returns (Epoch) {
return _ts < GENESIS_TIME ? Epoch.wrap(0) : EpochLib.fromTimestamp(_ts - GENESIS_TIME);
return _ts < GENESIS_TIME ? Epoch.wrap(0) : epochFromTimestamp(_ts - GENESIS_TIME);
}

/**
Expand All @@ -314,7 +307,7 @@ contract Leonidas is Ownable, ILeonidas {
* @return The computed slot
*/
function getSlotAt(Timestamp _ts) public view override(ILeonidas) returns (Slot) {
return _ts < GENESIS_TIME ? Slot.wrap(0) : SlotLib.fromTimestamp(_ts - GENESIS_TIME);
return _ts < GENESIS_TIME ? Slot.wrap(0) : slotFromTimestamp(_ts - GENESIS_TIME);
}

/**
Expand All @@ -324,7 +317,7 @@ contract Leonidas is Ownable, ILeonidas {
*
* @return The computed epoch
*/
function getEpochAtSlot(Slot _slotNumber) public pure override(ILeonidas) returns (Epoch) {
function getEpochAtSlot(Slot _slotNumber) public view override(ILeonidas) returns (Epoch) {
return Epoch.wrap(_slotNumber.unwrap() / EPOCH_DURATION);
}

Expand Down
12 changes: 8 additions & 4 deletions l1-contracts/src/core/ProofCommitmentEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
pragma solidity >=0.8.27;

import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {Timestamp} from "@aztec/core/libraries/TimeMath.sol";
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
Expand All @@ -17,8 +16,7 @@ contract ProofCommitmentEscrow is IProofCommitmentEscrow {
Timestamp executableAt;
}

uint256 public constant WITHDRAW_DELAY =
Constants.ETHEREUM_SLOT_DURATION * Constants.AZTEC_EPOCH_DURATION * 3;
uint256 public immutable WITHDRAW_DELAY;

address public immutable ROLLUP;
IERC20 public immutable TOKEN;
Expand All @@ -31,9 +29,15 @@ contract ProofCommitmentEscrow is IProofCommitmentEscrow {
_;
}

constructor(IERC20 _token, address _rollup) {
constructor(
IERC20 _token,
address _rollup,
uint256 _aztecSlotDuration,
uint256 _aztecEpochDuration
) {
ROLLUP = _rollup;
TOKEN = _token;
WITHDRAW_DELAY = _aztecSlotDuration * _aztecEpochDuration;
}

/**
Expand Down
40 changes: 29 additions & 11 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,18 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
Slot slotNumber;
}

struct Config {
uint256 aztecSlotDuration;
uint256 aztecEpochDuration;
uint256 targetCommitteeSize;
uint256 aztecEpochProofClaimWindowInL2Slots;
}

// See https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8401-proof-timeliness/proof-timeliness.ipynb
// for justification of CLAIM_DURATION_IN_L2_SLOTS.
uint256 public constant CLAIM_DURATION_IN_L2_SLOTS =
Constants.AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS;
uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000;

uint256 public immutable CLAIM_DURATION_IN_L2_SLOTS;
uint256 public immutable L1_BLOCK_AT_GENESIS;
IInbox public immutable INBOX;
IOutbox public immutable OUTBOX;
Expand All @@ -66,6 +72,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
IFeeJuicePortal public immutable FEE_JUICE_PORTAL;
IRewardDistributor public immutable REWARD_DISTRIBUTOR;
IERC20 public immutable ASSET;

IVerifier public epochProofVerifier;

ChainTips public tips;
Expand All @@ -91,19 +98,30 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
bytes32 _vkTreeRoot,
bytes32 _protocolContractTreeRoot,
address _ares,
address[] memory _validators
) Leonidas(_ares) {
address[] memory _validators,
Config memory _config
)
Leonidas(
_ares,
_config.aztecSlotDuration,
_config.aztecEpochDuration,
_config.targetCommitteeSize
)
{
epochProofVerifier = new MockVerifier();
FEE_JUICE_PORTAL = _fpcJuicePortal;
REWARD_DISTRIBUTOR = _rewardDistributor;
ASSET = _fpcJuicePortal.UNDERLYING();
PROOF_COMMITMENT_ESCROW = new ProofCommitmentEscrow(ASSET, address(this));
PROOF_COMMITMENT_ESCROW = new ProofCommitmentEscrow(
ASSET, address(this), _config.aztecSlotDuration, _config.aztecEpochDuration
);
INBOX = IInbox(address(new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT)));
OUTBOX = IOutbox(address(new Outbox(address(this))));
vkTreeRoot = _vkTreeRoot;
protocolContractTreeRoot = _protocolContractTreeRoot;
VERSION = 1;
L1_BLOCK_AT_GENESIS = block.number;
CLAIM_DURATION_IN_L2_SLOTS = _config.aztecEpochProofClaimWindowInL2Slots;

// Genesis block
blocks[0] = BlockLog({
Expand Down Expand Up @@ -641,7 +659,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
// out_hash: root of this epoch's l2 to l1 message tree
publicInputs[8] = _args[5];

uint256 feesLength = Constants.AZTEC_EPOCH_DURATION * 2;
uint256 feesLength = Constants.AZTEC_MAX_EPOCH_DURATION * 2;
// fees[9 to (9+feesLength-1)]: array of recipient-value pairs
for (uint256 i = 0; i < feesLength; i++) {
publicInputs[9 + i] = _fees[i];
Expand Down Expand Up @@ -703,8 +721,8 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {
);

require(
currentSlot.positionInEpoch() < CLAIM_DURATION_IN_L2_SLOTS,
Errors.Rollup__NotInClaimPhase(currentSlot.positionInEpoch(), CLAIM_DURATION_IN_L2_SLOTS)
positionInEpoch(currentSlot) < CLAIM_DURATION_IN_L2_SLOTS,
Errors.Rollup__NotInClaimPhase(positionInEpoch(currentSlot), CLAIM_DURATION_IN_L2_SLOTS)
);

// if the epoch to prove is not the one that has been claimed,
Expand Down Expand Up @@ -795,16 +813,16 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Leonidas, IRollup, ITestRollup {

Slot currentSlot = getSlotAt(_ts);
Epoch oldestPendingEpoch = getEpochForBlock(tips.provenBlockNumber + 1);
Slot startSlotOfPendingEpoch = oldestPendingEpoch.toSlots();
Slot startSlotOfPendingEpoch = 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 + Epoch.wrap(1).toSlots() + Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS);
< startSlotOfPendingEpoch + toSlots(Epoch.wrap(1)) + Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS);

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

if (inClaimPhase || claimExists) {
Expand Down
12 changes: 4 additions & 8 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GENERATED FILE - DO NOT EDIT, RUN yarn remake-constants in circuits.js
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Aztec Labs.
// Copyright 2023 Aztec Labs.
pragma solidity >=0.8.27;

/**
Expand Down Expand Up @@ -94,11 +94,7 @@ library Constants {
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
uint256 internal constant PRIVATE_LOG_SIZE_IN_BYTES = 576;
uint256 internal constant BLOB_SIZE_IN_BYTES = 126976;
uint256 internal constant ETHEREUM_SLOT_DURATION = 12;
uint256 internal constant AZTEC_SLOT_DURATION = 24;
uint256 internal constant AZTEC_EPOCH_DURATION = 16;
uint256 internal constant AZTEC_TARGET_COMMITTEE_SIZE = 48;
uint256 internal constant AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS = 13;
uint256 internal constant AZTEC_MAX_EPOCH_DURATION = 32;
uint256 internal constant GENESIS_ARCHIVE_ROOT =
19007378675971183768036762391356802220352606103602592933942074152320327194720;
uint256 internal constant FEE_JUICE_INITIAL_MINT = 20000000000;
Expand Down Expand Up @@ -235,8 +231,8 @@ library Constants {
uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 601;
uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13;
uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 30;
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 60;
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 44;
uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 90;
uint256 internal constant ROOT_ROLLUP_PUBLIC_INPUTS_LENGTH = 76;
uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674;
uint256 internal constant NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048;
uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048;
Expand Down
61 changes: 40 additions & 21 deletions l1-contracts/src/core/libraries/TimeMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,66 @@
// Copyright 2024 Aztec Labs.
pragma solidity >=0.8.27;

import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";

type Timestamp is uint256;

type Slot is uint256;

type Epoch is uint256;

library SlotLib {
function toTimestamp(Slot _a) internal pure returns (Timestamp) {
return Timestamp.wrap(Slot.unwrap(_a) * Constants.AZTEC_SLOT_DURATION);
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 fromTimestamp(Timestamp _a) internal pure returns (Slot) {
return Slot.wrap(Timestamp.unwrap(_a) / Constants.AZTEC_SLOT_DURATION);
function toTimestamp(Slot _a) internal view returns (Timestamp) {
return Timestamp.wrap(Slot.unwrap(_a) * SLOT_DURATION);
}

function positionInEpoch(Slot _a) internal pure returns (uint256) {
return Slot.unwrap(_a) % Constants.AZTEC_EPOCH_DURATION;
function slotFromTimestamp(Timestamp _a) internal view returns (Slot) {
return Slot.wrap(Timestamp.unwrap(_a) / SLOT_DURATION);
}

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

library EpochLib {
function toSlots(Epoch _a) internal pure returns (Slot) {
return Slot.wrap(Epoch.unwrap(_a) * Constants.AZTEC_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 toTimestamp(Epoch _a) internal pure returns (Timestamp) {
return SlotLib.toTimestamp(toSlots(_a));
function epochFromTimestamp(Timestamp _a) internal view returns (Epoch) {
return Epoch.wrap(Timestamp.unwrap(_a) / (EPOCH_DURATION * SLOT_DURATION));
}
}

function fromTimestamp(Timestamp _a) internal pure returns (Epoch) {
return Epoch.wrap(
Timestamp.unwrap(_a) / (Constants.AZTEC_EPOCH_DURATION * Constants.AZTEC_SLOT_DURATION)
);
library SlotLib {
function unwrap(Slot _a) internal pure returns (uint256) {
return Slot.unwrap(_a);
}
}

library EpochLib {
function unwrap(Epoch _a) internal pure returns (uint256) {
return Epoch.unwrap(_a);
}
Expand Down
Loading

0 comments on commit eca6507

Please sign in to comment.