@aztec/p2p 3.0.0-devnet.2 → 3.0.0-devnet.2-patch.1

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 (259) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +1 -1
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/client/factory.d.ts +1 -1
  4. package/dest/client/index.d.ts +1 -1
  5. package/dest/client/interface.d.ts +4 -2
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +8 -26
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +31 -24
  10. package/dest/config.d.ts +60 -54
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +12 -2
  13. package/dest/enr/generate-enr.d.ts +1 -1
  14. package/dest/enr/index.d.ts +1 -1
  15. package/dest/errors/attestation-pool.error.d.ts +7 -0
  16. package/dest/errors/attestation-pool.error.d.ts.map +1 -0
  17. package/dest/errors/attestation-pool.error.js +12 -0
  18. package/dest/errors/reqresp.error.d.ts +1 -1
  19. package/dest/errors/reqresp.error.d.ts.map +1 -1
  20. package/dest/index.d.ts +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +43 -6
  22. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  24. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +67 -34
  26. package/dest/mem_pools/attestation_pool/index.d.ts +1 -1
  27. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +15 -6
  28. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  29. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +57 -18
  30. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +13 -6
  31. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  32. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +51 -7
  33. package/dest/mem_pools/attestation_pool/mocks.d.ts +226 -5
  34. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  35. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  36. package/dest/mem_pools/index.d.ts +1 -1
  37. package/dest/mem_pools/instrumentation.d.ts +3 -1
  38. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  39. package/dest/mem_pools/instrumentation.js +11 -2
  40. package/dest/mem_pools/interface.d.ts +1 -1
  41. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +5 -38
  42. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +9 -3
  44. package/dest/mem_pools/tx_pool/index.d.ts +1 -1
  45. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +5 -3
  46. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool/memory_tx_pool.js +7 -0
  48. package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
  49. package/dest/mem_pools/tx_pool/tx_pool.d.ts +10 -3
  50. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  51. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  52. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +5 -4
  54. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +4 -3
  55. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  56. package/dest/msg_validators/attestation_validator/attestation_validator.js +12 -12
  57. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +20 -0
  58. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
  59. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +67 -0
  60. package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
  61. package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
  62. package/dest/msg_validators/attestation_validator/index.js +1 -0
  63. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +1 -1
  64. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
  65. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +22 -10
  66. package/dest/msg_validators/block_proposal_validator/index.d.ts +1 -1
  67. package/dest/msg_validators/index.d.ts +1 -1
  68. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
  69. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
  70. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  71. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  72. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  73. package/dest/msg_validators/tx_validator/archive_cache.d.ts +2 -2
  74. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  75. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
  76. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  77. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  78. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  79. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
  80. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  81. package/dest/msg_validators/tx_validator/factory.d.ts +4 -3
  82. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  83. package/dest/msg_validators/tx_validator/factory.js +1 -1
  84. package/dest/msg_validators/tx_validator/gas_validator.d.ts +1 -1
  85. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  86. package/dest/msg_validators/tx_validator/index.d.ts +1 -1
  87. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
  88. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  89. package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
  90. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/phases_validator.js +3 -1
  92. package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
  93. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
  94. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +3 -2
  95. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  96. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +1 -1
  97. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  98. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +1 -1
  99. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  100. package/dest/services/data_store.d.ts +1 -1
  101. package/dest/services/data_store.d.ts.map +1 -1
  102. package/dest/services/discv5/discV5_service.d.ts +1 -1
  103. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  104. package/dest/services/dummy_service.d.ts +1 -1
  105. package/dest/services/dummy_service.d.ts.map +1 -1
  106. package/dest/services/encoding.d.ts +25 -4
  107. package/dest/services/encoding.d.ts.map +1 -1
  108. package/dest/services/encoding.js +74 -6
  109. package/dest/services/gossipsub/scoring.d.ts +1 -1
  110. package/dest/services/index.d.ts +1 -1
  111. package/dest/services/libp2p/instrumentation.d.ts +3 -1
  112. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  113. package/dest/services/libp2p/instrumentation.js +9 -2
  114. package/dest/services/libp2p/libp2p_service.d.ts +25 -74
  115. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  116. package/dest/services/libp2p/libp2p_service.js +308 -84
  117. package/dest/services/peer-manager/interface.d.ts +1 -1
  118. package/dest/services/peer-manager/metrics.d.ts +3 -1
  119. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  120. package/dest/services/peer-manager/metrics.js +11 -0
  121. package/dest/services/peer-manager/peer_manager.d.ts +1 -32
  122. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  123. package/dest/services/peer-manager/peer_manager.js +4 -2
  124. package/dest/services/peer-manager/peer_scoring.d.ts +7 -2
  125. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  126. package/dest/services/peer-manager/peer_scoring.js +40 -2
  127. package/dest/services/reqresp/config.d.ts +1 -1
  128. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +1 -1
  129. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  130. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -4
  131. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  132. package/dest/services/reqresp/index.d.ts +1 -1
  133. package/dest/services/reqresp/interface.d.ts +2 -2
  134. package/dest/services/reqresp/interface.d.ts.map +1 -1
  135. package/dest/services/reqresp/interface.js +1 -1
  136. package/dest/services/reqresp/metrics.d.ts +1 -1
  137. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  138. package/dest/services/reqresp/protocols/auth.d.ts +2 -2
  139. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
  140. package/dest/services/reqresp/protocols/auth.js +2 -2
  141. package/dest/services/reqresp/protocols/block.d.ts +1 -1
  142. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  143. package/dest/services/reqresp/protocols/block.js +3 -2
  144. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +1 -1
  145. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  146. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +1 -1
  147. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +4 -6
  148. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  149. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +1 -1
  150. package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
  151. package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
  152. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  153. package/dest/services/reqresp/protocols/index.d.ts +1 -1
  154. package/dest/services/reqresp/protocols/ping.d.ts +1 -1
  155. package/dest/services/reqresp/protocols/status.d.ts +6 -5
  156. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  157. package/dest/services/reqresp/protocols/status.js +4 -3
  158. package/dest/services/reqresp/protocols/tx.d.ts +1 -1
  159. package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
  160. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +2 -2
  161. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  162. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  163. package/dest/services/reqresp/reqresp.d.ts +1 -41
  164. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  165. package/dest/services/reqresp/reqresp.js +2 -2
  166. package/dest/services/reqresp/status.d.ts +2 -2
  167. package/dest/services/reqresp/status.d.ts.map +1 -1
  168. package/dest/services/service.d.ts +1 -1
  169. package/dest/services/tx_collection/config.d.ts +1 -1
  170. package/dest/services/tx_collection/fast_tx_collection.d.ts +4 -9
  171. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  172. package/dest/services/tx_collection/index.d.ts +1 -1
  173. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  174. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  175. package/dest/services/tx_collection/slow_tx_collection.d.ts +6 -7
  176. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  177. package/dest/services/tx_collection/slow_tx_collection.js +2 -1
  178. package/dest/services/tx_collection/tx_collection.d.ts +11 -11
  179. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  180. package/dest/services/tx_collection/tx_collection_sink.d.ts +3 -3
  181. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  182. package/dest/services/tx_collection/tx_source.d.ts +1 -1
  183. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  184. package/dest/services/tx_provider.d.ts +5 -4
  185. package/dest/services/tx_provider.d.ts.map +1 -1
  186. package/dest/services/tx_provider_instrumentation.d.ts +1 -1
  187. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  188. package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
  189. package/dest/test-helpers/get-ports.d.ts +1 -1
  190. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  191. package/dest/test-helpers/index.d.ts +1 -1
  192. package/dest/test-helpers/make-enrs.d.ts +1 -1
  193. package/dest/test-helpers/make-test-p2p-clients.d.ts +2 -2
  194. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  195. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  196. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  197. package/dest/test-helpers/mock-tx-helpers.d.ts +2 -2
  198. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
  199. package/dest/test-helpers/mock-tx-helpers.js +1 -1
  200. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  201. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  202. package/dest/testbench/p2p_client_testbench_worker.d.ts +1 -1
  203. package/dest/testbench/p2p_client_testbench_worker.js +14 -8
  204. package/dest/testbench/parse_log_file.d.ts +1 -1
  205. package/dest/testbench/testbench.d.ts +1 -1
  206. package/dest/testbench/testbench.js +2 -2
  207. package/dest/testbench/worker_client_manager.d.ts +1 -1
  208. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  209. package/dest/types/index.d.ts +1 -1
  210. package/dest/util.d.ts +2 -1
  211. package/dest/util.d.ts.map +1 -1
  212. package/dest/util.js +11 -2
  213. package/dest/versioning.d.ts +1 -1
  214. package/package.json +19 -18
  215. package/src/client/interface.ts +4 -1
  216. package/src/client/p2p_client.ts +51 -43
  217. package/src/config.ts +19 -2
  218. package/src/errors/attestation-pool.error.ts +13 -0
  219. package/src/mem_pools/attestation_pool/attestation_pool.ts +46 -5
  220. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +84 -34
  221. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +87 -24
  222. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +77 -15
  223. package/src/mem_pools/attestation_pool/mocks.ts +3 -3
  224. package/src/mem_pools/instrumentation.ts +13 -0
  225. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +15 -9
  226. package/src/mem_pools/tx_pool/memory_tx_pool.ts +13 -6
  227. package/src/mem_pools/tx_pool/tx_pool.ts +10 -2
  228. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +5 -4
  229. package/src/msg_validators/attestation_validator/attestation_validator.ts +14 -16
  230. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +91 -0
  231. package/src/msg_validators/attestation_validator/index.ts +1 -0
  232. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +26 -10
  233. package/src/msg_validators/tx_validator/archive_cache.ts +1 -1
  234. package/src/msg_validators/tx_validator/block_header_validator.ts +1 -1
  235. package/src/msg_validators/tx_validator/factory.ts +3 -2
  236. package/src/msg_validators/tx_validator/metadata_validator.ts +1 -1
  237. package/src/msg_validators/tx_validator/phases_validator.ts +3 -1
  238. package/src/msg_validators/tx_validator/test_utils.ts +1 -1
  239. package/src/msg_validators/tx_validator/timestamp_validator.ts +2 -1
  240. package/src/services/encoding.ts +81 -6
  241. package/src/services/libp2p/instrumentation.ts +10 -1
  242. package/src/services/libp2p/libp2p_service.ts +334 -91
  243. package/src/services/peer-manager/metrics.ts +10 -0
  244. package/src/services/peer-manager/peer_manager.ts +4 -2
  245. package/src/services/peer-manager/peer_scoring.ts +46 -3
  246. package/src/services/reqresp/interface.ts +1 -1
  247. package/src/services/reqresp/protocols/auth.ts +2 -2
  248. package/src/services/reqresp/protocols/block.ts +3 -2
  249. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +1 -1
  250. package/src/services/reqresp/protocols/status.ts +9 -8
  251. package/src/services/reqresp/reqresp.ts +2 -2
  252. package/src/services/tx_collection/fast_tx_collection.ts +3 -2
  253. package/src/services/tx_collection/slow_tx_collection.ts +7 -6
  254. package/src/services/tx_collection/tx_collection.ts +10 -9
  255. package/src/services/tx_provider.ts +4 -3
  256. package/src/test-helpers/mock-tx-helpers.ts +1 -1
  257. package/src/testbench/p2p_client_testbench_worker.ts +11 -5
  258. package/src/testbench/testbench.ts +2 -2
  259. package/src/util.ts +12 -2
@@ -1,5 +1,6 @@
1
- import { Secp256k1Signer } from '@aztec/foundation/crypto';
2
- import { Fr } from '@aztec/foundation/fields';
1
+ import { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
4
  import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
4
5
  import {
5
6
  BlockProposal as BlockProposalClass,
@@ -42,7 +43,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
42
43
 
43
44
  const mockBlockProposal = (signer: Secp256k1Signer, slotNumber: number, archive: Fr = Fr.random()): BlockProposal => {
44
45
  const header = makeL2BlockHeader(1, 2, slotNumber);
45
- const payload = new ConsensusPayload(header.toCheckpointHeader(), archive, header.state);
46
+ const payload = new ConsensusPayload(header.toCheckpointHeader(), archive);
46
47
 
47
48
  const hash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockProposal);
48
49
  const signature = signer.sign(hash);
@@ -68,11 +69,19 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
68
69
 
69
70
  await ap.addAttestations(attestations);
70
71
 
71
- const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
72
+ const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(
73
+ SlotNumber(slotNumber),
74
+ archive.toString(),
75
+ );
72
76
  expect(retrievedAttestations.length).toBe(attestations.length);
73
77
  compareAttestations(retrievedAttestations, attestations);
74
78
 
75
- const retrievedAttestationsForSlot = await ap.getAttestationsForSlot(BigInt(slotNumber));
79
+ // Check hasAttestation for added attestations
80
+ for (const attestation of attestations) {
81
+ expect(await ap.hasAttestation(attestation)).toBe(true);
82
+ }
83
+
84
+ const retrievedAttestationsForSlot = await ap.getAttestationsForSlot(SlotNumber(slotNumber));
76
85
  expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
77
86
  compareAttestations(retrievedAttestationsForSlot, attestations);
78
87
 
@@ -80,23 +89,29 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
80
89
  const newAttestation = mockAttestation(signers[NUMBER_OF_SIGNERS_PER_TEST - 1], slotNumber, archive);
81
90
  await ap.addAttestations([newAttestation]);
82
91
  const retrievedAttestationsAfterAdd = await ap.getAttestationsForSlotAndProposal(
83
- BigInt(slotNumber),
92
+ SlotNumber(slotNumber),
84
93
  archive.toString(),
85
94
  );
86
95
  expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
87
96
  compareAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
88
- const retrievedAttestationsForSlotAfterAdd = await ap.getAttestationsForSlot(BigInt(slotNumber));
97
+ expect(await ap.hasAttestation(newAttestation)).toBe(true);
98
+ const retrievedAttestationsForSlotAfterAdd = await ap.getAttestationsForSlot(SlotNumber(slotNumber));
89
99
  expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
90
100
  compareAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
91
101
 
92
102
  // Delete by slot
93
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
103
+ await ap.deleteAttestationsForSlot(SlotNumber(slotNumber));
94
104
 
95
105
  const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
96
- BigInt(slotNumber),
106
+ SlotNumber(slotNumber),
97
107
  archive.toString(),
98
108
  );
99
109
  expect(retreivedAttestationsAfterDelete.length).toBe(0);
110
+ // Check hasAttestation after deletion
111
+ for (const attestation of attestations) {
112
+ expect(await ap.hasAttestation(attestation)).toBe(false);
113
+ }
114
+ expect(await ap.hasAttestation(newAttestation)).toBe(false);
100
115
  });
101
116
 
102
117
  it('should handle duplicate proposals in a slot', async () => {
@@ -113,14 +128,17 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
113
128
  // Add them to store and check we end up with only one
114
129
  await ap.addAttestations(attestations);
115
130
 
116
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
131
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(
132
+ SlotNumber(slotNumber),
133
+ archive.toString(),
134
+ );
117
135
  expect(retreivedAttestations.length).toBe(1);
118
136
  expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
119
137
  expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
120
138
 
121
139
  // Try adding them on another operation and check they are still not duplicated
122
140
  await ap.addAttestations([attestations[0]]);
123
- expect(await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString())).toHaveLength(1);
141
+ expect(await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), archive.toString())).toHaveLength(1);
124
142
  });
125
143
 
126
144
  it('should store attestations by differing slot', async () => {
@@ -133,7 +151,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
133
151
  const slot = attestation.payload.header.slotNumber;
134
152
  const archive = attestation.archive.toString();
135
153
 
136
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot.toBigInt(), archive);
154
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot, archive);
137
155
  expect(retreivedAttestations.length).toBe(1);
138
156
  expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
139
157
  expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
@@ -151,7 +169,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
151
169
  const slot = attestation.payload.header.slotNumber;
152
170
  const proposalId = attestation.archive.toString();
153
171
 
154
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot.toBigInt(), proposalId);
172
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot, proposalId);
155
173
  expect(retreivedAttestations.length).toBe(1);
156
174
  expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
157
175
  expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
@@ -166,14 +184,24 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
166
184
 
167
185
  await ap.addAttestations(attestations);
168
186
 
169
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
187
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
170
188
  expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
171
189
  compareAttestations(retreivedAttestations, attestations);
172
190
 
191
+ // Check hasAttestation before deletion
192
+ for (const attestation of attestations) {
193
+ expect(await ap.hasAttestation(attestation)).toBe(true);
194
+ }
195
+
173
196
  await ap.deleteAttestations(attestations);
174
197
 
175
- const gottenAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
198
+ const gottenAfterDelete = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
176
199
  expect(gottenAfterDelete.length).toBe(0);
200
+
201
+ // Check hasAttestation after deletion
202
+ for (const attestation of attestations) {
203
+ expect(await ap.hasAttestation(attestation)).toBe(false);
204
+ }
177
205
  });
178
206
 
179
207
  it('should blanket delete attestations per slot', async () => {
@@ -184,13 +212,16 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
184
212
 
185
213
  await ap.addAttestations(attestations);
186
214
 
187
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
215
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
188
216
  expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
189
217
  compareAttestations(retreivedAttestations, attestations);
190
218
 
191
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
219
+ await ap.deleteAttestationsForSlot(SlotNumber(slotNumber));
192
220
 
193
- const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
221
+ const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
222
+ SlotNumber(slotNumber),
223
+ proposalId,
224
+ );
194
225
  expect(retreivedAttestationsAfterDelete.length).toBe(0);
195
226
  });
196
227
 
@@ -208,17 +239,20 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
208
239
  await ap.addAttestations(attestations);
209
240
  await ap.addAttestations(attestations2);
210
241
 
211
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
242
+ const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
212
243
  expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
213
244
  compareAttestations(retreivedAttestations, attestations);
214
245
 
215
- await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
246
+ await ap.deleteAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
216
247
 
217
- const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
248
+ const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
249
+ SlotNumber(slotNumber),
250
+ proposalId,
251
+ );
218
252
  expect(retreivedAttestationsAfterDelete.length).toBe(0);
219
253
 
220
254
  const retreivedAttestationsAfterDeleteForOtherProposal = await ap.getAttestationsForSlotAndProposal(
221
- BigInt(slotNumber),
255
+ SlotNumber(slotNumber),
222
256
  proposalId2,
223
257
  );
224
258
  expect(retreivedAttestationsAfterDeleteForOtherProposal.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
@@ -234,22 +268,22 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
234
268
 
235
269
  await ap.addAttestations(attestations);
236
270
 
237
- const attestationsForSlot1 = await ap.getAttestationsForSlotAndProposal(BigInt(1), proposalId);
271
+ const attestationsForSlot1 = await ap.getAttestationsForSlotAndProposal(SlotNumber(1), proposalId);
238
272
  expect(attestationsForSlot1.length).toBe(signers.length);
239
273
 
240
274
  const deleteAttestationsSpy = jest.spyOn(ap, 'deleteAttestationsForSlot');
241
275
 
242
- await ap.deleteAttestationsOlderThan(BigInt(73));
276
+ await ap.deleteAttestationsOlderThan(SlotNumber(73));
243
277
 
244
- const attestationsForSlot1AfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(1), proposalId);
278
+ const attestationsForSlot1AfterDelete = await ap.getAttestationsForSlotAndProposal(SlotNumber(1), proposalId);
245
279
  expect(attestationsForSlot1AfterDelete.length).toBe(0);
246
280
 
247
281
  expect(deleteAttestationsSpy).toHaveBeenCalledTimes(5);
248
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(1));
249
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(2));
250
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(3));
251
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(69));
252
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(72));
282
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(SlotNumber(1));
283
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(SlotNumber(2));
284
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(SlotNumber(3));
285
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(SlotNumber(69));
286
+ expect(deleteAttestationsSpy).toHaveBeenCalledWith(SlotNumber(72));
253
287
  });
254
288
 
255
289
  describe('BlockProposal in attestation pool', () => {
@@ -265,12 +299,19 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
265
299
 
266
300
  expect(retrievedProposal).toBeDefined();
267
301
  expect(retrievedProposal!).toEqual(proposal);
302
+
303
+ // Check hasBlockProposal with both id and object
304
+ expect(await ap.hasBlockProposal(proposalId)).toBe(true);
305
+ expect(await ap.hasBlockProposal(proposal)).toBe(true);
268
306
  });
269
307
 
270
308
  it('should return undefined for non-existent block proposal', async () => {
271
309
  const nonExistentId = Fr.random().toString();
272
310
  const retrievedProposal = await ap.getBlockProposal(nonExistentId);
273
311
  expect(retrievedProposal).toBeUndefined();
312
+
313
+ // Check hasBlockProposal returns false for non-existent proposal
314
+ expect(await ap.hasBlockProposal(nonExistentId)).toBe(false);
274
315
  });
275
316
 
276
317
  it('should update block proposal if added twice with same id', async () => {
@@ -306,7 +347,7 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
306
347
  const retrievedProposal = await ap.getBlockProposal(proposalId);
307
348
  expect(retrievedProposal).toBeDefined();
308
349
  expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toBuffer());
309
- expect(retrievedProposal!.slotNumber.toBigInt()).toBe(BigInt(200));
350
+ expect(retrievedProposal!.slotNumber).toBe(SlotNumber(200));
310
351
  });
311
352
 
312
353
  it('should delete block proposal when deleting attestations for slot and proposal', async () => {
@@ -323,13 +364,15 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
323
364
  // Verify proposal exists
324
365
  let retrievedProposal = await ap.getBlockProposal(proposalId);
325
366
  expect(retrievedProposal).toBeDefined();
367
+ expect(await ap.hasBlockProposal(proposalId)).toBe(true);
326
368
 
327
369
  // Delete attestations for slot and proposal
328
- await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
370
+ await ap.deleteAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
329
371
 
330
372
  // Proposal should be deleted
331
373
  retrievedProposal = await ap.getBlockProposal(proposalId);
332
374
  expect(retrievedProposal).toBeUndefined();
375
+ expect(await ap.hasBlockProposal(proposalId)).toBe(false);
333
376
  });
334
377
 
335
378
  it('should delete block proposal when deleting attestations for slot', async () => {
@@ -344,13 +387,15 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
344
387
  // Verify proposal exists
345
388
  let retrievedProposal = await ap.getBlockProposal(proposalId);
346
389
  expect(retrievedProposal).toBeDefined();
390
+ expect(await ap.hasBlockProposal(proposal)).toBe(true);
347
391
 
348
392
  // Delete attestations for slot
349
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
393
+ await ap.deleteAttestationsForSlot(SlotNumber(slotNumber));
350
394
 
351
395
  // Proposal should be deleted
352
396
  retrievedProposal = await ap.getBlockProposal(proposalId);
353
397
  expect(retrievedProposal).toBeUndefined();
398
+ expect(await ap.hasBlockProposal(proposal)).toBe(false);
354
399
  });
355
400
 
356
401
  it('should be able to fetch both block proposal and attestations', async () => {
@@ -368,12 +413,17 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
368
413
 
369
414
  // Retrieve both proposal and attestations
370
415
  const retrievedProposal = await ap.getBlockProposal(proposalId);
371
- const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
416
+ const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(SlotNumber(slotNumber), proposalId);
372
417
 
373
418
  expect(retrievedProposal).toBeDefined();
374
419
  expect(retrievedProposal).toEqual(proposal);
420
+ expect(await ap.hasBlockProposal(proposalId)).toBe(true);
375
421
 
376
422
  compareAttestations(retrievedAttestations, attestations);
423
+ // Check hasAttestation for all attestations
424
+ for (const attestation of attestations) {
425
+ expect(await ap.hasAttestation(attestation)).toBe(true);
426
+ }
377
427
  });
378
428
  });
379
429
  }
@@ -1,13 +1,18 @@
1
- import { Fr } from '@aztec/foundation/fields';
1
+ import { SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
3
  import { toArray } from '@aztec/foundation/iterable';
3
4
  import { createLogger } from '@aztec/foundation/log';
4
5
  import type { AztecAsyncKVStore, AztecAsyncMap, AztecAsyncMultiMap } from '@aztec/kv-store';
5
6
  import { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
6
7
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
7
8
 
9
+ import { ProposalSlotCapExceededError } from '../../errors/attestation-pool.error.js';
8
10
  import { PoolInstrumentation, PoolName, type PoolStatsCallback } from '../instrumentation.js';
9
11
  import type { AttestationPool } from './attestation_pool.js';
10
12
 
13
+ export const MAX_PROPOSALS_PER_SLOT = 5;
14
+ export const ATTESTATION_CAP_BUFFER = 10;
15
+
11
16
  export class KvAttestationPool implements AttestationPool {
12
17
  private metrics: PoolInstrumentation<BlockAttestation>;
13
18
 
@@ -16,7 +21,7 @@ export class KvAttestationPool implements AttestationPool {
16
21
  /* proposal.payload.archive */ string,
17
22
  /* buffer representation of proposal */ Buffer
18
23
  >;
19
- private proposalsForSlot: AztecAsyncMultiMap<string, string>;
24
+ private proposalsForSlot: AztecAsyncMultiMap<number, string>;
20
25
  private attestationsForProposal: AztecAsyncMultiMap<string, string>;
21
26
 
22
27
  constructor(
@@ -70,7 +75,7 @@ export class KvAttestationPool implements AttestationPool {
70
75
 
71
76
  // Skip attestations with invalid signatures
72
77
  if (!sender) {
73
- this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber.toBigInt()}`, {
78
+ this.log.warn(`Skipping attestation with invalid signature for slot ${slotNumber}`, {
74
79
  signature: attestation.signature.toString(),
75
80
  slotNumber,
76
81
  proposalId,
@@ -82,13 +87,13 @@ export class KvAttestationPool implements AttestationPool {
82
87
 
83
88
  await this.attestations.set(this.getAttestationKey(slotNumber, proposalId, address), attestation.toBuffer());
84
89
 
85
- await this.proposalsForSlot.set(slotNumber.toString(), proposalId.toString());
90
+ await this.proposalsForSlot.set(slotNumber, proposalId.toString());
86
91
  await this.attestationsForProposal.set(
87
92
  this.getProposalKey(slotNumber, proposalId),
88
93
  this.getAttestationKey(slotNumber, proposalId, address),
89
94
  );
90
95
 
91
- this.log.verbose(`Added attestation for slot ${slotNumber.toBigInt()} from ${address}`, {
96
+ this.log.verbose(`Added attestation for slot ${slotNumber} from ${address}`, {
92
97
  signature: attestation.signature.toString(),
93
98
  slotNumber,
94
99
  address,
@@ -98,9 +103,8 @@ export class KvAttestationPool implements AttestationPool {
98
103
  });
99
104
  }
100
105
 
101
- public async getAttestationsForSlot(slot: bigint): Promise<BlockAttestation[]> {
102
- const slotFr = new Fr(slot);
103
- const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slotFr.toString()));
106
+ public async getAttestationsForSlot(slot: SlotNumber): Promise<BlockAttestation[]> {
107
+ const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slot));
104
108
  const attestations: BlockAttestation[] = [];
105
109
 
106
110
  for (const proposalId of proposalIds) {
@@ -110,7 +114,7 @@ export class KvAttestationPool implements AttestationPool {
110
114
  return attestations;
111
115
  }
112
116
 
113
- public async getAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<BlockAttestation[]> {
117
+ public async getAttestationsForSlotAndProposal(slot: SlotNumber, proposalId: string): Promise<BlockAttestation[]> {
114
118
  const attestationIds = await toArray(
115
119
  this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
116
120
  );
@@ -132,21 +136,20 @@ export class KvAttestationPool implements AttestationPool {
132
136
  return attestations;
133
137
  }
134
138
 
135
- public async deleteAttestationsOlderThan(oldestSlot: bigint): Promise<void> {
136
- const olderThan = await toArray(this.proposalsForSlot.keysAsync({ end: new Fr(oldestSlot).toString() }));
139
+ public async deleteAttestationsOlderThan(oldestSlot: SlotNumber): Promise<void> {
140
+ const olderThan = await toArray(this.proposalsForSlot.keysAsync({ end: oldestSlot }));
137
141
  for (const oldSlot of olderThan) {
138
- await this.deleteAttestationsForSlot(BigInt(oldSlot));
142
+ await this.deleteAttestationsForSlot(SlotNumber(oldSlot));
139
143
  }
140
144
  }
141
145
 
142
- public async deleteAttestationsForSlot(slot: bigint): Promise<void> {
143
- const slotFr = new Fr(slot);
146
+ public async deleteAttestationsForSlot(slot: SlotNumber): Promise<void> {
144
147
  let numberOfAttestations = 0;
145
148
  await this.store.transactionAsync(async () => {
146
- const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slotFr.toString()));
149
+ const proposalIds = await toArray(this.proposalsForSlot.getValuesAsync(slot));
147
150
  for (const proposalId of proposalIds) {
148
151
  const attestations = await toArray(
149
- this.attestationsForProposal.getValuesAsync(this.getProposalKey(slotFr, proposalId)),
152
+ this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
150
153
  );
151
154
 
152
155
  numberOfAttestations += attestations.length;
@@ -155,17 +158,19 @@ export class KvAttestationPool implements AttestationPool {
155
158
  }
156
159
 
157
160
  await this.proposals.delete(proposalId);
158
- await this.attestationsForProposal.delete(this.getProposalKey(slotFr, proposalId));
161
+ await this.attestationsForProposal.delete(this.getProposalKey(slot, proposalId));
159
162
  }
160
163
 
164
+ // Delete from proposalsForSlot
165
+ await this.proposalsForSlot.delete(slot);
166
+
161
167
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot}`);
162
168
  });
163
169
  }
164
170
 
165
- public async deleteAttestationsForSlotAndProposal(slot: bigint, proposalId: string): Promise<void> {
171
+ public async deleteAttestationsForSlotAndProposal(slot: SlotNumber, proposalId: string): Promise<void> {
166
172
  let numberOfAttestations = 0;
167
173
  await this.store.transactionAsync(async () => {
168
- const slotString = new Fr(slot).toString();
169
174
  const attestations = await toArray(
170
175
  this.attestationsForProposal.getValuesAsync(this.getProposalKey(slot, proposalId)),
171
176
  );
@@ -176,8 +181,8 @@ export class KvAttestationPool implements AttestationPool {
176
181
  }
177
182
 
178
183
  await this.proposals.delete(proposalId);
179
- await this.proposalsForSlot.deleteValue(slotString, proposalId);
180
- await this.attestationsForProposal.delete(this.getProposalKey(slotString, proposalId));
184
+ await this.proposalsForSlot.deleteValue(slot, proposalId);
185
+ await this.attestationsForProposal.delete(this.getProposalKey(slot, proposalId));
181
186
 
182
187
  this.log.verbose(`Removed ${numberOfAttestations} attestations for slot ${slot} and proposal ${proposalId}`);
183
188
  });
@@ -192,7 +197,7 @@ export class KvAttestationPool implements AttestationPool {
192
197
 
193
198
  // Skip attestations with invalid signatures
194
199
  if (!sender) {
195
- this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber.toBigInt()}`);
200
+ this.log.warn(`Skipping deletion of attestation with invalid signature for slot ${slotNumber}`);
196
201
  continue;
197
202
  }
198
203
 
@@ -213,6 +218,22 @@ export class KvAttestationPool implements AttestationPool {
213
218
  });
214
219
  }
215
220
 
221
+ public async hasAttestation(attestation: BlockAttestation): Promise<boolean> {
222
+ const slotNumber = attestation.payload.header.slotNumber;
223
+ const proposalId = attestation.archive;
224
+ const sender = attestation.getSender();
225
+
226
+ // Attestations with invalid signatures are never in the pool
227
+ if (!sender) {
228
+ return false;
229
+ }
230
+
231
+ const address = sender.toString();
232
+ const key = this.getAttestationKey(slotNumber, proposalId, address);
233
+
234
+ return await this.attestations.hasAsync(key);
235
+ }
236
+
216
237
  public async getBlockProposal(id: string): Promise<BlockProposal | undefined> {
217
238
  const buffer = await this.proposals.getAsync(id);
218
239
  try {
@@ -226,10 +247,52 @@ export class KvAttestationPool implements AttestationPool {
226
247
  return Promise.resolve(undefined);
227
248
  }
228
249
 
250
+ public async hasBlockProposal(idOrProposal: string | BlockProposal): Promise<boolean> {
251
+ const id = typeof idOrProposal === 'string' ? idOrProposal : idOrProposal.payload.archive.toString();
252
+ return await this.proposals.hasAsync(id);
253
+ }
254
+
229
255
  public async addBlockProposal(blockProposal: BlockProposal): Promise<void> {
230
256
  await this.store.transactionAsync(async () => {
231
- await this.proposalsForSlot.set(blockProposal.slotNumber.toString(), blockProposal.archive.toString());
232
- await this.proposals.set(blockProposal.payload.archive.toString(), blockProposal.toBuffer());
257
+ const slotKey = blockProposal.slotNumber;
258
+ const proposalId = blockProposal.archive.toString();
259
+
260
+ if (!(await this.canAddProposal(blockProposal))) {
261
+ throw new ProposalSlotCapExceededError(
262
+ `Maximum proposals per slot reached: slot=${slotKey} cap=${MAX_PROPOSALS_PER_SLOT} proposal=${proposalId}`,
263
+ );
264
+ }
265
+
266
+ await this.proposalsForSlot.set(slotKey, proposalId);
267
+ // Always update the stored proposal buffer so re-adds overwrite with latest data
268
+ await this.proposals.set(proposalId, blockProposal.toBuffer());
233
269
  });
234
270
  }
271
+
272
+ public async hasReachedProposalCap(slot: SlotNumber): Promise<boolean> {
273
+ const uniqueProposalCount = await this.proposalsForSlot.getValueCountAsync(slot);
274
+ return uniqueProposalCount >= MAX_PROPOSALS_PER_SLOT;
275
+ }
276
+
277
+ public async hasReachedAttestationCap(slot: SlotNumber, proposalId: string, committeeSize: number): Promise<boolean> {
278
+ const limit = committeeSize + ATTESTATION_CAP_BUFFER;
279
+ return (await this.attestationsForProposal.getValueCountAsync(this.getProposalKey(slot, proposalId))) >= limit;
280
+ }
281
+
282
+ public async canAddProposal(block: BlockProposal): Promise<boolean> {
283
+ return (
284
+ (await this.proposals.hasAsync(block.archive.toString())) || !(await this.hasReachedProposalCap(block.slotNumber))
285
+ );
286
+ }
287
+
288
+ public async canAddAttestation(attestation: BlockAttestation, committeeSize: number): Promise<boolean> {
289
+ return (
290
+ (await this.hasAttestation(attestation)) ||
291
+ !(await this.hasReachedAttestationCap(
292
+ attestation.payload.header.slotNumber,
293
+ attestation.archive.toString(),
294
+ committeeSize,
295
+ ))
296
+ );
297
+ }
235
298
  }