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

chore: Remove single block proving #8856

Merged
merged 5 commits into from
Sep 27, 2024
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
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
Loading