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
35 changes: 11 additions & 24 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,25 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
* @param _blobsHash - The blobs hash for this block
* @param _flags - The flags to validate
*/
function validateHeader(
function validateHeaderWithAttestations(
ProposedHeader calldata _header,
CommitteeAttestations memory _attestations,
address[] calldata _signers,
bytes32 _digest,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external override(IRollup) {
Timestamp currentTime = Timestamp.wrap(block.timestamp);
ExtRollupLib.validateHeader(
ExtRollupLib.validateHeaderWithAttestations(
ValidateHeaderArgs({
header: _header,
attestations: _attestations,
digest: _digest,
manaBaseFee: getManaBaseFeeAt(currentTime, true),
blobsHashesCommitment: _blobsHash,
flags: _flags
})
}),
_attestations,
_signers
);
}

Expand Down Expand Up @@ -181,34 +183,17 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
*
* @param _ts - The timestamp to check
* @param _archive - The archive to check (should be the latest archive)
* @param _who - The address to check
*
* @return uint256 - The slot at the given timestamp
* @return uint256 - The block number at the given timestamp
*/
function canProposeAtTime(Timestamp _ts, bytes32 _archive)
function canProposeAtTime(Timestamp _ts, bytes32 _archive, address _who)
external
override(IRollup)
returns (Slot, uint256)
{
Slot slot = _ts.slotFromTimestamp();
RollupStore storage rollupStore = STFLib.getStorage();

uint256 pendingBlockNumber = STFLib.getEffectivePendingBlockNumber(_ts);

Slot lastSlot = STFLib.getSlotNumber(pendingBlockNumber);

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.archives[pendingBlockNumber];
require(tipArchive == _archive, Errors.Rollup__InvalidArchive(tipArchive, _archive));

address proposer = ExtRollupLib2.getProposerAt(slot);
require(
proposer == msg.sender, Errors.ValidatorSelection__InvalidProposer(proposer, msg.sender)
);

return (slot, pendingBlockNumber + 1);
return ExtRollupLib2.canProposeAtTime(_ts, _archive, _who);
}

function getTargetCommitteeSize() external view override(IValidatorSelection) returns (uint256) {
Expand Down Expand Up @@ -365,6 +350,8 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
archive: rollupStore.archives[_blockNumber],
headerHash: tempBlockLog.headerHash,
blobCommitmentsHash: tempBlockLog.blobCommitmentsHash,
attestationsHash: tempBlockLog.attestationsHash,
payloadDigest: tempBlockLog.payloadDigest,
slotNumber: tempBlockLog.slotNumber,
feeHeader: tempBlockLog.feeHeader
});
Expand Down
32 changes: 25 additions & 7 deletions l1-contracts/src/core/RollupCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {CommitteeAttestations} from "@aztec/shared/libraries/SignatureLib.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {ExtRollupLib} from "@aztec/core/libraries/rollup/ExtRollupLib.sol";
import {ExtRollupLib2} from "@aztec/core/libraries/rollup/ExtRollupLib2.sol";
import {ExtRollupLib3} from "@aztec/core/libraries/rollup/ExtRollupLib3.sol";
import {EthValue, FeeLib} from "@aztec/core/libraries/rollup/FeeLib.sol";
import {ProposeArgs} from "@aztec/core/libraries/rollup/ProposeLib.sol";
import {STFLib, GenesisState} from "@aztec/core/libraries/rollup/STFLib.sol";
Expand Down Expand Up @@ -86,7 +87,7 @@ contract RollupCore is
);

Timestamp exitDelay = Timestamp.wrap(_config.exitDelaySeconds);
ISlasher slasher = ExtRollupLib2.deploySlasher(
ISlasher slasher = ExtRollupLib3.deploySlasher(
_config.slashingQuorum,
_config.slashingRoundSize,
_config.slashingLifetimeInRounds,
Expand All @@ -101,7 +102,7 @@ contract RollupCore is

// If no booster specifically provided deploy one.
if (address(_config.rewardConfig.booster) == address(0)) {
_config.rewardConfig.booster = ExtRollupLib2.deployRewardBooster(_config.rewardBoostConfig);
_config.rewardConfig.booster = ExtRollupLib3.deployRewardBooster(_config.rewardBoostConfig);
}

RewardLib.setConfig(_config.rewardConfig);
Expand Down Expand Up @@ -223,16 +224,15 @@ contract RollupCore is
}

function finaliseWithdraw(address _attester) external override(IStakingCore) {
StakingLib.finaliseWithdraw(_attester);
ExtRollupLib2.finaliseWithdraw(_attester);
}

function slash(address _attester, uint256 _amount) external override(IStakingCore) returns (bool) {
return StakingLib.trySlash(_attester, _amount);
return ExtRollupLib2.slash(_attester, _amount);
}

function prune() external override(IRollupCore) {
require(STFLib.canPruneAtTime(Timestamp.wrap(block.timestamp)), Errors.Rollup__NothingToPrune());
STFLib.prune();
ExtRollupLib.prune();
}

function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args)
Expand All @@ -245,9 +245,27 @@ contract RollupCore is
function propose(
ProposeArgs calldata _args,
CommitteeAttestations memory _attestations,
address[] calldata _signers,
bytes calldata _blobInput
) external override(IRollupCore) {
ExtRollupLib.propose(_args, _attestations, _blobInput, checkBlob);
ExtRollupLib.propose(_args, _attestations, _signers, _blobInput, checkBlob);
}

function invalidateBadAttestation(
uint256 _blockNumber,
CommitteeAttestations memory _attestations,
address[] memory _committee,
uint256 _invalidIndex
) external override(IRollupCore) {
ExtRollupLib2.invalidateBadAttestation(_blockNumber, _attestations, _committee, _invalidIndex);
}

function invalidateInsufficientAttestations(
uint256 _blockNumber,
CommitteeAttestations memory _attestations,
address[] memory _committee
) external override(IRollupCore) {
ExtRollupLib2.invalidateInsufficientAttestations(_blockNumber, _attestations, _committee);
}

function setupEpoch() public override(IValidatorSelectionCore) {
Expand Down
25 changes: 21 additions & 4 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,17 @@ struct SubmitEpochRootProofArgs {
uint256 end; // inclusive
PublicInputArgs args;
bytes32[] fees;
CommitteeAttestations attestations; // attestations for the last block in epoch
bytes blobInputs;
bytes proof;
}

/**
* @notice Struct for storing flags for block header validation
* @param ignoreDA - True will ignore DA check, otherwise checks
* @param ignoreSignature - True will ignore the signatures, otherwise checks
*/
struct BlockHeaderValidationFlags {
bool ignoreDA;
bool ignoreSignatures;
}

struct GenesisState {
Expand Down Expand Up @@ -98,6 +97,7 @@ interface IRollupCore {
uint256 indexed blockNumber, bytes32 indexed archive, bytes32[] versionedBlobHashes
);
event L2ProofVerified(uint256 indexed blockNumber, address indexed proverId);
event BlockInvalidated(uint256 indexed blockNumber);
event RewardConfigUpdated(RewardConfig rewardConfig);
event ManaTargetUpdated(uint256 indexed manaTarget);
event PrunedPending(uint256 provenBlockNumber, uint256 pendingBlockNumber);
Expand All @@ -119,11 +119,25 @@ interface IRollupCore {
function propose(
ProposeArgs calldata _args,
CommitteeAttestations memory _attestations,
address[] memory _signers,
bytes calldata _blobInput
) external;

function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external;

function invalidateBadAttestation(
uint256 _blockNumber,
CommitteeAttestations memory _attestations,
address[] memory _committee,
uint256 _invalidIndex
) external;

function invalidateInsufficientAttestations(
uint256 _blockNumber,
CommitteeAttestations memory _attestations,
address[] memory _committee
) external;

function setRewardConfig(RewardConfig memory _config) external;
function updateManaTarget(uint256 _manaTarget) external;

Expand All @@ -132,15 +146,18 @@ interface IRollupCore {
}

interface IRollup is IRollupCore, IHaveVersion {
function validateHeader(
function validateHeaderWithAttestations(
ProposedHeader calldata _header,
CommitteeAttestations memory _attestations,
address[] memory _signers,
bytes32 _digest,
bytes32 _blobsHash,
BlockHeaderValidationFlags memory _flags
) external;

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

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

Expand Down
6 changes: 6 additions & 0 deletions l1-contracts/src/core/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ library Errors {
error Rollup__InvalidProof(); // 0xa5b2ba17
error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73
error Rollup__InvalidTimestamp(Timestamp expected, Timestamp actual); // 0x3132e895
error Rollup__InvalidAttestations();
error Rollup__AttestationsAreValid();
error Rollup__BlockAlreadyProven();
error Rollup__BlockNotInPendingChain();
error Rollup__InvalidBlobHash(bytes32 expected, bytes32 actual); // 0x13031e6a
error Rollup__InvalidBlobProof(bytes32 blobHash); // 0x5ca17bef
error Rollup__NoEpochToProve(); // 0xcbaa3951
Expand Down Expand Up @@ -98,10 +102,12 @@ library Errors {
// Sequencer Selection (ValidatorSelection)
error ValidatorSelection__EpochNotSetup(); // 0x10816cae
error ValidatorSelection__InvalidProposer(address expected, address actual); // 0xa8843a68
error ValidatorSelection__MissingProposerSignature(address proposer, uint256 index);
error ValidatorSelection__InvalidDeposit(address attester, address proposer); // 0x533169bd
error ValidatorSelection__InsufficientAttestations(uint256 minimumNeeded, uint256 provided); // 0xaf47297f
error ValidatorSelection__InvalidCommitteeCommitment(bytes32 reconstructed, bytes32 expected); // 0xca8d5954
error ValidatorSelection__InsufficientCommitteeSize(uint256 actual, uint256 expected); // 0x98673597
error ValidatorSelection__ProposerIndexTooLarge(uint256 index);

// Staking
error Staking__AlreadyQueued(address _attester);
Expand Down
12 changes: 12 additions & 0 deletions l1-contracts/src/core/libraries/compressed-data/BlockLog.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@ import {Slot} from "@aztec/shared/libraries/TimeMath.sol";
* @param archive - Archive tree root of the block
* @param headerHash - Hash of the proposed block header
* @param blobCommitmentsHash - H(...H(H(commitment_0), commitment_1).... commitment_n) - used to validate we are using the same blob commitments on L1 and in the rollup circuit
* @param attestationsHash - Hash of the attestations for this block
* @param payloadDigest - Digest of the proposal payload that was attested to
* @param slotNumber - This block's slot
*/
struct BlockLog {
bytes32 archive;
bytes32 headerHash;
bytes32 blobCommitmentsHash;
bytes32 attestationsHash;
bytes32 payloadDigest;
Slot slotNumber;
FeeHeader feeHeader;
}

struct TempBlockLog {
bytes32 headerHash;
bytes32 blobCommitmentsHash;
bytes32 attestationsHash;
bytes32 payloadDigest;
Slot slotNumber;
FeeHeader feeHeader;
}

struct CompressedTempBlockLog {
bytes32 headerHash;
bytes32 blobCommitmentsHash;
bytes32 attestationsHash;
bytes32 payloadDigest;
CompressedSlot slotNumber;
CompressedFeeHeader feeHeader;
}
Expand All @@ -53,6 +61,8 @@ library CompressedTempBlockLogLib {
return CompressedTempBlockLog({
headerHash: _blockLog.headerHash,
blobCommitmentsHash: _blockLog.blobCommitmentsHash,
attestationsHash: _blockLog.attestationsHash,
payloadDigest: _blockLog.payloadDigest,
slotNumber: _blockLog.slotNumber.compress(),
feeHeader: _blockLog.feeHeader.compress()
});
Expand All @@ -66,6 +76,8 @@ library CompressedTempBlockLogLib {
return TempBlockLog({
headerHash: _compressedBlockLog.headerHash,
blobCommitmentsHash: _compressedBlockLog.blobCommitmentsHash,
attestationsHash: _compressedBlockLog.attestationsHash,
payloadDigest: _compressedBlockLog.payloadDigest,
slotNumber: _compressedBlockLog.slotNumber.decompress(),
feeHeader: _compressedBlockLog.feeHeader.decompress()
});
Expand Down
34 changes: 34 additions & 0 deletions l1-contracts/src/core/libraries/rollup/EpochProofLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import {
IRollupCore,
RollupStore
} from "@aztec/core/interfaces/IRollup.sol";
import {CompressedTempBlockLog} from "@aztec/core/libraries/compressed-data/BlockLog.sol";
import {ChainTipsLib, CompressedChainTips} from "@aztec/core/libraries/compressed-data/Tips.sol";
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
import {Errors} from "@aztec/core/libraries/Errors.sol";
import {BlobLib} from "@aztec/core/libraries/rollup/BlobLib.sol";
import {CompressedFeeHeader, FeeHeaderLib} from "@aztec/core/libraries/rollup/FeeLib.sol";
import {RewardLib} from "@aztec/core/libraries/rollup/RewardLib.sol";
import {STFLib} from "@aztec/core/libraries/rollup/STFLib.sol";
import {ValidatorSelectionLib} from "@aztec/core/libraries/rollup/ValidatorSelectionLib.sol";
import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
import {CompressedSlot, CompressedTimeMath} from "@aztec/shared/libraries/CompressedTimeMath.sol";
import {CommitteeAttestations, SignatureLib} from "@aztec/shared/libraries/SignatureLib.sol";
import {Math} from "@oz/utils/math/Math.sol";
import {SafeCast} from "@oz/utils/math/SafeCast.sol";

Expand All @@ -26,6 +30,8 @@ library EpochProofLib {
using FeeHeaderLib for CompressedFeeHeader;
using SafeCast for uint256;
using ChainTipsLib for CompressedChainTips;
using SignatureLib for CommitteeAttestations;
using CompressedTimeMath for CompressedSlot;

// This is a temporary struct to avoid stack too deep errors
struct BlobVarsTemp {
Expand Down Expand Up @@ -65,6 +71,9 @@ library EpochProofLib {

Epoch endEpoch = assertAcceptable(_args.start, _args.end);

// Verify attestations for the last block in the epoch
verifyLastBlockAttestations(_args.end, _args.attestations);

require(verifyEpochRootProof(_args), Errors.Rollup__InvalidProof());

RollupStore storage rollupStore = STFLib.getStorage();
Expand Down Expand Up @@ -207,6 +216,31 @@ library EpochProofLib {
return publicInputs;
}

/**
* @notice Verifies the attestations for the last block in the epoch
* @param _endBlockNumber The last block number in the epoch
* @param _attestations The attestations to verify
*/
function verifyLastBlockAttestations(
uint256 _endBlockNumber,
CommitteeAttestations memory _attestations
) private {
// Get the stored attestation hash and payload digest for the last block
CompressedTempBlockLog storage blockLog = STFLib.getStorageTempBlockLog(_endBlockNumber);

// Verify that the provided attestations match the stored hash
bytes32 providedAttestationsHash = keccak256(abi.encode(_attestations));
require(
providedAttestationsHash == blockLog.attestationsHash, Errors.Rollup__InvalidAttestations()
);

// Get the slot and epoch for the last block
Slot slot = blockLog.slotNumber.decompress();
Epoch epoch = STFLib.getEpochForBlock(_endBlockNumber);

ValidatorSelectionLib.verifyAttestations(slot, epoch, _attestations, blockLog.payloadDigest);
}

function assertAcceptable(uint256 _start, uint256 _end) private view returns (Epoch) {
RollupStore storage rollupStore = STFLib.getStorage();

Expand Down
Loading
Loading