Skip to content
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
64 changes: 32 additions & 32 deletions l1-contracts/gas_report.md

Large diffs are not rendered by default.

283 changes: 140 additions & 143 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,119 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
)
{}

/**
* @notice Validate a header for submission
*
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header
* without having to deal with viem or anvil for simulating timestamps in the future.
*
* @param _header - The header to validate
* @param _signatures - The signatures to validate
* @param _digest - The digest to validate
* @param _currentTime - The current time
* @param _blobsHash - The blobs hash for this block
* @param _flags - The flags to validate
*/
function validateHeader(
bytes calldata _header,
Signature[] memory _signatures,
bytes32 _digest,
Timestamp _currentTime,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external override(IRollup) {
ProposeLib.validateHeader(
ValidateHeaderArgs({
header: HeaderLib.decode(_header),
attestations: _signatures,
digest: _digest,
currentTime: _currentTime,
manaBaseFee: getManaBaseFeeAt(_currentTime, true),
blobsHashesCommitment: _blobsHash,
flags: _flags
})
);
}

/**
* @notice Get the validator set for the current epoch
* @return The validator set for the current epoch
*/
function getCurrentEpochCommittee()
external
override(IValidatorSelection)
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getCurrentEpoch());
}

/**
* @notice Get the committee for a given timestamp
*
* @param _ts - The timestamp to get the committee for
*
* @return The committee for the given timestamp
*/
function getCommitteeAt(Timestamp _ts)
external
override(IValidatorSelection)
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getEpochAt(_ts));
}

/**
* @notice Get the proposer for the current slot
*
* @dev Calls `getCurrentProposer(uint256)` with the current timestamp
*
* @return The address of the proposer
*/
function getCurrentProposer() external override(IValidatorSelection) returns (address) {
return getProposerAt(Timestamp.wrap(block.timestamp));
}

/**
* @notice Check if msg.sender can propose at a given time
*
* @param _ts - The timestamp to check
* @param _archive - The archive to check (should be the latest archive)
*
* @return uint256 - The slot at the given timestamp
* @return uint256 - The block number at the given timestamp
*/
function canProposeAtTime(Timestamp _ts, bytes32 _archive)
external
override(IRollup)
returns (Slot, uint256)
{
Slot slot = _ts.slotFromTimestamp();
RollupStore storage rollupStore = STFLib.getStorage();

uint256 pendingBlockNumber = STFLib.getEffectivePendingBlockNumber(_ts);

Slot lastSlot = rollupStore.blocks[pendingBlockNumber].slotNumber;

require(slot > lastSlot, Errors.Rollup__SlotAlreadyInChain(lastSlot, slot));

// Make sure that the proposer is up to date and on the right chain (ie no reorgs)
bytes32 tipArchive = rollupStore.blocks[pendingBlockNumber].archive;
require(tipArchive == _archive, Errors.Rollup__InvalidArchive(tipArchive, _archive));

Signature[] memory sigs = new Signature[](0);

ValidatorSelectionLib.verify(
StakingLib.getStorage(),
slot,
slot.epochFromSlot(),
sigs,
_archive,
BlockHeaderValidationFlags({ignoreDA: true, ignoreSignatures: true})
);

return (slot, pendingBlockNumber + 1);
}

function getTargetCommitteeSize() external view override(IValidatorSelection) returns (uint256) {
return ValidatorSelectionLib.getStorage().targetCommitteeSize;
}
Expand Down Expand Up @@ -180,40 +293,6 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
);
}

/**
* @notice Validate a header for submission
*
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header
* without having to deal with viem or anvil for simulating timestamps in the future.
*
* @param _header - The header to validate
* @param _signatures - The signatures to validate
* @param _digest - The digest to validate
* @param _currentTime - The current time
* @param _blobsHash - The blobs hash for this block
* @param _flags - The flags to validate
*/
function validateHeader(
bytes calldata _header,
Signature[] memory _signatures,
bytes32 _digest,
Timestamp _currentTime,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external view override(IRollup) {
ProposeLib.validateHeader(
ValidateHeaderArgs({
header: HeaderLib.decode(_header),
attestations: _signatures,
digest: _digest,
currentTime: _currentTime,
manaBaseFee: getManaBaseFeeAt(_currentTime, true),
blobsHashesCommitment: _blobsHash,
flags: _flags
})
);
}

/**
* @notice Validate blob transactions against given inputs.
* @dev Only exists here for gas estimation.
Expand Down Expand Up @@ -331,35 +410,6 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
return ValidatorSelectionLib.getStorage().epochs[_epoch].committee;
}

/**
* @notice Get the validator set for the current epoch
* @return The validator set for the current epoch
*/
function getCurrentEpochCommittee()
external
view
override(IValidatorSelection)
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getCurrentEpoch());
}

/**
* @notice Get the committee for a given timestamp
*
* @param _ts - The timestamp to get the committee for
*
* @return The committee for the given timestamp
*/
function getCommitteeAt(Timestamp _ts)
external
view
override(IValidatorSelection)
returns (address[] memory)
{
return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getEpochAt(_ts));
}

/**
* @notice Get the sample seed for a given timestamp
*
Expand Down Expand Up @@ -421,17 +471,6 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
return _slotNumber.toTimestamp();
}

/**
* @notice Get the proposer for the current slot
*
* @dev Calls `getCurrentProposer(uint256)` with the current timestamp
*
* @return The address of the proposer
*/
function getCurrentProposer() external view override(IValidatorSelection) returns (address) {
return getProposerAt(Timestamp.wrap(block.timestamp));
}

/**
* @notice Computes the slot at a specific time
*
Expand Down Expand Up @@ -558,48 +597,6 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
return STFLib.getStorage().config.rewardDistributor;
}

/**
* @notice Check if msg.sender can propose at a given time
*
* @param _ts - The timestamp to check
* @param _archive - The archive to check (should be the latest archive)
*
* @return uint256 - The slot at the given timestamp
* @return uint256 - The block number at the given timestamp
*/
function canProposeAtTime(Timestamp _ts, bytes32 _archive)
external
view
override(IRollup)
returns (Slot, uint256)
{
Slot slot = _ts.slotFromTimestamp();
RollupStore storage rollupStore = STFLib.getStorage();

uint256 pendingBlockNumber = STFLib.getEffectivePendingBlockNumber(_ts);

Slot lastSlot = rollupStore.blocks[pendingBlockNumber].slotNumber;

require(slot > lastSlot, Errors.Rollup__SlotAlreadyInChain(lastSlot, slot));

// Make sure that the proposer is up to date and on the right chain (ie no reorgs)
bytes32 tipArchive = rollupStore.blocks[pendingBlockNumber].archive;
require(tipArchive == _archive, Errors.Rollup__InvalidArchive(tipArchive, _archive));

Signature[] memory sigs = new Signature[](0);

ValidatorSelectionLib.verify(
StakingLib.getStorage(),
slot,
slot.epochFromSlot(),
sigs,
_archive,
BlockHeaderValidationFlags({ignoreDA: true, ignoreSignatures: true})
);

return (slot, pendingBlockNumber + 1);
}

function getL1FeesAt(Timestamp _timestamp)
external
view
Expand All @@ -617,6 +614,33 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
return EpochProofLib.BURN_ADDRESS;
}

/**
* @notice Get the proposer for the slot at a specific timestamp
*
* @dev This function is very useful for off-chain usage, as it easily allow a client to
* determine who will be the proposer at the NEXT ethereum block.
* Should not be trusted when moving beyond the current epoch, since changes to the
* validator set might not be reflected when we actually reach that epoch (more changes
* might have happened).
*
* @dev The proposer is selected from the validator set of the current epoch.
*
* @dev Should only be access on-chain if epoch is setup, otherwise very expensive.
*
* @dev A return value of address(0) means that the proposer is "open" and can be anyone.
*
* @dev If the current epoch is the first epoch, returns address(0)
* If the current epoch is setup, we will return the proposer for the current slot
* If the current epoch is not setup, we will perform a sample as if it was (gas heavy)
*
* @return The address of the proposer
*/
function getProposerAt(Timestamp _ts) public override(IValidatorSelection) returns (address) {
Slot slot = _ts.slotFromTimestamp();
Epoch epochNumber = slot.epochFromSlot();
return ValidatorSelectionLib.getProposerAt(StakingLib.getStorage(), slot, epochNumber);
}

/**
* @notice Gets the mana base fee
*
Expand Down Expand Up @@ -688,31 +712,4 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
function getCurrentEpoch() public view override(IValidatorSelection) returns (Epoch) {
return Timestamp.wrap(block.timestamp).epochFromTimestamp();
}

/**
* @notice Get the proposer for the slot at a specific timestamp
*
* @dev This function is very useful for off-chain usage, as it easily allow a client to
* determine who will be the proposer at the NEXT ethereum block.
* Should not be trusted when moving beyond the current epoch, since changes to the
* validator set might not be reflected when we actually reach that epoch (more changes
* might have happened).
*
* @dev The proposer is selected from the validator set of the current epoch.
*
* @dev Should only be access on-chain if epoch is setup, otherwise very expensive.
*
* @dev A return value of address(0) means that the proposer is "open" and can be anyone.
*
* @dev If the current epoch is the first epoch, returns address(0)
* If the current epoch is setup, we will return the proposer for the current slot
* If the current epoch is not setup, we will perform a sample as if it was (gas heavy)
*
* @return The address of the proposer
*/
function getProposerAt(Timestamp _ts) public view override(IValidatorSelection) returns (address) {
Slot slot = _ts.slotFromTimestamp();
Epoch epochNumber = slot.epochFromSlot();
return ValidatorSelectionLib.getProposerAt(StakingLib.getStorage(), slot, epochNumber);
}
}
22 changes: 11 additions & 11 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ interface IRollupCore {
}

interface IRollup is IRollupCore {
function validateHeader(
bytes calldata _header,
Signature[] memory _signatures,
bytes32 _digest,
Timestamp _currentTime,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external;

function canProposeAtTime(Timestamp _ts, bytes32 _archive) external returns (Slot, uint256);

function getTips() external view returns (ChainTips memory);

function status(uint256 _myHeaderBlockNumber)
Expand All @@ -181,17 +192,6 @@ interface IRollup is IRollupCore {
bytes calldata _aggregationObject
) external view returns (bytes32[] memory);

function validateHeader(
bytes calldata _header,
Signature[] memory _signatures,
bytes32 _digest,
Timestamp _currentTime,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external view;

function canProposeAtTime(Timestamp _ts, bytes32 _archive) external view returns (Slot, uint256);

function validateBlobs(bytes calldata _blobsInputs)
external
view
Expand Down
10 changes: 6 additions & 4 deletions l1-contracts/src/core/interfaces/IValidatorSelection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ interface IValidatorSelectionCore {

interface IValidatorSelection is IValidatorSelectionCore {
// Likely changing to optimize in Pleistarchus
function getCurrentProposer() external view returns (address);
function getProposerAt(Timestamp _ts) external view returns (address);
function getCurrentProposer() external returns (address);
function getProposerAt(Timestamp _ts) external returns (address);

// Non view as uses transient storage
function getCurrentEpochCommittee() external returns (address[] memory);
function getCommitteeAt(Timestamp _ts) external returns (address[] memory);

// Stable
function getCurrentEpoch() external view returns (Epoch);
Expand All @@ -42,8 +46,6 @@ interface IValidatorSelection is IValidatorSelectionCore {

// Likely removal of these to replace with a size and indiviual getter
// Get the current epoch committee
function getCurrentEpochCommittee() external view returns (address[] memory);
function getCommitteeAt(Timestamp _ts) external view returns (address[] memory);
function getEpochCommittee(Epoch _epoch) external view returns (address[] memory);
function getAttesters() external view returns (address[] memory);

Expand Down
1 change: 1 addition & 0 deletions l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ library Errors {

// SampleLib
error SampleLib__IndexOutOfBounds(uint256 requested, uint256 bound); // 0xa12fc559
error SampleLib__SampleLargerThanIndex(uint256 sample, uint256 index); // 0xa11b0f79

// Sequencer Selection (ValidatorSelection)
error ValidatorSelection__EpochNotSetup(); // 0x10816cae
Expand Down
Loading