@aztec/p2p 0.71.0 → 0.73.0

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 (153) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +2 -2
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +1 -1
  4. package/dest/client/factory.js +4 -4
  5. package/dest/client/p2p_client.d.ts +13 -16
  6. package/dest/client/p2p_client.d.ts.map +1 -1
  7. package/dest/client/p2p_client.js +55 -67
  8. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  9. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +11 -19
  10. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +6 -13
  11. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  12. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +74 -80
  13. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  14. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +5 -5
  15. package/dest/mem_pools/attestation_pool/mocks.d.ts +3 -2
  16. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  17. package/dest/mem_pools/attestation_pool/mocks.js +3 -3
  18. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +9 -9
  19. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  20. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +60 -54
  21. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +7 -7
  22. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  23. package/dest/mem_pools/tx_pool/memory_tx_pool.js +17 -18
  24. package/dest/mem_pools/tx_pool/tx_pool.d.ts +7 -7
  25. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  27. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +48 -47
  28. package/dest/mocks/index.d.ts +3 -3
  29. package/dest/mocks/index.d.ts.map +1 -1
  30. package/dest/mocks/index.js +19 -18
  31. package/dest/msg_validators/attestation_validator/attestation_validator.js +2 -2
  32. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +2 -2
  33. package/dest/msg_validators/tx_validator/block_header_validator.js +3 -3
  34. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  35. package/dest/msg_validators/tx_validator/data_validator.js +7 -7
  36. package/dest/msg_validators/tx_validator/double_spend_validator.js +3 -3
  37. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  38. package/dest/msg_validators/tx_validator/metadata_validator.js +9 -9
  39. package/dest/services/data_store.d.ts +4 -4
  40. package/dest/services/data_store.d.ts.map +1 -1
  41. package/dest/services/data_store.js +7 -7
  42. package/dest/services/dummy_service.d.ts +7 -0
  43. package/dest/services/dummy_service.d.ts.map +1 -1
  44. package/dest/services/dummy_service.js +10 -1
  45. package/dest/services/libp2p/libp2p_service.d.ts +19 -15
  46. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  47. package/dest/services/libp2p/libp2p_service.js +163 -134
  48. package/dest/services/peer-manager/metrics.d.ts +12 -0
  49. package/dest/services/peer-manager/metrics.d.ts.map +1 -0
  50. package/dest/services/peer-manager/metrics.js +26 -0
  51. package/dest/services/{peer_manager.d.ts → peer-manager/peer_manager.d.ts} +24 -8
  52. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -0
  53. package/dest/services/peer-manager/peer_manager.js +395 -0
  54. package/dest/services/{peer-scoring → peer-manager}/peer_scoring.d.ts +3 -0
  55. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -0
  56. package/dest/services/peer-manager/peer_scoring.js +84 -0
  57. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +45 -0
  58. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -0
  59. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +81 -0
  60. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +61 -0
  61. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -0
  62. package/dest/services/reqresp/connection-sampler/connection_sampler.js +175 -0
  63. package/dest/services/reqresp/interface.d.ts +17 -4
  64. package/dest/services/reqresp/interface.d.ts.map +1 -1
  65. package/dest/services/reqresp/interface.js +34 -11
  66. package/dest/services/reqresp/metrics.d.ts +15 -0
  67. package/dest/services/reqresp/metrics.d.ts.map +1 -0
  68. package/dest/services/reqresp/metrics.js +42 -0
  69. package/dest/services/reqresp/protocols/block.d.ts +4 -0
  70. package/dest/services/reqresp/protocols/block.d.ts.map +1 -0
  71. package/dest/services/reqresp/protocols/block.js +9 -0
  72. package/dest/services/reqresp/protocols/goodbye.d.ts +51 -0
  73. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -0
  74. package/dest/services/reqresp/protocols/goodbye.js +92 -0
  75. package/dest/services/reqresp/protocols/index.d.ts +9 -0
  76. package/dest/services/reqresp/protocols/index.d.ts.map +1 -0
  77. package/dest/services/reqresp/protocols/index.js +9 -0
  78. package/dest/services/reqresp/protocols/ping.d.ts +9 -0
  79. package/dest/services/reqresp/protocols/ping.d.ts.map +1 -0
  80. package/dest/services/reqresp/protocols/ping.js +9 -0
  81. package/dest/services/reqresp/{handlers.d.ts → protocols/status.d.ts} +1 -7
  82. package/dest/services/reqresp/protocols/status.d.ts.map +1 -0
  83. package/dest/services/reqresp/protocols/status.js +9 -0
  84. package/dest/services/reqresp/protocols/tx.d.ts +13 -0
  85. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -0
  86. package/dest/services/reqresp/protocols/tx.js +23 -0
  87. package/dest/services/reqresp/rate-limiter/index.d.ts.map +1 -0
  88. package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.js +1 -1
  89. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts +3 -3
  90. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.d.ts.map +1 -1
  91. package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.js +4 -4
  92. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -0
  93. package/dest/services/reqresp/rate-limiter/rate_limits.js +55 -0
  94. package/dest/services/reqresp/reqresp.d.ts +33 -6
  95. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  96. package/dest/services/reqresp/reqresp.js +414 -249
  97. package/dest/services/service.d.ts +8 -0
  98. package/dest/services/service.d.ts.map +1 -1
  99. package/dest/util.d.ts +6 -2
  100. package/dest/util.d.ts.map +1 -1
  101. package/dest/util.js +2 -2
  102. package/package.json +8 -8
  103. package/src/bootstrap/bootstrap.ts +2 -2
  104. package/src/client/factory.ts +3 -3
  105. package/src/client/p2p_client.ts +68 -80
  106. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +14 -22
  107. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +100 -94
  108. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +4 -4
  109. package/src/mem_pools/attestation_pool/mocks.ts +5 -5
  110. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +84 -73
  111. package/src/mem_pools/tx_pool/memory_tx_pool.ts +26 -23
  112. package/src/mem_pools/tx_pool/tx_pool.ts +7 -7
  113. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +50 -47
  114. package/src/mocks/index.ts +19 -20
  115. package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
  116. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +1 -1
  117. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  118. package/src/msg_validators/tx_validator/data_validator.ts +12 -9
  119. package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
  120. package/src/msg_validators/tx_validator/metadata_validator.ts +8 -8
  121. package/src/services/data_store.ts +9 -9
  122. package/src/services/dummy_service.ts +13 -0
  123. package/src/services/libp2p/libp2p_service.ts +212 -163
  124. package/src/services/peer-manager/metrics.ts +41 -0
  125. package/src/services/{peer_manager.ts → peer-manager/peer_manager.ts} +73 -23
  126. package/src/services/{peer-scoring → peer-manager}/peer_scoring.ts +16 -3
  127. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +94 -0
  128. package/src/services/reqresp/connection-sampler/connection_sampler.ts +211 -0
  129. package/src/services/reqresp/interface.ts +39 -16
  130. package/src/services/reqresp/metrics.ts +57 -0
  131. package/src/services/reqresp/protocols/block.ts +15 -0
  132. package/src/services/reqresp/protocols/goodbye.ts +101 -0
  133. package/src/services/reqresp/protocols/index.ts +8 -0
  134. package/src/services/reqresp/protocols/ping.ts +8 -0
  135. package/src/services/reqresp/{handlers.ts → protocols/status.ts} +0 -9
  136. package/src/services/reqresp/protocols/tx.ts +29 -0
  137. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limiter.ts +3 -3
  138. package/src/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.ts +24 -4
  139. package/src/services/reqresp/reqresp.ts +231 -26
  140. package/src/services/service.ts +12 -0
  141. package/src/util.ts +11 -4
  142. package/dest/services/peer-scoring/peer_scoring.d.ts.map +0 -1
  143. package/dest/services/peer-scoring/peer_scoring.js +0 -75
  144. package/dest/services/peer_manager.d.ts.map +0 -1
  145. package/dest/services/peer_manager.js +0 -358
  146. package/dest/services/reqresp/handlers.d.ts.map +0 -1
  147. package/dest/services/reqresp/handlers.js +0 -17
  148. package/dest/services/reqresp/rate_limiter/index.d.ts.map +0 -1
  149. package/dest/services/reqresp/rate_limiter/rate_limits.d.ts.map +0 -1
  150. package/dest/services/reqresp/rate_limiter/rate_limits.js +0 -35
  151. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/index.d.ts +0 -0
  152. /package/dest/services/reqresp/{rate_limiter → rate-limiter}/rate_limits.d.ts +0 -0
  153. /package/src/services/reqresp/{rate_limiter → rate-limiter}/index.ts +0 -0
@@ -29,7 +29,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
29
29
 
30
30
  const createAttestationsForSlot = (slotNumber: number) => {
31
31
  const archive = Fr.random();
32
- return signers.map(signer => mockAttestation(signer, slotNumber, archive));
32
+ return Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
33
33
  };
34
34
 
35
35
  // We compare buffers as the objects can have cached values attached to them which are not serialised
@@ -44,7 +44,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
44
44
  it('should add attestations to pool', async () => {
45
45
  const slotNumber = 420;
46
46
  const archive = Fr.random();
47
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
47
+ const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
48
48
 
49
49
  await ap.addAttestations(attestations);
50
50
 
@@ -75,7 +75,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
75
75
  const attestations: BlockAttestation[] = [];
76
76
  const signer = signers[0];
77
77
  for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
78
- attestations.push(mockAttestation(signer, slotNumber, archive, txs));
78
+ attestations.push(await mockAttestation(signer, slotNumber, archive, txs));
79
79
  }
80
80
 
81
81
  await ap.addAttestations(attestations);
@@ -84,12 +84,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
84
84
  expect(retreivedAttestations.length).toBe(1);
85
85
  expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
86
86
  expect(retreivedAttestations[0].payload.txHashes).toEqual(txs);
87
- expect(retreivedAttestations[0].getSender().toString()).toEqual(signer.address.toString());
87
+ expect((await retreivedAttestations[0].getSender()).toString()).toEqual(signer.address.toString());
88
88
  });
89
89
 
90
90
  it('Should store attestations by differing slot', async () => {
91
91
  const slotNumbers = [1, 2, 3, 4];
92
- const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i]));
92
+ const attestations = await Promise.all(signers.map((signer, i) => mockAttestation(signer, slotNumbers[i])));
93
93
 
94
94
  await ap.addAttestations(attestations);
95
95
 
@@ -107,7 +107,9 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
107
107
  it('Should store attestations by differing slot and archive', async () => {
108
108
  const slotNumbers = [1, 1, 2, 3];
109
109
  const archives = [Fr.random(), Fr.random(), Fr.random(), Fr.random()];
110
- const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i], archives[i]));
110
+ const attestations = await Promise.all(
111
+ signers.map((signer, i) => mockAttestation(signer, slotNumbers[i], archives[i])),
112
+ );
111
113
 
112
114
  await ap.addAttestations(attestations);
113
115
 
@@ -125,7 +127,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
125
127
  it('Should delete attestations', async () => {
126
128
  const slotNumber = 420;
127
129
  const archive = Fr.random();
128
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
130
+ const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
129
131
  const proposalId = attestations[0].archive.toString();
130
132
 
131
133
  await ap.addAttestations(attestations);
@@ -165,12 +167,12 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
165
167
  it('Should blanket delete attestations per slot and proposal', async () => {
166
168
  const slotNumber = 420;
167
169
  const archive = Fr.random();
168
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
170
+ const attestations = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive)));
169
171
  const proposalId = attestations[0].archive.toString();
170
172
 
171
173
  // Add another set of attestations with a different proposalId, yet the same slot
172
174
  const archive2 = Fr.random();
173
- const attestations2 = signers.map(signer => mockAttestation(signer, slotNumber, archive2));
175
+ const attestations2 = await Promise.all(signers.map(signer => mockAttestation(signer, slotNumber, archive2)));
174
176
  const proposalId2 = attestations2[0].archive.toString();
175
177
 
176
178
  await ap.addAttestations(attestations);
@@ -198,21 +200,11 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
198
200
  compareAttestations(retreivedAttestationsAfterDeleteForOtherProposal, attestations2);
199
201
  });
200
202
 
201
- it('Should blanket delete attestations per slot and proposal (does not perform db ops if there are no attestations)', async () => {
202
- const slotNumber = 420;
203
- const proposalId = 'proposalId';
204
-
205
- const retreivedAttestations = await ap.getAttestationsForSlot(BigInt(slotNumber), proposalId);
206
- expect(retreivedAttestations.length).toBe(0);
207
-
208
- await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
209
-
210
- expect(metricsMock.recordRemovedObjects).toHaveBeenCalledTimes(0);
211
- });
212
-
213
203
  it('Should delete attestations older than a given slot', async () => {
214
204
  const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
215
- const attestations = slotNumbers.map(slotNumber => createAttestationsForSlot(slotNumber)).flat();
205
+ const attestations = (
206
+ await Promise.all(slotNumbers.map(slotNumber => createAttestationsForSlot(slotNumber)))
207
+ ).flat();
216
208
  const proposalId = attestations[0].archive.toString();
217
209
 
218
210
  await ap.addAttestations(attestations);
@@ -1,7 +1,8 @@
1
1
  import { BlockAttestation } from '@aztec/circuit-types';
2
2
  import { Fr } from '@aztec/foundation/fields';
3
+ import { toArray } from '@aztec/foundation/iterable';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
- import { type AztecKVStore, type AztecMapWithSize, type AztecMultiMap } from '@aztec/kv-store';
5
+ import { type AztecAsyncKVStore, type AztecAsyncMap, type AztecAsyncMultiMap } from '@aztec/kv-store';
5
6
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
6
7
 
7
8
  import { PoolInstrumentation, PoolName } from '../instrumentation.js';
@@ -10,144 +11,149 @@ import { type AttestationPool } from './attestation_pool.js';
10
11
  export class KvAttestationPool implements AttestationPool {
11
12
  private metrics: PoolInstrumentation<BlockAttestation>;
12
13
 
13
- // Index of all proposal ids in a slot
14
- private attestations: AztecMultiMap<string, string>;
14
+ private attestations: AztecAsyncMap<string, Buffer>;
15
+ private proposalsForSlot: AztecAsyncMultiMap<string, string>;
16
+ private attestationsForProposal: AztecAsyncMultiMap<string, string>;
15
17
 
16
18
  constructor(
17
- private store: AztecKVStore,
19
+ private store: AztecAsyncKVStore,
18
20
  telemetry: TelemetryClient = getTelemetryClient(),
19
21
  private log = createLogger('aztec:attestation_pool'),
20
22
  ) {
21
- this.attestations = store.openMultiMap('attestations');
23
+ this.attestations = store.openMap('attestations');
24
+ this.proposalsForSlot = store.openMultiMap('proposals_for_slot');
25
+ this.attestationsForProposal = store.openMultiMap('attestations_for_proposal');
26
+
22
27
  this.metrics = new PoolInstrumentation(telemetry, PoolName.ATTESTATION_POOL);
23
28
  }
24
29
 
25
- private getProposalMapKey(slot: string, proposalId: string): string {
26
- return `proposal-${slot}-${proposalId}`;
30
+ private getProposalKey(slot: number | bigint | Fr | string, proposalId: Fr | string | Buffer): string {
31
+ const slotStr = typeof slot === 'string' ? slot : new Fr(slot).toString();
32
+ const proposalIdStr =
33
+ typeof proposalId === 'string'
34
+ ? proposalId
35
+ : Buffer.isBuffer(proposalId)
36
+ ? Fr.fromBuffer(proposalId).toString()
37
+ : proposalId.toString();
38
+
39
+ return `${slotStr}-${proposalIdStr}`;
27
40
  }
28
41
 
29
- /**
30
- * Get the proposal map for a given slot and proposalId
31
- *
32
- * Essentially a nested mapping of address -> attestation
33
- *
34
- * @param slot - The slot to get the proposal map for
35
- * @param proposalId - The proposalId to get the map for
36
- * @returns The proposal map
37
- */
38
- private getProposalMap(slot: string, proposalId: string): AztecMapWithSize<string, Buffer> {
39
- const mapKey = this.getProposalMapKey(slot, proposalId);
40
- return this.store.openMapWithSize(mapKey);
42
+ private getAttestationKey(slot: number | bigint | Fr | string, proposalId: Fr | string, address: string): string {
43
+ return `${this.getProposalKey(slot, proposalId)}-${address}`;
41
44
  }
42
45
 
43
46
  public async addAttestations(attestations: BlockAttestation[]): Promise<void> {
44
- for (const attestation of attestations) {
45
- const slotNumber = attestation.payload.header.globalVariables.slotNumber.toString();
46
- const proposalId = attestation.archive.toString();
47
- const address = attestation.getSender().toString();
47
+ await this.store.transactionAsync(async () => {
48
+ for (const attestation of attestations) {
49
+ const slotNumber = attestation.payload.header.globalVariables.slotNumber;
50
+ const proposalId = attestation.archive;
51
+ const address = (await attestation.getSender()).toString();
48
52
 
49
- // Index the proposalId in the slot map
50
- await this.attestations.set(slotNumber, proposalId);
53
+ await this.attestations.set(this.getAttestationKey(slotNumber, proposalId, address), attestation.toBuffer());
51
54
 
52
- // Store the actual attestation in the proposal map
53
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
54
- await proposalMap.set(address, attestation.toBuffer());
55
+ await this.proposalsForSlot.set(slotNumber.toString(), proposalId.toString());
56
+ await this.attestationsForProposal.set(
57
+ this.getProposalKey(slotNumber, proposalId),
58
+ this.getAttestationKey(slotNumber, proposalId, address),
59
+ );
55
60
 
56
- this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`);
57
- }
61
+ this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`);
62
+ }
63
+ });
58
64
 
59
65
  this.metrics.recordAddedObjects(attestations.length);
60
66
  }
61
67
 
62
- public getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
63
- const slotNumber = new Fr(slot).toString();
64
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
65
- const attestations = proposalMap.values();
66
- const attestationsArray = Array.from(attestations).map(attestation => BlockAttestation.fromBuffer(attestation));
67
- return Promise.resolve(attestationsArray);
68
- }
68
+ public async getAttestationsForSlot(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
69
+ const attestationIds = await toArray(
70
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
71
+ );
72
+ const attestations: BlockAttestation[] = [];
69
73
 
70
- public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
71
- const olderThan = [];
74
+ // alternatively iterate this.attestaions starting from slot-proposal-EthAddress.zero
75
+ for (const id of attestationIds) {
76
+ const buf = await this.attestations.getAsync(id);
72
77
 
73
- const slots = this.attestations.keys();
74
- for (const slot of slots) {
75
- if (BigInt(slot) < oldestSlot) {
76
- olderThan.push(slot);
78
+ if (!buf) {
79
+ // this should not happen unless we lost writes
80
+ throw new Error('Attestation not found ' + id);
77
81
  }
82
+
83
+ const attestation = BlockAttestation.fromBuffer(buf);
84
+ attestations.push(attestation);
78
85
  }
79
86
 
80
- await Promise.all(olderThan.map(oldSlot => this.deleteAttestationsForSlot(BigInt(oldSlot))));
81
- return Promise.resolve();
87
+ return attestations;
82
88
  }
83
89
 
84
- public async deleteAttestationsForSlot(slot: bigint): Promise<void> {
85
- const deletionPromises = [];
90
+ public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
91
+ const olderThan = await toArray(this.proposalsForSlot.keysAsync({ end: new Fr(oldestSlot).toString() }));
92
+ for (const oldSlot of olderThan) {
93
+ await this.deleteAttestationsForSlot(BigInt(oldSlot));
94
+ }
95
+ }
86
96
 
87
- const slotString = new Fr(slot).toString();
97
+ public async deleteAttestationsForSlot(slot: bigint): Promise<void> {
98
+ const slotFr = new Fr(slot);
88
99
  let numberOfAttestations = 0;
89
- const proposalIds = this.attestations.getValues(slotString);
90
-
91
- if (proposalIds) {
100
+ await this.store.transactionAsync(async () => {
101
+ const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slotFr.toString()));
92
102
  for (const proposalId of proposalIds) {
93
- const proposalMap = this.getProposalMap(slotString, proposalId);
94
- numberOfAttestations += proposalMap.size();
95
- deletionPromises.push(proposalMap.clear());
96
- }
97
- }
103
+ const attestations = await toArray(
104
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slotFr, proposalId)),
105
+ );
98
106
 
99
- await Promise.all(deletionPromises);
107
+ numberOfAttestations += attestations.length;
108
+ for (const attestation of attestations) {
109
+ await this.attestations.delete(attestation);
110
+ }
111
+
112
+ await this.attestationsForProposal.delete(this.getProposalKey(slotFr, proposalId));
113
+ }
114
+ });
100
115
 
101
116
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
102
117
  this.metrics.recordRemovedObjects(numberOfAttestations);
103
- return Promise.resolve();
104
118
  }
105
119
 
106
120
  public async deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void> {
107
- const deletionPromises = [];
108
-
109
- const slotString = new Fr(slot).toString();
110
- const exists = this.attestations.get(slotString);
111
-
112
- if (exists) {
113
- // Remove the proposalId from the slot index
114
- deletionPromises.push(this.attestations.deleteValue(slotString, proposalId));
115
-
116
- // Delete all attestations for the proposalId
117
- const proposalMap = this.getProposalMap(slotString, proposalId);
118
- const numberOfAttestations = proposalMap.size();
119
- deletionPromises.push(proposalMap.clear());
121
+ let numberOfAttestations = 0;
122
+ await this.store.transactionAsync(async () => {
123
+ const slotString = new Fr(slot).toString();
124
+ const attestations = await toArray(
125
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
126
+ );
127
+
128
+ numberOfAttestations += attestations.length;
129
+ for (const attestation of attestations) {
130
+ await this.attestations.delete(attestation);
131
+ }
120
132
 
121
- this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
122
- this.metrics.recordRemovedObjects(numberOfAttestations);
123
- }
133
+ await this.proposalsForSlot.deleteValue(slotString, proposalId);
134
+ await this.attestationsForProposal.delete(this.getProposalKey(slotString, proposalId));
135
+ });
124
136
 
125
- await Promise.all(deletionPromises);
126
- return Promise.resolve();
137
+ this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
138
+ this.metrics.recordRemovedObjects(numberOfAttestations);
127
139
  }
128
140
 
129
141
  public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
130
- const deletionPromises = [];
131
-
132
- for (const attestation of attestations) {
133
- const slotNumber = attestation.payload.header.globalVariables.slotNumber.toString();
134
- const proposalId = attestation.archive.toString();
135
- const proposalMap = this.getProposalMap(slotNumber, proposalId);
142
+ await this.store.transactionAsync(async () => {
143
+ for (const attestation of attestations) {
144
+ const slotNumber = attestation.payload.header.globalVariables.slotNumber;
145
+ const proposalId = attestation.archive;
146
+ const address = (await attestation.getSender()).toString();
147
+
148
+ await this.attestations.delete(this.getAttestationKey(slotNumber, proposalId, address));
149
+ await this.attestationsForProposal.deleteValue(
150
+ this.getProposalKey(slotNumber, proposalId),
151
+ this.getAttestationKey(slotNumber, proposalId, address),
152
+ );
136
153
 
137
- if (proposalMap) {
138
- const address = attestation.getSender().toString();
139
- deletionPromises.push(proposalMap.delete(address));
140
154
  this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
141
155
  }
142
-
143
- if (proposalMap.size() === 0) {
144
- deletionPromises.push(this.attestations.deleteValue(slotNumber, proposalId));
145
- }
146
- }
147
-
148
- await Promise.all(deletionPromises);
149
-
156
+ });
150
157
  this.metrics.recordRemovedObjects(attestations.length);
151
- return Promise.resolve();
152
158
  }
153
159
  }
@@ -26,13 +26,13 @@ export class InMemoryAttestationPool implements AttestationPool {
26
26
  return Promise.resolve([]);
27
27
  }
28
28
 
29
- public addAttestations(attestations: BlockAttestation[]): Promise<void> {
29
+ public async addAttestations(attestations: BlockAttestation[]): Promise<void> {
30
30
  for (const attestation of attestations) {
31
31
  // Perf: order and group by slot before insertion
32
32
  const slotNumber = attestation.payload.header.globalVariables.slotNumber;
33
33
 
34
34
  const proposalId = attestation.archive.toString();
35
- const address = attestation.getSender();
35
+ const address = await attestation.getSender();
36
36
 
37
37
  const slotAttestationMap = getSlotOrDefault(this.attestations, slotNumber.toBigInt());
38
38
  const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
@@ -105,7 +105,7 @@ export class InMemoryAttestationPool implements AttestationPool {
105
105
  return Promise.resolve();
106
106
  }
107
107
 
108
- public deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
108
+ public async deleteAttestations(attestations: BlockAttestation[]): Promise<void> {
109
109
  for (const attestation of attestations) {
110
110
  const slotNumber = attestation.payload.header.globalVariables.slotNumber;
111
111
  const slotAttestationMap = this.attestations.get(slotNumber.toBigInt());
@@ -113,7 +113,7 @@ export class InMemoryAttestationPool implements AttestationPool {
113
113
  const proposalId = attestation.archive.toString();
114
114
  const proposalAttestationMap = getProposalOrDefault(slotAttestationMap, proposalId);
115
115
  if (proposalAttestationMap) {
116
- const address = attestation.getSender();
116
+ const address = await attestation.getSender();
117
117
  proposalAttestationMap.delete(address.toString());
118
118
  this.log.debug(`Deleted attestation for slot ${slotNumber} from ${address}`);
119
119
  }
@@ -9,14 +9,14 @@ import { makeHeader } from '@aztec/circuits.js/testing';
9
9
  import { type Secp256k1Signer } from '@aztec/foundation/crypto';
10
10
  import { Fr } from '@aztec/foundation/fields';
11
11
 
12
- import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
12
+ import { type LocalAccount, generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
13
13
 
14
14
  /** Generate Account
15
15
  *
16
16
  * Create a random signer
17
17
  * @returns A random viem signer
18
18
  */
19
- export const generateAccount = () => {
19
+ export const generateAccount = (): LocalAccount => {
20
20
  const privateKey = generatePrivateKey();
21
21
  return privateKeyToAccount(privateKey);
22
22
  };
@@ -27,17 +27,17 @@ export const generateAccount = () => {
27
27
  * @param slot The slot number the attestation is for
28
28
  * @returns A Block Attestation
29
29
  */
30
- export const mockAttestation = (
30
+ export const mockAttestation = async (
31
31
  signer: Secp256k1Signer,
32
32
  slot: number = 0,
33
33
  archive: Fr = Fr.random(),
34
34
  txs: TxHash[] = [0, 1, 2, 3, 4, 5].map(() => TxHash.random()),
35
- ): BlockAttestation => {
35
+ ): Promise<BlockAttestation> => {
36
36
  // Use arbitrary numbers for all other than slot
37
37
  const header = makeHeader(1, 2, slot);
38
38
  const payload = new ConsensusPayload(header, archive, txs);
39
39
 
40
- const hash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
40
+ const hash = await getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockAttestation);
41
41
  const signature = signer.sign(hash);
42
42
 
43
43
  return new BlockAttestation(payload, signature);