@aztec/p2p 0.87.6 → 0.87.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dest/client/interface.d.ts +1 -1
  2. package/dest/client/interface.d.ts.map +1 -1
  3. package/dest/client/p2p_client.d.ts +2 -2
  4. package/dest/client/p2p_client.d.ts.map +1 -1
  5. package/dest/client/p2p_client.js +3 -3
  6. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  7. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +0 -9
  8. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +1 -0
  9. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  10. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +13 -8
  11. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +1 -0
  12. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  13. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +7 -6
  14. package/dest/mem_pools/instrumentation.d.ts +7 -11
  15. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  16. package/dest/mem_pools/instrumentation.js +25 -37
  17. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +2 -1
  18. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  19. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +22 -38
  20. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +1 -0
  21. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool/memory_tx_pool.js +13 -21
  23. package/dest/services/encoding.d.ts +2 -0
  24. package/dest/services/encoding.d.ts.map +1 -1
  25. package/dest/services/encoding.js +9 -1
  26. package/dest/services/libp2p/instrumentation.d.ts +11 -0
  27. package/dest/services/libp2p/instrumentation.d.ts.map +1 -0
  28. package/dest/services/libp2p/instrumentation.js +29 -0
  29. package/dest/services/libp2p/libp2p_service.d.ts +3 -2
  30. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  31. package/dest/services/libp2p/libp2p_service.js +30 -17
  32. package/dest/services/reqresp/reqresp.d.ts +1 -1
  33. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  34. package/dest/services/reqresp/reqresp.js +9 -5
  35. package/dest/services/tx_collect_instrumentation.d.ts +13 -0
  36. package/dest/services/tx_collect_instrumentation.d.ts.map +1 -0
  37. package/dest/services/tx_collect_instrumentation.js +34 -0
  38. package/dest/services/tx_collector.d.ts +6 -2
  39. package/dest/services/tx_collector.d.ts.map +1 -1
  40. package/dest/services/tx_collector.js +65 -50
  41. package/dest/test-helpers/reqresp-nodes.d.ts +2 -0
  42. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  43. package/dest/test-helpers/reqresp-nodes.js +6 -0
  44. package/package.json +12 -12
  45. package/src/client/interface.ts +1 -1
  46. package/src/client/p2p_client.ts +3 -3
  47. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +0 -14
  48. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +17 -12
  49. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +8 -7
  50. package/src/mem_pools/instrumentation.ts +32 -46
  51. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +23 -58
  52. package/src/mem_pools/tx_pool/memory_tx_pool.ts +14 -26
  53. package/src/services/encoding.ts +9 -1
  54. package/src/services/libp2p/instrumentation.ts +39 -0
  55. package/src/services/libp2p/libp2p_service.ts +41 -15
  56. package/src/services/reqresp/reqresp.ts +6 -6
  57. package/src/services/tx_collect_instrumentation.ts +44 -0
  58. package/src/services/tx_collector.ts +93 -67
  59. package/src/test-helpers/reqresp-nodes.ts +6 -0
@@ -1,11 +1,51 @@
1
1
  import { compactArray } from '@aztec/foundation/collection';
2
2
  import { createLogger } from '@aztec/foundation/log';
3
+ import { getTelemetryClient } from '@aztec/telemetry-client';
4
+ import { TxCollectorInstrumentation } from './tx_collect_instrumentation.js';
3
5
  export class TxCollector {
4
6
  p2pClient;
5
7
  log;
6
- constructor(p2pClient, log = createLogger('p2p:tx-collector')){
8
+ instrumentation;
9
+ constructor(p2pClient, log = createLogger('p2p:tx-collector'), client = getTelemetryClient()){
7
10
  this.p2pClient = p2pClient;
8
11
  this.log = log;
12
+ this.instrumentation = new TxCollectorInstrumentation(client, 'TxCollector');
13
+ }
14
+ // Checks the proposal for transactions we don't already have, validates them and adds them to our pool
15
+ async collectFromProposal(proposal) {
16
+ // Does this proposal have any transactions?
17
+ if (!proposal.txs || proposal.txs.length === 0) {
18
+ return 0;
19
+ }
20
+ const proposalHashes = new Set((proposal.payload.txHashes ?? []).map((txHash)=>txHash.toString()));
21
+ // Get the transactions from the proposal and their hashes
22
+ // also, we are only interested in txs that are part of the proposal
23
+ const txsFromProposal = compactArray(await Promise.all(proposal.txs.map((tx)=>tx === undefined ? Promise.resolve(undefined) : tx.getTxHash().then((hash)=>({
24
+ txHash: hash,
25
+ tx
26
+ }))))).filter((tx)=>proposalHashes.has(tx.txHash.toString()));
27
+ // Of the transactions from the proposal, retrieve those that we have in the pool already
28
+ const txsToValidate = [];
29
+ const txsWeAlreadyHave = await this.p2pClient.getTxsByHashFromPool(txsFromProposal.map((tx)=>tx.txHash));
30
+ // Txs we already have will have holes where we did not find them
31
+ // Where that is the case we need to validate the tx in the proposal
32
+ for(let i = 0; i < txsWeAlreadyHave.length; i++){
33
+ if (txsWeAlreadyHave[i] === undefined) {
34
+ txsToValidate.push(txsFromProposal[i].tx);
35
+ }
36
+ }
37
+ // Now validate all the transactions from the proposal that we don't have
38
+ // This will throw if any of the transactions are invalid, this is probably correct, if someone sends us a proposal with invalid
39
+ // transactions we probably shouldn't spend any more effort on it
40
+ try {
41
+ await this.p2pClient.validate(txsToValidate);
42
+ } catch (err) {
43
+ this.log.error(`Received proposal with invalid transactions, skipping`);
44
+ throw err;
45
+ }
46
+ // Now store these transactions in our pool, provided these are the txs in proposal.payload.txHashes they will be pinned already
47
+ await this.p2pClient.addTxsToPool(txsToValidate);
48
+ return txsToValidate.length;
9
49
  }
10
50
  async collectForBlockProposal(proposal, peerWhoSentTheProposal) {
11
51
  if (proposal.payload.txHashes.length === 0) {
@@ -14,57 +54,32 @@ export class TxCollector {
14
54
  txs: []
15
55
  };
16
56
  }
17
- // Is this a new style proposal?
18
- if (proposal.txs && proposal.txs.length > 0 && proposal.txs.length === proposal.payload.txHashes.length) {
19
- // Yes, any txs that we already have we should use
20
- this.log.info(`Using new style proposal with ${proposal.txs.length} transactions`);
21
- // Request from the pool based on the signed hashes in the payload
22
- const hashesFromPayload = proposal.payload.txHashes;
23
- const txsToUse = await this.p2pClient.getTxsByHashFromPool(hashesFromPayload);
24
- const missingTxs = txsToUse.filter((tx)=>tx === undefined).length;
25
- if (missingTxs > 0) {
26
- this.log.verbose(`Missing ${missingTxs}/${hashesFromPayload.length} transactions in the tx pool, will attempt to take from the proposal`);
27
- }
28
- let usedFromProposal = 0;
29
- // Fill any holes with txs in the proposal, provided their hash matches the hash in the payload
30
- for(let i = 0; i < txsToUse.length; i++){
31
- if (txsToUse[i] === undefined) {
32
- // We don't have the transaction, take from the proposal, provided the hash is the same
33
- const hashOfTxInProposal = await proposal.txs[i].getTxHash();
34
- if (hashOfTxInProposal.equals(hashesFromPayload[i])) {
35
- // Hash is equal, we can use the tx from the proposal
36
- txsToUse[i] = proposal.txs[i];
37
- usedFromProposal++;
38
- } else {
39
- this.log.warn(`Unable to take tx: ${hashOfTxInProposal.toString()} from the proposal, it does not match payload hash: ${hashesFromPayload[i].toString()}`);
40
- }
41
- }
42
- }
43
- // See if we still have any holes, if there are then we were not successful and will try the old method
44
- if (txsToUse.some((tx)=>tx === undefined)) {
45
- this.log.warn(`Failed to use transactions from proposal. Falling back to old proposal logic`);
46
- } else {
47
- this.log.info(`Successfully used ${usedFromProposal}/${hashesFromPayload.length} transactions from the proposal`);
48
- await this.p2pClient.validate(txsToUse);
49
- return {
50
- txs: txsToUse
51
- };
52
- }
53
- }
54
- this.log.info(`Using old style proposal with ${proposal.payload.txHashes.length} transactions`);
55
- // Old style proposal, we will perform a request by hash from pool
56
- // This will request from network any txs that are missing
57
+ const txsInMempool = (await this.p2pClient.hasTxsInPool(proposal.payload.txHashes)).filter(Boolean).length;
58
+ this.instrumentation.incTxsFromMempool(txsInMempool);
59
+ // Take txs from the proposal if there are any
60
+ const txTakenFromProposal = await this.collectFromProposal(proposal);
61
+ this.instrumentation.incTxsFromProposals(txTakenFromProposal);
62
+ // Now get the txs we need, either from the pool or the p2p network
57
63
  const txHashes = proposal.payload.txHashes;
58
- // This part is just for logging that we are requesting from the network
59
- const availability = await this.p2pClient.hasTxsInPool(txHashes);
60
- const notAvailable = availability.filter((availability)=>availability === false);
61
- if (notAvailable.length) {
62
- this.log.verbose(`Missing ${notAvailable.length} transactions in the tx pool, will need to request from the network`);
63
- }
64
64
  // This will request from the network any txs that are missing
65
- const retrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
66
- const missingTxs = compactArray(retrievedTxs.map((tx, index)=>tx === undefined ? txHashes[index] : undefined));
67
- await this.p2pClient.validate(retrievedTxs);
65
+ // NOTE: this could still return missing txs so we need to (1) be careful to handle undefined and (2) keep the txs in the correct order for re-execution
66
+ const maybeRetrievedTxs = await this.p2pClient.getTxsByHash(txHashes, peerWhoSentTheProposal);
67
+ // Get the txs that we didn't get from the network, if any. This will be empty if we got them al
68
+ const missingTxs = compactArray(maybeRetrievedTxs.map((tx, index)=>tx === undefined ? txHashes[index] : undefined));
69
+ this.instrumentation.incMissingTxs(missingTxs.length);
70
+ const txsFromP2P = txHashes.length - txTakenFromProposal - txsInMempool - missingTxs.length;
71
+ this.instrumentation.incTxsFromP2P(txsFromP2P);
72
+ // if we found all txs, this is a noop. If we didn't find all txs then tell the validator to skip attestations because missingTxs.length > 0
73
+ const retrievedTxs = compactArray(maybeRetrievedTxs);
74
+ this.log.info(`Retrieved ${retrievedTxs.length}/${txHashes.length} txs for block proposal`, {
75
+ blockNumber: proposal.blockNumber.toNumber(),
76
+ slotNumber: proposal.slotNumber.toNumber(),
77
+ totalTxsInProposal: txHashes.length,
78
+ txsFromProposal: txTakenFromProposal,
79
+ txsFromMempool: txsInMempool,
80
+ txsFromP2P,
81
+ missingTxs: missingTxs.length
82
+ });
68
83
  return {
69
84
  txs: retrievedTxs,
70
85
  missing: missingTxs
@@ -49,9 +49,11 @@ export declare const stopNodes: (nodes: ReqRespNode[]) => Promise<void>;
49
49
  export declare const createReqResp: (peerScoring: PeerScoring, rateLimits?: Partial<ReqRespSubProtocolRateLimits>) => Promise<ReqRespNode>;
50
50
  export declare const connectToPeers: (nodes: ReqRespNode[]) => Promise<void>;
51
51
  export declare class AlwaysTrueCircuitVerifier implements ClientProtocolCircuitVerifier {
52
+ stop(): Promise<void>;
52
53
  verifyProof(_tx: Tx): Promise<boolean>;
53
54
  }
54
55
  export declare class AlwaysFalseCircuitVerifier implements ClientProtocolCircuitVerifier {
56
+ stop(): Promise<void>;
55
57
  verifyProof(_tx: Tx): Promise<boolean>;
56
58
  }
57
59
  export declare function createBootstrapNodeConfig(privateKey: string, port: number, chainConfig: ChainConfig): BootnodeConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reqresp-nodes.d.ts","sourceRoot":"","sources":["../../src/test-helpers/reqresp-nodes.ts"],"names":[],"mappings":"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"}
@@ -154,11 +154,17 @@ export const connectToPeers = async (nodes)=>{
154
154
  };
155
155
  // Mock circuit verifier for testing - reimplementation from bb to avoid dependency
156
156
  export class AlwaysTrueCircuitVerifier {
157
+ stop() {
158
+ return Promise.resolve();
159
+ }
157
160
  verifyProof(_tx) {
158
161
  return Promise.resolve(true);
159
162
  }
160
163
  }
161
164
  export class AlwaysFalseCircuitVerifier {
165
+ stop() {
166
+ return Promise.resolve();
167
+ }
162
168
  verifyProof(_tx) {
163
169
  return Promise.resolve(false);
164
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/p2p",
3
- "version": "0.87.6",
3
+ "version": "0.87.8",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -63,16 +63,16 @@
63
63
  ]
64
64
  },
65
65
  "dependencies": {
66
- "@aztec/constants": "0.87.6",
67
- "@aztec/epoch-cache": "0.87.6",
68
- "@aztec/foundation": "0.87.6",
69
- "@aztec/kv-store": "0.87.6",
70
- "@aztec/noir-contracts.js": "0.87.6",
71
- "@aztec/noir-protocol-circuits-types": "0.87.6",
72
- "@aztec/protocol-contracts": "0.87.6",
73
- "@aztec/simulator": "0.87.6",
74
- "@aztec/stdlib": "0.87.6",
75
- "@aztec/telemetry-client": "0.87.6",
66
+ "@aztec/constants": "0.87.8",
67
+ "@aztec/epoch-cache": "0.87.8",
68
+ "@aztec/foundation": "0.87.8",
69
+ "@aztec/kv-store": "0.87.8",
70
+ "@aztec/noir-contracts.js": "0.87.8",
71
+ "@aztec/noir-protocol-circuits-types": "0.87.8",
72
+ "@aztec/protocol-contracts": "0.87.8",
73
+ "@aztec/simulator": "0.87.8",
74
+ "@aztec/stdlib": "0.87.8",
75
+ "@aztec/telemetry-client": "0.87.8",
76
76
  "@chainsafe/discv5": "9.0.0",
77
77
  "@chainsafe/enr": "3.0.0",
78
78
  "@chainsafe/libp2p-gossipsub": "13.0.0",
@@ -101,7 +101,7 @@
101
101
  "xxhash-wasm": "^1.1.0"
102
102
  },
103
103
  "devDependencies": {
104
- "@aztec/archiver": "0.87.6",
104
+ "@aztec/archiver": "0.87.8",
105
105
  "@jest/globals": "^29.5.0",
106
106
  "@types/jest": "^29.5.0",
107
107
  "@types/node": "^22.15.17",
@@ -78,7 +78,7 @@ export type P2P<T extends P2PClientType = P2PClientType.Full> = P2PApi<T> & {
78
78
  * Adds transactions to the pool. Does not send to peers or validate the tx.
79
79
  * @param txs - The transactions.
80
80
  **/
81
- addTxs(txs: Tx[]): Promise<void>;
81
+ addTxsToPool(txs: Tx[]): Promise<void>;
82
82
 
83
83
  /**
84
84
  * Deletes 'txs' from the pool, given hashes.
@@ -444,7 +444,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
444
444
  /**
445
445
  * Returns transactions in the transaction pool by hash.
446
446
  * @param txHashes - Hashes of the transactions to look for.
447
- * @returns The txs found, not necessarily on the same order as the hashes.
447
+ * @returns The txs found, in the same order as the requested hashes. If a tx is not found, it will be undefined.
448
448
  */
449
449
  getTxsByHashFromPool(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
450
450
  return this.txPool.getTxsByHash(txHashes);
@@ -527,7 +527,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
527
527
  * @returns Empty promise.
528
528
  **/
529
529
  public async sendTx(tx: Tx): Promise<void> {
530
- await this.addTxs([tx]);
530
+ await this.addTxsToPool([tx]);
531
531
  await this.p2pService.propagate(tx);
532
532
  }
533
533
 
@@ -535,7 +535,7 @@ export class P2PClient<T extends P2PClientType = P2PClientType.Full>
535
535
  * Adds transactions to the pool. Does not send to peers or validate the txs.
536
536
  * @param txs - The transactions.
537
537
  **/
538
- public async addTxs(txs: Tx[]): Promise<void> {
538
+ public async addTxsToPool(txs: Tx[]): Promise<void> {
539
539
  this.#assertIsReady();
540
540
  await this.txPool.addTxs(txs);
541
541
  }
@@ -49,9 +49,6 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
49
49
 
50
50
  await ap.addAttestations(attestations);
51
51
 
52
- // Check metrics have been updated.
53
- expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
54
-
55
52
  const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
56
53
  expect(retrievedAttestations.length).toBe(attestations.length);
57
54
  compareAttestations(retrievedAttestations, attestations);
@@ -63,7 +60,6 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
63
60
  // Add another one
64
61
  const newAttestation = mockAttestation(signers[NUMBER_OF_SIGNERS_PER_TEST - 1], slotNumber, archive);
65
62
  await ap.addAttestations([newAttestation]);
66
- expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(1);
67
63
  const retrievedAttestationsAfterAdd = await ap.getAttestationsForSlotAndProposal(
68
64
  BigInt(slotNumber),
69
65
  archive.toString(),
@@ -76,7 +72,6 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
76
72
 
77
73
  // Delete by slot
78
74
  await ap.deleteAttestationsForSlot(BigInt(slotNumber));
79
- expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length + 1);
80
75
 
81
76
  const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
82
77
  BigInt(slotNumber),
@@ -154,16 +149,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
154
149
 
155
150
  await ap.addAttestations(attestations);
156
151
 
157
- expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
158
-
159
152
  const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
160
153
  expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
161
154
  compareAttestations(retreivedAttestations, attestations);
162
155
 
163
156
  await ap.deleteAttestations(attestations);
164
157
 
165
- expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length);
166
-
167
158
  const gottenAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
168
159
  expect(gottenAfterDelete.length).toBe(0);
169
160
  });
@@ -200,17 +191,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
200
191
  await ap.addAttestations(attestations);
201
192
  await ap.addAttestations(attestations2);
202
193
 
203
- expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations.length);
204
- expect(metricsMock.recordAddedObjects).toHaveBeenCalledWith(attestations2.length);
205
-
206
194
  const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
207
195
  expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
208
196
  compareAttestations(retreivedAttestations, attestations);
209
197
 
210
198
  await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
211
199
 
212
- expect(metricsMock.recordRemovedObjects).toHaveBeenCalledWith(attestations.length);
213
-
214
200
  const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
215
201
  expect(retreivedAttestationsAfterDelete.length).toBe(0);
216
202
 
@@ -5,7 +5,7 @@ import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@azte
5
5
  import { BlockAttestation } from '@aztec/stdlib/p2p';
6
6
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
7
7
 
8
- import { PoolInstrumentation, PoolName } from '../instrumentation.js';
8
+ import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
9
9
  import type { AttestationPool } from './attestation_pool.js';
10
10
 
11
11
  export class KvAttestationPool implements AttestationPool {
@@ -24,9 +24,15 @@ export class KvAttestationPool implements AttestationPool {
24
24
  this.proposalsForSlot = store.openMultiMap('proposals_for_slot');
25
25
  this.attestationsForProposal = store.openMultiMap('attestations_for_proposal');
26
26
 
27
- this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL);
27
+ this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL, this.poolStats);
28
28
  }
29
29
 
30
+ private poolStats: PoolStatsCallback = async () => {
31
+ return {
32
+ itemCount: await this.attestations.sizeAsync(),
33
+ };
34
+ };
35
+
30
36
  public async isEmpty(): Promise<boolean> {
31
37
  for await (const _ of this.attestations.entriesAsync()) {
32
38
  return false;
@@ -73,8 +79,6 @@ export class KvAttestationPool implements AttestationPool {
73
79
  });
74
80
  }
75
81
  });
76
-
77
- this.metrics.recordAddedObjects(attestations.length);
78
82
  }
79
83
 
80
84
  public async getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]> {
@@ -135,10 +139,9 @@ export class KvAttestationPool implements AttestationPool {
135
139
 
136
140
  await this.attestationsForProposal.delete(this.getProposalKey(slotFr, proposalId));
137
141
  }
138
- });
139
142
 
140
- this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
141
- this.metrics.recordRemovedObjects(numberOfAttestations);
143
+ this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
144
+ });
142
145
  }
143
146
 
144
147
  public async deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void> {
@@ -156,10 +159,9 @@ export class KvAttestationPool implements AttestationPool {
156
159
 
157
160
  await this.proposalsForSlot.deleteValue(slotString, proposalId);
158
161
  await this.attestationsForProposal.delete(this.getProposalKey(slotString, proposalId));
159
- });
160
162
 
161
- this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
162
- this.metrics.recordRemovedObjects(numberOfAttestations);
163
+ this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
164
+ });
163
165
  }
164
166
 
165
167
  public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
@@ -168,8 +170,12 @@ export class KvAttestationPool implements AttestationPool {
168
170
  const slotNumber = attestation.payload.header.slotNumber;
169
171
  const proposalId = attestation.archive;
170
172
  const address = attestation.getSender().toString();
173
+ const key = this.getAttestationKey(slotNumber, proposalId, address);
174
+
175
+ if (await this.attestations.hasAsync(key)) {
176
+ await this.attestations.delete(key);
177
+ }
171
178
 
172
- await this.attestations.delete(this.getAttestationKey(slotNumber, proposalId, address));
173
179
  await this.attestationsForProposal.deleteValue(
174
180
  this.getProposalKey(slotNumber, proposalId),
175
181
  this.getAttestationKey(slotNumber, proposalId, address),
@@ -178,6 +184,5 @@ export class KvAttestationPool implements AttestationPool {
178
184
  this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
179
185
  }
180
186
  });
181
- this.metrics.recordRemovedObjects(attestations.length);
182
187
  }
183
188
  }
@@ -2,7 +2,7 @@ import { createLogger } from '@aztec/foundation/log';
2
2
  import type { BlockAttestation } from '@aztec/stdlib/p2p';
3
3
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
4
4
 
5
- import { PoolInstrumentation, PoolName } from '../instrumentation.js';
5
+ import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
6
6
  import type { AttestationPool } from './attestation_pool.js';
7
7
 
8
8
  export class InMemoryAttestationPool implements AttestationPool {
@@ -15,9 +15,15 @@ export class InMemoryAttestationPool implements AttestationPool {
15
15
  private log = createLogger('p2p:attestation_pool'),
16
16
  ) {
17
17
  this.attestations = new Map();
18
- this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL);
18
+ this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL, this.poolStats);
19
19
  }
20
20
 
21
+ private poolStats: PoolStatsCallback = () => {
22
+ return Promise.resolve({
23
+ itemCount: this.attestations.size,
24
+ });
25
+ };
26
+
21
27
  public isEmpty(): Promise<boolean> {
22
28
  return Promise.resolve(this.attestations.size === 0);
23
29
  }
@@ -61,8 +67,6 @@ export class InMemoryAttestationPool implements AttestationPool {
61
67
  });
62
68
  }
63
69
 
64
- // TODO: set these to pending or something ????
65
- this.metrics.recordAddedObjects(attestations.length);
66
70
  return Promise.resolve();
67
71
  }
68
72
 
@@ -106,7 +110,6 @@ export class InMemoryAttestationPool implements AttestationPool {
106
110
  this.attestations.delete(slot);
107
111
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
108
112
 
109
- this.metrics.recordRemovedObjects(numberOfAttestations);
110
113
  return Promise.resolve();
111
114
  }
112
115
 
@@ -119,7 +122,6 @@ export class InMemoryAttestationPool implements AttestationPool {
119
122
  slotAttestationMap.delete(proposalId);
120
123
 
121
124
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
122
- this.metrics.recordRemovedObjects(numberOfAttestations);
123
125
  }
124
126
  }
125
127
  return Promise.resolve();
@@ -139,7 +141,6 @@ export class InMemoryAttestationPool implements AttestationPool {
139
141
  }
140
142
  }
141
143
  }
142
- this.metrics.recordRemovedObjects(attestations.length);
143
144
  return Promise.resolve();
144
145
  }
145
146
  }
@@ -1,13 +1,15 @@
1
1
  import type { Gossipable } from '@aztec/stdlib/p2p';
2
2
  import {
3
3
  Attributes,
4
+ type BatchObservableResult,
4
5
  type Histogram,
5
6
  LmdbMetrics,
6
7
  type LmdbStatsCallback,
8
+ type Meter,
7
9
  Metrics,
8
10
  type MetricsType,
11
+ type ObservableGauge,
9
12
  type TelemetryClient,
10
- type UpDownCounter,
11
13
  } from '@aztec/telemetry-client';
12
14
 
13
15
  export enum PoolName {
@@ -41,86 +43,70 @@ function getMetricsLabels(name: PoolName): MetricsLabels {
41
43
  throw new Error('Invalid pool type');
42
44
  }
43
45
 
46
+ export type PoolStatsCallback = () => Promise<{
47
+ itemCount: number | Record<string, number>;
48
+ }>;
49
+
44
50
  /**
45
51
  * Instrumentation class for the Pools (TxPool, AttestationPool, etc).
46
52
  */
47
53
  export class PoolInstrumentation<PoolObject extends Gossipable> {
48
54
  /** The number of txs in the mempool */
49
- private objectsInMempool: UpDownCounter;
55
+ private objectsInMempool: ObservableGauge;
50
56
  /** Tracks tx size */
51
57
  private objectSize: Histogram;
52
58
 
53
59
  private dbMetrics: LmdbMetrics;
54
60
 
55
61
  private defaultAttributes;
56
-
57
- constructor(telemetry: TelemetryClient, name: PoolName, dbStats?: LmdbStatsCallback) {
58
- const meter = telemetry.getMeter(name);
62
+ private meter: Meter;
63
+
64
+ constructor(
65
+ telemetry: TelemetryClient,
66
+ name: PoolName,
67
+ private poolStats: PoolStatsCallback,
68
+ dbStats?: LmdbStatsCallback,
69
+ ) {
70
+ this.meter = telemetry.getMeter(name);
59
71
  this.defaultAttributes = { [Attributes.POOL_NAME]: name };
60
72
 
61
73
  const metricsLabels = getMetricsLabels(name);
62
74
 
63
- this.objectsInMempool = meter.createUpDownCounter(metricsLabels.objectInMempool, {
75
+ this.objectsInMempool = this.meter.createObservableGauge(metricsLabels.objectInMempool, {
64
76
  description: 'The current number of transactions in the mempool',
65
77
  });
66
78
 
67
- this.objectSize = meter.createHistogram(metricsLabels.objectSize, {
79
+ this.objectSize = this.meter.createHistogram(metricsLabels.objectSize, {
68
80
  unit: 'By',
69
81
  description: 'The size of transactions in the mempool',
70
82
  });
71
83
 
72
84
  this.dbMetrics = new LmdbMetrics(
73
- meter,
85
+ this.meter,
74
86
  {
75
87
  [Attributes.DB_DATA_TYPE]: 'tx-pool',
76
88
  },
77
89
  dbStats,
78
90
  );
91
+
92
+ this.meter.addBatchObservableCallback(this.observeStats, [this.objectsInMempool]);
79
93
  }
80
94
 
81
95
  public recordSize(poolObject: PoolObject) {
82
96
  this.objectSize.record(poolObject.getSize());
83
97
  }
84
98
 
85
- /**
86
- * Updates the metrics with the new objects.
87
- * @param txs - The objects to record
88
- */
89
- public recordAddedObjects(count = 1, status?: string) {
90
- if (count < 0) {
91
- throw new Error('Count must be positive');
92
- }
93
- if (count === 0) {
94
- return;
95
- }
96
- const attributes = status
97
- ? {
99
+ private observeStats = async (observer: BatchObservableResult) => {
100
+ const { itemCount } = await this.poolStats();
101
+ if (typeof itemCount === 'number') {
102
+ observer.observe(this.objectsInMempool, itemCount, this.defaultAttributes);
103
+ } else {
104
+ for (const [status, count] of Object.entries(itemCount)) {
105
+ observer.observe(this.objectsInMempool, count, {
98
106
  ...this.defaultAttributes,
99
107
  [Attributes.STATUS]: status,
100
- }
101
- : this.defaultAttributes;
102
-
103
- this.objectsInMempool.add(count, attributes);
104
- }
105
-
106
- /**
107
- * Updates the metrics by removing objects from the mempool.
108
- * @param count - The number of objects to remove from the mempool
109
- */
110
- public recordRemovedObjects(count = 1, status?: string) {
111
- if (count < 0) {
112
- throw new Error('Count must be positive');
113
- }
114
- if (count === 0) {
115
- return;
108
+ });
109
+ }
116
110
  }
117
-
118
- const attributes = status
119
- ? {
120
- ...this.defaultAttributes,
121
- [Attributes.STATUS]: status,
122
- }
123
- : this.defaultAttributes;
124
- this.objectsInMempool.add(-1 * count, attributes);
125
- }
111
+ };
126
112
  }