Skip to content

Commit

Permalink
Connect public kernel circuit and processor to sequencer (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
spalladino authored Apr 27, 2023
1 parent fd8da14 commit 12e44a2
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import {
BaseRollupInputs,
CircuitsWasm,
Fr,
PublicDataRead,
PublicDataWrite,
RootRollupPublicInputs,
UInt8Vector,
} from '@aztec/circuits.js';
import { computeContractLeaf } from '@aztec/circuits.js/abis';
import {
fr,
makeBaseRollupPublicInputs,
makeKernelPublicInputs,
makeNewContractData,
makeProof,
makeRootRollupPublicInputs,
} from '@aztec/circuits.js/factories';
import { toBufferBE } from '@aztec/foundation';
Expand All @@ -22,13 +26,13 @@ import { default as levelup } from 'levelup';
import flatMap from 'lodash.flatmap';
import times from 'lodash.times';
import { default as memdown, type MemDown } from 'memdown';
import { makeEmptyUnverifiedData } from '../mocks/tx.js';
import { makeEmptyUnverifiedData, makePublicTx } from '../mocks/tx.js';
import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js';
import { EmptyRollupProver } from '../prover/empty.js';
import { RollupProver } from '../prover/index.js';
import { ProcessedTx, makeEmptyProcessedTx, makeProcessedTx } from '../sequencer/processed_tx.js';
import { RollupSimulator } from '../simulator/index.js';
import { WasmCircuitSimulator } from '../simulator/wasm.js';
import { WasmRollupCircuitSimulator } from '../simulator/rollup.js';
import { CircuitBlockBuilder } from './circuit_block_builder.js';

export const createMemDown = () => (memdown as any)() as MemDown<any, any>;
Expand Down Expand Up @@ -197,19 +201,28 @@ describe('sequencer/circuit_block_builder', () => {

describe('circuits simulator', () => {
beforeEach(async () => {
const simulator = await WasmCircuitSimulator.new();
const simulator = await WasmRollupCircuitSimulator.new();
const prover = new EmptyRollupProver();
builder = new TestSubject(builderDb, vks, simulator, prover);
await builder.updateRootTrees();
});

const makeContractDeployTx = async (seed = 0x1) => {
const makeContractDeployProcessedTx = async (seed = 0x1) => {
const tx = await makeEmptyProcessedTx();
await setTxHistoricTreeRoots(tx);
tx.data.end.newContracts = [makeNewContractData(seed + 0x1000)];
return tx;
};

const makePublicCallProcessedTx = async (seed = 0x1) => {
const publicTx = makePublicTx(seed);
const tx = await makeProcessedTx(publicTx, makeKernelPublicInputs(seed), makeProof());
await setTxHistoricTreeRoots(tx);
tx.data.end.stateReads[0] = new PublicDataRead(fr(1), fr(0));
tx.data.end.stateTransitions[0] = new PublicDataWrite(fr(2), fr(0), fr(12));
return tx;
};

it.each([
[0, 4],
[1, 4],
Expand All @@ -222,7 +235,7 @@ describe('sequencer/circuit_block_builder', () => {
const contractTreeBefore = await builderDb.getTreeInfo(MerkleTreeId.CONTRACT_TREE);

const txs = [
...(await Promise.all(times(deployCount, makeContractDeployTx))),
...(await Promise.all(times(deployCount, makeContractDeployProcessedTx))),
...(await Promise.all(times(totalCount - deployCount, makeEmptyProcessedTx))),
];

Expand All @@ -243,9 +256,26 @@ describe('sequencer/circuit_block_builder', () => {
10000,
);

it('builds an L2 block with private and public txs', async () => {
const txs = await Promise.all([
makeContractDeployProcessedTx(),
makePublicCallProcessedTx(),
makeEmptyProcessedTx(),
makeEmptyProcessedTx(),
]);

const [l2Block] = await builder.buildL2Block(blockNumber, txs);
expect(l2Block.number).toEqual(blockNumber);

// TODO: Check that l2 block got the new state transitions once we merge
// https://github.com/AztecProtocol/aztec3-packages/pull/360

await updateExpectedTreesFromTxs(txs);
});

// This test specifically tests nullifier values which previously caused e2e_zk_token test to fail
it('e2e edge case - regression test', async () => {
const simulator = await WasmCircuitSimulator.new();
it('e2e_zk_token edge case regression test on nullifier values', async () => {
const simulator = await WasmRollupCircuitSimulator.new();
const prover = new EmptyRollupProver();
builder = new TestSubject(builderDb, vks, simulator, prover);
// update the starting tree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
RollupTypes,
RootRollupInputs,
RootRollupPublicInputs,
STATE_TRANSITIONS_LENGTH,
UInt8Vector,
VK_TREE_HEIGHT,
VerificationKey,
Expand Down Expand Up @@ -253,6 +252,7 @@ export class CircuitBlockBuilder implements BlockBuilder {
this.validateTree(rollupOutput, MerkleTreeId.CONTRACT_TREE, 'Contract'),
this.validateTree(rollupOutput, MerkleTreeId.PRIVATE_DATA_TREE, 'PrivateData'),
this.validateTree(rollupOutput, MerkleTreeId.NULLIFIER_TREE, 'Nullifier'),
this.validateTree(rollupOutput, MerkleTreeId.PUBLIC_DATA_TREE, 'PublicData'),
]);
}

Expand Down Expand Up @@ -280,7 +280,7 @@ export class CircuitBlockBuilder implements BlockBuilder {
protected async validateTree(
output: BaseOrMergeRollupPublicInputs | RootRollupPublicInputs,
treeId: MerkleTreeId,
name: 'PrivateData' | 'Contract' | 'Nullifier',
name: 'PrivateData' | 'Contract' | 'Nullifier' | 'PublicData',
) {
const localTree = await this.getTreeSnapshot(treeId);
const simulatedTree = output[`end${name}TreeSnapshot`];
Expand All @@ -291,13 +291,15 @@ export class CircuitBlockBuilder implements BlockBuilder {
protected validateSimulatedTree(
localTree: AppendOnlyTreeSnapshot,
simulatedTree: AppendOnlyTreeSnapshot,
name: string,
name: 'PrivateData' | 'Contract' | 'Nullifier' | 'PublicData',
label?: string,
) {
if (!simulatedTree.root.toBuffer().equals(localTree.root.toBuffer())) {
throw new Error(`${label ?? name} tree root mismatch (local ${localTree.root}, simulated ${simulatedTree.root})`);
}
if (simulatedTree.nextAvailableLeafIndex !== localTree.nextAvailableLeafIndex) {
// Public data tree is sparse, so the "next available leaf index" doesn't make sense there
// We'll eventually drop it, see https://github.com/AztecProtocol/aztec3-packages/issues/379
if (name !== 'PublicData' && simulatedTree.nextAvailableLeafIndex !== localTree.nextAvailableLeafIndex) {
throw new Error(
`${label ?? name} tree next available leaf index mismatch (local ${
localTree.nextAvailableLeafIndex
Expand Down
15 changes: 7 additions & 8 deletions yarn-project/sequencer-client/src/client/sequencer-client.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { P2P } from '@aztec/p2p';
import { WorldStateSynchroniser } from '@aztec/world-state';

import { ContractDataSource } from '@aztec/types';
import { CircuitBlockBuilder } from '../block_builder/circuit_block_builder.js';
import { SequencerClientConfig } from '../config.js';
import { getL1Publisher, getVerificationKeys, Sequencer } from '../index.js';
import { EmptyPublicProver, EmptyRollupProver } from '../prover/empty.js';
import { MockPublicProcessor } from '../sequencer/public_processor.js';
import { PublicProcessor } from '../sequencer/public_processor.js';
import { FakePublicCircuitSimulator } from '../simulator/fake_public.js';
import { MockPublicKernelCircuitSimulator } from '../simulator/mock_public_kernel.js';
import { WasmCircuitSimulator } from '../simulator/wasm.js';
import { ContractDataSource } from '@aztec/types';
import { WasmPublicKernelCircuitSimulator } from '../simulator/public_kernel.js';
import { WasmRollupCircuitSimulator } from '../simulator/rollup.js';

/**
* Encapsulates the full sequencer and publisher.
Expand All @@ -29,15 +29,14 @@ export class SequencerClient {
const blockBuilder = new CircuitBlockBuilder(
merkleTreeDb,
getVerificationKeys(),
await WasmCircuitSimulator.new(),
await WasmRollupCircuitSimulator.new(),
new EmptyRollupProver(),
);

// TODO: Swap with actual processor once the integration is good to go
const publicProcessor = new MockPublicProcessor(
const publicProcessor = new PublicProcessor(
merkleTreeDb,
new FakePublicCircuitSimulator(merkleTreeDb),
new MockPublicKernelCircuitSimulator(),
new WasmPublicKernelCircuitSimulator(),
new EmptyPublicProver(),
contractDataSource,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { PUBLIC_DATA_TREE_HEIGHT, makeEmptyProof } from '@aztec/circuits.js';
import { makeKernelPublicInputs, makePublicCircuitPublicInputs } from '@aztec/circuits.js/factories';
import { SiblingPath } from '@aztec/merkle-tree';
import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state';
import { CompleteContractData, ContractData, ContractDataSource, EncodedContractFunction } from '@aztec/types';
import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state';
import { jest } from '@jest/globals';
import { MockProxy, mock } from 'jest-mock-extended';
import pick from 'lodash.pick';
import times from 'lodash.times';
import { makePrivateTx, makePublicTx } from '../index.js';
import { Proof, PublicProver } from '../prover/index.js';
import { PublicCircuitSimulator, PublicKernelCircuitSimulator } from '../simulator/index.js';
import { WasmPublicKernelCircuitSimulator } from '../simulator/public_kernel.js';
import { PublicProcessor } from './public_processor.js';

describe('public_processor', () => {
Expand Down Expand Up @@ -65,7 +67,7 @@ describe('public_processor', () => {
expect(failed).toEqual([tx]);
});

it('runs a public tx through the public and public kernel circuits', async function () {
it('runs a public tx through mock circuits', async function () {
const publicCircuitOutput = makePublicCircuitPublicInputs();
publicCircuit.publicCircuit.mockResolvedValue(publicCircuitOutput);

Expand All @@ -85,4 +87,27 @@ describe('public_processor', () => {
expect(publicCircuit.publicCircuit).toHaveBeenCalled();
expect(publicKernel.publicKernelCircuitNoInput).toHaveBeenCalled();
});

it('runs a public tx through the actual public kernel circuit', async function () {
const publicKernel = new WasmPublicKernelCircuitSimulator();
const publicKernelSpy = jest.spyOn(publicKernel, 'publicKernelCircuitNoInput');
processor = new PublicProcessor(db, publicCircuit, publicKernel, publicProver, contractDataSource);

const publicCircuitOutput = makePublicCircuitPublicInputs();
publicCircuit.publicCircuit.mockResolvedValue(publicCircuitOutput);

const path = times(PUBLIC_DATA_TREE_HEIGHT, i => Buffer.alloc(32, i));
db.getSiblingPath.mockResolvedValue(new SiblingPath(path));

const tx = makePublicTx();
const hash = await tx.getTxHash();
const [processed, failed] = await processor.process([tx]);

expect(processed[0].data.isPrivateKernel).toBeFalsy();
expect(processed).toEqual([expect.objectContaining({ hash, proof, ...pick(tx, 'txRequest') })]);
expect(failed).toEqual([]);

expect(publicCircuit.publicCircuit).toHaveBeenCalled();
expect(publicKernelSpy).toHaveBeenCalled();
});
});
4 changes: 2 additions & 2 deletions yarn-project/sequencer-client/src/sequencer/sequencer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import times from 'lodash.times';
import { RunningPromise, createDebugLogger } from '@aztec/foundation';
import { P2P } from '@aztec/p2p';
import { CompleteContractData, ContractData, PrivateTx, PublicTx, Tx, UnverifiedData, isPrivateTx } from '@aztec/types';
import { ContractData, PrivateTx, PublicTx, Tx, UnverifiedData, isPrivateTx } from '@aztec/types';
import { MerkleTreeId, WorldStateStatus, WorldStateSynchroniser } from '@aztec/world-state';
import times from 'lodash.times';
import { BlockBuilder } from '../block_builder/index.js';
import { L1Publisher } from '../publisher/l1-publisher.js';
import { ceilPowerOfTwo } from '../utils.js';
Expand Down
14 changes: 0 additions & 14 deletions yarn-project/sequencer-client/src/simulator/mock_public_kernel.ts

This file was deleted.

22 changes: 22 additions & 0 deletions yarn-project/sequencer-client/src/simulator/public_kernel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
PublicKernelInputs,
PublicKernelInputsNoPreviousKernel,
PublicKernelPublicInputs,
simulatePublicKernelCircuit,
simulatePublicKernelCircuitNoPreviousKernel,
} from '@aztec/circuits.js';
import { PublicKernelCircuitSimulator } from './index.js';

export class WasmPublicKernelCircuitSimulator implements PublicKernelCircuitSimulator {
publicKernelCircuitNoInput(inputs: PublicKernelInputsNoPreviousKernel): Promise<PublicKernelPublicInputs> {
return simulatePublicKernelCircuitNoPreviousKernel(inputs);
}
publicKernelCircuitPrivateInput(inputs: PublicKernelInputs): Promise<PublicKernelPublicInputs> {
if (!inputs.previousKernel.publicInputs.isPrivateKernel) throw new Error(`Expected private kernel previous inputs`);
return simulatePublicKernelCircuit(inputs);
}
publicKernelCircuitNonFirstIteration(inputs: PublicKernelInputs): Promise<PublicKernelPublicInputs> {
if (inputs.previousKernel.publicInputs.isPrivateKernel) throw new Error(`Expected public kernel previous inputs`);
return simulatePublicKernelCircuit(inputs);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@aztec/circuits.js';
import { RollupSimulator } from './index.js';

export class WasmCircuitSimulator implements RollupSimulator {
export class WasmRollupCircuitSimulator implements RollupSimulator {
private rollupWasmWrapper: RollupWasmWrapper;

constructor(wasm: CircuitsWasm) {
Expand Down

0 comments on commit 12e44a2

Please sign in to comment.