Skip to content

Commit

Permalink
Merge 042ea11 into f8b0802
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino authored Sep 27, 2024
2 parents f8b0802 + 042ea11 commit 7f94a33
Show file tree
Hide file tree
Showing 56 changed files with 423 additions and 1,127 deletions.
159 changes: 1 addition & 158 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 blockProofVerifier;
IVerifier public epochProofVerifier;

ChainTips public tips;
DataStructures.EpochProofClaim public proofClaim;
Expand All @@ -78,17 +78,12 @@ 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(
IFeeJuicePortal _fpcJuicePortal,
bytes32 _vkTreeRoot,
address _ares,
address[] memory _validators
) Leonidas(_ares) {
blockProofVerifier = new MockVerifier();
epochProofVerifier = new MockVerifier();
FEE_JUICE_PORTAL = _fpcJuicePortal;
PROOF_COMMITMENT_ESCROW = new MockProofCommitmentEscrow();
Expand Down Expand Up @@ -138,17 +133,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
assumeProvenThroughBlockNumber = blockNumber;
}

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

/**
* @notice Set the verifier contract
*
Expand Down Expand Up @@ -194,147 +178,6 @@ contract Rollup is Leonidas, IRollup, ITestRollup {
claimEpochProofRight(_quote);
}

/**
* @notice Submit a proof for a block in the pending chain
*
* @dev TODO(#7346): Verify root proofs rather than block root when batch rollups are integrated.
*
* @dev Will emit `L2ProofVerified` if the proof is valid
*
* @dev Will throw if:
* - The block number is past the pending chain
* - The last archive root of the header does not match the archive root of parent block
* - The archive root of the header does not match the archive root of the proposed block
* - The proof is invalid
*
* @dev We provide the `_archive` even if it could be read from storage itself because it allow for
* better error messages. Without passing it, we would just have a proof verification failure.
*
* @dev Following the `BlockLog` struct assumption
*
* @param _header - The header of the block (should match the block in the pending chain)
* @param _archive - The archive root of the block (should match the block in the pending chain)
* @param _proverId - The id of this block's prover
* @param _aggregationObject - The aggregation object for the proof
* @param _proof - The proof to verify
*/
function submitBlockRootProof(
bytes calldata _header,
bytes32 _archive,
bytes32 _proverId,
bytes calldata _aggregationObject,
bytes calldata _proof
) external override(IRollup) {
if (_canPrune()) {
_prune();
}
HeaderLib.Header memory header = HeaderLib.decode(_header);

if (header.globalVariables.blockNumber > tips.pendingBlockNumber) {
revert Errors.Rollup__TryingToProveNonExistingBlock();
}

// @note This implicitly also ensures that we have not already proven, since
// the value `tips.provenBlockNumber` is incremented at the end of this function
if (header.globalVariables.blockNumber != tips.provenBlockNumber + 1) {
revert Errors.Rollup__NonSequentialProving();
}

bytes32 expectedLastArchive = blocks[header.globalVariables.blockNumber - 1].archive;
// We do it this way to provide better error messages than passing along the storage values
if (header.lastArchive.root != expectedLastArchive) {
revert Errors.Rollup__InvalidArchive(expectedLastArchive, header.lastArchive.root);
}

bytes32 expectedArchive = blocks[header.globalVariables.blockNumber].archive;
if (_archive != expectedArchive) {
revert Errors.Rollup__InvalidProposedArchive(expectedArchive, _archive);
}

// TODO(#7346): Currently verifying block root proofs until batch rollups fully integrated.
// Hence the below pub inputs are BlockRootOrBlockMergePublicInputs, which are larger than
// the planned set (RootRollupPublicInputs), for the interim.
// Public inputs are not fully verified (TODO(#7373))

bytes32[] memory publicInputs = new bytes32[](
Constants.BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH + Constants.AGGREGATION_OBJECT_LENGTH
);

// From block_root_or_block_merge_public_inputs.nr: BlockRootOrBlockMergePublicInputs.
// previous_archive.root: the previous archive tree root
publicInputs[0] = expectedLastArchive;
// previous_archive.next_available_leaf_index: the previous archive next available index
publicInputs[1] = bytes32(header.globalVariables.blockNumber);

// new_archive.root: the new archive tree root
publicInputs[2] = expectedArchive;
// this is the _next_ available leaf in the archive tree
// normally this should be equal to the block number (since leaves are 0-indexed and blocks 1-indexed)
// but in yarn-project/merkle-tree/src/new_tree.ts we prefill the tree so that block N is in leaf N
// new_archive.next_available_leaf_index: the new archive next available index
publicInputs[3] = bytes32(header.globalVariables.blockNumber + 1);

// previous_block_hash: the block hash just preceding this block (will eventually become the end_block_hash of the prev batch)
publicInputs[4] = blocks[header.globalVariables.blockNumber - 1].blockHash;

// end_block_hash: the current block hash (will eventually become the hash of the final block proven in a batch)
publicInputs[5] = blocks[header.globalVariables.blockNumber].blockHash;

// For block root proof outputs, we have a block 'range' of just 1 block => start and end globals are the same
bytes32[] memory globalVariablesFields = HeaderLib.toFields(header.globalVariables);
for (uint256 i = 0; i < globalVariablesFields.length; i++) {
// start_global_variables
publicInputs[i + 6] = globalVariablesFields[i];
// end_global_variables
publicInputs[globalVariablesFields.length + i + 6] = globalVariablesFields[i];
}
// out_hash: root of this block's l2 to l1 message tree (will eventually be root of roots)
publicInputs[24] = header.contentCommitment.outHash;

// For block root proof outputs, we have a single recipient-value fee payment pair,
// but the struct contains space for the max (32) => we keep 31*2=62 fields blank to represent it.
// fees: array of recipient-value pairs, for a single block just one entry (will eventually be filled and paid out here)
publicInputs[25] = bytes32(uint256(uint160(header.globalVariables.coinbase)));
publicInputs[26] = bytes32(header.totalFees);
// publicInputs[27] -> publicInputs[88] left blank for empty fee array entries

// vk_tree_root
publicInputs[89] = vkTreeRoot;
// prover_id: id of current block range's prover
publicInputs[90] = _proverId;

// the block proof is recursive, which means it comes with an aggregation object
// this snippet copies it into the public inputs needed for verification
// it also guards against empty _aggregationObject used with mocked proofs
uint256 aggregationLength = _aggregationObject.length / 32;
for (uint256 i = 0; i < Constants.AGGREGATION_OBJECT_LENGTH && i < aggregationLength; i++) {
bytes32 part;
assembly {
part := calldataload(add(_aggregationObject.offset, mul(i, 32)))
}
publicInputs[i + 91] = part;
}

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

tips.provenBlockNumber = header.globalVariables.blockNumber;

for (uint256 i = 0; i < 32; i++) {
address coinbase = address(uint160(uint256(publicInputs[25 + i * 2])));
uint256 fees = uint256(publicInputs[26 + i * 2]);

if (coinbase != address(0) && fees > 0) {
// @note This will currently fail if there are insufficient funds in the bridge
// which WILL happen for the old version after an upgrade where the bridge follow.
// Consider allowing a failure. See #7938.
FEE_JUICE_PORTAL.distributeFees(coinbase, fees);
}
}
emit L2ProofVerified(header.globalVariables.blockNumber, _proverId);
}

/**
* @notice Submit a proof for an epoch in the pending chain
*
Expand Down
21 changes: 0 additions & 21 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
import {Timestamp, Slot, Epoch} from "@aztec/core/libraries/TimeMath.sol";

interface ITestRollup {
function setBlockVerifier(address _verifier) external;
function setEpochVerifier(address _verifier) external;
function setVkTreeRoot(bytes32 _vkTreeRoot) external;
function setAssumeProvenThroughBlockNumber(uint256 blockNumber) external;
Expand Down Expand Up @@ -52,14 +51,6 @@ interface IRollup {
DataStructures.SignedEpochProofQuote calldata _quote
) external;

function submitBlockRootProof(
bytes calldata _header,
bytes32 _archive,
bytes32 _proverId,
bytes calldata _aggregationObject,
bytes calldata _proof
) external;

function submitEpochRootProof(
uint256 _epochSize,
bytes32[7] calldata _args,
Expand Down Expand Up @@ -100,18 +91,6 @@ interface IRollup {
Epoch provenEpochNumber
);

// TODO(#7346): Integrate batch rollups
// function submitRootProof(
// bytes32 _previousArchive,
// bytes32 _archive,
// bytes32 outHash,
// address[32] calldata coinbases,
// uint256[32] calldata fees,
// bytes32 _proverId,
// bytes calldata _aggregationObject,
// bytes calldata _proof
// ) external;

function archive() external view returns (bytes32);
function archiveAt(uint256 _blockNumber) external view returns (bytes32);
function getProvenBlockNumber() external view returns (uint256);
Expand Down
1 change: 0 additions & 1 deletion l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ library Constants {
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 23;
uint256 internal constant ROOT_ROLLUP_INDEX = 24;
uint256 internal constant BLOCK_ROOT_ROLLUP_EMPTY_INDEX = 25;
uint256 internal constant BLOCK_ROOT_ROLLUP_FINAL_INDEX = 26;
uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4;
uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000;
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
Expand Down
1 change: 0 additions & 1 deletion noir-projects/noir-protocol-circuits/Nargo.template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,5 @@ members = [
"crates/rollup-block-merge",
"crates/rollup-block-root",
"crates/rollup-block-root-empty",
"crates/rollup-block-root-final",
"crates/rollup-root",
]

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ global BLOCK_ROOT_ROLLUP_INDEX: u32 = 22;
global BLOCK_MERGE_ROLLUP_INDEX: u32 = 23;
global ROOT_ROLLUP_INDEX: u32 = 24;
global BLOCK_ROOT_ROLLUP_EMPTY_INDEX: u32 = 25;
global BLOCK_ROOT_ROLLUP_FINAL_INDEX: u32 = 26;

// MISC CONSTANTS
global FUNCTION_SELECTOR_NUM_BYTES: Field = 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use crate::constants::{
EMPTY_NESTED_INDEX, PRIVATE_KERNEL_EMPTY_INDEX, PUBLIC_KERNEL_INNER_INDEX,
PUBLIC_KERNEL_MERGE_INDEX, PUBLIC_KERNEL_TAIL_INDEX, BASE_PARITY_INDEX, ROOT_PARITY_INDEX,
BASE_ROLLUP_INDEX, MERGE_ROLLUP_INDEX, BLOCK_ROOT_ROLLUP_INDEX, BLOCK_MERGE_ROLLUP_INDEX,
ROOT_ROLLUP_INDEX, PRIVATE_KERNEL_RESET_TINY_INDEX, BLOCK_ROOT_ROLLUP_EMPTY_INDEX,
BLOCK_ROOT_ROLLUP_FINAL_INDEX
ROOT_ROLLUP_INDEX, PRIVATE_KERNEL_RESET_TINY_INDEX, BLOCK_ROOT_ROLLUP_EMPTY_INDEX
};
use crate::merkle_tree::merkle_tree::MerkleTree;

Expand Down Expand Up @@ -43,7 +42,6 @@ pub fn get_vk_merkle_tree() -> MerkleTree<VK_TREE_WIDTH> {
leaves[BLOCK_MERGE_ROLLUP_INDEX] = 23;
leaves[ROOT_ROLLUP_INDEX] = 24;
leaves[BLOCK_ROOT_ROLLUP_EMPTY_INDEX] = 25;
leaves[BLOCK_ROOT_ROLLUP_FINAL_INDEX] = 26;

MerkleTree::new(leaves)
}
18 changes: 2 additions & 16 deletions yarn-project/archiver/src/archiver/data_retrieval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export async function retrieveL2ProofsFromRollup(
const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1)!.l1BlockNumber : searchStartBlock - 1n;

for (const { txHash, proverId, l2BlockNumber } of logs) {
const proofData = await getProofFromSubmitProofTx(publicClient, txHash, l2BlockNumber, proverId);
const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
retrievedData.push({ proof: proofData.proof, proverId: proofData.proverId, l2BlockNumber, txHash });
}
return {
Expand Down Expand Up @@ -267,31 +267,17 @@ export type SubmitBlockProof = {
export async function getProofFromSubmitProofTx(
publicClient: PublicClient,
txHash: `0x${string}`,
l2BlockNum: bigint,
expectedProverId: Fr,
): Promise<SubmitBlockProof> {
const { input: data } = await publicClient.getTransaction({ hash: txHash });
const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data });

let proverId: Fr;
let blockNumber: bigint;
let archiveRoot: Fr;
let aggregationObject: Buffer;
let proof: Proof;

if (functionName === 'submitBlockRootProof') {
const [headerHex, archiveHex, proverIdHex, aggregationObjectHex, proofHex] = args!;
const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex)));
aggregationObject = Buffer.from(hexToBytes(aggregationObjectHex));
proverId = Fr.fromString(proverIdHex);
proof = Proof.fromBuffer(Buffer.from(hexToBytes(proofHex)));
archiveRoot = Fr.fromString(archiveHex);

blockNumber = header.globalVariables.blockNumber.toBigInt();
if (blockNumber !== l2BlockNum) {
throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${blockNumber}`);
}
} else if (functionName === 'submitEpochRootProof') {
if (functionName === 'submitEpochRootProof') {
const [_epochSize, nestedArgs, _fees, aggregationObjectHex, proofHex] = args!;
aggregationObject = Buffer.from(hexToBytes(aggregationObjectHex));
proverId = Fr.fromString(nestedArgs[6]);
Expand Down
5 changes: 1 addition & 4 deletions yarn-project/bb-prover/src/honk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { type ProtocolArtifact } from '@aztec/noir-protocol-circuits-types';

export type UltraHonkFlavor = 'ultra_honk' | 'ultra_keccak_honk';

const UltraKeccakHonkCircuits = [
'BlockRootRollupFinalArtifact',
'RootRollupArtifact',
] as const satisfies ProtocolArtifact[];
const UltraKeccakHonkCircuits = ['RootRollupArtifact'] as const satisfies ProtocolArtifact[];
export type UltraKeccakHonkProtocolArtifact = (typeof UltraKeccakHonkCircuits)[number];
export type UltraHonkProtocolArtifact = Exclude<ProtocolArtifact, UltraKeccakHonkProtocolArtifact>;

Expand Down
26 changes: 0 additions & 26 deletions yarn-project/bb-prover/src/prover/bb_prover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,32 +406,6 @@ export class BBNativeRollupProver implements ServerCircuitProver {
return makePublicInputsAndRecursiveProof(circuitOutput, proof, verificationKey);
}

/**
* Simulates the block root rollup circuit from its inputs.
* Returns a non-recursive proof to verify on L1.
* @dev TODO(palla/prover): This is a temporary workaround to get the proof to L1 with the old block flow.
* @param input - Inputs to the circuit.
* @returns The public inputs as outputs of the simulation.
*/
public async getBlockRootRollupFinalProof(
input: BlockRootRollupInputs,
): Promise<PublicInputsAndRecursiveProof<BlockRootOrBlockMergePublicInputs>> {
const { circuitOutput, proof } = await this.createProof(
input,
'BlockRootRollupFinalArtifact',
convertBlockRootRollupInputsToWitnessMap,
convertBlockRootRollupOutputsFromWitnessMap,
);

const recursiveProof = makeRecursiveProofFromBinary(proof, NESTED_RECURSIVE_PROOF_LENGTH);

const verificationKey = await this.getVerificationKeyDataForCircuit('BlockRootRollupFinalArtifact');

await this.verifyProof('BlockRootRollupFinalArtifact', proof);

return makePublicInputsAndRecursiveProof(circuitOutput, recursiveProof, verificationKey);
}

/**
* Simulates the block merge rollup circuit from its inputs.
* @param input - Inputs to the circuit.
Expand Down
2 changes: 0 additions & 2 deletions yarn-project/bb-prover/src/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ export function mapProtocolArtifactNameToCircuitName(
return 'empty-nested';
case 'PrivateKernelEmptyArtifact':
return 'private-kernel-empty';
case 'BlockRootRollupFinalArtifact':
return 'block-root-rollup-final';
default: {
const _foo: never = artifact;
throw new Error(`Unknown circuit type: ${artifact}`);
Expand Down
Loading

0 comments on commit 7f94a33

Please sign in to comment.