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: Pad epochs with empty blocks #8842

Closed
wants to merge 6 commits into from
Closed
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
41 changes: 29 additions & 12 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
IProofCommitmentEscrow public immutable PROOF_COMMITMENT_ESCROW;
uint256 public immutable VERSION;
IFeeJuicePortal public immutable FEE_JUICE_PORTAL;
IVerifier public verifier;
IVerifier public blockProofVerifier;

ChainTips public tips;
DataStructures.EpochProofClaim public proofClaim;
@@ -80,14 +80,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// Testing only. This should be removed eventually.
uint256 private assumeProvenThroughBlockNumber;

// Listed at the end of the contract to avoid changing storage slots
// TODO(palla/prover) Drop blockProofVerifier and move this verifier to that slot
IVerifier public epochProofVerifier;

constructor(
IRegistry _registry,
IFeeJuicePortal _fpcJuicePortal,
bytes32 _vkTreeRoot,
address _ares,
address[] memory _validators
) Leonidas(_ares) {
verifier = new MockVerifier();
blockProofVerifier = new MockVerifier();
epochProofVerifier = new MockVerifier();
REGISTRY = _registry;
FEE_JUICE_PORTAL = _fpcJuicePortal;
PROOF_COMMITMENT_ESCROW = new MockProofCommitmentEscrow();
@@ -100,7 +105,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// Genesis block
blocks[0] = BlockLog({
archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT),
blockHash: bytes32(0),
blockHash: bytes32(0), // TODO(palla/prover): The first block does not have hash zero
slotNumber: Slot.wrap(0)
});
for (uint256 i = 0; i < _validators.length; i++) {
@@ -144,8 +149,19 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
*
* @param _verifier - The new verifier contract
*/
function setVerifier(address _verifier) external override(ITestRollup) onlyOwner {
verifier = IVerifier(_verifier);
function setBlockVerifier(address _verifier) external override(ITestRollup) onlyOwner {
blockProofVerifier = IVerifier(_verifier);
}

/**
* @notice Set the verifier contract
*
* @dev This is only needed for testing, and should be removed
*
* @param _verifier - The new verifier contract
*/
function setEpochVerifier(address _verifier) external override(ITestRollup) onlyOwner {
epochProofVerifier = IVerifier(_verifier);
}

/**
@@ -410,7 +426,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
publicInputs[i + 91] = part;
}

if (!verifier.verify(_proof, publicInputs)) {
if (!blockProofVerifier.verify(_proof, publicInputs)) {
revert Errors.Rollup__InvalidProof();
}

@@ -484,7 +500,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
bytes32[] memory publicInputs =
getEpochProofPublicInputs(_epochSize, _args, _fees, _aggregationObject);

if (!verifier.verify(_proof, publicInputs)) {
if (!epochProofVerifier.verify(_proof, publicInputs)) {
revert Errors.Rollup__InvalidProof();
}

@@ -550,7 +566,8 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
}

bytes32 expectedPreviousBlockHash = blocks[previousBlockNumber].blockHash;
if (expectedPreviousBlockHash != _args[2]) {
// TODO: Remove 0 check once we inject the proper genesis block hash
if (expectedPreviousBlockHash != 0 && expectedPreviousBlockHash != _args[2]) {
revert Errors.Rollup__InvalidPreviousBlockHash(expectedPreviousBlockHash, _args[2]);
}

@@ -608,16 +625,16 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
// out_hash: root of this epoch's l2 to l1 message tree
publicInputs[8] = _args[5];

// fees[9-40]: array of recipient-value pairs
// fees[9-72]: array of recipient-value pairs
for (uint256 i = 0; i < 64; i++) {
publicInputs[9 + i] = _fees[i];
}

// vk_tree_root
publicInputs[41] = vkTreeRoot;
publicInputs[73] = vkTreeRoot;

// prover_id: id of current epoch's prover
publicInputs[42] = _args[6];
publicInputs[74] = _args[6];

// the block proof is recursive, which means it comes with an aggregation object
// this snippet copies it into the public inputs needed for verification
@@ -628,7 +645,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
assembly {
part := calldataload(add(_aggregationObject.offset, mul(i, 32)))
}
publicInputs[i + 43] = part;
publicInputs[i + 75] = part;
}

return publicInputs;
3 changes: 2 additions & 1 deletion l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
@@ -11,7 +11,8 @@ import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";

interface ITestRollup {
function setVerifier(address _verifier) external;
function setBlockVerifier(address _verifier) external;
function setEpochVerifier(address _verifier) external;
function setVkTreeRoot(bytes32 _vkTreeRoot) external;
function setAssumeProvenThroughBlockNumber(uint256 blockNumber) external;
}
9 changes: 5 additions & 4 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
@@ -671,10 +671,11 @@ contract RollupTest is DecoderBase {
);
_submitEpochProof(rollup, 1, wrong, data.archive, preBlockHash, data.blockHash, bytes32(0));

vm.expectRevert(
abi.encodeWithSelector(Errors.Rollup__InvalidPreviousBlockHash.selector, preBlockHash, wrong)
);
_submitEpochProof(rollup, 1, preArchive, data.archive, wrong, data.blockHash, bytes32(0));
// TODO: Reenable when we setup proper initial block hash
// vm.expectRevert(
// abi.encodeWithSelector(Errors.Rollup__InvalidPreviousBlockHash.selector, preBlockHash, wrong)
// );
// _submitEpochProof(rollup, 1, preArchive, data.archive, wrong, data.blockHash, bytes32(0));
}

function testSubmitProofInvalidArchive() public setUpFor("empty_block_1") {
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ pub struct EmptyBlockRootRollupInputs {
archive: AppendOnlyTreeSnapshot,
block_hash: Field,
global_variables: GlobalVariables,
out_hash: Field,
vk_tree_root: Field,
// TODO(#7346): Temporarily added prover_id while we verify block-root proofs on L1
prover_id: Field,
@@ -21,7 +20,7 @@ impl EmptyBlockRootRollupInputs {
end_block_hash: self.block_hash,
start_global_variables: self.global_variables,
end_global_variables: self.global_variables,
out_hash: self.out_hash,
out_hash: 0, // out_hash is ignored when merging if the block proof is padding
fees: [FeeRecipient::empty(); 32],
vk_tree_root: self.vk_tree_root,
prover_id: self.prover_id
12 changes: 6 additions & 6 deletions yarn-project/bb-prover/src/honk.ts
Original file line number Diff line number Diff line change
@@ -6,16 +6,16 @@ const UltraKeccakHonkCircuits = [
'BlockRootRollupFinalArtifact',
'RootRollupArtifact',
] as const satisfies ProtocolArtifact[];
type UltraKeccakHonkCircuits = (typeof UltraKeccakHonkCircuits)[number];
type UltraHonkCircuits = Exclude<ProtocolArtifact, UltraKeccakHonkCircuits>;
export type UltraKeccakHonkProtocolArtifact = (typeof UltraKeccakHonkCircuits)[number];
export type UltraHonkProtocolArtifact = Exclude<ProtocolArtifact, UltraKeccakHonkProtocolArtifact>;

export function getUltraHonkFlavorForCircuit(artifact: UltraKeccakHonkCircuits): 'ultra_keccak_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraHonkCircuits): 'ultra_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraKeccakHonkProtocolArtifact): 'ultra_keccak_honk';
export function getUltraHonkFlavorForCircuit(artifact: UltraHonkProtocolArtifact): 'ultra_honk';
export function getUltraHonkFlavorForCircuit(artifact: ProtocolArtifact): UltraHonkFlavor;
export function getUltraHonkFlavorForCircuit(artifact: ProtocolArtifact): UltraHonkFlavor {
return isUltraKeccakHonkCircuit(artifact) ? 'ultra_keccak_honk' : 'ultra_honk';
}

function isUltraKeccakHonkCircuit(artifact: ProtocolArtifact): artifact is UltraKeccakHonkCircuits {
return UltraKeccakHonkCircuits.includes(artifact as UltraKeccakHonkCircuits);
function isUltraKeccakHonkCircuit(artifact: ProtocolArtifact): artifact is UltraKeccakHonkProtocolArtifact {
return UltraKeccakHonkCircuits.includes(artifact as UltraKeccakHonkProtocolArtifact);
}
1 change: 1 addition & 0 deletions yarn-project/bb-prover/src/index.ts
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@ export * from './test/index.js';
export * from './verifier/index.js';
export * from './config.js';
export * from './bb/execute.js';
export * from './honk.js';

export { type ClientProtocolCircuitVerifier } from '@aztec/circuit-types';
7 changes: 4 additions & 3 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
@@ -59,6 +59,7 @@ import {
convertBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertEmptyBlockRootRollupOutputsFromWitnessMap,
convertMergeRollupInputsToWitnessMap,
convertMergeRollupOutputsFromWitnessMap,
convertPrivateKernelEmptyInputsToWitnessMap,
@@ -395,12 +396,12 @@ export class BBNativeRollupProver implements ServerCircuitProver {
'EmptyBlockRootRollupArtifact',
RECURSIVE_PROOF_LENGTH,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
convertEmptyBlockRootRollupOutputsFromWitnessMap,
);

const verificationKey = await this.getVerificationKeyDataForCircuit('BlockRootRollupArtifact');
const verificationKey = await this.getVerificationKeyDataForCircuit('EmptyBlockRootRollupArtifact');

await this.verifyProof('BlockRootRollupArtifact', proof.binaryProof);
await this.verifyProof('EmptyBlockRootRollupArtifact', proof.binaryProof);

return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
}
3 changes: 2 additions & 1 deletion yarn-project/bb-prover/src/test/test_circuit_prover.ts
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@ import {
convertBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
convertEmptyBlockRootRollupInputsToWitnessMap,
convertEmptyBlockRootRollupOutputsFromWitnessMap,
convertMergeRollupInputsToWitnessMap,
convertMergeRollupOutputsFromWitnessMap,
convertPrivateKernelEmptyInputsToWitnessMap,
@@ -367,7 +368,7 @@ export class TestCircuitProver implements ServerCircuitProver {
SimulatedServerCircuitArtifacts.EmptyBlockRootRollupArtifact,
);

const result = convertBlockRootRollupOutputsFromWitnessMap(witness);
const result = convertEmptyBlockRootRollupOutputsFromWitnessMap(witness);

this.instrumentation.recordDuration('simulationDuration', 'empty-block-root-rollup', timer);
emitCircuitSimulationStats(
4 changes: 2 additions & 2 deletions yarn-project/bb-prover/src/verifier/bb_verifier.ts
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import {
verifyProof,
} from '../bb/execute.js';
import { type BBConfig } from '../config.js';
import { getUltraHonkFlavorForCircuit } from '../honk.js';
import { type UltraKeccakHonkProtocolArtifact, getUltraHonkFlavorForCircuit } from '../honk.js';
import { mapProtocolArtifactNameToCircuitName } from '../stats.js';
import { extractVkData } from '../verification_key/verification_key_data.js';

@@ -127,7 +127,7 @@ export class BBCircuitVerifier implements ClientProtocolCircuitVerifier {
await runInDirectory(this.config.bbWorkingDirectory, operation, this.config.bbSkipCleanup);
}

public async generateSolidityContract(circuit: ProtocolArtifact, contractName: string) {
public async generateSolidityContract(circuit: UltraKeccakHonkProtocolArtifact, contractName: string) {
const result = await generateContractForCircuit(
this.config.bbBinaryPath,
this.config.bbWorkingDirectory,
8 changes: 7 additions & 1 deletion yarn-project/circuit-types/src/interfaces/block-prover.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Fr, type GlobalVariables, type Proof } from '@aztec/circuits.js';
import { type Fr, type GlobalVariables, type Proof, type RootRollupPublicInputs } from '@aztec/circuits.js';

import { type L2Block } from '../l2_block.js';
import { type ProcessedTx } from '../tx/processed_tx.js';
@@ -32,6 +32,8 @@ export type ProvingBlockResult = SimulationBlockResult & {
aggregationObject: Fr[];
};

export type ProvingEpochResult = { publicInputs: RootRollupPublicInputs; proof: Proof };

/** Receives processed txs as part of block simulation or proving. */
export interface ProcessedTxHandler {
/**
@@ -75,4 +77,8 @@ export interface BlockProver extends BlockSimulator {

export interface EpochProver extends BlockProver {
startNewEpoch(epochNumber: number, totalNumBlocks: number): ProvingTicket;

setEpochCompleted(): void;

finaliseEpoch(): ProvingEpochResult;
}
7 changes: 3 additions & 4 deletions yarn-project/circuit-types/src/interfaces/prover-client.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { type TxHash } from '@aztec/circuit-types';
import { Fr } from '@aztec/circuits.js';
import { type ConfigMappingsType, booleanConfigHelper, numberConfigHelper } from '@aztec/foundation/config';

import { type BlockProver } from './block-prover.js';
import { type EpochProver } from './block-prover.js';
import { type MerkleTreeOperations } from './merkle_tree_operations.js';
import { type ProvingJobSource } from './proving-job.js';

@@ -84,10 +84,9 @@ function parseProverId(str: string) {
/**
* The interface to the prover client.
* Provides the ability to generate proofs and build rollups.
* TODO(palla/prover-node): Rename this interface
*/
export interface ProverClient {
createBlockProver(db: MerkleTreeOperations): BlockProver;
export interface EpochProverManager {
createEpochProver(db: MerkleTreeOperations): EpochProver;

start(): Promise<void>;

7 changes: 7 additions & 0 deletions yarn-project/circuits.js/src/structs/proof.ts
Original file line number Diff line number Diff line change
@@ -91,6 +91,13 @@ export class Proof {
static fromString(str: string) {
return Proof.fromBuffer(Buffer.from(str, 'hex'));
}

/** Returns whether this proof is actually empty. */
public isEmpty() {
return (
this.buffer.length === EMPTY_PROOF_SIZE && this.buffer.every(byte => byte === 0) && this.numPublicInputs === 0
);
}
}

/**
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@ export class EmptyBlockRootRollupInputs {
public readonly archive: AppendOnlyTreeSnapshot,
public readonly blockHash: Fr,
public readonly globalVariables: GlobalVariables,
public readonly outHash: Fr,
public readonly vkTreeRoot: Fr,
// // TODO(#7346): Temporarily added prover_id while we verify block-root proofs on L1
public readonly proverId: Fr,
@@ -50,14 +49,7 @@ export class EmptyBlockRootRollupInputs {
* @returns An array of fields.
*/
static getFields(fields: FieldsOf<EmptyBlockRootRollupInputs>) {
return [
fields.archive,
fields.blockHash,
fields.globalVariables,
fields.outHash,
fields.vkTreeRoot,
fields.proverId,
] as const;
return [fields.archive, fields.blockHash, fields.globalVariables, fields.vkTreeRoot, fields.proverId] as const;
}

/**
@@ -73,7 +65,6 @@ export class EmptyBlockRootRollupInputs {
GlobalVariables.fromBuffer(reader),
Fr.fromBuffer(reader),
Fr.fromBuffer(reader),
Fr.fromBuffer(reader),
);
}

1 change: 0 additions & 1 deletion yarn-project/circuits.js/src/tests/factories.ts
Original file line number Diff line number Diff line change
@@ -1077,7 +1077,6 @@ export function makeEmptyBlockRootRollupInputs(
globalVariables ?? makeGlobalVariables(seed + 0x200),
fr(seed + 0x300),
fr(seed + 0x400),
fr(seed + 0x500),
);
}

Loading

Unchanged files with check annotations Beta

e2e-fees-failures:
LOCALLY
RUN ./scripts/e2e_test.sh ./src/e2e_fees/failures.test.ts

Check failure on line 149 in yarn-project/end-to-end/Earthfile

GitHub Actions / e2e (e2e-fees-failures)

Error

The command RUN ./scripts/e2e_test.sh ./src/e2e_fees/failures.test.ts did not complete successfully. Exit code 1
e2e-fees-fee-juice-payments:
LOCALLY