Skip to content

Commit 12719d4

Browse files
committed
feat: Delayed signature verification during block proposals
Implements AztecProtocol/engineering-designs#69
1 parent 03138c4 commit 12719d4

File tree

18 files changed

+439
-35
lines changed

18 files changed

+439
-35
lines changed

l1-contracts/src/core/Rollup.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
113113
ExtRollupLib.validateHeader(
114114
ValidateHeaderArgs({
115115
header: _header,
116-
attestations: _attestations,
117116
digest: _digest,
118117
manaBaseFee: getManaBaseFeeAt(currentTime, true),
119118
blobsHashesCommitment: _blobsHash,
120119
flags: _flags
121-
})
120+
}),
121+
_attestations
122122
);
123123
}
124124

@@ -365,6 +365,8 @@ contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore {
365365
archive: rollupStore.archives[_blockNumber],
366366
headerHash: tempBlockLog.headerHash,
367367
blobCommitmentsHash: tempBlockLog.blobCommitmentsHash,
368+
attestationsHash: tempBlockLog.attestationsHash,
369+
payloadDigest: tempBlockLog.payloadDigest,
368370
slotNumber: tempBlockLog.slotNumber,
369371
feeHeader: tempBlockLog.feeHeader
370372
});

l1-contracts/src/core/RollupCore.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,23 @@ contract RollupCore is
243243
ExtRollupLib.propose(_args, _attestations, _blobInput, checkBlob);
244244
}
245245

246+
function invalidateBadAttestation(
247+
uint256 _blockNumber,
248+
CommitteeAttestations memory _attestations,
249+
address[] memory _committee,
250+
uint256 _invalidIndex
251+
) external {
252+
ExtRollupLib2.invalidateBadAttestation(_blockNumber, _attestations, _committee, _invalidIndex);
253+
}
254+
255+
function invalidateInsufficientAttestations(
256+
uint256 _blockNumber,
257+
CommitteeAttestations memory _attestations,
258+
address[] memory _committee
259+
) external {
260+
ExtRollupLib2.invalidateInsufficientAttestations(_blockNumber, _attestations, _committee);
261+
}
262+
246263
function setupEpoch() public override(IValidatorSelectionCore) {
247264
ExtRollupLib2.setupEpoch();
248265
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct SubmitEpochRootProofArgs {
3636
uint256 end; // inclusive
3737
PublicInputArgs args;
3838
bytes32[] fees;
39+
CommitteeAttestations attestations; // attestations for the last block in epoch
3940
bytes blobInputs;
4041
bytes proof;
4142
}
@@ -95,6 +96,7 @@ interface IRollupCore {
9596
uint256 indexed blockNumber, bytes32 indexed archive, bytes32[] versionedBlobHashes
9697
);
9798
event L2ProofVerified(uint256 indexed blockNumber, address indexed proverId);
99+
event BlockInvalidated(uint256 indexed blockNumber);
98100
event RewardConfigUpdated(RewardConfig rewardConfig);
99101
event ManaTargetUpdated(uint256 indexed manaTarget);
100102
event PrunedPending(uint256 provenBlockNumber, uint256 pendingBlockNumber);
@@ -121,6 +123,19 @@ interface IRollupCore {
121123

122124
function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external;
123125

126+
function invalidateBadAttestation(
127+
uint256 _blockNumber,
128+
CommitteeAttestations memory _attestations,
129+
address[] memory _committee,
130+
uint256 _invalidIndex
131+
) external;
132+
133+
function invalidateInsufficientAttestations(
134+
uint256 _blockNumber,
135+
CommitteeAttestations memory _attestations,
136+
address[] memory _committee
137+
) external;
138+
124139
function setRewardConfig(RewardConfig memory _config) external;
125140
function updateManaTarget(uint256 _manaTarget) external;
126141

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ library Errors {
5656
error Rollup__InvalidProof(); // 0xa5b2ba17
5757
error Rollup__InvalidProposedArchive(bytes32 expected, bytes32 actual); // 0x32532e73
5858
error Rollup__InvalidTimestamp(Timestamp expected, Timestamp actual); // 0x3132e895
59+
error Rollup__InvalidAttestations();
60+
error Rollup__AttestationsAreValid();
61+
error Rollup__BlockAlreadyProven();
62+
error Rollup__BlockNotInPendingChain();
5963
error Rollup__InvalidBlobHash(bytes32 expected, bytes32 actual); // 0x13031e6a
6064
error Rollup__InvalidBlobProof(bytes32 blobHash); // 0x5ca17bef
6165
error Rollup__NoEpochToProve(); // 0xcbaa3951
@@ -102,6 +106,7 @@ library Errors {
102106
error ValidatorSelection__InsufficientAttestations(uint256 minimumNeeded, uint256 provided); // 0xaf47297f
103107
error ValidatorSelection__InvalidCommitteeCommitment(bytes32 reconstructed, bytes32 expected); // 0xca8d5954
104108
error ValidatorSelection__InsufficientCommitteeSize(uint256 actual, uint256 expected); // 0x98673597
109+
error ValidatorSelection__ProposerIndexTooLarge(uint256 index);
105110

106111
// Staking
107112
error Staking__AlreadyQueued(address _attester);

l1-contracts/src/core/libraries/compressed-data/BlockLog.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,34 @@ import {Slot} from "@aztec/shared/libraries/TimeMath.sol";
1515
* @param archive - Archive tree root of the block
1616
* @param headerHash - Hash of the proposed block header
1717
* @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
18+
* @param attestationsHash - Hash of the attestations for this block
19+
* @param payloadDigest - Digest of the proposal payload that was attested to
1820
* @param slotNumber - This block's slot
1921
*/
2022
struct BlockLog {
2123
bytes32 archive;
2224
bytes32 headerHash;
2325
bytes32 blobCommitmentsHash;
26+
bytes32 attestationsHash;
27+
bytes32 payloadDigest;
2428
Slot slotNumber;
2529
FeeHeader feeHeader;
2630
}
2731

2832
struct TempBlockLog {
2933
bytes32 headerHash;
3034
bytes32 blobCommitmentsHash;
35+
bytes32 attestationsHash;
36+
bytes32 payloadDigest;
3137
Slot slotNumber;
3238
FeeHeader feeHeader;
3339
}
3440

3541
struct CompressedTempBlockLog {
3642
bytes32 headerHash;
3743
bytes32 blobCommitmentsHash;
44+
bytes32 attestationsHash;
45+
bytes32 payloadDigest;
3846
CompressedSlot slotNumber;
3947
CompressedFeeHeader feeHeader;
4048
}
@@ -53,6 +61,8 @@ library CompressedTempBlockLogLib {
5361
return CompressedTempBlockLog({
5462
headerHash: _blockLog.headerHash,
5563
blobCommitmentsHash: _blockLog.blobCommitmentsHash,
64+
attestationsHash: _blockLog.attestationsHash,
65+
payloadDigest: _blockLog.payloadDigest,
5666
slotNumber: _blockLog.slotNumber.compress(),
5767
feeHeader: _blockLog.feeHeader.compress()
5868
});
@@ -66,6 +76,8 @@ library CompressedTempBlockLogLib {
6676
return TempBlockLog({
6777
headerHash: _compressedBlockLog.headerHash,
6878
blobCommitmentsHash: _compressedBlockLog.blobCommitmentsHash,
79+
attestationsHash: _compressedBlockLog.attestationsHash,
80+
payloadDigest: _compressedBlockLog.payloadDigest,
6981
slotNumber: _compressedBlockLog.slotNumber.decompress(),
7082
feeHeader: _compressedBlockLog.feeHeader.decompress()
7183
});

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

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import {
66
SubmitEpochRootProofArgs,
77
PublicInputArgs,
88
IRollupCore,
9-
RollupStore
9+
RollupStore,
10+
BlockHeaderValidationFlags
1011
} from "@aztec/core/interfaces/IRollup.sol";
1112
import {ChainTipsLib, CompressedChainTips} from "@aztec/core/libraries/compressed-data/Tips.sol";
13+
import {TempBlockLog} from "@aztec/core/libraries/compressed-data/BlockLog.sol";
1214
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
1315
import {Errors} from "@aztec/core/libraries/Errors.sol";
1416
import {BlobLib} from "@aztec/core/libraries/rollup/BlobLib.sol";
1517
import {CompressedFeeHeader, FeeHeaderLib} from "@aztec/core/libraries/rollup/FeeLib.sol";
1618
import {RewardLib} from "@aztec/core/libraries/rollup/RewardLib.sol";
1719
import {STFLib} from "@aztec/core/libraries/rollup/STFLib.sol";
20+
import {ValidatorSelectionLib} from "@aztec/core/libraries/rollup/ValidatorSelectionLib.sol";
1821
import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
22+
import {CommitteeAttestations} from "@aztec/shared/libraries/SignatureLib.sol";
1923
import {Math} from "@oz/utils/math/Math.sol";
2024
import {SafeCast} from "@oz/utils/math/SafeCast.sol";
2125

@@ -65,6 +69,9 @@ library EpochProofLib {
6569

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

72+
// Verify attestations for the last block in the epoch
73+
verifyLastBlockAttestations(_args.end, _args.attestations);
74+
6875
require(verifyEpochRootProof(_args), Errors.Rollup__InvalidProof());
6976

7077
RollupStore storage rollupStore = STFLib.getStorage();
@@ -286,4 +293,39 @@ library EpochProofLib {
286293
function addressToField(address _a) private pure returns (bytes32) {
287294
return bytes32(uint256(uint160(_a)));
288295
}
296+
297+
/**
298+
* @notice Verifies the attestations for the last block in the epoch
299+
* @param _endBlockNumber The last block number in the epoch
300+
* @param _attestations The attestations to verify
301+
*/
302+
function verifyLastBlockAttestations(
303+
uint256 _endBlockNumber,
304+
CommitteeAttestations memory _attestations
305+
) private {
306+
// Get the stored attestation hash and payload digest for the last block
307+
TempBlockLog memory blockLog = STFLib.getTempBlockLog(_endBlockNumber);
308+
309+
// Verify that the provided attestations match the stored hash
310+
bytes32 providedAttestationsHash = keccak256(abi.encode(_attestations));
311+
require(
312+
providedAttestationsHash == blockLog.attestationsHash,
313+
Errors.Rollup__InvalidAttestations()
314+
);
315+
316+
// Get the slot and epoch for the last block
317+
Slot slot = blockLog.slotNumber;
318+
Epoch epoch = STFLib.getEpochForBlock(_endBlockNumber);
319+
320+
// Only verify attestations if they are not empty (for testing compatibility)
321+
if (_attestations.signatureIndices.length > 0 || _attestations.signaturesOrAddresses.length > 0) {
322+
ValidatorSelectionLib.verify(
323+
slot,
324+
epoch,
325+
_attestations,
326+
blockLog.payloadDigest,
327+
BlockHeaderValidationFlags({ignoreDA: false, ignoreSignatures: false})
328+
);
329+
}
330+
}
289331
}

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,39 @@
44
pragma solidity >=0.8.27;
55

66
import {SubmitEpochRootProofArgs, PublicInputArgs} from "@aztec/core/interfaces/IRollup.sol";
7-
import {Timestamp, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
7+
import {TempBlockLog} from "@aztec/core/libraries/compressed-data/BlockLog.sol";
8+
import {STFLib} from "@aztec/core/libraries/rollup/STFLib.sol";
9+
import {Timestamp, TimeLib, Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol";
810
import {BlobLib} from "./BlobLib.sol";
911
import {EpochProofLib} from "./EpochProofLib.sol";
12+
import {InvalidateLib} from "./InvalidateLib.sol";
1013
import {
11-
ProposeLib, ProposeArgs, CommitteeAttestations, ValidateHeaderArgs
14+
ProposeLib,
15+
ProposeArgs,
16+
CommitteeAttestations,
17+
ValidateHeaderArgs,
18+
ValidatorSelectionLib
1219
} from "./ProposeLib.sol";
1320

1421
// We are using this library such that we can more easily "link" just a larger external library
1522
// instead of a few smaller ones.
1623
library ExtRollupLib {
1724
using TimeLib for Timestamp;
25+
using TimeLib for Slot;
1826

1927
function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external {
2028
EpochProofLib.submitEpochRootProof(_args);
2129
}
2230

23-
function validateHeader(ValidateHeaderArgs calldata _args) external {
31+
function validateHeader(
32+
ValidateHeaderArgs calldata _args,
33+
CommitteeAttestations calldata _attestations
34+
) external {
2435
ProposeLib.validateHeader(_args);
36+
37+
Slot slot = _args.header.slotNumber;
38+
Epoch epoch = slot.epochFromSlot();
39+
ValidatorSelectionLib.verify(slot, epoch, _attestations, _args.digest, _args.flags);
2540
}
2641

2742
function propose(

l1-contracts/src/core/libraries/rollup/ExtRollupLib2.sol

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ pragma solidity >=0.8.27;
66
import {Epoch, Slot, Timestamp, TimeLib} from "@aztec/core/libraries/TimeLib.sol";
77
import {StakingQueueConfig} from "@aztec/core/libraries/compressed-data/StakingQueueConfig.sol";
88
import {StakingLib} from "./StakingLib.sol";
9+
import {InvalidateLib} from "./InvalidateLib.sol";
910
import {ValidatorSelectionLib} from "./ValidatorSelectionLib.sol";
11+
import {CommitteeAttestations} from "@aztec/shared/libraries/SignatureLib.sol";
1012
import {
1113
RewardBooster,
1214
RewardBoostConfig,
@@ -60,12 +62,29 @@ library ExtRollupLib2 {
6062
StakingLib.updateStakingQueueConfig(_config);
6163
}
6264

65+
function invalidateBadAttestation(
66+
uint256 _blockNumber,
67+
CommitteeAttestations memory _attestations,
68+
address[] memory _committee,
69+
uint256 _invalidIndex
70+
) external {
71+
InvalidateLib.invalidateBadAttestation(_blockNumber, _attestations, _committee, _invalidIndex);
72+
}
73+
74+
function invalidateInsufficientAttestations(
75+
uint256 _blockNumber,
76+
CommitteeAttestations memory _attestations,
77+
address[] memory _committee
78+
) external {
79+
InvalidateLib.invalidateInsufficientAttestations(_blockNumber, _attestations, _committee);
80+
}
81+
6382
function getCommitteeAt(Epoch _epoch) external returns (address[] memory) {
6483
return ValidatorSelectionLib.getCommitteeAt(_epoch);
6584
}
6685

67-
function getProposerAt(Slot _slot) external returns (address) {
68-
return ValidatorSelectionLib.getProposerAt(_slot);
86+
function getProposerAt(Slot _slot) external returns (address proposer) {
87+
(proposer,) = ValidatorSelectionLib.getProposerAt(_slot);
6988
}
7089

7190
function getCommitteeCommitmentAt(Epoch _epoch) external returns (bytes32, uint256) {

0 commit comments

Comments
 (0)