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

Connect public kernel circuit and processor to sequencer #394

Merged
merged 1 commit into from
Apr 27, 2023
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
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