From 9fbde32027bfb19ee8323b756f72090474f7afe8 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 08:53:34 +0000 Subject: [PATCH 01/13] feat(acir): added skeleton for acir sim --- yarn-project/acir-simulator/.eslintrc.cjs | 15 ++ yarn-project/acir-simulator/src/acvm.ts | 31 +++ yarn-project/acir-simulator/src/circuits.ts | 179 ++++++++++++++++++ yarn-project/acir-simulator/src/db_oracle.ts | 16 ++ yarn-project/acir-simulator/src/foundation.ts | 12 ++ yarn-project/acir-simulator/src/index.ts | 5 +- yarn-project/acir-simulator/src/simulator.ts | 71 +++++++ 7 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 yarn-project/acir-simulator/src/acvm.ts create mode 100644 yarn-project/acir-simulator/src/circuits.ts create mode 100644 yarn-project/acir-simulator/src/db_oracle.ts create mode 100644 yarn-project/acir-simulator/src/foundation.ts create mode 100644 yarn-project/acir-simulator/src/simulator.ts diff --git a/yarn-project/acir-simulator/.eslintrc.cjs b/yarn-project/acir-simulator/.eslintrc.cjs index 9cf806b1500f..333ff38eab81 100644 --- a/yarn-project/acir-simulator/.eslintrc.cjs +++ b/yarn-project/acir-simulator/.eslintrc.cjs @@ -3,4 +3,19 @@ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@aztec/eslint-config'], parserOptions: { tsconfigRootDir: __dirname }, + rules: { + 'tsdoc/syntax': 'off', + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-description': 'off', + 'jsdoc/require-description-complete-sentence': 'off', + 'jsdoc/require-hyphen-before-param-description': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-param-name': 'off', + 'jsdoc/require-property': 'off', + 'jsdoc/require-property-description': 'off', + 'jsdoc/require-property-name': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-returns-description': 'off', + }, }; diff --git a/yarn-project/acir-simulator/src/acvm.ts b/yarn-project/acir-simulator/src/acvm.ts new file mode 100644 index 000000000000..5b04ff54209e --- /dev/null +++ b/yarn-project/acir-simulator/src/acvm.ts @@ -0,0 +1,31 @@ +import { AztecAddress, CallContext, ContractDeploymentData } from './circuits.js'; +import { NoteLoadOracleInputs } from './db_oracle.js'; + +interface ACIRCallback { + getSecretKey(keyId: Buffer): Promise; + getNotes(storageSlot: Buffer): Promise; + getRandomField(): Promise; + privateFunctionCall( + contractAddress: AztecAddress, + functionSelector: string, + args: Array, + ): Promise>; +} + +export interface ExecutionPreimages { + newNotes: Buffer[]; + nullifiedNotes: Buffer[]; +} + +interface Executionresult { + preimages: ExecutionPreimages; + partialWitness: Buffer; +} + +export type execute = ( + acir: Buffer, + args: Array, + callContext: CallContext, + contractDeploymentData: ContractDeploymentData, + oracle: ACIRCallback, +) => Promise; diff --git a/yarn-project/acir-simulator/src/circuits.ts b/yarn-project/acir-simulator/src/circuits.ts new file mode 100644 index 000000000000..a067525a6dc2 --- /dev/null +++ b/yarn-project/acir-simulator/src/circuits.ts @@ -0,0 +1,179 @@ +import { randomBytes } from './foundation.js'; + +// See aztec3/constants.hpp +// Copied here for prototyping purposes +// In future: structured serialization? +export const ARGS_LENGTH = 8; +export const RETURN_VALUES_LENGTH = 4; +export const EMITTED_EVENTS_LENGTH = 4; + +export const NEW_COMMITMENTS_LENGTH = 4; +export const NEW_NULLIFIERS_LENGTH = 4; + +export const STATE_TRANSITIONS_LENGTH = 4; +export const STATE_READS_LENGTH = 4; + +export const PRIVATE_CALL_STACK_LENGTH = 4; +export const PUBLIC_CALL_STACK_LENGTH = 4; +export const L1_MSG_STACK_LENGTH = 2; + +export const KERNEL_NEW_COMMITMENTS_LENGTH = 16; +export const KERNEL_NEW_NULLIFIERS_LENGTH = 16; +export const KERNEL_NEW_CONTRACTS_LENGTH = 8; +export const KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +export const KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +export const KERNEL_L1_MSG_STACK_LENGTH = 4; +export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +export const VK_TREE_HEIGHT = 3; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; + +export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + +export const FUNCTION_SELECTOR_NUM_BYTES = 31; + +/** + * Assert a member is a certain length. + * @param obj - An object. + * @param member - A member string. + * @param length - The length. + */ +export function assertLength( + obj: T, + member: F, + length: number, +) { + if (obj[member].length !== length) { + throw new Error(`Expected ${member} to have length ${length}! Was: ${obj[member].length}`); + } +} + +export class Fr { + public static ZERO = new Fr(Buffer.alloc(32)); + + public static random() { + return new Fr(randomBytes(32)); + } + + constructor(public readonly buffer: Buffer) {} +} + +export class AztecAddress { + public static SIZE = 64; + + public static ZERO = new AztecAddress(Buffer.alloc(AztecAddress.SIZE)); + + public static random() { + return new AztecAddress(randomBytes(AztecAddress.SIZE)); + } + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: AztecAddress) { + return this.buffer.equals(rhs.buffer); + } +} + +export class EthAddress { + public static ZERO = new EthAddress(Buffer.alloc(20)); + + public static random() { + return new EthAddress(randomBytes(20)); + } + + constructor(public readonly buffer: Buffer) {} +} + +/** + * Call context. + * @see abis/call_context.hpp + */ +export class CallContext { + constructor( + public msgSender: AztecAddress, + public storageContractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public isDelegateCall: boolean, + public isStaticCall: boolean, + public isContractDeployment: boolean, + ) {} +} + +/** + * Contract deployment data in a @TxContext. + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ +export class ContractDeploymentData { + constructor( + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, + ) {} +} + +/** + * Public inputs to a private circuit. + * @see abis/private_circuit_public_inputs.hpp. + */ +export class PrivateCircuitPublicInputs { + constructor( + // NOTE: Must have same order as CPP. + public callContext: CallContext, + public args: Fr[], + public returnValues: Fr[], + public emittedEvents: Fr[], + public newCommitments: Fr[], + public newNullifiers: Fr[], + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + public historicPrivateDataTreeRoot: Fr, + public historicPrivateNullifierTreeRoot: Fr, + public historicContractTreeRoot: Fr, + public contractDeploymentData: ContractDeploymentData, + ) { + assertLength(this, 'args', ARGS_LENGTH); + assertLength(this, 'returnValues', RETURN_VALUES_LENGTH); + assertLength(this, 'emittedEvents', EMITTED_EVENTS_LENGTH); + assertLength(this, 'newCommitments', NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', L1_MSG_STACK_LENGTH); + } +} + +export class TxContext { + constructor( + public readonly isFeePaymentTx: boolean, + public readonly isRebatePaymentTx: boolean, + public readonly isContractDeploymentTx: boolean, + public readonly contractDeploymentData: ContractDeploymentData, + ) {} +} + +export interface FunctionData { + functionSelector: Buffer; + isSecret: boolean; + isContructor: boolean; +} + +export class TxRequest { + constructor( + public readonly from: AztecAddress, + public readonly to: AztecAddress, + public readonly functionData: FunctionData, + public readonly args: Fr[], + public readonly txContext: TxContext, + public readonly nonce: Fr, + public readonly chainId: Fr, + ) {} + + toBuffer() { + return Buffer.alloc(0); + } +} diff --git a/yarn-project/acir-simulator/src/db_oracle.ts b/yarn-project/acir-simulator/src/db_oracle.ts new file mode 100644 index 000000000000..ae006a01f950 --- /dev/null +++ b/yarn-project/acir-simulator/src/db_oracle.ts @@ -0,0 +1,16 @@ +import { AztecAddress, EthAddress } from './circuits.js'; + +export interface NoteLoadOracleInputs { + note: Buffer; + siblingPath: Buffer; + leafIndex: number; + root: Buffer; +} + +export interface DBOracle { + getSecretKey(contractAddress: AztecAddress, keyId: Buffer): Promise; + getNotes(contractAddress: AztecAddress, storageSlot: Buffer): Promise; + getBytecode(contractAddress: AztecAddress, functionSelector: string): Promise; + getProvingKey(contractAddress: AztecAddress, functionSelector: string): Promise; + getPortalContractAddress(contractAddress: AztecAddress): Promise; +} diff --git a/yarn-project/acir-simulator/src/foundation.ts b/yarn-project/acir-simulator/src/foundation.ts new file mode 100644 index 000000000000..aa664f0d46f3 --- /dev/null +++ b/yarn-project/acir-simulator/src/foundation.ts @@ -0,0 +1,12 @@ +import nodeCrypto from 'crypto'; +import { Keccak } from 'sha3'; + +export const randomBytes = (len: number) => { + return nodeCrypto.randomBytes(len) as Buffer; +}; + +export function keccak256(input: Buffer | string) { + const inputBuf = typeof input === 'string' ? Buffer.from(input) : input; + const hash = new Keccak(256); + return hash.update(inputBuf).digest(); +} diff --git a/yarn-project/acir-simulator/src/index.ts b/yarn-project/acir-simulator/src/index.ts index e517e3e3ac0a..e660e82c1b4a 100644 --- a/yarn-project/acir-simulator/src/index.ts +++ b/yarn-project/acir-simulator/src/index.ts @@ -1,4 +1 @@ -/** - * A placeholder for the Acir Simulator. - */ -export class AcirSimulator {} +export * from './simulator.js'; diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts new file mode 100644 index 000000000000..66b83566ae29 --- /dev/null +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -0,0 +1,71 @@ +import { execute, ExecutionPreimages } from './acvm.js'; +import { CallContext, PrivateCircuitPublicInputs, TxRequest, Fr, EthAddress } from './circuits.js'; +import { DBOracle } from './db_oracle.js'; + +export interface ExecutionResult { + // Needed for prover + acir: Buffer; + partialWitness: Buffer; + // Needed for the verifier (kernel) + publicInputs: PrivateCircuitPublicInputs; + // Needed for the user + preimages: ExecutionPreimages; + // Nested executions + nestedExecutions: ExecutionResult[]; +} + +export interface HistoricRoots { + historicPrivateDataTreeRoot: Fr; + historicPrivateNullifierTreeRoot: Fr; + historicContractTreeRoot: Fr; +} + +/** + * A placeholder for the Acir Simulator. + */ +export class AcirSimulator { + constructor(private dbOracle: DBOracle, private acvmExecute: execute) {} + + run( + request: TxRequest, + entryPointACIR: Buffer, + portalContractAddress: EthAddress, + historicRoots: HistoricRoots, + ): Promise { + const callContext = new CallContext( + request.from, + request.to, + portalContractAddress, + false, + false, + request.functionData.isContructor, + ); + + const publicInputs = new PrivateCircuitPublicInputs( + callContext, + request.args, + [], // returnValues, + [], // emittedEvents, + [], // newCommitments, + [], // newNullifiers, + [], // privateCallStack, + [], // publicCallStack, + [], // l1MsgStack, + historicRoots.historicPrivateDataTreeRoot, + historicRoots.historicPrivateNullifierTreeRoot, + historicRoots.historicContractTreeRoot, + request.txContext.contractDeploymentData, + ); + + return Promise.resolve({ + acir: entryPointACIR, + partialWitness: Buffer.alloc(0), + publicInputs: publicInputs, + preimages: { + newNotes: [], + nullifiedNotes: [], + }, + nestedExecutions: [], + }); + } +} From d5e66253d05d54b51f39c940969239276d766574 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 09:16:10 +0000 Subject: [PATCH 02/13] feat(sim): use callstackitem --- yarn-project/acir-simulator/src/acvm.ts | 6 +++--- yarn-project/acir-simulator/src/circuits.ts | 8 ++++++++ yarn-project/acir-simulator/src/index.ts | 2 ++ yarn-project/acir-simulator/src/simulator.ts | 13 ++++++++++--- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/yarn-project/acir-simulator/src/acvm.ts b/yarn-project/acir-simulator/src/acvm.ts index 5b04ff54209e..2c2f5daabe24 100644 --- a/yarn-project/acir-simulator/src/acvm.ts +++ b/yarn-project/acir-simulator/src/acvm.ts @@ -1,7 +1,7 @@ import { AztecAddress, CallContext, ContractDeploymentData } from './circuits.js'; import { NoteLoadOracleInputs } from './db_oracle.js'; -interface ACIRCallback { +export interface ACIRCallback { getSecretKey(keyId: Buffer): Promise; getNotes(storageSlot: Buffer): Promise; getRandomField(): Promise; @@ -17,7 +17,7 @@ export interface ExecutionPreimages { nullifiedNotes: Buffer[]; } -interface Executionresult { +export interface ACIRExecutionResult { preimages: ExecutionPreimages; partialWitness: Buffer; } @@ -28,4 +28,4 @@ export type execute = ( callContext: CallContext, contractDeploymentData: ContractDeploymentData, oracle: ACIRCallback, -) => Promise; +) => Promise; diff --git a/yarn-project/acir-simulator/src/circuits.ts b/yarn-project/acir-simulator/src/circuits.ts index a067525a6dc2..6614e9583bb3 100644 --- a/yarn-project/acir-simulator/src/circuits.ts +++ b/yarn-project/acir-simulator/src/circuits.ts @@ -177,3 +177,11 @@ export class TxRequest { return Buffer.alloc(0); } } + +export class PrivateCallStackItem { + constructor( + public readonly contractAddress: AztecAddress, + public readonly functionSelector: Buffer, + public readonly publicInputs: PrivateCircuitPublicInputs, + ) {} +} diff --git a/yarn-project/acir-simulator/src/index.ts b/yarn-project/acir-simulator/src/index.ts index e660e82c1b4a..330c9900b134 100644 --- a/yarn-project/acir-simulator/src/index.ts +++ b/yarn-project/acir-simulator/src/index.ts @@ -1 +1,3 @@ export * from './simulator.js'; +export * from './db_oracle.js'; +export * from './acvm.js'; diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts index 66b83566ae29..3e6b0dde089c 100644 --- a/yarn-project/acir-simulator/src/simulator.ts +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -1,5 +1,12 @@ import { execute, ExecutionPreimages } from './acvm.js'; -import { CallContext, PrivateCircuitPublicInputs, TxRequest, Fr, EthAddress } from './circuits.js'; +import { + CallContext, + PrivateCircuitPublicInputs, + TxRequest, + Fr, + EthAddress, + PrivateCallStackItem, +} from './circuits.js'; import { DBOracle } from './db_oracle.js'; export interface ExecutionResult { @@ -7,7 +14,7 @@ export interface ExecutionResult { acir: Buffer; partialWitness: Buffer; // Needed for the verifier (kernel) - publicInputs: PrivateCircuitPublicInputs; + callStackItem: PrivateCallStackItem; // Needed for the user preimages: ExecutionPreimages; // Nested executions @@ -60,7 +67,7 @@ export class AcirSimulator { return Promise.resolve({ acir: entryPointACIR, partialWitness: Buffer.alloc(0), - publicInputs: publicInputs, + callStackItem: new PrivateCallStackItem(request.to, request.functionData.functionSelector, publicInputs), preimages: { newNotes: [], nullifiedNotes: [], From 54d862baf282d8716645befd77734296dfce0e99 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 10:36:02 +0000 Subject: [PATCH 03/13] feat(sim): kernel prover skeleton --- yarn-project/acir-simulator/src/circuits.ts | 70 ++++-- yarn-project/acir-simulator/src/foundation.ts | 12 - yarn-project/acir-simulator/src/simulator.ts | 17 +- yarn-project/kernel-simulator/.eslintrc.cjs | 15 ++ yarn-project/kernel-simulator/package.json | 1 + yarn-project/kernel-simulator/src/circuits.ts | 229 ++++++++++++++++++ yarn-project/kernel-simulator/src/index.ts | 56 ++++- yarn-project/yarn.lock | 3 +- 8 files changed, 361 insertions(+), 42 deletions(-) delete mode 100644 yarn-project/acir-simulator/src/foundation.ts create mode 100644 yarn-project/kernel-simulator/src/circuits.ts diff --git a/yarn-project/acir-simulator/src/circuits.ts b/yarn-project/acir-simulator/src/circuits.ts index 6614e9583bb3..917b55cc08a2 100644 --- a/yarn-project/acir-simulator/src/circuits.ts +++ b/yarn-project/acir-simulator/src/circuits.ts @@ -1,5 +1,3 @@ -import { randomBytes } from './foundation.js'; - // See aztec3/constants.hpp // Copied here for prototyping purposes // In future: structured serialization? @@ -54,10 +52,6 @@ export function assertLength { - return nodeCrypto.randomBytes(len) as Buffer; -}; - -export function keccak256(input: Buffer | string) { - const inputBuf = typeof input === 'string' ? Buffer.from(input) : input; - const hash = new Keccak(256); - return hash.update(inputBuf).digest(); -} diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts index 3e6b0dde089c..4de4cd722d88 100644 --- a/yarn-project/acir-simulator/src/simulator.ts +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -6,6 +6,7 @@ import { Fr, EthAddress, PrivateCallStackItem, + OldTreeRoots, } from './circuits.js'; import { DBOracle } from './db_oracle.js'; @@ -18,13 +19,7 @@ export interface ExecutionResult { // Needed for the user preimages: ExecutionPreimages; // Nested executions - nestedExecutions: ExecutionResult[]; -} - -export interface HistoricRoots { - historicPrivateDataTreeRoot: Fr; - historicPrivateNullifierTreeRoot: Fr; - historicContractTreeRoot: Fr; + nestedExecutions: this[]; } /** @@ -37,7 +32,7 @@ export class AcirSimulator { request: TxRequest, entryPointACIR: Buffer, portalContractAddress: EthAddress, - historicRoots: HistoricRoots, + oldRoots: OldTreeRoots, ): Promise { const callContext = new CallContext( request.from, @@ -58,9 +53,9 @@ export class AcirSimulator { [], // privateCallStack, [], // publicCallStack, [], // l1MsgStack, - historicRoots.historicPrivateDataTreeRoot, - historicRoots.historicPrivateNullifierTreeRoot, - historicRoots.historicContractTreeRoot, + oldRoots.privateDataTreeRoot, + oldRoots.nullifierTreeRoot, + oldRoots.contractTreeRoot, request.txContext.contractDeploymentData, ); diff --git a/yarn-project/kernel-simulator/.eslintrc.cjs b/yarn-project/kernel-simulator/.eslintrc.cjs index 9cf806b1500f..333ff38eab81 100644 --- a/yarn-project/kernel-simulator/.eslintrc.cjs +++ b/yarn-project/kernel-simulator/.eslintrc.cjs @@ -3,4 +3,19 @@ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@aztec/eslint-config'], parserOptions: { tsconfigRootDir: __dirname }, + rules: { + 'tsdoc/syntax': 'off', + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-description': 'off', + 'jsdoc/require-description-complete-sentence': 'off', + 'jsdoc/require-hyphen-before-param-description': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-param-name': 'off', + 'jsdoc/require-property': 'off', + 'jsdoc/require-property-description': 'off', + 'jsdoc/require-property-name': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-returns-description': 'off', + }, }; diff --git a/yarn-project/kernel-simulator/package.json b/yarn-project/kernel-simulator/package.json index 40676dbeab19..9e4ae664f049 100644 --- a/yarn-project/kernel-simulator/package.json +++ b/yarn-project/kernel-simulator/package.json @@ -29,6 +29,7 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/acir-simulator": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/kernel-simulator/src/circuits.ts b/yarn-project/kernel-simulator/src/circuits.ts new file mode 100644 index 000000000000..917b55cc08a2 --- /dev/null +++ b/yarn-project/kernel-simulator/src/circuits.ts @@ -0,0 +1,229 @@ +// See aztec3/constants.hpp +// Copied here for prototyping purposes +// In future: structured serialization? +export const ARGS_LENGTH = 8; +export const RETURN_VALUES_LENGTH = 4; +export const EMITTED_EVENTS_LENGTH = 4; + +export const NEW_COMMITMENTS_LENGTH = 4; +export const NEW_NULLIFIERS_LENGTH = 4; + +export const STATE_TRANSITIONS_LENGTH = 4; +export const STATE_READS_LENGTH = 4; + +export const PRIVATE_CALL_STACK_LENGTH = 4; +export const PUBLIC_CALL_STACK_LENGTH = 4; +export const L1_MSG_STACK_LENGTH = 2; + +export const KERNEL_NEW_COMMITMENTS_LENGTH = 16; +export const KERNEL_NEW_NULLIFIERS_LENGTH = 16; +export const KERNEL_NEW_CONTRACTS_LENGTH = 8; +export const KERNEL_PRIVATE_CALL_STACK_LENGTH = 8; +export const KERNEL_PUBLIC_CALL_STACK_LENGTH = 8; +export const KERNEL_L1_MSG_STACK_LENGTH = 4; +export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; + +export const VK_TREE_HEIGHT = 3; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; + +export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; +export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; + +export const FUNCTION_SELECTOR_NUM_BYTES = 31; + +/** + * Assert a member is a certain length. + * @param obj - An object. + * @param member - A member string. + * @param length - The length. + */ +export function assertLength( + obj: T, + member: F, + length: number, +) { + if (obj[member].length !== length) { + throw new Error(`Expected ${member} to have length ${length}! Was: ${obj[member].length}`); + } +} + +export class Fr { + public static ZERO = new Fr(Buffer.alloc(32)); + + constructor(public readonly buffer: Buffer) {} +} + +export class AztecAddress { + public static SIZE = 64; + + public static ZERO = new AztecAddress(Buffer.alloc(AztecAddress.SIZE)); + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: AztecAddress) { + return this.buffer.equals(rhs.buffer); + } +} + +export class EthAddress { + public static ZERO = new EthAddress(Buffer.alloc(20)); + + constructor(public readonly buffer: Buffer) {} +} + +/** + * Call context. + * @see abis/call_context.hpp + */ +export class CallContext { + constructor( + public msgSender: AztecAddress, + public storageContractAddress: AztecAddress, + public portalContractAddress: EthAddress, + public isDelegateCall: boolean, + public isStaticCall: boolean, + public isContractDeployment: boolean, + ) {} +} + +/** + * Contract deployment data in a @TxContext. + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ +export class ContractDeploymentData { + constructor( + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, + ) {} +} + +/** + * Public inputs to a private circuit. + * @see abis/private_circuit_public_inputs.hpp. + */ +export class PrivateCircuitPublicInputs { + constructor( + // NOTE: Must have same order as CPP. + public callContext: CallContext, + public args: Fr[], + public returnValues: Fr[], + public emittedEvents: Fr[], + public newCommitments: Fr[], + public newNullifiers: Fr[], + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + public historicPrivateDataTreeRoot: Fr, + public historicPrivateNullifierTreeRoot: Fr, + public historicContractTreeRoot: Fr, + public contractDeploymentData: ContractDeploymentData, + ) { + assertLength(this, 'args', ARGS_LENGTH); + assertLength(this, 'returnValues', RETURN_VALUES_LENGTH); + assertLength(this, 'emittedEvents', EMITTED_EVENTS_LENGTH); + assertLength(this, 'newCommitments', NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', L1_MSG_STACK_LENGTH); + } +} + +export class TxContext { + constructor( + public readonly isFeePaymentTx: boolean, + public readonly isRebatePaymentTx: boolean, + public readonly isContractDeploymentTx: boolean, + public readonly contractDeploymentData: ContractDeploymentData, + ) {} +} + +export interface FunctionData { + functionSelector: Buffer; + isSecret: boolean; + isContructor: boolean; +} + +export class TxRequest { + constructor( + public readonly from: AztecAddress, + public readonly to: AztecAddress, + public readonly functionData: FunctionData, + public readonly args: Fr[], + public readonly txContext: TxContext, + public readonly nonce: Fr, + public readonly chainId: Fr, + ) {} + + toBuffer() { + return Buffer.alloc(0); + } +} + +export class PrivateCallStackItem { + constructor( + public readonly contractAddress: AztecAddress, + public readonly functionSelector: Buffer, + public readonly publicInputs: PrivateCircuitPublicInputs, + ) {} +} + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} +} + +export class AggregationObject {} + +export class NewContractData { + constructor( + public readonly contractAddress: AztecAddress, + public readonly portalContractAddress: EthAddress, + public readonly functionTreeRoot: Fr, + ) {} +} + +export class OptionallyRevealedData {} + +export class AccumulatedTxData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[], + ) { + assertLength(this, 'newCommitments', KERNEL_NEW_COMMITMENTS_LENGTH); + assertLength(this, 'newNullifiers', KERNEL_NEW_NULLIFIERS_LENGTH); + assertLength(this, 'privateCallStack', KERNEL_PRIVATE_CALL_STACK_LENGTH); + assertLength(this, 'publicCallStack', KERNEL_PUBLIC_CALL_STACK_LENGTH); + assertLength(this, 'l1MsgStack', KERNEL_L1_MSG_STACK_LENGTH); + assertLength(this, 'newContracts', KERNEL_NEW_CONTRACTS_LENGTH); + assertLength(this, 'optionallyRevealedData', KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH); + } +} + +export class PrivateKernelPublicInputs { + constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} +} diff --git a/yarn-project/kernel-simulator/src/index.ts b/yarn-project/kernel-simulator/src/index.ts index d63aa680f381..539408f34828 100644 --- a/yarn-project/kernel-simulator/src/index.ts +++ b/yarn-project/kernel-simulator/src/index.ts @@ -1,4 +1,52 @@ -/** - * A placeholder for the Kernel Simulator. - */ -export class KernelSimulator {} +import { ExecutionResult } from '@aztec/acir-simulator'; +import { + AccumulatedTxData, + AggregationObject, + ConstantData, + Fr, + NewContractData, + OldTreeRoots, + PrivateKernelPublicInputs, + TxRequest, +} from './circuits.js'; +export class KernelProver { + prove( + txRequest: TxRequest, + executionResult: ExecutionResult, + oldRoots: OldTreeRoots, + ): Promise<{ publicInputs: PrivateKernelPublicInputs; proof: Buffer }> { + // TODO: implement this + const newContracts = []; + if (txRequest.functionData.isContructor) { + newContracts.push( + new NewContractData( + txRequest.to, + txRequest.txContext.contractDeploymentData.portalContractAddress, + txRequest.txContext.contractDeploymentData.functionTreeRoot, + ), + ); + } + const accumulatedTxData = new AccumulatedTxData( + new AggregationObject(), + new Fr(Buffer.from([1])), + [], // newCommitments + [], // newNullifiers + [], // privateCallStack + [], // publicCallStack + [], // l1MsgStack + newContracts, + [], // optionallyRevealedData + ); + + const publicInputs = new PrivateKernelPublicInputs( + accumulatedTxData, + new ConstantData(oldRoots, txRequest.txContext), + true, + ); + + return Promise.resolve({ + publicInputs, + proof: Buffer.alloc(0), + }); + } +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 0f4b1884c4f5..21e074bb4807 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -15,7 +15,7 @@ __metadata: languageName: node linkType: hard -"@aztec/acir-simulator@workspace:acir-simulator": +"@aztec/acir-simulator@workspace:^, @aztec/acir-simulator@workspace:acir-simulator": version: 0.0.0-use.local resolution: "@aztec/acir-simulator@workspace:acir-simulator" dependencies: @@ -214,6 +214,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/kernel-simulator@workspace:kernel-simulator" dependencies: + "@aztec/acir-simulator": "workspace:^" "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 From b7230fe151f86ee02d402737eac3600c28d846d9 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 10:44:32 +0000 Subject: [PATCH 04/13] merge milestone/1_1 into arv/simulators --- .circleci/config.yml | 22 +- .gitmodules | 6 + README.md | 3 +- barretenberg | 1 + bootstrap.sh | 25 +- bootstrap_docker.sh | 2 +- build-system | 2 +- build_manifest.json | 51 +- build_manifest.sh | 4 +- l1-contracts | 2 +- yarn-project/.yarnrc.prod.yml | 9 - yarn-project/acir-simulator/.eslintrc.cjs | 22 +- yarn-project/acir-simulator/package.json | 1 - yarn-project/acir-simulator/src/simulator.ts | 1 - yarn-project/archiver/.eslintrc.cjs | 7 +- yarn-project/archiver/README.md | 3 - yarn-project/archiver/package.json | 3 +- .../src/{ => archiver}/archiver.test.ts | 19 +- .../archiver/src/{ => archiver}/archiver.ts | 82 +- yarn-project/archiver/src/archiver/index.ts | 1 + .../archiver/src/block_downloader/index.ts | 1 + .../block_downloader/l2_block_downloader.ts | 82 ++ yarn-project/archiver/src/index.ts | 80 +- yarn-project/archiver/src/l2_block/index.ts | 3 + .../archiver/src/l2_block/l2_block.test.ts | 3 +- .../archiver/src/l2_block/l2_block.ts | 24 +- .../src/{ => l2_block}/l2_block_source.ts | 22 +- yarn-project/archiver/src/l2_block/mocks.ts | 7 +- .../src/movetofoundation/log/console.ts | 17 - .../src/movetofoundation/log/debug.ts | 38 - .../src/movetofoundation/log/index.ts | 3 - .../movetofoundation/log/log_history.test.ts | 87 -- .../src/movetofoundation/log/log_history.ts | 21 - yarn-project/archiver/tsconfig.dest.json | 10 +- yarn-project/archiver/tsconfig.json | 11 +- yarn-project/aztec-cli/.eslintrc.cjs | 7 +- yarn-project/aztec-cli/package.json | 1 - .../.dockerignore | 0 yarn-project/aztec-node/.eslintrc.cjs | 1 + .../{public-client => aztec-node}/.gitignore | 0 .../{public-client => aztec-node}/Dockerfile | 8 +- yarn-project/aztec-node/README.md | 1 + yarn-project/aztec-node/package.json | 49 + .../aztec-node/src/aztec_node.test.ts | 29 + yarn-project/aztec-node/src/index.ts | 109 ++ yarn-project/aztec-node/tsconfig.dest.json | 18 + .../tsconfig.json | 0 yarn-project/aztec-rpc/.eslintrc.cjs | 1 + yarn-project/aztec-rpc/Dockerfile | 3 +- yarn-project/aztec-rpc/package.json | 5 +- .../src/account_state/account_state.ts | 2 +- yarn-project/aztec-rpc/src/aztec_node.ts | 29 - .../src/aztec_rpc_client/aztec_rpc_client.ts | 4 +- .../src/aztec_rpc_server/aztec_rpc_server.ts | 12 +- .../create_aztec_rpc_server.ts | 28 +- yarn-project/aztec-rpc/src/circuits.ts | 4 + .../aztec-rpc/src/database/database.ts | 2 +- .../aztec-rpc/src/database/memory_db.ts | 2 +- yarn-project/aztec-rpc/src/database/tx_dao.ts | 2 +- yarn-project/aztec-rpc/src/index.ts | 2 +- .../src/proof_generator/proof_generator.ts | 5 +- .../src/synchroniser/synchroniser.ts | 2 +- yarn-project/aztec-rpc/src/tx/index.ts | 1 + yarn-project/aztec-rpc/src/tx/tx_hash.ts | 9 + yarn-project/aztec-rpc/src/tx/tx_receipt.ts | 2 +- yarn-project/aztec.js/.eslintrc.cjs | 22 +- yarn-project/aztec.js/Dockerfile | 11 +- yarn-project/aztec.js/package.json | 5 +- yarn-project/end-to-end/.eslintrc.cjs | 7 +- yarn-project/end-to-end/Dockerfile | 4 +- yarn-project/end-to-end/package.json | 3 +- .../src/e2e_deploy_contract.test.ts | 23 +- yarn-project/eslint-config/index.js | 93 -- yarn-project/eslint-config/package.json | 13 - yarn-project/ethereum.js/.eslintrc.cjs | 22 +- yarn-project/ethereum.js/Dockerfile | 3 +- .../ethereum.js/example/.eslintrc.cjs | 7 +- yarn-project/ethereum.js/example/package.json | 2 +- yarn-project/ethereum.js/package.json | 2 +- yarn-project/ethereum.js/tsconfig.dest.json | 12 +- yarn-project/ethereum.js/tsconfig.json | 5 + yarn-project/foundation | 1 + yarn-project/kernel-simulator/.eslintrc.cjs | 22 +- yarn-project/kernel-simulator/package.json | 1 - yarn-project/key-store/.eslintrc.cjs | 7 +- yarn-project/key-store/package.json | 2 +- yarn-project/l1-contracts/.eslintrc.cjs | 1 + yarn-project/l1-contracts/Dockerfile | 14 + yarn-project/l1-contracts/README.md | 3 + yarn-project/l1-contracts/contracts.json | 9 + .../package.json | 10 +- .../src/aztec-ethereumjs-contracts/Rollup.ts | 42 + .../aztec-ethereumjs-contracts/RollupAbi.ts | 86 ++ yarn-project/l1-contracts/src/index.ts | 6 + .../tsconfig.dest.json | 0 yarn-project/l1-contracts/tsconfig.json | 9 + yarn-project/merkle-tree/.eslintrc.cjs | 1 + yarn-project/merkle-tree/Dockerfile | 15 + yarn-project/merkle-tree/README.md | 1 + yarn-project/merkle-tree/package.json | 46 + yarn-project/merkle-tree/src/hasher.ts | 8 + yarn-project/merkle-tree/src/index.ts | 6 + .../src/indexed_tree/indexed_tree.test.ts | 149 ++ .../src/indexed_tree/indexed_tree.ts | 311 +++++ yarn-project/merkle-tree/src/merkle_tree.ts | 66 + yarn-project/merkle-tree/src/pedersen.ts | 15 + .../src/sibling_path/sibling_path.ts | 86 ++ .../src/standard_tree/standard_tree.test.ts | 81 ++ .../src/standard_tree/standard_tree.ts | 288 ++++ .../merkle-tree/src/test/test_suite.ts | 140 ++ yarn-project/merkle-tree/tsconfig.dest.json | 5 + yarn-project/merkle-tree/tsconfig.json | 10 + yarn-project/noir-contracts/.eslintrc.cjs | 7 +- yarn-project/noir-contracts/Dockerfile | 1 + yarn-project/noir-contracts/package.json | 2 +- yarn-project/p2p/.eslintrc.cjs | 7 +- yarn-project/p2p/package.json | 8 +- yarn-project/p2p/src/client/index.ts | 2 + yarn-project/p2p/src/client/mocks.ts | 79 ++ .../p2p/src/client/p2p_client.test.ts | 68 + yarn-project/p2p/src/client/p2p_client.ts | 240 ++++ yarn-project/p2p/src/client/tx.ts | 63 + yarn-project/p2p/src/index.ts | 24 +- yarn-project/p2p/src/tx_pool/index.ts | 2 + .../p2p/src/tx_pool/memory_tx_pool.ts | 70 + yarn-project/p2p/src/tx_pool/tx_pool.test.ts | 24 + yarn-project/p2p/src/tx_pool/tx_pool.ts | 31 + yarn-project/p2p/tsconfig.dest.json | 8 + yarn-project/p2p/tsconfig.json | 9 +- yarn-project/package.json | 12 +- yarn-project/prettier-config/index.js | 6 - yarn-project/prettier-config/package.json | 8 - yarn-project/prover-client/.eslintrc.cjs | 7 +- yarn-project/prover-client/package.json | 1 - yarn-project/public-client/.eslintrc.cjs | 6 - yarn-project/public-client/README.md | 1 - yarn-project/public-client/src/index.ts | 4 - yarn-project/sequencer-client/.eslintrc.cjs | 7 +- .../jest.integration.config.json | 13 + yarn-project/sequencer-client/package.json | 11 +- yarn-project/sequencer-client/src/config.ts | 7 + .../publisher/aztec-ethereumjs-tx-sender.ts | 42 + .../sequencer-client/src/publisher/index.ts | 9 + .../src/publisher/l2-block-publisher.test.ts | 78 ++ .../src/publisher/l2-block-publisher.ts | 131 ++ yarn-project/sequencer-client/src/receiver.ts | 9 + yarn-project/sequencer-client/src/utils.ts | 9 + .../test/l2-block-publisher.test.ts | 75 ++ yarn-project/sequencer-client/tsconfig.json | 2 +- yarn-project/typedoc.json | 6 +- yarn-project/world-state/.eslintrc.cjs | 1 + yarn-project/world-state/Dockerfile | 14 + yarn-project/world-state/README.md | 1 + yarn-project/world-state/package.json | 47 + yarn-project/world-state/src/index.ts | 2 + .../world-state/src/synchroniser/index.ts | 2 + .../server_world_state_synchroniser.test.ts | 215 +++ .../server_world_state_synchroniser.ts | 137 ++ .../synchroniser/world_state_synchroniser.ts | 32 + .../world-state/src/world-state-db/index.ts | 39 + .../world-state-db/memory_world_state_db.ts | 176 +++ yarn-project/world-state/tsconfig.dest.json | 15 + yarn-project/world-state/tsconfig.json | 22 + yarn-project/yarn-project-base/Dockerfile | 19 +- yarn-project/yarn.lock | 1197 ++++++++++------- 165 files changed, 4522 insertions(+), 1174 deletions(-) create mode 160000 barretenberg delete mode 100644 yarn-project/.yarnrc.prod.yml rename yarn-project/archiver/src/{ => archiver}/archiver.test.ts (68%) rename yarn-project/archiver/src/{ => archiver}/archiver.ts (66%) create mode 100644 yarn-project/archiver/src/archiver/index.ts create mode 100644 yarn-project/archiver/src/block_downloader/index.ts create mode 100644 yarn-project/archiver/src/block_downloader/l2_block_downloader.ts create mode 100644 yarn-project/archiver/src/l2_block/index.ts rename yarn-project/archiver/src/{ => l2_block}/l2_block_source.ts (63%) delete mode 100644 yarn-project/archiver/src/movetofoundation/log/console.ts delete mode 100644 yarn-project/archiver/src/movetofoundation/log/debug.ts delete mode 100644 yarn-project/archiver/src/movetofoundation/log/index.ts delete mode 100644 yarn-project/archiver/src/movetofoundation/log/log_history.test.ts delete mode 100644 yarn-project/archiver/src/movetofoundation/log/log_history.ts rename yarn-project/{public-client => aztec-node}/.dockerignore (100%) create mode 100644 yarn-project/aztec-node/.eslintrc.cjs rename yarn-project/{public-client => aztec-node}/.gitignore (100%) rename yarn-project/{public-client => aztec-node}/Dockerfile (57%) create mode 100644 yarn-project/aztec-node/README.md create mode 100644 yarn-project/aztec-node/package.json create mode 100644 yarn-project/aztec-node/src/aztec_node.test.ts create mode 100644 yarn-project/aztec-node/src/index.ts create mode 100644 yarn-project/aztec-node/tsconfig.dest.json rename yarn-project/{public-client => aztec-node}/tsconfig.json (100%) delete mode 100644 yarn-project/aztec-rpc/src/aztec_node.ts create mode 100644 yarn-project/aztec-rpc/src/tx/tx_hash.ts delete mode 100644 yarn-project/eslint-config/index.js delete mode 100644 yarn-project/eslint-config/package.json create mode 160000 yarn-project/foundation create mode 100644 yarn-project/l1-contracts/.eslintrc.cjs create mode 100644 yarn-project/l1-contracts/Dockerfile create mode 100644 yarn-project/l1-contracts/README.md create mode 100644 yarn-project/l1-contracts/contracts.json rename yarn-project/{public-client => l1-contracts}/package.json (85%) create mode 100644 yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/Rollup.ts create mode 100644 yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/RollupAbi.ts create mode 100644 yarn-project/l1-contracts/src/index.ts rename yarn-project/{public-client => l1-contracts}/tsconfig.dest.json (100%) create mode 100644 yarn-project/l1-contracts/tsconfig.json create mode 100644 yarn-project/merkle-tree/.eslintrc.cjs create mode 100644 yarn-project/merkle-tree/Dockerfile create mode 100644 yarn-project/merkle-tree/README.md create mode 100644 yarn-project/merkle-tree/package.json create mode 100644 yarn-project/merkle-tree/src/hasher.ts create mode 100644 yarn-project/merkle-tree/src/index.ts create mode 100644 yarn-project/merkle-tree/src/indexed_tree/indexed_tree.test.ts create mode 100644 yarn-project/merkle-tree/src/indexed_tree/indexed_tree.ts create mode 100644 yarn-project/merkle-tree/src/merkle_tree.ts create mode 100644 yarn-project/merkle-tree/src/pedersen.ts create mode 100644 yarn-project/merkle-tree/src/sibling_path/sibling_path.ts create mode 100644 yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts create mode 100644 yarn-project/merkle-tree/src/standard_tree/standard_tree.ts create mode 100644 yarn-project/merkle-tree/src/test/test_suite.ts create mode 100644 yarn-project/merkle-tree/tsconfig.dest.json create mode 100644 yarn-project/merkle-tree/tsconfig.json create mode 100644 yarn-project/p2p/src/client/index.ts create mode 100644 yarn-project/p2p/src/client/mocks.ts create mode 100644 yarn-project/p2p/src/client/p2p_client.test.ts create mode 100644 yarn-project/p2p/src/client/p2p_client.ts create mode 100644 yarn-project/p2p/src/client/tx.ts create mode 100644 yarn-project/p2p/src/tx_pool/index.ts create mode 100644 yarn-project/p2p/src/tx_pool/memory_tx_pool.ts create mode 100644 yarn-project/p2p/src/tx_pool/tx_pool.test.ts create mode 100644 yarn-project/p2p/src/tx_pool/tx_pool.ts delete mode 100644 yarn-project/prettier-config/index.js delete mode 100644 yarn-project/prettier-config/package.json delete mode 100644 yarn-project/public-client/.eslintrc.cjs delete mode 100644 yarn-project/public-client/README.md delete mode 100644 yarn-project/public-client/src/index.ts create mode 100644 yarn-project/sequencer-client/jest.integration.config.json create mode 100644 yarn-project/sequencer-client/src/config.ts create mode 100644 yarn-project/sequencer-client/src/publisher/aztec-ethereumjs-tx-sender.ts create mode 100644 yarn-project/sequencer-client/src/publisher/index.ts create mode 100644 yarn-project/sequencer-client/src/publisher/l2-block-publisher.test.ts create mode 100644 yarn-project/sequencer-client/src/publisher/l2-block-publisher.ts create mode 100644 yarn-project/sequencer-client/src/receiver.ts create mode 100644 yarn-project/sequencer-client/src/utils.ts create mode 100644 yarn-project/sequencer-client/test/l2-block-publisher.test.ts create mode 100644 yarn-project/world-state/.eslintrc.cjs create mode 100644 yarn-project/world-state/Dockerfile create mode 100644 yarn-project/world-state/README.md create mode 100644 yarn-project/world-state/package.json create mode 100644 yarn-project/world-state/src/index.ts create mode 100644 yarn-project/world-state/src/synchroniser/index.ts create mode 100644 yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts create mode 100644 yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.ts create mode 100644 yarn-project/world-state/src/synchroniser/world_state_synchroniser.ts create mode 100644 yarn-project/world-state/src/world-state-db/index.ts create mode 100644 yarn-project/world-state/src/world-state-db/memory_world_state_db.ts create mode 100644 yarn-project/world-state/tsconfig.dest.json create mode 100644 yarn-project/world-state/tsconfig.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 24952f5d77c8..68a5071a9c5c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,8 +47,8 @@ checkout: &checkout # Only download metadata when fetching. git fetch --depth 50 --filter=blob:none origin $CIRCLE_SHA1 git checkout FETCH_HEAD - # Pull in build-system submodule. - git submodule update --init build-system + # Initialize submodules recursively + git submodule update --init --recursive build-system yarn-project/foundation # Called setup_env to setup a bunch of global variables used throughout the rest of the build process. # It takes the required CCI environment variables as inputs, and gives them normalised names for the rest of @@ -81,6 +81,17 @@ jobs: name: "Build and test" command: build ethereum.js + foundation: + machine: + image: ubuntu-2004:202010-01 + resource_class: large + steps: + - *checkout + - *setup_env + - run: + name: "Build and test" + command: build foundation + aztec-js: machine: image: ubuntu-2004:202010-01 @@ -145,10 +156,12 @@ defaults: &defaults yarn_project: &yarn_project requires: - yarn-project-base + - foundation <<: *defaults e2e_test: &e2e_test requires: - e2e-join + - foundation <<: *defaults workflows: @@ -161,12 +174,17 @@ workflows: - ethereum-js: *yarn_project - aztec-js: *yarn_project - end-to-end: *yarn_project + - foundation: + requires: + - yarn-project-base + <<: *defaults - e2e-join: requires: - ethereum-js - aztec-js - end-to-end - noir-contracts + - foundation <<: *defaults - e2e-deploy-contract: *e2e_test - noir-contracts: *yarn_project diff --git a/.gitmodules b/.gitmodules index fc785e10ad17..9f898950188c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,9 @@ [submodule "l1-contracts"] path = l1-contracts url = git@github.com:AztecProtocol/aztec3-l1-contracts.git +[submodule "barretenberg"] + path = barretenberg + url = git@github.com:AztecProtocol/barretenberg.git +[submodule "yarn-project/foundation"] + path = yarn-project/foundation + url = git@github.com:AztecProtocol/foundation.git diff --git a/README.md b/README.md index 9dcda3e8e498..a02be8117158 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ The Aztec 3 system consists of the following sub projects. - `ethereum.js` - `kernel-simulator` - `key-store` +- `l1-contracts` - `p2p` - `prover-client` -- `public-client` +- `aztec-node` - `sequencer-client` diff --git a/barretenberg b/barretenberg new file mode 160000 index 000000000000..f2f8d1f7a24c --- /dev/null +++ b/barretenberg @@ -0,0 +1 @@ +Subproject commit f2f8d1f7a24ca73e30c981fd245c86f7f964abb7 diff --git a/bootstrap.sh b/bootstrap.sh index 5c0706b494a8..d4b2c0c171ea 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -40,21 +40,24 @@ cd yarn-project yarn install --immutable cd .. +# make sure to run yarn install from foundation, has its own yarn.lock +pushd yarn-project/foundation >/dev/null +yarn install +popd >/dev/null + # We only bootstrap projects that produce artefacts needed for running end-to-end tests. PROJECTS=( - # "circuits:./bootstrap.sh db_cli rollup_cli" - # "yarn-project/acir-simulator:yarn build" - # "yarn-project/aztec-cli:yarn build" - "yarn-project/aztec-rpc:yarn build" - "yarn-project/aztec.js:yarn build" + # "yarn-project/foundation:yarn build" + "yarn-project/ethereum.js:yarn build" + "yarn-project/merkle-tree:yarn build" "yarn-project/archiver:yarn build" - # "yarn-project/ethereum.js:yarn build" - # "yarn-project/kernel-simulator:yarn build" + "yarn-project/world-state:yarn build" + "yarn-project/p2p:yarn build" + "yarn-project/aztec-node:yarn build" "yarn-project/key-store:yarn build" - # "yarn-project/p2p:yarn build" - # "yarn-project/prover-client:yarn build" - # "yarn-project/public-client:yarn build" - # "yarn-project/sequencer-client:yarn build" + "yarn-project/acir-simulator:yarn build" + "yarn-project/aztec-rpc:yarn build" + "yarn-project/aztec.js:yarn build" ) for E in "${PROJECTS[@]}"; do diff --git a/bootstrap_docker.sh b/bootstrap_docker.sh index abff2bfdc8c5..f12b77b5cb9b 100755 --- a/bootstrap_docker.sh +++ b/bootstrap_docker.sh @@ -19,4 +19,4 @@ if [ -z "$TARGET_PROJECT" ]; then fi source ./build-system/scripts/setup_env $COMMIT_HASH '' mainframe_$USER $(git rev-parse --show-toplevel) -build_local $TARGET_PROJECT $ONLY_TARGET \ No newline at end of file +build_local $TARGET_PROJECT $ONLY_TARGET diff --git a/build-system b/build-system index c85b185d917d..274f5637d457 160000 --- a/build-system +++ b/build-system @@ -1 +1 @@ -Subproject commit c85b185d917df423586897fd036275400b7159d9 +Subproject commit 274f5637d4573372a90cf745a60968103dec8b92 diff --git a/build_manifest.json b/build_manifest.json index bb31ff6ca13c..e0d49269ab08 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -50,42 +50,56 @@ "projectDir": "yarn-project/archiver", "dockerfile": "archiver/Dockerfile", "rebuildPatterns": ["^yarn-project/archiver/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["yarn-project-base", "ethereum.js"] }, "aztec-cli": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec-cli", "dockerfile": "aztec-cli/Dockerfile", "rebuildPatterns": ["^yarn-project/aztec-cli/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["aztec.js"] + }, + "aztec-node": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/aztec-node", + "dockerfile": "aztec-node/Dockerfile", + "rebuildPatterns": ["^yarn-project/aztec-node/"], + "dependencies": ["foundation", "p2p", "world-state", "ethereum.js"] }, "aztec-rpc": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec-rpc", "dockerfile": "aztec-rpc/Dockerfile", "rebuildPatterns": ["^yarn-project/aztec-rpc/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["aztec-node"] }, "aztec.js": { "buildDir": "yarn-project", "projectDir": "yarn-project/aztec.js", "dockerfile": "aztec.js/Dockerfile", "rebuildPatterns": ["^yarn-project/aztec.js/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["aztec-rpc"] }, "end-to-end": { "buildDir": "yarn-project", "projectDir": "yarn-project/end-to-end", "dockerfile": "end-to-end/Dockerfile", "rebuildPatterns": ["^yarn-project/end-to-end/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["aztec.js"] }, "ethereum.js": { "buildDir": "yarn-project", "projectDir": "yarn-project/ethereum.js", "dockerfile": "ethereum.js/Dockerfile", "rebuildPatterns": ["^yarn-project/ethereum.js/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["yarn-project-base", "foundation"] + }, + "foundation": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/foundation", + "dockerfile": "foundation/Dockerfile", + "rebuildPatterns": ["^yarn-project/foundation/"], + "dependencies": [] }, "kernel-simulator": { "buildDir": "yarn-project", @@ -101,19 +115,26 @@ "rebuildPatterns": ["^yarn-project/key-store/"], "dependencies": ["yarn-project-base"] }, + "merkle-tree": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/merkle-tree", + "dockerfile": "merkle-tree/Dockerfile", + "rebuildPatterns": ["^yarn-project/merkle-tree/"], + "dependencies": ["yarn-project-base", "foundation"] + }, "noir-contracts": { "buildDir": "yarn-project", "projectDir": "yarn-project/noir-contracts", "dockerfile": "noir-contracts/Dockerfile", "rebuildPatterns": ["^yarn-project/noir-contracts/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["yarn-project-base", "foundation"] }, "p2p": { "buildDir": "yarn-project", "projectDir": "yarn-project/p2p", "dockerfile": "p2p/Dockerfile", "rebuildPatterns": ["^yarn-project/p2p/"], - "dependencies": ["yarn-project-base"] + "dependencies": ["yarn-project-base", "archiver"] }, "prover-client": { "buildDir": "yarn-project", @@ -122,18 +143,18 @@ "rebuildPatterns": ["^yarn-project/prover-client/"], "dependencies": ["yarn-project-base"] }, - "public-client": { - "buildDir": "yarn-project", - "projectDir": "yarn-project/public-client", - "dockerfile": "public-client/Dockerfile", - "rebuildPatterns": ["^yarn-project/public-client/"], - "dependencies": ["yarn-project-base"] - }, "sequencer-client": { "buildDir": "yarn-project", "projectDir": "yarn-project/sequencer-client", "dockerfile": "sequencer-client/Dockerfile", "rebuildPatterns": ["^yarn-project/sequencer-client/"], "dependencies": ["yarn-project-base"] + }, + "world-state": { + "buildDir": "yarn-project", + "projectDir": "yarn-project/world-state", + "dockerfile": "world-state/Dockerfile", + "rebuildPatterns": ["^yarn-project/world-state/"], + "dependencies": ["yarn-project-base", "merkle-tree"] } } diff --git a/build_manifest.sh b/build_manifest.sh index 1ed6ed6d72cf..6cd66ec2600f 100755 --- a/build_manifest.sh +++ b/build_manifest.sh @@ -20,8 +20,10 @@ PROJECTS=( # ethereum.js:yarn-project # kernel-simulator:yarn-project # key-store:yarn-project + # merkle-tree:yarn-project # p2p:yarn-project # prover-client:yarn-project - # public-client:yarn-project + # aztec-node:yarn-project # sequencer-client:yarn-project + # world-state:yarn-project ) diff --git a/l1-contracts b/l1-contracts index 74316d6e71bc..7f01e8875c18 160000 --- a/l1-contracts +++ b/l1-contracts @@ -1 +1 @@ -Subproject commit 74316d6e71bc995dad94abffa01a1a50ffc1ba4b +Subproject commit 7f01e8875c187e56feda3e3a7bf6d8d1ce638b62 diff --git a/yarn-project/.yarnrc.prod.yml b/yarn-project/.yarnrc.prod.yml deleted file mode 100644 index 59e787791f62..000000000000 --- a/yarn-project/.yarnrc.prod.yml +++ /dev/null @@ -1,9 +0,0 @@ -plugins: - - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - spec: '@yarnpkg/plugin-workspace-tools' - -# note that node-modules is used during dev -nodeLinker: pnp -# compatibility with node-modules linker -pnpMode: loose -yarnPath: .yarn/releases/yarn-3.4.1.cjs diff --git a/yarn-project/acir-simulator/.eslintrc.cjs b/yarn-project/acir-simulator/.eslintrc.cjs index 333ff38eab81..e659927475c0 100644 --- a/yarn-project/acir-simulator/.eslintrc.cjs +++ b/yarn-project/acir-simulator/.eslintrc.cjs @@ -1,21 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, - rules: { - 'tsdoc/syntax': 'off', - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-description-complete-sentence': 'off', - 'jsdoc/require-hyphen-before-param-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-name': 'off', - 'jsdoc/require-property': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-property-name': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/acir-simulator/package.json b/yarn-project/acir-simulator/package.json index 957a7cf19968..beca27e246b4 100644 --- a/yarn-project/acir-simulator/package.json +++ b/yarn-project/acir-simulator/package.json @@ -32,7 +32,6 @@ "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@noir-lang/noir-source-resolver": "^1.1.0", "@noir-lang/noir_wasm": "0.3.2-29b1f7df", diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts index 4de4cd722d88..58c05912de19 100644 --- a/yarn-project/acir-simulator/src/simulator.ts +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -3,7 +3,6 @@ import { CallContext, PrivateCircuitPublicInputs, TxRequest, - Fr, EthAddress, PrivateCallStackItem, OldTreeRoots, diff --git a/yarn-project/archiver/.eslintrc.cjs b/yarn-project/archiver/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/archiver/.eslintrc.cjs +++ b/yarn-project/archiver/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/archiver/README.md b/yarn-project/archiver/README.md index f787b04c84a4..a6743c372bea 100644 --- a/yarn-project/archiver/README.md +++ b/yarn-project/archiver/README.md @@ -4,6 +4,3 @@ To run: 2. in the aztec3-l1-contracts repo check out my branch `janb/archiver-test-data`, 3. deploy the contracts and generate initial activity with: `forge script --fork-url "http://127.0.0.1:8545/" --ffi GenerateActivityTest --sig "testGenerateActivity()" --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast` 4. in this repository run `yarn start:dev` (Note: this repo is currently messy and eslint will not allow it to be built with `yarn start`) - -Relevant unresolved issues: -https://stackoverflow.com/questions/75739742/why-is-eslint-complaining-about-inheritdoc-tag diff --git a/yarn-project/archiver/package.json b/yarn-project/archiver/package.json index c43b39032b28..97c491ebfbd1 100644 --- a/yarn-project/archiver/package.json +++ b/yarn-project/archiver/package.json @@ -26,6 +26,8 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/ethereum.js": "workspace:^", + "@aztec/foundation": "workspace:^", "debug": "^4.3.4", "tsc-watch": "^6.0.0", "tslib": "^2.5.0", @@ -33,7 +35,6 @@ "ws": "^8.13.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.5.0", "@rushstack/eslint-patch": "^1.2.0", "@types/debug": "^4.1.7", diff --git a/yarn-project/archiver/src/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts similarity index 68% rename from yarn-project/archiver/src/archiver.test.ts rename to yarn-project/archiver/src/archiver/archiver.test.ts index ff8a4868ffe2..138e8575d479 100644 --- a/yarn-project/archiver/src/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,12 +1,13 @@ +import { EthAddress } from '@aztec/ethereum.js/eth_address'; import { jest } from '@jest/globals'; -import { getAddress, PublicClient } from 'viem'; +import { PublicClient } from 'viem'; import { Archiver } from './archiver.js'; jest.mock('viem'); describe('Archiver', () => { - const rollupAddress = getAddress('0x0000000000000000000000000000000000000000'); - const yeeterAddress = getAddress('0x0000000000000000000000000000000000000000'); + const rollupAddress = '0x0000000000000000000000000000000000000000'; + const yeeterAddress = '0x0000000000000000000000000000000000000000'; let publicClient: PublicClient; beforeEach(() => { @@ -35,9 +36,13 @@ describe('Archiver', () => { }); it('can start, sync and stop', async () => { - const archiver = new Archiver(publicClient, rollupAddress, yeeterAddress); + const archiver = new Archiver( + publicClient, + EthAddress.fromString(rollupAddress), + EthAddress.fromString(yeeterAddress), + ); let syncStatus = await archiver.getSyncStatus(); - let latestBlockNum = archiver.getLatestBlockNum(); + let latestBlockNum = await archiver.getLatestBlockNum(); expect(syncStatus).toStrictEqual({ syncedToBlock: -1, latestBlock: 2, @@ -47,13 +52,13 @@ describe('Archiver', () => { await archiver.start(); syncStatus = await archiver.getSyncStatus(); - latestBlockNum = archiver.getLatestBlockNum(); + latestBlockNum = await archiver.getLatestBlockNum(); expect(syncStatus).toStrictEqual({ syncedToBlock: 2, latestBlock: 2, }); expect(latestBlockNum).toBe(syncStatus.syncedToBlock); - archiver.stop(); + await archiver.stop(); }); }); diff --git a/yarn-project/archiver/src/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts similarity index 66% rename from yarn-project/archiver/src/archiver.ts rename to yarn-project/archiver/src/archiver/archiver.ts index 5f229f0f0383..33aa09e70d29 100644 --- a/yarn-project/archiver/src/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,10 +1,12 @@ -import { Address, PublicClient } from 'viem'; -import { rollupAbi } from './abis/rollup.js'; -import { yeeterAbi } from './abis/yeeter.js'; -import { ContractData, L2Block } from './l2_block/l2_block.js'; -import { randomAppendOnlyTreeSnapshot, randomBytes, randomContractData } from './l2_block/mocks.js'; -import { L2BlockSource, SyncStatus } from './l2_block_source.js'; -import { createLogger } from './movetofoundation/log/console.js'; +import { PublicClient, getAddress, http, createPublicClient } from 'viem'; +import { rollupAbi } from '../abis/rollup.js'; +import { yeeterAbi } from '../abis/yeeter.js'; +import { ContractData, L2Block } from '../l2_block/l2_block.js'; +import { randomAppendOnlyTreeSnapshot, randomContractData } from '../l2_block/mocks.js'; +import { L2BlockSource, L2BlockSourceSyncStatus } from '../l2_block/l2_block_source.js'; +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { localhost } from 'viem/chains'; +import { createDebugLogger, randomBytes } from '@aztec/foundation'; /** * Pulls L2 blocks in a non-blocking manner and provides interface for their retrieval. @@ -33,23 +35,39 @@ export class Archiver implements L2BlockSource { */ constructor( private readonly publicClient: PublicClient, - private readonly rollupAddress: Address, - private readonly yeeterAddress: Address, - private readonly log = createLogger('Archiver'), + private readonly rollupAddress: EthAddress, + private readonly yeeterAddress: EthAddress, + private readonly log = createDebugLogger('aztec:archiver'), ) {} /** - * {@inheritDoc L2BlockSource.getSyncStatus} + * Creates a new instance of the Archiver. + * @param rpcUrl - The RPC url for connecting to an eth node. + * @param rollupAddress - Ethereum address of the rollup contract. + * @param yeeterAddress - Ethereum address of the yeeter contract. + * @returns - An instance of the archiver. + */ + public static new(rpcUrl: string, rollupAddress: EthAddress, yeeterAddress: EthAddress) { + const publicClient = createPublicClient({ + chain: localhost, + transport: http(rpcUrl), + }); + return new Archiver(publicClient, rollupAddress, yeeterAddress); + } + + /** + * Gets the sync status of the L2 block source. + * @returns The sync status of the L2 block source. */ - public async getSyncStatus(): Promise { + public async getSyncStatus(): Promise { const nextBlockNum = await this.publicClient.readContract({ - address: this.rollupAddress, + address: getAddress(this.rollupAddress.toString()), abi: rollupAbi, functionName: 'nextBlockNum', }); return { - syncedToBlock: this.getLatestBlockNum(), + syncedToBlock: await this.getLatestBlockNum(), latestBlock: Number(nextBlockNum) - 1, }; } @@ -70,13 +88,13 @@ export class Archiver implements L2BlockSource { */ private async runInitialSync() { const blockFilter = await this.publicClient.createEventFilter({ - address: this.rollupAddress, + address: getAddress(this.rollupAddress.toString()), fromBlock: 0n, event: rollupAbi[0], }); const yeetFilter = await this.publicClient.createEventFilter({ - address: this.yeeterAddress, + address: getAddress(this.yeeterAddress.toString()), event: yeeterAbi[0], fromBlock: 0n, }); @@ -93,13 +111,13 @@ export class Archiver implements L2BlockSource { */ private startWatchingEvents() { this.unwatchBlocks = this.publicClient.watchEvent({ - address: this.rollupAddress, + address: getAddress(this.rollupAddress.toString()), event: rollupAbi[0], onLogs: logs => this.processBlockLogs(logs), }); this.unwatchYeets = this.publicClient.watchEvent({ - address: this.yeeterAddress, + address: getAddress(this.yeeterAddress.toString()), event: yeeterAbi[0], onLogs: logs => this.processYeetLogs(logs), }); @@ -147,9 +165,10 @@ export class Archiver implements L2BlockSource { } /** - * Stops the event polling loop. + * Stops the archiver. + * @returns A promise signalling completion of the stop process. */ - public stop() { + public stop(): Promise { this.log('Stopping...'); if (this.unwatchBlocks === undefined || this.unwatchYeets === undefined) { throw new Error('Archiver is not running.'); @@ -159,27 +178,32 @@ export class Archiver implements L2BlockSource { this.unwatchYeets(); this.log('Stopped.'); + return Promise.resolve(); } /** - * {@inheritDoc L2BlockSource.getL2Blocks} + * Gets the `take` amount of L2 blocks starting from `from`. + * @param from - If of the first rollup to return (inclusive). + * @param take - The number of blocks to return. + * @returns The requested L2 blocks. */ - public getL2Blocks(from: number, take: number): L2Block[] { + public getL2Blocks(from: number, take: number): Promise { if (from > this.l2Blocks.length) { - return []; + return Promise.resolve([]); } if (from + take > this.l2Blocks.length) { - return this.l2Blocks.slice(from); + return Promise.resolve(this.l2Blocks.slice(from)); } - return this.l2Blocks.slice(from, from + take); + return Promise.resolve(this.l2Blocks.slice(from, from + take)); } /** - * {@inheritDoc L2BlockSource.getLatestBlockNum} + * Gets the number of the latest L2 block processed by the block source implementation. + * @returns The number of the latest L2 block processed by the block source implementation. */ - public getLatestBlockNum(): number { - return this.l2Blocks.length - 1; + public getLatestBlockNum(): Promise { + return Promise.resolve(this.l2Blocks.length - 1); } } @@ -188,7 +212,7 @@ export class Archiver implements L2BlockSource { * @param l2BlockNum - Block number. * @returns Random L2Block. */ -function mockRandomL2Block(l2BlockNum: number): L2Block { +export function mockRandomL2Block(l2BlockNum: number): L2Block { const newNullifiers = [randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32)]; const newCommitments = [randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32)]; const newContracts: Buffer[] = [randomBytes(32)]; diff --git a/yarn-project/archiver/src/archiver/index.ts b/yarn-project/archiver/src/archiver/index.ts new file mode 100644 index 000000000000..661ac2ff02f5 --- /dev/null +++ b/yarn-project/archiver/src/archiver/index.ts @@ -0,0 +1 @@ +export * from './archiver.js'; diff --git a/yarn-project/archiver/src/block_downloader/index.ts b/yarn-project/archiver/src/block_downloader/index.ts new file mode 100644 index 000000000000..9084cc7d81af --- /dev/null +++ b/yarn-project/archiver/src/block_downloader/index.ts @@ -0,0 +1 @@ +export * from './l2_block_downloader.js'; diff --git a/yarn-project/archiver/src/block_downloader/l2_block_downloader.ts b/yarn-project/archiver/src/block_downloader/l2_block_downloader.ts new file mode 100644 index 000000000000..f72abbf79df5 --- /dev/null +++ b/yarn-project/archiver/src/block_downloader/l2_block_downloader.ts @@ -0,0 +1,82 @@ +import { InterruptableSleep, Semaphore, MemoryFifo } from '@aztec/foundation'; +import { L2BlockSource, L2Block } from '../index.js'; + +/** + * Downloads L2 blocks from a L2BlockSource. + * The blocks are stored in a queue and can be retrieved using the getBlocks method. + * The queue size is limited by the maxQueueSize parameter. + * The downloader will pause when the queue is full or when the L2BlockSource is out of blocks. + */ +export class L2BlockDownloader { + private runningPromise?: Promise; + private running = false; + private from = 0; + private interruptableSleep = new InterruptableSleep(); + private semaphore: Semaphore; + private queue = new MemoryFifo(); + + constructor(private l2BlockSource: L2BlockSource, maxQueueSize: number, private pollIntervalMS = 10000) { + this.semaphore = new Semaphore(maxQueueSize); + } + + /** + * Starts the downloader. + * @param from - The block number to start downloading from. Defaults to 0. + */ + public start(from = 0) { + this.from = from; + + if (this.running) { + this.interruptableSleep.interrupt(); + return; + } + + this.running = true; + + const fn = async () => { + while (this.running) { + try { + const blocks = await this.l2BlockSource.getL2Blocks(this.from, 10); + + if (!blocks.length) { + await this.interruptableSleep.sleep(this.pollIntervalMS); + continue; + } + + // Blocks if there are maxQueueSize results in the queue, until released after the callback. + await this.semaphore.acquire(); + this.queue.put(blocks); + this.from += blocks.length; + } catch (err) { + console.log(err); + await this.interruptableSleep.sleep(this.pollIntervalMS); + } + } + }; + + this.runningPromise = fn(); + } + + /** + * Stops the downloader. + */ + public async stop() { + this.running = false; + this.interruptableSleep.interrupt(); + this.queue.cancel(); + await this.runningPromise; + } + + /** + * Gets the next batch of blocks from the queue. + * @returns The next batch of blocks from the queue. + */ + public async getL2Blocks() { + const blocks = await this.queue.get(); + if (!blocks) { + return []; + } + this.semaphore.release(); + return blocks; + } +} diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index 343e570f15cb..944dc8cb170a 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -1,38 +1,42 @@ -import { createPublicClient, getAddress, http } from 'viem'; -import { localhost } from 'viem/chains'; -import { Archiver } from './archiver.js'; - -const { - ETHEREUM_HOST = 'http://localhost:8545/', - ROLLUP_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3', - YEETER_ADDRESS = '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', -} = process.env; - -/** - * A function which instantiates and starts Archiver. - */ -async function main() { - const rollupAddress = getAddress(ROLLUP_ADDRESS); - const yeeterAddress = getAddress(YEETER_ADDRESS); - - const publicClient = createPublicClient({ - chain: localhost, - transport: http(ETHEREUM_HOST), - }); - - const archiver = new Archiver(publicClient, rollupAddress, yeeterAddress); - - const shutdown = () => { - archiver.stop(); - process.exit(0); - }; - process.once('SIGINT', shutdown); - process.once('SIGTERM', shutdown); - - await archiver.start(); -} - -main().catch(err => { - console.log(err); - process.exit(1); -}); +// import { createPublicClient, getAddress, http } from 'viem'; +// import { localhost } from 'viem/chains'; +// import { Archiver } from './archiver/archiver.js'; + +export * from './archiver/index.js'; +export * from './block_downloader/index.js'; +export * from './l2_block/index.js'; + +// const { +// ETHEREUM_HOST = 'http://localhost:8545/', +// ROLLUP_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3', +// YEETER_ADDRESS = '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', +// } = process.env; + +// /** +// * A function which instantiates and starts Archiver. +// */ +// async function main() { +// const rollupAddress = getAddress(ROLLUP_ADDRESS); +// const yeeterAddress = getAddress(YEETER_ADDRESS); + +// const publicClient = createPublicClient({ +// chain: localhost, +// transport: http(ETHEREUM_HOST), +// }); + +// const archiver = new Archiver(publicClient, rollupAddress, yeeterAddress); + +// const shutdown = () => { +// archiver.stop(); +// process.exit(0); +// }; +// process.once('SIGINT', shutdown); +// process.once('SIGTERM', shutdown); + +// await archiver.start(); +// } + +// main().catch(err => { +// console.log(err); +// process.exit(1); +// }); diff --git a/yarn-project/archiver/src/l2_block/index.ts b/yarn-project/archiver/src/l2_block/index.ts new file mode 100644 index 000000000000..e8e9e0a8a417 --- /dev/null +++ b/yarn-project/archiver/src/l2_block/index.ts @@ -0,0 +1,3 @@ +export * from './l2_block.js'; +export * from './l2_block_source.js'; +export * from './mocks.js'; diff --git a/yarn-project/archiver/src/l2_block/l2_block.test.ts b/yarn-project/archiver/src/l2_block/l2_block.test.ts index 8206b19c0e38..854498ae8f76 100644 --- a/yarn-project/archiver/src/l2_block/l2_block.test.ts +++ b/yarn-project/archiver/src/l2_block/l2_block.test.ts @@ -1,4 +1,5 @@ -import { randomAppendOnlyTreeSnapshot, randomBytes, randomContractData } from './mocks.js'; +import { randomBytes } from '@aztec/foundation'; +import { randomAppendOnlyTreeSnapshot, randomContractData } from './mocks.js'; import { ContractData, L2Block } from './l2_block.js'; describe('L2Block', () => { diff --git a/yarn-project/archiver/src/l2_block/l2_block.ts b/yarn-project/archiver/src/l2_block/l2_block.ts index fa1ff5492497..8d5d4dd8eb4c 100644 --- a/yarn-project/archiver/src/l2_block/l2_block.ts +++ b/yarn-project/archiver/src/l2_block/l2_block.ts @@ -1,3 +1,5 @@ +import { numToUInt32BE } from '@aztec/foundation'; + /** * A snapshot of an append only tree. */ @@ -30,6 +32,9 @@ export type ContractData = { * The data that makes up the rollup proof, with encoder decoder functions. */ export class L2Block { + /** + * A yeet to go with the block. + */ public yeet?: Buffer; /** @@ -69,6 +74,10 @@ export class L2Block { public newContractData: ContractData[], ) {} + /** + * Sets the yeet on this block. + * @param yeet - The yeet to set. + */ setYeet(yeet: Buffer) { this.yeet = yeet; } @@ -236,21 +245,6 @@ export function bufferToAppendOnlyTreeSnapshot(buffer: Buffer): AppendOnlyTreeSn }; } -/** - * FUNCTIONS THAT SHOULD NOT BE HERE. - */ - -/** - * For serializing numbers to 32 byte big-endian form. - * @param n - The number to serialize. - * @param bufferSize - The size of the buffer to serialize to, defaults to 4. - */ -export function numToUInt32BE(n: number, bufferSize = 4): Buffer { - const buf = Buffer.alloc(bufferSize); - buf.writeUInt32BE(n, bufferSize - 4); - return buf; -} - /** * UNUSED TYPED THAT COULD BE USEFUL. */ diff --git a/yarn-project/archiver/src/l2_block_source.ts b/yarn-project/archiver/src/l2_block/l2_block_source.ts similarity index 63% rename from yarn-project/archiver/src/l2_block_source.ts rename to yarn-project/archiver/src/l2_block/l2_block_source.ts index 200a02961f4e..bb4d6e776950 100644 --- a/yarn-project/archiver/src/l2_block_source.ts +++ b/yarn-project/archiver/src/l2_block/l2_block_source.ts @@ -1,9 +1,9 @@ -import { L2Block } from './l2_block/l2_block.js'; +import { L2Block } from './index.js'; /** * Describes sync status of the archiver. */ -export interface SyncStatus { +export interface L2BlockSourceSyncStatus { /** * The height of the L2 block that the archiver is synced to. */ @@ -22,13 +22,13 @@ export interface L2BlockSource { * Gets the sync status of the L2 block source. * @returns The sync status of the L2 block source. */ - getSyncStatus(): Promise; + getSyncStatus(): Promise; /** * Gets the number of the latest L2 block processed by the block source implementation. * @returns The number of the latest L2 block processed by the block source implementation. */ - getLatestBlockNum(): number; + getLatestBlockNum(): Promise; /** * Gets the `take` amount of L2 blocks starting from `from`. @@ -36,5 +36,17 @@ export interface L2BlockSource { * @param take - The number of blocks to return. * @returns The requested L2 blocks. */ - getL2Blocks(from: number, take: number): L2Block[]; + getL2Blocks(from: number, take: number): Promise; + + /** + * Starts the L2 block source. + * @returns A promise signalling completion of the start process. + */ + start(): Promise; + + /** + * Stops the L2 block source. + * @returns A promise signalling completion of the stop process. + */ + stop(): Promise; } diff --git a/yarn-project/archiver/src/l2_block/mocks.ts b/yarn-project/archiver/src/l2_block/mocks.ts index b69b33fe1698..d7533c88a896 100644 --- a/yarn-project/archiver/src/l2_block/mocks.ts +++ b/yarn-project/archiver/src/l2_block/mocks.ts @@ -1,9 +1,6 @@ -import nodeCrypto from 'crypto'; -import { AppendOnlyTreeSnapshot, ContractData } from './l2_block.js'; +import { randomBytes } from '@aztec/foundation'; -export const randomBytes = (len: number) => { - return nodeCrypto.randomBytes(len) as Buffer; -}; +import { AppendOnlyTreeSnapshot, ContractData } from './l2_block.js'; export const randomAppendOnlyTreeSnapshot = (nextIndex: number): AppendOnlyTreeSnapshot => { return { diff --git a/yarn-project/archiver/src/movetofoundation/log/console.ts b/yarn-project/archiver/src/movetofoundation/log/console.ts deleted file mode 100644 index 6315a10e0e75..000000000000 --- a/yarn-project/archiver/src/movetofoundation/log/console.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type Logger = (...args: any[]) => void; - -class ConsoleLogger { - constructor(private prefix: string, private logger: (...args: any[]) => void = console.log) {} - - public log(...args: any[]) { - this.logger(`${this.prefix}:`, ...args); - } -} - -export function createLogger(prefix: string): Logger { - if (prefix) { - const logger = new ConsoleLogger(prefix, console.log); - return (...args: any[]) => logger.log(...args); - } - return console.log; -} diff --git a/yarn-project/archiver/src/movetofoundation/log/debug.ts b/yarn-project/archiver/src/movetofoundation/log/debug.ts deleted file mode 100644 index f9be3945d9b3..000000000000 --- a/yarn-project/archiver/src/movetofoundation/log/debug.ts +++ /dev/null @@ -1,38 +0,0 @@ -import debug from 'debug'; - -let preLogHook: ((...args: any[]) => void) | undefined; -let postLogHook: ((...args: any[]) => void) | undefined; - -function theFunctionThroughWhichAllLogsPass(logger: any, ...args: any[]) { - if (!debug.enabled(logger.namespace)) { - return; - } - if (preLogHook) { - preLogHook(logger.namespace, ...args); - } - logger(...args); - if (postLogHook) { - postLogHook(logger.namespace, ...args); - } -} - -export function createDebugLogger(name: string) { - const logger = debug(name); - return (...args: any[]) => theFunctionThroughWhichAllLogsPass(logger, ...args); -} - -export function setPreDebugLogHook(fn: (...args: any[]) => void) { - preLogHook = fn; -} - -export function setPostDebugLogHook(fn: (...args: any[]) => void) { - postLogHook = fn; -} - -export function enableLogs(str: string) { - debug.enable(str); -} - -export function isLogEnabled(str: string) { - return debug.enabled(str); -} diff --git a/yarn-project/archiver/src/movetofoundation/log/index.ts b/yarn-project/archiver/src/movetofoundation/log/index.ts deleted file mode 100644 index 1705648184af..000000000000 --- a/yarn-project/archiver/src/movetofoundation/log/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './console.js'; -export * from './debug.js'; -export * from './log_history.js'; diff --git a/yarn-project/archiver/src/movetofoundation/log/log_history.test.ts b/yarn-project/archiver/src/movetofoundation/log/log_history.test.ts deleted file mode 100644 index 62dc8c4ae6f8..000000000000 --- a/yarn-project/archiver/src/movetofoundation/log/log_history.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { jest } from '@jest/globals'; -import { createDebugLogger, enableLogs } from './debug.js'; -import { LogHistory } from './log_history.js'; - -jest.useFakeTimers(); - -describe('log history', () => { - let debug: (...any: any[]) => void; - let logHistory: LogHistory; - const timestemp = new Date().toISOString(); - const name = 'test:a'; - - beforeEach(() => { - debug = createDebugLogger(name); - enableLogs(name); - logHistory = new LogHistory(); - }); - - it('keeps debug logs', () => { - logHistory.enable(); - expect(logHistory.getLogs()).toEqual([]); - debug('0'); - debug('1', 2); - debug('2', { key: ['value'] }, Buffer.alloc(2)); - expect(logHistory.getLogs()).toEqual([ - [timestemp, name, '0'], - [timestemp, name, '1', 2], - [timestemp, name, '2', { key: ['value'] }, Buffer.alloc(2)], - ]); - }); - - it('does not keep logs if not enabled', () => { - debug('0'); - debug('1', 2); - expect(logHistory.getLogs()).toEqual([]); - }); - - it('returns last n logs', () => { - logHistory.enable(); - expect(logHistory.getLogs()).toEqual([]); - debug('0'); - debug('1'); - debug('2'); - debug('3'); - debug('4'); - expect(logHistory.getLogs(2)).toEqual([ - [timestemp, name, '3'], - [timestemp, name, '4'], - ]); - }); - - it('only keeps logs with enabled namespace', () => { - logHistory.enable(); - const name2 = 'test:b'; - const debug2 = createDebugLogger(name2); - debug('0'); - debug2('zero'); - expect(logHistory.getLogs()).toEqual([[timestemp, name, '0']]); - - enableLogs(`${name},${name2}`); - debug('1', 2); - debug2('one', 3); - expect(logHistory.getLogs()).toEqual([ - [timestemp, name, '0'], - [timestemp, name, '1', 2], - [timestemp, name2, 'one', 3], - ]); - }); - - it('clears all logs', () => { - logHistory.enable(); - debug('0'); - debug('1'); - debug('2'); - logHistory.clear(); - expect(logHistory.getLogs()).toEqual([]); - }); - - it('clears first n logs', () => { - logHistory.enable(); - debug('0'); - debug('1'); - debug('2'); - logHistory.clear(2); - expect(logHistory.getLogs()).toEqual([[timestemp, name, '2']]); - }); -}); diff --git a/yarn-project/archiver/src/movetofoundation/log/log_history.ts b/yarn-project/archiver/src/movetofoundation/log/log_history.ts deleted file mode 100644 index d60151a78c1a..000000000000 --- a/yarn-project/archiver/src/movetofoundation/log/log_history.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { setPreDebugLogHook } from './debug.js'; - -export class LogHistory { - private logs: any[][] = []; - - public enable() { - setPreDebugLogHook((...args: any[]) => { - this.logs.push([new Date().toISOString(), ...args]); - }); - } - - public getLogs(last = 0) { - return last ? this.logs.slice(-last) : this.logs; - } - - public clear(count = this.logs.length) { - this.logs = this.logs.slice(count); - } -} - -export const logHistory = new LogHistory(); diff --git a/yarn-project/archiver/tsconfig.dest.json b/yarn-project/archiver/tsconfig.dest.json index 74be6e829f10..424bb413ffbc 100644 --- a/yarn-project/archiver/tsconfig.dest.json +++ b/yarn-project/archiver/tsconfig.dest.json @@ -1,4 +1,12 @@ { "extends": ".", - "exclude": ["**/*.test.*", "**/fixtures/*"], + "references": [ + { + "path": "../ethereum.js/tsconfig.dest.json" + }, + { + "path": "../foundation/tsconfig.dest.json" + } + ], + "exclude": ["**/*.test.*", "**/fixtures/*"] } diff --git a/yarn-project/archiver/tsconfig.json b/yarn-project/archiver/tsconfig.json index f67ddec9fd6b..afaa5db00cb7 100644 --- a/yarn-project/archiver/tsconfig.json +++ b/yarn-project/archiver/tsconfig.json @@ -5,5 +5,12 @@ "rootDir": "src", "tsBuildInfoFile": ".tsbuildinfo" }, - "include": ["src"] -} + "references": [ + { + "path": "../foundation/tsconfig.dest.json" + } + ], + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/yarn-project/aztec-cli/.eslintrc.cjs b/yarn-project/aztec-cli/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/aztec-cli/.eslintrc.cjs +++ b/yarn-project/aztec-cli/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/aztec-cli/package.json b/yarn-project/aztec-cli/package.json index 97e04c58a384..9d6da2973d6e 100644 --- a/yarn-project/aztec-cli/package.json +++ b/yarn-project/aztec-cli/package.json @@ -36,7 +36,6 @@ "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/public-client/.dockerignore b/yarn-project/aztec-node/.dockerignore similarity index 100% rename from yarn-project/public-client/.dockerignore rename to yarn-project/aztec-node/.dockerignore diff --git a/yarn-project/aztec-node/.eslintrc.cjs b/yarn-project/aztec-node/.eslintrc.cjs new file mode 100644 index 000000000000..e659927475c0 --- /dev/null +++ b/yarn-project/aztec-node/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/public-client/.gitignore b/yarn-project/aztec-node/.gitignore similarity index 100% rename from yarn-project/public-client/.gitignore rename to yarn-project/aztec-node/.gitignore diff --git a/yarn-project/public-client/Dockerfile b/yarn-project/aztec-node/Dockerfile similarity index 57% rename from yarn-project/public-client/Dockerfile rename to yarn-project/aztec-node/Dockerfile index f376fd807bff..1cf447897679 100644 --- a/yarn-project/public-client/Dockerfile +++ b/yarn-project/aztec-node/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder -COPY public-client public-client -WORKDIR /usr/src/yarn-project/public-client +COPY aztec-node aztec-node +WORKDIR /usr/src/yarn-project/aztec-node RUN yarn build && yarn formatting && yarn test # Prune dev dependencies. See comment in base image. @@ -9,6 +9,6 @@ RUN yarn cache clean RUN yarn workspaces focus --production > /dev/null FROM node:18-alpine -COPY --from=builder /usr/src/yarn-project/public-client /usr/src/yarn-project/public-client -WORKDIR /usr/src/yarn-project/public-client +COPY --from=builder /usr/src/yarn-project/aztec-node /usr/src/yarn-project/aztec-node +WORKDIR /usr/src/yarn-project/aztec-node ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/aztec-node/README.md b/yarn-project/aztec-node/README.md new file mode 100644 index 000000000000..089629c6ea71 --- /dev/null +++ b/yarn-project/aztec-node/README.md @@ -0,0 +1 @@ +# Aztec Node diff --git a/yarn-project/aztec-node/package.json b/yarn-project/aztec-node/package.json new file mode 100644 index 000000000000..af38735290d3 --- /dev/null +++ b/yarn-project/aztec-node/package.json @@ -0,0 +1,49 @@ +{ + "name": "@aztec/aztec-node", + "version": "0.0.0", + "main": "dest/index.js", + "type": "module", + "exports": "./dest/index.js", + "typedoc": { + "entryPoint": "./src/index.ts", + "displayName": "Aztec Node", + "tsconfig": "./tsconfig.dest.json" + }, + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": ".*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/archiver": "workspace:^", + "@aztec/ethereum.js": "workspace:^", + "@aztec/p2p": "workspace:^", + "@aztec/world-state": "workspace:^", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@jest/globals": "^29.4.3", + "@rushstack/eslint-patch": "^1.1.4", + "@types/jest": "^29.4.0", + "@types/node": "^18.7.23", + "jest": "^28.1.3", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + } +} diff --git a/yarn-project/aztec-node/src/aztec_node.test.ts b/yarn-project/aztec-node/src/aztec_node.test.ts new file mode 100644 index 000000000000..ba2fc950e085 --- /dev/null +++ b/yarn-project/aztec-node/src/aztec_node.test.ts @@ -0,0 +1,29 @@ +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { AccumulatedTxData, Tx } from '@aztec/p2p'; +import { AztecNode } from './index.js'; + +const ETHEREUM_HOST = 'http://localhost:8545/'; +const ROLLUP_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3'; +const YEETER_ADDRESS = '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512'; + +describe('AztecNode', () => { + it('should start and stop all services', async () => { + const node = new AztecNode(); + await node.init(ETHEREUM_HOST, EthAddress.fromString(ROLLUP_ADDRESS), EthAddress.fromString(YEETER_ADDRESS)); + const isReady = await node.isReady(); + expect(isReady).toBeTruthy(); + await node.stop(); + }); + + it('should accept a transaction', async () => { + const node = new AztecNode(); + await node.init(ETHEREUM_HOST, EthAddress.fromString(ROLLUP_ADDRESS), EthAddress.fromString(YEETER_ADDRESS)); + const isReady = await node.isReady(); + expect(isReady).toBeTruthy(); + const tx: Tx = new Tx(AccumulatedTxData.random()); + await node.sendTx(tx); + const txs = await node.getTxs(); + expect(txs.length).toBe(1); + expect(txs[0].txId).toEqual(tx.txId); + }); +}); diff --git a/yarn-project/aztec-node/src/index.ts b/yarn-project/aztec-node/src/index.ts new file mode 100644 index 000000000000..2e9253bb3939 --- /dev/null +++ b/yarn-project/aztec-node/src/index.ts @@ -0,0 +1,109 @@ +import { default as levelup } from 'levelup'; +import { default as memdown } from 'memdown'; +import { L2BlockSource, Archiver } from '@aztec/archiver'; +import { P2P, P2PCLient } from '@aztec/p2p'; +import { MerkleTrees, WorldStateSynchroniser, ServerWorldStateSynchroniser } from '@aztec/world-state'; +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { Tx } from '@aztec/p2p'; + +export { Tx } from '@aztec/p2p'; + +/* eslint-disable @typescript-eslint/ban-ts-comment */ +// @ts-ignore +export const createMemDown = () => memdown(); + +/** + * The public client. + */ +export class AztecNode { + private p2pClient?: P2P; + private blockSource?: L2BlockSource; + private merkleTreeDB?: MerkleTrees; + private worldStateSynchroniser?: WorldStateSynchroniser; + + constructor() {} + + /** + * Initialises the Aztec Node, wait for component to sync. + * @param rpcUrl - The URL of an Ethereum RPC node. + * @param rollupAddress - The rollup contract address. + * @param yeeterAddress - The yeeter contract address. + */ + public async init(rpcUrl: string, rollupAddress: EthAddress, yeeterAddress: EthAddress) { + // first configure the block source + this.blockSource = Archiver.new(rpcUrl, rollupAddress, yeeterAddress); + + await this.blockSource.start(); + + // give the block source to the P2P network and the world state synchroniser + this.p2pClient = new P2PCLient(this.blockSource); + const db = levelup(createMemDown()); + this.merkleTreeDB = await MerkleTrees.new(db); + this.worldStateSynchroniser = new ServerWorldStateSynchroniser(this.merkleTreeDB, this.blockSource); + + // start both and wait for them to sync from the block source + const p2pSyncPromise = this.p2pClient.start(); + const worldStateSyncPromise = this.worldStateSynchroniser.start(); + await Promise.all([p2pSyncPromise, worldStateSyncPromise]); + + // create and start the sequencer + // new Sequencer(this.blockSource, this.p2pClient, this.merkleTreeDB, this.publisher); + } + + /** + * Method to determine if the node is ready to accept transactions. + * @returns - Flag indicating the readiness for tx submission. + */ + public async isReady() { + return (await this.p2pClient?.isReady()) ?? false; + } + + /** + * Method to request blocks. Will attempt to return all requested blocks but will return only those available. + * @param from - The start of the range of blocks to return. + * @param take - The number of blocks desired. + * @returns The blocks requested. + */ + public async getBlocks(from: number, take: number) { + this.verifyInitialised(); + return (await this.blockSource?.getL2Blocks(from, take)) ?? []; + } + + /** + * Method to submit a transaction to the p2p pool. + * @param tx - The transaction to be submitted. + */ + public async sendTx(tx: Tx) { + this.verifyInitialised(); + await this.p2pClient!.sendTx(tx); + } + + /** + * Method to stop the aztec node. + */ + public async stop() { + this.verifyInitialised(); + await this.p2pClient!.stop(); + await this.worldStateSynchroniser!.stop(); + await this.merkleTreeDB!.stop(); + await this.blockSource!.stop(); + } + + /** + * Method to retrieve pending txs. + * @returns - The pending txs. + */ + public async getTxs() { + return await this.p2pClient!.getTxs(); + } + + /** + * Method to verify that we are initialised, throws if not. + */ + private verifyInitialised() { + const invalid = [this.blockSource, this.merkleTreeDB, this.p2pClient, this.worldStateSynchroniser].filter(x => !x); + if (invalid.length) { + throw new Error('Aztec Node not initialised'); + } + } +} diff --git a/yarn-project/aztec-node/tsconfig.dest.json b/yarn-project/aztec-node/tsconfig.dest.json new file mode 100644 index 000000000000..1c9a9e1edac8 --- /dev/null +++ b/yarn-project/aztec-node/tsconfig.dest.json @@ -0,0 +1,18 @@ +{ + "extends": ".", + "references": [ + { + "path": "../archiver/tsconfig.dest.json" + }, + { + "path": "../foundation/tsconfig.dest.json" + }, + { + "path": "../p2p/tsconfig.dest.json" + }, + { + "path": "../world-state/tsconfig.dest.json" + } + ], + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/yarn-project/public-client/tsconfig.json b/yarn-project/aztec-node/tsconfig.json similarity index 100% rename from yarn-project/public-client/tsconfig.json rename to yarn-project/aztec-node/tsconfig.json diff --git a/yarn-project/aztec-rpc/.eslintrc.cjs b/yarn-project/aztec-rpc/.eslintrc.cjs index 333ff38eab81..cc7b3df1143a 100644 --- a/yarn-project/aztec-rpc/.eslintrc.cjs +++ b/yarn-project/aztec-rpc/.eslintrc.cjs @@ -3,6 +3,7 @@ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: ['@aztec/eslint-config'], parserOptions: { tsconfigRootDir: __dirname }, + // TODO - Remove these rules. rules: { 'tsdoc/syntax': 'off', 'jsdoc/require-jsdoc': 'off', diff --git a/yarn-project/aztec-rpc/Dockerfile b/yarn-project/aztec-rpc/Dockerfile index 12c4ff17ca80..7fe3382a43bf 100644 --- a/yarn-project/aztec-rpc/Dockerfile +++ b/yarn-project/aztec-rpc/Dockerfile @@ -1,6 +1,7 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder - +COPY aztec-node aztec-node COPY aztec-rpc aztec-rpc +RUN cd aztec-node && yarn build WORKDIR /usr/src/yarn-project/aztec-rpc RUN yarn build && yarn formatting && yarn test diff --git a/yarn-project/aztec-rpc/package.json b/yarn-project/aztec-rpc/package.json index 692df8a5d5cb..fbf0ae595f68 100644 --- a/yarn-project/aztec-rpc/package.json +++ b/yarn-project/aztec-rpc/package.json @@ -12,7 +12,7 @@ "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", "build:dev": "tsc -b tsconfig.dest.json --watch", "clean": "rm -rf ./dest .tsbuildinfo", - "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 10 ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" }, "jest": { @@ -29,10 +29,11 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/aztec-node": "workspace:^", + "sha3": "^2.1.4", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/aztec-rpc/src/account_state/account_state.ts b/yarn-project/aztec-rpc/src/account_state/account_state.ts index 7fbb7994c916..8e5e97e27f91 100644 --- a/yarn-project/aztec-rpc/src/account_state/account_state.ts +++ b/yarn-project/aztec-rpc/src/account_state/account_state.ts @@ -1,6 +1,6 @@ -import { TxHash } from '../aztec_node.js'; import { AztecAddress } from '../circuits.js'; import { Database } from '../database/index.js'; +import { TxHash } from '../tx/index.js'; export class AccountState { constructor(public readonly publicKey: AztecAddress, private db: Database) {} diff --git a/yarn-project/aztec-rpc/src/aztec_node.ts b/yarn-project/aztec-rpc/src/aztec_node.ts deleted file mode 100644 index 760d1745b297..000000000000 --- a/yarn-project/aztec-rpc/src/aztec_node.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AccumulatedTxData } from './circuits.js'; - -export class TxHash { - public static SIZE = 32; - - constructor(public readonly buffer: Buffer) {} - - public equals(rhs: TxHash) { - return this.buffer.equals(rhs.buffer); - } -} - -export class Tx { - constructor(public readonly proofData: Buffer, public readonly data: AccumulatedTxData) {} - - get txHash() { - return new TxHash(Buffer.alloc(32)); - } -} - -export class AztecNode { - sendTx(tx: Tx) { - return Promise.resolve(tx.txHash); - } - - getBlocks() { - return Promise.resolve([]); - } -} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts index cb699a54fd90..0cc7b0826c3b 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_client/aztec_rpc_client.ts @@ -1,7 +1,7 @@ -import { Tx, TxHash } from '../aztec_node.js'; +import { Tx } from '@aztec/aztec-node'; import { AztecAddress, EthAddress, Fr, Signature, TxRequest } from '../circuits.js'; import { ContractAbi } from '../noir.js'; -import { TxReceipt } from '../tx/index.js'; +import { TxHash, TxReceipt } from '../tx/index.js'; export interface AztecRPCClient { addAccount(): Promise; diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index cc0027efdfc4..e7f4d8a8845d 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -1,6 +1,6 @@ +import { AztecNode, Tx } from '@aztec/aztec-node'; import { generateFunctionSelector } from '../abi_coder/index.js'; import { AcirSimulator } from '../acir_simulator.js'; -import { AztecNode, Tx, TxHash } from '../aztec_node.js'; import { AztecRPCClient } from '../aztec_rpc_client/index.js'; import { AztecAddress, @@ -18,6 +18,7 @@ import { KeyStore } from '../key_store/index.js'; import { ContractAbi } from '../noir.js'; import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; +import { TxHash } from '../tx/index.js'; export class AztecRPCServer implements AztecRPCClient { constructor( @@ -122,12 +123,13 @@ export class AztecRPCServer implements AztecRPCClient { public async createTx(txRequest: TxRequest, signature: Signature) { const { kernelData, callData } = await this.simulator.simulate(txRequest); const privateInputs = new KernelPrivateInputs(txRequest, signature, kernelData, callData); - const { proofData, accumulatedTxData } = await this.proofGenerator.createProof(privateInputs); - return new Tx(proofData, accumulatedTxData); + const { accumulatedTxData } = await this.proofGenerator.createProof(privateInputs); + return new Tx(accumulatedTxData); } - public sendTx(tx: Tx) { - return this.node.sendTx(tx); + public async sendTx(tx: Tx) { + await this.node.sendTx(tx); + return new TxHash(tx.txId); } public async getTxReceipt(txHash: TxHash) { diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts index 8c8a1228de84..f266b65f63ba 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts @@ -1,19 +1,22 @@ +import { AztecNode } from '@aztec/aztec-node'; import { AcirSimulator } from '../acir_simulator.js'; -import { AztecNode } from '../aztec_node.js'; -import { KernelCircuitProver } from '../circuits.js'; +import { EthAddress, KernelCircuitProver } from '../circuits.js'; import { MemoryDB } from '../database/index.js'; import { KeyStore, TestKeyStore } from '../key_store/index.js'; import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; import { AztecRPCServer } from './aztec_rpc_server.js'; -export function createAztecRPCServer({ +export async function createAztecRPCServer({ keyStore, node, db, synchroniser, simulator, proofGenerator, + rpcUrl, + rollupAddress, + yeeterAddress, }: { keyStore?: KeyStore; node?: AztecNode; @@ -21,13 +24,28 @@ export function createAztecRPCServer({ synchroniser?: Synchroniser; simulator?: AcirSimulator; proofGenerator?: ProofGenerator; + rpcUrl?: string; + rollupAddress?: EthAddress; + yeeterAddress?: EthAddress; } = {}) { keyStore = keyStore || new TestKeyStore(); - node = node || new AztecNode(); + if (!node) { + if (!rpcUrl) { + throw new Error('`rpcUrl` undefined.'); + } + if (!rollupAddress) { + throw new Error('`rollupAddress` undefined.'); + } + if (!yeeterAddress) { + throw new Error('`yeeterAddress` undefined.'); + } + node = new AztecNode(); + await node.init(rpcUrl!, rollupAddress! as any, yeeterAddress! as any); + } db = db || new MemoryDB(); synchroniser = synchroniser || new Synchroniser(node, db); simulator = simulator || new AcirSimulator(); proofGenerator = proofGenerator || new ProofGenerator(new KernelCircuitProver()); - return Promise.resolve(new AztecRPCServer(keyStore, synchroniser, simulator, proofGenerator, node, db)); + return new AztecRPCServer(keyStore, synchroniser, simulator, proofGenerator, node, db); } diff --git a/yarn-project/aztec-rpc/src/circuits.ts b/yarn-project/aztec-rpc/src/circuits.ts index 3a387b84cd6e..4611a8f863bd 100644 --- a/yarn-project/aztec-rpc/src/circuits.ts +++ b/yarn-project/aztec-rpc/src/circuits.ts @@ -17,6 +17,10 @@ export class EthAddress { return new EthAddress(randomBytes(20)); } + public static fromString(address: string) { + return new EthAddress(Buffer.from(address.replace(/^0x/i, ''), 'hex')); + } + constructor(public readonly buffer: Buffer) {} } diff --git a/yarn-project/aztec-rpc/src/database/database.ts b/yarn-project/aztec-rpc/src/database/database.ts index a0522bf61673..3e74a51a55fa 100644 --- a/yarn-project/aztec-rpc/src/database/database.ts +++ b/yarn-project/aztec-rpc/src/database/database.ts @@ -1,5 +1,5 @@ -import { TxHash } from '../aztec_node.js'; import { ContractDataSource } from '../contract_data_source/index.js'; +import { TxHash } from '../tx/index.js'; import { TxDao } from './tx_dao.js'; export interface Database extends ContractDataSource { diff --git a/yarn-project/aztec-rpc/src/database/memory_db.ts b/yarn-project/aztec-rpc/src/database/memory_db.ts index cda0907910a2..cc2215964d08 100644 --- a/yarn-project/aztec-rpc/src/database/memory_db.ts +++ b/yarn-project/aztec-rpc/src/database/memory_db.ts @@ -1,5 +1,5 @@ -import { TxHash } from '../aztec_node.js'; import { MemoryContractDataSource } from '../contract_data_source/index.js'; +import { TxHash } from '../tx/index.js'; import { Database } from './database.js'; import { TxDao } from './tx_dao.js'; diff --git a/yarn-project/aztec-rpc/src/database/tx_dao.ts b/yarn-project/aztec-rpc/src/database/tx_dao.ts index f8c3bbb93467..30d0b77b5624 100644 --- a/yarn-project/aztec-rpc/src/database/tx_dao.ts +++ b/yarn-project/aztec-rpc/src/database/tx_dao.ts @@ -1,5 +1,5 @@ -import { TxHash } from '../aztec_node.js'; import { AztecAddress } from '../circuits.js'; +import { TxHash } from '../tx/index.js'; export class TxDao { constructor( diff --git a/yarn-project/aztec-rpc/src/index.ts b/yarn-project/aztec-rpc/src/index.ts index 134755851ae3..9a95a92fb7bf 100644 --- a/yarn-project/aztec-rpc/src/index.ts +++ b/yarn-project/aztec-rpc/src/index.ts @@ -3,7 +3,7 @@ export * from './aztec_rpc_client/index.js'; export * from './aztec_rpc_server/index.js'; export * from './tx/index.js'; +export { Tx } from '@aztec/aztec-node'; // TODO - only export necessary stuffs -export * from './aztec_node.js'; export * from './circuits.js'; export * from './noir.js'; diff --git a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts index adddc5135f4e..383ef462f490 100644 --- a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts +++ b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts @@ -3,8 +3,9 @@ import { KernelCircuitProver, KernelPrivateInputs } from '../circuits.js'; export class ProofGenerator { constructor(private prover: KernelCircuitProver) {} - createProof(inputs: KernelPrivateInputs) { + public async createProof(inputs: KernelPrivateInputs) { // TODO - iterate - return this.prover.createProof(inputs); + const { accumulatedTxData } = await this.prover.createProof(inputs); + return { accumulatedTxData: accumulatedTxData as any }; } } diff --git a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts index 7234f751574d..521b5e693516 100644 --- a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts +++ b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts @@ -1,5 +1,5 @@ +import { AztecNode } from '@aztec/aztec-node'; import { AccountState } from '../account_state/index.js'; -import { AztecNode } from '../aztec_node.js'; import { AztecAddress } from '../circuits.js'; import { Database } from '../database/index.js'; diff --git a/yarn-project/aztec-rpc/src/tx/index.ts b/yarn-project/aztec-rpc/src/tx/index.ts index 0576563fb7f8..342a3450227b 100644 --- a/yarn-project/aztec-rpc/src/tx/index.ts +++ b/yarn-project/aztec-rpc/src/tx/index.ts @@ -1 +1,2 @@ +export * from './tx_hash.js'; export * from './tx_receipt.js'; diff --git a/yarn-project/aztec-rpc/src/tx/tx_hash.ts b/yarn-project/aztec-rpc/src/tx/tx_hash.ts new file mode 100644 index 000000000000..c6a819b82cb3 --- /dev/null +++ b/yarn-project/aztec-rpc/src/tx/tx_hash.ts @@ -0,0 +1,9 @@ +export class TxHash { + public static SIZE = 32; + + constructor(public readonly buffer: Buffer) {} + + public equals(rhs: TxHash) { + return this.buffer.equals(rhs.buffer); + } +} diff --git a/yarn-project/aztec-rpc/src/tx/tx_receipt.ts b/yarn-project/aztec-rpc/src/tx/tx_receipt.ts index e4671e59c51c..fce2e72ffa89 100644 --- a/yarn-project/aztec-rpc/src/tx/tx_receipt.ts +++ b/yarn-project/aztec-rpc/src/tx/tx_receipt.ts @@ -1,5 +1,5 @@ -import { TxHash } from '../aztec_node.js'; import { AztecAddress } from '../circuits.js'; +import { TxHash } from './tx_hash.js'; export interface TxReceipt { txHash: TxHash; diff --git a/yarn-project/aztec.js/.eslintrc.cjs b/yarn-project/aztec.js/.eslintrc.cjs index 333ff38eab81..e659927475c0 100644 --- a/yarn-project/aztec.js/.eslintrc.cjs +++ b/yarn-project/aztec.js/.eslintrc.cjs @@ -1,21 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, - rules: { - 'tsdoc/syntax': 'off', - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-description-complete-sentence': 'off', - 'jsdoc/require-hyphen-before-param-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-name': 'off', - 'jsdoc/require-property': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-property-name': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/aztec.js/Dockerfile b/yarn-project/aztec.js/Dockerfile index f1c41c6611c5..4852ad583f28 100644 --- a/yarn-project/aztec.js/Dockerfile +++ b/yarn-project/aztec.js/Dockerfile @@ -1,6 +1,15 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder - +COPY foundation foundation +COPY ethereum.js ethereum.js +COPY archiver archiver +COPY world-state world-state +COPY p2p p2p +COPY aztec-node aztec-node +COPY aztec-rpc aztec-rpc COPY aztec.js aztec.js +RUN cd ethereum.js && yarn build && cd ../archiver && yarn build && cd ../world-state && yarn build && cd ../p2p && yarn build +RUN cd ../aztec-node && yarn build +RUN cd ../aztec-rpc && yarn build WORKDIR /usr/src/yarn-project/aztec.js RUN yarn build && yarn formatting && yarn test diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 7eff00fb239e..cbdf9fb80b3d 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -12,7 +12,7 @@ "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", "build:dev": "tsc -b tsconfig.dest.json --watch", "clean": "rm -rf ./dest .tsbuildinfo", - "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 10 ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" }, "jest": { @@ -30,11 +30,10 @@ }, "dependencies": { "@aztec/aztec-rpc": "workspace:^", - "sha3": "^2.1.4", + "@aztec/foundation": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/end-to-end/.eslintrc.cjs b/yarn-project/end-to-end/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/end-to-end/.eslintrc.cjs +++ b/yarn-project/end-to-end/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/end-to-end/Dockerfile b/yarn-project/end-to-end/Dockerfile index 9391d0589e38..b527c28e07e4 100644 --- a/yarn-project/end-to-end/Dockerfile +++ b/yarn-project/end-to-end/Dockerfile @@ -1,10 +1,12 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder +COPY foundation foundation +COPY noir-contracts noir-contracts COPY aztec.js aztec.js RUN cd aztec.js && yarn build COPY end-to-end end-to-end WORKDIR /usr/src/yarn-project/end-to-end -RUN yarn build && yarn formatting +RUN yarn formatting # Prune dev dependencies. See comment in base image. RUN yarn cache clean diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index 402923a4dcb2..c0f669ddc22f 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -24,6 +24,8 @@ }, "dependencies": { "@aztec/aztec.js": "workspace:^", + "@aztec/foundation": "workspace:^", + "@aztec/noir-contracts": "workspace:^", "@types/jest": "^29.4.0", "jest": "^28.1.3", "ts-jest": "^28.0.7", @@ -31,7 +33,6 @@ "typescript": "^4.9.5" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/node": "^18.7.23", diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index a1b7a6a0aed0..c1bb04fd1190 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -1,15 +1,23 @@ import { AztecAddress, AztecRPCClient, ContractDeployer } from '@aztec/aztec.js'; -import { createAztecNode } from '@aztec/aztec-node'; -import { createAztecRPCServer } from '@aztec/aztec-rpc'; -import { abi } from './fixtures/test_contract.json'; +import { createAztecRPCServer, EthAddress } from '@aztec/aztec-rpc'; +import abi from '@aztec/noir-contracts/examples/test_contract.json'; + +const { + ETHEREUM_HOST = 'http://localhost:8545', + ROLLUP_ROLLUP_ADDRESS = '0x5FbDB2315678afecb367f032d93F642f64180aa3', + YEETER_ADDRESS = '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512', +} = process.env; describe('e2e_deploy_contract', () => { let arc: AztecRPCClient; let accounts: AztecAddress[]; beforeAll(async () => { - const node = await createAztecNode(); - arc = await createAztecRPCServer({ node }); + arc = await createAztecRPCServer({ + rpcUrl: ETHEREUM_HOST, + rollupAddress: EthAddress.fromString(ROLLUP_ROLLUP_ADDRESS), + yeeterAddress: EthAddress.fromString(YEETER_ADDRESS), + }); await arc.addAccount(); accounts = await arc.getAccounts(); }); @@ -25,7 +33,8 @@ describe('e2e_deploy_contract', () => { ); const { contractAddress } = receipt; - const bytecode = await arc.getCode(contractAddress); - expect(bytecode).toEqual(abi.bytecode); + const constructor = abi.functions.find(f => f.name === 'constructor')!; + const bytecode = await arc.getCode(contractAddress!); + expect(bytecode).toEqual(constructor.bytecode); }); }); diff --git a/yarn-project/eslint-config/index.js b/yarn-project/eslint-config/index.js deleted file mode 100644 index 54550e5de21f..000000000000 --- a/yarn-project/eslint-config/index.js +++ /dev/null @@ -1,93 +0,0 @@ -const contexts = [ - 'TSMethodDefinition', - 'MethodDefinition', - 'TSParameterProperty[accessibility=public]', - 'TSPropertySignature', - 'PropertySignature', - 'TSInterfaceDeclaration', - 'InterfaceDeclaration', - 'TSPropertyDefinition[accessibility=public]', - 'PropertyDefinition[accessibility=public]', - 'TSTypeAliasDeclaration', - 'TypeAliasDeclaration', - 'TSTypeDeclaration', - 'TypeDeclaration', - 'TSEnumDeclaration', - 'EnumDeclaration', - 'TSClassDeclaration', - 'ClassDeclaration', - 'TSClassExpression', - 'ClassExpression', - 'TSFunctionExpression', - 'FunctionExpression', - 'TSInterfaceExpression', - 'InterfaceExpression', - 'TSEnumExpression', - 'EnumExpression', -]; - -module.exports = { - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], - root: true, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'eslint-plugin-tsdoc', 'jsdoc'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - parserOptions: { - project: ['./tsconfig.json'], - }, - }, - ], - env: { - node: true, - }, - rules: { - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-non-null-assertion': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/await-thenable': 'error', - '@typescript-eslint/no-floating-promises': 2, - 'require-await': 2, - 'no-constant-condition': 'off', - camelcase: 2, - 'no-restricted-imports': [ - 'warn', - { - patterns: [ - { - group: ['client-dest'], - message: "Fix this absolute garbage import. It's your duty to solve it before it spreads.", - }, - { - group: ['dest'], - message: 'You should not be importing from a build directory. Did you accidentally do a relative import?', - }, - ], - }, - ], - 'tsdoc/syntax': 'warn', - 'jsdoc/require-jsdoc': [ - 'warn', - { - contexts, - checkConstructors: false, - checkGetters: true, - checkSetters: true, - }, - ], - 'jsdoc/require-description': ['warn', { contexts }], - 'jsdoc/require-description-complete-sentence': ['warn'], - 'jsdoc/require-hyphen-before-param-description': ['warn'], - 'jsdoc/require-param': ['warn', { contexts, checkDestructured: false }], - 'jsdoc/require-param-description': ['warn', { contexts }], - 'jsdoc/require-param-name': ['warn', { contexts }], - 'jsdoc/require-property': ['warn', { contexts }], - 'jsdoc/require-property-description': ['warn', { contexts }], - 'jsdoc/require-property-name': ['warn', { contexts }], - 'jsdoc/require-returns': ['warn', { contexts }], - 'jsdoc/require-returns-description': ['warn', { contexts }], - }, - ignorePatterns: ['node_modules', 'dest*', 'dist', '*.js', '.eslintrc.cjs'], -}; diff --git a/yarn-project/eslint-config/package.json b/yarn-project/eslint-config/package.json deleted file mode 100644 index b059ec8e99cb..000000000000 --- a/yarn-project/eslint-config/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@aztec/eslint-config", - "version": "0.0.0", - "packageManager": "yarn@3.2.2", - "dependencies": { - "@typescript-eslint/eslint-plugin": "^5.38.0", - "@typescript-eslint/parser": "^5.38.0", - "eslint": "^8.21.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-jsdoc": "^40.0.0", - "eslint-plugin-tsdoc": "^0.2.17" - } -} diff --git a/yarn-project/ethereum.js/.eslintrc.cjs b/yarn-project/ethereum.js/.eslintrc.cjs index 333ff38eab81..e659927475c0 100644 --- a/yarn-project/ethereum.js/.eslintrc.cjs +++ b/yarn-project/ethereum.js/.eslintrc.cjs @@ -1,21 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, - rules: { - 'tsdoc/syntax': 'off', - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-description-complete-sentence': 'off', - 'jsdoc/require-hyphen-before-param-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-name': 'off', - 'jsdoc/require-property': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-property-name': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/ethereum.js/Dockerfile b/yarn-project/ethereum.js/Dockerfile index 1f079013d720..dc4ab6be25f5 100644 --- a/yarn-project/ethereum.js/Dockerfile +++ b/yarn-project/ethereum.js/Dockerfile @@ -1,5 +1,6 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder +COPY foundation foundation COPY ethereum.js ethereum.js WORKDIR /usr/src/yarn-project/ethereum.js RUN yarn build && yarn formatting && yarn test @@ -9,4 +10,4 @@ RUN yarn cache clean RUN yarn workspaces focus --production > /dev/null FROM alpine:latest -COPY --from=builder /usr/src/yarn-project/ethereum.js /usr/src/yarn-project/ethereum.js \ No newline at end of file +COPY --from=builder /usr/src/yarn-project/ethereum.js /usr/src/yarn-project/ethereum.js diff --git a/yarn-project/ethereum.js/example/.eslintrc.cjs b/yarn-project/ethereum.js/example/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/ethereum.js/example/.eslintrc.cjs +++ b/yarn-project/ethereum.js/example/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/ethereum.js/example/package.json b/yarn-project/ethereum.js/example/package.json index 78df09b20ded..c396ababa2c7 100644 --- a/yarn-project/ethereum.js/example/package.json +++ b/yarn-project/ethereum.js/example/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@aztec/ethereum.js": "workspace:^", + "@aztec/foundation": "workspace:^", "source-map-support": "^0.5.21" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@rushstack/eslint-patch": "^1.2.0", "@types/node": "^18.15.0", "typescript": "^4.9.5" diff --git a/yarn-project/ethereum.js/package.json b/yarn-project/ethereum.js/package.json index 10f14f62203f..b2683ba40884 100644 --- a/yarn-project/ethereum.js/package.json +++ b/yarn-project/ethereum.js/package.json @@ -47,6 +47,7 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/foundation": "workspace:^", "bip39": "^3.0.4", "browserify-aes": "^1.2.0", "debug": "^4.3.4", @@ -60,7 +61,6 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.5.0", "@rushstack/eslint-patch": "^1.2.0", "@types/elliptic": "^6.4.14", diff --git a/yarn-project/ethereum.js/tsconfig.dest.json b/yarn-project/ethereum.js/tsconfig.dest.json index ba8512d45cec..87af7f6c1c85 100644 --- a/yarn-project/ethereum.js/tsconfig.dest.json +++ b/yarn-project/ethereum.js/tsconfig.dest.json @@ -1,4 +1,12 @@ { "extends": ".", - "exclude": ["src/**/*.test.ts", "src/**/fixtures/*"] -} + "references": [ + { + "path": "../foundation/tsconfig.dest.json" + } + ], + "exclude": [ + "src/**/*.test.ts", + "src/**/fixtures/*" + ] +} \ No newline at end of file diff --git a/yarn-project/ethereum.js/tsconfig.json b/yarn-project/ethereum.js/tsconfig.json index 33a248f3824c..c6e97daca24f 100644 --- a/yarn-project/ethereum.js/tsconfig.json +++ b/yarn-project/ethereum.js/tsconfig.json @@ -6,5 +6,10 @@ "rootDir": "src", "tsBuildInfoFile": ".tsbuildinfo" }, + "references": [ + { + "path": "../foundation/tsconfig.dest.json" + } + ], "include": ["src", "src/eth_typed_data/fixtures/*.json"] } diff --git a/yarn-project/foundation b/yarn-project/foundation new file mode 160000 index 000000000000..9086f3807942 --- /dev/null +++ b/yarn-project/foundation @@ -0,0 +1 @@ +Subproject commit 9086f3807942459e0c8c86b174f1c2f11aae4976 diff --git a/yarn-project/kernel-simulator/.eslintrc.cjs b/yarn-project/kernel-simulator/.eslintrc.cjs index 333ff38eab81..e659927475c0 100644 --- a/yarn-project/kernel-simulator/.eslintrc.cjs +++ b/yarn-project/kernel-simulator/.eslintrc.cjs @@ -1,21 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, - rules: { - 'tsdoc/syntax': 'off', - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-description-complete-sentence': 'off', - 'jsdoc/require-hyphen-before-param-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-name': 'off', - 'jsdoc/require-property': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-property-name': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/kernel-simulator/package.json b/yarn-project/kernel-simulator/package.json index 9e4ae664f049..e15ea6f7d5a5 100644 --- a/yarn-project/kernel-simulator/package.json +++ b/yarn-project/kernel-simulator/package.json @@ -33,7 +33,6 @@ "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/key-store/.eslintrc.cjs b/yarn-project/key-store/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/key-store/.eslintrc.cjs +++ b/yarn-project/key-store/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/key-store/package.json b/yarn-project/key-store/package.json index c84146dd7966..472205b4916b 100644 --- a/yarn-project/key-store/package.json +++ b/yarn-project/key-store/package.json @@ -29,10 +29,10 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/foundation": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/l1-contracts/.eslintrc.cjs b/yarn-project/l1-contracts/.eslintrc.cjs new file mode 100644 index 000000000000..e659927475c0 --- /dev/null +++ b/yarn-project/l1-contracts/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/l1-contracts/Dockerfile b/yarn-project/l1-contracts/Dockerfile new file mode 100644 index 000000000000..8c4489541f8f --- /dev/null +++ b/yarn-project/l1-contracts/Dockerfile @@ -0,0 +1,14 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY l1-contracts l1-contracts +WORKDIR /usr/src/yarn-project/l1-contracts +RUN yarn build && yarn formatting && yarn test + +# Prune dev dependencies. See comment in base image. +RUN yarn cache clean +RUN yarn workspaces focus --production > /dev/null + +FROM node:18-alpine +COPY --from=builder /usr/src/yarn-project/l1-contracts /usr/src/yarn-project/l1-contracts +WORKDIR /usr/src/yarn-project/l1-contracts +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/l1-contracts/README.md b/yarn-project/l1-contracts/README.md new file mode 100644 index 000000000000..39a517e874cf --- /dev/null +++ b/yarn-project/l1-contracts/README.md @@ -0,0 +1,3 @@ +# L1 Contracts + +Typed classes for the L1 contracts. diff --git a/yarn-project/l1-contracts/contracts.json b/yarn-project/l1-contracts/contracts.json new file mode 100644 index 000000000000..dc961d2a737c --- /dev/null +++ b/yarn-project/l1-contracts/contracts.json @@ -0,0 +1,9 @@ +{ + "outputPath": "./src/aztec-ethereumjs-contracts", + "contracts": { + "Rollup": { + "source": "foundry", + "buildFile": "../../l1-contracts/out/Rollup.sol/Rollup.json" + } + } +} \ No newline at end of file diff --git a/yarn-project/public-client/package.json b/yarn-project/l1-contracts/package.json similarity index 85% rename from yarn-project/public-client/package.json rename to yarn-project/l1-contracts/package.json index 76039a8f412f..e3242ac058da 100644 --- a/yarn-project/public-client/package.json +++ b/yarn-project/l1-contracts/package.json @@ -1,17 +1,17 @@ { - "name": "@aztec/public-client", + "name": "@aztec/l1-contracts", "version": "0.0.0", - "main": "dest/index.js", "type": "module", "exports": "./dest/index.js", "typedoc": { "entryPoint": "./src/index.ts", - "displayName": "Public Client", + "displayName": "L1 Contracts", "tsconfig": "./tsconfig.dest.json" }, "scripts": { "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", "build:dev": "tsc -b tsconfig.dest.json --watch", + "generate": "contract_gen_def", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" @@ -26,14 +26,14 @@ "moduleNameMapper": { "^(\\.{1,2}/.*)\\.js$": "$1" }, - "testRegex": ".*\\.test\\.ts$", + "testRegex": "./src/.*\\.test\\.ts$", "rootDir": "./src" }, "dependencies": { "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", + "@aztec/ethereum.js": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/Rollup.ts b/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/Rollup.ts new file mode 100644 index 000000000000..3f72c762e855 --- /dev/null +++ b/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/Rollup.ts @@ -0,0 +1,42 @@ +// THIS IS GENERATED CODE, DO NOT EDIT! +/* eslint-disable */ +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { EthereumRpc } from '@aztec/ethereum.js/eth_rpc'; +import { Contract, ContractTxReceipt, EventLog, Options, TxCall, TxSend } from '@aztec/ethereum.js/contract'; +import * as Bytes from '@aztec/ethereum.js/contract/bytes.js'; +import abi from './RollupAbi.js'; +export type RollupBlockProcessedEvent = { + rollupBlockNumber: bigint; +}; +export interface RollupBlockProcessedEventLog extends EventLog {} +interface RollupEvents { + RollupBlockProcessed: RollupBlockProcessedEvent; +} +interface RollupEventLogs { + RollupBlockProcessed: RollupBlockProcessedEventLog; +} +interface RollupTxEventLogs { + RollupBlockProcessed: RollupBlockProcessedEventLog[]; +} +export interface RollupTransactionReceipt extends ContractTxReceipt {} +interface RollupMethods { + processRollup(_proof: Bytes.Bytes, _inputs: Bytes.Bytes): TxSend; + rollupStateHash(): TxCall; + verifier(): TxCall; +} +export interface RollupDefinition { + methods: RollupMethods; + events: RollupEvents; + eventLogs: RollupEventLogs; +} +export class Rollup extends Contract { + constructor(eth: EthereumRpc, address?: EthAddress, options?: Options) { + super(eth, abi, address, options); + } + deploy(): TxSend { + return super.deployBytecode( + '0x60a060405234801561001057600080fd5b5060405161001d9061004b565b604051809103906000f080158015610039573d6000803e3d6000fd5b506001600160a01b0316608052610058565b61019d80610e8883390190565b608051610e0f610079600039600081816067015261016a0152610e0f6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80631ab9c603146100465780632b7ac3f314610062578063f81cccbe146100a1575b600080fd5b61004f60005481565b6040519081526020015b60405180910390f35b6100897f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610059565b6100b46100af366004610adf565b6100b6565b005b6000806000806100c585610235565b60005493975091955093509150158015906100e257508260005414155b1561011257600054604051632d2ef59f60e11b815260048101919091526024810184905260440160405180910390fd5b60408051600180825281830190925260009160208083019080368337019050509050818160008151811061014857610148610b43565b6020908102919091010152604051633a94343960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ea50d0e4906101a1908a908590600401610b7d565b602060405180830381865afa1580156101be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e29190610bf7565b6101ff576040516309bde33960e01b815260040160405180910390fd5b600083815560405186917f3b8a2090d4235f22cdb27dec2d75d724354dd3c747beb2df2bd09f1f251428b391a250505050505050565b600080600080610249856020015160e01c90565b9350610261610259600186610c36565b600487610283565b925061026f8460b887610283565b915061027a85610335565b90509193509193565b6040805160b880825260e082019092526000918291906020820181803683370190505090508460181c60208201538460101c60218201538460081c602282015384602382015360b46024820160b486602001860160045afa506002816040516102ec9190610c4f565b602060405180830381855afa158015610309573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061032c9190610c6b565b95945050505050565b60008060006103468461016c61049a565b909250905060008061036e8661035d866020610c84565b61036990610170610c9b565b61049a565b90925090506000806103a0886103848689610c9b565b61038f906020610c84565b61039b90610174610c9b565b61060d565b909250905060006103dd89846103b6888b610c9b565b6103c09190610c9b565b6103cb906020610c84565b6103d790610174610c9b565b8561076e565b604080516101ec8082526102208201909252919250906000908260208201818036833701905050905081602082018360208e0160045afa5061018c81018690526101ac81018890526101cc81018490526101ec810183905260405161020c9060029061044a908490610c4f565b602060405180830381855afa158015610467573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061048a9190610c6b565b9c9b505050505050505050505050565b8181016020015160e01c60006008816104b38285610cae565b67ffffffffffffffff8111156104cb576104cb610a3c565b6040519080825280602002602001820160405280156104f4578160200160208202803683370190505b50905060005b6105048386610cae565b8110156105f5576000610518826008610c84565b610523906020610c84565b61052e886024610c9b565b6105389190610c9b565b6040805161010080825261012082019092529192506000919060208201818036833701905050905061010060208201610100848c0160045afa506002816040516105829190610c4f565b602060405180830381855afa15801561059f573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906105c29190610c6b565b8484815181106105d4576105d4610b43565b602002602001018181525050505080806105ed90610cd0565b9150506104fa565b506000610601826108c4565b93505050509250929050565b8181016020015160e01c60006002816106268285610cae565b67ffffffffffffffff81111561063e5761063e610a3c565b604051908082528060200260200182016040528015610667578160200160208202803683370190505b50905060005b6106778386610cae565b81101561075657600061068b826040610c84565b610696886024610c9b565b6106a09190610c9b565b60408051818152606081018252919250600091906020820181803683370190505090506040602082016040848c0160045afa506002816040516106e39190610c4f565b602060405180830381855afa158015610700573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906107239190610c6b565b84848151811061073557610735610b43565b6020026020010181815250505050808061074e90610cd0565b91505061066d565b5083610761826108c4565b9350935050509250929050565b600060028161077d8285610cae565b67ffffffffffffffff81111561079557610795610a3c565b6040519080825280602002602001820160405280156107be578160200160208202803683370190505b50905060005b6107ce8386610cae565b8110156108b05760006107e2826068610c84565b6107ed886024610c9b565b6107f79190610c9b565b60408051606880825260a08201909252919250600091906020820181803683370190505090506068602082016068848c0160045afa5060028160405161083d9190610c4f565b602060405180830381855afa15801561085a573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061087d9190610c6b565b84848151811061088f5761088f610b43565b602002602001018181525050505080806108a890610cd0565b9150506107c4565b506108ba816108c4565b9695505050505050565b6000805b82516108d5826002610dcd565b10156108ed57806108e581610cd0565b9150506108c8565b60006108fa826002610dcd565b905080845260005b82811015610a175760005b82811015610a0457600286828151811061092957610929610b43565b60200260200101518783600161093f9190610c9b565b8151811061094f5761094f610b43565b6020026020010151604051602001610971929190918252602082015260400190565b60408051601f198184030181529082905261098b91610c4f565b602060405180830381855afa1580156109a8573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906109cb9190610c6b565b866109d7600284610cae565b815181106109e7576109e7610b43565b60209081029190910101526109fd600282610c9b565b905061090d565b5080610a0f81610cd0565b915050610902565b5083600081518110610a2b57610a2b610b43565b602002602001015192505050919050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610a6357600080fd5b813567ffffffffffffffff80821115610a7e57610a7e610a3c565b604051601f8301601f19908116603f01168101908282118183101715610aa657610aa6610a3c565b81604052838152866020858801011115610abf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215610af257600080fd5b823567ffffffffffffffff80821115610b0a57600080fd5b610b1686838701610a52565b93506020850135915080821115610b2c57600080fd5b50610b3985828601610a52565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b60005b83811015610b74578181015183820152602001610b5c565b50506000910152565b60408152600083518060408401526020610b9d8260608601838901610b59565b6060601f19601f93909301929092168401848103830185830152855192810183905285820192600091608001905b80831015610beb5784518252938301936001929092019190830190610bcb565b50979650505050505050565b600060208284031215610c0957600080fd5b81518015158114610c1957600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c4957610c49610c20565b92915050565b60008251610c61818460208701610b59565b9190910192915050565b600060208284031215610c7d57600080fd5b5051919050565b8082028115828204841417610c4957610c49610c20565b80820180821115610c4957610c49610c20565b600082610ccb57634e487b7160e01b600052601260045260246000fd5b500490565b600060018201610ce257610ce2610c20565b5060010190565b600181815b80851115610d24578160001904821115610d0a57610d0a610c20565b80851615610d1757918102915b93841c9390800290610cee565b509250929050565b600082610d3b57506001610c49565b81610d4857506000610c49565b8160018114610d5e5760028114610d6857610d84565b6001915050610c49565b60ff841115610d7957610d79610c20565b50506001821b610c49565b5060208310610133831016604e8410600b8410161715610da7575081810a610c49565b610db18383610ce9565b8060001904821115610dc557610dc5610c20565b029392505050565b6000610c198383610d2c56fea2646970667358221220ece9d35f0dabd2ce67f2fc7b08e612bd5e3e292de94f6df90a3bb48f782fd9ef64736f6c63430008120033608060405234801561001057600080fd5b5061017d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063937f6a101461003b578063ea50d0e41461005a575b600080fd5b60405168496d2061206d6f636b60b81b81526020015b60405180910390f35b610072610068366004610082565b6001949350505050565b6040519015158152602001610051565b6000806000806040858703121561009857600080fd5b843567ffffffffffffffff808211156100b057600080fd5b818701915087601f8301126100c457600080fd5b8135818111156100d357600080fd5b8860208285010111156100e557600080fd5b60209283019650945090860135908082111561010057600080fd5b818701915087601f83011261011457600080fd5b81358181111561012357600080fd5b8860208260051b850101111561013857600080fd5b9598949750506020019450505056fea2646970667358221220dccfdb9ed1ec020c6477c07aa6b7354d591126e95a8df81bf7a547459d30b6cb64736f6c63430008120033', + ) as any; + } +} +export var RollupAbi = abi; diff --git a/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/RollupAbi.ts b/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/RollupAbi.ts new file mode 100644 index 000000000000..2c1bc7ba3630 --- /dev/null +++ b/yarn-project/l1-contracts/src/aztec-ethereumjs-contracts/RollupAbi.ts @@ -0,0 +1,86 @@ +import { ContractAbi } from '@aztec/ethereum.js/contract'; +export default new ContractAbi([ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [], + name: 'InvalidProof', + type: 'error', + }, + { + inputs: [ + { + internalType: 'bytes32', + name: 'expected', + type: 'bytes32', + }, + { + internalType: 'bytes32', + name: 'actual', + type: 'bytes32', + }, + ], + name: 'InvalidStateHash', + type: 'error', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'rollupBlockNumber', + type: 'uint256', + }, + ], + name: 'RollupBlockProcessed', + type: 'event', + }, + { + inputs: [ + { + internalType: 'bytes', + name: '_proof', + type: 'bytes', + }, + { + internalType: 'bytes', + name: '_inputs', + type: 'bytes', + }, + ], + name: 'processRollup', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'rollupStateHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'verifier', + outputs: [ + { + internalType: 'contract MockVerifier', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, +]); diff --git a/yarn-project/l1-contracts/src/index.ts b/yarn-project/l1-contracts/src/index.ts new file mode 100644 index 000000000000..517b33aeefe1 --- /dev/null +++ b/yarn-project/l1-contracts/src/index.ts @@ -0,0 +1,6 @@ +export interface L1Addresses { + rollupContract: string; + feeDistributor: string; +} + +export * from './aztec-ethereumjs-contracts/Rollup.js'; diff --git a/yarn-project/public-client/tsconfig.dest.json b/yarn-project/l1-contracts/tsconfig.dest.json similarity index 100% rename from yarn-project/public-client/tsconfig.dest.json rename to yarn-project/l1-contracts/tsconfig.dest.json diff --git a/yarn-project/l1-contracts/tsconfig.json b/yarn-project/l1-contracts/tsconfig.json new file mode 100644 index 000000000000..f67ddec9fd6b --- /dev/null +++ b/yarn-project/l1-contracts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "include": ["src"] +} diff --git a/yarn-project/merkle-tree/.eslintrc.cjs b/yarn-project/merkle-tree/.eslintrc.cjs new file mode 100644 index 000000000000..e659927475c0 --- /dev/null +++ b/yarn-project/merkle-tree/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/merkle-tree/Dockerfile b/yarn-project/merkle-tree/Dockerfile new file mode 100644 index 000000000000..01df7865bbe5 --- /dev/null +++ b/yarn-project/merkle-tree/Dockerfile @@ -0,0 +1,15 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY foundation foundation +COPY merkle-tree merkle-tree +WORKDIR /usr/src/yarn-project/merkle-tree +RUN yarn build && yarn formatting && yarn test + +# Prune dev dependencies. See comment in base image. +RUN yarn cache clean +RUN yarn workspaces focus --production > /dev/null + +FROM node:18-alpine +COPY --from=builder /usr/src/yarn-project/merkle-tree /usr/src/yarn-project/merkle-tree +WORKDIR /usr/src/yarn-project/merkle-tree +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/merkle-tree/README.md b/yarn-project/merkle-tree/README.md new file mode 100644 index 000000000000..a59fc047a5fb --- /dev/null +++ b/yarn-project/merkle-tree/README.md @@ -0,0 +1 @@ +# Merkle Tree diff --git a/yarn-project/merkle-tree/package.json b/yarn-project/merkle-tree/package.json new file mode 100644 index 000000000000..1e657e352ebe --- /dev/null +++ b/yarn-project/merkle-tree/package.json @@ -0,0 +1,46 @@ +{ + "name": "@aztec/merkle-tree", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/foundation": "workspace:^", + "levelup": "^5.1.1", + "memdown": "^6.1.1", + "sha256": "^0.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@jest/globals": "^29.4.3", + "@rushstack/eslint-patch": "^1.1.4", + "@types/jest": "^29.4.0", + "@types/levelup": "^5.1.2", + "@types/memdown": "^3.0.1", + "@types/node": "^18.15.3", + "@types/sha256": "^0.2.0", + "jest": "^28.1.3", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + } +} diff --git a/yarn-project/merkle-tree/src/hasher.ts b/yarn-project/merkle-tree/src/hasher.ts new file mode 100644 index 000000000000..b85218e2fbbf --- /dev/null +++ b/yarn-project/merkle-tree/src/hasher.ts @@ -0,0 +1,8 @@ +/** + * Defines hasher interface used by Merkle trees. + */ +export interface Hasher { + compress(lhs: Uint8Array, rhs: Uint8Array): Buffer; + hashToField(data: Uint8Array): Buffer; + hashToTree(leaves: Buffer[]): Promise; +} diff --git a/yarn-project/merkle-tree/src/index.ts b/yarn-project/merkle-tree/src/index.ts new file mode 100644 index 000000000000..7d6590c633d4 --- /dev/null +++ b/yarn-project/merkle-tree/src/index.ts @@ -0,0 +1,6 @@ +export * from './sibling_path/sibling_path.js'; +export * from './hasher.js'; +export * from './standard_tree/standard_tree.js'; +export * from './pedersen.js'; +export * from './merkle_tree.js'; +export * from './indexed_tree/indexed_tree.js'; diff --git a/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.test.ts b/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.test.ts new file mode 100644 index 000000000000..dc09089aece4 --- /dev/null +++ b/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.test.ts @@ -0,0 +1,149 @@ +import { default as levelup } from 'levelup'; +import { Hasher, Pedersen, SiblingPath } from '../index.js'; +import { IndexedTree } from './indexed_tree.js'; +import { merkleTreeTestSuite, createMemDown } from '../test/test_suite.js'; +import { toBufferBE } from '@aztec/foundation'; + +const createDb = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string, depth: number) => { + return await IndexedTree.new(levelUp, hasher, name, depth); +}; + +const createFromName = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string) => { + return await IndexedTree.fromName(levelUp, hasher, name); +}; + +const createIndexedTreeLeaf = (value: number, nextIndex: number, nextValue: number) => { + return Buffer.concat([ + toBufferBE(BigInt(value), 32), + toBufferBE(BigInt(nextIndex), 32), + toBufferBE(BigInt(nextValue), 32), + ]); +}; + +merkleTreeTestSuite('IndexedMerkleTree', createDb, createFromName); + +describe('IndexedMerkleTreeSpecific', () => { + const pedersen = new Pedersen(); + + it('produces the correct roots and sibling paths', async () => { + // Create a depth-3 indexed merkle tree + const db = levelup(createMemDown()); + const tree = await createDb(db, pedersen, 'test', 3); + + /** + * Initial state: + * + * index 0 1 2 3 4 5 6 7 + * --------------------------------------------------------------------- + * val 0 0 0 0 0 0 0 0 + * nextIdx 0 0 0 0 0 0 0 0 + * nextVal 0 0 0 0 0 0 0 0. + */ + + const zeroTreeLeafHash = pedersen.hashToField(createIndexedTreeLeaf(0, 0, 0)); + const level1ZeroHash = pedersen.compress(zeroTreeLeafHash, zeroTreeLeafHash); + const level2ZeroHash = pedersen.compress(level1ZeroHash, level1ZeroHash); + let root = pedersen.compress(level2ZeroHash, level2ZeroHash); + + expect(tree.getRoot()).toEqual(root); + expect(tree.getNumLeaves()).toEqual(1n); + expect(await tree.getSiblingPath(0n)).toEqual(new SiblingPath([zeroTreeLeafHash, level1ZeroHash, level2ZeroHash])); + + /** + * Add new value 30: + * + * index 0 1 2 3 4 5 6 7 + * --------------------------------------------------------------------- + * val 0 30 0 0 0 0 0 0 + * nextIdx 1 0 0 0 0 0 0 0 + * nextVal 30 0 0 0 0 0 0 0. + */ + let index0Hash = pedersen.hashToField(createIndexedTreeLeaf(0, 1, 30)); + let index1Hash = pedersen.hashToField(createIndexedTreeLeaf(30, 0, 0)); + let e10 = pedersen.compress(index0Hash, index1Hash); + let e20 = pedersen.compress(e10, level1ZeroHash); + root = pedersen.compress(e20, level2ZeroHash); + + await tree.appendLeaves([toBufferBE(30n, 32)]); + + expect(tree.getRoot()).toEqual(root); + expect(tree.getNumLeaves()).toEqual(2n); + expect(await tree.getSiblingPath(1n)).toEqual(new SiblingPath([index0Hash, level1ZeroHash, level2ZeroHash])); + + /** + * Add new value 10: + * + * index 0 1 2 3 4 5 6 7 + * --------------------------------------------------------------------- + * val 0 30 10 0 0 0 0 0 + * nextIdx 2 0 1 0 0 0 0 0 + * nextVal 10 0 30 0 0 0 0 0. + */ + index0Hash = pedersen.hashToField(createIndexedTreeLeaf(0, 2, 10)); + let index2Hash = pedersen.hashToField(createIndexedTreeLeaf(10, 1, 30)); + e10 = pedersen.compress(index0Hash, index1Hash); + let e11 = pedersen.compress(index2Hash, zeroTreeLeafHash); + e20 = pedersen.compress(e10, e11); + root = pedersen.compress(e20, level2ZeroHash); + + await tree.appendLeaves([toBufferBE(10n, 32)]); + + expect(tree.getRoot()).toEqual(root); + expect(tree.getNumLeaves()).toEqual(3n); + expect(await tree.getSiblingPath(2n)).toEqual(new SiblingPath([zeroTreeLeafHash, e10, level2ZeroHash])); + + /** + * Add new value 20: + * + * index 0 1 2 3 4 5 6 7 + * --------------------------------------------------------------------- + * val 0 30 10 20 0 0 0 0 + * nextIdx 2 0 3 1 0 0 0 0 + * nextVal 10 0 20 30 0 0 0 0. + */ + e10 = pedersen.compress(index0Hash, index1Hash); + index2Hash = pedersen.hashToField(createIndexedTreeLeaf(10, 3, 20)); + const index3Hash = pedersen.hashToField(createIndexedTreeLeaf(20, 1, 30)); + e11 = pedersen.compress(index2Hash, index3Hash); + e20 = pedersen.compress(e10, e11); + root = pedersen.compress(e20, level2ZeroHash); + + await tree.appendLeaves([toBufferBE(20n, 32)]); + + expect(tree.getRoot()).toEqual(root); + expect(tree.getNumLeaves()).toEqual(4n); + expect(await tree.getSiblingPath(3n)).toEqual(new SiblingPath([index2Hash, e10, level2ZeroHash])); + + /** + * Add new value 50: + * + * index 0 1 2 3 4 5 6 7 + * --------------------------------------------------------------------- + * val 0 30 10 20 50 0 0 0 + * nextIdx 2 4 3 1 0 0 0 0 + * nextVal 10 50 20 30 0 0 0 0. + */ + index1Hash = pedersen.hashToField(createIndexedTreeLeaf(30, 4, 50)); + const index4Hash = pedersen.hashToField(createIndexedTreeLeaf(50, 0, 0)); + e10 = pedersen.compress(index0Hash, index1Hash); + e20 = pedersen.compress(e10, e11); + const e12 = pedersen.compress(index4Hash, zeroTreeLeafHash); + const e21 = pedersen.compress(e12, level1ZeroHash); + root = pedersen.compress(e20, e21); + + await tree.appendLeaves([toBufferBE(50n, 32)]); + + expect(tree.getRoot()).toEqual(root); + expect(tree.getNumLeaves()).toEqual(5n); + + // check all hash paths + expect(await tree.getSiblingPath(0n)).toEqual(new SiblingPath([index1Hash, e11, e21])); + expect(await tree.getSiblingPath(1n)).toEqual(new SiblingPath([index0Hash, e11, e21])); + expect(await tree.getSiblingPath(2n)).toEqual(new SiblingPath([index3Hash, e10, e21])); + expect(await tree.getSiblingPath(3n)).toEqual(new SiblingPath([index2Hash, e10, e21])); + expect(await tree.getSiblingPath(4n)).toEqual(new SiblingPath([zeroTreeLeafHash, level1ZeroHash, e20])); + expect(await tree.getSiblingPath(5n)).toEqual(new SiblingPath([index4Hash, level1ZeroHash, e20])); + expect(await tree.getSiblingPath(6n)).toEqual(new SiblingPath([zeroTreeLeafHash, e12, e20])); + expect(await tree.getSiblingPath(7n)).toEqual(new SiblingPath([zeroTreeLeafHash, e12, e20])); + }); +}); diff --git a/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.ts b/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.ts new file mode 100644 index 000000000000..07cd0350aab1 --- /dev/null +++ b/yarn-project/merkle-tree/src/indexed_tree/indexed_tree.ts @@ -0,0 +1,311 @@ +import { LevelUp } from 'levelup'; +import { toBigIntBE, toBufferBE } from '@aztec/foundation'; +import { MerkleTree } from '../merkle_tree.js'; +import { SiblingPath } from '../sibling_path/sibling_path.js'; +import { StandardMerkleTree } from '../standard_tree/standard_tree.js'; +import { Hasher } from '../hasher.js'; + +const indexToKeyLeaf = (name: string, index: bigint) => { + return `${name}:leaf:${index}`; +}; + +/** + * A leaf of a tree. + */ +interface LeafData { + /** + * A value of the leaf. + */ + value: bigint; + /** + * An index of the next leaf. + */ + nextIndex: bigint; + /** + * A value of the next leaf. + */ + nextValue: bigint; +} + +const encodeTreeValue = (leafData: LeafData) => { + const valueAsBuffer = toBufferBE(leafData.value, 32); + const indexAsBuffer = toBufferBE(leafData.nextIndex, 32); + const nextValueAsBuffer = toBufferBE(leafData.nextValue, 32); + return Buffer.concat([valueAsBuffer, indexAsBuffer, nextValueAsBuffer]); +}; + +const decodeTreeValue = (buf: Buffer) => { + const value = toBigIntBE(buf.subarray(0, 32)); + const nextIndex = toBigIntBE(buf.subarray(32, 64)); + const nextValue = toBigIntBE(buf.subarray(64, 96)); + return { + value, + nextIndex, + nextValue, + } as LeafData; +}; + +const initialLeaf: LeafData = { + value: 0n, + nextIndex: 0n, + nextValue: 0n, +}; + +/** + * A Merkle tree that supports efficient lookup of leaves by value. + */ +export class IndexedTree implements MerkleTree { + private leaves: LeafData[] = []; + private cachedLeaves: { [key: number]: LeafData } = {}; + constructor(private underlying: StandardMerkleTree, private hasher: Hasher, private db: LevelUp) {} + + /** + * Creates an IndexedTree object. + * @param db - A database used to store the Merkle tree data. + * @param hasher - A hasher used to compute hash paths. + * @param name - A name of the tree. + * @param depth - A depth of the tree. + * @returns A promise with the new Merkle tree. + */ + public static async new(db: LevelUp, hasher: Hasher, name: string, depth: number): Promise { + const underlying = await StandardMerkleTree.new( + db, + hasher, + name, + depth, + hasher.hashToField(encodeTreeValue(initialLeaf)), + ); + const tree = new IndexedTree(underlying, hasher, db); + await tree.init(); + return tree; + } + + /** + * Creates a new tree and sets its root, depth and size based on the meta data which are associated with the name. + * @param db - A database used to store the Merkle tree data. + * @param hasher - A hasher used to compute hash paths. + * @param name - Name of the tree. + * @returns The newly created tree. + */ + static async fromName(db: LevelUp, hasher: Hasher, name: string): Promise { + const underlying = await StandardMerkleTree.fromName( + db, + hasher, + name, + hasher.hashToField(encodeTreeValue(initialLeaf)), + ); + const tree = new IndexedTree(underlying, hasher, db); + await tree.initFromDb(); + return tree; + } + + /** + * Returns the root of the tree. + * @returns The root of the tree. + */ + public getRoot(): Buffer { + return this.underlying.getRoot(); + } + + /** + * Returns the number of leaves in the tree. + * @returns The number of leaves in the tree. + */ + public getNumLeaves(): bigint { + return this.underlying.getNumLeaves(); + } + + /** + * Appends the given leaves to the tree. + * @param leaves - The leaves to append. + * @returns Empty promise. + */ + public async appendLeaves(leaves: Buffer[]): Promise { + for (const leaf of leaves) { + await this.appendLeaf(leaf); + } + } + + /** + * Commits the changes to the database. + * @returns Empty promise. + */ + public async commit(): Promise { + await this.underlying.commit(); + await this.commitLeaves(); + } + + /** + * Rolls back the not-yet-committed changes. + * @returns Empty promise. + */ + public async rollback(): Promise { + await this.underlying.rollback(); + this.rollbackLeaves(); + } + + /** + * Returns a sibling path for the element at the given index. + * @param index - The index of the element. + * @returns A sibling path for the element at the given index. + * Note: The sibling path is an array of sibling hashes, with the lowest hash (leaf hash) first, and the highest hash last. + */ + public async getSiblingPath(index: bigint): Promise { + return await this.underlying.getSiblingPath(index); + } + + /** + * Appends the given leaf to the tree. + * @param leaf - The leaf to append. + * @returns Empty promise. + */ + private async appendLeaf(leaf: Buffer): Promise { + const newValue = toBigIntBE(leaf); + const indexOfPrevious = this.findIndexOfPreviousValue(newValue); + const previousLeafCopy = this.getLatestLeafDataCopy(indexOfPrevious.index); + if (previousLeafCopy === undefined) { + throw new Error(`Previous leaf not found!`); + } + const newLeaf = { + value: newValue, + nextIndex: previousLeafCopy.nextIndex, + nextValue: previousLeafCopy.nextValue, + } as LeafData; + if (indexOfPrevious.alreadyPresent) { + return; + } + // insert a new leaf at the highest index and update the values of our previous leaf copy + const currentSize = this.underlying.getNumLeaves(); + previousLeafCopy.nextIndex = BigInt(currentSize); + previousLeafCopy.nextValue = newLeaf.value; + this.cachedLeaves[Number(currentSize)] = newLeaf; + this.cachedLeaves[Number(indexOfPrevious.index)] = previousLeafCopy; + const previousTreeValue = encodeTreeValue(previousLeafCopy); + const newTreeValue = encodeTreeValue(newLeaf); + await this.underlying.updateLeaf(this.hasher.hashToField(previousTreeValue), BigInt(indexOfPrevious.index)); + await this.underlying.appendLeaves([this.hasher.hashToField(newTreeValue)]); + } + + /** + * Finds the index of the largest leaf whose value is less than or equal to the provided value. + * @param newValue - The new value to be inserted into the tree. + * @returns Tuple containing the leaf index and a flag to say if the value is a duplicate. + */ + private findIndexOfPreviousValue(newValue: bigint) { + const numLeaves = this.underlying.getNumLeaves(); + const diff: bigint[] = []; + for (let i = 0; i < numLeaves; i++) { + const storedLeaf = this.getLatestLeafDataCopy(i)!; + if (storedLeaf.value > newValue) { + diff.push(newValue); + } else if (storedLeaf.value === newValue) { + return { index: i, alreadyPresent: true }; + } else { + diff.push(newValue - storedLeaf.value); + } + } + const minIndex = this.findMinIndex(diff); + return { index: minIndex, alreadyPresent: false }; + } + + /** + * Finds the index of the minimum value in an array. + * @param values - The collection of values to be searched. + * @returns The index of the minimum value in the array. + */ + private findMinIndex(values: bigint[]) { + if (!values.length) { + return 0; + } + let minIndex = 0; + for (let i = 1; i < values.length; i++) { + if (values[minIndex] > values[i]) { + minIndex = i; + } + } + return minIndex; + } + + /** + * Saves the initial leaf to this object and saves it to a database. + */ + private async init() { + this.leaves.push(initialLeaf); + await this.underlying.appendLeaves([this.hasher.hashToField(encodeTreeValue(initialLeaf))]); + await this.commit(); + } + + /** + * Loads Merkle tree data from a database and assigns them to this object. + * @param startingIndex - An index locating a first element of the tree. + */ + private async initFromDb(startingIndex = 0n): Promise { + const values: LeafData[] = []; + const promise = new Promise((resolve, reject) => { + this.db + .createReadStream({ + gte: indexToKeyLeaf(this.underlying.getName(), startingIndex), + lte: indexToKeyLeaf(this.underlying.getName(), 2n ** BigInt(this.underlying.getDepth())), + }) + .on('data', function (data) { + const index = Number(data.key); + values[index] = decodeTreeValue(data.value); + }) + .on('close', function () {}) + .on('end', function () { + resolve(); + }) + .on('error', function () { + console.log('stream error'); + reject(); + }); + }); + await promise; + this.leaves = values; + } + + /** + * Commits all the leaves to the database and removes them from a cache. + */ + private async commitLeaves(): Promise { + const batch = this.db.batch(); + const keys = Object.getOwnPropertyNames(this.cachedLeaves); + for (const key of keys) { + const index = Number(key); + batch.put(key, this.cachedLeaves[index]); + this.leaves[index] = this.cachedLeaves[index]; + } + await batch.write(); + this.clearCache(); + } + + /** + * Wipes all the leaves in a cache. + */ + private rollbackLeaves() { + this.clearCache(); + } + + /** + * Clears the cache. + */ + private clearCache() { + this.cachedLeaves = {}; + } + + /** + * Gets the latest LeafData copy. + * @param index - Index of the leaf of which to obtain the LeafData copy. + * @returns A copy of the leaf data at the given index or undefined if the leaf was not found. + */ + private getLatestLeafDataCopy(index: number): LeafData | undefined { + const leaf = this.cachedLeaves[index] ?? this.leaves[index]; + return leaf + ? ({ + value: leaf.value, + nextIndex: leaf.nextIndex, + nextValue: leaf.nextValue, + } as LeafData) + : undefined; + } +} diff --git a/yarn-project/merkle-tree/src/merkle_tree.ts b/yarn-project/merkle-tree/src/merkle_tree.ts new file mode 100644 index 000000000000..e300f28d8390 --- /dev/null +++ b/yarn-project/merkle-tree/src/merkle_tree.ts @@ -0,0 +1,66 @@ +import { SiblingPath } from './sibling_path/sibling_path.js'; + +/** + * Defines the possible Merkle tree IDs. + */ +export enum MerkleTreeId { + CONTRACT_TREE = 0, + CONTRACT_TREE_ROOTS_TREE = 1, + NULLIFIER_TREE = 2, +} + +/** + * Defines the depths of the various merkle trees. + */ +export enum MerkleTreeDepths { + CONTRACT_TREE = 32, + CONTRACT_TREE_ROOTS_TREE = 8, + NULLIFIER_TREE = 32, +} + +/** + * Defines tree information. + */ +export interface TreeInfo { + /** + * The tree ID. + */ + treeId: MerkleTreeId; + /** + * The tree root. + */ + root: Buffer; + /** + * The number of leaves in the tree. + */ + size: bigint; +} + +/** + * Defines the interface for a source of sibling paths. + */ +export interface SiblingPathSource { + getSiblingPath(index: bigint): Promise; +} + +/** + * Defines the interface for a Merkle tree. + */ +export interface MerkleTree extends SiblingPathSource { + getRoot(): Buffer; + getNumLeaves(): bigint; + appendLeaves(leaves: Buffer[]): Promise; + commit(): Promise; + rollback(): Promise; +} + +/** + * Defines the interface for a database that stores Merkle trees. + */ +export interface MerkleTreeDb { + getTreeInfo(treeId: MerkleTreeId): Promise; + appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise; + getSiblingPath(treeId: MerkleTreeId, index: bigint): Promise; + commit(): Promise; + rollback(): Promise; +} diff --git a/yarn-project/merkle-tree/src/pedersen.ts b/yarn-project/merkle-tree/src/pedersen.ts new file mode 100644 index 000000000000..d6dce6ea5b76 --- /dev/null +++ b/yarn-project/merkle-tree/src/pedersen.ts @@ -0,0 +1,15 @@ +/* eslint-disable */ +import { Hasher } from './hasher.js'; +import { default as sha256 } from 'sha256'; + +export class Pedersen implements Hasher { + public compress(lhs: Uint8Array, rhs: Uint8Array): Buffer { + return Buffer.from(sha256(Buffer.concat([lhs, rhs])), 'hex'); + } + public hashToField(data: Uint8Array): Buffer { + return Buffer.from(sha256(Buffer.from(data)), 'hex'); + } + public hashToTree(leaves: Buffer[]): Promise { + return Promise.resolve([Buffer.alloc(32)]); + } +} diff --git a/yarn-project/merkle-tree/src/sibling_path/sibling_path.ts b/yarn-project/merkle-tree/src/sibling_path/sibling_path.ts new file mode 100644 index 000000000000..6cb15f365236 --- /dev/null +++ b/yarn-project/merkle-tree/src/sibling_path/sibling_path.ts @@ -0,0 +1,86 @@ +import { Pedersen } from '../pedersen.js'; +import { deserializeArrayFromVector, serializeBufferArrayToVector } from '@aztec/foundation'; + +/** + * Contains functionality to compute and serialize/deserialize a sibling path. + */ +export class SiblingPath { + /** + * Returns sibling path hashed up from the a element. + * @param size - The number of elements in a given path. + * @param zeroElement - Value of the zero element. + * @param pedersen - Implementation of a hasher interface using the Pedersen hash. + * @returns A sibling path hashed up from a zero element. + */ + public static ZERO(size: number, zeroElement: Buffer, pedersen: Pedersen): SiblingPath { + const bufs: Buffer[] = []; + let current = zeroElement; + for (let i = 0; i < size; ++i) { + bufs.push(current); + current = pedersen.compress(current, current); + } + return new SiblingPath(bufs); + } + + /** + * Constructor. + * @param data - The sibling path data. + */ + constructor( + /** + * The sibling path data. + */ + public data: Buffer[] = [], + ) {} + + /** + * Serializes this SiblingPath object to a buffer. + * @returns The buffer representation of this object. + */ + public toBuffer(): Buffer { + return serializeBufferArrayToVector(this.data); + } + + /** + * Deserializes a SiblingPath from a buffer. + * @param buf - A buffer containing the buffer representation of SiblingPath. + * @param offset - An offset to start deserializing from. + * @returns A SiblingPath object. + */ + static fromBuffer(buf: Buffer, offset = 0): SiblingPath { + const { elem } = SiblingPath.deserialize(buf, offset); + return elem; + } + + /** + * Deserializes a SiblingPath object from a slice of a part of a buffer and returns the amount of bytes advanced. + * @param buf - A buffer representation of the sibling path. + * @param offset - An offset to start deserializing from. + * @returns The deserialized sibling path and the number of bytes advanced. + */ + static deserialize(buf: Buffer, offset = 0) { + const deserializePath = (buf: Buffer, offset: number) => ({ + elem: buf.slice(offset, offset + 32), + adv: 32, + }); + const { elem, adv } = deserializeArrayFromVector(deserializePath, buf, offset); + return { elem: new SiblingPath(elem), adv }; + } + + /** + * Serializes this SiblingPath object to a hex string representation. + * @returns A hex string representation of the sibling path. + */ + public toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes a SiblingPath object from a hex string representation. + * @param repr - A hex string representation of the sibling path. + * @returns A SiblingPath object. + */ + public static fromString(repr: string): SiblingPath { + return SiblingPath.fromBuffer(Buffer.from(repr, 'hex')); + } +} diff --git a/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts new file mode 100644 index 000000000000..d7119a60227a --- /dev/null +++ b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts @@ -0,0 +1,81 @@ +import { default as levelup } from 'levelup'; +import { Hasher } from '../hasher.js'; +import { SiblingPath } from '../index.js'; +import { Pedersen } from '../pedersen.js'; +import { StandardMerkleTree } from './standard_tree.js'; +import { merkleTreeTestSuite, createMemDown } from '../test/test_suite.js'; + +const createDb = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string, depth: number) => { + return await StandardMerkleTree.new(levelUp, hasher, name, depth); +}; + +const createFromName = async (levelUp: levelup.LevelUp, hasher: Hasher, name: string) => { + return await StandardMerkleTree.fromName(levelUp, hasher, name); +}; + +merkleTreeTestSuite('StandardMerkleTree', createDb, createFromName); + +describe('StandardMerkleTreeSpecific', () => { + const pedersen = new Pedersen(); + const values: Buffer[] = []; + + beforeAll(() => { + for (let i = 0; i < 4; ++i) { + const v = Buffer.alloc(32, i + 1); + v.writeUInt32BE(i, 28); + values[i] = v; + } + }); + it('should have correct root and sibling paths', async () => { + const db = levelup(createMemDown()); + const tree = await createDb(db, pedersen, 'test', 2); + + const zeroTreeLeafHash = StandardMerkleTree.ZERO_ELEMENT; + const level1ZeroHash = pedersen.compress(zeroTreeLeafHash, zeroTreeLeafHash); + expect(tree.getNumLeaves()).toEqual(0n); + expect(tree.getRoot()).toEqual(pedersen.compress(level1ZeroHash, level1ZeroHash)); + expect(await tree.getSiblingPath(0n)).toEqual(new SiblingPath([zeroTreeLeafHash, level1ZeroHash])); + + await tree.appendLeaves([values[0]]); + expect(tree.getNumLeaves()).toEqual(1n); + expect(tree.getRoot()).toEqual(pedersen.compress(pedersen.compress(values[0], zeroTreeLeafHash), level1ZeroHash)); + expect(await tree.getSiblingPath(0n)).toEqual(new SiblingPath([zeroTreeLeafHash, level1ZeroHash])); + + await tree.appendLeaves([values[1]]); + expect(tree.getNumLeaves()).toEqual(2n); + expect(tree.getRoot()).toEqual(pedersen.compress(pedersen.compress(values[0], values[1]), level1ZeroHash)); + expect(await tree.getSiblingPath(1n)).toEqual(new SiblingPath([values[0], level1ZeroHash])); + + await tree.appendLeaves([values[2]]); + expect(tree.getNumLeaves()).toEqual(3n); + expect(tree.getRoot()).toEqual( + pedersen.compress(pedersen.compress(values[0], values[1]), pedersen.compress(values[2], zeroTreeLeafHash)), + ); + expect(await tree.getSiblingPath(2n)).toEqual( + new SiblingPath([zeroTreeLeafHash, pedersen.compress(values[0], values[1])]), + ); + + await tree.appendLeaves([values[3]]); + expect(tree.getNumLeaves()).toEqual(4n); + expect(tree.getRoot()).toEqual( + pedersen.compress(pedersen.compress(values[0], values[1]), pedersen.compress(values[2], values[3])), + ); + expect(await tree.getSiblingPath(3n)).toEqual( + new SiblingPath([values[2], pedersen.compress(values[0], values[1])]), + ); + // Lifted from memory_tree.test.cpp to ensure consistency. + //expect(root.toString('hex')).toEqual('0bf2e78afd70f72b0e6eafb03c41faef167a82441b05e517cdf35d813302061f'); + expect(await tree.getSiblingPath(0n)).toEqual( + new SiblingPath([values[1], pedersen.compress(values[2], values[3])]), + ); + expect(await tree.getSiblingPath(1n)).toEqual( + new SiblingPath([values[0], pedersen.compress(values[2], values[3])]), + ); + expect(await tree.getSiblingPath(2n)).toEqual( + new SiblingPath([values[3], pedersen.compress(values[0], values[1])]), + ); + expect(await tree.getSiblingPath(3n)).toEqual( + new SiblingPath([values[2], pedersen.compress(values[0], values[1])]), + ); + }); +}); diff --git a/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts b/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts new file mode 100644 index 000000000000..7ac8418b8572 --- /dev/null +++ b/yarn-project/merkle-tree/src/standard_tree/standard_tree.ts @@ -0,0 +1,288 @@ +import { LevelUp, LevelUpChain } from 'levelup'; +import { SiblingPath } from '../sibling_path/sibling_path.js'; +import { Hasher } from '../hasher.js'; +import { MerkleTree } from '../merkle_tree.js'; +import { toBufferLE, toBigIntLE } from '@aztec/foundation'; + +const MAX_DEPTH = 32; + +const indexToKeyHash = (name: string, level: number, index: bigint) => `${name}:${level}:${index}`; +const encodeMeta = (root: Buffer, depth: number, size: bigint) => { + const data = Buffer.alloc(36); + root.copy(data); + data.writeUInt32LE(depth, 32); + return Buffer.concat([data, toBufferLE(size, 32)]); +}; +const decodeMeta = (meta: Buffer) => { + const root = meta.subarray(0, 32); + const depth = meta.readUInt32LE(32); + const size = toBigIntLE(meta.subarray(36)); + return { + root, + depth, + size, + }; +}; + +/** + * A Merkle tree implementation that uses a LevelDB database to store the tree. + */ +export class StandardMerkleTree implements MerkleTree { + /** + * The value of an 'empty' leaf. + */ + public static ZERO_ELEMENT = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'); + private root!: Buffer; + private zeroHashes: Buffer[] = []; + private cache: { [key: string]: Buffer } = {}; + private cachedSize?: bigint; + + constructor( + private db: LevelUp, + private hasher: Hasher, + private name: string, + private depth: number, + private size: bigint = 0n, + root?: Buffer, + initialLeafValue = StandardMerkleTree.ZERO_ELEMENT, + ) { + if (!(depth >= 1 && depth <= MAX_DEPTH)) { + throw Error('Bad depth'); + } + + // Compute the zero values at each layer. + let current = initialLeafValue; + for (let i = depth - 1; i >= 0; --i) { + this.zeroHashes[i] = current; + current = hasher.compress(current, current); + } + + this.root = root ? root : current; + } + + /** + * Creates a new tree. + * @param db - A database used to store the Merkle tree data. + * @param hasher - A hasher used to compute hash paths. + * @param name - Name of the tree. + * @param depth - Depth of the tree. + * @param initialLeafValue - The initial value of the leaves. + * @returns The newly created tree. + */ + static async new( + db: LevelUp, + hasher: Hasher, + name: string, + depth: number, + initialLeafValue = StandardMerkleTree.ZERO_ELEMENT, + ) { + const tree = new StandardMerkleTree(db, hasher, name, depth, 0n, undefined, initialLeafValue); + await tree.writeMeta(); + return tree; + } + + /** + * Creates a new tree and sets its root, depth and size based on the meta data which are associated with the name. + * @param db - A database used to store the Merkle tree data. + * @param hasher - A hasher used to compute hash paths. + * @param name - Name of the tree. + * @param initialLeafValue - The initial value of the leaves before assigned. + * @returns The newly created tree. + */ + static async fromName(db: LevelUp, hasher: Hasher, name: string, initialLeafValue = StandardMerkleTree.ZERO_ELEMENT) { + const meta: Buffer = await db.get(name); + const { root, depth, size } = decodeMeta(meta); + return new StandardMerkleTree(db, hasher, name, depth, size, root, initialLeafValue); + } + + /** + * Sets the root, depth and size of the tree based on the meta data which are associated with the tree name. + */ + public async syncFromDb() { + const meta: Buffer | undefined = await this.dbGet(this.name); + if (!meta) { + return; + } + const { root, depth, size } = decodeMeta(meta); + this.root = root; + this.depth = depth; + this.size = size; + this.clearCache(); + } + + /** + * Returns the root of the tree. + * @returns The root of the tree. + */ + public getRoot(): Buffer { + return this.cache[indexToKeyHash(this.name, 0, 0n)] ?? this.root; + } + + /** + * Returns the number of leaves in the tree. + * @returns The number of leaves in the tree. + */ + public getNumLeaves() { + return this.cachedSize ?? this.size; + } + + /** + * Returns the name of the tree. + * @returns The name of the tree. + */ + public getName(): string { + return this.name; + } + + /** + * Returns the depth of the tree. + * @returns The depth of the tree. + */ + public getDepth(): number { + return this.depth; + } + + /** + * Returns a sibling path for the element at the given index. + * @param index - The index of the element. + * @returns A sibling path for the element at the given index. + * Note: The sibling path is an array of sibling hashes, with the lowest hash (leaf hash) first, and the highest hash last. + */ + public async getSiblingPath(index: bigint) { + const path = new SiblingPath(); + let level = this.depth; + while (level > 0) { + const isRight = index & 0x01n; + const sibling = await this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n); + path.data.push(sibling); + level -= 1; + index >>= 1n; + } + return path; + } + + /** + * Appends the given leaves to the tree. + * @param leaves - The leaves to append. + * @returns Empty promise. + */ + public async appendLeaves(leaves: Buffer[]): Promise { + const numLeaves = this.getNumLeaves(); + for (let i = 0; i < leaves.length; i++) { + const index = numLeaves + BigInt(i); + await this.addLeafToCacheAndHashToRoot(leaves[i], index); + } + this.cachedSize = numLeaves + BigInt(leaves.length); + } + + /** + * Updates a leaf in the tree. + * @param leaf - New contents of the leaf. + * @param index - Index of the leaf to be updated. + */ + public async updateLeaf(leaf: Buffer, index: bigint) { + await this.addLeafToCacheAndHashToRoot(leaf, index); + const numLeaves = this.getNumLeaves(); + if (index >= numLeaves) { + this.cachedSize = index + 1n; + } + } + + /** + * Commits the changes to the database. + * @returns Empty promise. + */ + public async commit(): Promise { + const batch = this.db.batch(); + const keys = Object.getOwnPropertyNames(this.cache); + for (const key of keys) { + batch.put(key, this.cache[key]); + } + this.size = this.getNumLeaves(); + this.root = this.getRoot(); + await this.writeMeta(batch); + await batch.write(); + this.clearCache(); + } + + /** + * Rolls back the not-yet-committed changes. + * @returns Empty promise. + */ + public rollback(): Promise { + this.clearCache(); + return Promise.resolve(); + } + + /** + * Clears the catch. + */ + private clearCache() { + this.cache = {}; + this.cachedSize = undefined; + } + + /** + * Adds a leaf and all the hashes above it to the cache. + * @param leaf - Leaf to add to cache. + * @param index - Index of the leaf (used to derive the cache key). + */ + private async addLeafToCacheAndHashToRoot(leaf: Buffer, index: bigint) { + const key = indexToKeyHash(this.name, this.depth, index); + let current = leaf; + this.cache[key] = current; + let level = this.depth; + while (level > 0) { + const isRight = index & 0x01n; + const sibling = await this.getLatestValueAtIndex(level, isRight ? index - 1n : index + 1n); + const lhs = isRight ? sibling : current; + const rhs = isRight ? current : sibling; + current = this.hasher.compress(lhs, rhs); + level -= 1; + index >>= 1n; + const cacheKey = indexToKeyHash(this.name, level, index); + this.cache[cacheKey] = current; + } + } + + /** + * Returns the latest value at the given index. + * @param level - The level of the tree. + * @param index - The index of the element. + * @returns The latest value at the given index. + * Note: If the value is not in the cache, it will be fetched from the database. + */ + private async getLatestValueAtIndex(level: number, index: bigint): Promise { + const key = indexToKeyHash(this.name, level, index); + if (this.cache[key] !== undefined) { + return this.cache[key]; + } + const committed = await this.dbGet(key); + if (committed !== undefined) { + return committed; + } + return this.zeroHashes[level - 1]; + } + + /** + * Gets a value from db by key. + * @param key - The key to by which to get the value. + * @returns A value from the db based on the key. + */ + private async dbGet(key: string): Promise { + return await this.db.get(key).catch(() => {}); + } + + /** + * Writes meta data to the provided batch. + * @param batch - The batch to which to write the meta data. + */ + private async writeMeta(batch?: LevelUpChain) { + const data = encodeMeta(this.getRoot(), this.depth, this.getNumLeaves()); + if (batch) { + batch.put(this.name, data); + } else { + await this.db.put(this.name, data); + } + } +} diff --git a/yarn-project/merkle-tree/src/test/test_suite.ts b/yarn-project/merkle-tree/src/test/test_suite.ts new file mode 100644 index 000000000000..0fce9239ee1b --- /dev/null +++ b/yarn-project/merkle-tree/src/test/test_suite.ts @@ -0,0 +1,140 @@ +import { default as levelup } from 'levelup'; +import { default as memdown } from 'memdown'; +import { Hasher, MerkleTree, Pedersen, SiblingPath } from '../index.js'; + +/* eslint-disable @typescript-eslint/ban-ts-comment */ +// @ts-ignore +export const createMemDown = () => memdown(); + +const expectSameTrees = async (tree1: MerkleTree, tree2: MerkleTree) => { + const size = tree1.getNumLeaves(); + expect(size).toBe(tree2.getNumLeaves()); + expect(tree1.getRoot().toString('hex')).toBe(tree2.getRoot().toString('hex')); + + for (let i = 0; i < size; ++i) { + const siblingPath1 = await tree1.getSiblingPath(BigInt(i)); + const siblingPath2 = await tree2.getSiblingPath(BigInt(i)); + expect(siblingPath2).toStrictEqual(siblingPath1); + } +}; + +export const merkleTreeTestSuite = ( + testName: string, + createDb: (levelup: levelup.LevelUp, hasher: Hasher, name: string, depth: number) => Promise, + createFromName: (levelup: levelup.LevelUp, hasher: Hasher, name: string) => Promise, +) => { + describe(testName, () => { + const pedersen = new Pedersen(); + const values: Buffer[] = []; + + beforeAll(() => { + for (let i = 0; i < 32; ++i) { + const v = Buffer.alloc(32, i + 1); + v.writeUInt32BE(i, 28); + values[i] = v; + } + }); + + // it('should have correct empty tree root for depth 32', async () => { + // const db = levelup(memdown()); + // const tree = await StandardMerkleTree.new(db, pedersen, 'test', 32); + // const root = tree.getRoot(); + // expect(root.toString('hex')).toEqual('18ceb5cd201e1cee669a5c3ad96d3c4e933a365b37046fc3178264bede32c68d'); + // }); + + it('should revert changes on rollback', async () => { + const levelDownEmpty = createMemDown(); + const dbEmpty = levelup(levelDownEmpty); + const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); + + const levelDown = createMemDown(); + const db = levelup(levelDown); + const tree = await createDb(db, pedersen, 'test2', 10); + await tree.appendLeaves(values.slice(0, 4)); + + const firstRoot = tree.getRoot(); + + expect(firstRoot).not.toEqual(emptyTree.getRoot()); + + await tree.rollback(); + + await expectSameTrees(tree, emptyTree); + + // append the leaves again + await tree.appendLeaves(values.slice(0, 4)); + + expect(tree.getRoot()).toEqual(firstRoot); + + expect(firstRoot).not.toEqual(emptyTree.getRoot()); + + await tree.rollback(); + + await expectSameTrees(tree, emptyTree); + }); + + it('should not revert changes after commit', async () => { + const levelDownEmpty = createMemDown(); + const dbEmpty = levelup(levelDownEmpty); + const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); + + const levelDown = createMemDown(); + const db = levelup(levelDown); + const tree = await createDb(db, pedersen, 'test2', 10); + await tree.appendLeaves(values.slice(0, 4)); + + expect(tree.getRoot()).not.toEqual(emptyTree.getRoot()); + + await tree.commit(); + await tree.rollback(); + + expect(tree.getRoot()).not.toEqual(emptyTree.getRoot()); + }); + + it('should be able to restore from previous committed data', async () => { + const levelDown = createMemDown(); + const db = levelup(levelDown); + const tree = await createDb(db, pedersen, 'test', 10); + await tree.appendLeaves(values.slice(0, 4)); + await tree.commit(); + + const db2 = levelup(levelDown); + const tree2 = await createFromName(db2, pedersen, 'test'); + + expect(tree.getRoot()).toEqual(tree2.getRoot()); + for (let i = 0; i < 4; ++i) { + expect(await tree.getSiblingPath(BigInt(i))).toEqual(await tree2.getSiblingPath(BigInt(i))); + } + }); + + it('should throw an error if previous data does not exist for the given name', async () => { + const db = levelup(createMemDown()); + await expect( + (async () => { + await createFromName(db, pedersen, 'a_whole_new_tree'); + })(), + ).rejects.toThrow(); + }); + + it('should serialize sibling path data to a buffer and be able to deserialize it back', async () => { + const db = levelup(createMemDown()); + const tree = await createDb(db, pedersen, 'test', 10); + await tree.appendLeaves(values.slice(0, 1)); + + const siblingPath = await tree.getSiblingPath(0n); + const buf = siblingPath.toBuffer(); + const recovered = SiblingPath.fromBuffer(buf); + expect(recovered).toEqual(siblingPath); + const deserialized = SiblingPath.deserialize(buf); + expect(deserialized.elem).toEqual(siblingPath); + expect(deserialized.adv).toBe(4 + 10 * 32); + + const dummyData = Buffer.alloc(23, 1); + const paddedBuf = Buffer.concat([dummyData, buf]); + const recovered2 = SiblingPath.fromBuffer(paddedBuf, 23); + expect(recovered2).toEqual(siblingPath); + const deserialized2 = SiblingPath.deserialize(buf); + expect(deserialized2.elem).toEqual(siblingPath); + expect(deserialized2.adv).toBe(4 + 10 * 32); + }); + }); +}; diff --git a/yarn-project/merkle-tree/tsconfig.dest.json b/yarn-project/merkle-tree/tsconfig.dest.json new file mode 100644 index 000000000000..270bf9b6ea32 --- /dev/null +++ b/yarn-project/merkle-tree/tsconfig.dest.json @@ -0,0 +1,5 @@ +{ + "extends": ".", + "exclude": ["**/*.test.*", "**/fixtures/*"], + "references": [{ "path": "../foundation/tsconfig.dest.json" }] +} diff --git a/yarn-project/merkle-tree/tsconfig.json b/yarn-project/merkle-tree/tsconfig.json new file mode 100644 index 000000000000..43f4a4dda448 --- /dev/null +++ b/yarn-project/merkle-tree/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "references": [{ "path": "../foundation/tsconfig.dest.json" }], + "include": ["src"] +} diff --git a/yarn-project/noir-contracts/.eslintrc.cjs b/yarn-project/noir-contracts/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/noir-contracts/.eslintrc.cjs +++ b/yarn-project/noir-contracts/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/noir-contracts/Dockerfile b/yarn-project/noir-contracts/Dockerfile index 449a4e1173b4..0de2e52bf6f2 100644 --- a/yarn-project/noir-contracts/Dockerfile +++ b/yarn-project/noir-contracts/Dockerfile @@ -1,5 +1,6 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder +COPY foundation foundation COPY noir-contracts noir-contracts WORKDIR /usr/src/yarn-project/noir-contracts RUN yarn build && yarn formatting && yarn test diff --git a/yarn-project/noir-contracts/package.json b/yarn-project/noir-contracts/package.json index 098ffe4a56b1..c64c7be55353 100644 --- a/yarn-project/noir-contracts/package.json +++ b/yarn-project/noir-contracts/package.json @@ -32,10 +32,10 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/foundation": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@noir-lang/noir-source-resolver": "^1.1.0", "@noir-lang/noir_wasm": "0.3.2-29b1f7df", diff --git a/yarn-project/p2p/.eslintrc.cjs b/yarn-project/p2p/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/p2p/.eslintrc.cjs +++ b/yarn-project/p2p/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/p2p/package.json b/yarn-project/p2p/package.json index 81476af28b0a..71d0a5ce6591 100644 --- a/yarn-project/p2p/package.json +++ b/yarn-project/p2p/package.json @@ -11,6 +11,8 @@ "scripts": { "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", "build:dev": "tsc -b tsconfig.dest.json --watch", + "start": "node ./dest", + "start:dev": "tsc-watch -p tsconfig.dest.json --onSuccess 'yarn start'", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" @@ -29,14 +31,16 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/archiver": "workspace:^", + "@aztec/foundation": "workspace:^", + "sha3": "^2.1.4", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", - "@types/node": "^18.7.23", + "@types/node": "^18.14.6", "jest": "^28.1.3", "ts-jest": "^28.0.7", "ts-node": "^10.9.1", diff --git a/yarn-project/p2p/src/client/index.ts b/yarn-project/p2p/src/client/index.ts new file mode 100644 index 000000000000..a51149dae99d --- /dev/null +++ b/yarn-project/p2p/src/client/index.ts @@ -0,0 +1,2 @@ +export * from './p2p_client.js'; +export * from './tx.js'; diff --git a/yarn-project/p2p/src/client/mocks.ts b/yarn-project/p2p/src/client/mocks.ts new file mode 100644 index 000000000000..55427a3d6bc1 --- /dev/null +++ b/yarn-project/p2p/src/client/mocks.ts @@ -0,0 +1,79 @@ +import { randomBytes } from 'crypto'; +import { + L2BlockSource, + L2Block, + ContractData, + randomContractData, + randomAppendOnlyTreeSnapshot, + L2BlockSourceSyncStatus, +} from '@aztec/archiver'; +import { AccumulatedTxData, Tx } from './tx.js'; + +export const MockTx = () => { + return new Tx(AccumulatedTxData.random()); +}; + +export class MockBlockSource implements L2BlockSource { + private l2Blocks: L2Block[]; + + constructor(private numBlocks = 100) { + this.l2Blocks = []; + for (let i = 0; i < this.numBlocks; i++) { + this.l2Blocks.push(new MockBlock(i)); + } + } + + public getLatestBlockNum() { + return Promise.resolve(this.l2Blocks.length - 1); + } + + public getL2Blocks(from: number, take: number) { + return Promise.resolve(this.l2Blocks.slice(from, from + take)); + } + + public getSyncStatus(): Promise { + return Promise.resolve({ + syncedToBlock: this.numBlocks, + latestBlock: this.numBlocks, + } as L2BlockSourceSyncStatus); + } + + public start(): Promise { + return Promise.resolve(); + } + + public stop(): Promise { + return Promise.resolve(); + } +} + +export class MockBlock extends L2Block { + constructor(private _id: number) { + const newNullifiers = [randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32)]; + const newCommitments = [randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32)]; + const newContracts: Buffer[] = [randomBytes(32)]; + const newContractsData: ContractData[] = [randomContractData()]; + + super( + _id, + randomAppendOnlyTreeSnapshot(0), + randomAppendOnlyTreeSnapshot(0), + randomAppendOnlyTreeSnapshot(0), + randomAppendOnlyTreeSnapshot(0), + randomAppendOnlyTreeSnapshot(0), + randomAppendOnlyTreeSnapshot(newCommitments.length), + randomAppendOnlyTreeSnapshot(newNullifiers.length), + randomAppendOnlyTreeSnapshot(newContracts.length), + randomAppendOnlyTreeSnapshot(1), + randomAppendOnlyTreeSnapshot(1), + newCommitments, + newNullifiers, + newContracts, + newContractsData, + ); + } + + get settlementTimestamp() { + return Date.now(); + } +} diff --git a/yarn-project/p2p/src/client/p2p_client.test.ts b/yarn-project/p2p/src/client/p2p_client.test.ts new file mode 100644 index 000000000000..23831004bbcf --- /dev/null +++ b/yarn-project/p2p/src/client/p2p_client.test.ts @@ -0,0 +1,68 @@ +import { expect, jest } from '@jest/globals'; +import { L2BlockSource } from '@aztec/archiver'; + +import { P2PCLient } from './p2p_client.js'; +import { TxPool } from '../tx_pool/index.js'; +import { MockBlockSource } from './mocks.js'; +import { MockTx } from './mocks.js'; + +/** + * Mockify helper for testing purposes. + */ +type Mockify = { + [P in keyof T]: ReturnType; +}; + +describe('In-Memory P2P Client', () => { + let txPool: Mockify; + let blockSource: L2BlockSource; + + beforeEach(() => { + txPool = { + addTxs: jest.fn(), + getTx: jest.fn().mockReturnValue(undefined), + deleteTxs: jest.fn(), + getAllTxs: jest.fn().mockReturnValue([]), + }; + + blockSource = new MockBlockSource(); + }); + + it('can start & stop', async () => { + const client = new P2PCLient(blockSource, txPool); + expect(await client.isReady()).toEqual(false); + + await client.start(); + expect(await client.isReady()).toEqual(true); + + await client.stop(); + expect(await client.isReady()).toEqual(false); + }); + + it('adds txs to pool', async () => { + const client = new P2PCLient(blockSource, txPool); + await client.start(); + const tx1 = MockTx(); + const tx2 = MockTx(); + await client.sendTx(tx1); + await client.sendTx(tx2); + + expect(txPool.addTxs).toHaveBeenCalledTimes(2); + await client.stop(); + }); + + it('rejects txs after being stopped', async () => { + const client = new P2PCLient(blockSource, txPool); + await client.start(); + const tx1 = MockTx(); + const tx2 = MockTx(); + await client.sendTx(tx1); + await client.sendTx(tx2); + + expect(txPool.addTxs).toHaveBeenCalledTimes(2); + await client.stop(); + const tx3 = MockTx(); + await expect(client.sendTx(tx3)).rejects.toThrow(); + expect(txPool.addTxs).toHaveBeenCalledTimes(2); + }); +}); diff --git a/yarn-project/p2p/src/client/p2p_client.ts b/yarn-project/p2p/src/client/p2p_client.ts new file mode 100644 index 000000000000..c847979a83fe --- /dev/null +++ b/yarn-project/p2p/src/client/p2p_client.ts @@ -0,0 +1,240 @@ +import { L2Block, L2BlockSource, L2BlockDownloader } from '@aztec/archiver'; + +import { InMemoryTxPool } from '../tx_pool/memory_tx_pool.js'; +import { TxPool } from '../tx_pool/index.js'; +import { Tx } from './tx.js'; +import { createDebugLogger } from '@aztec/foundation'; + +const TAKE_NUM = 1; + +/** + * Enum defining the possible states of the p2p client. + */ +enum P2PClientState { + IDLE, + SYNCHING, + RUNNING, + STOPPED, +} + +/** + * Interface of a P2P client. + **/ +export interface P2P { + /** + * Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers. + **/ + sendTx(tx: Tx): Promise; + + /** + * Returns all transactions in the transaction pool. + * @returns An array of Txs. + */ + getTxs(): Promise; + + /** + * Starts the p2p client. + * @returns A promise signalling the completion of the block sync. + */ + start(): Promise; + + /** + * Stops the p2p client. + * @returns A promise signalling the completion of the stop process. + */ + stop(): Promise; + + /** + * Indicates if the p2p client is ready for transaction submission. + * @returns A boolean flag indicating readiness. + */ + isReady(): Promise; +} + +/** + * The P2P client implementation. + */ +export class P2PCLient implements P2P { + /** + * L2 Block download that p2p client uses to stay in sync with latest blocks. + */ + private blockDownloader: L2BlockDownloader; + + /** + * Property that indicates whether the client is running. + */ + private stopping = false; + + /** + * The JS promise that will be running to keep the client's data in sync. Can be interrupted if the client is stopped. + */ + private runningSyncPromise!: Promise; + + /** + * Store the ID of the latest block the client has synced to. + */ + private syncedBlockNum = -1; + + private currentState = P2PClientState.IDLE; + private syncPromise = Promise.resolve(); + private latestBlockNumberAtStart = -1; + private syncResolve?: () => void = undefined; + + /** + * In-memory P2P client constructor. + * @param l2BlockSource - P2P client's source for fetching existing block data. + * @param txPool - The client's instance of a transaction pool. Defaults to in-memory implementation. + * @param log - A logger. + */ + constructor( + private l2BlockSource: L2BlockSource, + private txPool: TxPool = new InMemoryTxPool(), + private log = createDebugLogger('aztec:p2p'), + ) { + this.blockDownloader = new L2BlockDownloader(l2BlockSource, TAKE_NUM); + } + + /** + * Starts the P2P client. + * @returns An empty promise signalling the synching process. + */ + public async start() { + if (this.currentState === P2PClientState.STOPPED) { + throw new Error('P2P client already stopped'); + } + if (this.currentState !== P2PClientState.IDLE) { + return this.syncPromise; + } + + // get the current latest block number + this.latestBlockNumberAtStart = await this.l2BlockSource.getLatestBlockNum(); + + if (this.syncedBlockNum >= this.latestBlockNumberAtStart) { + // if no blocks to be retrieved, go straight to running + this.setCurrentState(P2PClientState.RUNNING); + this.syncPromise = Promise.resolve(); + this.log(`already synched to latest block ${this.latestBlockNumberAtStart}`); + } else { + this.setCurrentState(P2PClientState.SYNCHING); + this.syncPromise = new Promise(resolve => { + this.syncResolve = resolve; + }); + this.log(`starting sync from ${this.syncedBlockNum}, latest block ${this.latestBlockNumberAtStart}`); + } + + // start looking for further blocks + const blockProcess = async () => { + while (!this.stopping) { + const blocks = await this.blockDownloader.getL2Blocks(); + await this.processBlocks(blocks); + } + }; + this.runningSyncPromise = blockProcess(); + const blockToDownloadFrom = this.syncedBlockNum + 1; + this.blockDownloader.start(blockToDownloadFrom); + this.log(`started block downloader from block ${blockToDownloadFrom}`); + return this.syncPromise; + } + + /** + * Allows consumers to stop the instance of the P2P client. + * 'ready' will now return 'false' and the running promise that keeps the client synced is interrupted. + */ + public async stop() { + this.log('stopping p2p client...'); + this.stopping = true; + await this.blockDownloader.stop(); + await this.runningSyncPromise; + this.setCurrentState(P2PClientState.STOPPED); + } + + /** + * Returns all transactions in the transaction pool. + * @returns An array of Txs. + */ + public getTxs(): Promise { + return Promise.resolve(this.txPool.getAllTxs()); + } + + /** + * Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers. + * @param tx - The tx to verify. + * @returns Empty promise. + **/ + public async sendTx(tx: Tx): Promise { + const ready = await this.isReady(); + if (!ready) { + throw new Error('P2P client not ready'); + } + this.txPool.addTxs([tx]); + } + + /** + * Public function to check if the p2p client is fully synced and ready to receive txs. + * @returns True if the P2P client is ready to receive txs. + */ + public isReady() { + return Promise.resolve(this.currentState === P2PClientState.RUNNING); + } + + /** + * Public function to check the latest block number that the P2P client is synced to. + * @returns Block number of latest L2 Block we've synced with. + */ + public getSyncedBlockNum() { + return this.syncedBlockNum; + } + + /** + * Method to check the status the p2p client. + * @returns Information about p2p client status: state & syncedToBlockNum. + */ + public getStatus() { + return { + state: this.currentState, + syncedToBlockNum: this.syncedBlockNum, + }; + } + + /** + * Internal method that uses the provided blocks to check against the client's tx pool. + * @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with. + * @returns Empty promise. + */ + private reconcileTxPool(blocks: L2Block[]): Promise { + for (let i = 0; i < blocks.length; i++) { + const { newContracts } = blocks[i]; + this.txPool.deleteTxs(newContracts?.map((data: Buffer) => Tx.createTxId(data)) || []); + } + return Promise.resolve(); + } + + /** + * Method for processing new blocks. + * @param blocks - A list of existing blocks with txs that the P2P client needs to ensure the tx pool is reconciled with. + * @returns Empty promise. + */ + private async processBlocks(blocks: L2Block[]): Promise { + if (!blocks.length) { + return Promise.resolve(); + } + await this.reconcileTxPool(blocks); + this.syncedBlockNum = blocks[blocks.length - 1].number; + this.log(`synched to block ${this.syncedBlockNum}`); + if (this.currentState === P2PClientState.SYNCHING && this.syncedBlockNum >= this.latestBlockNumberAtStart) { + this.setCurrentState(P2PClientState.RUNNING); + if (this.syncResolve !== undefined) { + this.syncResolve(); + } + } + } + + /** + * Method to set the value of the current state. + * @param newState - New state value. + */ + private setCurrentState(newState: P2PClientState) { + this.currentState = newState; + this.log(`moved to state ${P2PClientState[this.currentState]}`); + } +} diff --git a/yarn-project/p2p/src/client/tx.ts b/yarn-project/p2p/src/client/tx.ts new file mode 100644 index 000000000000..b27d15b109aa --- /dev/null +++ b/yarn-project/p2p/src/client/tx.ts @@ -0,0 +1,63 @@ +import { randomBytes } from 'crypto'; +import { Keccak } from 'sha3'; + +const hash = new Keccak(256); + +/** + * Accumulated data of an A3 transaction. + */ +export class AccumulatedTxData { + constructor( + public newCommitments: Buffer[], + public newNullifiers: Buffer[], + public privateCallStack: Buffer[], + public publicCallStack: Buffer[], + public l1MsgStack: Buffer[], + public newContracts: Buffer[], + public optionallyRevealedData: Buffer[], + public aggregationObject?: object, + public callCount?: number, + ) {} + + public static random() { + return new AccumulatedTxData( + [randomBytes(32)], + [randomBytes(32)], + [randomBytes(32)], + [randomBytes(32)], + [randomBytes(32)], + [randomBytes(32)], + [randomBytes(32)], + undefined, + undefined, + ); + } +} + +/** + * The interface of an L2 transaction. + */ +export class Tx { + constructor(private txData: AccumulatedTxData) {} + + /** + * Construct & return transaction ID. + * // TODO: actually construct & return tx id. + * @returns The transaction's id. + */ + get txId() { + const constractTxData = this.txData.newContracts[0]; + hash.reset(); + return hash.update(constractTxData).digest(); + } + + /** + * Utility function to generate tx ID. + * @param txData - Binary representation of the tx data. + * @returns A hash of the tx data that identifies the tx. + */ + static createTxId(txData: Buffer) { + hash.reset(); + return hash.update(txData).digest(); + } +} diff --git a/yarn-project/p2p/src/index.ts b/yarn-project/p2p/src/index.ts index e43af2992a92..e6a85a1efa9e 100644 --- a/yarn-project/p2p/src/index.ts +++ b/yarn-project/p2p/src/index.ts @@ -1,4 +1,24 @@ +// import { InMemoryP2PCLient } from './memory_p2p_client.js'; +// import { MockBlockSource } from './mocks.js'; + +export * from './client/index.js'; + /** - * A placeholder for the P2P layer. + * Main function of P2P in-memory client that runs at init. */ -export class P2P {} +// async function main() { +// // TODO: replace with actual rollup source that gets instantiated with env variables +// const rollupSource = new MockBlockSource(); +// const p2pClient = new InMemoryP2PCLient(rollupSource); +// await p2pClient.start(); + +// const shutdown = async () => { +// await p2pClient.stop(); +// process.exit(0); +// }; + +// process.once('SIGINT', shutdown); +// process.once('SIGTERM', shutdown); +// } + +// main().catch(err => console.log('ERROR in main p2p function: ', err)); diff --git a/yarn-project/p2p/src/tx_pool/index.ts b/yarn-project/p2p/src/tx_pool/index.ts new file mode 100644 index 000000000000..07d1496cc014 --- /dev/null +++ b/yarn-project/p2p/src/tx_pool/index.ts @@ -0,0 +1,2 @@ +export * from './tx_pool.js'; +export * from './memory_tx_pool.js'; diff --git a/yarn-project/p2p/src/tx_pool/memory_tx_pool.ts b/yarn-project/p2p/src/tx_pool/memory_tx_pool.ts new file mode 100644 index 000000000000..4d6ed9bd9788 --- /dev/null +++ b/yarn-project/p2p/src/tx_pool/memory_tx_pool.ts @@ -0,0 +1,70 @@ +import { createDebugLogger } from '@aztec/foundation'; +import { Tx } from '../index.js'; +import { TxPool } from './index.js'; + +/** + * Helper to tranform Buffer IDs to a bigint. + */ +// TODO: place in/use from foundation repo +const toBigInt = (buf: Buffer): bigint => { + const hex = buf.toString('hex'); + if (hex.length === 0) { + return BigInt(0); + } + return BigInt(`0x${hex}`); +}; + +/** + * In-memory implementation of the Transaction Pool. + */ +export class InMemoryTxPool implements TxPool { + /** + * Our tx pool, stored as a Map in-memory, with K: tx ID and V: the transaction. + */ + private txs: Map; + + /** + * Class constructor for in-memory TxPool. Initiates our transaction pool as a JS Map. + * @param log - A logger. + */ + constructor(private log = createDebugLogger('aztec:tx_pool')) { + this.txs = new Map(); + } + + /** + * Checks if a transaction exists in the pool and returns it. + * @param txId - The generated tx ID. + * @returns The transaction, if found, 'undefined' otherwise. + */ + public getTx(txId: Buffer): Tx | undefined { + const result = this.txs.get(toBigInt(txId)); + return result; + } + + /** + * Adds a list of transactions to the pool. Duplicates are ignored. + * @param txs - An array of txs to be added to the pool. + */ + public addTxs(txs: Tx[]): void { + this.log(`Adding tx with id ${txs[0].txId.toString('hex')}`); + txs.forEach(tx => this.txs.set(toBigInt(tx.txId), tx)); + } + + /** + * Deletes transactions from the pool. Tx IDs that are not present are ignored. + * @param txIds - An array of tx IDs to be removed from the tx pool. + * @returns The number of transactions that was deleted from the pool. + */ + public deleteTxs(txIds: Buffer[]): number { + const numTxsRemoved = txIds.map(txId => this.txs.delete(toBigInt(txId))).filter(result => result === true).length; + return numTxsRemoved; + } + + /** + * Gets all the transactions stored in the pool. + * @returns Array of tx objects in the order they were added to the pool. + */ + public getAllTxs(): Tx[] { + return Array.from(this.txs.values()); + } +} diff --git a/yarn-project/p2p/src/tx_pool/tx_pool.test.ts b/yarn-project/p2p/src/tx_pool/tx_pool.test.ts new file mode 100644 index 000000000000..1470b007fb2e --- /dev/null +++ b/yarn-project/p2p/src/tx_pool/tx_pool.test.ts @@ -0,0 +1,24 @@ +import { MockTx } from '../client/mocks.js'; +import { InMemoryTxPool } from './index.js'; + +describe('In-Memory TX pool', () => { + it('Adds txs to the pool', () => { + const pool = new InMemoryTxPool(); + const tx1 = MockTx(); + + pool.addTxs([tx1]); + const poolTx = pool.getTx(tx1.txId); + expect(poolTx?.txId.toString('hex')).toEqual(tx1.txId.toString('hex')); + }); + + it('Removes txs from the pool', () => { + const pool = new InMemoryTxPool(); + const tx1 = MockTx(); + + pool.addTxs([tx1]); + pool.deleteTxs([tx1.txId]); + + const poolTx = pool.getTx(tx1.txId); + expect(poolTx).toBeFalsy(); + }); +}); diff --git a/yarn-project/p2p/src/tx_pool/tx_pool.ts b/yarn-project/p2p/src/tx_pool/tx_pool.ts new file mode 100644 index 000000000000..c3134d45418c --- /dev/null +++ b/yarn-project/p2p/src/tx_pool/tx_pool.ts @@ -0,0 +1,31 @@ +import { Tx } from '../index.js'; + +/** + * Interface of a transaction pool. The pool includes tx requests and is kept up-to-date by a P2P client. + */ +export interface TxPool { + /** + * Adds a list of transactions to the pool. Duplicates are ignored. + * @param txs - An array of txs to be added to the pool. + */ + addTxs(txs: Tx[]): void; + + /** + * Checks if a transaction exists in the pool and returns it. + * @param txId - The generated tx ID. + * @returns The transaction, if found, 'undefined' otherwise. + */ + getTx(txId: Buffer): Tx | undefined; + + /** + * Deletes transactions from the pool. Tx IDs that are not present are ignored. + * @param txIds - An array of tx IDs to be removed from the tx pool. + */ + deleteTxs(txIds: Buffer[]): void; + + /** + * Gets all transactions currently in the tx pool. + * @returns An array of transaction objects found in the tx pool. + */ + getAllTxs(): Tx[]; +} diff --git a/yarn-project/p2p/tsconfig.dest.json b/yarn-project/p2p/tsconfig.dest.json index 965aaa1c433e..f454c8daf89b 100644 --- a/yarn-project/p2p/tsconfig.dest.json +++ b/yarn-project/p2p/tsconfig.dest.json @@ -1,4 +1,12 @@ { "extends": ".", + "references": [ + { + "path": "../archiver/tsconfig.dest.json" + }, + { + "path": "../foundation/tsconfig.dest.json" + } + ], "exclude": ["**/*.test.*", "**/fixtures/*"] } diff --git a/yarn-project/p2p/tsconfig.json b/yarn-project/p2p/tsconfig.json index f67ddec9fd6b..ca129bed4417 100644 --- a/yarn-project/p2p/tsconfig.json +++ b/yarn-project/p2p/tsconfig.json @@ -3,7 +3,14 @@ "compilerOptions": { "outDir": "dest", "rootDir": "src", - "tsBuildInfoFile": ".tsbuildinfo" + "tsBuildInfoFile": ".tsbuildinfo", + "moduleResolution": "nodenext", + "types": ["node", "jest"] }, + "references": [ + { + "path": "../archiver/tsconfig.dest.json" + } + ], "include": ["src"] } diff --git a/yarn-project/package.json b/yarn-project/package.json index 0e8d4f3d2be0..3253b261fe58 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -14,19 +14,21 @@ "aztec.js", "docs", "end-to-end", - "eslint-config", "ethereum.js", "ethereum.js/example", + "foundation", "kernel-simulator", "key-store", + "merkle-tree", "noir-contracts", + "l1-contracts", "p2p", - "prettier-config", "prover-client", - "public-client", - "sequencer-client" + "aztec-node", + "sequencer-client", + "world-state" ], - "prettier": "./prettier-config", + "prettier": "@aztec/foundation/prettier", "devDependencies": { "eslint": "^8.21.0", "prettier": "^2.7.1", diff --git a/yarn-project/prettier-config/index.js b/yarn-project/prettier-config/index.js deleted file mode 100644 index e80a1d3874a2..000000000000 --- a/yarn-project/prettier-config/index.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - singleQuote: true, - trailingComma: 'all', - printWidth: 120, - arrowParens: 'avoid', -}; diff --git a/yarn-project/prettier-config/package.json b/yarn-project/prettier-config/package.json deleted file mode 100644 index 942295382153..000000000000 --- a/yarn-project/prettier-config/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@aztec/prettier-config", - "version": "0.0.0", - "packageManager": "yarn@3.2.2", - "dependencies": { - "prettier": "^2.7.1" - } -} diff --git a/yarn-project/prover-client/.eslintrc.cjs b/yarn-project/prover-client/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/prover-client/.eslintrc.cjs +++ b/yarn-project/prover-client/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index e6b189a47b32..709986a55946 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -32,7 +32,6 @@ "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", diff --git a/yarn-project/public-client/.eslintrc.cjs b/yarn-project/public-client/.eslintrc.cjs deleted file mode 100644 index 9cf806b1500f..000000000000 --- a/yarn-project/public-client/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; diff --git a/yarn-project/public-client/README.md b/yarn-project/public-client/README.md deleted file mode 100644 index 9ea41167a791..000000000000 --- a/yarn-project/public-client/README.md +++ /dev/null @@ -1 +0,0 @@ -# Public Client diff --git a/yarn-project/public-client/src/index.ts b/yarn-project/public-client/src/index.ts deleted file mode 100644 index d91578d2c5f2..000000000000 --- a/yarn-project/public-client/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * A placeholder for the Public Client. - */ -export class PublicClient {} diff --git a/yarn-project/sequencer-client/.eslintrc.cjs b/yarn-project/sequencer-client/.eslintrc.cjs index 9cf806b1500f..e659927475c0 100644 --- a/yarn-project/sequencer-client/.eslintrc.cjs +++ b/yarn-project/sequencer-client/.eslintrc.cjs @@ -1,6 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/sequencer-client/jest.integration.config.json b/yarn-project/sequencer-client/jest.integration.config.json new file mode 100644 index 000000000000..f89093c1acff --- /dev/null +++ b/yarn-project/sequencer-client/jest.integration.config.json @@ -0,0 +1,13 @@ +{ + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./test/.*\\.test\\.ts$", + "rootDir": "./test" +} \ No newline at end of file diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index e1408b020ddc..c4ee48092cbe 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -13,7 +13,10 @@ "build:dev": "tsc -b tsconfig.dest.json --watch", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + "formatting:fix": "run -T prettier -w ./src && run -T eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests", + "test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"", + "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json" }, "jest": { "preset": "ts-jest/presets/default-esm", @@ -29,15 +32,19 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/archiver": "workspace:^", + "@aztec/ethereum.js": "workspace:^", + "@aztec/l1-contracts": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { - "@aztec/eslint-config": "workspace:^", "@jest/globals": "^29.4.3", "@rushstack/eslint-patch": "^1.1.4", "@types/jest": "^29.4.0", "@types/node": "^18.7.23", + "concurrently": "^7.6.0", "jest": "^28.1.3", + "jest-mock-extended": "^3.0.3", "ts-jest": "^28.0.7", "ts-node": "^10.9.1", "typescript": "^4.9.5" diff --git a/yarn-project/sequencer-client/src/config.ts b/yarn-project/sequencer-client/src/config.ts new file mode 100644 index 000000000000..d3596f7793bb --- /dev/null +++ b/yarn-project/sequencer-client/src/config.ts @@ -0,0 +1,7 @@ +import { L1Addresses } from '@aztec/l1-contracts'; + +export interface Config extends L1Addresses { + sequencerPrivateKey: string; + ethereumHost: string; + requiredConfirmations: number; +} diff --git a/yarn-project/sequencer-client/src/publisher/aztec-ethereumjs-tx-sender.ts b/yarn-project/sequencer-client/src/publisher/aztec-ethereumjs-tx-sender.ts new file mode 100644 index 000000000000..f8e00e2694db --- /dev/null +++ b/yarn-project/sequencer-client/src/publisher/aztec-ethereumjs-tx-sender.ts @@ -0,0 +1,42 @@ +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { EthereumRpc, TxHash, waitForTxReceipt } from '@aztec/ethereum.js/eth_rpc'; +import { WalletProvider } from '@aztec/ethereum.js/provider'; +import { Rollup } from '@aztec/l1-contracts'; +import { Config } from '../config.js'; +import { hexStringToBuffer } from '../utils.js'; +import { L1ProcessRollupArgs, PublisherTxSender } from './l2-block-publisher.js'; + +/** + * Pushes transactions to the L1 rollup contract using the custom aztec/ethereum.js library. + */ +export class AztecEthereumjsTxSender implements PublisherTxSender { + private ethRpc: EthereumRpc; + private rollupContract: Rollup; + private confirmations: number; + + constructor(config: Config) { + const { ethereumHost, sequencerPrivateKey, rollupContract: rollupContractAddress, requiredConfirmations } = config; + const provider = WalletProvider.fromHost(ethereumHost); + provider.addAccount(hexStringToBuffer(sequencerPrivateKey)); + this.ethRpc = new EthereumRpc(provider); + this.rollupContract = new Rollup(this.ethRpc, EthAddress.fromString(rollupContractAddress), { + from: provider.getAccount(0), + }); + this.confirmations = requiredConfirmations; + } + + getTransactionReceipt(txHash: string): Promise<{ status: boolean; transactionHash: string } | undefined> { + return waitForTxReceipt(TxHash.fromString(txHash), this.ethRpc, this.confirmations).then( + r => r && { ...r, transactionHash: r.transactionHash.toString() }, + ); + } + + async sendTransaction(encodedData: L1ProcessRollupArgs): Promise { + const methodCall = this.rollupContract.methods.processRollup(encodedData.proof, encodedData.inputs); + const gas = await methodCall.estimateGas(); + return methodCall + .send({ gas }) + .getTxHash() + .then(hash => hash.toString()); + } +} diff --git a/yarn-project/sequencer-client/src/publisher/index.ts b/yarn-project/sequencer-client/src/publisher/index.ts new file mode 100644 index 000000000000..b903b10a5205 --- /dev/null +++ b/yarn-project/sequencer-client/src/publisher/index.ts @@ -0,0 +1,9 @@ +import { Config } from '../config.js'; +import { AztecEthereumjsTxSender } from './aztec-ethereumjs-tx-sender.js'; +import { L2BlockPublisher } from './l2-block-publisher.js'; + +export { L2BlockPublisher } from './l2-block-publisher.js'; + +export function getL2BlockPublisher(config: Config): L2BlockPublisher { + return new L2BlockPublisher(new AztecEthereumjsTxSender(config)); +} diff --git a/yarn-project/sequencer-client/src/publisher/l2-block-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l2-block-publisher.test.ts new file mode 100644 index 000000000000..28eb8ae006f3 --- /dev/null +++ b/yarn-project/sequencer-client/src/publisher/l2-block-publisher.test.ts @@ -0,0 +1,78 @@ +import { L2Block, mockRandomL2Block } from '@aztec/archiver'; +import { TxHash } from '@aztec/ethereum.js/eth_rpc'; +import { mock, MockProxy } from 'jest-mock-extended'; +import { sleep } from '../utils.js'; +import { L2BlockPublisher, PublisherTxSender } from './l2-block-publisher.js'; + +describe('L2BlockPublisher', () => { + let txSender: MockProxy; + let txHash: string; + let txReceipt: { transactionHash: string; status: boolean }; + let l2Block: L2Block; + let l2Inputs: Buffer; + let l2Proof: Buffer; + let publisher: L2BlockPublisher; + + beforeEach(() => { + l2Block = mockRandomL2Block(42); + l2Inputs = l2Block.encode(); + l2Proof = Buffer.alloc(0); + + txSender = mock(); + txHash = TxHash.random().toString(); + txReceipt = { transactionHash: txHash, status: true }; + txSender.sendTransaction.mockResolvedValueOnce(txHash); + txSender.getTransactionReceipt.mockResolvedValueOnce(txReceipt); + + publisher = new L2BlockPublisher(txSender, { sleepTimeMs: 1 }); + }); + + it('publishes l2 block to l1', async () => { + const result = await publisher.processL2Block(l2Block); + + expect(result).toEqual(true); + expect(txSender.sendTransaction).toHaveBeenCalledWith({ proof: l2Proof, inputs: l2Inputs }); + expect(txSender.getTransactionReceipt).toHaveBeenCalledWith(txHash); + }); + + it('retries if sending a tx fails', async () => { + txSender.sendTransaction.mockReset().mockRejectedValueOnce(new Error()).mockResolvedValueOnce(txHash); + + const result = await publisher.processL2Block(l2Block); + + expect(result).toEqual(true); + expect(txSender.sendTransaction).toHaveBeenCalledTimes(2); + }); + + it('retries if fetching the receipt fails', async () => { + txSender.getTransactionReceipt.mockReset().mockRejectedValueOnce(new Error()).mockResolvedValueOnce(txReceipt); + + const result = await publisher.processL2Block(l2Block); + + expect(result).toEqual(true); + expect(txSender.getTransactionReceipt).toHaveBeenCalledTimes(2); + }); + + it('returns false if tx reverts', async () => { + txSender.getTransactionReceipt.mockReset().mockResolvedValueOnce({ ...txReceipt, status: false }); + + const result = await publisher.processL2Block(l2Block); + + expect(result).toEqual(false); + }); + + it('returns false if interrupted', async () => { + txSender.sendTransaction.mockReset().mockImplementationOnce(() => sleep(10, txHash)); + + const resultPromise = publisher.processL2Block(l2Block); + publisher.interrupt(); + const result = await resultPromise; + + expect(result).toEqual(false); + expect(txSender.getTransactionReceipt).not.toHaveBeenCalled(); + }); + + it.skip('waits for fee distributor balance', () => {}); + + it.skip('fails if contract is changed underfoot', () => {}); +}); diff --git a/yarn-project/sequencer-client/src/publisher/l2-block-publisher.ts b/yarn-project/sequencer-client/src/publisher/l2-block-publisher.ts new file mode 100644 index 000000000000..cae144d5295d --- /dev/null +++ b/yarn-project/sequencer-client/src/publisher/l2-block-publisher.ts @@ -0,0 +1,131 @@ +import { L2Block } from '@aztec/archiver'; +import { L2BlockReceiver } from '../receiver.js'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const MIN_FEE_DISTRIBUTOR_BALANCE = 5n * 10n ** 17n; + +/** + * Component responsible of pushing the txs to the chain and waiting for completion. + */ +export interface PublisherTxSender { + sendTransaction(encodedData: L1ProcessRollupArgs): Promise; + getTransactionReceipt(txHash: string): Promise<{ status: boolean; transactionHash: string } | undefined>; +} + +/** + * Encoded block data and proof ready to be pushed to the L1 contract. + */ +export type L1ProcessRollupArgs = { + proof: Buffer; + inputs: Buffer; +}; + +/** + * Publishes L2 blocks to the L1 rollup contracts. This implementation does *not* retry a transaction in + * the event of network congestion. + * - If sending (not mining) a tx fails, it retries indefinitely at 1-minute intervals. + * - If the tx is not mined, keeps polling indefinitely at 1-second intervals. + * + * Adapted from https://github.com/AztecProtocol/aztec2-internal/blob/master/falafel/src/rollup_publisher.ts. + */ +export class L2BlockPublisher implements L2BlockReceiver { + private interrupted = false; + private interruptPromise = Promise.resolve(); + private interruptResolve = () => {}; + private sleepTimeMs: number; + + constructor(private txSender: PublisherTxSender, opts?: { sleepTimeMs?: number }) { + this.interruptPromise = new Promise(resolve => (this.interruptResolve = resolve)); + this.sleepTimeMs = opts?.sleepTimeMs ?? 60_000; + } + + /** + * Processes incoming L2 block data by publishing it to the L1 rollup contract. + * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise. + */ + public async processL2Block(l2BlockData: L2Block): Promise { + const proof = Buffer.alloc(0); + const txData = { proof, inputs: l2BlockData.encode() }; + + while (!this.interrupted) { + if (!(await this.checkFeeDistributorBalance())) { + console.log(`Fee distributor ETH balance too low, awaiting top up...`); + await this.sleepOrInterrupted(); + continue; + } + + const txHash = await this.sendTransaction(txData); + if (!txHash) break; + + const receipt = await this.getTransactionReceipt(txHash); + if (!receipt) break; + + // Tx was mined successfully + if (receipt.status) return true; + + // Check if someone else moved the block id + if (!(await this.checkNextL2BlockId(l2BlockData.number))) { + console.log('Publish failed. Contract changed underfoot.'); + break; + } + + console.log(`Transaction status failed: ${receipt.transactionHash}`); + await this.sleepOrInterrupted(); + } + + console.log('Publish rollup interrupted.'); + return false; + } + + /** + * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap. + * Be warned, the call may return false even if the tx subsequently gets successfully mined. + * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail. + * A call to `clearInterrupt` is required before you can continue publishing. + */ + public interrupt() { + this.interrupted = true; + this.interruptResolve(); + } + + // TODO: Check fee distributor has at least 0.5 ETH. + // eslint-disable-next-line require-await + private async checkFeeDistributorBalance(): Promise { + return true; + } + + // TODO: Fail if blockchainStatus.nextRollupId > thisBlockId. + // eslint-disable-next-line require-await, @typescript-eslint/no-unused-vars + private async checkNextL2BlockId(thisBlockId: number): Promise { + return true; + } + + private async sendTransaction(encodedData: L1ProcessRollupArgs): Promise { + while (!this.interrupted) { + try { + return await this.txSender.sendTransaction(encodedData); + } catch (err) { + console.log(`Error sending tx to L1`, err); + await this.sleepOrInterrupted(); + } + } + } + + private async getTransactionReceipt( + txHash: string, + ): Promise<{ status: boolean; transactionHash: string } | undefined> { + while (!this.interrupted) { + try { + return await this.txSender.getTransactionReceipt(txHash); + } catch (err) { + console.log(`Error getting tx receipt`, err); + await this.sleepOrInterrupted(); + } + } + } + + protected async sleepOrInterrupted() { + const ms = this.sleepTimeMs; + await Promise.race([new Promise(resolve => setTimeout(resolve, ms)), this.interruptPromise]); + } +} diff --git a/yarn-project/sequencer-client/src/receiver.ts b/yarn-project/sequencer-client/src/receiver.ts new file mode 100644 index 000000000000..ed8949730af8 --- /dev/null +++ b/yarn-project/sequencer-client/src/receiver.ts @@ -0,0 +1,9 @@ +import { L2Block } from '@aztec/archiver'; + +/** + * Given the necessary rollup data, verifies it, and updates the underlying state accordingly to advance the state of the system. + * See https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#RollupReceiver. + */ +export interface L2BlockReceiver { + processL2Block(l2BlockData: L2Block): Promise; +} diff --git a/yarn-project/sequencer-client/src/utils.ts b/yarn-project/sequencer-client/src/utils.ts new file mode 100644 index 000000000000..70b7eedaa3ba --- /dev/null +++ b/yarn-project/sequencer-client/src/utils.ts @@ -0,0 +1,9 @@ +export function hexStringToBuffer(hex: string): Buffer { + if (!/^(0x)?[a-fA-F0-9]+$/.test(hex)) throw new Error(`Invalid format for hex string: "${hex}"`); + if (hex.length % 2 === 1) throw new Error(`Invalid length for hex string: "${hex}"`); + return Buffer.from(hex.replace(/^0x/, ''), 'hex'); +} + +export function sleep(ms: number, retval: T): Promise { + return new Promise(resolve => setTimeout(() => resolve(retval), ms)); +} diff --git a/yarn-project/sequencer-client/test/l2-block-publisher.test.ts b/yarn-project/sequencer-client/test/l2-block-publisher.test.ts new file mode 100644 index 000000000000..eff87471472d --- /dev/null +++ b/yarn-project/sequencer-client/test/l2-block-publisher.test.ts @@ -0,0 +1,75 @@ +import { L2Block, mockRandomL2Block } from '@aztec/archiver'; +import { EthAddress } from '@aztec/ethereum.js/eth_address'; +import { EthereumRpc } from '@aztec/ethereum.js/eth_rpc'; +import { WalletProvider } from '@aztec/ethereum.js/provider'; +import { Rollup } from '@aztec/l1-contracts'; +import { beforeAll, describe, expect, it } from '@jest/globals'; +import { AztecEthereumjsTxSender } from '../src/publisher/aztec-ethereumjs-tx-sender.js'; +import { L2BlockPublisher } from '../src/publisher/l2-block-publisher.js'; +import { hexStringToBuffer } from '../src/utils.js'; + +// Accounts 4 and 5 of Anvil default startup with mnemonic: 'test test test test test test test test test test test junk' +const sequencerPK = '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a'; +const deployerPK = '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba'; +const anvilHost = process.env.ANVIL_HOST ?? 'http://127.0.0.1:8545'; + +describe('L2BlockPublisher integration', () => { + let rollup: Rollup; + let ethRpc: EthereumRpc; + let publisher: L2BlockPublisher; + let l2Block: L2Block; + let l2Proof: Buffer; + + beforeAll(async () => { + let deployer: EthAddress; + ({ ethRpc, rollup, deployer } = await deployRollup()); + + l2Block = mockRandomL2Block(42); + l2Proof = Buffer.alloc(0); + + publisher = new L2BlockPublisher( + new AztecEthereumjsTxSender({ + ethereumHost: anvilHost, + feeDistributor: deployer.toChecksumString(), + requiredConfirmations: 1, + rollupContract: rollup.address.toChecksumString(), + sequencerPrivateKey: sequencerPK + }), + { + sleepTimeMs: 100 + } + ); + }); + + it('publishes l2 block data to l1 rollup contract', async () => { + const blockNumber = await ethRpc.blockNumber(); + await publisher.processL2Block(l2Block); + + const logs = await rollup.getLogs('RollupBlockProcessed', { fromBlock: blockNumber }); + expect(logs).toHaveLength(1); + expect(logs[0].args.rollupBlockNumber).toEqual(42n); + + const tx = await ethRpc.getTransactionByHash(logs[0].transactionHash!); + const expectedData = rollup.methods.processRollup(l2Proof, l2Block.encode()).encodeABI(); + expect(tx.input).toEqual(expectedData); + }); +}); + + +async function deployRollup() { + // Set up client + const provider = WalletProvider.fromHost(anvilHost); + provider.addAccount(hexStringToBuffer(deployerPK)); + provider.addAccount(hexStringToBuffer(sequencerPK)); + const [sequencer, deployer] = provider.getAccounts(); + const ethRpc = new EthereumRpc(provider); + + // Deploy rollup contract + const deployedRollup = new Rollup(ethRpc, undefined, { from: deployer, gas: 1e6 }); + await deployedRollup.deploy().send().getReceipt(); + + // Create new instance so we can attach the sequencer as sender + const rollup = new Rollup(ethRpc, deployedRollup.address, { from: sequencer }); + + return { rollup, deployer, sequencer, ethRpc }; +} \ No newline at end of file diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index f67ddec9fd6b..dec34639a4a9 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -5,5 +5,5 @@ "rootDir": "src", "tsBuildInfoFile": ".tsbuildinfo" }, - "include": ["src"] + "include": ["src", "test"] } diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index 1bdaa3857199..e405ee04264e 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -13,7 +13,9 @@ "noir-contracts", "p2p", "prover-client", - "public-client", - "sequencer-client" + "aztec-node", + "sequencer-client", + "world-state", + "merkle-tree" ] } diff --git a/yarn-project/world-state/.eslintrc.cjs b/yarn-project/world-state/.eslintrc.cjs new file mode 100644 index 000000000000..e659927475c0 --- /dev/null +++ b/yarn-project/world-state/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/world-state/Dockerfile b/yarn-project/world-state/Dockerfile new file mode 100644 index 000000000000..42f12b1bbddf --- /dev/null +++ b/yarn-project/world-state/Dockerfile @@ -0,0 +1,14 @@ +FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder + +COPY world-state world-state +WORKDIR /usr/src/yarn-project/world-state +RUN yarn build && yarn formatting && yarn test + +# Prune dev dependencies. See comment in base image. +RUN yarn cache clean +RUN yarn workspaces focus --production > /dev/null + +FROM node:18-alpine +COPY --from=builder /usr/src/yarn-project/world-state /usr/src/yarn-project/world-state +WORKDIR /usr/src/yarn-project/world-state +ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/world-state/README.md b/yarn-project/world-state/README.md new file mode 100644 index 000000000000..39212748a090 --- /dev/null +++ b/yarn-project/world-state/README.md @@ -0,0 +1 @@ +# World State diff --git a/yarn-project/world-state/package.json b/yarn-project/world-state/package.json new file mode 100644 index 000000000000..2cb91fcb8e81 --- /dev/null +++ b/yarn-project/world-state/package.json @@ -0,0 +1,47 @@ +{ + "name": "@aztec/world-state", + "version": "0.0.0", + "type": "module", + "exports": "./dest/index.js", + "scripts": { + "build": "yarn clean && yarn formatting && tsc -b tsconfig.dest.json", + "build:dev": "tsc -b tsconfig.dest.json --watch", + "clean": "rm -rf ./dest .tsbuildinfo", + "formatting": "run -T prettier --check ./src && run -T eslint --max-warnings 0 ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --passWithNoTests" + }, + "jest": { + "preset": "ts-jest/presets/default-esm", + "globals": { + "ts-jest": { + "useESM": true + } + }, + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.ts$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/archiver": "workspace:^", + "@aztec/foundation": "workspace:^", + "@aztec/merkle-tree": "workspace:^", + "levelup": "^5.1.1", + "memdown": "^6.1.1", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@aztec/archiver": "workspace:^", + "@jest/globals": "^29.4.3", + "@rushstack/eslint-patch": "^1.1.4", + "@types/jest": "^29.4.0", + "@types/levelup": "^5.1.2", + "@types/memdown": "^3.0.0", + "@types/node": "^18.7.23", + "jest": "^28.1.3", + "ts-jest": "^28.0.7", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + } +} diff --git a/yarn-project/world-state/src/index.ts b/yarn-project/world-state/src/index.ts new file mode 100644 index 000000000000..2d348b5a90c1 --- /dev/null +++ b/yarn-project/world-state/src/index.ts @@ -0,0 +1,2 @@ +export * from './synchroniser/index.js'; +export * from './world-state-db/index.js'; diff --git a/yarn-project/world-state/src/synchroniser/index.ts b/yarn-project/world-state/src/synchroniser/index.ts new file mode 100644 index 000000000000..b875061d458c --- /dev/null +++ b/yarn-project/world-state/src/synchroniser/index.ts @@ -0,0 +1,2 @@ +export * from './server_world_state_synchroniser.js'; +export * from './world_state_synchroniser.js'; diff --git a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts new file mode 100644 index 000000000000..f84409a894ca --- /dev/null +++ b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts @@ -0,0 +1,215 @@ +import { ServerWorldStateSynchroniser } from './server_world_state_synchroniser.js'; +import { L2BlockSource, L2BlockSourceSyncStatus, L2Block } from '@aztec/archiver'; +import { WorldStateRunningState } from './world_state_synchroniser.js'; +import { Pedersen, MerkleTreeDb, MerkleTreeId, SiblingPath, StandardMerkleTree } from '@aztec/merkle-tree'; +import { sleep } from '@aztec/foundation'; +import { jest } from '@jest/globals'; + +/** + * Generic mock implementation. + */ +type Mockify = { + [P in keyof T]: jest.Mock; +}; + +const syncStatus = { + syncedToBlock: 0, + latestBlock: 0, +} as L2BlockSourceSyncStatus; + +const LATEST_BLOCK_NUMBER = 5; +const getLatestBlockNumber = () => LATEST_BLOCK_NUMBER; +let nextBlocks: L2Block[] = []; +const consumeNextBlocks = () => { + const blocks = nextBlocks; + nextBlocks = []; + return Promise.resolve(blocks); +}; + +const getMockBlock = (blockNumber: number, newContractsCommitments?: Buffer[]) => { + const block = { + number: blockNumber, + newContracts: newContractsCommitments ?? [Buffer.alloc(32, 0)], + } as L2Block; + return block; +}; + +const createSynchroniser = (merkleTreeDb: any, rollupSource: any) => + new ServerWorldStateSynchroniser(merkleTreeDb as MerkleTreeDb, rollupSource as L2BlockSource, 1, 100); + +describe('server_world_state_synchroniser', () => { + const pedersen: Pedersen = new Pedersen(); + const rollupSource: Mockify = { + getSyncStatus: jest.fn().mockImplementation(() => Promise.resolve(syncStatus)), + getLatestBlockNum: jest.fn().mockImplementation(getLatestBlockNumber), + getL2Blocks: jest.fn().mockImplementation(consumeNextBlocks), + } as any; + + const merkleTreeDb: Mockify = { + getTreeInfo: jest + .fn() + .mockImplementation(() => + Promise.resolve({ treeId: MerkleTreeId.CONTRACT_TREE, root: Buffer.alloc(32, 0), size: 0n }), + ), + appendLeaves: jest.fn().mockImplementation(() => Promise.resolve()), + getSiblingPath: jest.fn().mockImplementation(() => { + return Promise.resolve(SiblingPath.ZERO(32, StandardMerkleTree.ZERO_ELEMENT, pedersen)); + }), + commit: jest.fn().mockImplementation(() => Promise.resolve()), + rollback: jest.fn().mockImplementation(() => Promise.resolve()), + } as any; + + it('can be constructed', () => { + expect(() => createSynchroniser(merkleTreeDb, rollupSource)).not.toThrow(); + }); + + it('updates sync progress', async () => { + const server = createSynchroniser(merkleTreeDb, rollupSource); + + // test initial state + let status = await server.status(); + expect(status.syncedToL2Block).toEqual(-1); + expect(status.state).toEqual(WorldStateRunningState.IDLE); + + // create an initial block + let currentBlockNumber = -1; + nextBlocks = [getMockBlock(currentBlockNumber + 1)]; + + // start the sync process but don't await + server.start(0).catch(() => console.log('Sync not completed!!')); + + // now setup a loop to monitor the sync progress and push new blocks in + while (currentBlockNumber <= LATEST_BLOCK_NUMBER) { + status = await server.status(); + expect( + status.syncedToL2Block >= currentBlockNumber || status.syncedToL2Block <= currentBlockNumber + 1, + ).toBeTruthy(); + if (status.syncedToL2Block === LATEST_BLOCK_NUMBER) { + break; + } + expect( + status.state >= WorldStateRunningState.IDLE || status.state <= WorldStateRunningState.SYNCHING, + ).toBeTruthy(); + if (status.syncedToL2Block === currentBlockNumber) { + await sleep(100); + continue; + } + currentBlockNumber++; + nextBlocks = [getMockBlock(currentBlockNumber + 1)]; + } + + // check the status agian, should be fully synced + status = await server.status(); + expect(status.state).toEqual(WorldStateRunningState.RUNNING); + expect(status.syncedToL2Block).toEqual(LATEST_BLOCK_NUMBER); + + // stop the synchroniser + await server.stop(); + + // check the final status + status = await server.status(); + expect(status.state).toEqual(WorldStateRunningState.STOPPED); + expect(status.syncedToL2Block).toEqual(LATEST_BLOCK_NUMBER); + }); + + it('enables blocking until synced', async () => { + const server = createSynchroniser(merkleTreeDb, rollupSource); + let currentBlockNumber = -1; + + const newBlocks = async () => { + while (currentBlockNumber <= LATEST_BLOCK_NUMBER) { + await sleep(100); + nextBlocks = [...nextBlocks, getMockBlock(++currentBlockNumber)]; + } + }; + + // kick off the background queueing of blocks + const newBlockPromise = newBlocks(); + + // kick off the synching + const syncPromise = server.start(0); + + // await the synching + await syncPromise; + + await newBlockPromise; + + let status = await server.status(); + expect(status.state).toEqual(WorldStateRunningState.RUNNING); + expect(status.syncedToL2Block).toEqual(LATEST_BLOCK_NUMBER); + await server.stop(); + status = await server.status(); + expect(status.state).toEqual(WorldStateRunningState.STOPPED); + expect(status.syncedToL2Block).toEqual(LATEST_BLOCK_NUMBER); + }); + + it('handles multiple calls to start', async () => { + const server = createSynchroniser(merkleTreeDb, rollupSource); + let currentBlockNumber = -1; + + const newBlocks = async () => { + while (currentBlockNumber < LATEST_BLOCK_NUMBER) { + await sleep(100); + const newBlock = getMockBlock(++currentBlockNumber); + nextBlocks = [...nextBlocks, newBlock]; + } + }; + + // kick off the background queueing of blocks + const newBlockPromise = newBlocks(); + + // kick off the synching + await server.start(0); + + // call start again, should get back the same promise + await server.start(0); + + // wait until the block production has finished + await newBlockPromise; + + await server.stop(); + }); + + it('immediately syncs if no new blocks', async () => { + const server = createSynchroniser(merkleTreeDb, rollupSource); + + // kick off the synching + const syncPromise = server.start(5); + + // it should already be synced, no need to push new blocks + await syncPromise; + + const status = await server.status(); + expect(status.state).toBe(WorldStateRunningState.RUNNING); + expect(status.syncedToL2Block).toBe(LATEST_BLOCK_NUMBER); + await server.stop(); + }); + + it("can't be started if already stopped", async () => { + const server = createSynchroniser(merkleTreeDb, rollupSource); + + // kick off the synching + const syncPromise = server.start(5); + await syncPromise; + await server.stop(); + + await expect(server.start()).rejects.toThrow(); + }); + + it('updates the contract tree', async () => { + merkleTreeDb.appendLeaves.mockReset(); + const server = createSynchroniser(merkleTreeDb, rollupSource); + const totalBlocks = LATEST_BLOCK_NUMBER + 1; + nextBlocks = Array(totalBlocks) + .fill(0) + .map((_, index) => getMockBlock(index, [Buffer.alloc(32, index)])); + // sync the server + await server.start(0); + expect(merkleTreeDb.appendLeaves).toHaveBeenCalledTimes(totalBlocks); + for (let i = 0; i < totalBlocks; i++) { + expect(merkleTreeDb.appendLeaves.mock.calls[i][0]).toEqual(MerkleTreeId.CONTRACT_TREE); + expect(merkleTreeDb.appendLeaves.mock.calls[i][1]).toEqual([Buffer.alloc(32, i)]); + } + await server.stop(); + }); +}); diff --git a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.ts b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.ts new file mode 100644 index 000000000000..5179d239f58a --- /dev/null +++ b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.ts @@ -0,0 +1,137 @@ +import { WorldStateRunningState, WorldStateStatus, WorldStateSynchroniser } from './world_state_synchroniser.js'; +import { MerkleTreeDb, MerkleTreeId } from '@aztec/merkle-tree'; +import { L2BlockSource, L2BlockDownloader, L2Block } from '@aztec/archiver'; +import { createDebugLogger } from '@aztec/foundation'; + +/** + * Synchronises the world state with the L2 blocks from a L2BlockSource. + * The synchroniser will download the L2 blocks from the L2BlockSource and insert the new commitments into the merkle + * tree. + */ +export class ServerWorldStateSynchroniser implements WorldStateSynchroniser { + private currentL2BlockNum = -1; + private latestBlockNumberAtStart = -1; + private l2BlockDownloader: L2BlockDownloader; + private syncPromise: Promise = Promise.resolve(); + private syncResolve?: () => void = undefined; + private stopping = false; + private runningPromise: Promise = Promise.resolve(); + private currentState: WorldStateRunningState = WorldStateRunningState.IDLE; + + constructor( + private merkleTreeDb: MerkleTreeDb, + private l2BlockSource: L2BlockSource, + maxQueueSize = 1000, + pollIntervalMS = 10000, + private log = createDebugLogger('aztec:world_state'), + ) { + this.l2BlockDownloader = new L2BlockDownloader(l2BlockSource, maxQueueSize, pollIntervalMS); + } + + /** + * Starts the synchroniser. + * @param from - The block number to start downloading from. Defaults to 0. + * @returns A promise that resolves once the initial sync is completed. + */ + public async start(from = 0) { + if (this.currentState === WorldStateRunningState.STOPPED) { + throw new Error('Synchroniser already stopped'); + } + if (this.currentState !== WorldStateRunningState.IDLE) { + return this.syncPromise; + } + + // get the current latest block number + this.latestBlockNumberAtStart = await this.l2BlockSource.getLatestBlockNum(); + + // if there are blocks to be retrieved, go to a synching state + if (from < this.latestBlockNumberAtStart) { + this.setCurrentState(WorldStateRunningState.SYNCHING); + this.syncPromise = new Promise(resolve => { + this.syncResolve = resolve; + }); + this.log(`starting sync from ${from}, latest block ${this.latestBlockNumberAtStart}`); + } else { + // if no blocks to be retrieved, go straight to running + this.setCurrentState(WorldStateRunningState.RUNNING); + this.currentL2BlockNum = this.latestBlockNumberAtStart; + this.syncPromise = Promise.resolve(); + this.log(`already synched to latest block at ${this.latestBlockNumberAtStart}`); + } + + // start looking for further blocks + const blockProcess = async () => { + while (!this.stopping) { + const blocks = await this.l2BlockDownloader.getL2Blocks(); + await this.handleL2Blocks(blocks); + } + }; + this.runningPromise = blockProcess(); + this.l2BlockDownloader.start(from); + this.log(`started block downloader from block ${from}`); + return this.syncPromise; + } + + /** + * Stops the synchroniser. + */ + public async stop() { + this.log('stopping world state...'); + this.stopping = true; + await this.l2BlockDownloader.stop(); + await this.runningPromise; + this.setCurrentState(WorldStateRunningState.STOPPED); + } + + /** + * Returns the current status of the synchroniser. + * @returns The current status of the synchroniser. + */ + public status(): Promise { + const status = { + syncedToL2Block: this.currentL2BlockNum, + state: this.currentState, + } as WorldStateStatus; + return Promise.resolve(status); + } + + /** + * Handles a list of L2 blocks (i.e. Inserts the new commitments into the merkle tree). + * @param l2blocks - The L2 blocks to handle. + */ + private async handleL2Blocks(l2blocks: L2Block[]) { + for (const l2block of l2blocks) { + await this.handleL2Block(l2block); + } + } + + /** + * Handles a single L2 block (i.e. Inserts the new commitments into the merkle tree). + * @param l2block - The L2 block to handle. + */ + private async handleL2Block(l2block: L2Block) { + this.log(`committing block ${l2block.number}`); + await this.merkleTreeDb.appendLeaves(MerkleTreeId.CONTRACT_TREE, l2block.newContracts); + await this.merkleTreeDb.commit(); + this.log(`committed block ${l2block.number} to world state`); + this.currentL2BlockNum = l2block.number; + if ( + this.currentState === WorldStateRunningState.SYNCHING && + this.currentL2BlockNum >= this.latestBlockNumberAtStart + ) { + this.setCurrentState(WorldStateRunningState.RUNNING); + if (this.syncResolve !== undefined) { + this.syncResolve(); + } + } + } + + /** + * Method to set the value of the current state. + * @param newState - New state value. + */ + private setCurrentState(newState: WorldStateRunningState) { + this.currentState = newState; + this.log(`moved to state ${WorldStateRunningState[this.currentState]}`); + } +} diff --git a/yarn-project/world-state/src/synchroniser/world_state_synchroniser.ts b/yarn-project/world-state/src/synchroniser/world_state_synchroniser.ts new file mode 100644 index 000000000000..08b8c8079c19 --- /dev/null +++ b/yarn-project/world-state/src/synchroniser/world_state_synchroniser.ts @@ -0,0 +1,32 @@ +/** + * Defines the possible states of the world state synchroniser. + */ +export enum WorldStateRunningState { + IDLE, + SYNCHING, + RUNNING, + STOPPED, +} + +/** + * Defines the status of the world state synchroniser. + */ +export interface WorldStateStatus { + /** + * The current state of the world state synchroniser. + */ + state: WorldStateRunningState; + /** + * The block number that the world state synchroniser is synced to. + */ + syncedToL2Block: number; +} + +/** + * Defines the interface for a world state synchroniser. + */ +export interface WorldStateSynchroniser { + start(): void; + status(): Promise; + stop(): Promise; +} diff --git a/yarn-project/world-state/src/world-state-db/index.ts b/yarn-project/world-state/src/world-state-db/index.ts new file mode 100644 index 000000000000..bf39aac9eddc --- /dev/null +++ b/yarn-project/world-state/src/world-state-db/index.ts @@ -0,0 +1,39 @@ +export * from './memory_world_state_db.js'; +/** + * Defines the possible tree IDs. + */ +export enum WorldStateTreeId { + CONTRACT_TREE = 0, +} + +/** + * Defines tree information. + */ +export interface TreeInfo { + /** + * The tree ID. + */ + treeId: WorldStateTreeId; + /** + * The tree root. + */ + root: Buffer; + /** + * The number of leaves in the tree. + */ + size: number; +} + +/** + * Defines a batch update. + */ +export interface BatchUpdate { + /** + * The ID of a tree to be updated. + */ + treeId: WorldStateTreeId; + /** + * The leaves to be updated. + */ + elements: Buffer[]; +} diff --git a/yarn-project/world-state/src/world-state-db/memory_world_state_db.ts b/yarn-project/world-state/src/world-state-db/memory_world_state_db.ts new file mode 100644 index 000000000000..c2aa0fa6aeaa --- /dev/null +++ b/yarn-project/world-state/src/world-state-db/memory_world_state_db.ts @@ -0,0 +1,176 @@ +import { default as levelup } from 'levelup'; +import { + StandardMerkleTree, + Pedersen, + SiblingPath, + MerkleTreeDb, + MerkleTreeId, + TreeInfo, + IndexedTree, + MerkleTreeDepths, + MerkleTree, +} from '@aztec/merkle-tree'; +import { SerialQueue } from '@aztec/foundation'; + +/** + * A convenience class for managing multiple merkle trees. + */ +export class MerkleTrees implements MerkleTreeDb { + private trees: MerkleTree[] = []; + private jobQueue = new SerialQueue(); + + constructor(private db: levelup.LevelUp) {} + + /** + * Initialises the collection of Merkle Trees. + */ + public async init() { + const hasher = new Pedersen(); + const contractTree = await StandardMerkleTree.new( + this.db, + hasher, + `${MerkleTreeId[MerkleTreeId.CONTRACT_TREE]}`, + MerkleTreeDepths.CONTRACT_TREE, + ); + const contractTreeRootsTree = await StandardMerkleTree.new( + this.db, + hasher, + `${MerkleTreeId[MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]}`, + MerkleTreeDepths.CONTRACT_TREE_ROOTS_TREE, + ); + const nullifierTree = await IndexedTree.new( + this.db, + hasher, + `${MerkleTreeId[MerkleTreeId.NULLIFIER_TREE]}`, + MerkleTreeDepths.NULLIFIER_TREE, + ); + this.trees = [contractTree, contractTreeRootsTree, nullifierTree]; + this.jobQueue.start(); + } + + /** + * Method to asynchronously create and initialise a MerkleTrees instance. + * @param db - The db instance to use for data persistance. + * @returns - A fully initialised MerkleTrees instance. + */ + public static async new(db: levelup.LevelUp) { + const merkleTrees = new MerkleTrees(db); + await merkleTrees.init(); + return merkleTrees; + } + + /** + * Stops the job queue (waits for all jobs to finish). + */ + public async stop() { + await this.jobQueue.end(); + } + + /** + * Gets the tree info for the specified tree. + * @param treeId - Id of the tree to get information from. + * @returns The tree info for the specified tree. + */ + public async getTreeInfo(treeId: MerkleTreeId): Promise { + return await this.synchronise(() => this._getTreeInfo(treeId)); + } + + /** + * Gets the sibling path for a leaf in a tree. + * @param treeId - The ID of the tree. + * @param index - The index of the leaf. + * @returns The sibling path for the leaf. + */ + public async getSiblingPath(treeId: MerkleTreeId, index: bigint): Promise { + return await this.synchronise(() => this._getSiblingPath(treeId, index)); + } + + /** + * Appends leaves to a tree. + * @param treeId - The ID of the tree. + * @param leaves - The leaves to append. + * @returns Empty promise. + */ + public async appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise { + return await this.synchronise(() => this._appendLeaves(treeId, leaves)); + } + + /** + * Commits all pending updates. + * @returns Empty promise. + */ + public async commit(): Promise { + return await this.synchronise(() => this._commit()); + } + + /** + * Rolls back all pending updates. + * @returns Empty promise. + */ + public async rollback(): Promise { + return await this.synchronise(() => this._rollback()); + } + + /** + * Waits for all jobs to finish before executing the given function. + * @param fn - The function to execute. + * @returns Promise containing the result of the function. + */ + private async synchronise(fn: () => Promise): Promise { + return await this.jobQueue.put(fn); + } + + /** + * Returns the tree info for the specified tree. + * @param treeId - Id of the tree to get information from. + * @returns The tree info for the specified tree. + */ + private _getTreeInfo(treeId: MerkleTreeId): Promise { + const treeInfo = { + treeId, + root: this.trees[treeId].getRoot(), + size: this.trees[treeId].getNumLeaves(), + } as TreeInfo; + return Promise.resolve(treeInfo); + } + + /** + * Returns the sibling path for a leaf in a tree. + * @param treeId - Id of the tree to get the sibling path from. + * @param index - Index of the leaf to get the sibling path for. + * @returns Promise containing the sibling path for the leaf. + */ + private _getSiblingPath(treeId: MerkleTreeId, index: bigint): Promise { + return Promise.resolve(this.trees[treeId].getSiblingPath(index)); + } + + /** + * Appends leaves to a tree. + * @param treeId - Id of the tree to append leaves to. + * @param leaves - Leaves to append. + * @returns Empty promise. + */ + private async _appendLeaves(treeId: MerkleTreeId, leaves: Buffer[]): Promise { + return await this.trees[treeId].appendLeaves(leaves); + } + + /** + * Commits all pending updates. + * @returns Empty promise. + */ + private async _commit(): Promise { + for (const tree of this.trees) { + await tree.commit(); + } + } + + /** + * Rolls back all pending updates. + * @returns Empty promise. + */ + private async _rollback(): Promise { + for (const tree of this.trees) { + await tree.rollback(); + } + } +} diff --git a/yarn-project/world-state/tsconfig.dest.json b/yarn-project/world-state/tsconfig.dest.json new file mode 100644 index 000000000000..93f9b9ecffc2 --- /dev/null +++ b/yarn-project/world-state/tsconfig.dest.json @@ -0,0 +1,15 @@ +{ + "extends": ".", + "references": [ + { + "path": "../archiver/tsconfig.dest.json" + }, + { + "path": "../merkle-tree/tsconfig.dest.json" + }, + { + "path": "../foundation/tsconfig.dest.json" + } + ], + "exclude": ["**/*.test.*", "**/fixtures/*"] +} diff --git a/yarn-project/world-state/tsconfig.json b/yarn-project/world-state/tsconfig.json new file mode 100644 index 000000000000..a3bf0b269ada --- /dev/null +++ b/yarn-project/world-state/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "references": [ + { + "path": "../archiver/tsconfig.dest.json" + }, + { + "path": "../merkle-tree/tsconfig.dest.json" + }, + { + "path": "../foundation/tsconfig.dest.json" + } + ], + "include": [ + "src" + ] +} diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index baab92c1206c..83e87ef2e5cc 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -10,6 +10,7 @@ RUN apk update && apk add --no-cache build-base git python3 curl bash jq # COPY --from=1 /usr/src/circuits/build/bin /usr/src/circuits/build-wasm/bin # COPY --from=2 /usr/src/l1-contracts /usr/src/l1-contracts WORKDIR /usr/src/yarn-project + # We only want to copy the package.json's, to ensure we only rebuild this image if project dependencies changed. COPY acir-simulator/package.json acir-simulator/package.json COPY archiver/package.json archiver/package.json @@ -20,22 +21,26 @@ COPY docs/package.json docs/package.json COPY end-to-end/package.json end-to-end/package.json COPY ethereum.js/example/package.json ethereum.js/example/package.json COPY ethereum.js/package.json ethereum.js/package.json +# Note: foundation has its own lock file, we need to copy it and build +COPY foundation/package.json foundation/package.json +COPY foundation/yarn.lock foundation/yarn.lock COPY kernel-simulator/package.json kernel-simulator/package.json COPY key-store/package.json key-store/package.json +COPY merkle-tree/package.json merkle-tree/package.json COPY noir-contracts/package.json noir-contracts/package.json +COPY l1-contracts/package.json l1-contracts/package.json COPY p2p/package.json p2p/package.json COPY prover-client/package.json prover-client/package.json -COPY public-client/package.json public-client/package.json +COPY aztec-node/package.json aztec-node/package.json COPY sequencer-client/package.json sequencer-client/package.json -# All workspaces use the linting config, so always include it. -COPY eslint-config eslint-config -COPY prettier-config prettier-config -COPY package.json tsconfig.json yarn.lock ./ +COPY world-state/package.json world-state/package.json +COPY package.json tsconfig.json yarn.lock .yarnrc.yml ./ COPY .yarn .yarn -# Use PNP in CI context -COPY .yarnrc.prod.yml .yarnrc.yml + # Although we're attempting to be "zero-install", in practice we still need to build arch specific packages. RUN yarn --immutable +# Build submodule packages that have their own yarn.lock. +RUN cd foundation && yarn --immutable && cd .. # If everything's worked properly, we should no longer need access to the network. RUN echo "enableNetwork: false" >> .yarnrc.yml diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 21e074bb4807..14fee48b7919 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -19,7 +19,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/acir-simulator@workspace:acir-simulator" dependencies: - "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@noir-lang/noir-source-resolver": ^1.1.0 "@noir-lang/noir_wasm": 0.3.2-29b1f7df @@ -35,11 +34,12 @@ __metadata: languageName: unknown linkType: soft -"@aztec/archiver@workspace:archiver": +"@aztec/archiver@workspace:^, @aztec/archiver@workspace:archiver": version: 0.0.0-use.local resolution: "@aztec/archiver@workspace:archiver" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/ethereum.js": "workspace:^" + "@aztec/foundation": "workspace:^" "@jest/globals": ^29.5.0 "@rushstack/eslint-patch": ^1.2.0 "@types/debug": ^4.1.7 @@ -62,7 +62,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/aztec-cli@workspace:aztec-cli" dependencies: - "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -78,16 +77,37 @@ __metadata: languageName: unknown linkType: soft +"@aztec/aztec-node@workspace:^, @aztec/aztec-node@workspace:aztec-node": + version: 0.0.0-use.local + resolution: "@aztec/aztec-node@workspace:aztec-node" + dependencies: + "@aztec/archiver": "workspace:^" + "@aztec/ethereum.js": "workspace:^" + "@aztec/p2p": "workspace:^" + "@aztec/world-state": "workspace:^" + "@jest/globals": ^29.4.3 + "@rushstack/eslint-patch": ^1.1.4 + "@types/jest": ^29.4.0 + "@types/node": ^18.7.23 + jest: ^28.1.3 + ts-jest: ^28.0.7 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^4.9.5 + languageName: unknown + linkType: soft + "@aztec/aztec-rpc@workspace:^, @aztec/aztec-rpc@workspace:aztec-rpc": version: 0.0.0-use.local resolution: "@aztec/aztec-rpc@workspace:aztec-rpc" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/aztec-node": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 "@types/node": ^18.7.23 jest: ^28.1.3 + sha3: ^2.1.4 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -100,14 +120,13 @@ __metadata: resolution: "@aztec/aztec.js@workspace:aztec.js" dependencies: "@aztec/aztec-rpc": "workspace:^" - "@aztec/eslint-config": "workspace:^" + "@aztec/foundation": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 "@types/node": ^18.7.23 jest: ^28.1.3 jest-mock-extended: ^3.0.3 - sha3: ^2.1.4 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -139,7 +158,8 @@ __metadata: resolution: "@aztec/end-to-end@workspace:end-to-end" dependencies: "@aztec/aztec.js": "workspace:^" - "@aztec/eslint-config": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/noir-contracts": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -152,25 +172,12 @@ __metadata: languageName: unknown linkType: soft -"@aztec/eslint-config@workspace:^, @aztec/eslint-config@workspace:eslint-config": - version: 0.0.0-use.local - resolution: "@aztec/eslint-config@workspace:eslint-config" - dependencies: - "@typescript-eslint/eslint-plugin": ^5.38.0 - "@typescript-eslint/parser": ^5.38.0 - eslint: ^8.21.0 - eslint-config-prettier: ^8.5.0 - eslint-plugin-jsdoc: ^40.0.0 - eslint-plugin-tsdoc: ^0.2.17 - languageName: unknown - linkType: soft - "@aztec/ethereum.js-example@workspace:ethereum.js/example": version: 0.0.0-use.local resolution: "@aztec/ethereum.js-example@workspace:ethereum.js/example" dependencies: - "@aztec/eslint-config": "workspace:^" "@aztec/ethereum.js": "workspace:^" + "@aztec/foundation": "workspace:^" "@rushstack/eslint-patch": ^1.2.0 "@types/node": ^18.15.0 source-map-support: ^0.5.21 @@ -182,7 +189,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/ethereum.js@workspace:ethereum.js" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/foundation": "workspace:^" "@jest/globals": ^29.5.0 "@rushstack/eslint-patch": ^1.2.0 "@types/elliptic": ^6.4.14 @@ -210,12 +217,36 @@ __metadata: languageName: unknown linkType: soft +"@aztec/foundation@workspace:^, @aztec/foundation@workspace:foundation": + version: 0.0.0-use.local + resolution: "@aztec/foundation@workspace:foundation" + dependencies: + "@jest/globals": ^29.4.3 + "@rushstack/eslint-patch": ^1.1.4 + "@types/debug": ^4.1.7 + "@types/detect-node": ^2.0.0 + "@types/jest": ^29.4.0 + "@types/node": ^18.7.23 + "@typescript-eslint/eslint-plugin": ^5.38.0 + "@typescript-eslint/parser": ^5.38.0 + cross-fetch: ^3.1.5 + debug: ^4.3.4 + detect-node: ^2.1.0 + eslint: ^8.21.0 + eslint-config-prettier: ^8.5.0 + jest: ^28.1.3 + prettier: ^2.7.1 + ts-jest: ^28.0.7 + ts-node: ^10.9.1 + typescript: ^4.9.5 + languageName: unknown + linkType: soft + "@aztec/kernel-simulator@workspace:kernel-simulator": version: 0.0.0-use.local resolution: "@aztec/kernel-simulator@workspace:kernel-simulator" dependencies: "@aztec/acir-simulator": "workspace:^" - "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -232,7 +263,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/key-store@workspace:key-store" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/foundation": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -245,19 +276,16 @@ __metadata: languageName: unknown linkType: soft -"@aztec/noir-contracts@workspace:noir-contracts": +"@aztec/l1-contracts@workspace:^, @aztec/l1-contracts@workspace:l1-contracts": version: 0.0.0-use.local - resolution: "@aztec/noir-contracts@workspace:noir-contracts" + resolution: "@aztec/l1-contracts@workspace:l1-contracts" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/ethereum.js": "workspace:^" "@jest/globals": ^29.4.3 - "@noir-lang/noir-source-resolver": ^1.1.0 - "@noir-lang/noir_wasm": 0.3.2-29b1f7df "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 "@types/node": ^18.7.23 jest: ^28.1.3 - toml: ^3.0.0 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -265,16 +293,42 @@ __metadata: languageName: unknown linkType: soft -"@aztec/p2p@workspace:p2p": +"@aztec/merkle-tree@workspace:^, @aztec/merkle-tree@workspace:merkle-tree": version: 0.0.0-use.local - resolution: "@aztec/p2p@workspace:p2p" + resolution: "@aztec/merkle-tree@workspace:merkle-tree" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/foundation": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 + "@types/levelup": ^5.1.2 + "@types/memdown": ^3.0.1 + "@types/node": ^18.15.3 + "@types/sha256": ^0.2.0 + jest: ^28.1.3 + levelup: ^5.1.1 + memdown: ^6.1.1 + sha256: ^0.2.0 + ts-jest: ^28.0.7 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^4.9.5 + languageName: unknown + linkType: soft + +"@aztec/noir-contracts@workspace:^, @aztec/noir-contracts@workspace:noir-contracts": + version: 0.0.0-use.local + resolution: "@aztec/noir-contracts@workspace:noir-contracts" + dependencies: + "@aztec/foundation": "workspace:^" + "@jest/globals": ^29.4.3 + "@noir-lang/noir-source-resolver": ^1.1.0 + "@noir-lang/noir_wasm": 0.3.2-29b1f7df + "@rushstack/eslint-patch": ^1.1.4 + "@types/jest": ^29.4.0 "@types/node": ^18.7.23 jest: ^28.1.3 + toml: ^3.0.0 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -282,11 +336,22 @@ __metadata: languageName: unknown linkType: soft -"@aztec/prettier-config@workspace:prettier-config": +"@aztec/p2p@workspace:^, @aztec/p2p@workspace:p2p": version: 0.0.0-use.local - resolution: "@aztec/prettier-config@workspace:prettier-config" + resolution: "@aztec/p2p@workspace:p2p" dependencies: - prettier: ^2.7.1 + "@aztec/archiver": "workspace:^" + "@aztec/foundation": "workspace:^" + "@jest/globals": ^29.4.3 + "@rushstack/eslint-patch": ^1.1.4 + "@types/jest": ^29.4.0 + "@types/node": ^18.14.6 + jest: ^28.1.3 + sha3: ^2.1.4 + ts-jest: ^28.0.7 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^4.9.5 languageName: unknown linkType: soft @@ -294,7 +359,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/prover-client@workspace:prover-client" dependencies: - "@aztec/eslint-config": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -307,16 +371,20 @@ __metadata: languageName: unknown linkType: soft -"@aztec/public-client@workspace:public-client": +"@aztec/sequencer-client@workspace:sequencer-client": version: 0.0.0-use.local - resolution: "@aztec/public-client@workspace:public-client" + resolution: "@aztec/sequencer-client@workspace:sequencer-client" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/archiver": "workspace:^" + "@aztec/ethereum.js": "workspace:^" + "@aztec/l1-contracts": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 "@types/node": ^18.7.23 + concurrently: ^7.6.0 jest: ^28.1.3 + jest-mock-extended: ^3.0.3 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -324,16 +392,22 @@ __metadata: languageName: unknown linkType: soft -"@aztec/sequencer-client@workspace:sequencer-client": +"@aztec/world-state@workspace:^, @aztec/world-state@workspace:world-state": version: 0.0.0-use.local - resolution: "@aztec/sequencer-client@workspace:sequencer-client" + resolution: "@aztec/world-state@workspace:world-state" dependencies: - "@aztec/eslint-config": "workspace:^" + "@aztec/archiver": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/merkle-tree": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 + "@types/levelup": ^5.1.2 + "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 jest: ^28.1.3 + levelup: ^5.1.1 + memdown: ^6.1.1 ts-jest: ^28.0.7 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -358,37 +432,37 @@ __metadata: linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3": - version: 7.21.0 - resolution: "@babel/core@npm:7.21.0" + version: 7.21.3 + resolution: "@babel/core@npm:7.21.3" dependencies: "@ampproject/remapping": ^2.2.0 "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.21.0 + "@babel/generator": ^7.21.3 "@babel/helper-compilation-targets": ^7.20.7 - "@babel/helper-module-transforms": ^7.21.0 + "@babel/helper-module-transforms": ^7.21.2 "@babel/helpers": ^7.21.0 - "@babel/parser": ^7.21.0 + "@babel/parser": ^7.21.3 "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.0 - "@babel/types": ^7.21.0 + "@babel/traverse": ^7.21.3 + "@babel/types": ^7.21.3 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.2 semver: ^6.3.0 - checksum: 357f4dd3638861ceebf6d95ff49ad8b902065ee8b7b352621deed5666c2a6d702a48ca7254dba23ecae2a0afb67d20f90db7dd645c3b75e35e72ad9776c671aa + checksum: bef25fbea96f461bf79bd1d0e4f0cdce679fd5ada464a89c1141ddba59ae1adfdbb23e04440c266ed525712d33d5ffd818cd8b0c25b1dee0e648d5559516153a languageName: node linkType: hard -"@babel/generator@npm:^7.21.0, @babel/generator@npm:^7.21.1, @babel/generator@npm:^7.7.2": - version: 7.21.1 - resolution: "@babel/generator@npm:7.21.1" +"@babel/generator@npm:^7.21.3, @babel/generator@npm:^7.7.2": + version: 7.21.3 + resolution: "@babel/generator@npm:7.21.3" dependencies: - "@babel/types": ^7.21.0 + "@babel/types": ^7.21.3 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 69085a211ff91a7a608ee3f86e6fcb9cf5e724b756d792a713b0c328a671cd3e423e1ef1b12533f366baba0616caffe0a7ba9d328727eab484de5961badbef00 + checksum: be6bb5a32a0273260b91210d4137b7b5da148a2db8dd324654275cb0af865ae59de5e1536e93ac83423b2586415059e1c24cf94293026755cf995757238da749 languageName: node linkType: hard @@ -442,7 +516,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.21.0": +"@babel/helper-module-transforms@npm:^7.21.2": version: 7.21.2 resolution: "@babel/helper-module-transforms@npm:7.21.2" dependencies: @@ -526,12 +600,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.0, @babel/parser@npm:^7.21.2": - version: 7.21.2 - resolution: "@babel/parser@npm:7.21.2" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.3": + version: 7.21.3 + resolution: "@babel/parser@npm:7.21.3" bin: parser: ./bin/babel-parser.js - checksum: e2b89de2c63d4cdd2cafeaea34f389bba729727eec7a8728f736bc472a59396059e3e9fe322c9bed8fd126d201fb609712949dc8783f4cae4806acd9a73da6ff + checksum: a71e6456a1260c2a943736b56cc0acdf5f2a53c6c79e545f56618967e51f9b710d1d3359264e7c979313a7153741b1d95ad8860834cc2ab4ce4f428b13cc07be languageName: node linkType: hard @@ -700,32 +774,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.21.0, @babel/traverse@npm:^7.21.2, @babel/traverse@npm:^7.7.2": - version: 7.21.2 - resolution: "@babel/traverse@npm:7.21.2" +"@babel/traverse@npm:^7.21.0, @babel/traverse@npm:^7.21.2, @babel/traverse@npm:^7.21.3, @babel/traverse@npm:^7.7.2": + version: 7.21.3 + resolution: "@babel/traverse@npm:7.21.3" dependencies: "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.21.1 + "@babel/generator": ^7.21.3 "@babel/helper-environment-visitor": ^7.18.9 "@babel/helper-function-name": ^7.21.0 "@babel/helper-hoist-variables": ^7.18.6 "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.21.2 - "@babel/types": ^7.21.2 + "@babel/parser": ^7.21.3 + "@babel/types": ^7.21.3 debug: ^4.1.0 globals: ^11.1.0 - checksum: d851e3f5cfbdc2fac037a014eae7b0707709de50f7d2fbb82ffbf932d3eeba90a77431529371d6e544f8faaf8c6540eeb18fdd8d1c6fa2b61acea0fb47e18d4b + checksum: 0af5bcd47a2fc501592b90ac1feae9d449afb9ab0772a4f6e68230f4cd3a475795d538c1de3f880fe3414b6c2820bac84d02c6549eea796f39d74a603717447b languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.2, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": - version: 7.21.2 - resolution: "@babel/types@npm:7.21.2" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.2, @babel/types@npm:^7.21.3, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.21.3 + resolution: "@babel/types@npm:7.21.3" dependencies: "@babel/helper-string-parser": ^7.19.4 "@babel/helper-validator-identifier": ^7.19.1 to-fast-properties: ^2.0.0 - checksum: a45a52acde139e575502c6de42c994bdbe262bafcb92ae9381fb54cdf1a3672149086843fda655c7683ce9806e998fd002bbe878fa44984498d0fdc7935ce7ff + checksum: b750274718ba9cefd0b81836c464009bb6ba339fccce51b9baff497a0a2d96c044c61dc90cf203cec0adc770454b53a9681c3f7716883c802b85ab84c365ba35 languageName: node linkType: hard @@ -745,192 +819,199 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.36.1": - version: 0.36.1 - resolution: "@es-joy/jsdoccomment@npm:0.36.1" - dependencies: - comment-parser: 1.3.1 - esquery: ^1.4.0 - jsdoc-type-pratt-parser: ~3.1.0 - checksum: 28e697779230dc6a95b1f233a8c2a72b64fbea686e407106e5d4292083421a997452731c414de26c10bee86e8e0397c5fb84d6ecfd4b472a29735e1af103ddb6 - languageName: node - linkType: hard - -"@esbuild/android-arm64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/android-arm64@npm:0.16.17" +"@esbuild/android-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-arm64@npm:0.17.12" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/android-arm@npm:0.16.17" +"@esbuild/android-arm@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-arm@npm:0.17.12" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/android-x64@npm:0.16.17" +"@esbuild/android-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/android-x64@npm:0.17.12" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/darwin-arm64@npm:0.16.17" +"@esbuild/darwin-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/darwin-arm64@npm:0.17.12" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/darwin-x64@npm:0.16.17" +"@esbuild/darwin-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/darwin-x64@npm:0.17.12" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/freebsd-arm64@npm:0.16.17" +"@esbuild/freebsd-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/freebsd-arm64@npm:0.17.12" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/freebsd-x64@npm:0.16.17" +"@esbuild/freebsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/freebsd-x64@npm:0.17.12" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-arm64@npm:0.16.17" +"@esbuild/linux-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-arm64@npm:0.17.12" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-arm@npm:0.16.17" +"@esbuild/linux-arm@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-arm@npm:0.17.12" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-ia32@npm:0.16.17" +"@esbuild/linux-ia32@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-ia32@npm:0.17.12" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-loong64@npm:0.16.17" +"@esbuild/linux-loong64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-loong64@npm:0.17.12" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-mips64el@npm:0.16.17" +"@esbuild/linux-mips64el@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-mips64el@npm:0.17.12" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-ppc64@npm:0.16.17" +"@esbuild/linux-ppc64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-ppc64@npm:0.17.12" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-riscv64@npm:0.16.17" +"@esbuild/linux-riscv64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-riscv64@npm:0.17.12" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-s390x@npm:0.16.17" +"@esbuild/linux-s390x@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-s390x@npm:0.17.12" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/linux-x64@npm:0.16.17" +"@esbuild/linux-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/linux-x64@npm:0.17.12" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/netbsd-x64@npm:0.16.17" +"@esbuild/netbsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/netbsd-x64@npm:0.17.12" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/openbsd-x64@npm:0.16.17" +"@esbuild/openbsd-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/openbsd-x64@npm:0.17.12" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/sunos-x64@npm:0.16.17" +"@esbuild/sunos-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/sunos-x64@npm:0.17.12" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/win32-arm64@npm:0.16.17" +"@esbuild/win32-arm64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-arm64@npm:0.17.12" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/win32-ia32@npm:0.16.17" +"@esbuild/win32-ia32@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-ia32@npm:0.17.12" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.16.17": - version: 0.16.17 - resolution: "@esbuild/win32-x64@npm:0.16.17" +"@esbuild/win32-x64@npm:0.17.12": + version: 0.17.12 + resolution: "@esbuild/win32-x64@npm:0.17.12" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.0.0": - version: 2.0.0 - resolution: "@eslint/eslintrc@npm:2.0.0" +"@eslint-community/eslint-utils@npm:^4.2.0": + version: 4.3.0 + resolution: "@eslint-community/eslint-utils@npm:4.3.0" + dependencies: + eslint-visitor-keys: ^3.3.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: f487760a692f0f1fef76e248ad72976919576ba57edc2b1b1dc1d182553bae6b5bf7b078e654da85d04f0af8a485d20bd26280002768f4fbcd2e330078340cb0 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.4.0": + version: 4.4.1 + resolution: "@eslint-community/regexpp@npm:4.4.1" + checksum: db97d8d08e784147b55ab0dda5892503c1a0eebad94d1c4646d89a94f02ca70b25f05d8e021fc05a075e7eb312e03e21f63d84f0b327719f8cf3bb64e66917cb + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.0.1": + version: 2.0.1 + resolution: "@eslint/eslintrc@npm:2.0.1" dependencies: ajv: ^6.12.4 debug: ^4.3.2 - espree: ^9.4.0 + espree: ^9.5.0 globals: ^13.19.0 ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: 31119c8ca06723d80384f18f5c78e0530d8e6306ad36379868650131a8b10dd7cffd7aff79a5deb3a2e9933660823052623d268532bae9538ded53d5b19a69a6 + checksum: 56b9192a687a450db53a7b883daf9f0f447c43b3510189cf88808a7a2467c2a302a42a50f184cc6d5a9faf3d1df890a2ef0fd0d60b751f32a3e9dfea717c6b48 languageName: node linkType: hard -"@eslint/js@npm:8.35.0": - version: 8.35.0 - resolution: "@eslint/js@npm:8.35.0" - checksum: 6687ceff659a6d617e37823f809dc9c4b096535961a81acead27d26b1a51a4cf608a5e59d831ddd57f24f6f8bb99340a4a0e19f9c99b390fbb4b275f51ed5f5e +"@eslint/js@npm:8.36.0": + version: 8.36.0 + resolution: "@eslint/js@npm:8.36.0" + checksum: b7d6b84b823c8c7784be390741196617565527b1f7c0977fde9455bfb57fd88f81c074a03dd878757d2c33fa29f24291e9ecbc1425710f067917324b55e1bf3a languageName: node linkType: hard @@ -1509,29 +1590,17 @@ __metadata: languageName: node linkType: hard -"@microsoft/tsdoc-config@npm:0.16.2": - version: 0.16.2 - resolution: "@microsoft/tsdoc-config@npm:0.16.2" - dependencies: - "@microsoft/tsdoc": 0.14.2 - ajv: ~6.12.6 - jju: ~1.4.0 - resolve: ~1.19.0 - checksum: 12b0d703154076bcaac75ca42e804e4fc292672396441e54346d7eadd0d6b57f90980eda2b1bab89b224af86da34a2389f9054002e282011e795ca5919a4386f - languageName: node - linkType: hard - -"@microsoft/tsdoc@npm:0.14.2": - version: 0.14.2 - resolution: "@microsoft/tsdoc@npm:0.14.2" - checksum: b167c89e916ba73ee20b9c9d5dba6aa3a0de25ed3d50050e8a344dca7cd43cb2e1059bd515c820369b6e708901dd3fda476a42bc643ca74a35671ce77f724a3a +"@noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0": + version: 1.3.0 + resolution: "@noble/hashes@npm:1.3.0" + checksum: d7ddb6d7c60f1ce1f87facbbef5b724cdea536fc9e7f59ae96e0fc9de96c8f1a2ae2bdedbce10f7dcc621338dfef8533daa73c873f2b5c87fa1a4e05a95c2e2e languageName: node linkType: hard -"@noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0": - version: 1.2.0 - resolution: "@noble/hashes@npm:1.2.0" - checksum: 8ca080ce557b8f40fb2f78d3aedffd95825a415ac8e13d7ffe3643f8626a8c2d99a3e5975b555027ac24316d8b3c02a35b8358567c0c23af681e6573602aa434 +"@noble/secp256k1@npm:^1.7.1": + version: 1.7.1 + resolution: "@noble/secp256k1@npm:1.7.1" + checksum: d2301f1f7690368d8409a3152450458f27e54df47e3f917292de3de82c298770890c2de7c967d237eff9c95b70af485389a9695f73eb05a43e2bd562d18b18cb languageName: node linkType: hard @@ -1563,9 +1632,9 @@ __metadata: linkType: hard "@noir-lang/noir-source-resolver@npm:^1.1.0": - version: 1.1.0 - resolution: "@noir-lang/noir-source-resolver@npm:1.1.0" - checksum: c3077f6740e613fd7866715ba01053f9711cff47c1196a780ff7b2683a5e500d08791ac304515ccbe906d32cdabf658df6fc825c775bb7d181abbf16e87cee92 + version: 1.1.1 + resolution: "@noir-lang/noir-source-resolver@npm:1.1.1" + checksum: 43acc4c1a720ad0837db68bfac59efe58fe2b7467a8508807857aa738e3095d088547692efba5655f3e89e6c4747307c769e582d6ef5b4d454c7787090601a82 languageName: node linkType: hard @@ -1690,6 +1759,13 @@ __metadata: languageName: node linkType: hard +"@types/abstract-leveldown@npm:*": + version: 7.2.1 + resolution: "@types/abstract-leveldown@npm:7.2.1" + checksum: 20689e7d144ce26d2384e2e151eed59046c95d573a6988da5e77e3076808eb4f435f474a0387af9ac786bfbfc7089e277dcfd9572ae902553d5c018e9b527a30 + languageName: node + linkType: hard + "@types/babel__core@npm:^7.1.14": version: 7.20.0 resolution: "@types/babel__core@npm:7.20.0" @@ -1749,6 +1825,13 @@ __metadata: languageName: node linkType: hard +"@types/detect-node@npm:^2.0.0": + version: 2.0.0 + resolution: "@types/detect-node@npm:2.0.0" + checksum: f0f5c8ec948f5d4a40944773c8f81460ca7fa08fddf53330166feff1f8e28719bba9a01984872c5823c5de00c8223984381640a41b3c541bc57f3b2d529a0024 + languageName: node + linkType: hard + "@types/elliptic@npm:^6.4.14": version: 6.4.14 resolution: "@types/elliptic@npm:6.4.14" @@ -1801,23 +1884,13 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^29.4.0": - version: 29.4.0 - resolution: "@types/jest@npm:29.4.0" - dependencies: - expect: ^29.0.0 - pretty-format: ^29.0.0 - checksum: 23760282362a252e6690314584d83a47512d4cd61663e957ed3398ecf98195fe931c45606ee2f9def12f8ed7d8aa102d492ec42d26facdaf8b78094a31e6568e - languageName: node - linkType: hard - -"@types/jest@npm:^29.4.1": - version: 29.4.1 - resolution: "@types/jest@npm:29.4.1" +"@types/jest@npm:^29.4.0, @types/jest@npm:^29.4.1": + version: 29.5.0 + resolution: "@types/jest@npm:29.5.0" dependencies: expect: ^29.0.0 pretty-format: ^29.0.0 - checksum: 75cdd1804615b663b88844eef61cb7c8104d65baf718190a1cd88ce199412dbe2ee136df3698604cc258a9a62ba7cbd7bd7712a17d8cb748909263ef56d6aac3 + checksum: cd877e5c56d299cceb8bfdcbb1a77723c706750dd3c3bc47403bc3599b8faff590a3b009c68bb5b11bf7a8c77d1fb01de5e124329b4a08e65f1cdda28b0ecdb8 languageName: node linkType: hard @@ -1828,6 +1901,33 @@ __metadata: languageName: node linkType: hard +"@types/level-errors@npm:*": + version: 3.0.0 + resolution: "@types/level-errors@npm:3.0.0" + checksum: ad9392663439306677ac9cb704f8fa0b64c300dfea4f3494369eb78a2e09c194156cbab2b52c71a361a09b735d54a2de65195dcadba0ec7db1d14a320198133e + languageName: node + linkType: hard + +"@types/levelup@npm:^5.1.2": + version: 5.1.2 + resolution: "@types/levelup@npm:5.1.2" + dependencies: + "@types/abstract-leveldown": "*" + "@types/level-errors": "*" + "@types/node": "*" + checksum: 6740284488b6806ba398bc38842fa789edd5667a342830c544a6b3611ebeed957a08d03dc8bde1e32fe03ac9c439341647c044c1ff0f73a26bcded9ca302a009 + languageName: node + linkType: hard + +"@types/memdown@npm:^3.0.0, @types/memdown@npm:^3.0.1": + version: 3.0.1 + resolution: "@types/memdown@npm:3.0.1" + dependencies: + "@types/abstract-leveldown": "*" + checksum: 08085fff44f1868d352ec3be81890cfd0034ad1086f3dbc8bbfc412d55434bb6f5bbd512a22a92f2f9c416ccb0784815ecaa0a6fada4478c9a39db3f0f7a1a43 + languageName: node + linkType: hard + "@types/ms@npm:*": version: 0.7.31 resolution: "@types/ms@npm:0.7.31" @@ -1835,17 +1935,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^18.7.23": - version: 18.14.6 - resolution: "@types/node@npm:18.14.6" - checksum: 2f88f482cabadc6dbddd627a1674239e68c3c9beab56eb4ae2309fb96fd17fc3a509d99b0309bafe13b58529574f49ecf3a583f2ebe2896dd32fe4be436dc96e - languageName: node - linkType: hard - -"@types/node@npm:^18.14.6, @types/node@npm:^18.15.0, @types/node@npm:^18.15.2": - version: 18.15.2 - resolution: "@types/node@npm:18.15.2" - checksum: 6db83062d295f9da63e7b24477f734b497170a577b21e0c13637d6f355d53713f875536e52ff02938221330d919700b5ed787dc493e32624a3ecb6c86105cfc8 +"@types/node@npm:*, @types/node@npm:^18.14.6, @types/node@npm:^18.15.0, @types/node@npm:^18.15.2, @types/node@npm:^18.15.3, @types/node@npm:^18.7.23": + version: 18.15.5 + resolution: "@types/node@npm:18.15.5" + checksum: 5fbf3453bd5ce1402bb2964e55d928fc8a8a7de5451b1b0fe66587fecb8a3eb86854ca9cefa5076a5971e2cff00e1773ceeb5d872a54f6c6ddfbbc1064b4e91a languageName: node linkType: hard @@ -1863,6 +1956,15 @@ __metadata: languageName: node linkType: hard +"@types/sha256@npm:^0.2.0": + version: 0.2.0 + resolution: "@types/sha256@npm:0.2.0" + dependencies: + "@types/node": "*" + checksum: f3c8e0dcaf11d833292b7dd19db567ef41b23036b2fb9ea7335cba100aac8c56e1346171fae6c63885f6c0e1048550506fd165628bc0001902fea010a16d3842 + languageName: node + linkType: hard + "@types/stack-utils@npm:^2.0.0": version: 2.0.1 resolution: "@types/stack-utils@npm:2.0.1" @@ -1894,26 +1996,26 @@ __metadata: linkType: hard "@types/yargs@npm:^17.0.8": - version: 17.0.22 - resolution: "@types/yargs@npm:17.0.22" + version: 17.0.23 + resolution: "@types/yargs@npm:17.0.23" dependencies: "@types/yargs-parser": "*" - checksum: 0773523fda71bafdc52f13f5970039e535a353665a60ba9261149a5c9c2b908242e6e77fbb7a8c06931ec78ce889d64d09673c68ba23eb5f5742d5385d0d1982 + checksum: c5f787d7a9a36ea94ba5d3f340fc5d93d2860eff8fa9731cd614ed23212e4fca75637e2386e37e376a720e4bf088ceed6f39050f1c3638fc1b75bce5c70b1ad4 languageName: node linkType: hard "@typescript-eslint/eslint-plugin@npm:^5.38.0": - version: 5.54.1 - resolution: "@typescript-eslint/eslint-plugin@npm:5.54.1" + version: 5.56.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.56.0" dependencies: - "@typescript-eslint/scope-manager": 5.54.1 - "@typescript-eslint/type-utils": 5.54.1 - "@typescript-eslint/utils": 5.54.1 + "@eslint-community/regexpp": ^4.4.0 + "@typescript-eslint/scope-manager": 5.56.0 + "@typescript-eslint/type-utils": 5.56.0 + "@typescript-eslint/utils": 5.56.0 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 natural-compare-lite: ^1.4.0 - regexpp: ^3.2.0 semver: ^7.3.7 tsutils: ^3.21.0 peerDependencies: @@ -1922,43 +2024,43 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 76476c08ca0142a9bf6e2381f5cd1c037d86fbafa9c0dded4a97bd3b23b5962dd2c3943bade11b21d674195674f0e36dbf80faa15a1906f5a2ca1f699baf1dd5 + checksum: 2eed4a4ed8279950ad553252e8623e947ffdee39b0d677a13f6e4e2d863ea1cbc5d683ff189e55d0de6fd5a25afd72d3c3a9ab7ae417d5405a21ead907e1b154 languageName: node linkType: hard "@typescript-eslint/parser@npm:^5.38.0": - version: 5.54.1 - resolution: "@typescript-eslint/parser@npm:5.54.1" + version: 5.56.0 + resolution: "@typescript-eslint/parser@npm:5.56.0" dependencies: - "@typescript-eslint/scope-manager": 5.54.1 - "@typescript-eslint/types": 5.54.1 - "@typescript-eslint/typescript-estree": 5.54.1 + "@typescript-eslint/scope-manager": 5.56.0 + "@typescript-eslint/types": 5.56.0 + "@typescript-eslint/typescript-estree": 5.56.0 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: f466513d306ca926b97c2cec1eebaf2cd15d45bd5633a4358f23ba9a4de1b0ec4630b1c20abc395943934ed1d2ef65f545fd6737c317a7abe579612101e8a83f + checksum: eb25490290bd5e22f9c42603dedc0d2d8ee845553e3cf48ea377bd5dc22440d3463f8b84be637b6a2b37cd9ea56b21e4e43007a0a69998948d9c8965c03fe1aa languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/scope-manager@npm:5.54.1" +"@typescript-eslint/scope-manager@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/scope-manager@npm:5.56.0" dependencies: - "@typescript-eslint/types": 5.54.1 - "@typescript-eslint/visitor-keys": 5.54.1 - checksum: 9add24cf3a7852634ad0680a827646860ac4698a6ac8aae31e8b781e29f59e84b51f0cdaacffd0747811012647f01b51969d988da9b302ead374ceebffbe204b + "@typescript-eslint/types": 5.56.0 + "@typescript-eslint/visitor-keys": 5.56.0 + checksum: bacac255ee52148cee6622be2811c0d7e25419058b89f1a11f4c1303faef4535a0a1237549f9556ec1d7a297c640ce4357183a1a8465d72e1393b7d8fb43874b languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/type-utils@npm:5.54.1" +"@typescript-eslint/type-utils@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/type-utils@npm:5.56.0" dependencies: - "@typescript-eslint/typescript-estree": 5.54.1 - "@typescript-eslint/utils": 5.54.1 + "@typescript-eslint/typescript-estree": 5.56.0 + "@typescript-eslint/utils": 5.56.0 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1966,23 +2068,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 0073838b782b7f4619775be124ca6643fec43a2d56043eaf3ceb100960a5193f14ac747b28ce17a5c9ac643fdee8abda82a7d905c81521358de7b27a2dcbc9af + checksum: 3dd1fcfadad18790b900a3d90f6617904adb6b0e2bd1e1edb6ebf239e1399865ca9098647405385feb4252d8b2b4577883e6fd3ef8d00bdd521d6070972d486b languageName: node linkType: hard -"@typescript-eslint/types@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/types@npm:5.54.1" - checksum: 84a8f725cfa10646af389659e09c510c38d82c65960c7b613f844a264acc0e197471cba03f3e8f4b6411bc35dca28922c8352a7bd44621411c73fd6dd4096da2 +"@typescript-eslint/types@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/types@npm:5.56.0" + checksum: 82ca11553bbb1bbfcaf7e7760b03c0d898940238dc002552c21af3e58f7d482c64c3c6cf0666521aff2a1e7b4b58bb6e4d9a00b1e4998a16b5039f5d288d003a languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/typescript-estree@npm:5.54.1" +"@typescript-eslint/typescript-estree@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.56.0" dependencies: - "@typescript-eslint/types": 5.54.1 - "@typescript-eslint/visitor-keys": 5.54.1 + "@typescript-eslint/types": 5.56.0 + "@typescript-eslint/visitor-keys": 5.56.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1991,47 +2093,47 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ea42bdb4832fa96fa1121237c9b664ac4506e2836646651e08a8542c8601d78af6c288779707f893ca4c884221829bb7d7b4b43c4a9c3ed959519266d03a139b + checksum: ec3e85201786aa9adddba7cb834a9f330a7f55c729ee9ccf847dbdc2f7437b760f3774152ccad6d0aa48d13fd78df766c880e3a7ca42e01a20aba0e1a1ed61c5 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/utils@npm:5.54.1" +"@typescript-eslint/utils@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/utils@npm:5.56.0" dependencies: + "@eslint-community/eslint-utils": ^4.2.0 "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.54.1 - "@typescript-eslint/types": 5.54.1 - "@typescript-eslint/typescript-estree": 5.54.1 + "@typescript-eslint/scope-manager": 5.56.0 + "@typescript-eslint/types": 5.56.0 + "@typescript-eslint/typescript-estree": 5.56.0 eslint-scope: ^5.1.1 - eslint-utils: ^3.0.0 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 8f428ea4d338ce85d55fd0c9ae2b217b323f29f51b7c9f8077fef7001ca21d28b032c5e5165b67ae6057aef69edb0e7a164c3c483703be6f3e4e574248bbc399 + checksum: 413e8d4bf7023ee5ba4f695b62e796a1f94930bb92fe5aa0cee58f63b9837116c23f618825a9c671f610e50f5630188b6059b4ed6b05a2a3336f01d8e977becb languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.54.1": - version: 5.54.1 - resolution: "@typescript-eslint/visitor-keys@npm:5.54.1" +"@typescript-eslint/visitor-keys@npm:5.56.0": + version: 5.56.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.56.0" dependencies: - "@typescript-eslint/types": 5.54.1 + "@typescript-eslint/types": 5.56.0 eslint-visitor-keys: ^3.3.0 - checksum: 3a691abd2a43b86a0c41526d14a2afcc93a2e0512b5f8b9ec43f6029c493870808036eae5ee4fc655d26e1999017c4a4dffb241f47c36c2a1238ec9fbd08719c + checksum: 568fda40134e153d7befb59b55698f7919ba780d2d3431d8745feabf2e0fbb8aa7a02173b3c467dd20a0f6594e5248a1f82bb25d6c37827716d77452e86cad29 languageName: node linkType: hard "@wagmi/chains@npm:~0.2.11": - version: 0.2.11 - resolution: "@wagmi/chains@npm:0.2.11" + version: 0.2.14 + resolution: "@wagmi/chains@npm:0.2.14" peerDependencies: typescript: ">=4.9.4" peerDependenciesMeta: typescript: optional: true - checksum: 240d810fa254f15619a669be52cbb1839075cb2b77c89fb08d3409ccbbb0903fe817fec8ca0739bb1015335b608664ac8038026571b7bc3a43e70ea39dccc3a9 + checksum: c2fbb6b886bec5715354dcca536579f9e416b8330ab2bae615148f9780d4da0b8e4ff12e1faee2e9a5f06c5c7803318c21e6f09667124e766071e871f1b86bd2 languageName: node linkType: hard @@ -2055,6 +2157,20 @@ __metadata: languageName: node linkType: hard +"abstract-leveldown@npm:^7.2.0": + version: 7.2.0 + resolution: "abstract-leveldown@npm:7.2.0" + dependencies: + buffer: ^6.0.3 + catering: ^2.0.0 + is-buffer: ^2.0.5 + level-concat-iterator: ^3.0.0 + level-supports: ^2.0.1 + queue-microtask: ^1.2.3 + checksum: d558111f2d123da95ac80b8ba3b9b0a5bc8cd87296e64b05dca693f5f4839aa0e2fc97bad56a101766f499824e2962611750f8a76bbac4a5db35801968fbbe02 + languageName: node + linkType: hard + "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -2110,7 +2226,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.4, ajv@npm:~6.12.6": +"ajv@npm:^6.10.0, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -2498,7 +2614,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:6.0.3": +"buffer@npm:6.0.3, buffer@npm:^6.0.3": version: 6.0.3 resolution: "buffer@npm:6.0.3" dependencies: @@ -2556,9 +2672,16 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001462 - resolution: "caniuse-lite@npm:1.0.30001462" - checksum: e4a57d7851eec65e7c9b6c11c4bbcecdc49d87b1b01bff3c15ea27efb05f959891b4c70ac169842067c134d6fa126d9ad5a91d0f85c7387c5bd912eaf41ea647 + version: 1.0.30001469 + resolution: "caniuse-lite@npm:1.0.30001469" + checksum: 8e496509d7e9ff189c72205675b5db0c5f1b6a09917027441e835efae0848a468a8c4e7d2b409ffc202438fcd23ae53e017f976a03c22c04d12d3c0e1e33e5de + languageName: node + linkType: hard + +"catering@npm:^2.0.0, catering@npm:^2.1.0": + version: 2.1.1 + resolution: "catering@npm:2.1.1" + checksum: 205daefa69c935b0c19f3d8f2e0a520dd69aebe9bda55902958003f7c9cff8f967dfb90071b421bd6eb618576f657a89d2bc0986872c9bc04bbd66655e9d4bd6 languageName: node linkType: hard @@ -2573,7 +2696,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0": +"chalk@npm:^4.0.0, chalk@npm:^4.1.0": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -2701,13 +2824,6 @@ __metadata: languageName: node linkType: hard -"comment-parser@npm:1.3.1": - version: 1.3.1 - resolution: "comment-parser@npm:1.3.1" - checksum: 421e6a113a3afd548500e7174ab46a2049dccf92e82bbaa3b209031b1bdf97552aabfa1ae2a120c0b62df17e1ba70e0d8b05d68504fee78e1ef974c59bcfe718 - languageName: node - linkType: hard - "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -2715,6 +2831,26 @@ __metadata: languageName: node linkType: hard +"concurrently@npm:^7.6.0": + version: 7.6.0 + resolution: "concurrently@npm:7.6.0" + dependencies: + chalk: ^4.1.0 + date-fns: ^2.29.1 + lodash: ^4.17.21 + rxjs: ^7.0.0 + shell-quote: ^1.7.3 + spawn-command: ^0.0.2-1 + supports-color: ^8.1.0 + tree-kill: ^1.2.2 + yargs: ^17.3.1 + bin: + conc: dist/bin/concurrently.js + concurrently: dist/bin/concurrently.js + checksum: f705c9a7960f1b16559ca64958043faeeef6385c0bf30a03d1375e15ab2d96dba4f8166f1bbbb1c85e8da35ca0ce3c353875d71dff2aa132b2357bb533b3332e + languageName: node + linkType: hard + "console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" @@ -2722,6 +2858,13 @@ __metadata: languageName: node linkType: hard +"convert-hex@npm:~0.1.0": + version: 0.1.0 + resolution: "convert-hex@npm:0.1.0" + checksum: eacb880dbc45a36a0e6b5f5674f7e57bdce59bbf5a3ebfba980f694e2be81f1b2c81c9c89834f8054f23cc9c21d1fd210265e2000287a1cd0426657797b2f462 + languageName: node + linkType: hard + "convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" @@ -2736,6 +2879,13 @@ __metadata: languageName: node linkType: hard +"convert-string@npm:~0.1.0": + version: 0.1.0 + resolution: "convert-string@npm:0.1.0" + checksum: a1775cb186d2fbf175486f02e3f7cc68c75e7a0c7609bf434d2a933e801b3a0499ab57de4230919ec824351dc344055bf639a1db5e44a976787145817106d9aa + languageName: node + linkType: hard + "create-hash@npm:^1.1.0, create-hash@npm:^1.1.2": version: 1.2.0 resolution: "create-hash@npm:1.2.0" @@ -2770,6 +2920,15 @@ __metadata: languageName: node linkType: hard +"cross-fetch@npm:^3.1.5": + version: 3.1.5 + resolution: "cross-fetch@npm:3.1.5" + dependencies: + node-fetch: 2.6.7 + checksum: f6b8c6ee3ef993ace6277fd789c71b6acf1b504fd5f5c7128df4ef2f125a429e29cd62dc8c127523f04a5f2fa4771ed80e3f3d9695617f441425045f505cf3bb + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -2781,6 +2940,13 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^2.29.1": + version: 2.29.3 + resolution: "date-fns@npm:2.29.3" + checksum: e01cf5b62af04e05dfff921bb9c9933310ed0e1ae9a81eb8653452e64dc841acf7f6e01e1a5ae5644d0337e9a7f936175fd2cb6819dc122fdd9c5e86c56be484 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" @@ -2808,9 +2974,19 @@ __metadata: linkType: hard "deepmerge@npm:^4.2.2": - version: 4.3.0 - resolution: "deepmerge@npm:4.3.0" - checksum: c7980eb5c5be040b371f1df0d566473875cfabed9f672ccc177b81ba8eee5686ce2478de2f1d0076391621cbe729e5eacda397179a59ef0f68901849647db126 + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 + languageName: node + linkType: hard + +"deferred-leveldown@npm:^7.0.0": + version: 7.0.0 + resolution: "deferred-leveldown@npm:7.0.0" + dependencies: + abstract-leveldown: ^7.2.0 + inherits: ^2.0.3 + checksum: 1ed5eb73e381aeb36d7153bf94dd957060b0294903660c1c8123a375e2b5cd5b3865428d7490aa1561c6ea08a5559563751e59e468d5786c99c765d2a868c658 languageName: node linkType: hard @@ -2889,9 +3065,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.284": - version: 1.4.322 - resolution: "electron-to-chromium@npm:1.4.322" - checksum: 195796a25f28b315d4e2ee17f8aac9d8f7a98c8aaad1b9633113cf6ea8394094b45132e2a7f4e191ec1492303e54fb23667c9ce7794a5a57c961a37aaccaa6cd + version: 1.4.337 + resolution: "electron-to-chromium@npm:1.4.337" + checksum: b7da59afa5e3239f222c3e146d27757cef10bdcb4180f3f77d7a7d339d1ee7c99d0e281807fe47a865426995a3d1c06809743ca71dddc0aaf65e749e66a8be40 languageName: node linkType: hard @@ -2963,32 +3139,32 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.16.14": - version: 0.16.17 - resolution: "esbuild@npm:0.16.17" - dependencies: - "@esbuild/android-arm": 0.16.17 - "@esbuild/android-arm64": 0.16.17 - "@esbuild/android-x64": 0.16.17 - "@esbuild/darwin-arm64": 0.16.17 - "@esbuild/darwin-x64": 0.16.17 - "@esbuild/freebsd-arm64": 0.16.17 - "@esbuild/freebsd-x64": 0.16.17 - "@esbuild/linux-arm": 0.16.17 - "@esbuild/linux-arm64": 0.16.17 - "@esbuild/linux-ia32": 0.16.17 - "@esbuild/linux-loong64": 0.16.17 - "@esbuild/linux-mips64el": 0.16.17 - "@esbuild/linux-ppc64": 0.16.17 - "@esbuild/linux-riscv64": 0.16.17 - "@esbuild/linux-s390x": 0.16.17 - "@esbuild/linux-x64": 0.16.17 - "@esbuild/netbsd-x64": 0.16.17 - "@esbuild/openbsd-x64": 0.16.17 - "@esbuild/sunos-x64": 0.16.17 - "@esbuild/win32-arm64": 0.16.17 - "@esbuild/win32-ia32": 0.16.17 - "@esbuild/win32-x64": 0.16.17 +"esbuild@npm:^0.17.5": + version: 0.17.12 + resolution: "esbuild@npm:0.17.12" + dependencies: + "@esbuild/android-arm": 0.17.12 + "@esbuild/android-arm64": 0.17.12 + "@esbuild/android-x64": 0.17.12 + "@esbuild/darwin-arm64": 0.17.12 + "@esbuild/darwin-x64": 0.17.12 + "@esbuild/freebsd-arm64": 0.17.12 + "@esbuild/freebsd-x64": 0.17.12 + "@esbuild/linux-arm": 0.17.12 + "@esbuild/linux-arm64": 0.17.12 + "@esbuild/linux-ia32": 0.17.12 + "@esbuild/linux-loong64": 0.17.12 + "@esbuild/linux-mips64el": 0.17.12 + "@esbuild/linux-ppc64": 0.17.12 + "@esbuild/linux-riscv64": 0.17.12 + "@esbuild/linux-s390x": 0.17.12 + "@esbuild/linux-x64": 0.17.12 + "@esbuild/netbsd-x64": 0.17.12 + "@esbuild/openbsd-x64": 0.17.12 + "@esbuild/sunos-x64": 0.17.12 + "@esbuild/win32-arm64": 0.17.12 + "@esbuild/win32-ia32": 0.17.12 + "@esbuild/win32-x64": 0.17.12 dependenciesMeta: "@esbuild/android-arm": optional: true @@ -3036,7 +3212,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 4c2cc609ecfb426554bc3f75beb92d89eb2d0c515cfceebaa36c7599d7dcaab7056b70f6d6b51e72b45951ddf9021ee28e356cf205f8e42cc055d522312ea30c + checksum: ea6d33eb1bc6c9e00dcee5e253c7e935251b4801d376661fd9f19a9dcffc27f970078a6f7116d6c78ee825ceff9b974594b0b616bd560ce4d875a951aa92977b languageName: node linkType: hard @@ -3069,40 +3245,13 @@ __metadata: linkType: hard "eslint-config-prettier@npm:^8.5.0": - version: 8.7.0 - resolution: "eslint-config-prettier@npm:8.7.0" + version: 8.8.0 + resolution: "eslint-config-prettier@npm:8.8.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: b05bc7f2296ce3e0925c14147849706544870e0382d38af2352d709a6cf8521bdaff2bd8e5021f1780e570775a8ffa1d2bac28b8065d90d43a3f1f98fd26ce52 - languageName: node - linkType: hard - -"eslint-plugin-jsdoc@npm:^40.0.0": - version: 40.0.1 - resolution: "eslint-plugin-jsdoc@npm:40.0.1" - dependencies: - "@es-joy/jsdoccomment": ~0.36.1 - comment-parser: 1.3.1 - debug: ^4.3.4 - escape-string-regexp: ^4.0.0 - esquery: ^1.4.0 - semver: ^7.3.8 - spdx-expression-parse: ^3.0.1 - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - checksum: 19c5de2f8d0dec11c981eccce7255a8cc58e37c8d697c75144913879b16a9ea90995764bfeb00cbfc2b0678e28210cbe62a6b7865b05e756e887fffc892baf61 - languageName: node - linkType: hard - -"eslint-plugin-tsdoc@npm:^0.2.17": - version: 0.2.17 - resolution: "eslint-plugin-tsdoc@npm:0.2.17" - dependencies: - "@microsoft/tsdoc": 0.14.2 - "@microsoft/tsdoc-config": 0.16.2 - checksum: d143a5f1c5967812d75f246ae2776cb030f6e7966b981406c9df9352a9ab02b035f294cedb30054eac2c4a217ee4ab2ed9fb76292bdccda9438e54d2d7b0146e + checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c languageName: node linkType: hard @@ -3126,24 +3275,6 @@ __metadata: languageName: node linkType: hard -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: ^2.0.0 - peerDependencies: - eslint: ">=5" - checksum: 0668fe02f5adab2e5a367eee5089f4c39033af20499df88fe4e6aba2015c20720404d8c3d6349b6f716b08fdf91b9da4e5d5481f265049278099c4c836ccb619 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d - languageName: node - linkType: hard - "eslint-visitor-keys@npm:^3.3.0": version: 3.3.0 resolution: "eslint-visitor-keys@npm:3.3.0" @@ -3152,11 +3283,13 @@ __metadata: linkType: hard "eslint@npm:^8.21.0": - version: 8.35.0 - resolution: "eslint@npm:8.35.0" + version: 8.36.0 + resolution: "eslint@npm:8.36.0" dependencies: - "@eslint/eslintrc": ^2.0.0 - "@eslint/js": 8.35.0 + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.4.0 + "@eslint/eslintrc": ^2.0.1 + "@eslint/js": 8.36.0 "@humanwhocodes/config-array": ^0.11.8 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -3167,9 +3300,8 @@ __metadata: doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 eslint-scope: ^7.1.1 - eslint-utils: ^3.0.0 eslint-visitor-keys: ^3.3.0 - espree: ^9.4.0 + espree: ^9.5.0 esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 @@ -3191,24 +3323,23 @@ __metadata: minimatch: ^3.1.2 natural-compare: ^1.4.0 optionator: ^0.9.1 - regexpp: ^3.2.0 strip-ansi: ^6.0.1 strip-json-comments: ^3.1.0 text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 6212173691d90b1bc94dd3d640e1f210374b30c3905fc0a15e501cf71c6ca52aa3d80ea7a9a245adaaed26d6019169e01fb6881b3f2885b188d37069c749308c + checksum: e9a961fc3b3de5cff5a1cb2c92eeffaa7e155a715489e30b3e1e76f186bd1255e0481e09564f2094733c0b1dbd3453499fb72ae7c043c83156e11e6d965b2304 languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.4.1 - resolution: "espree@npm:9.4.1" +"espree@npm:^9.5.0": + version: 9.5.0 + resolution: "espree@npm:9.5.0" dependencies: acorn: ^8.8.0 acorn-jsx: ^5.3.2 eslint-visitor-keys: ^3.3.0 - checksum: 4d266b0cf81c7dfe69e542c7df0f246e78d29f5b04dda36e514eb4c7af117ee6cfbd3280e560571ed82ff6c9c3f0003c05b82583fc7a94006db7497c4fe4270e + checksum: a7f110aefb6407e0d3237aa635ab3cea87106ae63748dd23c67031afccc640d04c4209fca2daf16e2233c82efb505faead0fb84097478fd9cc6e8f8dd80bf99d languageName: node linkType: hard @@ -3222,7 +3353,7 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.0, esquery@npm:^1.4.2": +"esquery@npm:^1.4.2": version: 1.5.0 resolution: "esquery@npm:1.5.0" dependencies: @@ -3493,6 +3624,13 @@ __metadata: languageName: node linkType: hard +"functional-red-black-tree@npm:^1.0.1": + version: 1.0.1 + resolution: "functional-red-black-tree@npm:1.0.1" + checksum: ca6c170f37640e2d94297da8bb4bf27a1d12bea3e00e6a3e007fd7aa32e37e000f5772acf941b4e4f3cf1c95c3752033d0c509af157ad8f526e7f00723b9eb9f + languageName: node + linkType: hard + "gauge@npm:^4.0.3": version: 4.0.4 resolution: "gauge@npm:4.0.4" @@ -3613,9 +3751,9 @@ __metadata: linkType: hard "graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": - version: 4.2.10 - resolution: "graceful-fs@npm:4.2.10" - checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 languageName: node linkType: hard @@ -3857,7 +3995,14 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.1.0, is-core-module@npm:^2.9.0": +"is-buffer@npm:^2.0.5": + version: 2.0.5 + resolution: "is-buffer@npm:2.0.5" + checksum: 764c9ad8b523a9f5a32af29bdf772b08eb48c04d2ad0a7240916ac2688c983bf5f8504bf25b35e66240edeb9d9085461f9b5dae1f3d2861c6b06a65fe983de42 + languageName: node + linkType: hard + +"is-core-module@npm:^2.9.0": version: 2.11.0 resolution: "is-core-module@npm:2.11.0" dependencies: @@ -4432,14 +4577,14 @@ __metadata: linkType: hard "jest-mock-extended@npm:^3.0.1, jest-mock-extended@npm:^3.0.3": - version: 3.0.3 - resolution: "jest-mock-extended@npm:3.0.3" + version: 3.0.4 + resolution: "jest-mock-extended@npm:3.0.4" dependencies: ts-essentials: ^7.0.3 peerDependencies: jest: ^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0 - typescript: ^3.0.0 || ^4.0.0 - checksum: 826d619b0e9e5f4a7691259a5f8919fd40d6468d13d9c0d8c0724d8ebd106404e7416079692f4dce5b4d42e3579b5948ea789b951ab6858ab76c192113e1d759 + typescript: ^3.0.0 || ^4.0.0 || ^5.0.0 + checksum: f861253c63508b30d971fbbbc1bf2911ff4406cd260d0e23483a1d4514898b18ba5efbd43fbdf6d94996dc09b20eb1aad1b46aeaea9c99244ba12dc99814fd3f languageName: node linkType: hard @@ -4873,17 +5018,10 @@ __metadata: languageName: node linkType: hard -"jju@npm:~1.4.0": - version: 1.4.0 - resolution: "jju@npm:1.4.0" - checksum: 3790481bd2b7827dd6336e6e3dc2dcc6d425679ba7ebde7b679f61dceb4457ea0cda330972494de608571f4973c6dfb5f70fab6f3c5037dbab19ac449a60424f - languageName: node - linkType: hard - "js-sdsl@npm:^4.1.4": - version: 4.3.0 - resolution: "js-sdsl@npm:4.3.0" - checksum: ce908257cf6909e213af580af3a691a736f5ee8b16315454768f917a682a4ea0c11bde1b241bbfaecedc0eb67b72101b2c2df2ffaed32aed5d539fca816f054e + version: 4.4.0 + resolution: "js-sdsl@npm:4.4.0" + checksum: 7bb08a2d746ab7ff742720339aa006c631afe05e77d11eda988c1c35fae8e03e492e4e347e883e786e3ce6170685d4780c125619111f0730c11fdb41b04059c7 languageName: node linkType: hard @@ -4917,13 +5055,6 @@ __metadata: languageName: node linkType: hard -"jsdoc-type-pratt-parser@npm:~3.1.0": - version: 3.1.0 - resolution: "jsdoc-type-pratt-parser@npm:3.1.0" - checksum: 2f437b57621f1e481918165f6cf0e48256628a9e510d8b3f88a2ab667bf2128bf8b94c628b57c43e78f555ca61983e9c282814703840dc091d2623992214a061 - languageName: node - linkType: hard - "jsesc@npm:^2.5.1": version: 2.5.2 resolution: "jsesc@npm:2.5.2" @@ -4977,6 +5108,53 @@ __metadata: languageName: node linkType: hard +"level-concat-iterator@npm:^3.0.0": + version: 3.1.0 + resolution: "level-concat-iterator@npm:3.1.0" + dependencies: + catering: ^2.1.0 + checksum: a15bc4c5fbbb30c1efa7fad06b72feaac84d90990b356b461593c198a833336f31f6daff8f40c3908fabd14cfd8856d1c5ecae9e1cb0575037b65fa607e760e9 + languageName: node + linkType: hard + +"level-errors@npm:^3.0.1": + version: 3.0.1 + resolution: "level-errors@npm:3.0.1" + checksum: fe4486c423e78ab509a8f7908b89a1692cc810dd47e02d9ceca50543b5be0ce3a4d555fb8f4d3c82122f56bd48c27e6175ca06da359b8e359ea2c7848209d8e7 + languageName: node + linkType: hard + +"level-iterator-stream@npm:^5.0.0": + version: 5.0.0 + resolution: "level-iterator-stream@npm:5.0.0" + dependencies: + inherits: ^2.0.4 + readable-stream: ^3.4.0 + checksum: 3f5bbb9caf6cf6d6c4735219194b85f903377d9da76d37db0691b836c8ea3a78e5233fb18c91f0ef8ca8faaa19bd59e46572ebe27ad2039c51cf83e6c974b9f1 + languageName: node + linkType: hard + +"level-supports@npm:^2.0.1": + version: 2.1.0 + resolution: "level-supports@npm:2.1.0" + checksum: f7b16aea7ddd13326ee4fbc2c1099bcaf8a74dc95346af9ebedea4e02518c6f7a438e829b79b7890d67489b59f615a9428369a0a065021797aa7cb6b6bd84d75 + languageName: node + linkType: hard + +"levelup@npm:^5.1.1": + version: 5.1.1 + resolution: "levelup@npm:5.1.1" + dependencies: + catering: ^2.0.0 + deferred-leveldown: ^7.0.0 + level-errors: ^3.0.1 + level-iterator-stream: ^5.0.0 + level-supports: ^2.0.1 + queue-microtask: ^1.2.3 + checksum: 3053cd3495f615874f1695a47bc7c1eaf432f4c1323b41d58770230b39f2b845100c6e6e912bcffdc504051a8540a39b5d05f3b54f65cfdcb43ce613f6182dd6 + languageName: node + linkType: hard + "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -5033,6 +5211,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -5058,6 +5243,13 @@ __metadata: languageName: node linkType: hard +"ltgt@npm:^2.2.0": + version: 2.2.1 + resolution: "ltgt@npm:2.2.1" + checksum: 7e3874296f7538bc8087b428ac4208008d7b76916354b34a08818ca7c83958c1df10ec427eeeaad895f6b81e41e24745b18d30f89abcc21d228b94f6961d50a2 + languageName: node + linkType: hard + "lunr@npm:^2.3.9": version: 2.3.9 resolution: "lunr@npm:2.3.9" @@ -5122,11 +5314,11 @@ __metadata: linkType: hard "marked@npm:^4.2.12": - version: 4.2.12 - resolution: "marked@npm:4.2.12" + version: 4.3.0 + resolution: "marked@npm:4.3.0" bin: marked: bin/marked.js - checksum: bd551cd61028ee639d4ca2ccdfcc5a6ba4227c1b143c4538f3cde27f569dcb57df8e6313560394645b418b84a7336c07ab1e438b89b6324c29d7d8cdd3102d63 + checksum: 0db6817893952c3ec710eb9ceafb8468bf5ae38cb0f92b7b083baa13d70b19774674be04db5b817681fa7c5c6a088f61300815e4dd75a59696f4716ad69f6260 languageName: node linkType: hard @@ -5141,6 +5333,19 @@ __metadata: languageName: node linkType: hard +"memdown@npm:^6.1.1": + version: 6.1.1 + resolution: "memdown@npm:6.1.1" + dependencies: + abstract-leveldown: ^7.2.0 + buffer: ^6.0.3 + functional-red-black-tree: ^1.0.1 + inherits: ^2.0.1 + ltgt: ^2.2.0 + checksum: a8c418620781a396e650834ab18022c1ae13060b3ca47dc80152eff45caf0e4780598610fd0f9b5a50ebdf195e686ed53fadbae1272addfafad98d598a165a4b + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -5205,11 +5410,11 @@ __metadata: linkType: hard "minimatch@npm:^7.1.3": - version: 7.4.2 - resolution: "minimatch@npm:7.4.2" + version: 7.4.3 + resolution: "minimatch@npm:7.4.3" dependencies: brace-expansion: ^2.0.1 - checksum: 9e341b04e69d5ab03e4206dcb61c8a158e3b8709628bf5e1a4eaa9f3b72c0ba925e24ad959b1f6ce6835caa5a927131d5087fae6836b69e7d99d7d5e63ef0bd8 + checksum: daa954231b6859e3ba0e5fbd2486986d3cae283bb69acb7ed3833c84a293f8d7edb8514360ea62c01426ba791446b2a1e1cc0d718bed15c0212cef35c59a6b95 languageName: node linkType: hard @@ -5274,9 +5479,9 @@ __metadata: linkType: hard "minipass@npm:^4.0.0": - version: 4.2.4 - resolution: "minipass@npm:4.2.4" - checksum: c664f2ae4401408d1e7a6e4f50aca45f87b1b0634bc9261136df5c378e313e77355765f73f59c4a5abcadcdf43d83fcd3eb14e4a7cdcce8e36508e2290345753 + version: 4.2.5 + resolution: "minipass@npm:4.2.5" + checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f languageName: node linkType: hard @@ -5359,6 +5564,20 @@ __metadata: languageName: node linkType: hard +"node-fetch@npm:2.6.7": + version: 2.6.7 + resolution: "node-fetch@npm:2.6.7" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b + languageName: node + linkType: hard + "node-gyp-build@npm:^4.2.0": version: 4.6.0 resolution: "node-gyp-build@npm:4.6.0" @@ -5569,7 +5788,7 @@ __metadata: languageName: node linkType: hard -"path-parse@npm:^1.0.6, path-parse@npm:^1.0.7": +"path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a @@ -5654,11 +5873,11 @@ __metadata: linkType: hard "prettier@npm:^2.7.1": - version: 2.8.4 - resolution: "prettier@npm:2.8.4" + version: 2.8.6 + resolution: "prettier@npm:2.8.6" bin: prettier: bin-prettier.js - checksum: c173064bf3df57b6d93d19aa98753b9b9dd7657212e33b41ada8e2e9f9884066bb9ca0b4005b89b3ab137efffdf8fbe0b462785aba20364798ff4303aadda57e + checksum: 8ac94fa67aec0e65743ea15ebf954ef2f1e52638abd129dc04e8b49e8bb3224c0233c98df6b5c98efd31bd2a43866590486559438ee4ead09dc81be389068572 languageName: node linkType: hard @@ -5731,13 +5950,13 @@ __metadata: linkType: hard "pure-rand@npm:^6.0.0": - version: 6.0.0 - resolution: "pure-rand@npm:6.0.0" - checksum: ad1378d0a4859482d053a5264b2b485b445ece4bbc56f8959c233ea678b81ac2d613737925d496ded134eff5f29cc5546bf7492b6bce319ee27bebbad8a0c612 + version: 6.0.1 + resolution: "pure-rand@npm:6.0.1" + checksum: 4bb565399993b815658a72e359f574ce4f04827a42a905105d61163ae86f456d91595a0e4241e7bce04328fae0638ae70ac0428d93ecb55971c465bd084f8648 languageName: node linkType: hard -"queue-microtask@npm:^1.2.2": +"queue-microtask@npm:^1.2.2, queue-microtask@npm:^1.2.3": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 @@ -5751,21 +5970,14 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.6.0": - version: 3.6.1 - resolution: "readable-stream@npm:3.6.1" +"readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" dependencies: inherits: ^2.0.3 string_decoder: ^1.1.1 util-deprecate: ^1.0.1 - checksum: b7ab0508dba3c37277b9e43c0a970ea27635375698859a687f558c3c9393154b6c4f39c3aa5689641de183fffa26771bc1a45878ddde0236ad18fc8fdfde50ea - languageName: node - linkType: hard - -"regexpp@npm:^3.2.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d languageName: node linkType: hard @@ -5826,16 +6038,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:~1.19.0": - version: 1.19.0 - resolution: "resolve@npm:1.19.0" - dependencies: - is-core-module: ^2.1.0 - path-parse: ^1.0.6 - checksum: a05b356e47b85ad3613d9e2a39a824f3c27f4fcad9c9ff6c7cc71a2e314c5904a90ab37481ad0069d03cab9eaaac6eb68aca1bc3355fdb05f1045cd50e2aacea - languageName: node - linkType: hard - "resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin": version: 1.22.1 resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d" @@ -5849,16 +6051,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@~1.19.0#~builtin": - version: 1.19.0 - resolution: "resolve@patch:resolve@npm%3A1.19.0#~builtin::version=1.19.0&hash=c3c19d" - dependencies: - is-core-module: ^2.1.0 - path-parse: ^1.0.6 - checksum: 2443b94d347e6946c87c85faf13071f605e609e0b54784829b0ed2b917d050bfc1cbaf4ecc6453f224cfa7d0c5dcd97cbb273454cd210bee68e4af15c1a5abc9 - languageName: node - linkType: hard - "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -5903,9 +6095,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.10.0": - version: 3.18.0 - resolution: "rollup@npm:3.18.0" +"rollup@npm:^3.18.0": + version: 3.20.1 + resolution: "rollup@npm:3.20.1" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -5913,7 +6105,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 0bcd1abb1cc383abdd09b5594de862ecb2f946e950954bb472a370289bdc4499aea8d04477be55ce205450d973d38ad255f0dc6926162500a251d73bf0e60e6f + checksum: dc88f337133228311c4d52f005310f2b23ad6d0765b8909698aede1eecde32057ef2ae84e244fd27a45ff944f66f3c120d0b5e163c4642356d2d501df531b798 languageName: node linkType: hard @@ -5926,6 +6118,15 @@ __metadata: languageName: node linkType: hard +"rxjs@npm:^7.0.0": + version: 7.8.0 + resolution: "rxjs@npm:7.8.0" + dependencies: + tslib: ^2.1.0 + checksum: 61b4d4fd323c1043d8d6ceb91f24183b28bcf5def4f01ca111511d5c6b66755bc5578587fe714ef5d67cf4c9f2e26f4490d4e1d8cabf9bd5967687835e9866a2 + languageName: node + linkType: hard + "safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" @@ -5952,7 +6153,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.x, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": +"semver@npm:7.x, semver@npm:^7.3.5, semver@npm:^7.3.7": version: 7.3.8 resolution: "semver@npm:7.3.8" dependencies: @@ -5991,6 +6192,16 @@ __metadata: languageName: node linkType: hard +"sha256@npm:^0.2.0": + version: 0.2.0 + resolution: "sha256@npm:0.2.0" + dependencies: + convert-hex: ~0.1.0 + convert-string: ~0.1.0 + checksum: bed2d6507279e34ad2c517d18fbe871900244aca425a298d6ba10115e9beb49a8028296aeff5441b6db4902503a47198138e23ba1be440761a84288c93101ca1 + languageName: node + linkType: hard + "sha3@npm:^2.1.4": version: 2.1.4 resolution: "sha3@npm:2.1.4" @@ -6016,6 +6227,13 @@ __metadata: languageName: node linkType: hard +"shell-quote@npm:^1.7.3": + version: 1.8.0 + resolution: "shell-quote@npm:1.8.0" + checksum: 6ef7c5e308b9c77eedded882653a132214fa98b4a1512bb507588cf6cd2fc78bfee73e945d0c3211af028a1eabe09c6a19b96edd8977dc149810797e93809749 + languageName: node + linkType: hard + "shiki@npm:^0.14.1": version: 0.14.1 resolution: "shiki@npm:0.14.1" @@ -6111,27 +6329,10 @@ __metadata: languageName: node linkType: hard -"spdx-exceptions@npm:^2.1.0": - version: 2.3.0 - resolution: "spdx-exceptions@npm:2.3.0" - checksum: cb69a26fa3b46305637123cd37c85f75610e8c477b6476fa7354eb67c08128d159f1d36715f19be6f9daf4b680337deb8c65acdcae7f2608ba51931540687ac0 - languageName: node - linkType: hard - -"spdx-expression-parse@npm:^3.0.1": - version: 3.0.1 - resolution: "spdx-expression-parse@npm:3.0.1" - dependencies: - spdx-exceptions: ^2.1.0 - spdx-license-ids: ^3.0.0 - checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde - languageName: node - linkType: hard - -"spdx-license-ids@npm:^3.0.0": - version: 3.0.12 - resolution: "spdx-license-ids@npm:3.0.12" - checksum: 92a4dddce62ce1db6fe54a7a839cf85e06abc308fc83b776a55b44e4f1906f02e7ebd506120847039e976bbbad359ea8bdfafb7925eae5cd7e73255f02e0b7d6 +"spawn-command@npm:^0.0.2-1": + version: 0.0.2 + resolution: "spawn-command@npm:0.0.2" + checksum: e35c5d28177b4d461d33c88cc11f6f3a5079e2b132c11e1746453bbb7a0c0b8a634f07541a2a234fa4758239d88203b758def509161b651e81958894c0b4b64b languageName: node linkType: hard @@ -6263,7 +6464,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^8.0.0": +"supports-color@npm:^8.0.0, supports-color@npm:^8.1.0": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: @@ -6368,6 +6569,22 @@ __metadata: languageName: node linkType: hard +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + +"tree-kill@npm:^1.2.2": + version: 1.2.2 + resolution: "tree-kill@npm:1.2.2" + bin: + tree-kill: cli.js + checksum: 49117f5f410d19c84b0464d29afb9642c863bc5ba40fcb9a245d474c6d5cc64d1b177a6e6713129eb346b40aebb9d4631d967517f9fbe8251c35b21b13cd96c7 + languageName: node + linkType: hard + "ts-essentials@npm:^7.0.3": version: 7.0.3 resolution: "ts-essentials@npm:7.0.3" @@ -6537,7 +6754,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.4.0, tslib@npm:^2.5.0": +"tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0": version: 2.5.0 resolution: "tslib@npm:2.5.0" checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 @@ -6586,18 +6803,18 @@ __metadata: linkType: hard "typedoc@npm:^0.23.26": - version: 0.23.26 - resolution: "typedoc@npm:0.23.26" + version: 0.23.28 + resolution: "typedoc@npm:0.23.28" dependencies: lunr: ^2.3.9 marked: ^4.2.12 minimatch: ^7.1.3 shiki: ^0.14.1 peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x bin: typedoc: bin/typedoc - checksum: 09dbd221b5bd27a7f6c593a6aa7e4efc3c46f20761e109a76bf0ed7239011cca1261357094710c01472582060d75a7558aab5bf5b78db3aff7c52188d146ee65 + checksum: 40eb4e207aac1b734e09400cf03f543642cc7b11000895198dd5a0d3166315759ccf4ac30a2915153597c5c186101c72bac2f1fc12b428184a9274d3a0e44c5e languageName: node linkType: hard @@ -6697,28 +6914,29 @@ __metadata: linkType: hard "viem@npm:^0.1.15": - version: 0.1.15 - resolution: "viem@npm:0.1.15" + version: 0.1.22 + resolution: "viem@npm:0.1.22" dependencies: "@noble/hashes": ^1.1.2 + "@noble/secp256k1": ^1.7.1 "@wagmi/chains": ~0.2.11 abitype: ~0.7.1 idna-uts46-hx: ^4.1.2 isomorphic-ws: ^5.0.0 ws: ^8.12.0 - checksum: 9f935e5f8ad7bff674c491782b7ca47263fed7bf9ec52f97aa6914e23ee4418481e6f0c605819b86fb9e6c03fa578c547d5f1d3861a112cec8fc1ded2d45b5ad + checksum: 55ca47241c3e7b6a5720909955cbf003c598e2564db0e25dce2f954a3a7894057e1c1bc0e9dda30b1e8007861bc850704b02eed244a3fde96b3dc6ecb7bd77b4 languageName: node linkType: hard "vite@npm:^4.1.4": - version: 4.1.4 - resolution: "vite@npm:4.1.4" + version: 4.2.1 + resolution: "vite@npm:4.2.1" dependencies: - esbuild: ^0.16.14 + esbuild: ^0.17.5 fsevents: ~2.3.2 postcss: ^8.4.21 resolve: ^1.22.1 - rollup: ^3.10.0 + rollup: ^3.18.0 peerDependencies: "@types/node": ">= 14" less: "*" @@ -6744,7 +6962,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 50a9a1f2e29e0ee8fefdec60314d38fb9b746df0bb6ae5a8114014b5bfd95e0fc9b29c0d5e73939361ba53af7eb66c7d20c5656bbe53a783e96540bd3b907c47 + checksum: 70eb162ffc299017a3c310e3adc95e9661def6b17aafd1f8e5e02e516766060435590dbe3df1e4e95acc3583c728a76e91f07c546221d1e701f1b2b021293f45 languageName: node linkType: hard @@ -6771,6 +6989,23 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: ~0.0.3 + webidl-conversions: ^3.0.0 + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + "which@npm:^2.0.1, which@npm:^2.0.2": version: 2.0.2 resolution: "which@npm:2.0.2" From a5a7e140062a1c80c44ec51cb4907385ecd262a5 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 11:56:39 +0000 Subject: [PATCH 05/13] feat(sim): integrate sim skeleton with rpc --- yarn-project/acir-simulator/src/simulator.ts | 5 +- yarn-project/aztec-rpc/.eslintrc.cjs | 23 +----- yarn-project/aztec-rpc/package.json | 2 + yarn-project/aztec-rpc/src/acir_simulator.ts | 9 --- .../src/aztec_rpc_server/aztec_rpc_server.ts | 49 +++++++++--- .../create_aztec_rpc_server.ts | 20 ++--- yarn-project/aztec-rpc/src/circuits.ts | 79 +++++++++++++------ .../aztec-rpc/src/proof_generator/index.ts | 1 - .../src/proof_generator/proof_generator.ts | 11 --- yarn-project/yarn.lock | 4 +- 10 files changed, 110 insertions(+), 93 deletions(-) delete mode 100644 yarn-project/aztec-rpc/src/acir_simulator.ts delete mode 100644 yarn-project/aztec-rpc/src/proof_generator/index.ts delete mode 100644 yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts diff --git a/yarn-project/acir-simulator/src/simulator.ts b/yarn-project/acir-simulator/src/simulator.ts index 58c05912de19..0716d462c694 100644 --- a/yarn-project/acir-simulator/src/simulator.ts +++ b/yarn-project/acir-simulator/src/simulator.ts @@ -1,4 +1,4 @@ -import { execute, ExecutionPreimages } from './acvm.js'; +import { ExecutionPreimages } from './acvm.js'; import { CallContext, PrivateCircuitPublicInputs, @@ -7,7 +7,6 @@ import { PrivateCallStackItem, OldTreeRoots, } from './circuits.js'; -import { DBOracle } from './db_oracle.js'; export interface ExecutionResult { // Needed for prover @@ -25,8 +24,6 @@ export interface ExecutionResult { * A placeholder for the Acir Simulator. */ export class AcirSimulator { - constructor(private dbOracle: DBOracle, private acvmExecute: execute) {} - run( request: TxRequest, entryPointACIR: Buffer, diff --git a/yarn-project/aztec-rpc/.eslintrc.cjs b/yarn-project/aztec-rpc/.eslintrc.cjs index cc7b3df1143a..e659927475c0 100644 --- a/yarn-project/aztec-rpc/.eslintrc.cjs +++ b/yarn-project/aztec-rpc/.eslintrc.cjs @@ -1,22 +1 @@ -require('@rushstack/eslint-patch/modern-module-resolution'); - -module.exports = { - extends: ['@aztec/eslint-config'], - parserOptions: { tsconfigRootDir: __dirname }, - // TODO - Remove these rules. - rules: { - 'tsdoc/syntax': 'off', - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-description-complete-sentence': 'off', - 'jsdoc/require-hyphen-before-param-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-param-description': 'off', - 'jsdoc/require-param-name': 'off', - 'jsdoc/require-property': 'off', - 'jsdoc/require-property-description': 'off', - 'jsdoc/require-property-name': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-returns-description': 'off', - }, -}; +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/aztec-rpc/package.json b/yarn-project/aztec-rpc/package.json index fbf0ae595f68..6813a5b1134a 100644 --- a/yarn-project/aztec-rpc/package.json +++ b/yarn-project/aztec-rpc/package.json @@ -29,7 +29,9 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/acir-simulator": "workspace:^", "@aztec/aztec-node": "workspace:^", + "@aztec/kernel-simulator": "workspace:^", "sha3": "^2.1.4", "tslib": "^2.4.0" }, diff --git a/yarn-project/aztec-rpc/src/acir_simulator.ts b/yarn-project/aztec-rpc/src/acir_simulator.ts deleted file mode 100644 index c5c5c78fa50d..000000000000 --- a/yarn-project/aztec-rpc/src/acir_simulator.ts +++ /dev/null @@ -1,9 +0,0 @@ -// TODO use @aztce/acir-simulator - -import { PreviousKernelData, PrivateCallData, TxRequest } from './circuits.js'; - -export class AcirSimulator { - public simulate(txRequest: TxRequest) { - return Promise.resolve({ kernelData: new PreviousKernelData(), callData: new PrivateCallData() }); - } -} diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index e7f4d8a8845d..56286ebc927c 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -1,6 +1,7 @@ import { AztecNode, Tx } from '@aztec/aztec-node'; +import { AcirSimulator } from '@aztec/acir-simulator'; +import { KernelProver } from '@aztec/kernel-simulator'; import { generateFunctionSelector } from '../abi_coder/index.js'; -import { AcirSimulator } from '../acir_simulator.js'; import { AztecRPCClient } from '../aztec_rpc_client/index.js'; import { AztecAddress, @@ -8,7 +9,8 @@ import { EthAddress, Fr, generateContractAddress, - KernelPrivateInputs, + OldTreeRoots, + PrivateKernelPublicInputs, Signature, TxContext, TxRequest, @@ -16,16 +18,16 @@ import { import { Database } from '../database/index.js'; import { KeyStore } from '../key_store/index.js'; import { ContractAbi } from '../noir.js'; -import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; import { TxHash } from '../tx/index.js'; +import { AccumulatedTxData } from '@aztec/p2p'; export class AztecRPCServer implements AztecRPCClient { constructor( private keyStore: KeyStore, private synchroniser: Synchroniser, - private simulator: AcirSimulator, - private proofGenerator: ProofGenerator, + private acirSimulator: AcirSimulator, + private kernelProver: KernelProver, private node: AztecNode, private db: Database, ) {} @@ -60,13 +62,11 @@ export class AztecRPCServer implements AztecRPCClient { isContructor: true, }; - const contractDataHash = Fr.ZERO; + const constructorVkHash = Fr.ZERO; const functionTreeRoot = Fr.ZERO; - const constructorHash = Fr.ZERO; const contractDeploymentData = new ContractDeploymentData( - contractDataHash, + constructorVkHash, functionTreeRoot, - constructorHash, contractAddressSalt, portalContract, ); @@ -121,10 +121,33 @@ export class AztecRPCServer implements AztecRPCClient { } public async createTx(txRequest: TxRequest, signature: Signature) { - const { kernelData, callData } = await this.simulator.simulate(txRequest); - const privateInputs = new KernelPrivateInputs(txRequest, signature, kernelData, callData); - const { accumulatedTxData } = await this.proofGenerator.createProof(privateInputs); - return new Tx(accumulatedTxData); + // TODO - get the contract/fn details from the db + const entryPointACIR = Buffer.alloc(0); + const portalContractAddress = EthAddress.ZERO; + const oldRoots = new OldTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); // TODO - get old roots from the database + const executionResult = await this.acirSimulator.run(txRequest, entryPointACIR, portalContractAddress, oldRoots); + // TODO - kernel prover should use the signature along with the request + const { publicInputs, proof } = await this.kernelProver.prove(txRequest, executionResult, oldRoots); + return this.buildTx(publicInputs, proof); + } + + private buildTx(publicInputs: PrivateKernelPublicInputs, proof: Buffer) { + const accumulatedData = publicInputs.end; + + //TODO I think the TX should include all the data from the publicInputs + proof + return new Tx( + new AccumulatedTxData( + accumulatedData.newCommitments.map(fr => fr.buffer), // newCommitments + accumulatedData.newNullifiers.map(fr => fr.buffer), // newNullifiers + accumulatedData.privateCallStack.map(fr => fr.buffer), // privateCallStack + accumulatedData.publicCallStack.map(fr => fr.buffer), // publicCallStack + accumulatedData.l1MsgStack.map(fr => fr.buffer), // l1MsgStack + accumulatedData.newContracts.map(() => Buffer.alloc(0)), // newContracts TODO: use toBuffer from circuits/ts + accumulatedData.newCommitments.map(fr => fr.buffer), // optionallyRevealedData + {}, // aggregationObject + accumulatedData.privateCallCount.buffer.readUInt32BE(), // callCount TODO: check if correct + ), + ); } public async sendTx(tx: Tx) { diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts index f266b65f63ba..802e07da461f 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts @@ -1,9 +1,9 @@ +import { AcirSimulator } from '@aztec/acir-simulator'; import { AztecNode } from '@aztec/aztec-node'; -import { AcirSimulator } from '../acir_simulator.js'; -import { EthAddress, KernelCircuitProver } from '../circuits.js'; +import { KernelProver } from '@aztec/kernel-simulator'; +import { EthAddress } from '../circuits.js'; import { MemoryDB } from '../database/index.js'; import { KeyStore, TestKeyStore } from '../key_store/index.js'; -import { ProofGenerator } from '../proof_generator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; import { AztecRPCServer } from './aztec_rpc_server.js'; @@ -12,8 +12,8 @@ export async function createAztecRPCServer({ node, db, synchroniser, - simulator, - proofGenerator, + acirSimulator, + kernelProver, rpcUrl, rollupAddress, yeeterAddress, @@ -22,8 +22,8 @@ export async function createAztecRPCServer({ node?: AztecNode; db?: MemoryDB; synchroniser?: Synchroniser; - simulator?: AcirSimulator; - proofGenerator?: ProofGenerator; + acirSimulator?: AcirSimulator; + kernelProver?: KernelProver; rpcUrl?: string; rollupAddress?: EthAddress; yeeterAddress?: EthAddress; @@ -44,8 +44,8 @@ export async function createAztecRPCServer({ } db = db || new MemoryDB(); synchroniser = synchroniser || new Synchroniser(node, db); - simulator = simulator || new AcirSimulator(); - proofGenerator = proofGenerator || new ProofGenerator(new KernelCircuitProver()); + acirSimulator = acirSimulator || new AcirSimulator(); + kernelProver = kernelProver || new KernelProver(); - return new AztecRPCServer(keyStore, synchroniser, simulator, proofGenerator, node, db); + return new AztecRPCServer(keyStore, synchroniser, acirSimulator, kernelProver, node, db); } diff --git a/yarn-project/aztec-rpc/src/circuits.ts b/yarn-project/aztec-rpc/src/circuits.ts index 4611a8f863bd..7360897095fc 100644 --- a/yarn-project/aztec-rpc/src/circuits.ts +++ b/yarn-project/aztec-rpc/src/circuits.ts @@ -56,15 +56,18 @@ export interface FunctionData { isContructor: boolean; } +/** + * Contract deployment data in a TxContext + * cpp/src/aztec3/circuits/abis/contract_deployment_data.hpp + */ export class ContractDeploymentData { - public static EMPTY = new ContractDeploymentData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); + public static EMPTY = new ContractDeploymentData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); constructor( - public readonly contractDataHash: Fr, - public readonly functionTreeRoot: Fr, - public readonly constructorHash: Fr, - public readonly contractAddressSalt: Fr, - public readonly portalContractAddress: Fr, + public constructorVkHash: Fr, + public functionTreeRoot: Fr, + public contractAddressSalt: Fr, + public portalContractAddress: EthAddress, ) {} } @@ -97,8 +100,6 @@ export class PreviousKernelData {} export class PrivateCallData {} -export class AccumulatedTxData {} - export class KernelPrivateInputs { constructor( public readonly txRequest: TxRequest, @@ -108,20 +109,6 @@ export class KernelPrivateInputs { ) {} } -export class KernelProofData { - public readonly accumulatedTxData: AccumulatedTxData; - - constructor(public readonly proofData: Buffer) { - this.accumulatedTxData = new AccumulatedTxData(); - } -} - -export class KernelCircuitProver { - public createProof(inputs: KernelPrivateInputs) { - return Promise.resolve(new KernelProofData(Buffer.alloc(100))); - } -} - export function generateContractAddress( deployerAddress: AztecAddress, salt: Fr, @@ -130,3 +117,51 @@ export function generateContractAddress( ) { return AztecAddress.random(); } + +export class OldTreeRoots { + constructor( + public privateDataTreeRoot: Fr, + public nullifierTreeRoot: Fr, + public contractTreeRoot: Fr, + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} +} + +export class ConstantData { + constructor(public oldTreeRoots: OldTreeRoots, public txContext: TxContext) {} +} + +export class AggregationObject {} + +export class NewContractData { + constructor( + public readonly contractAddress: AztecAddress, + public readonly portalContractAddress: EthAddress, + public readonly functionTreeRoot: Fr, + ) {} +} + +export class OptionallyRevealedData {} + +export class AccumulatedTxData { + constructor( + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + + public privateCallCount: Fr, + + public newCommitments: Fr[], + public newNullifiers: Fr[], + + public privateCallStack: Fr[], + public publicCallStack: Fr[], + public l1MsgStack: Fr[], + + public newContracts: NewContractData[], + + public optionallyRevealedData: OptionallyRevealedData[], + ) {} +} + +export class PrivateKernelPublicInputs { + constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} +} diff --git a/yarn-project/aztec-rpc/src/proof_generator/index.ts b/yarn-project/aztec-rpc/src/proof_generator/index.ts deleted file mode 100644 index 0907f3cd0065..000000000000 --- a/yarn-project/aztec-rpc/src/proof_generator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './proof_generator.js'; diff --git a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts b/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts deleted file mode 100644 index 383ef462f490..000000000000 --- a/yarn-project/aztec-rpc/src/proof_generator/proof_generator.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { KernelCircuitProver, KernelPrivateInputs } from '../circuits.js'; - -export class ProofGenerator { - constructor(private prover: KernelCircuitProver) {} - - public async createProof(inputs: KernelPrivateInputs) { - // TODO - iterate - const { accumulatedTxData } = await this.prover.createProof(inputs); - return { accumulatedTxData: accumulatedTxData as any }; - } -} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 14fee48b7919..94e8d62ccafd 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -101,7 +101,9 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/aztec-rpc@workspace:aztec-rpc" dependencies: + "@aztec/acir-simulator": "workspace:^" "@aztec/aztec-node": "workspace:^" + "@aztec/kernel-simulator": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -242,7 +244,7 @@ __metadata: languageName: unknown linkType: soft -"@aztec/kernel-simulator@workspace:kernel-simulator": +"@aztec/kernel-simulator@workspace:^, @aztec/kernel-simulator@workspace:kernel-simulator": version: 0.0.0-use.local resolution: "@aztec/kernel-simulator@workspace:kernel-simulator" dependencies: From 0c00790072c57abf9e3afcdf10f63199e03ee1de Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 12:00:44 +0000 Subject: [PATCH 06/13] refactor: remove unused comments --- .../src/aztec_rpc_server/aztec_rpc_server.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 56286ebc927c..a9a1a74b9248 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -137,15 +137,15 @@ export class AztecRPCServer implements AztecRPCClient { //TODO I think the TX should include all the data from the publicInputs + proof return new Tx( new AccumulatedTxData( - accumulatedData.newCommitments.map(fr => fr.buffer), // newCommitments - accumulatedData.newNullifiers.map(fr => fr.buffer), // newNullifiers - accumulatedData.privateCallStack.map(fr => fr.buffer), // privateCallStack - accumulatedData.publicCallStack.map(fr => fr.buffer), // publicCallStack - accumulatedData.l1MsgStack.map(fr => fr.buffer), // l1MsgStack - accumulatedData.newContracts.map(() => Buffer.alloc(0)), // newContracts TODO: use toBuffer from circuits/ts - accumulatedData.newCommitments.map(fr => fr.buffer), // optionallyRevealedData - {}, // aggregationObject - accumulatedData.privateCallCount.buffer.readUInt32BE(), // callCount TODO: check if correct + accumulatedData.newCommitments.map(fr => fr.buffer), + accumulatedData.newNullifiers.map(fr => fr.buffer), + accumulatedData.privateCallStack.map(fr => fr.buffer), + accumulatedData.publicCallStack.map(fr => fr.buffer), + accumulatedData.l1MsgStack.map(fr => fr.buffer), + accumulatedData.newContracts.map(() => Buffer.alloc(0)), // TODO: use toBuffer from circuits/ts + accumulatedData.newCommitments.map(fr => fr.buffer), + {}, // TODO aggregationObject from circuits/ts + accumulatedData.privateCallCount.buffer.readUInt32BE(), // TODO: check if correct ), ); } From fe274275b6f868ec749545b7ee2bc11d65f9c976 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 12:53:09 +0000 Subject: [PATCH 07/13] chore: global skipLibCheck --- yarn-project/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index 21349f9d38db..aa3e469bc511 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -12,6 +12,7 @@ "declarationMap": true, "importHelpers": true, "resolveJsonModule": true, - "composite": true + "composite": true, + "skipLibCheck": true } } From ab11f70c6f3041c19b5c84511520163ab06a9e63 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 12:57:45 +0000 Subject: [PATCH 08/13] Revert "chore: global skipLibCheck" This reverts commit fe274275b6f868ec749545b7ee2bc11d65f9c976. --- yarn-project/tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index aa3e469bc511..21349f9d38db 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -12,7 +12,6 @@ "declarationMap": true, "importHelpers": true, "resolveJsonModule": true, - "composite": true, - "skipLibCheck": true + "composite": true } } From d1b5ea279e8fdcba2ffd418c0ba4a025c41ae534 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 13:34:20 +0000 Subject: [PATCH 09/13] chore: renamed kernel-simulator to kernel-prover --- README.md | 2 +- build_manifest.json | 8 ++++---- build_manifest.sh | 2 +- yarn-project/aztec-rpc/package.json | 2 +- .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 2 +- .../src/aztec_rpc_server/create_aztec_rpc_server.ts | 2 +- .../{kernel-simulator => kernel-prover}/.eslintrc.cjs | 0 .../{kernel-simulator => kernel-prover}/Dockerfile | 8 ++++---- .../{kernel-simulator => kernel-prover}/README.md | 0 .../{kernel-simulator => kernel-prover}/package.json | 2 +- .../{kernel-simulator => kernel-prover}/src/circuits.ts | 0 .../{kernel-simulator => kernel-prover}/src/index.ts | 0 .../tsconfig.dest.json | 0 .../{kernel-simulator => kernel-prover}/tsconfig.json | 0 yarn-project/package.json | 2 +- yarn-project/typedoc.json | 2 +- yarn-project/yarn-project-base/Dockerfile | 2 +- yarn-project/yarn.lock | 6 +++--- 18 files changed, 20 insertions(+), 20 deletions(-) rename yarn-project/{kernel-simulator => kernel-prover}/.eslintrc.cjs (100%) rename yarn-project/{kernel-simulator => kernel-prover}/Dockerfile (55%) rename yarn-project/{kernel-simulator => kernel-prover}/README.md (100%) rename yarn-project/{kernel-simulator => kernel-prover}/package.json (97%) rename yarn-project/{kernel-simulator => kernel-prover}/src/circuits.ts (100%) rename yarn-project/{kernel-simulator => kernel-prover}/src/index.ts (100%) rename yarn-project/{kernel-simulator => kernel-prover}/tsconfig.dest.json (100%) rename yarn-project/{kernel-simulator => kernel-prover}/tsconfig.json (100%) diff --git a/README.md b/README.md index a02be8117158..6d127df72c7d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The Aztec 3 system consists of the following sub projects. - `aztec-rpc` - `aztec.js` - `ethereum.js` -- `kernel-simulator` +- `kernel-prover` - `key-store` - `l1-contracts` - `p2p` diff --git a/build_manifest.json b/build_manifest.json index e0d49269ab08..c6817fce918c 100644 --- a/build_manifest.json +++ b/build_manifest.json @@ -101,11 +101,11 @@ "rebuildPatterns": ["^yarn-project/foundation/"], "dependencies": [] }, - "kernel-simulator": { + "kernel-prover": { "buildDir": "yarn-project", - "projectDir": "yarn-project/kernel-simulator", - "dockerfile": "kernel-simulator/Dockerfile", - "rebuildPatterns": ["^yarn-project/kernel-simulator/"], + "projectDir": "yarn-project/kernel-prover", + "dockerfile": "kernel-prover/Dockerfile", + "rebuildPatterns": ["^yarn-project/kernel-prover/"], "dependencies": ["yarn-project-base"] }, "key-store": { diff --git a/build_manifest.sh b/build_manifest.sh index 6cd66ec2600f..7857d7653f38 100755 --- a/build_manifest.sh +++ b/build_manifest.sh @@ -18,7 +18,7 @@ PROJECTS=( # aztec.js:yarn-project # end-to-end:yarn-project # ethereum.js:yarn-project - # kernel-simulator:yarn-project + # kernel-prover:yarn-project # key-store:yarn-project # merkle-tree:yarn-project # p2p:yarn-project diff --git a/yarn-project/aztec-rpc/package.json b/yarn-project/aztec-rpc/package.json index 6813a5b1134a..ae0c49b467c5 100644 --- a/yarn-project/aztec-rpc/package.json +++ b/yarn-project/aztec-rpc/package.json @@ -31,7 +31,7 @@ "dependencies": { "@aztec/acir-simulator": "workspace:^", "@aztec/aztec-node": "workspace:^", - "@aztec/kernel-simulator": "workspace:^", + "@aztec/kernel-prover": "workspace:^", "sha3": "^2.1.4", "tslib": "^2.4.0" }, diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index a9a1a74b9248..34e913aa3484 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -1,6 +1,6 @@ import { AztecNode, Tx } from '@aztec/aztec-node'; import { AcirSimulator } from '@aztec/acir-simulator'; -import { KernelProver } from '@aztec/kernel-simulator'; +import { KernelProver } from '@aztec/kernel-prover'; import { generateFunctionSelector } from '../abi_coder/index.js'; import { AztecRPCClient } from '../aztec_rpc_client/index.js'; import { diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts index 93ee408b5e0c..23dd610e2127 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/create_aztec_rpc_server.ts @@ -1,6 +1,6 @@ import { AcirSimulator } from '@aztec/acir-simulator'; import { AztecNode } from '@aztec/aztec-node'; -import { KernelProver } from '@aztec/kernel-simulator'; +import { KernelProver } from '@aztec/kernel-prover'; import { EthAddress } from '../circuits.js'; import { MemoryDB } from '../database/index.js'; import { KeyStore, TestKeyStore } from '../key_store/index.js'; diff --git a/yarn-project/kernel-simulator/.eslintrc.cjs b/yarn-project/kernel-prover/.eslintrc.cjs similarity index 100% rename from yarn-project/kernel-simulator/.eslintrc.cjs rename to yarn-project/kernel-prover/.eslintrc.cjs diff --git a/yarn-project/kernel-simulator/Dockerfile b/yarn-project/kernel-prover/Dockerfile similarity index 55% rename from yarn-project/kernel-simulator/Dockerfile rename to yarn-project/kernel-prover/Dockerfile index 60c31d5c269c..0738898f4433 100644 --- a/yarn-project/kernel-simulator/Dockerfile +++ b/yarn-project/kernel-prover/Dockerfile @@ -1,7 +1,7 @@ FROM 278380418400.dkr.ecr.eu-west-2.amazonaws.com/yarn-project-base AS builder -COPY kernel-simulator kernel-simulator -WORKDIR /usr/src/yarn-project/kernel-simulator +COPY kernel-prover kernel-prover +WORKDIR /usr/src/yarn-project/kernel-prover RUN yarn build && yarn formatting && yarn test # Prune dev dependencies. See comment in base image. @@ -9,6 +9,6 @@ RUN yarn cache clean RUN yarn workspaces focus --production > /dev/null FROM node:18-alpine -COPY --from=builder /usr/src/yarn-project/kernel-simulator /usr/src/yarn-project/kernel-simulator -WORKDIR /usr/src/yarn-project/kernel-simulator +COPY --from=builder /usr/src/yarn-project/kernel-prover /usr/src/yarn-project/kernel-prover +WORKDIR /usr/src/yarn-project/kernel-prover ENTRYPOINT ["yarn"] \ No newline at end of file diff --git a/yarn-project/kernel-simulator/README.md b/yarn-project/kernel-prover/README.md similarity index 100% rename from yarn-project/kernel-simulator/README.md rename to yarn-project/kernel-prover/README.md diff --git a/yarn-project/kernel-simulator/package.json b/yarn-project/kernel-prover/package.json similarity index 97% rename from yarn-project/kernel-simulator/package.json rename to yarn-project/kernel-prover/package.json index e15ea6f7d5a5..bd8398e1f775 100644 --- a/yarn-project/kernel-simulator/package.json +++ b/yarn-project/kernel-prover/package.json @@ -1,5 +1,5 @@ { - "name": "@aztec/kernel-simulator", + "name": "@aztec/kernel-prover", "version": "0.0.0", "type": "module", "exports": "./dest/index.js", diff --git a/yarn-project/kernel-simulator/src/circuits.ts b/yarn-project/kernel-prover/src/circuits.ts similarity index 100% rename from yarn-project/kernel-simulator/src/circuits.ts rename to yarn-project/kernel-prover/src/circuits.ts diff --git a/yarn-project/kernel-simulator/src/index.ts b/yarn-project/kernel-prover/src/index.ts similarity index 100% rename from yarn-project/kernel-simulator/src/index.ts rename to yarn-project/kernel-prover/src/index.ts diff --git a/yarn-project/kernel-simulator/tsconfig.dest.json b/yarn-project/kernel-prover/tsconfig.dest.json similarity index 100% rename from yarn-project/kernel-simulator/tsconfig.dest.json rename to yarn-project/kernel-prover/tsconfig.dest.json diff --git a/yarn-project/kernel-simulator/tsconfig.json b/yarn-project/kernel-prover/tsconfig.json similarity index 100% rename from yarn-project/kernel-simulator/tsconfig.json rename to yarn-project/kernel-prover/tsconfig.json diff --git a/yarn-project/package.json b/yarn-project/package.json index 3253b261fe58..ecc6350ba1ec 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -17,7 +17,7 @@ "ethereum.js", "ethereum.js/example", "foundation", - "kernel-simulator", + "kernel-prover", "key-store", "merkle-tree", "noir-contracts", diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index e405ee04264e..475584d6a5de 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -8,7 +8,7 @@ "aztec-rpc", "aztec.js", "ethereum.js", - "kernel-simulator", + "kernel-prover", "key-store", "noir-contracts", "p2p", diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile index 83e87ef2e5cc..329795a5982b 100644 --- a/yarn-project/yarn-project-base/Dockerfile +++ b/yarn-project/yarn-project-base/Dockerfile @@ -24,7 +24,7 @@ COPY ethereum.js/package.json ethereum.js/package.json # Note: foundation has its own lock file, we need to copy it and build COPY foundation/package.json foundation/package.json COPY foundation/yarn.lock foundation/yarn.lock -COPY kernel-simulator/package.json kernel-simulator/package.json +COPY kernel-prover/package.json kernel-prover/package.json COPY key-store/package.json key-store/package.json COPY merkle-tree/package.json merkle-tree/package.json COPY noir-contracts/package.json noir-contracts/package.json diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 94e8d62ccafd..b3fc4b684f8a 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -103,7 +103,7 @@ __metadata: dependencies: "@aztec/acir-simulator": "workspace:^" "@aztec/aztec-node": "workspace:^" - "@aztec/kernel-simulator": "workspace:^" + "@aztec/kernel-prover": "workspace:^" "@jest/globals": ^29.4.3 "@rushstack/eslint-patch": ^1.1.4 "@types/jest": ^29.4.0 @@ -244,9 +244,9 @@ __metadata: languageName: unknown linkType: soft -"@aztec/kernel-simulator@workspace:^, @aztec/kernel-simulator@workspace:kernel-simulator": +"@aztec/kernel-prover@workspace:^, @aztec/kernel-prover@workspace:kernel-prover": version: 0.0.0-use.local - resolution: "@aztec/kernel-simulator@workspace:kernel-simulator" + resolution: "@aztec/kernel-prover@workspace:kernel-prover" dependencies: "@aztec/acir-simulator": "workspace:^" "@jest/globals": ^29.4.3 From 166230c2eb64557aa91502d52797d1a286d7e526 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 14:21:18 +0000 Subject: [PATCH 10/13] feat(rpc): fetch acir and portal from DB --- .../src/aztec_rpc_server/aztec_rpc_server.ts | 54 ++++++++++++++----- .../src/contract_data_source/contract_dao.ts | 11 +++- .../contract_data_source.ts | 4 +- .../memory_contract_data_source.ts | 6 +-- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 34e913aa3484..28a06c20e07d 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -21,6 +21,7 @@ import { ContractAbi } from '../noir.js'; import { Synchroniser } from '../synchroniser/index.js'; import { TxHash } from '../tx/index.js'; import { AccumulatedTxData } from '@aztec/p2p'; +import { ContractDao } from '../contract_data_source/contract_dao.js'; export class AztecRPCServer implements AztecRPCClient { constructor( @@ -73,7 +74,7 @@ export class AztecRPCServer implements AztecRPCClient { const txContext = new TxContext(false, false, false, contractDeploymentData); const contractAddress = generateContractAddress(from, contractAddressSalt, args); - await this.db.addContract(contractAddress, abi, false); + await this.db.addContract(contractAddress, portalContract, abi, false); return new TxRequest( from, @@ -87,19 +88,16 @@ export class AztecRPCServer implements AztecRPCClient { } public async createTxRequest(functionSelector: Buffer, args: Fr[], to: AztecAddress, from: AztecAddress) { - const abi = await this.db.getContract(to); - if (!abi) { + const contract = await this.db.getContract(to); + if (!contract) { throw new Error('Unknown contract.'); } - const functionAbi = abi.functions.find(f => f.selector.equals(functionSelector)); - if (!functionAbi) { - throw new Error('Unknown function.'); - } + const functionDao = this.findFunction(contract, functionSelector); const functionData = { functionSelector, - isSecret: functionAbi.isSecret, + isSecret: functionDao.isSecret, isContructor: false, }; @@ -121,11 +119,33 @@ export class AztecRPCServer implements AztecRPCClient { } public async createTx(txRequest: TxRequest, signature: Signature) { - // TODO - get the contract/fn details from the db - const entryPointACIR = Buffer.alloc(0); - const portalContractAddress = EthAddress.ZERO; - const oldRoots = new OldTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); // TODO - get old roots from the database - const executionResult = await this.acirSimulator.run(txRequest, entryPointACIR, portalContractAddress, oldRoots); + let contractAddress; + + if (txRequest.to === AztecAddress.ZERO) { + contractAddress = generateContractAddress( + txRequest.from, + txRequest.txContext.contractDeploymentData.contractAddressSalt, + txRequest.args, + ); + } else { + contractAddress = txRequest.to; + } + + const contract = await this.db.getContract(contractAddress); + + if (!contract) { + throw new Error('Unknown contract.'); + } + + const functionDao = this.findFunction(contract, txRequest.functionData.functionSelector); + + const oldRoots = new OldTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); // TODO - get old roots from the database/node + const executionResult = await this.acirSimulator.run( + txRequest, + Buffer.from(functionDao.bytecode, 'base64'), + contract.portalAddress, + oldRoots, + ); // TODO - kernel prover should use the signature along with the request const { publicInputs, proof } = await this.kernelProver.prove(txRequest, executionResult, oldRoots); return this.buildTx(publicInputs, proof); @@ -177,4 +197,12 @@ export class AztecRPCServer implements AztecRPCClient { status: !tx.error, }; } + + private findFunction(contract: ContractDao, functionSelector: Buffer) { + const functionDao = contract.functions.find(f => f.selector.equals(functionSelector)); + if (!functionDao) { + throw new Error('Unknown function.'); + } + return functionDao; + } } diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts index d15712687ae2..ae3f167c3985 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_dao.ts @@ -1,5 +1,5 @@ import { generateFunctionSelector } from '../abi_coder/index.js'; -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi, FunctionAbi } from '../noir.js'; export interface ContractFunctionDao extends FunctionAbi { @@ -8,6 +8,7 @@ export interface ContractFunctionDao extends FunctionAbi { export interface ContractDao extends ContractAbi { address: AztecAddress; + portalAddress: EthAddress; functions: ContractFunctionDao[]; deployed: boolean; } @@ -20,9 +21,15 @@ export function functionAbiToFunctionDao(abi: FunctionAbi) { }; } -export function contractAbiToContractDao(address: AztecAddress, abi: ContractAbi, deployed: boolean): ContractDao { +export function contractAbiToContractDao( + address: AztecAddress, + portalAddress: EthAddress, + abi: ContractAbi, + deployed: boolean, +): ContractDao { return { address, + portalAddress, functions: abi.functions.map(functionAbiToFunctionDao), deployed, }; diff --git a/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts index f086dc05cc7b..f22699ee79a9 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/contract_data_source.ts @@ -1,9 +1,9 @@ -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi } from '../noir.js'; import { ContractDao } from './contract_dao.js'; export interface ContractDataSource { - addContract(address: AztecAddress, abi: ContractAbi, deployed?: boolean): Promise; + addContract(address: AztecAddress, portalAddress: EthAddress, abi: ContractAbi, deployed?: boolean): Promise; getContract(address: AztecAddress): Promise; getCode(contractAddress: AztecAddress, functionSelector: Buffer): Promise; } diff --git a/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts index 3f40eb39b771..ba377e5a1b50 100644 --- a/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts +++ b/yarn-project/aztec-rpc/src/contract_data_source/memory_contract_data_source.ts @@ -1,4 +1,4 @@ -import { AztecAddress } from '../circuits.js'; +import { AztecAddress, EthAddress } from '../circuits.js'; import { ContractAbi } from '../noir.js'; import { contractAbiToContractDao, ContractDao } from './contract_dao.js'; import { ContractDataSource } from './contract_data_source.js'; @@ -6,8 +6,8 @@ import { ContractDataSource } from './contract_data_source.js'; export class MemoryContractDataSource implements ContractDataSource { private contracts: ContractDao[] = []; - public addContract(address: AztecAddress, abi: ContractAbi, deployed = false) { - this.contracts.push(contractAbiToContractDao(address, abi, deployed)); + public addContract(address: AztecAddress, portalAddress: EthAddress, abi: ContractAbi, deployed = false) { + this.contracts.push(contractAbiToContractDao(address, portalAddress, abi, deployed)); return Promise.resolve(); } From 9cc8145f462f2086a2752606fae9963b5b9e1c25 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 14:55:24 +0000 Subject: [PATCH 11/13] fix(prover): pass signature to kernel --- .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 5 ++--- yarn-project/kernel-prover/src/circuits.ts | 6 ++++++ yarn-project/kernel-prover/src/index.ts | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 28a06c20e07d..690debda9ad4 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -146,15 +146,14 @@ export class AztecRPCServer implements AztecRPCClient { contract.portalAddress, oldRoots, ); - // TODO - kernel prover should use the signature along with the request - const { publicInputs, proof } = await this.kernelProver.prove(txRequest, executionResult, oldRoots); + const { publicInputs, proof } = await this.kernelProver.prove(txRequest, signature, executionResult, oldRoots); return this.buildTx(publicInputs, proof); } private buildTx(publicInputs: PrivateKernelPublicInputs, proof: Buffer) { const accumulatedData = publicInputs.end; - //TODO I think the TX should include all the data from the publicInputs + proof + // TODO I think the TX should include all the data from the publicInputs + proof return new Tx( new AccumulatedTxData( accumulatedData.newCommitments.map(fr => fr.buffer), diff --git a/yarn-project/kernel-prover/src/circuits.ts b/yarn-project/kernel-prover/src/circuits.ts index 917b55cc08a2..6c9c25ab6c9a 100644 --- a/yarn-project/kernel-prover/src/circuits.ts +++ b/yarn-project/kernel-prover/src/circuits.ts @@ -227,3 +227,9 @@ export class AccumulatedTxData { export class PrivateKernelPublicInputs { constructor(public end: AccumulatedTxData, public constants: ConstantData, public isPrivateKernel: true) {} } + +export class Signature { + public static SIZE = 64; + + constructor(public readonly buffer: Buffer) {} +} diff --git a/yarn-project/kernel-prover/src/index.ts b/yarn-project/kernel-prover/src/index.ts index 539408f34828..173a83b2bb77 100644 --- a/yarn-project/kernel-prover/src/index.ts +++ b/yarn-project/kernel-prover/src/index.ts @@ -7,11 +7,13 @@ import { NewContractData, OldTreeRoots, PrivateKernelPublicInputs, + Signature, TxRequest, } from './circuits.js'; export class KernelProver { prove( txRequest: TxRequest, + txSignature: Signature, executionResult: ExecutionResult, oldRoots: OldTreeRoots, ): Promise<{ publicInputs: PrivateKernelPublicInputs; proof: Buffer }> { From fd510f9520ce292c6d8a15c3024cacfada437b16 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 15:25:55 +0000 Subject: [PATCH 12/13] chore: added build of deps --- yarn-project/aztec.js/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn-project/aztec.js/Dockerfile b/yarn-project/aztec.js/Dockerfile index 0257381620c2..f729395ffacc 100644 --- a/yarn-project/aztec.js/Dockerfile +++ b/yarn-project/aztec.js/Dockerfile @@ -14,6 +14,8 @@ RUN cd merkle-tree && yarn build RUN cd world-state && yarn build RUN cd p2p && yarn build RUN cd aztec-node && yarn build +RUN cd acir-simulator && yarn build +RUN cd kernel-prover && yarn build RUN cd aztec-rpc && yarn build WORKDIR /usr/src/yarn-project/aztec.js RUN yarn build && yarn formatting && yarn test From ecbfc13be3cd1d96185b7fc28a2ac1a850f5b054 Mon Sep 17 00:00:00 2001 From: sirasistant Date: Fri, 24 Mar 2023 15:29:58 +0000 Subject: [PATCH 13/13] chore: fixed dockerfile --- yarn-project/aztec.js/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn-project/aztec.js/Dockerfile b/yarn-project/aztec.js/Dockerfile index f729395ffacc..f09e9a608b00 100644 --- a/yarn-project/aztec.js/Dockerfile +++ b/yarn-project/aztec.js/Dockerfile @@ -6,6 +6,8 @@ COPY archiver archiver COPY world-state world-state COPY p2p p2p COPY aztec-node aztec-node +COPY acir-simulator acir-simulator +COPY kernel-prover kernel-prover COPY aztec-rpc aztec-rpc COPY aztec.js aztec.js RUN cd ethereum.js && yarn build