Skip to content
Closed
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
41 changes: 29 additions & 12 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,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;
Expand All @@ -78,14 +78,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();
Expand All @@ -98,7 +103,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: The first block does not have hash zero
slotNumber: 0
});
for (uint256 i = 0; i < _validators.length; i++) {
Expand Down Expand Up @@ -142,8 +147,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);
}

/**
Expand Down Expand Up @@ -406,7 +422,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();
}

Expand Down Expand Up @@ -480,7 +496,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();
}

Expand Down Expand Up @@ -546,7 +562,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]);
}

Expand Down Expand Up @@ -604,16 +621,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
Expand All @@ -624,7 +641,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;
Expand Down
3 changes: 2 additions & 1 deletion l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {SignatureLib} from "../libraries/SignatureLib.sol";
import {DataStructures} from "../libraries/DataStructures.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;
}
Expand Down
9 changes: 5 additions & 4 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -715,10 +715,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") {
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ boxes/*/src/artifacts/*.json
boxes/*/src/artifacts/*.ts
boxes/*/src/contracts/target/*.json
*.md
end-to-end/src/fixtures/dumps/block_result.json
end-to-end/src/fixtures/dumps/*.json
12 changes: 6 additions & 6 deletions yarn-project/bb-prover/src/honk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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';
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
Expand Up @@ -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';

Expand Down Expand Up @@ -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,
Expand Down
6 changes: 5 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';
Expand Down Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -75,4 +77,6 @@ export interface BlockProver extends BlockSimulator {

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

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
Expand Up @@ -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';

Expand Down Expand Up @@ -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>;

Expand Down
7 changes: 7 additions & 0 deletions yarn-project/circuits.js/src/structs/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
}

/**
Expand Down
64 changes: 23 additions & 41 deletions yarn-project/cli/src/cmds/l1/deploy_l1_verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createCompatibleClient } from '@aztec/aztec.js';
import { createEthereumChain, createL1Clients, deployL1Contract } from '@aztec/ethereum';
import { compileContract, createEthereumChain, createL1Clients, deployL1Contract } from '@aztec/ethereum';
import { type DebugLogger, type LogFn } from '@aztec/foundation/log';

import { InvalidOptionArgumentError } from 'commander';
Expand All @@ -24,51 +24,14 @@ export async function deployUltraHonkVerifier(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Importing bb-prover even in devDeps results in a circular dependency error through @aztec/simulator. Need to ignore because this line doesn't cause an error in a dev environment
const { BBCircuitVerifier } = await import('@aztec/bb-prover');

const circuitVerifier = await BBCircuitVerifier.new({ bbBinaryPath, bbWorkingDirectory });
const contractSrc = await circuitVerifier.generateSolidityContract(
'BlockRootRollupFinalArtifact',
'UltraHonkVerifier.sol',
);
log('Generated UltraHonkVerifier contract');

const input = {
language: 'Solidity',
sources: {
'UltraHonkVerifier.sol': {
content: contractSrc,
},
},
settings: {
// we require the optimizer
optimizer: {
enabled: true,
runs: 200,
},
evmVersion: 'paris',
outputSelection: {
'*': {
'*': ['evm.bytecode.object', 'abi'],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));
log('Compiled UltraHonkVerifier');

const abi = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].abi;
const bytecode: string = output.contracts['UltraHonkVerifier.sol']['HonkVerifier'].evm.bytecode.object;
const verifier = await BBCircuitVerifier.new({ bbBinaryPath, bbWorkingDirectory });

const { publicClient, walletClient } = createL1Clients(
ethRpcUrl,
privateKey ?? mnemonic,
createEthereumChain(ethRpcUrl, l1ChainId).chainInfo,
);

const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, `0x${bytecode}`);
log(`Deployed HonkVerifier at ${verifierAddress.toString()}`);

const pxe = await createCompatibleClient(pxeRpcUrl, debugLogger);
const { l1ContractAddresses } = await pxe.getNodeInfo();

Expand All @@ -80,7 +43,25 @@ export async function deployUltraHonkVerifier(
client: walletClient,
});

await rollup.write.setVerifier([verifierAddress.toString()]);
// REFACTOR: Extract this method to a common package. We need a package that deals with L1
// but also has a reference to L1 artifacts and bb-prover.
const setupVerifier = async (
artifact: Parameters<(typeof verifier)['generateSolidityContract']>[0], // Cannot properly import the type here due to the hack above
method: 'setBlockVerifier' | 'setEpochVerifier',
) => {
const contract = await verifier.generateSolidityContract(artifact, 'UltraHonkVerifier.sol');
log(`Generated UltraHonkVerifier contract for ${artifact}`);
const { abi, bytecode } = compileContract('UltraHonkVerifier.sol', 'HonkVerifier', contract, solc);
log(`Compiled UltraHonkVerifier contract for ${artifact}`);
const { address: verifierAddress } = await deployL1Contract(walletClient, publicClient, abi, bytecode);
log(`Deployed real ${artifact} verifier at ${verifierAddress}`);
await rollup.write[method]([verifierAddress.toString()]);
log(`Set ${artifact} verifier in ${rollup.address} rollup contract to ${verifierAddress}`);
};

await setupVerifier('BlockRootRollupFinalArtifact', 'setBlockVerifier');
await setupVerifier('RootRollupArtifact', 'setEpochVerifier');

log(`Rollup accepts only real proofs now`);
}

Expand Down Expand Up @@ -117,6 +98,7 @@ export async function deployMockVerifier(
client: walletClient,
});

await rollup.write.setVerifier([mockVerifierAddress.toString()]);
await rollup.write.setBlockVerifier([mockVerifierAddress.toString()]);
await rollup.write.setEpochVerifier([mockVerifierAddress.toString()]);
log(`Rollup accepts only fake proofs now`);
}
2 changes: 1 addition & 1 deletion yarn-project/end-to-end/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
src/e2e_sandbox_example.test.ts
src/fixtures/dumps/block_result.json
src/fixtures/dumps/*.json
Loading