diff --git a/.github/workflows/devnet-deploys.yml b/.github/workflows/devnet-deploys.yml index b08d25a0994..1749cb4c1fb 100644 --- a/.github/workflows/devnet-deploys.yml +++ b/.github/workflows/devnet-deploys.yml @@ -770,7 +770,7 @@ jobs: run: | ./.github/scripts/wait_for_infra.sh pxe ${{ env.DEPLOY_TAG }} ${{ env.API_KEY }} - - name: Deploy verifier (allow failure) + - name: Deploy verifier working-directory: ./yarn-project/aztec/terraform/pxe run: | set -eo pipefail diff --git a/yarn-project/end-to-end/package.local.json b/yarn-project/end-to-end/package.local.json index 62f136fa45d..a5214893419 100644 --- a/yarn-project/end-to-end/package.local.json +++ b/yarn-project/end-to-end/package.local.json @@ -5,4 +5,4 @@ "test": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", "test:unit": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest src/fixtures" } -} \ No newline at end of file +} diff --git a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts index 60d07291cc0..178d1c5bdc3 100644 --- a/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts +++ b/yarn-project/foundation/src/json-rpc/server/json_rpc_server.ts @@ -6,6 +6,7 @@ import compress from 'koa-compress'; import Router from 'koa-router'; import { createDebugLogger } from '../../log/index.js'; +import { promiseWithResolvers } from '../../promise/utils.js'; import { type JsonClassConverterInput, type StringClassConverterInput } from '../class_converter.js'; import { convertBigintsInObj } from '../convert.js'; import { type ClassMaps, JsonProxy } from './json_proxy.js'; @@ -19,6 +20,13 @@ export class JsonRpcServer { * The proxy object. */ public proxy: JsonProxy; + + /** + * The HTTP server accepting remote requests. + * This member field is initialized when the server is started. + */ + private httpServer?: http.Server; + constructor( private handler: object, private stringClassMap: StringClassConverterInput, @@ -141,9 +149,32 @@ export class JsonRpcServer { * @param port - Port number. * @param prefix - Prefix string. */ - public start(port: number, prefix = '') { - const httpServer = http.createServer(this.getApp(prefix).callback()); - httpServer.listen(port); + public start(port: number, prefix = ''): void { + if (this.httpServer) { + throw new Error('Server is already listening'); + } + + this.httpServer = http.createServer(this.getApp(prefix).callback()); + this.httpServer.listen(port); + } + + /** + * Stops the HTTP server + */ + public stop(): Promise { + if (!this.httpServer) { + return Promise.resolve(); + } + + const { promise, resolve, reject } = promiseWithResolvers(); + this.httpServer.close(err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + return promise; } /** diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index 6f451907c83..4171e53f781 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -80,6 +80,7 @@ "@types/memdown": "^3.0.0", "@types/node": "^18.7.23", "@types/source-map-support": "^0.5.10", + "get-port": "^7.1.0", "jest": "^29.5.0", "jest-mock-extended": "^3.0.3", "ts-node": "^10.9.1", diff --git a/yarn-project/prover-client/src/prover-agent/agent-queue-rpc-integration.test.ts b/yarn-project/prover-client/src/prover-agent/agent-queue-rpc-integration.test.ts new file mode 100644 index 00000000000..6d0b3be301d --- /dev/null +++ b/yarn-project/prover-client/src/prover-agent/agent-queue-rpc-integration.test.ts @@ -0,0 +1,87 @@ +import { PublicKernelType, type ServerCircuitProver } from '@aztec/circuit-types'; +import { ClientIvcProof, Fr, PrivateKernelEmptyInputData, TubeInputs } from '@aztec/circuits.js'; +import { + makeAvmCircuitInputs, + makeBaseParityInputs, + makeBaseRollupInputs, + makeBlockMergeRollupInputs, + makeBlockRootRollupInputs, + makeHeader, + makeMergeRollupInputs, + makePublicKernelCircuitPrivateInputs, + makePublicKernelTailCircuitPrivateInputs, + makeRootParityInputs, + makeRootRollupInputs, +} from '@aztec/circuits.js/testing'; +import { type JsonRpcServer } from '@aztec/foundation/json-rpc/server'; +import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; + +import getPort from 'get-port'; + +import { MockProver } from '../test/mock_prover.js'; +import { MemoryProvingQueue } from './memory-proving-queue.js'; +import { ProverAgent } from './prover-agent.js'; +import { createProvingJobSourceClient, createProvingJobSourceServer } from './rpc.js'; + +describe('Prover agent <-> queue integration', () => { + let queue: MemoryProvingQueue; + let queueRpcServer: JsonRpcServer; + let agent: ProverAgent; + let prover: ServerCircuitProver; + + type MakeInputs = { + [K in keyof ServerCircuitProver]: () => Parameters[0]; + }; + + const makeInputs: MakeInputs = { + getAvmProof: makeAvmCircuitInputs, + getBaseParityProof: makeBaseParityInputs, + getBaseRollupProof: makeBaseRollupInputs, + getRootParityProof: makeRootParityInputs, + getBlockMergeRollupProof: makeBlockMergeRollupInputs, + getBlockRootRollupProof: makeBlockRootRollupInputs, + getEmptyPrivateKernelProof: () => + new PrivateKernelEmptyInputData(makeHeader(), Fr.random(), Fr.random(), Fr.random()), + getEmptyTubeProof: () => new PrivateKernelEmptyInputData(makeHeader(), Fr.random(), Fr.random(), Fr.random()), + getMergeRollupProof: makeMergeRollupInputs, + getPublicKernelProof: () => { + return { + type: PublicKernelType.APP_LOGIC, + inputs: makePublicKernelCircuitPrivateInputs(), + }; + }, + getPublicTailProof: () => { + return { + type: PublicKernelType.TAIL, + inputs: makePublicKernelTailCircuitPrivateInputs(), + }; + }, + getRootRollupProof: makeRootRollupInputs, + getTubeProof: () => new TubeInputs(ClientIvcProof.empty()), + }; + + beforeEach(async () => { + prover = new MockProver(); + + queue = new MemoryProvingQueue(new NoopTelemetryClient(), 100, 10); + queue.start(); + const port = await getPort(); + queueRpcServer = createProvingJobSourceServer(queue); + queueRpcServer.start(port); + + agent = new ProverAgent(prover, 1, 10); + const queueRpcClient = createProvingJobSourceClient(`http://127.0.0.1:${port}`); + agent.start(queueRpcClient); + }); + + afterEach(async () => { + await agent.stop(); + await queueRpcServer.stop(); + await queue.stop(); + }); + + it.each(Object.entries(makeInputs))('can call %s over JSON-RPC', async (fnName, makeInputs) => { + const resp = await queue[fnName as keyof ServerCircuitProver](makeInputs() as any); + expect(resp).toBeDefined(); + }); +}); diff --git a/yarn-project/prover-client/src/prover-agent/rpc.ts b/yarn-project/prover-client/src/prover-agent/rpc.ts index 4474882f187..8b3e518328c 100644 --- a/yarn-project/prover-client/src/prover-agent/rpc.ts +++ b/yarn-project/prover-client/src/prover-agent/rpc.ts @@ -1,6 +1,7 @@ import { type ProvingJobSource } from '@aztec/circuit-types'; import { AvmCircuitInputs, + AvmVerificationKeyData, AztecAddress, BaseOrMergeRollupPublicInputs, BaseParityInputs, @@ -37,6 +38,7 @@ export function createProvingJobSourceServer(queue: ProvingJobSource): JsonRpcSe return new JsonRpcServer( queue, { + AvmVerificationKeyData, AvmCircuitInputs, BaseOrMergeRollupPublicInputs, BaseParityInputs, @@ -75,6 +77,7 @@ export function createProvingJobSourceClient( return createJsonRpcClient( url, { + AvmVerificationKeyData, AvmCircuitInputs, BaseOrMergeRollupPublicInputs, BaseParityInputs, diff --git a/yarn-project/prover-client/src/test/mock_prover.ts b/yarn-project/prover-client/src/test/mock_prover.ts new file mode 100644 index 00000000000..af54ea81fd0 --- /dev/null +++ b/yarn-project/prover-client/src/test/mock_prover.ts @@ -0,0 +1,148 @@ +import { + type PublicInputsAndRecursiveProof, + type PublicInputsAndTubeProof, + type ServerCircuitProver, + makePublicInputsAndRecursiveProof, +} from '@aztec/circuit-types'; +import { + AvmVerificationKeyData, + type BaseOrMergeRollupPublicInputs, + type BlockRootOrBlockMergePublicInputs, + type KernelCircuitPublicInputs, + type PublicKernelCircuitPublicInputs, + RECURSIVE_PROOF_LENGTH, + type RecursiveProof, + type RootRollupPublicInputs, + VerificationKeyData, + makeEmptyProof, + makeRecursiveProof, +} from '@aztec/circuits.js'; +import { + makeBaseOrMergeRollupPublicInputs, + makeBlockRootOrBlockMergeRollupPublicInputs, + makeKernelCircuitPublicInputs, + makePublicKernelCircuitPublicInputs, + makeRootParityInput, + makeRootRollupPublicInputs, +} from '@aztec/circuits.js/testing'; + +export class MockProver implements ServerCircuitProver { + constructor() {} + + getAvmProof() { + return Promise.resolve( + Promise.resolve({ + proof: makeEmptyProof(), + verificationKey: AvmVerificationKeyData.makeFake(), + }), + ); + } + + getBaseParityProof() { + return Promise.resolve(makeRootParityInput(RECURSIVE_PROOF_LENGTH)); + } + + getRootParityProof() { + return Promise.resolve(makeRootParityInput(RECURSIVE_PROOF_LENGTH)); + } + + getBaseRollupProof() { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeBaseOrMergeRollupPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getMergeRollupProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeBaseOrMergeRollupPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getBlockMergeRollupProof() { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeBlockRootOrBlockMergeRollupPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getBlockRootRollupProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeBlockRootOrBlockMergeRollupPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getEmptyPrivateKernelProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeKernelCircuitPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getEmptyTubeProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeKernelCircuitPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getPublicKernelProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makePublicKernelCircuitPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getPublicTailProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeKernelCircuitPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getRootRollupProof(): Promise> { + return Promise.resolve( + makePublicInputsAndRecursiveProof( + makeRootRollupPublicInputs(), + makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + VerificationKeyData.makeFake(), + ), + ); + } + + getTubeProof(): Promise<{ + tubeVK: VerificationKeyData; + tubeProof: RecursiveProof; + }> { + return Promise.resolve({ + tubeVK: VerificationKeyData.makeFake(), + tubeProof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + }); + } +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index beac450610c..8f923fdf239 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -945,6 +945,7 @@ __metadata: "@types/node": ^18.7.23 "@types/source-map-support": ^0.5.10 commander: ^12.1.0 + get-port: ^7.1.0 jest: ^29.5.0 jest-mock-extended: ^3.0.3 lodash.chunk: ^4.2.0