Skip to content

Commit

Permalink
feat: Remove proof from L1 Rollup process (#7347)
Browse files Browse the repository at this point in the history
Moves the proof verification from `Rollup.process` and into a new
`submitProof` method, called separately from the sequencer. Eventually
we'll want to move it out of the sequencer completely, but this way we
don't break the current e2e flow.

See #7346
  • Loading branch information
spalladino authored Jul 10, 2024
1 parent db96077 commit 2645eab
Show file tree
Hide file tree
Showing 18 changed files with 232 additions and 153 deletions.
63 changes: 34 additions & 29 deletions l1-contracts/src/core/Rollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,8 @@ contract Rollup is IRollup {
* @notice Process an incoming L2 block and progress the state
* @param _header - The L2 block header
* @param _archive - A root of the archive tree after the L2 block is applied
* @param _proof - The proof of correct execution
*/
function process(
bytes calldata _header,
bytes32 _archive,
bytes calldata _aggregationObject,
bytes calldata _proof
) external override(IRollup) {
function process(bytes calldata _header, bytes32 _archive) external override(IRollup) {
// Decode and validate header
HeaderLib.Header memory header = HeaderLib.decode(_header);
HeaderLib.validate(header, VERSION, lastBlockTs, archive);
Expand All @@ -124,6 +118,38 @@ contract Rollup is IRollup {
revert Errors.Rollup__InvalidSequencer(msg.sender);
}

archive = _archive;
lastBlockTs = block.timestamp;

bytes32 inHash = INBOX.consume();
if (header.contentCommitment.inHash != inHash) {
revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash);
}

// TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim
// Min size = smallest path of the rollup tree + 1
(uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs);
uint256 l2ToL1TreeMinHeight = min + 1;
OUTBOX.insert(
header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight
);

// pay the coinbase 1 gas token if it is not empty and header.totalFees is not zero
if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) {
GAS_TOKEN.transfer(address(header.globalVariables.coinbase), header.totalFees);
}

emit L2BlockProcessed(header.globalVariables.blockNumber);
}

function submitProof(
bytes calldata _header,
bytes32 _archive,
bytes calldata _aggregationObject,
bytes calldata _proof
) external override(IRollup) {
HeaderLib.Header memory header = HeaderLib.decode(_header);

bytes32[] memory publicInputs =
new bytes32[](3 + Constants.HEADER_LENGTH + Constants.AGGREGATION_OBJECT_LENGTH);
// the archive tree root
Expand Down Expand Up @@ -156,28 +182,7 @@ contract Rollup is IRollup {
revert Errors.Rollup__InvalidProof();
}

archive = _archive;
lastBlockTs = block.timestamp;

bytes32 inHash = INBOX.consume();
if (header.contentCommitment.inHash != inHash) {
revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash);
}

// TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim
// Min size = smallest path of the rollup tree + 1
(uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs);
uint256 l2ToL1TreeMinHeight = min + 1;
OUTBOX.insert(
header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight
);

// pay the coinbase 1 gas token if it is not empty and header.totalFees is not zero
if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) {
GAS_TOKEN.transfer(address(header.globalVariables.coinbase), header.totalFees);
}

emit L2BlockProcessed(header.globalVariables.blockNumber);
emit L2ProofVerified(header.globalVariables.blockNumber);
}

function _computePublicInputHash(bytes calldata _header, bytes32 _archive)
Expand Down
7 changes: 5 additions & 2 deletions l1-contracts/src/core/interfaces/IRollup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ pragma solidity >=0.8.18;

interface IRollup {
event L2BlockProcessed(uint256 indexed blockNumber);
event L2ProofVerified(uint256 indexed blockNumber);

function process(
function process(bytes calldata _header, bytes32 _archive) external;

function submitProof(
bytes calldata _header,
bytes32 _archive,
bytes calldata _aggregationObject,
bytes memory _proof
bytes calldata _proof
) external;

function setVerifier(address _verifier) external;
Expand Down
10 changes: 5 additions & 5 deletions l1-contracts/test/Rollup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ contract RollupTest is DecoderBase {
availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337));
rollup.process(header, archive, bytes(""), bytes(""));
rollup.process(header, archive);
}

function testRevertInvalidVersion() public {
Expand All @@ -101,7 +101,7 @@ contract RollupTest is DecoderBase {
availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1));
rollup.process(header, archive, bytes(""), bytes(""));
rollup.process(header, archive);
}

function testRevertTimestampInFuture() public {
Expand All @@ -118,7 +118,7 @@ contract RollupTest is DecoderBase {
availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector));
rollup.process(header, archive, bytes(""), bytes(""));
rollup.process(header, archive);
}

function testRevertTimestampTooOld() public {
Expand All @@ -133,7 +133,7 @@ contract RollupTest is DecoderBase {
availabilityOracle.publish(body);

vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector));
rollup.process(header, archive, bytes(""), bytes(""));
rollup.process(header, archive);
}

function _testBlock(string memory name) public {
Expand All @@ -153,7 +153,7 @@ contract RollupTest is DecoderBase {
uint256 toConsume = inbox.toConsume();

vm.record();
rollup.process(header, archive, bytes(""), bytes(""));
rollup.process(header, archive);

assertEq(inbox.toConsume(), toConsume + 1, "Message subtree not consumed");

Expand Down
9 changes: 2 additions & 7 deletions yarn-project/accounts/package.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,5 @@
"build:ts": "tsc -b",
"clean": "rm -rf ./dest .tsbuildinfo ./artifacts"
},
"files": [
"dest",
"src",
"artifacts",
"!*.test.*"
]
}
"files": ["dest", "src", "artifacts", "!*.test.*"]
}
4 changes: 1 addition & 3 deletions yarn-project/archiver/src/archiver/archiver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,12 +248,10 @@ function makeMessageSentEvent(l1BlockNum: bigint, l2BlockNumber: bigint, index:
function makeRollupTx(l2Block: L2Block) {
const header = toHex(l2Block.header.toBuffer());
const archive = toHex(l2Block.archive.root.toBuffer());
const aggregationObject = `0x`;
const proof = `0x`;
const input = encodeFunctionData({
abi: RollupAbi,
functionName: 'process',
args: [header, archive, aggregationObject, proof],
args: [header, archive],
});
return { input } as Transaction<bigint, number>;
}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/archiver/src/archiver/eth_log_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async function getBlockMetadataFromRollupTx(
if (functionName !== 'process') {
throw new Error(`Unexpected method called ${functionName}`);
}
const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex, Hex, Hex];
const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex];

const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex)));

Expand Down
22 changes: 17 additions & 5 deletions yarn-project/circuit-types/src/stats/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ export type L2BlockStats = {
unencryptedLogSize?: number;
};

/** Stats logged for each L1 rollup publish tx.*/
/** Stats logged for each L1 publish tx.*/
export type L1PublishStats = {
/** Name of the event for metrics purposes */
eventName: 'rollup-published-to-l1';
/** Effective gas price of the tx. */
gasPrice: bigint;
/** Effective gas used in the tx. */
Expand All @@ -40,7 +38,20 @@ export type L1PublishStats = {
calldataGas: number;
/** Size in bytes of the calldata. */
calldataSize: number;
} & L2BlockStats;
};

/** Stats logged for each L1 rollup publish tx.*/
export type L1PublishBlockStats = {
/** Name of the event for metrics purposes */
eventName: 'rollup-published-to-l1';
} & L1PublishStats &
L2BlockStats;

/** Stats logged for each L1 rollup publish tx.*/
export type L1PublishProofStats = {
/** Name of the event for metrics purposes */
eventName: 'proof-published-to-l1';
} & L1PublishStats;

/** Stats logged for synching node chain history. */
export type NodeSyncedChainHistoryStats = {
Expand Down Expand Up @@ -271,7 +282,8 @@ export type Stats =
| CircuitSimulationStats
| CircuitWitnessGenerationStats
| PublicDBAccessStats
| L1PublishStats
| L1PublishBlockStats
| L1PublishProofStats
| L2BlockBuiltStats
| L2BlockHandledStats
| NodeSyncedChainHistoryStats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ import {
MAX_NULLIFIERS_PER_TX,
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
type Proof,
PublicDataUpdateRequest,
makeEmptyProof,
} from '@aztec/circuits.js';
import { fr, makeProof } from '@aztec/circuits.js/testing';
import { type L1ContractAddresses, createEthereumChain } from '@aztec/ethereum';
Expand Down Expand Up @@ -89,7 +87,6 @@ describe('L1Publisher integration', () => {
let outbox: GetContractReturnType<typeof OutboxAbi, PublicClient<HttpTransport, Chain>>;

let publisher: L1Publisher;
let l2Proof: Proof;

let builder: TxProver;
let builderDb: MerkleTrees;
Expand Down Expand Up @@ -147,7 +144,6 @@ describe('L1Publisher integration', () => {
const worldStateSynchronizer = new ServerWorldStateSynchronizer(tmpStore, builderDb, blockSource, worldStateConfig);
await worldStateSynchronizer.start();
builder = await TxProver.new(config, worldStateSynchronizer, new NoopTelemetryClient());
l2Proof = makeEmptyProof();

publisher = getL1Publisher({
rpcUrl: config.rpcUrl,
Expand Down Expand Up @@ -411,7 +407,7 @@ describe('L1Publisher integration', () => {

writeJson(`mixed_block_${i}`, block, l1ToL2Content, recipientAddress, deployerAccount.address);

await publisher.processL2Block(block, [], l2Proof);
await publisher.processL2Block(block);

const logs = await publicClient.getLogs({
address: rollupAddress,
Expand All @@ -431,12 +427,7 @@ describe('L1Publisher integration', () => {
const expectedData = encodeFunctionData({
abi: RollupAbi,
functionName: 'process',
args: [
`0x${block.header.toBuffer().toString('hex')}`,
`0x${block.archive.root.toBuffer().toString('hex')}`,
`0x`, // empty aggregation object
`0x${l2Proof.withoutPublicInputs().toString('hex')}`,
],
args: [`0x${block.header.toBuffer().toString('hex')}`, `0x${block.archive.root.toBuffer().toString('hex')}`],
});
expect(ethTx.input).toEqual(expectedData);

Expand Down Expand Up @@ -501,7 +492,7 @@ describe('L1Publisher integration', () => {

writeJson(`empty_block_${i}`, block, [], AztecAddress.ZERO, deployerAccount.address);

await publisher.processL2Block(block, [], l2Proof);
await publisher.processL2Block(block);

const logs = await publicClient.getLogs({
address: rollupAddress,
Expand All @@ -521,12 +512,7 @@ describe('L1Publisher integration', () => {
const expectedData = encodeFunctionData({
abi: RollupAbi,
functionName: 'process',
args: [
`0x${block.header.toBuffer().toString('hex')}`,
`0x${block.archive.root.toBuffer().toString('hex')}`,
`0x`, // empty aggregation object
`0x${l2Proof.withoutPublicInputs().toString('hex')}`,
],
args: [`0x${block.header.toBuffer().toString('hex')}`, `0x${block.archive.root.toBuffer().toString('hex')}`],
});
expect(ethTx.input).toEqual(expectedData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ describe('proof_verification', () => {
`0x${proof.withoutPublicInputs().toString('hex')}`,
] as const;

await expect(rollupContract.write.process(args)).resolves.toBeDefined();
await expect(rollupContract.write.submitProof(args)).resolves.toBeDefined();
});
});
});
9 changes: 2 additions & 7 deletions yarn-project/noir-protocol-circuits-types/package.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,5 @@
"build": "yarn clean && yarn generate && tsc -b",
"clean": "rm -rf ./dest .tsbuildinfo src/types artifacts"
},
"files": [
"dest",
"src",
"artifacts",
"!*.test.*"
]
}
"files": ["dest", "src", "artifacts", "!*.test.*"]
}
9 changes: 2 additions & 7 deletions yarn-project/protocol-contracts/package.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,5 @@
"build:ts": "tsc -b",
"clean": "rm -rf ./dest .tsbuildinfo ./artifacts"
},
"files": [
"dest",
"src",
"artifacts",
"!*.test.*"
]
}
"files": ["dest", "src", "artifacts", "!*.test.*"]
}
4 changes: 2 additions & 2 deletions yarn-project/scripts/src/benchmarks/aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
type CircuitProvingStats,
type CircuitSimulationStats,
type CircuitWitnessGenerationStats,
type L1PublishStats,
type L1PublishBlockStats,
type L2BlockBuiltStats,
type L2BlockHandledStats,
type MetricName,
Expand Down Expand Up @@ -87,7 +87,7 @@ function processAcirProofGenerated(entry: ProofConstructed, results: BenchmarkCo
}

/** Processes an entry with event name 'rollup-published-to-l1' and updates results */
function processRollupPublished(entry: L1PublishStats, results: BenchmarkCollectedResults) {
function processRollupPublished(entry: L1PublishBlockStats, results: BenchmarkCollectedResults) {
const bucket = entry.txCount;
if (!BENCHMARK_BLOCK_SIZES.includes(bucket)) {
return;
Expand Down
Loading

0 comments on commit 2645eab

Please sign in to comment.