@aztec/p2p 0.0.1-commit.f2ce05ee → 0.0.1-commit.f504929

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 (326) hide show
  1. package/dest/client/factory.d.ts +8 -8
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +37 -13
  4. package/dest/client/interface.d.ts +39 -33
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +37 -50
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +138 -199
  9. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +6 -7
  10. package/dest/config.d.ts +29 -15
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +39 -35
  13. package/dest/errors/tx-pool.error.d.ts +8 -0
  14. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  15. package/dest/errors/tx-pool.error.js +9 -0
  16. package/dest/index.d.ts +2 -1
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +1 -0
  19. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +21 -12
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/attestation_pool.js +72 -38
  22. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +53 -53
  25. package/dest/mem_pools/attestation_pool/index.d.ts +2 -2
  26. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/index.js +1 -1
  28. package/dest/mem_pools/attestation_pool/mocks.d.ts +2 -2
  29. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  30. package/dest/mem_pools/attestation_pool/mocks.js +2 -2
  31. package/dest/mem_pools/index.d.ts +2 -1
  32. package/dest/mem_pools/index.d.ts.map +1 -1
  33. package/dest/mem_pools/instrumentation.d.ts +4 -2
  34. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  35. package/dest/mem_pools/instrumentation.js +16 -14
  36. package/dest/mem_pools/interface.d.ts +3 -3
  37. package/dest/mem_pools/interface.d.ts.map +1 -1
  38. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +3 -3
  39. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
  40. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
  41. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
  42. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +3 -3
  43. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -1
  44. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +18 -9
  45. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  46. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  47. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +5 -2
  48. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +3 -3
  49. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  50. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +12 -4
  51. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +2 -2
  52. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool_v2/eviction/index.js +1 -1
  54. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +48 -5
  55. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +8 -0
  57. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +7 -5
  58. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +7 -5
  59. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  60. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  61. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +14 -6
  62. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +4 -4
  63. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  64. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +14 -4
  65. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +3 -3
  66. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  67. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  68. package/dest/mem_pools/tx_pool_v2/index.d.ts +3 -2
  69. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  70. package/dest/mem_pools/tx_pool_v2/index.js +2 -1
  71. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  72. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  73. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  74. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +22 -8
  75. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  76. package/dest/mem_pools/tx_pool_v2/interfaces.js +4 -1
  77. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +56 -8
  78. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  79. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +108 -10
  80. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +12 -3
  81. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  82. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +36 -14
  83. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +9 -4
  84. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  85. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +14 -6
  86. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +14 -5
  87. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  88. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +344 -184
  89. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +2 -1
  90. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +2 -1
  92. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  93. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +3 -1
  94. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  95. package/dest/msg_validators/proposal_validator/proposal_validator.js +10 -0
  96. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +2 -1
  97. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +1 -1
  98. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +166 -0
  99. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
  100. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  101. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  102. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  103. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  104. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -10
  105. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +16 -3
  106. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  107. package/dest/msg_validators/tx_validator/block_header_validator.js +1 -1
  108. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +13 -3
  109. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  110. package/dest/msg_validators/tx_validator/double_spend_validator.js +4 -4
  111. package/dest/msg_validators/tx_validator/factory.d.ts +114 -6
  112. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  113. package/dest/msg_validators/tx_validator/factory.js +219 -58
  114. package/dest/msg_validators/tx_validator/gas_validator.d.ts +58 -3
  115. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  116. package/dest/msg_validators/tx_validator/gas_validator.js +73 -36
  117. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  118. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  119. package/dest/msg_validators/tx_validator/index.js +1 -0
  120. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  121. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  122. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  123. package/dest/msg_validators/tx_validator/phases_validator.d.ts +2 -2
  124. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  125. package/dest/msg_validators/tx_validator/phases_validator.js +25 -24
  126. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +20 -4
  127. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  128. package/dest/msg_validators/tx_validator/timestamp_validator.js +6 -6
  129. package/dest/services/dummy_service.d.ts +9 -5
  130. package/dest/services/dummy_service.d.ts.map +1 -1
  131. package/dest/services/dummy_service.js +7 -4
  132. package/dest/services/encoding.d.ts +3 -3
  133. package/dest/services/encoding.d.ts.map +1 -1
  134. package/dest/services/encoding.js +11 -10
  135. package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
  136. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  137. package/dest/services/gossipsub/topic_score_params.js +32 -10
  138. package/dest/services/libp2p/libp2p_service.d.ts +25 -14
  139. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  140. package/dest/services/libp2p/libp2p_service.js +143 -114
  141. package/dest/services/peer-manager/metrics.d.ts +3 -1
  142. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  143. package/dest/services/peer-manager/metrics.js +6 -0
  144. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  145. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  146. package/dest/services/peer-manager/peer_manager.js +2 -1
  147. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +4 -3
  148. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  149. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +19 -46
  150. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +2 -6
  151. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  152. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +10 -13
  153. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  154. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +25 -46
  155. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +17 -11
  156. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  157. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +49 -15
  158. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  159. package/dest/services/reqresp/interface.d.ts +10 -1
  160. package/dest/services/reqresp/interface.d.ts.map +1 -1
  161. package/dest/services/reqresp/interface.js +15 -1
  162. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +3 -3
  163. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  164. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +7 -1
  165. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  166. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +15 -0
  167. package/dest/services/reqresp/protocols/tx.d.ts +7 -1
  168. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  169. package/dest/services/reqresp/protocols/tx.js +20 -0
  170. package/dest/services/reqresp/reqresp.d.ts +1 -1
  171. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  172. package/dest/services/reqresp/reqresp.js +13 -5
  173. package/dest/services/service.d.ts +22 -3
  174. package/dest/services/service.d.ts.map +1 -1
  175. package/dest/services/tx_collection/config.d.ts +19 -1
  176. package/dest/services/tx_collection/config.d.ts.map +1 -1
  177. package/dest/services/tx_collection/config.js +46 -0
  178. package/dest/services/tx_collection/fast_tx_collection.d.ts +3 -1
  179. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  180. package/dest/services/tx_collection/fast_tx_collection.js +56 -36
  181. package/dest/services/tx_collection/file_store_tx_collection.d.ts +53 -0
  182. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
  183. package/dest/services/tx_collection/file_store_tx_collection.js +167 -0
  184. package/dest/services/tx_collection/file_store_tx_source.d.ts +37 -0
  185. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
  186. package/dest/services/tx_collection/file_store_tx_source.js +90 -0
  187. package/dest/services/tx_collection/index.d.ts +2 -1
  188. package/dest/services/tx_collection/index.d.ts.map +1 -1
  189. package/dest/services/tx_collection/index.js +1 -0
  190. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  191. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  192. package/dest/services/tx_collection/instrumentation.js +2 -1
  193. package/dest/services/tx_collection/missing_txs_tracker.d.ts +32 -0
  194. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +1 -0
  195. package/dest/services/tx_collection/missing_txs_tracker.js +27 -0
  196. package/dest/services/tx_collection/proposal_tx_collector.d.ts +7 -6
  197. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  198. package/dest/services/tx_collection/proposal_tx_collector.js +5 -4
  199. package/dest/services/tx_collection/slow_tx_collection.d.ts +7 -3
  200. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -1
  201. package/dest/services/tx_collection/slow_tx_collection.js +60 -26
  202. package/dest/services/tx_collection/tx_collection.d.ts +23 -10
  203. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  204. package/dest/services/tx_collection/tx_collection.js +75 -3
  205. package/dest/services/tx_collection/tx_collection_sink.d.ts +18 -8
  206. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  207. package/dest/services/tx_collection/tx_collection_sink.js +26 -29
  208. package/dest/services/tx_collection/tx_source.d.ts +8 -3
  209. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  210. package/dest/services/tx_collection/tx_source.js +19 -2
  211. package/dest/services/tx_file_store/config.d.ts +1 -3
  212. package/dest/services/tx_file_store/config.d.ts.map +1 -1
  213. package/dest/services/tx_file_store/config.js +0 -4
  214. package/dest/services/tx_file_store/tx_file_store.d.ts +4 -3
  215. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -1
  216. package/dest/services/tx_file_store/tx_file_store.js +9 -6
  217. package/dest/services/tx_provider.d.ts +4 -4
  218. package/dest/services/tx_provider.d.ts.map +1 -1
  219. package/dest/services/tx_provider.js +9 -8
  220. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
  221. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  222. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  223. package/dest/test-helpers/mock-pubsub.d.ts +30 -4
  224. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  225. package/dest/test-helpers/mock-pubsub.js +105 -4
  226. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  227. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  228. package/dest/test-helpers/reqresp-nodes.js +2 -2
  229. package/dest/test-helpers/testbench-utils.d.ts +35 -24
  230. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  231. package/dest/test-helpers/testbench-utils.js +93 -35
  232. package/dest/testbench/p2p_client_testbench_worker.d.ts +2 -2
  233. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  234. package/dest/testbench/p2p_client_testbench_worker.js +14 -14
  235. package/dest/util.d.ts +2 -2
  236. package/dest/util.d.ts.map +1 -1
  237. package/package.json +14 -14
  238. package/src/client/factory.ts +71 -23
  239. package/src/client/interface.ts +43 -33
  240. package/src/client/p2p_client.ts +164 -243
  241. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -10
  242. package/src/config.ts +60 -42
  243. package/src/errors/tx-pool.error.ts +12 -0
  244. package/src/index.ts +1 -0
  245. package/src/mem_pools/attestation_pool/attestation_pool.ts +100 -48
  246. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +57 -53
  247. package/src/mem_pools/attestation_pool/index.ts +3 -3
  248. package/src/mem_pools/attestation_pool/mocks.ts +2 -1
  249. package/src/mem_pools/index.ts +3 -0
  250. package/src/mem_pools/instrumentation.ts +17 -13
  251. package/src/mem_pools/interface.ts +2 -2
  252. package/src/mem_pools/tx_pool/README.md +1 -1
  253. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +3 -3
  254. package/src/mem_pools/tx_pool_v2/README.md +76 -10
  255. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
  256. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +21 -8
  257. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +5 -2
  258. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +18 -4
  259. package/src/mem_pools/tx_pool_v2/eviction/index.ts +4 -0
  260. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +49 -4
  261. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +5 -5
  262. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +5 -5
  263. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +14 -9
  264. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +24 -6
  265. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +3 -3
  266. package/src/mem_pools/tx_pool_v2/index.ts +2 -1
  267. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  268. package/src/mem_pools/tx_pool_v2/interfaces.ts +23 -8
  269. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +153 -17
  270. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +43 -16
  271. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +21 -7
  272. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +388 -182
  273. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +1 -1
  274. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +1 -1
  275. package/src/msg_validators/proposal_validator/proposal_validator.ts +15 -1
  276. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +144 -1
  277. package/src/msg_validators/tx_validator/README.md +115 -0
  278. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +5 -5
  279. package/src/msg_validators/tx_validator/allowed_public_setup.ts +27 -13
  280. package/src/msg_validators/tx_validator/block_header_validator.ts +15 -3
  281. package/src/msg_validators/tx_validator/double_spend_validator.ts +11 -6
  282. package/src/msg_validators/tx_validator/factory.ts +353 -77
  283. package/src/msg_validators/tx_validator/gas_validator.ts +90 -27
  284. package/src/msg_validators/tx_validator/index.ts +1 -0
  285. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  286. package/src/msg_validators/tx_validator/phases_validator.ts +25 -29
  287. package/src/msg_validators/tx_validator/timestamp_validator.ts +23 -18
  288. package/src/services/dummy_service.ts +12 -6
  289. package/src/services/encoding.ts +9 -9
  290. package/src/services/gossipsub/README.md +29 -14
  291. package/src/services/gossipsub/topic_score_params.ts +49 -13
  292. package/src/services/libp2p/libp2p_service.ts +153 -123
  293. package/src/services/peer-manager/metrics.ts +7 -0
  294. package/src/services/peer-manager/peer_manager.ts +2 -1
  295. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +20 -48
  296. package/src/services/reqresp/batch-tx-requester/interface.ts +1 -5
  297. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +23 -71
  298. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +63 -24
  299. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  300. package/src/services/reqresp/interface.ts +26 -1
  301. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +2 -2
  302. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +17 -0
  303. package/src/services/reqresp/protocols/tx.ts +22 -0
  304. package/src/services/reqresp/reqresp.ts +16 -4
  305. package/src/services/service.ts +31 -2
  306. package/src/services/tx_collection/config.ts +68 -0
  307. package/src/services/tx_collection/fast_tx_collection.ts +65 -32
  308. package/src/services/tx_collection/file_store_tx_collection.ts +202 -0
  309. package/src/services/tx_collection/file_store_tx_source.ts +117 -0
  310. package/src/services/tx_collection/index.ts +1 -0
  311. package/src/services/tx_collection/instrumentation.ts +7 -1
  312. package/src/services/tx_collection/missing_txs_tracker.ts +52 -0
  313. package/src/services/tx_collection/proposal_tx_collector.ts +8 -7
  314. package/src/services/tx_collection/slow_tx_collection.ts +66 -33
  315. package/src/services/tx_collection/tx_collection.ts +113 -16
  316. package/src/services/tx_collection/tx_collection_sink.ts +30 -34
  317. package/src/services/tx_collection/tx_source.ts +22 -3
  318. package/src/services/tx_file_store/config.ts +0 -6
  319. package/src/services/tx_file_store/tx_file_store.ts +10 -8
  320. package/src/services/tx_provider.ts +10 -9
  321. package/src/test-helpers/make-test-p2p-clients.ts +3 -5
  322. package/src/test-helpers/mock-pubsub.ts +146 -9
  323. package/src/test-helpers/reqresp-nodes.ts +2 -5
  324. package/src/test-helpers/testbench-utils.ts +108 -40
  325. package/src/testbench/p2p_client_testbench_worker.ts +23 -20
  326. package/src/util.ts +7 -1
@@ -8,7 +8,7 @@ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
8
8
  import type { L2BlockSource } from '@aztec/stdlib/block';
9
9
  import type { ContractDataSource } from '@aztec/stdlib/contract';
10
10
  import type { ClientProtocolCircuitVerifier } from '@aztec/stdlib/interfaces/server';
11
- import { P2PClientType, PeerErrorSeverity } from '@aztec/stdlib/p2p';
11
+ import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
12
12
  import type { Tx, TxValidationResult } from '@aztec/stdlib/tx';
13
13
  import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
14
14
 
@@ -16,14 +16,12 @@ import type { PeerId } from '@libp2p/interface';
16
16
  import { peerIdFromString } from '@libp2p/peer-id';
17
17
 
18
18
  import type { P2PConfig } from '../../../config.js';
19
+ import { BatchTxRequesterCollector, SendBatchRequestCollector } from '../../../services/index.js';
19
20
  import type { IBatchRequestTxValidator } from '../../../services/reqresp/batch-tx-requester/tx_validator.js';
20
21
  import { RateLimitStatus } from '../../../services/reqresp/rate-limiter/rate_limiter.js';
22
+ import { MissingTxsTracker } from '../../../services/tx_collection/missing_txs_tracker.js';
21
23
  import {
22
- BatchTxRequesterCollector,
23
- SendBatchRequestCollector,
24
- } from '../../../services/tx_collection/proposal_tx_collector.js';
25
- import { AlwaysTrueCircuitVerifier } from '../../../test-helpers/reqresp-nodes.js';
26
- import {
24
+ AlwaysTrueCircuitVerifier,
27
25
  BENCHMARK_CONSTANTS,
28
26
  InMemoryAttestationPool,
29
27
  InMemoryTxPool,
@@ -31,7 +29,7 @@ import {
31
29
  calculateInternalTimeout,
32
30
  createMockEpochCache,
33
31
  createMockWorldStateSynchronizer,
34
- } from '../../../test-helpers/testbench-utils.js';
32
+ } from '../../../test-helpers/index.js';
35
33
  import { createP2PClient } from '../../index.js';
36
34
  import type { P2PClient } from '../../p2p_client.js';
37
35
  import {
@@ -116,7 +114,6 @@ async function startClient(config: P2PConfig, clientIndex: number) {
116
114
  };
117
115
 
118
116
  client = await createP2PClient(
119
- P2PClientType.Full,
120
117
  config as P2PConfig & DataStoreConfig,
121
118
  l2BlockSource as L2BlockSource & ContractDataSource,
122
119
  proofVerifier as ClientProtocolCircuitVerifier,
@@ -214,7 +211,13 @@ async function runCollector(cmd: Extract<WorkerCommand, { type: 'RUN_COLLECTOR'
214
211
  if (collectorType === 'batch-requester') {
215
212
  const collector = new BatchTxRequesterCollector(p2pService, logger, new DateProvider(), noopTxValidator);
216
213
  const fetched = await executeTimeout(
217
- (_signal: AbortSignal) => collector.collectTxs(parsedTxHashes, parsedProposal, pinnedPeer, internalTimeoutMs),
214
+ (_signal: AbortSignal) =>
215
+ collector.collectTxs(
216
+ MissingTxsTracker.fromArray(parsedTxHashes),
217
+ parsedProposal,
218
+ pinnedPeer,
219
+ internalTimeoutMs,
220
+ ),
218
221
  timeoutMs,
219
222
  () => new Error(`Collector timed out after ${timeoutMs}ms`),
220
223
  );
@@ -226,7 +229,13 @@ async function runCollector(cmd: Extract<WorkerCommand, { type: 'RUN_COLLECTOR'
226
229
  BENCHMARK_CONSTANTS.FIXED_MAX_RETRY_ATTEMPTS,
227
230
  );
228
231
  const fetched = await executeTimeout(
229
- (_signal: AbortSignal) => collector.collectTxs(parsedTxHashes, parsedProposal, pinnedPeer, internalTimeoutMs),
232
+ (_signal: AbortSignal) =>
233
+ collector.collectTxs(
234
+ MissingTxsTracker.fromArray(parsedTxHashes),
235
+ parsedProposal,
236
+ pinnedPeer,
237
+ internalTimeoutMs,
238
+ ),
230
239
  timeoutMs,
231
240
  () => new Error(`Collector timed out after ${timeoutMs}ms`),
232
241
  );
package/src/config.ts CHANGED
@@ -38,13 +38,16 @@ export interface P2PConfig
38
38
  ChainConfig,
39
39
  TxCollectionConfig,
40
40
  TxFileStoreConfig,
41
- Pick<SequencerConfig, 'blockDurationMs'> {
41
+ Pick<SequencerConfig, 'blockDurationMs' | 'expectedBlockProposalsPerSlot' | 'maxTxsPerBlock'> {
42
42
  /** A flag dictating whether the P2P subsystem should be enabled. */
43
43
  p2pEnabled: boolean;
44
44
 
45
45
  /** The frequency in which to check for new L2 blocks. */
46
46
  blockCheckIntervalMS: number;
47
47
 
48
+ /** The frequency in which to check for new L2 slots. */
49
+ slotCheckIntervalMS: number;
50
+
48
51
  /** The number of blocks to fetch in a single batch. */
49
52
  blockRequestBatchSize: number;
50
53
 
@@ -147,8 +150,8 @@ export interface P2PConfig
147
150
  /** The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb. */
148
151
  p2pStoreMapSizeKb?: number;
149
152
 
150
- /** Which calls are allowed in the public setup phase of a tx. */
151
- txPublicSetupAllowList: AllowedElement[];
153
+ /** Additional entries to extend the default setup allow list. */
154
+ txPublicSetupAllowListExtend: AllowedElement[];
152
155
 
153
156
  /** The maximum number of pending txs before evicting lower priority txs. */
154
157
  maxPendingTxCount: number;
@@ -170,10 +173,7 @@ export interface P2PConfig
170
173
  /** Whether transactions are disabled for this node. This means transactions will be rejected at the RPC and P2P layers. */
171
174
  disableTransactions: boolean;
172
175
 
173
- /** True to simulate discarding transactions. - For testing purposes only*/
174
- dropTransactions: boolean;
175
-
176
- /** The probability that a transaction is discarded. - For testing purposes only */
176
+ /** The probability that a transaction is discarded (0 = disabled). - For testing purposes only */
177
177
  dropTransactionsProbability: number;
178
178
 
179
179
  /** Whether to delete transactions from the pool after a reorg instead of moving them back to pending. */
@@ -184,6 +184,12 @@ export interface P2PConfig
184
184
 
185
185
  /** Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus */
186
186
  fishermanMode: boolean;
187
+
188
+ /** Broadcast block proposals even when a conflicting proposal for the same slot already exists in the pool (for testing purposes only). */
189
+ broadcastEquivocatedProposals?: boolean;
190
+
191
+ /** Minimum age (ms) a transaction must have been in the pool before it's eligible for block building. */
192
+ minTxPoolAgeMs: number;
187
193
  }
188
194
 
189
195
  export const DEFAULT_P2P_PORT = 40400;
@@ -204,6 +210,11 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
204
210
  description: 'The frequency in which to check for new L2 blocks.',
205
211
  ...numberConfigHelper(100),
206
212
  },
213
+ slotCheckIntervalMS: {
214
+ env: 'P2P_SLOT_CHECK_INTERVAL_MS',
215
+ description: 'The frequency in which to check for new L2 slots.',
216
+ ...numberConfigHelper(1000),
217
+ },
207
218
  debugDisableColocationPenalty: {
208
219
  env: 'DEBUG_P2P_DISABLE_COLOCATION_PENALTY',
209
220
  description: 'DEBUG: Disable colocation penalty - NEVER set to true in production',
@@ -382,12 +393,13 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
382
393
  parseEnv: (val: string | undefined) => (val ? +val : undefined),
383
394
  description: 'The maximum possible size of the P2P DB in KB. Overwrites the general dataStoreMapSizeKb.',
384
395
  },
385
- txPublicSetupAllowList: {
396
+ txPublicSetupAllowListExtend: {
386
397
  env: 'TX_PUBLIC_SETUP_ALLOWLIST',
387
398
  parseEnv: (val: string) => parseAllowList(val),
388
- description: 'The list of functions calls allowed to run in setup',
399
+ description:
400
+ 'Additional entries to extend the default setup allow list. Format: I:address:selector,C:classId:selector',
389
401
  printDefault: () =>
390
- 'AuthRegistry, FeeJuice.increase_public_balance, Token.increase_public_balance, FPC.prepare_fee',
402
+ 'Default: AuthRegistry._set_authorized, FeeJuice._increase_public_balance, Token._increase_public_balance, Token.transfer_in_public',
391
403
  },
392
404
  maxPendingTxCount: {
393
405
  env: 'P2P_MAX_PENDING_TX_COUNT',
@@ -416,11 +428,6 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
416
428
  description: 'Number of auth attempts to allow before peer is banned. Number is inclusive',
417
429
  ...numberConfigHelper(3),
418
430
  },
419
- dropTransactions: {
420
- env: 'P2P_DROP_TX',
421
- description: 'True to simulate discarding transactions. - For testing purposes only',
422
- ...booleanConfigHelper(false),
423
- },
424
431
  dropTransactionsProbability: {
425
432
  env: 'P2P_DROP_TX_CHANCE',
426
433
  description: 'The probability that a transaction is discarded (0 - 1). - For testing purposes only',
@@ -448,6 +455,16 @@ export const p2pConfigMappings: ConfigMappingsType<P2PConfig> = {
448
455
  'Whether to run in fisherman mode: validates all proposals and attestations but does not broadcast attestations or participate in consensus.',
449
456
  ...booleanConfigHelper(false),
450
457
  },
458
+ broadcastEquivocatedProposals: {
459
+ description:
460
+ 'Broadcast block proposals even when a conflicting proposal for the same slot already exists in the pool (for testing purposes only).',
461
+ ...booleanConfigHelper(false),
462
+ },
463
+ minTxPoolAgeMs: {
464
+ env: 'P2P_MIN_TX_POOL_AGE_MS',
465
+ description: 'Minimum age (ms) a transaction must have been in the pool before it is eligible for block building.',
466
+ ...numberConfigHelper(2_000),
467
+ },
451
468
  ...sharedSequencerConfigMappings,
452
469
  ...p2pReqRespConfigMappings,
453
470
  ...batchTxRequesterConfigMappings,
@@ -507,11 +524,9 @@ export const bootnodeConfigMappings = pickConfigMappings(
507
524
 
508
525
  /**
509
526
  * Parses a string to a list of allowed elements.
510
- * Each encoded is expected to be of one of the following formats
511
- * `I:${address}`
512
- * `I:${address}:${selector}`
513
- * `C:${classId}`
514
- * `C:${classId}:${selector}`
527
+ * Each entry is expected to be of one of the following formats:
528
+ * `I:${address}:${selector}` — instance (contract address) with function selector
529
+ * `C:${classId}:${selector}` — class with function selector
515
530
  *
516
531
  * @param value The string to parse
517
532
  * @returns A list of allowed elements
@@ -524,31 +539,34 @@ export function parseAllowList(value: string): AllowedElement[] {
524
539
  }
525
540
 
526
541
  for (const val of value.split(',')) {
527
- const [typeString, identifierString, selectorString] = val.split(':');
528
- const selector = selectorString !== undefined ? FunctionSelector.fromString(selectorString) : undefined;
542
+ const trimmed = val.trim();
543
+ if (!trimmed) {
544
+ continue;
545
+ }
546
+ const [typeString, identifierString, selectorString] = trimmed.split(':');
547
+
548
+ if (!selectorString) {
549
+ throw new Error(
550
+ `Invalid allow list entry "${trimmed}": selector is required. Expected format: I:address:selector or C:classId:selector`,
551
+ );
552
+ }
553
+
554
+ const selector = FunctionSelector.fromString(selectorString);
529
555
 
530
556
  if (typeString === 'I') {
531
- if (selector) {
532
- entries.push({
533
- address: AztecAddress.fromString(identifierString),
534
- selector,
535
- });
536
- } else {
537
- entries.push({
538
- address: AztecAddress.fromString(identifierString),
539
- });
540
- }
557
+ entries.push({
558
+ address: AztecAddress.fromString(identifierString),
559
+ selector,
560
+ });
541
561
  } else if (typeString === 'C') {
542
- if (selector) {
543
- entries.push({
544
- classId: Fr.fromHexString(identifierString),
545
- selector,
546
- });
547
- } else {
548
- entries.push({
549
- classId: Fr.fromHexString(identifierString),
550
- });
551
- }
562
+ entries.push({
563
+ classId: Fr.fromHexString(identifierString),
564
+ selector,
565
+ });
566
+ } else {
567
+ throw new Error(
568
+ `Invalid allow list entry "${trimmed}": unknown type "${typeString}". Expected "I" (instance) or "C" (class).`,
569
+ );
552
570
  }
553
571
  }
554
572
 
@@ -0,0 +1,12 @@
1
+ import type { TxPoolRejectionError } from '../mem_pools/tx_pool_v2/eviction/interfaces.js';
2
+
3
+ /** Error thrown when a transaction is not added to the mempool. */
4
+ export class TxPoolError extends Error {
5
+ public readonly data: TxPoolRejectionError;
6
+
7
+ constructor(public readonly reason: TxPoolRejectionError) {
8
+ super(reason.message);
9
+ this.name = 'TxPoolError';
10
+ this.data = reason;
11
+ }
12
+ }
package/src/index.ts CHANGED
@@ -7,5 +7,6 @@ export * from './enr/index.js';
7
7
  export * from './config.js';
8
8
  export * from './mem_pools/attestation_pool/index.js';
9
9
  export * from './mem_pools/tx_pool/index.js';
10
+ export * from './mem_pools/tx_pool_v2/index.js';
10
11
  export * from './msg_validators/index.js';
11
12
  export * from './services/index.js';
@@ -19,13 +19,17 @@ export type TryAddResult = {
19
19
  added: boolean;
20
20
  /** Whether the exact item already existed */
21
21
  alreadyExists: boolean;
22
- /** Total items for this position - used for duplicate detection */
23
- totalForPosition: number;
22
+ /** Count of items for the position. Meaning varies by method:
23
+ * - tryAddBlockProposal: proposals at (slot, indexWithinCheckpoint)
24
+ * - tryAddCheckpointProposal: proposals at slot
25
+ * - tryAddCheckpointAttestation: attestations by this signer for this slot */
26
+ count: number;
24
27
  };
25
28
 
26
- export const MAX_PROPOSALS_PER_SLOT = 5;
27
- export const MAX_PROPOSALS_PER_POSITION = 3;
28
- export const ATTESTATION_CAP_BUFFER = 10;
29
+ export const MAX_CHECKPOINT_PROPOSALS_PER_SLOT = 5;
30
+ export const MAX_BLOCK_PROPOSALS_PER_POSITION = 3;
31
+ /** Maximum attestations a single signer can make per slot before being rejected. */
32
+ export const MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER = 3;
29
33
 
30
34
  /** Public API interface for attestation pools. Used for typing mocks and test implementations. */
31
35
  export type AttestationPoolApi = Pick<
@@ -39,6 +43,7 @@ export type AttestationPoolApi = Pick<
39
43
  | 'deleteOlderThan'
40
44
  | 'getCheckpointAttestationsForSlot'
41
45
  | 'getCheckpointAttestationsForSlotAndProposal'
46
+ | 'hasBlockProposalsForSlot'
42
47
  | 'isEmpty'
43
48
  >;
44
49
 
@@ -69,6 +74,10 @@ export class AttestationPool {
69
74
  // Key: (slot << 10) | indexWithinCheckpoint, Value: archive string
70
75
  private blockProposalsForSlotAndIndex: AztecAsyncMultiMap<number, string>;
71
76
 
77
+ // Checkpoint attestations indexed by (slot, signer) for tracking attestations per (slot, signer) for duplicate detection
78
+ // Key: `${Fr(slot).toString()}-${signerAddress}` string (padded for lexicographic ordering), Value: `proposalId` strings
79
+ private checkpointAttestationsPerSlotAndSigner: AztecAsyncMultiMap<string, string>;
80
+
72
81
  constructor(
73
82
  private store: AztecAsyncKVStore,
74
83
  telemetry: TelemetryClient = getTelemetryClient(),
@@ -80,6 +89,7 @@ export class AttestationPool {
80
89
 
81
90
  // Initialize checkpoint attestations storage
82
91
  this.checkpointAttestations = store.openMap('checkpoint_attestations');
92
+ this.checkpointAttestationsPerSlotAndSigner = store.openMultiMap('checkpoint_attestations_per_slot_and_signer');
83
93
 
84
94
  // Initialize checkpoint proposal storage
85
95
  this.checkpointProposals = store.openMap('checkpoint_proposals');
@@ -133,6 +143,12 @@ export class AttestationPool {
133
143
  return { start: `${proposalKey}-`, end: `${proposalKey}-Z` };
134
144
  }
135
145
 
146
+ /** Creates a key for the per-signer-per-slot attestation index. Uses padded slot for lexicographic ordering. */
147
+ private getSlotSignerKey(slot: SlotNumber, signerAddress: string): string {
148
+ const slotStr = new Fr(slot).toString();
149
+ return `${slotStr}-${signerAddress}`;
150
+ }
151
+
136
152
  /** Number of bits reserved for indexWithinCheckpoint in position keys. */
137
153
  private static readonly INDEX_BITS = 10;
138
154
  /** Maximum indexWithinCheckpoint value (2^10 - 1 = 1023). */
@@ -166,21 +182,21 @@ export class AttestationPool {
166
182
  // Check if already exists
167
183
  const alreadyExists = await this.blockProposals.hasAsync(proposalId);
168
184
  if (alreadyExists) {
169
- const totalForPosition = await this.getBlockProposalCountForPosition(
185
+ const count = await this.getBlockProposalCountForPosition(
170
186
  blockProposal.slotNumber,
171
187
  blockProposal.indexWithinCheckpoint,
172
188
  );
173
- return { added: false, alreadyExists: true, totalForPosition };
189
+ return { added: false, alreadyExists: true, count };
174
190
  }
175
191
 
176
192
  // Get current count for position and check cap, do not add if exceeded
177
- const totalForPosition = await this.getBlockProposalCountForPosition(
193
+ const count = await this.getBlockProposalCountForPosition(
178
194
  blockProposal.slotNumber,
179
195
  blockProposal.indexWithinCheckpoint,
180
196
  );
181
197
 
182
- if (totalForPosition >= MAX_PROPOSALS_PER_POSITION) {
183
- return { added: false, alreadyExists: false, totalForPosition };
198
+ if (count >= MAX_BLOCK_PROPOSALS_PER_POSITION) {
199
+ return { added: false, alreadyExists: false, count };
184
200
  }
185
201
 
186
202
  // Add the proposal
@@ -195,7 +211,7 @@ export class AttestationPool {
195
211
  },
196
212
  );
197
213
 
198
- return { added: true, alreadyExists: false, totalForPosition: totalForPosition + 1 };
214
+ return { added: true, alreadyExists: false, count: count + 1 };
199
215
  });
200
216
  }
201
217
 
@@ -239,6 +255,13 @@ export class AttestationPool {
239
255
  return undefined;
240
256
  }
241
257
 
258
+ /** Checks if any block proposals exist for a given slot (at index 0). */
259
+ public async hasBlockProposalsForSlot(slot: SlotNumber): Promise<boolean> {
260
+ const positionKey = this.getBlockPositionKey(slot, 0);
261
+ const count = await this.blockProposalsForSlotAndIndex.getValueCountAsync(positionKey);
262
+ return count > 0;
263
+ }
264
+
242
265
  /**
243
266
  * Attempts to add a checkpoint proposal to the pool.
244
267
  *
@@ -261,14 +284,14 @@ export class AttestationPool {
261
284
  // Check if already exists
262
285
  const alreadyExists = await this.checkpointProposals.hasAsync(proposalId);
263
286
  if (alreadyExists) {
264
- const totalForPosition = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
265
- return { added: false, alreadyExists: true, totalForPosition };
287
+ const count = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
288
+ return { added: false, alreadyExists: true, count };
266
289
  }
267
290
 
268
291
  // Get current count for slot and check cap
269
- const totalForPosition = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
270
- if (totalForPosition >= MAX_PROPOSALS_PER_SLOT) {
271
- return { added: false, alreadyExists: false, totalForPosition };
292
+ const count = await this.checkpointProposalsForSlot.getValueCountAsync(proposal.slotNumber);
293
+ if (count >= MAX_CHECKPOINT_PROPOSALS_PER_SLOT) {
294
+ return { added: false, alreadyExists: false, count };
272
295
  }
273
296
 
274
297
  // Add the proposal if cap not exceeded
@@ -279,7 +302,7 @@ export class AttestationPool {
279
302
  slotNumber: proposal.slotNumber,
280
303
  });
281
304
 
282
- return { added: true, alreadyExists: false, totalForPosition: totalForPosition + 1 };
305
+ return { added: true, alreadyExists: false, count: count + 1 };
283
306
  });
284
307
  }
285
308
 
@@ -336,11 +359,10 @@ export class AttestationPool {
336
359
  }
337
360
 
338
361
  const address = sender.toString();
362
+ const ownKey = this.getAttestationKey(slotNumber, proposalId, address);
339
363
 
340
- await this.checkpointAttestations.set(
341
- this.getAttestationKey(slotNumber, proposalId, address),
342
- attestation.toBuffer(),
343
- );
364
+ await this.checkpointAttestations.set(ownKey, attestation.toBuffer());
365
+ this.metrics.trackMempoolItemAdded(ownKey);
344
366
 
345
367
  this.log.debug(`Added own checkpoint attestation for slot ${slotNumber} from ${address}`, {
346
368
  signature: attestation.signature.toString(),
@@ -406,9 +428,18 @@ export class AttestationPool {
406
428
  const attestationEndKey = new Fr(oldestSlot).toString();
407
429
  for await (const key of this.checkpointAttestations.keysAsync({ end: attestationEndKey })) {
408
430
  await this.checkpointAttestations.delete(key);
431
+ this.metrics.trackMempoolItemRemoved(key);
409
432
  numberOfAttestations++;
410
433
  }
411
434
 
435
+ // Clean up per-signer-per-slot index. Keys are formatted as `${Fr(slot).toString()}-${signerAddress}`.
436
+ // Since Fr pads to fixed-width hex, Fr(oldestSlot) is lexicographically greater than any key with
437
+ // a smaller slot (even with the signer suffix), so using it as the exclusive end bound is correct.
438
+ const slotSignerEndKey = new Fr(oldestSlot).toString();
439
+ for await (const key of this.checkpointAttestationsPerSlotAndSigner.keysAsync({ end: slotSignerEndKey })) {
440
+ await this.checkpointAttestationsPerSlotAndSigner.delete(key);
441
+ }
442
+
412
443
  // Delete checkpoint proposals for slots < oldestSlot, using checkpointProposalsForSlot as index
413
444
  for await (const slot of this.checkpointProposalsForSlot.keysAsync({ end: oldestSlot })) {
414
445
  const proposalIds = await toArray(this.checkpointProposalsForSlot.getValuesAsync(slot));
@@ -445,61 +476,82 @@ export class AttestationPool {
445
476
  *
446
477
  * This method performs validation and addition in a single call:
447
478
  * - Checks if the attestation already exists (returns alreadyExists: true if so)
448
- * - Checks if the (slot, proposalId) has reached the attestation cap (returns added: false if so)
479
+ * - Checks if this signer has reached the per-signer attestation cap for this slot
449
480
  * - Adds the attestation if validation passes
450
481
  *
451
482
  * @param attestation - The checkpoint attestation to add
452
- * @param committeeSize - Committee size for the attestation's slot
453
- * @returns Result indicating whether the attestation was added and existence info
483
+ * @returns Result indicating whether the attestation was added, existence info, and count of
484
+ * attestations by this signer for this slot (for equivocation detection)
454
485
  */
455
- public async tryAddCheckpointAttestation(
456
- attestation: CheckpointAttestation,
457
- committeeSize: number,
458
- ): Promise<TryAddResult> {
486
+ public async tryAddCheckpointAttestation(attestation: CheckpointAttestation): Promise<TryAddResult> {
459
487
  const slotNumber = attestation.payload.header.slotNumber;
460
488
  const proposalId = attestation.archive.toString();
461
489
  const sender = attestation.getSender();
462
490
 
463
491
  if (!sender) {
464
- return { added: false, alreadyExists: false, totalForPosition: 0 };
492
+ return { added: false, alreadyExists: false, count: 0 };
465
493
  }
466
494
 
495
+ const signerAddress = sender.toString();
496
+
467
497
  return await this.store.transactionAsync(async () => {
468
- const key = this.getAttestationKey(slotNumber, proposalId, sender.toString());
498
+ const key = this.getAttestationKey(slotNumber, proposalId, signerAddress);
469
499
  const alreadyExists = await this.checkpointAttestations.hasAsync(key);
470
500
 
501
+ // Get count of attestations by this signer for this slot (for duplicate detection)
502
+ const signerAttestationCount = await this.getSignerAttestationCountForSlot(slotNumber, signerAddress);
503
+
471
504
  if (alreadyExists) {
472
- const total = await this.getAttestationCount(slotNumber, proposalId);
473
- return { added: false, alreadyExists: true, totalForPosition: total };
505
+ return {
506
+ added: false,
507
+ alreadyExists: true,
508
+ count: signerAttestationCount,
509
+ };
474
510
  }
475
511
 
476
- const limit = committeeSize + ATTESTATION_CAP_BUFFER;
477
- const currentCount = await this.getAttestationCount(slotNumber, proposalId);
478
-
479
- if (currentCount >= limit) {
480
- return { added: false, alreadyExists: false, totalForPosition: currentCount };
512
+ // Check if this signer has exceeded the per-signer cap for this slot
513
+ if (signerAttestationCount >= MAX_ATTESTATIONS_PER_SLOT_AND_SIGNER) {
514
+ this.log.debug(`Rejecting attestation: signer ${signerAddress} exceeded per-slot cap for slot ${slotNumber}`, {
515
+ slotNumber,
516
+ signerAddress,
517
+ proposalId,
518
+ signerAttestationCount,
519
+ });
520
+ return {
521
+ added: false,
522
+ alreadyExists: false,
523
+ count: signerAttestationCount,
524
+ };
481
525
  }
482
526
 
527
+ // Add the attestation
483
528
  await this.checkpointAttestations.set(key, attestation.toBuffer());
529
+ this.metrics.trackMempoolItemAdded(key);
484
530
 
485
- this.log.debug(`Added checkpoint attestation for slot ${slotNumber} from ${sender.toString()}`, {
531
+ // Track this attestation in the per-signer-per-slot index for duplicate detection
532
+ const slotSignerKey = this.getSlotSignerKey(slotNumber, signerAddress);
533
+ await this.checkpointAttestationsPerSlotAndSigner.set(slotSignerKey, proposalId);
534
+
535
+ this.log.debug(`Added checkpoint attestation for slot ${slotNumber} from ${signerAddress}`, {
486
536
  signature: attestation.signature.toString(),
487
537
  slotNumber,
488
- address: sender.toString(),
538
+ address: signerAddress,
489
539
  proposalId,
490
540
  });
491
- return { added: true, alreadyExists: false, totalForPosition: currentCount + 1 };
541
+
542
+ // Return the new count
543
+ return {
544
+ added: true,
545
+ alreadyExists: false,
546
+ count: signerAttestationCount + 1,
547
+ };
492
548
  });
493
549
  }
494
550
 
495
- /** Gets the count of attestations for a given (slot, proposalId). */
496
- private async getAttestationCount(slot: SlotNumber, proposalId: string): Promise<number> {
497
- const range = this.getAttestationKeyRangeForProposal(slot, proposalId);
498
- let count = 0;
499
- for await (const _ of this.checkpointAttestations.keysAsync(range)) {
500
- count++;
501
- }
502
- return count;
551
+ /** Gets the count of attestations by a specific signer for a given slot. */
552
+ private async getSignerAttestationCountForSlot(slot: SlotNumber, signerAddress: string): Promise<number> {
553
+ const slotSignerKey = this.getSlotSignerKey(slot, signerAddress);
554
+ return await this.checkpointAttestationsPerSlotAndSigner.getValueCountAsync(slotSignerKey);
503
555
  }
504
556
  }
505
557