diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 57961c558e22..df9823534304 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -20,7 +20,6 @@ import { } from '@aztec/circuits.js'; import { type P2P } from '@aztec/p2p'; import { type GlobalVariableBuilder } from '@aztec/sequencer-client'; -import { getTelemetryClient } from '@aztec/telemetry-client'; import { type MockProxy, mock } from 'jest-mock-extended'; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 6cad69093262..ef4bc47c0da7 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -73,12 +73,7 @@ import { createValidatorForAcceptingTxs, getDefaultAllowedSetupFunctions, } from '@aztec/sequencer-client'; -<<<<<<< HEAD import { PublicProcessorFactory } from '@aztec/simulator/server'; -import { Attributes, type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { PublicProcessorFactory } from '@aztec/simulator'; import { Attributes, type TelemetryClient, @@ -87,7 +82,6 @@ import { getTelemetryClient, trackSpan, } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { createValidatorClient } from '@aztec/validator-client'; import { createWorldStateSynchronizer } from '@aztec/world-state'; diff --git a/yarn-project/aztec/src/cli/cmds/start_archiver.ts b/yarn-project/aztec/src/cli/cmds/start_archiver.ts index 7e1272b5148f..a6d9fd8e9942 100644 --- a/yarn-project/aztec/src/cli/cmds/start_archiver.ts +++ b/yarn-project/aztec/src/cli/cmds/start_archiver.ts @@ -28,7 +28,7 @@ export async function startArchiver( const store = await createStore('archiver', archiverConfig, storeLog); const archiverStore = new KVArchiverDataStore(store, archiverConfig.maxLogs); - const telemetry = await initTelemetryClient(getTelemetryClientConfig()); + const telemetry = initTelemetryClient(getTelemetryClientConfig()); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/10056): place CL url in config here const blobSinkClient = createBlobSinkClient(); const archiver = await Archiver.createAndSync(archiverConfig, archiverStore, { telemetry, blobSinkClient }, true); diff --git a/yarn-project/aztec/src/cli/cmds/start_bot.ts b/yarn-project/aztec/src/cli/cmds/start_bot.ts index a7c94504926f..4e5af62d1bcf 100644 --- a/yarn-project/aztec/src/cli/cmds/start_bot.ts +++ b/yarn-project/aztec/src/cli/cmds/start_bot.ts @@ -27,7 +27,7 @@ export async function startBot( pxe = await addPXE(options, signalHandlers, services, userLog); } - const telemetry = await initTelemetryClient(getTelemetryClientConfig()); + const telemetry = initTelemetryClient(getTelemetryClientConfig()); await addBot(options, signalHandlers, services, { pxe, telemetry }); } diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts index 98e3bfa3069b..a68b6a5b6e0e 100644 --- a/yarn-project/aztec/src/cli/cmds/start_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -88,7 +88,7 @@ export async function startNode( } const telemetryConfig = extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'); - const telemetry = await initTelemetryClient(telemetryConfig); + const telemetry = initTelemetryClient(telemetryConfig); // Create and start Aztec Node const node = await createAztecNode(nodeConfig, { telemetry }); diff --git a/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts b/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts index abf96682aa92..ae9181f68417 100644 --- a/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts +++ b/yarn-project/aztec/src/cli/cmds/start_p2p_bootstrap.ts @@ -15,7 +15,7 @@ export async function startP2PBootstrap( ) { // Start a P2P bootstrap node. const config = extractRelevantOptions(options, bootnodeConfigMappings, 'p2p'); - const telemetryClient = await initTelemetryClient(getTelemetryClientConfig()); + const telemetryClient = initTelemetryClient(getTelemetryClientConfig()); const store = await createStore('p2p-bootstrap', config, createLogger('p2p:bootstrap:store')); const node = new BootstrapNode(store, telemetryClient); await node.start(config); diff --git a/yarn-project/aztec/src/cli/cmds/start_proof_verifier.ts b/yarn-project/aztec/src/cli/cmds/start_proof_verifier.ts index 1e9120f48093..8ce25e1b2990 100644 --- a/yarn-project/aztec/src/cli/cmds/start_proof_verifier.ts +++ b/yarn-project/aztec/src/cli/cmds/start_proof_verifier.ts @@ -8,7 +8,7 @@ export async function startProofVerifier(options: any, signalHandlers: (() => Pr const config = extractRelevantOptions(options, proofVerifierConfigMappings, 'proofVerifier'); const telemetryConfig = extractRelevantOptions(options, telemetryClientConfigMappings, 'tel'); - const telemetry = await initTelemetryClient(telemetryConfig); + const telemetry = initTelemetryClient(telemetryConfig); const proofVerifier = await ProofVerifier.new(config, telemetry); userLog('Starting proof verifier'); diff --git a/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts b/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts index 25ee9d236530..23919f407d0f 100644 --- a/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts +++ b/yarn-project/aztec/src/cli/cmds/start_prover_agent.ts @@ -40,7 +40,7 @@ export async function startProverAgent( const broker = createProvingJobBrokerClient(config.proverBrokerUrl); - const telemetry = await initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel')); + const telemetry = initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel')); const prover = await buildServerCircuitProver(config, telemetry); const proofStore = new InlineProofStore(); const agents = times( diff --git a/yarn-project/aztec/src/cli/cmds/start_prover_broker.ts b/yarn-project/aztec/src/cli/cmds/start_prover_broker.ts index 6ce6e8ebff57..ad53dea8fa2a 100644 --- a/yarn-project/aztec/src/cli/cmds/start_prover_broker.ts +++ b/yarn-project/aztec/src/cli/cmds/start_prover_broker.ts @@ -28,7 +28,7 @@ export async function startProverBroker( ...extractRelevantOptions(options, proverBrokerConfigMappings, 'proverBroker'), // override with command line options }; - const client = await initTelemetryClient(getTelemetryClientConfig()); + const client = initTelemetryClient(getTelemetryClientConfig()); const broker = await createAndStartProvingBroker(config, client); services.proverBroker = [broker, ProvingJobBrokerSchema]; signalHandlers.push(() => broker.stop()); diff --git a/yarn-project/aztec/src/cli/cmds/start_prover_node.ts b/yarn-project/aztec/src/cli/cmds/start_prover_node.ts index a68a266027c3..275be3eeea35 100644 --- a/yarn-project/aztec/src/cli/cmds/start_prover_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_prover_node.ts @@ -58,7 +58,7 @@ export async function startProverNode( proverConfig.l1Contracts = await createAztecNodeClient(nodeUrl).getL1ContractAddresses(); } - const telemetry = await initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel')); + const telemetry = initTelemetryClient(extractRelevantOptions(options, telemetryClientConfigMappings, 'tel')); let broker: ProvingJobBroker; if (proverConfig.proverBrokerUrl) { diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 7a66a499cd62..17d1af6c862d 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -145,7 +145,7 @@ export async function createSandbox(config: Partial = {}) { await watcher.start(); } - const telemetry = await initTelemetryClient(getTelemetryClientConfig()); + const telemetry = initTelemetryClient(getTelemetryClientConfig()); // Create a local blob sink client inside the sandbox, no http connectivity const blobSinkClient = createBlobSinkClient(); const node = await createAztecNode(aztecNodeConfig, { telemetry, blobSinkClient }); diff --git a/yarn-project/bb-prover/src/prover/bb_prover.ts b/yarn-project/bb-prover/src/prover/bb_prover.ts index 050551ee94ef..ea6b4fe46330 100644 --- a/yarn-project/bb-prover/src/prover/bb_prover.ts +++ b/yarn-project/bb-prover/src/prover/bb_prover.ts @@ -69,13 +69,8 @@ import { convertSingleTxBlockRootRollupInputsToWitnessMap, convertSingleTxBlockRootRollupOutputsFromWitnessMap, } from '@aztec/noir-protocol-circuits-types/server'; -<<<<<<< HEAD import { NativeACVMSimulator } from '@aztec/simulator/server'; -import { Attributes, type TelemetryClient, trackSpan } from '@aztec/telemetry-client'; -======= -import { NativeACVMSimulator } from '@aztec/simulator'; import { Attributes, type TelemetryClient, getTelemetryClient, trackSpan } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type WitnessMap } from '@noir-lang/types'; import { assert } from 'console'; diff --git a/yarn-project/bb-prover/src/test/test_circuit_prover.ts b/yarn-project/bb-prover/src/test/test_circuit_prover.ts index b96124789ecd..04b4a77bfa01 100644 --- a/yarn-project/bb-prover/src/test/test_circuit_prover.ts +++ b/yarn-project/bb-prover/src/test/test_circuit_prover.ts @@ -63,13 +63,8 @@ import { convertSimulatedSingleTxBlockRootRollupOutputsFromWitnessMap, } from '@aztec/noir-protocol-circuits-types/server'; import { ProtocolCircuitVks } from '@aztec/noir-protocol-circuits-types/vks'; -<<<<<<< HEAD import { type SimulationProvider, WASMSimulatorWithBlobs, emitCircuitSimulationStats } from '@aztec/simulator/server'; -import { type TelemetryClient, trackSpan } from '@aztec/telemetry-client'; -======= -import { type SimulationProvider, WASMSimulatorWithBlobs, emitCircuitSimulationStats } from '@aztec/simulator'; import { type TelemetryClient, getTelemetryClient, trackSpan } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type WitnessMap } from '@noir-lang/types'; diff --git a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts index 8331c217261a..ce7d27170c6b 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts @@ -114,7 +114,7 @@ export class P2PNetworkTest { }) { const port = basePort || (await getPort()); - const telemetry = await getEndToEndTestTelemetryClient(metricsPort); + const telemetry = getEndToEndTestTelemetryClient(metricsPort); const bootstrapNode = await createBootstrapNodeFromPrivateKey(BOOTSTRAP_NODE_PRIVATE_KEY, port, telemetry); const bootstrapNodeEnr = bootstrapNode.getENR().encodeTxt(); diff --git a/yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts b/yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts index cfdfc1fd5442..5cb5ba6e60f5 100644 --- a/yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts +++ b/yarn-project/end-to-end/src/fixtures/setup_p2p_test.ts @@ -86,7 +86,7 @@ export async function createNode( ) { const createNode = async () => { const validatorConfig = await createValidatorConfig(config, bootstrapNode, tcpPort, accountIndex, dataDirectory); - const telemetry = await getEndToEndTestTelemetryClient(metricsPort); + const telemetry = getEndToEndTestTelemetryClient(metricsPort); return await AztecNodeService.createAndSync(validatorConfig, { telemetry, dateProvider }); }; return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createNode) : createNode(); diff --git a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts index c2d0304d4f16..791476559a62 100644 --- a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts +++ b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts @@ -386,7 +386,7 @@ async function setupFromFresh( aztecNodeConfig.bbWorkingDirectory = bbConfig.bbWorkingDirectory; } - const telemetry = await getEndToEndTestTelemetryClient(opts.metricsPort); + const telemetry = getEndToEndTestTelemetryClient(opts.metricsPort); logger.verbose('Creating and synching an aztec node...'); const dateProvider = new TestDateProvider(); @@ -492,7 +492,7 @@ async function setupFromState(statePath: string, logger: Logger): Promise PXE_URL; -let telemetryPromise: TelemetryClient | undefined = undefined; +let telemetry: TelemetryClient | undefined = undefined; function getTelemetryClient(partialConfig: Partial & { benchmark?: boolean } = {}) { - if (!telemetryPromise) { + if (!telemetry) { const config = { ...getTelemetryConfig(), ...partialConfig }; - telemetryPromise = config.benchmark - ? new BenchmarkTelemetryClient() - : initTelemetryClient(config); + telemetry = config.benchmark ? new BenchmarkTelemetryClient() : initTelemetryClient(config); } - return telemetryPromise; + return telemetry; } if (typeof afterAll === 'function') { afterAll(() => { - await telemetryPromise?.stop(); + telemetry?.stop(); }); } @@ -472,8 +471,6 @@ export async function setup( const telemetry = await getTelemetryClient(opts.telemetryConfig); -======= ->>>>>>> ebdf383f12 (refactor: global telemetry client) const blobSinkClient = createBlobSinkClient(config.blobSinkUrl); const publisher = new TestL1Publisher(config, { blobSinkClient }); const aztecNode = await AztecNodeService.createAndSync(config, { diff --git a/yarn-project/end-to-end/src/fixtures/with_telemetry_utils.ts b/yarn-project/end-to-end/src/fixtures/with_telemetry_utils.ts index c8644816d53a..9b93b6444861 100644 --- a/yarn-project/end-to-end/src/fixtures/with_telemetry_utils.ts +++ b/yarn-project/end-to-end/src/fixtures/with_telemetry_utils.ts @@ -7,7 +7,7 @@ import { } from '@aztec/telemetry-client'; import { OTelPinoStream } from '@aztec/telemetry-client/otel-pino-stream'; -export function getEndToEndTestTelemetryClient(metricsPort?: number): Promise { +export function getEndToEndTestTelemetryClient(metricsPort?: number): TelemetryClient { if (metricsPort) { const otelStream = new OTelPinoStream({ levels }); registerLoggingStream(otelStream); diff --git a/yarn-project/prover-client/src/mocks/test_context.ts b/yarn-project/prover-client/src/mocks/test_context.ts index 705bcee77375..0350f2e89274 100644 --- a/yarn-project/prover-client/src/mocks/test_context.ts +++ b/yarn-project/prover-client/src/mocks/test_context.ts @@ -26,13 +26,8 @@ import { type SimulationProvider, WASMSimulatorWithBlobs, type WorldStateDB, -<<<<<<< HEAD } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -} from '@aztec/simulator'; import { getTelemetryClient } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type MerkleTreeAdminDatabase } from '@aztec/world-state'; import { NativeWorldStateService } from '@aztec/world-state/native'; diff --git a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts index 9b7a68ab4a86..c0bd1d180a46 100644 --- a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts +++ b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts @@ -53,6 +53,7 @@ import { computeUnbalancedMerkleRoot } from '@aztec/foundation/trees'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vks'; import { protocolContractTreeRoot } from '@aztec/protocol-contracts'; import { computeFeePayerBalanceLeafSlot } from '@aztec/simulator/server'; +import { Attributes, Span, runInSpan } from '@aztec/telemetry-client'; import { type MerkleTreeReadOperations } from '@aztec/world-state'; import { inspect } from 'util'; @@ -67,185 +68,191 @@ type BaseTreeNames = 'NoteHashTree' | 'ContractTree' | 'NullifierTree' | 'Public export type TreeNames = BaseTreeNames | 'L1ToL2MessageTree' | 'Archive'; // Builds the hints for base rollup. Updating the contract, nullifier, and data trees in the process. -export async function buildBaseRollupHints( - tx: ProcessedTx, - globalVariables: GlobalVariables, - db: MerkleTreeWriteOperations, - startSpongeBlob: SpongeBlob, -) { - // Get trees info before any changes hit - const constants = await getConstantRollupData(globalVariables, db); - const start = new PartialStateReference( - await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db), - await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db), - await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db), - ); - // Get the subtree sibling paths for the circuit - const noteHashSubtreeSiblingPathArray = await getSubtreeSiblingPath( - MerkleTreeId.NOTE_HASH_TREE, - NOTE_HASH_SUBTREE_HEIGHT, - db, - ); - - const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => - i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO, - ); - - // Update the note hash trees with the new items being inserted to get the new roots - // that will be used by the next iteration of the base rollup circuit, skipping the empty ones - const noteHashes = padArrayEnd(tx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX); - await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes); - - // The read witnesses for a given TX should be generated before the writes of the same TX are applied. - // All reads that refer to writes in the same tx are transient and can be simplified out. - const txPublicDataUpdateRequestInfo = await processPublicDataUpdateRequests(tx, db); - - // Update the nullifier tree, capturing the low nullifier info for each individual operation - const { - lowLeavesWitnessData: nullifierWitnessLeaves, - newSubtreeSiblingPath: nullifiersSubtreeSiblingPath, - sortedNewLeaves: sortednullifiers, - sortedNewLeavesIndexes, - } = await db.batchInsert( - MerkleTreeId.NULLIFIER_TREE, - padArrayEnd(tx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()), - NULLIFIER_SUBTREE_HEIGHT, - ); - - if (nullifierWitnessLeaves === undefined) { - throw new Error(`Could not craft nullifier batch insertion proofs`); - } - - // Extract witness objects from returned data - const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness[] = - nullifierWitnessLeaves.map(l => - MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), +export const buildBaseRollupHints = runInSpan( + 'BlockBuilderHelpers', + 'buildBaseRollupHints', + async ( + span: Span, + tx: ProcessedTx, + globalVariables: GlobalVariables, + db: MerkleTreeWriteOperations, + startSpongeBlob: SpongeBlob, + ) => { + span.setAttribute(Attributes.TX_HASH, tx.hash.toString()); + // Get trees info before any changes hit + const constants = await getConstantRollupData(globalVariables, db); + const start = new PartialStateReference( + await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db), + await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db), + await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db), + ); + // Get the subtree sibling paths for the circuit + const noteHashSubtreeSiblingPathArray = await getSubtreeSiblingPath( + MerkleTreeId.NOTE_HASH_TREE, + NOTE_HASH_SUBTREE_HEIGHT, + db, ); - const nullifierSubtreeSiblingPathArray = nullifiersSubtreeSiblingPath.toFields(); - - const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => - i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO, - ); - - // Append new data to startSpongeBlob - const inputSpongeBlob = startSpongeBlob.clone(); - startSpongeBlob.absorb(tx.txEffect.toBlobFields()); - - if (tx.avmProvingRequest) { - // Build public base rollup hints - const stateDiffHints = PublicBaseStateDiffHints.from({ - nullifierPredecessorPreimages: makeTuple(MAX_NULLIFIERS_PER_TX, i => - i < nullifierWitnessLeaves.length - ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) - : NullifierLeafPreimage.empty(), - ), - nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i => - i < nullifierPredecessorMembershipWitnessesWithoutPadding.length - ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] - : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), - ), - sortedNullifiers: makeTuple(MAX_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortednullifiers[i])), - sortedNullifierIndexes: makeTuple(MAX_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), - noteHashSubtreeSiblingPath, - nullifierSubtreeSiblingPath, - lowPublicDataWritesPreimages: padArrayEnd( - txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, - PublicDataTreeLeafPreimage.empty(), - MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ), - lowPublicDataWritesMembershipWitnesses: padArrayEnd( - txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, - MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT), - MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ), - publicDataTreeSiblingPaths: padArrayEnd( - txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths, - makeTuple(PUBLIC_DATA_TREE_HEIGHT, () => Fr.ZERO), - MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ), - }); + const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => + i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO, + ); - const blockHash = tx.constants.historicalHeader.hash(); - const archiveRootMembershipWitness = await getMembershipWitnessFor( - blockHash, - MerkleTreeId.ARCHIVE, - ARCHIVE_HEIGHT, - db, + // Update the note hash trees with the new items being inserted to get the new roots + // that will be used by the next iteration of the base rollup circuit, skipping the empty ones + const noteHashes = padArrayEnd(tx.txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX); + await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes); + + // The read witnesses for a given TX should be generated before the writes of the same TX are applied. + // All reads that refer to writes in the same tx are transient and can be simplified out. + const txPublicDataUpdateRequestInfo = await processPublicDataUpdateRequests(tx, db); + + // Update the nullifier tree, capturing the low nullifier info for each individual operation + const { + lowLeavesWitnessData: nullifierWitnessLeaves, + newSubtreeSiblingPath: nullifiersSubtreeSiblingPath, + sortedNewLeaves: sortednullifiers, + sortedNewLeavesIndexes, + } = await db.batchInsert( + MerkleTreeId.NULLIFIER_TREE, + padArrayEnd(tx.txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map(n => n.toBuffer()), + NULLIFIER_SUBTREE_HEIGHT, ); - return PublicBaseRollupHints.from({ - start, - startSpongeBlob: inputSpongeBlob, - stateDiffHints, - archiveRootMembershipWitness, - constants, - }); - } else { - if ( - txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses.length > 1 || - txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages.length > 1 || - txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths.length > 1 - ) { - throw new Error(`More than one public data write in a private only tx`); + if (nullifierWitnessLeaves === undefined) { + throw new Error(`Could not craft nullifier batch insertion proofs`); } - // Create data hint for reading fee payer initial balance in Fee Juice - // If no fee payer is set, read hint should be empty - const leafSlot = computeFeePayerBalanceLeafSlot(tx.data.feePayer); - const feePayerFeeJuiceBalanceReadHint = tx.data.feePayer.isZero() - ? PublicDataHint.empty() - : await getPublicDataHint(db, leafSlot.toBigInt()); - - const feeWriteLowLeafPreimage = - txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages[0] || PublicDataTreeLeafPreimage.empty(); - const feeWriteLowLeafMembershipWitness = - txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses[0] || - MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT); - const feeWriteSiblingPath = - txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths[0] || - makeTuple(PUBLIC_DATA_TREE_HEIGHT, () => Fr.ZERO); - - const stateDiffHints = PrivateBaseStateDiffHints.from({ - nullifierPredecessorPreimages: makeTuple(MAX_NULLIFIERS_PER_TX, i => - i < nullifierWitnessLeaves.length - ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) - : NullifierLeafPreimage.empty(), - ), - nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i => - i < nullifierPredecessorMembershipWitnessesWithoutPadding.length - ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] - : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), - ), - sortedNullifiers: makeTuple(MAX_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortednullifiers[i])), - sortedNullifierIndexes: makeTuple(MAX_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), - noteHashSubtreeSiblingPath, - nullifierSubtreeSiblingPath, - feeWriteLowLeafPreimage, - feeWriteLowLeafMembershipWitness, - feeWriteSiblingPath, - }); + // Extract witness objects from returned data + const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness[] = + nullifierWitnessLeaves.map(l => + MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), + ); - const blockHash = tx.constants.historicalHeader.hash(); - const archiveRootMembershipWitness = await getMembershipWitnessFor( - blockHash, - MerkleTreeId.ARCHIVE, - ARCHIVE_HEIGHT, - db, + const nullifierSubtreeSiblingPathArray = nullifiersSubtreeSiblingPath.toFields(); + + const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => + i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO, ); - return PrivateBaseRollupHints.from({ - start, - startSpongeBlob: inputSpongeBlob, - stateDiffHints, - feePayerFeeJuiceBalanceReadHint: feePayerFeeJuiceBalanceReadHint, - archiveRootMembershipWitness, - constants, - }); - } -} + // Append new data to startSpongeBlob + const inputSpongeBlob = startSpongeBlob.clone(); + startSpongeBlob.absorb(tx.txEffect.toBlobFields()); + + if (tx.avmProvingRequest) { + // Build public base rollup hints + const stateDiffHints = PublicBaseStateDiffHints.from({ + nullifierPredecessorPreimages: makeTuple(MAX_NULLIFIERS_PER_TX, i => + i < nullifierWitnessLeaves.length + ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) + : NullifierLeafPreimage.empty(), + ), + nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i => + i < nullifierPredecessorMembershipWitnessesWithoutPadding.length + ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] + : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), + ), + sortedNullifiers: makeTuple(MAX_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortednullifiers[i])), + sortedNullifierIndexes: makeTuple(MAX_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), + noteHashSubtreeSiblingPath, + nullifierSubtreeSiblingPath, + lowPublicDataWritesPreimages: padArrayEnd( + txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, + PublicDataTreeLeafPreimage.empty(), + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ), + lowPublicDataWritesMembershipWitnesses: padArrayEnd( + txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, + MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT), + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ), + publicDataTreeSiblingPaths: padArrayEnd( + txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths, + makeTuple(PUBLIC_DATA_TREE_HEIGHT, () => Fr.ZERO), + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ), + }); + + const blockHash = tx.constants.historicalHeader.hash(); + const archiveRootMembershipWitness = await getMembershipWitnessFor( + blockHash, + MerkleTreeId.ARCHIVE, + ARCHIVE_HEIGHT, + db, + ); + + return PublicBaseRollupHints.from({ + start, + startSpongeBlob: inputSpongeBlob, + stateDiffHints, + archiveRootMembershipWitness, + constants, + }); + } else { + if ( + txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses.length > 1 || + txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages.length > 1 || + txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths.length > 1 + ) { + throw new Error(`More than one public data write in a private only tx`); + } + + // Create data hint for reading fee payer initial balance in Fee Juice + // If no fee payer is set, read hint should be empty + const leafSlot = computeFeePayerBalanceLeafSlot(tx.data.feePayer); + const feePayerFeeJuiceBalanceReadHint = tx.data.feePayer.isZero() + ? PublicDataHint.empty() + : await getPublicDataHint(db, leafSlot.toBigInt()); + + const feeWriteLowLeafPreimage = + txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages[0] || PublicDataTreeLeafPreimage.empty(); + const feeWriteLowLeafMembershipWitness = + txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses[0] || + MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT); + const feeWriteSiblingPath = + txPublicDataUpdateRequestInfo.publicDataWritesSiblingPaths[0] || + makeTuple(PUBLIC_DATA_TREE_HEIGHT, () => Fr.ZERO); + + const stateDiffHints = PrivateBaseStateDiffHints.from({ + nullifierPredecessorPreimages: makeTuple(MAX_NULLIFIERS_PER_TX, i => + i < nullifierWitnessLeaves.length + ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) + : NullifierLeafPreimage.empty(), + ), + nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NULLIFIERS_PER_TX, i => + i < nullifierPredecessorMembershipWitnessesWithoutPadding.length + ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] + : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), + ), + sortedNullifiers: makeTuple(MAX_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortednullifiers[i])), + sortedNullifierIndexes: makeTuple(MAX_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), + noteHashSubtreeSiblingPath, + nullifierSubtreeSiblingPath, + feeWriteLowLeafPreimage, + feeWriteLowLeafMembershipWitness, + feeWriteSiblingPath, + }); + + const blockHash = tx.constants.historicalHeader.hash(); + const archiveRootMembershipWitness = await getMembershipWitnessFor( + blockHash, + MerkleTreeId.ARCHIVE, + ARCHIVE_HEIGHT, + db, + ); + + return PrivateBaseRollupHints.from({ + start, + startSpongeBlob: inputSpongeBlob, + stateDiffHints, + feePayerFeeJuiceBalanceReadHint: feePayerFeeJuiceBalanceReadHint, + archiveRootMembershipWitness, + constants, + }); + } + }, +); -async function getPublicDataHint(db: MerkleTreeWriteOperations, leafSlot: bigint) { +export async function getPublicDataHint(db: MerkleTreeWriteOperations, leafSlot: bigint) { const { index } = (await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot)) ?? {}; if (index === undefined) { throw new Error(`Cannot find the previous value index for public data ${leafSlot}.`); @@ -265,111 +272,126 @@ async function getPublicDataHint(db: MerkleTreeWriteOperations, leafSlot: bigint return new PublicDataHint(new Fr(leafSlot), value, membershipWitness, leafPreimage); } -export function buildBlobHints(txEffects: TxEffect[]) { - const blobFields = txEffects.flatMap(tx => tx.toBlobFields()); - const blobs = Blob.getBlobs(blobFields); - const blobCommitments = blobs.map(b => b.commitmentToFields()); - const blobsHash = new Fr(getBlobsHashFromBlobs(blobs)); - return { blobFields, blobCommitments, blobs, blobsHash }; -} - -export function buildHeaderFromCircuitOutputs( - previousRollupData: BaseOrMergeRollupPublicInputs[], - parityPublicInputs: ParityPublicInputs, - rootRollupOutputs: BlockRootOrBlockMergePublicInputs, - endState: StateReference, - logger?: Logger, -) { - if (previousRollupData.length > 2) { - throw new Error(`There can't be more than 2 previous rollups. Received ${previousRollupData.length}.`); - } - - const blobsHash = rootRollupOutputs.blobPublicInputs[0].getBlobsHash(); - const numTxs = previousRollupData.reduce((sum, d) => sum + d.numTxs, 0); - const outHash = - previousRollupData.length === 0 - ? Fr.ZERO.toBuffer() - : previousRollupData.length === 1 - ? previousRollupData[0].outHash.toBuffer() - : sha256Trunc( - Buffer.concat([previousRollupData[0].outHash.toBuffer(), previousRollupData[1].outHash.toBuffer()]), - ); - const contentCommitment = new ContentCommitment( - new Fr(numTxs), - blobsHash, - parityPublicInputs.shaRoot.toBuffer(), - outHash, - ); +export const buildBlobHints = runInSpan( + 'BlockBuilderHelpers', + 'buildBlobHints', + (_span: Span, txEffects: TxEffect[]) => { + const blobFields = txEffects.flatMap(tx => tx.toBlobFields()); + const blobs = Blob.getBlobs(blobFields); + const blobCommitments = blobs.map(b => b.commitmentToFields()); + const blobsHash = new Fr(getBlobsHashFromBlobs(blobs)); + return { blobFields, blobCommitments, blobs, blobsHash }; + }, +); + +export const buildHeaderFromCircuitOutputs = runInSpan( + 'BlockBuilderHelpers', + 'buildHeaderFromCircuitOutputs', + ( + _span, + previousRollupData: BaseOrMergeRollupPublicInputs[], + parityPublicInputs: ParityPublicInputs, + rootRollupOutputs: BlockRootOrBlockMergePublicInputs, + endState: StateReference, + logger?: Logger, + ) => { + if (previousRollupData.length > 2) { + throw new Error(`There can't be more than 2 previous rollups. Received ${previousRollupData.length}.`); + } - const accumulatedFees = previousRollupData.reduce((sum, d) => sum.add(d.accumulatedFees), Fr.ZERO); - const accumulatedManaUsed = previousRollupData.reduce((sum, d) => sum.add(d.accumulatedManaUsed), Fr.ZERO); - const header = new BlockHeader( - rootRollupOutputs.previousArchive, - contentCommitment, - endState, - rootRollupOutputs.endGlobalVariables, - accumulatedFees, - accumulatedManaUsed, - ); - if (!header.hash().equals(rootRollupOutputs.endBlockHash)) { - logger?.error( - `Block header mismatch when building header from circuit outputs.` + - `\n\nHeader: ${inspect(header)}` + - `\n\nCircuit: ${toFriendlyJSON(rootRollupOutputs)}`, + const blobsHash = rootRollupOutputs.blobPublicInputs[0].getBlobsHash(); + const numTxs = previousRollupData.reduce((sum, d) => sum + d.numTxs, 0); + const outHash = + previousRollupData.length === 0 + ? Fr.ZERO.toBuffer() + : previousRollupData.length === 1 + ? previousRollupData[0].outHash.toBuffer() + : sha256Trunc( + Buffer.concat([previousRollupData[0].outHash.toBuffer(), previousRollupData[1].outHash.toBuffer()]), + ); + const contentCommitment = new ContentCommitment( + new Fr(numTxs), + blobsHash, + parityPublicInputs.shaRoot.toBuffer(), + outHash, ); - throw new Error(`Block header mismatch when building from circuit outputs`); - } - return header; -} -export async function buildHeaderAndBodyFromTxs( - txs: ProcessedTx[], - globalVariables: GlobalVariables, - l1ToL2Messages: Fr[], - db: MerkleTreeReadOperations, -) { - const stateReference = new StateReference( - await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db), - new PartialStateReference( - await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db), - await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db), - await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db), - ), - ); + const accumulatedFees = previousRollupData.reduce((sum, d) => sum.add(d.accumulatedFees), Fr.ZERO); + const accumulatedManaUsed = previousRollupData.reduce((sum, d) => sum.add(d.accumulatedManaUsed), Fr.ZERO); + const header = new BlockHeader( + rootRollupOutputs.previousArchive, + contentCommitment, + endState, + rootRollupOutputs.endGlobalVariables, + accumulatedFees, + accumulatedManaUsed, + ); + if (!header.hash().equals(rootRollupOutputs.endBlockHash)) { + logger?.error( + `Block header mismatch when building header from circuit outputs.` + + `\n\nHeader: ${inspect(header)}` + + `\n\nCircuit: ${toFriendlyJSON(rootRollupOutputs)}`, + ); + throw new Error(`Block header mismatch when building from circuit outputs`); + } + return header; + }, +); + +export const buildHeaderAndBodyFromTxs = runInSpan( + 'BlockBuilderHelpers', + 'buildHeaderAndBodyFromTxs', + async ( + span, + txs: ProcessedTx[], + globalVariables: GlobalVariables, + l1ToL2Messages: Fr[], + db: MerkleTreeReadOperations, + ) => { + span.setAttribute(Attributes.BLOCK_NUMBER, globalVariables.blockNumber.toNumber()); + const stateReference = new StateReference( + await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db), + new PartialStateReference( + await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db), + await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db), + await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db), + ), + ); - const previousArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db); - - const txEffects = txs.map(tx => tx.txEffect); - const body = new Body(txEffects); - - const numTxs = body.txEffects.length; - const outHash = - numTxs === 0 - ? Fr.ZERO.toBuffer() - : numTxs === 1 - ? body.txEffects[0].txOutHash() - : computeUnbalancedMerkleRoot( - body.txEffects.map(tx => tx.txOutHash()), - TxEffect.empty().txOutHash(), - ); - - l1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - const hasher = (left: Buffer, right: Buffer) => sha256Trunc(Buffer.concat([left, right])); - const parityHeight = Math.ceil(Math.log2(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)); - const parityShaRoot = new MerkleTreeCalculator(parityHeight, Fr.ZERO.toBuffer(), hasher).computeTreeRoot( - l1ToL2Messages.map(msg => msg.toBuffer()), - ); - const blobsHash = getBlobsHashFromBlobs(Blob.getBlobs(body.toBlobFields())); + const previousArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db); + + const txEffects = txs.map(tx => tx.txEffect); + const body = new Body(txEffects); + + const numTxs = body.txEffects.length; + const outHash = + numTxs === 0 + ? Fr.ZERO.toBuffer() + : numTxs === 1 + ? body.txEffects[0].txOutHash() + : computeUnbalancedMerkleRoot( + body.txEffects.map(tx => tx.txOutHash()), + TxEffect.empty().txOutHash(), + ); + + l1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); + const hasher = (left: Buffer, right: Buffer) => sha256Trunc(Buffer.concat([left, right])); + const parityHeight = Math.ceil(Math.log2(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)); + const parityShaRoot = new MerkleTreeCalculator(parityHeight, Fr.ZERO.toBuffer(), hasher).computeTreeRoot( + l1ToL2Messages.map(msg => msg.toBuffer()), + ); + const blobsHash = getBlobsHashFromBlobs(Blob.getBlobs(body.toBlobFields())); - const contentCommitment = new ContentCommitment(new Fr(numTxs), blobsHash, parityShaRoot, outHash); + const contentCommitment = new ContentCommitment(new Fr(numTxs), blobsHash, parityShaRoot, outHash); - const fees = body.txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO); - const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.totalGas.l2Gas)), Fr.ZERO); + const fees = body.txEffects.reduce((acc, tx) => acc.add(tx.transactionFee), Fr.ZERO); + const manaUsed = txs.reduce((acc, tx) => acc.add(new Fr(tx.gasUsed.totalGas.l2Gas)), Fr.ZERO); - const header = new BlockHeader(previousArchive, contentCommitment, stateReference, globalVariables, fees, manaUsed); + const header = new BlockHeader(previousArchive, contentCommitment, stateReference, globalVariables, fees, manaUsed); - return { header, body }; -} + return { header, body }; + }, +); export function getBlobsHashFromBlobs(inputs: Blob[]): Buffer { const blobHashes = serializeToBuffer(inputs.map(b => b.getEthVersionedBlobHash())); @@ -388,22 +410,26 @@ export async function validateBlockRootOutput( ]); } -export async function validateState(state: StateReference, db: MerkleTreeReadOperations) { - const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( - async (id: MerkleTreeId) => { - return { key: id, value: await getTreeSnapshot(id, db) }; - }, - ); - const snapshots: Map = new Map( - (await Promise.all(promises)).map(obj => [obj.key, obj.value]), - ); - validatePartialState(state.partial, snapshots); - validateSimulatedTree( - await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db), - state.l1ToL2MessageTree, - 'L1ToL2MessageTree', - ); -} +export const validateState = runInSpan( + 'BlockBuilderHelpers', + 'validateState', + async (_span, state: StateReference, db: MerkleTreeReadOperations) => { + const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( + async (id: MerkleTreeId) => { + return { key: id, value: await getTreeSnapshot(id, db) }; + }, + ); + const snapshots: Map = new Map( + (await Promise.all(promises)).map(obj => [obj.key, obj.value]), + ); + validatePartialState(state.partial, snapshots); + validateSimulatedTree( + await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db), + state.l1ToL2MessageTree, + 'L1ToL2MessageTree', + ); + }, +); export async function getRootTreeSiblingPath(treeId: TID, db: MerkleTreeReadOperations) { const { size } = await db.getTreeInfo(treeId); @@ -411,17 +437,18 @@ export async function getRootTreeSiblingPath(treeId: T return padArrayEnd(path.toFields(), Fr.ZERO, getTreeHeight(treeId)); } -export async function getConstantRollupData( - globalVariables: GlobalVariables, - db: MerkleTreeReadOperations, -): Promise { - return ConstantRollupData.from({ - vkTreeRoot: getVKTreeRoot(), - protocolContractTreeRoot, - lastArchive: await getTreeSnapshot(MerkleTreeId.ARCHIVE, db), - globalVariables, - }); -} +export const getConstantRollupData = runInSpan( + 'BlockBuilderHelpers', + 'getConstantRollupData', + async (_span, globalVariables: GlobalVariables, db: MerkleTreeReadOperations): Promise => { + return ConstantRollupData.from({ + vkTreeRoot: getVKTreeRoot(), + protocolContractTreeRoot, + lastArchive: await getTreeSnapshot(MerkleTreeId.ARCHIVE, db), + globalVariables, + }); + }, +); export async function getTreeSnapshot(id: MerkleTreeId, db: MerkleTreeReadOperations): Promise { const treeInfo = await db.getTreeInfo(id); @@ -436,42 +463,47 @@ export function makeEmptyMembershipWitness(height: N) { ); } -async function processPublicDataUpdateRequests(tx: ProcessedTx, db: MerkleTreeWriteOperations) { - const allPublicDataWrites = tx.txEffect.publicDataWrites.map( - ({ leafSlot, value }) => new PublicDataTreeLeaf(leafSlot, value), - ); +const processPublicDataUpdateRequests = runInSpan( + 'BlockBuilderHelpers', + 'processPublicDataUpdateRequests', + async (span, tx: ProcessedTx, db: MerkleTreeWriteOperations) => { + span.setAttribute(Attributes.TX_HASH, tx.hash.toString()); + const allPublicDataWrites = tx.txEffect.publicDataWrites.map( + ({ leafSlot, value }) => new PublicDataTreeLeaf(leafSlot, value), + ); - const { lowLeavesWitnessData, insertionWitnessData } = await db.sequentialInsert( - MerkleTreeId.PUBLIC_DATA_TREE, - allPublicDataWrites.map(write => { - if (write.isEmpty()) { - throw new Error(`Empty public data write in tx: ${toFriendlyJSON(tx)}`); - } - return write.toBuffer(); - }), - ); + const { lowLeavesWitnessData, insertionWitnessData } = await db.sequentialInsert( + MerkleTreeId.PUBLIC_DATA_TREE, + allPublicDataWrites.map(write => { + if (write.isEmpty()) { + throw new Error(`Empty public data write in tx: ${toFriendlyJSON(tx)}`); + } + return write.toBuffer(); + }), + ); - const lowPublicDataWritesPreimages = lowLeavesWitnessData.map( - lowLeafWitness => lowLeafWitness.leafPreimage as PublicDataTreeLeafPreimage, - ); - const lowPublicDataWritesMembershipWitnesses = lowLeavesWitnessData.map(lowLeafWitness => - MembershipWitness.fromBufferArray( - lowLeafWitness.index, - assertLength(lowLeafWitness.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT), - ), - ); - const publicDataWritesSiblingPaths = insertionWitnessData.map(w => { - const insertionSiblingPath = w.siblingPath.toFields(); - assertLength(insertionSiblingPath, PUBLIC_DATA_TREE_HEIGHT); - return insertionSiblingPath as Tuple; - }); - - return { - lowPublicDataWritesPreimages, - lowPublicDataWritesMembershipWitnesses, - publicDataWritesSiblingPaths, - }; -} + const lowPublicDataWritesPreimages = lowLeavesWitnessData.map( + lowLeafWitness => lowLeafWitness.leafPreimage as PublicDataTreeLeafPreimage, + ); + const lowPublicDataWritesMembershipWitnesses = lowLeavesWitnessData.map(lowLeafWitness => + MembershipWitness.fromBufferArray( + lowLeafWitness.index, + assertLength(lowLeafWitness.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT), + ), + ); + const publicDataWritesSiblingPaths = insertionWitnessData.map(w => { + const insertionSiblingPath = w.siblingPath.toFields(); + assertLength(insertionSiblingPath, PUBLIC_DATA_TREE_HEIGHT); + return insertionSiblingPath as Tuple; + }); + + return { + lowPublicDataWritesPreimages, + lowPublicDataWritesMembershipWitnesses, + publicDataWritesSiblingPaths, + }; + }, +); export async function getSubtreeSiblingPath( treeId: MerkleTreeId, diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts index 138be5778013..26151a1ae5fd 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts @@ -2,12 +2,7 @@ import { TestCircuitProver } from '@aztec/bb-prover'; import { type ServerCircuitProver } from '@aztec/circuit-types'; import { timesAsync } from '@aztec/foundation/collection'; import { createLogger } from '@aztec/foundation/log'; -<<<<<<< HEAD import { WASMSimulatorWithBlobs } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { WASMSimulatorWithBlobs } from '@aztec/simulator'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { jest } from '@jest/globals'; diff --git a/yarn-project/prover-client/src/prover-client/prover-client.ts b/yarn-project/prover-client/src/prover-client/prover-client.ts index abce3bc8dcda..7ba94e9f102d 100644 --- a/yarn-project/prover-client/src/prover-client/prover-client.ts +++ b/yarn-project/prover-client/src/prover-client/prover-client.ts @@ -12,13 +12,8 @@ import { import { Fr } from '@aztec/circuits.js'; import { times } from '@aztec/foundation/collection'; import { createLogger } from '@aztec/foundation/log'; -<<<<<<< HEAD import { NativeACVMSimulator } from '@aztec/simulator/server'; -import { type TelemetryClient } from '@aztec/telemetry-client'; -======= -import { NativeACVMSimulator } from '@aztec/simulator'; import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type ProverClientConfig } from '../config.js'; import { ProvingOrchestrator } from '../orchestrator/orchestrator.js'; diff --git a/yarn-project/prover-node/src/job/epoch-proving-job.test.ts b/yarn-project/prover-node/src/job/epoch-proving-job.test.ts index 82a6424e7c0f..3f12c2e01661 100644 --- a/yarn-project/prover-node/src/job/epoch-proving-job.test.ts +++ b/yarn-project/prover-node/src/job/epoch-proving-job.test.ts @@ -13,13 +13,8 @@ import { RootRollupPublicInputs } from '@aztec/circuits.js/rollup'; import { times } from '@aztec/foundation/collection'; import { sleep } from '@aztec/foundation/sleep'; import { type L1Publisher } from '@aztec/sequencer-client'; -<<<<<<< HEAD import { type PublicProcessor, type PublicProcessorFactory } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { type PublicProcessor, type PublicProcessorFactory } from '@aztec/simulator'; import { getTelemetryClient } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type MockProxy, mock } from 'jest-mock-extended'; diff --git a/yarn-project/prover-node/src/prover-node.test.ts b/yarn-project/prover-node/src/prover-node.test.ts index fce2cf15c768..2a167b24a2e1 100644 --- a/yarn-project/prover-node/src/prover-node.test.ts +++ b/yarn-project/prover-node/src/prover-node.test.ts @@ -25,13 +25,8 @@ import { openTmpStore } from '@aztec/kv-store/lmdb'; import { type BootstrapNode, InMemoryTxPool, MemoryEpochProofQuotePool, P2PClient } from '@aztec/p2p'; import { createBootstrapNode, createTestLibP2PService } from '@aztec/p2p/mocks'; import { type L1Publisher } from '@aztec/sequencer-client'; -<<<<<<< HEAD import { type PublicProcessorFactory } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { type PublicProcessorFactory } from '@aztec/simulator'; import { getTelemetryClient } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { jest } from '@jest/globals'; import { type MockProxy, mock } from 'jest-mock-extended'; diff --git a/yarn-project/prover-node/src/prover-node.ts b/yarn-project/prover-node/src/prover-node.ts index 941ec270a126..80b0f5b19d35 100644 --- a/yarn-project/prover-node/src/prover-node.ts +++ b/yarn-project/prover-node/src/prover-node.ts @@ -27,11 +27,7 @@ import { DateProvider } from '@aztec/foundation/timer'; import { type Maybe } from '@aztec/foundation/types'; import { type P2P } from '@aztec/p2p'; import { type L1Publisher } from '@aztec/sequencer-client'; -<<<<<<< HEAD import { PublicProcessorFactory } from '@aztec/simulator/server'; -import { Attributes, type TelemetryClient, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client'; -======= -import { PublicProcessorFactory } from '@aztec/simulator'; import { Attributes, type TelemetryClient, @@ -40,7 +36,6 @@ import { getTelemetryClient, trackSpan, } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { type BondManager } from './bond/bond-manager.js'; import { EpochProvingJob, type EpochProvingJobState } from './job/epoch-proving-job.js'; diff --git a/yarn-project/simulator/src/public/fixtures/index.ts b/yarn-project/simulator/src/public/fixtures/index.ts index e410365b9c00..f21a56c2736f 100644 --- a/yarn-project/simulator/src/public/fixtures/index.ts +++ b/yarn-project/simulator/src/public/fixtures/index.ts @@ -32,17 +32,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { openTmpStore } from '@aztec/kv-store/lmdb'; import { AvmTestContractArtifact } from '@aztec/noir-contracts.js/AvmTest'; -<<<<<<< HEAD -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { - AvmEphemeralForest, - AvmSimulator, - PublicEnqueuedCallSideEffectTrace, - PublicTxSimulator, - WorldStateDB, -} from '@aztec/simulator'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { MerkleTrees } from '@aztec/world-state'; import { strict as assert } from 'assert'; diff --git a/yarn-project/telemetry-client/package.json b/yarn-project/telemetry-client/package.json index 62e7547afd12..48cbd5793929 100644 --- a/yarn-project/telemetry-client/package.json +++ b/yarn-project/telemetry-client/package.json @@ -6,12 +6,7 @@ "type": "module", "exports": { ".": "./dest/index.js", -<<<<<<< HEAD - "./start": "./dest/start.js", - "./noop": "./dest/noop.js", "./bench": "./dest/bench.js", -======= ->>>>>>> ebdf383f12 (refactor: global telemetry client) "./otel-pino-stream": "./dest/vendor/otel-pino-stream.js" }, "scripts": { diff --git a/yarn-project/telemetry-client/src/otel.ts b/yarn-project/telemetry-client/src/otel.ts index 56377a966b7a..b0a509239cd2 100644 --- a/yarn-project/telemetry-client/src/otel.ts +++ b/yarn-project/telemetry-client/src/otel.ts @@ -281,8 +281,8 @@ export class OpenTelemetryClient implements TelemetryClient { }; } - public static async createAndStart(config: TelemetryClientConfig, log: Logger): Promise { - const resource = await getOtelResource(); + public static createAndStart(config: TelemetryClientConfig, log: Logger): OpenTelemetryClient { + const resource = getOtelResource(); const factory = config.useGcloudObservability ? OpenTelemetryClient.getGcloudClientFactory(config) : OpenTelemetryClient.getCustomClientFactory(config); diff --git a/yarn-project/telemetry-client/src/otel_resource.ts b/yarn-project/telemetry-client/src/otel_resource.ts index 6a41d95c9920..a91dbd944343 100644 --- a/yarn-project/telemetry-client/src/otel_resource.ts +++ b/yarn-project/telemetry-client/src/otel_resource.ts @@ -10,7 +10,7 @@ import { import { aztecDetector } from './aztec_resource_detector.js'; -export async function getOtelResource(): Promise { +export function getOtelResource(): IResource { const resource = detectResourcesSync({ detectors: [ osDetectorSync, @@ -22,9 +22,5 @@ export async function getOtelResource(): Promise { ], }); - if (resource.asyncAttributesPending) { - await resource.waitForAsyncAttributes!(); - } - return resource; } diff --git a/yarn-project/telemetry-client/src/start.ts b/yarn-project/telemetry-client/src/start.ts index 9d4ad2c0a409..e99853052056 100644 --- a/yarn-project/telemetry-client/src/start.ts +++ b/yarn-project/telemetry-client/src/start.ts @@ -10,27 +10,21 @@ export * from './config.js'; let initialised = false; let telemetry: TelemetryClient = new NoopTelemetryClient(); -export async function initTelemetryClient(config: TelemetryClientConfig): Promise { +export function initTelemetryClient(config: TelemetryClientConfig): TelemetryClient { const log = createLogger('telemetry:client'); -<<<<<<< HEAD - if (config.metricsCollectorUrl || config.useGcloudObservability) { - log.info(`Using OpenTelemetry client ${config.useGcloudObservability ? 'with GCP' : 'with custom collector'}`); - return await OpenTelemetryClient.createAndStart(config, log); -======= if (initialised) { log.warn('Telemetry client has already been initialized once'); return telemetry; } - initialised = true; - if (config.metricsCollectorUrl) { - log.info('Using OpenTelemetry client'); - telemetry = await OpenTelemetryClient.createAndStart(config, log); ->>>>>>> 1f11010e9f (refactor: global telemetry client) + if (config.metricsCollectorUrl || config.useGcloudObservability) { + log.info(`Using OpenTelemetry client ${config.useGcloudObservability ? 'with GCP' : 'with custom collector'}`); + telemetry = OpenTelemetryClient.createAndStart(config, log); } else { log.info('Using NoopTelemetryClient'); } + initialised = true; return telemetry; } diff --git a/yarn-project/telemetry-client/src/telemetry.ts b/yarn-project/telemetry-client/src/telemetry.ts index 9fb8497fb212..727c827e30a6 100644 --- a/yarn-project/telemetry-client/src/telemetry.ts +++ b/yarn-project/telemetry-client/src/telemetry.ts @@ -14,9 +14,11 @@ import { SpanStatusCode, Tracer, } from '@opentelemetry/api'; +import { isPromise } from 'node:util/types'; import * as Attributes from './attributes.js'; import * as Metrics from './metrics.js'; +import { getTelemetryClient } from './start.js'; export { Span, ValueType } from '@opentelemetry/api'; @@ -221,3 +223,45 @@ export function wrapCallbackInSpan any>( } }) as F; } + +export function runInSpan( + tracer: Tracer | string, + spanName: string, + callback: (span: Span, ...args: A) => R, +): (...args: A) => R { + return (...args: A): R => { + const actualTracer = typeof tracer === 'string' ? getTelemetryClient().getTracer(tracer) : tracer; + return actualTracer.startActiveSpan(spanName, (span: Span): R => { + let deferSpanEnd = false; + try { + const res = callback(span, ...args); + if (isPromise(res)) { + deferSpanEnd = true; + return res + .catch(err => { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: String(err), + }); + throw err; + }) + .finally(() => { + span.end(); + }) as R; + } else { + return res; + } + } catch (err) { + span.setStatus({ + code: SpanStatusCode.ERROR, + message: String(err), + }); + throw err; + } finally { + if (!deferSpanEnd) { + span.end(); + } + } + }); + }; +} diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 7884610c4a26..565f1a8578b2 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -74,7 +74,6 @@ import { pickNotes, toACVMWitness, witnessMapToFields, -<<<<<<< HEAD } from '@aztec/simulator/client'; import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures'; import { @@ -85,11 +84,6 @@ import { createSimulationError, resolveAssertionMessageFromError, } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -} from '@aztec/simulator'; -import { createTxForPublicCall } from '@aztec/simulator/public/fixtures'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state'; import { TXENode } from '../node/txe_node.js'; diff --git a/yarn-project/txe/src/txe_service/txe_service.ts b/yarn-project/txe/src/txe_service/txe_service.ts index bf1eb6abc571..9b27a2b5fe92 100644 --- a/yarn-project/txe/src/txe_service/txe_service.ts +++ b/yarn-project/txe/src/txe_service/txe_service.ts @@ -18,14 +18,9 @@ import { openTmpStore } from '@aztec/kv-store/lmdb'; import { protocolContractNames } from '@aztec/protocol-contracts'; import { getCanonicalProtocolContract } from '@aztec/protocol-contracts/bundle'; import { enrichPublicSimulationError } from '@aztec/pxe'; -<<<<<<< HEAD import { type TypedOracle } from '@aztec/simulator/client'; import { HashedValuesCache } from '@aztec/simulator/server'; -import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -======= -import { ExecutionNoteCache, PackedValuesCache, type TypedOracle } from '@aztec/simulator'; import { getTelemetryClient } from '@aztec/telemetry-client'; ->>>>>>> ebdf383f12 (refactor: global telemetry client) import { MerkleTrees } from '@aztec/world-state'; import { TXE } from '../oracle/txe_oracle.js'; @@ -47,15 +42,8 @@ export class TXEService { static async init(logger: Logger) { const store = openTmpStore(true); -<<<<<<< HEAD - const trees = await MerkleTrees.new(store, new NoopTelemetryClient(), logger); - const executionCache = new HashedValuesCache(); -======= const trees = await MerkleTrees.new(store, getTelemetryClient(), logger); - const packedValuesCache = new PackedValuesCache(); - const txHash = new Fr(1); // The txHash is used for computing the revertible nullifiers for non-revertible note hashes. It can be any value for testing. - const noteCache = new ExecutionNoteCache(txHash); ->>>>>>> ebdf383f12 (refactor: global telemetry client) + const executionCache = new HashedValuesCache(); const keyStore = new KeyStore(store); const txeDatabase = new TXEDatabase(store); // Register protocol contracts.