@aztec/p2p 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa

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 (606) hide show
  1. package/README.md +130 -3
  2. package/dest/bootstrap/bootstrap.d.ts +4 -3
  3. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  4. package/dest/bootstrap/bootstrap.js +26 -10
  5. package/dest/client/factory.d.ts +13 -12
  6. package/dest/client/factory.d.ts.map +1 -1
  7. package/dest/client/factory.js +70 -21
  8. package/dest/client/index.d.ts +1 -1
  9. package/dest/client/interface.d.ts +104 -39
  10. package/dest/client/interface.d.ts.map +1 -1
  11. package/dest/client/p2p_client.d.ts +76 -92
  12. package/dest/client/p2p_client.d.ts.map +1 -1
  13. package/dest/client/p2p_client.js +685 -344
  14. package/dest/config.d.ts +175 -87
  15. package/dest/config.d.ts.map +1 -1
  16. package/dest/config.js +180 -59
  17. package/dest/enr/generate-enr.d.ts +1 -1
  18. package/dest/enr/index.d.ts +1 -1
  19. package/dest/errors/attestation-pool.error.d.ts +7 -0
  20. package/dest/errors/attestation-pool.error.d.ts.map +1 -0
  21. package/dest/errors/attestation-pool.error.js +12 -0
  22. package/dest/errors/p2p-service.error.d.ts +9 -0
  23. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  24. package/dest/errors/p2p-service.error.js +10 -0
  25. package/dest/errors/reqresp.error.d.ts +9 -16
  26. package/dest/errors/reqresp.error.d.ts.map +1 -1
  27. package/dest/errors/reqresp.error.js +10 -17
  28. package/dest/errors/tx-pool.error.d.ts +8 -0
  29. package/dest/errors/tx-pool.error.d.ts.map +1 -0
  30. package/dest/errors/tx-pool.error.js +9 -0
  31. package/dest/index.d.ts +2 -2
  32. package/dest/index.d.ts.map +1 -1
  33. package/dest/index.js +1 -1
  34. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +156 -57
  35. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  36. package/dest/mem_pools/attestation_pool/attestation_pool.js +518 -3
  37. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +2 -2
  38. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  39. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +694 -294
  40. package/dest/mem_pools/attestation_pool/index.d.ts +2 -3
  41. package/dest/mem_pools/attestation_pool/index.d.ts.map +1 -1
  42. package/dest/mem_pools/attestation_pool/index.js +1 -2
  43. package/dest/mem_pools/attestation_pool/mocks.d.ts +234 -10
  44. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  45. package/dest/mem_pools/attestation_pool/mocks.js +19 -13
  46. package/dest/mem_pools/index.d.ts +3 -3
  47. package/dest/mem_pools/index.d.ts.map +1 -1
  48. package/dest/mem_pools/index.js +1 -1
  49. package/dest/mem_pools/instrumentation.d.ts +16 -1
  50. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  51. package/dest/mem_pools/instrumentation.js +58 -10
  52. package/dest/mem_pools/interface.d.ts +6 -7
  53. package/dest/mem_pools/interface.d.ts.map +1 -1
  54. package/dest/mem_pools/tx_pool_v2/archive/index.d.ts +2 -0
  55. package/dest/mem_pools/tx_pool_v2/archive/index.d.ts.map +1 -0
  56. package/dest/mem_pools/tx_pool_v2/archive/index.js +1 -0
  57. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts +39 -0
  58. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.d.ts.map +1 -0
  59. package/dest/mem_pools/tx_pool_v2/archive/tx_archive.js +97 -0
  60. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts +104 -0
  61. package/dest/mem_pools/tx_pool_v2/deleted_pool.d.ts.map +1 -0
  62. package/dest/mem_pools/tx_pool_v2/deleted_pool.js +251 -0
  63. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts +47 -0
  64. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.d.ts.map +1 -0
  65. package/dest/mem_pools/tx_pool_v2/eviction/eviction_manager.js +128 -0
  66. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +17 -0
  67. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -0
  68. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +94 -0
  69. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +19 -0
  70. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -0
  71. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +97 -0
  72. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts +11 -0
  73. package/dest/mem_pools/tx_pool_v2/eviction/index.d.ts.map +1 -0
  74. package/dest/mem_pools/tx_pool_v2/eviction/index.js +12 -0
  75. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts +16 -0
  76. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.d.ts.map +1 -0
  77. package/dest/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.js +62 -0
  78. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +180 -0
  79. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -0
  80. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.js +25 -0
  81. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts +15 -0
  82. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.d.ts.map +1 -0
  83. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.js +65 -0
  84. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts +17 -0
  85. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.d.ts.map +1 -0
  86. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +93 -0
  87. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +16 -0
  88. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -0
  89. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +78 -0
  90. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +20 -0
  91. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -0
  92. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +75 -0
  93. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +15 -0
  94. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -0
  95. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +19 -0
  96. package/dest/mem_pools/tx_pool_v2/index.d.ts +6 -0
  97. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -0
  98. package/dest/mem_pools/tx_pool_v2/index.js +5 -0
  99. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts +15 -0
  100. package/dest/mem_pools/tx_pool_v2/instrumentation.d.ts.map +1 -0
  101. package/dest/mem_pools/tx_pool_v2/instrumentation.js +43 -0
  102. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +243 -0
  103. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -0
  104. package/dest/mem_pools/tx_pool_v2/interfaces.js +11 -0
  105. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +137 -0
  106. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -0
  107. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +223 -0
  108. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts +26 -0
  109. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.d.ts.map +1 -0
  110. package/dest/mem_pools/tx_pool_v2/tx_pool_bench_metrics.js +70 -0
  111. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +122 -0
  112. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -0
  113. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +368 -0
  114. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +68 -0
  115. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -0
  116. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +178 -0
  117. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +91 -0
  118. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -0
  119. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +1013 -0
  120. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +15 -7
  121. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  122. package/dest/msg_validators/attestation_validator/attestation_validator.js +82 -26
  123. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts +24 -0
  124. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.d.ts.map +1 -0
  125. package/dest/msg_validators/attestation_validator/fisherman_attestation_validator.js +75 -0
  126. package/dest/msg_validators/attestation_validator/index.d.ts +2 -1
  127. package/dest/msg_validators/attestation_validator/index.d.ts.map +1 -1
  128. package/dest/msg_validators/attestation_validator/index.js +1 -0
  129. package/dest/msg_validators/index.d.ts +2 -2
  130. package/dest/msg_validators/index.d.ts.map +1 -1
  131. package/dest/msg_validators/index.js +1 -1
  132. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts +1 -1
  133. package/dest/msg_validators/msg_seen_validator/msg_seen_validator.d.ts.map +1 -1
  134. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +16 -0
  135. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -0
  136. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +14 -0
  137. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +16 -0
  138. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -0
  139. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +26 -0
  140. package/dest/msg_validators/proposal_validator/index.d.ts +4 -0
  141. package/dest/msg_validators/proposal_validator/index.d.ts.map +1 -0
  142. package/dest/msg_validators/proposal_validator/index.js +3 -0
  143. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +40 -0
  144. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -0
  145. package/dest/msg_validators/proposal_validator/proposal_validator.js +186 -0
  146. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +4 -4
  147. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  148. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +11 -18
  149. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  150. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  151. package/dest/msg_validators/tx_validator/allowed_public_setup.js +25 -21
  152. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  153. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  154. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  155. package/dest/msg_validators/tx_validator/archive_cache.d.ts +3 -3
  156. package/dest/msg_validators/tx_validator/archive_cache.d.ts.map +1 -1
  157. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +20 -6
  158. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  159. package/dest/msg_validators/tx_validator/block_header_validator.js +4 -3
  160. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts +15 -0
  161. package/dest/msg_validators/tx_validator/cached_tx_validator.d.ts.map +1 -0
  162. package/dest/msg_validators/tx_validator/cached_tx_validator.js +19 -0
  163. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  164. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  165. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  166. package/dest/msg_validators/tx_validator/data_validator.d.ts +4 -1
  167. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  168. package/dest/msg_validators/tx_validator/data_validator.js +40 -3
  169. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +15 -4
  170. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  171. package/dest/msg_validators/tx_validator/double_spend_validator.js +7 -6
  172. package/dest/msg_validators/tx_validator/factory.d.ts +138 -6
  173. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  174. package/dest/msg_validators/tx_validator/factory.js +268 -58
  175. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +10 -0
  176. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -0
  177. package/dest/msg_validators/tx_validator/fee_payer_balance.js +24 -0
  178. package/dest/msg_validators/tx_validator/gas_validator.d.ts +105 -3
  179. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  180. package/dest/msg_validators/tx_validator/gas_validator.js +146 -67
  181. package/dest/msg_validators/tx_validator/index.d.ts +6 -1
  182. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  183. package/dest/msg_validators/tx_validator/index.js +5 -0
  184. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +4 -3
  185. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  186. package/dest/msg_validators/tx_validator/metadata_validator.js +6 -6
  187. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  188. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  189. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  190. package/dest/msg_validators/tx_validator/phases_validator.d.ts +24 -3
  191. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  192. package/dest/msg_validators/tx_validator/phases_validator.js +78 -28
  193. package/dest/msg_validators/tx_validator/size_validator.d.ts +8 -0
  194. package/dest/msg_validators/tx_validator/size_validator.d.ts.map +1 -0
  195. package/dest/msg_validators/tx_validator/size_validator.js +23 -0
  196. package/dest/msg_validators/tx_validator/test_utils.d.ts +2 -2
  197. package/dest/msg_validators/tx_validator/test_utils.d.ts.map +1 -1
  198. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts +23 -5
  199. package/dest/msg_validators/tx_validator/timestamp_validator.d.ts.map +1 -1
  200. package/dest/msg_validators/tx_validator/timestamp_validator.js +8 -8
  201. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts +3 -2
  202. package/dest/msg_validators/tx_validator/tx_permitted_validator.d.ts.map +1 -1
  203. package/dest/msg_validators/tx_validator/tx_permitted_validator.js +2 -2
  204. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +4 -2
  205. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  206. package/dest/msg_validators/tx_validator/tx_proof_validator.js +4 -2
  207. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts +48 -0
  208. package/dest/msg_validators/tx_validator/tx_validation_cache.d.ts.map +1 -0
  209. package/dest/msg_validators/tx_validator/tx_validation_cache.js +68 -0
  210. package/dest/services/data_store.d.ts +1 -1
  211. package/dest/services/data_store.d.ts.map +1 -1
  212. package/dest/services/data_store.js +14 -10
  213. package/dest/services/discv5/discV5_service.d.ts +13 -2
  214. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  215. package/dest/services/discv5/discV5_service.js +120 -24
  216. package/dest/services/discv5/persisted_enr_store.d.ts +38 -0
  217. package/dest/services/discv5/persisted_enr_store.d.ts.map +1 -0
  218. package/dest/services/discv5/persisted_enr_store.js +145 -0
  219. package/dest/services/dummy_service.d.ts +40 -16
  220. package/dest/services/dummy_service.d.ts.map +1 -1
  221. package/dest/services/dummy_service.js +61 -14
  222. package/dest/services/encoding.d.ts +24 -7
  223. package/dest/services/encoding.d.ts.map +1 -1
  224. package/dest/services/encoding.js +48 -30
  225. package/dest/services/gossipsub/index.d.ts +3 -0
  226. package/dest/services/gossipsub/index.d.ts.map +1 -0
  227. package/dest/services/gossipsub/index.js +2 -0
  228. package/dest/services/gossipsub/scoring.d.ts +21 -3
  229. package/dest/services/gossipsub/scoring.d.ts.map +1 -1
  230. package/dest/services/gossipsub/scoring.js +24 -7
  231. package/dest/services/gossipsub/topic_score_params.d.ts +167 -0
  232. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -0
  233. package/dest/services/gossipsub/topic_score_params.js +336 -0
  234. package/dest/services/index.d.ts +2 -1
  235. package/dest/services/index.d.ts.map +1 -1
  236. package/dest/services/index.js +1 -0
  237. package/dest/services/libp2p/instrumentation.d.ts +5 -1
  238. package/dest/services/libp2p/instrumentation.d.ts.map +1 -1
  239. package/dest/services/libp2p/instrumentation.js +49 -70
  240. package/dest/services/libp2p/libp2p_service.d.ts +127 -110
  241. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  242. package/dest/services/libp2p/libp2p_service.js +1385 -447
  243. package/dest/services/peer-manager/interface.d.ts +1 -1
  244. package/dest/services/peer-manager/metrics.d.ts +11 -2
  245. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  246. package/dest/services/peer-manager/metrics.js +45 -16
  247. package/dest/services/peer-manager/peer_manager.d.ts +21 -35
  248. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  249. package/dest/services/peer-manager/peer_manager.js +89 -38
  250. package/dest/services/peer-manager/peer_scoring.d.ts +39 -2
  251. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  252. package/dest/services/peer-manager/peer_scoring.js +168 -15
  253. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +44 -0
  254. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -0
  255. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +534 -0
  256. package/dest/services/reqresp/batch-tx-requester/config.d.ts +17 -0
  257. package/dest/services/reqresp/batch-tx-requester/config.d.ts.map +1 -0
  258. package/dest/services/reqresp/batch-tx-requester/config.js +27 -0
  259. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +50 -0
  260. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -0
  261. package/dest/services/reqresp/batch-tx-requester/interface.js +1 -0
  262. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +35 -0
  263. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -0
  264. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +136 -0
  265. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +62 -0
  266. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -0
  267. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +176 -0
  268. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts +11 -0
  269. package/dest/services/reqresp/batch-tx-requester/tx_validator.d.ts.map +1 -0
  270. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +7 -0
  271. package/dest/services/reqresp/config.d.ts +15 -3
  272. package/dest/services/reqresp/config.d.ts.map +1 -1
  273. package/dest/services/reqresp/config.js +11 -0
  274. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +2 -4
  275. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  276. package/dest/services/reqresp/connection-sampler/connection_sampler.js +12 -0
  277. package/dest/services/reqresp/constants.d.ts +12 -0
  278. package/dest/services/reqresp/constants.d.ts.map +1 -0
  279. package/dest/services/reqresp/constants.js +7 -0
  280. package/dest/services/reqresp/index.d.ts +1 -1
  281. package/dest/services/reqresp/interface.d.ts +27 -18
  282. package/dest/services/reqresp/interface.d.ts.map +1 -1
  283. package/dest/services/reqresp/interface.js +23 -19
  284. package/dest/services/reqresp/metrics.d.ts +6 -5
  285. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  286. package/dest/services/reqresp/metrics.js +16 -21
  287. package/dest/services/reqresp/protocols/auth.d.ts +2 -2
  288. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -1
  289. package/dest/services/reqresp/protocols/auth.js +2 -2
  290. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +8 -3
  291. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -1
  292. package/dest/services/reqresp/protocols/block_txs/bitvector.js +15 -2
  293. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +7 -5
  294. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -1
  295. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +35 -14
  296. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +37 -11
  297. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -1
  298. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +85 -21
  299. package/dest/services/reqresp/protocols/block_txs/index.d.ts +1 -1
  300. package/dest/services/reqresp/protocols/goodbye.d.ts +1 -1
  301. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  302. package/dest/services/reqresp/protocols/index.d.ts +1 -2
  303. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  304. package/dest/services/reqresp/protocols/index.js +0 -1
  305. package/dest/services/reqresp/protocols/ping.d.ts +1 -1
  306. package/dest/services/reqresp/protocols/status.d.ts +6 -5
  307. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  308. package/dest/services/reqresp/protocols/status.js +7 -3
  309. package/dest/services/reqresp/protocols/tx.d.ts +8 -3
  310. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  311. package/dest/services/reqresp/protocols/tx.js +21 -3
  312. package/dest/services/reqresp/rate-limiter/index.d.ts +1 -1
  313. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +6 -5
  314. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  315. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  316. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts +1 -1
  317. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  318. package/dest/services/reqresp/rate-limiter/rate_limits.js +3 -13
  319. package/dest/services/reqresp/reqresp.d.ts +12 -69
  320. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  321. package/dest/services/reqresp/reqresp.js +480 -200
  322. package/dest/services/reqresp/status.d.ts +2 -2
  323. package/dest/services/reqresp/status.d.ts.map +1 -1
  324. package/dest/services/service.d.ts +78 -13
  325. package/dest/services/service.d.ts.map +1 -1
  326. package/dest/services/tx_collection/config.d.ts +11 -11
  327. package/dest/services/tx_collection/config.d.ts.map +1 -1
  328. package/dest/services/tx_collection/config.js +28 -27
  329. package/dest/services/tx_collection/file_store_tx_collection.d.ts +37 -0
  330. package/dest/services/tx_collection/file_store_tx_collection.d.ts.map +1 -0
  331. package/dest/services/tx_collection/file_store_tx_collection.js +127 -0
  332. package/dest/services/tx_collection/file_store_tx_source.d.ts +38 -0
  333. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -0
  334. package/dest/services/tx_collection/file_store_tx_source.js +100 -0
  335. package/dest/services/tx_collection/index.d.ts +3 -2
  336. package/dest/services/tx_collection/index.d.ts.map +1 -1
  337. package/dest/services/tx_collection/index.js +1 -0
  338. package/dest/services/tx_collection/instrumentation.d.ts +1 -1
  339. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -1
  340. package/dest/services/tx_collection/instrumentation.js +9 -13
  341. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  342. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  343. package/dest/services/tx_collection/request_tracker.js +84 -0
  344. package/dest/services/tx_collection/tx_collection.d.ts +51 -57
  345. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  346. package/dest/services/tx_collection/tx_collection.js +298 -70
  347. package/dest/services/tx_collection/tx_collection_sink.d.ts +20 -10
  348. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -1
  349. package/dest/services/tx_collection/tx_collection_sink.js +28 -31
  350. package/dest/services/tx_collection/tx_source.d.ts +13 -7
  351. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  352. package/dest/services/tx_collection/tx_source.js +29 -7
  353. package/dest/services/tx_file_store/config.d.ts +16 -0
  354. package/dest/services/tx_file_store/config.d.ts.map +1 -0
  355. package/dest/services/tx_file_store/config.js +22 -0
  356. package/dest/services/tx_file_store/index.d.ts +4 -0
  357. package/dest/services/tx_file_store/index.d.ts.map +1 -0
  358. package/dest/services/tx_file_store/index.js +3 -0
  359. package/dest/services/tx_file_store/instrumentation.d.ts +15 -0
  360. package/dest/services/tx_file_store/instrumentation.d.ts.map +1 -0
  361. package/dest/services/tx_file_store/instrumentation.js +29 -0
  362. package/dest/services/tx_file_store/tx_file_store.d.ts +46 -0
  363. package/dest/services/tx_file_store/tx_file_store.d.ts.map +1 -0
  364. package/dest/services/tx_file_store/tx_file_store.js +142 -0
  365. package/dest/services/tx_provider.d.ts +9 -5
  366. package/dest/services/tx_provider.d.ts.map +1 -1
  367. package/dest/services/tx_provider.js +23 -10
  368. package/dest/services/tx_provider_instrumentation.d.ts +5 -2
  369. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -1
  370. package/dest/services/tx_provider_instrumentation.js +14 -14
  371. package/dest/test-helpers/generate-peer-id-private-keys.d.ts +1 -1
  372. package/dest/test-helpers/get-ports.d.ts +1 -1
  373. package/dest/test-helpers/get-ports.d.ts.map +1 -1
  374. package/dest/test-helpers/index.d.ts +3 -1
  375. package/dest/test-helpers/index.d.ts.map +1 -1
  376. package/dest/test-helpers/index.js +2 -0
  377. package/dest/test-helpers/make-enrs.d.ts +1 -1
  378. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -8
  379. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  380. package/dest/test-helpers/make-test-p2p-clients.js +5 -3
  381. package/dest/test-helpers/mock-pubsub.d.ts +48 -8
  382. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  383. package/dest/test-helpers/mock-pubsub.js +115 -14
  384. package/dest/test-helpers/mock-tx-helpers.d.ts +2 -2
  385. package/dest/test-helpers/mock-tx-helpers.d.ts.map +1 -1
  386. package/dest/test-helpers/mock-tx-helpers.js +1 -1
  387. package/dest/test-helpers/reqresp-nodes.d.ts +5 -7
  388. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  389. package/dest/test-helpers/reqresp-nodes.js +19 -20
  390. package/dest/test-helpers/test_tx_provider.d.ts +42 -0
  391. package/dest/test-helpers/test_tx_provider.d.ts.map +1 -0
  392. package/dest/test-helpers/test_tx_provider.js +44 -0
  393. package/dest/test-helpers/testbench-utils.d.ts +164 -0
  394. package/dest/test-helpers/testbench-utils.d.ts.map +1 -0
  395. package/dest/test-helpers/testbench-utils.js +400 -0
  396. package/dest/testbench/p2p_client_testbench_worker.d.ts +26 -2
  397. package/dest/testbench/p2p_client_testbench_worker.d.ts.map +1 -1
  398. package/dest/testbench/p2p_client_testbench_worker.js +289 -128
  399. package/dest/testbench/parse_log_file.d.ts +1 -1
  400. package/dest/testbench/testbench.d.ts +1 -1
  401. package/dest/testbench/worker_client_manager.d.ts +57 -6
  402. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  403. package/dest/testbench/worker_client_manager.js +277 -44
  404. package/dest/types/index.d.ts +1 -1
  405. package/dest/util.d.ts +14 -8
  406. package/dest/util.d.ts.map +1 -1
  407. package/dest/util.js +41 -11
  408. package/dest/versioning.d.ts +3 -6
  409. package/dest/versioning.d.ts.map +1 -1
  410. package/dest/versioning.js +3 -24
  411. package/package.json +21 -20
  412. package/src/bootstrap/bootstrap.ts +24 -7
  413. package/src/client/factory.ts +141 -46
  414. package/src/client/interface.ts +114 -47
  415. package/src/client/p2p_client.ts +356 -424
  416. package/src/client/test/p2p_client.batch_tx_requester.bench.README.md +197 -0
  417. package/src/config.ts +316 -67
  418. package/src/errors/attestation-pool.error.ts +13 -0
  419. package/src/errors/p2p-service.error.ts +11 -0
  420. package/src/errors/reqresp.error.ts +13 -19
  421. package/src/errors/tx-pool.error.ts +12 -0
  422. package/src/index.ts +1 -1
  423. package/src/mem_pools/attestation_pool/attestation_pool.ts +598 -56
  424. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +796 -316
  425. package/src/mem_pools/attestation_pool/index.ts +9 -2
  426. package/src/mem_pools/attestation_pool/mocks.ts +29 -17
  427. package/src/mem_pools/index.ts +2 -2
  428. package/src/mem_pools/instrumentation.ts +58 -10
  429. package/src/mem_pools/interface.ts +5 -7
  430. package/src/mem_pools/tx_pool_v2/README.md +283 -0
  431. package/src/mem_pools/tx_pool_v2/archive/index.ts +1 -0
  432. package/src/mem_pools/tx_pool_v2/archive/tx_archive.ts +112 -0
  433. package/src/mem_pools/tx_pool_v2/deleted_pool.ts +321 -0
  434. package/src/mem_pools/tx_pool_v2/eviction/eviction_manager.ts +160 -0
  435. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +122 -0
  436. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +125 -0
  437. package/src/mem_pools/tx_pool_v2/eviction/index.ts +28 -0
  438. package/src/mem_pools/tx_pool_v2/eviction/insufficient_fee_per_gas_eviction_rule.ts +65 -0
  439. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +219 -0
  440. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_mining_rule.ts +74 -0
  441. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +101 -0
  442. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +91 -0
  443. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +99 -0
  444. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +32 -0
  445. package/src/mem_pools/tx_pool_v2/index.ts +12 -0
  446. package/src/mem_pools/tx_pool_v2/instrumentation.ts +69 -0
  447. package/src/mem_pools/tx_pool_v2/interfaces.ts +274 -0
  448. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +349 -0
  449. package/src/mem_pools/tx_pool_v2/tx_pool_bench_metrics.ts +77 -0
  450. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +465 -0
  451. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +252 -0
  452. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +1215 -0
  453. package/src/msg_validators/attestation_validator/README.md +49 -0
  454. package/src/msg_validators/attestation_validator/attestation_validator.ts +78 -33
  455. package/src/msg_validators/attestation_validator/fisherman_attestation_validator.ts +102 -0
  456. package/src/msg_validators/attestation_validator/index.ts +1 -0
  457. package/src/msg_validators/index.ts +1 -1
  458. package/src/msg_validators/proposal_validator/README.md +123 -0
  459. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +32 -0
  460. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +49 -0
  461. package/src/msg_validators/proposal_validator/index.ts +3 -0
  462. package/src/msg_validators/proposal_validator/proposal_validator.ts +198 -0
  463. package/src/msg_validators/tx_validator/README.md +129 -0
  464. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +8 -17
  465. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  466. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  467. package/src/msg_validators/tx_validator/archive_cache.ts +2 -2
  468. package/src/msg_validators/tx_validator/block_header_validator.ts +21 -8
  469. package/src/msg_validators/tx_validator/cached_tx_validator.ts +31 -0
  470. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  471. package/src/msg_validators/tx_validator/data_validator.ts +62 -7
  472. package/src/msg_validators/tx_validator/double_spend_validator.ts +15 -9
  473. package/src/msg_validators/tx_validator/factory.ts +433 -58
  474. package/src/msg_validators/tx_validator/fee_payer_balance.ts +44 -0
  475. package/src/msg_validators/tx_validator/gas_validator.ts +206 -76
  476. package/src/msg_validators/tx_validator/index.ts +5 -0
  477. package/src/msg_validators/tx_validator/metadata_validator.ts +31 -12
  478. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  479. package/src/msg_validators/tx_validator/phases_validator.ts +90 -31
  480. package/src/msg_validators/tx_validator/size_validator.ts +22 -0
  481. package/src/msg_validators/tx_validator/test_utils.ts +1 -1
  482. package/src/msg_validators/tx_validator/timestamp_validator.ts +30 -19
  483. package/src/msg_validators/tx_validator/tx_permitted_validator.ts +8 -3
  484. package/src/msg_validators/tx_validator/tx_proof_validator.ts +10 -3
  485. package/src/msg_validators/tx_validator/tx_validation_cache.ts +101 -0
  486. package/src/services/data_store.ts +14 -19
  487. package/src/services/discv5/discV5_service.ts +127 -15
  488. package/src/services/discv5/persisted_enr_store.ts +158 -0
  489. package/src/services/dummy_service.ts +82 -38
  490. package/src/services/encoding.ts +46 -29
  491. package/src/services/gossipsub/README.md +663 -0
  492. package/src/services/gossipsub/index.ts +2 -0
  493. package/src/services/gossipsub/scoring.ts +29 -5
  494. package/src/services/gossipsub/topic_score_params.ts +478 -0
  495. package/src/services/index.ts +1 -0
  496. package/src/services/libp2p/instrumentation.ts +54 -72
  497. package/src/services/libp2p/libp2p_service.ts +1152 -497
  498. package/src/services/peer-manager/metrics.ts +51 -16
  499. package/src/services/peer-manager/peer_manager.ts +98 -29
  500. package/src/services/peer-manager/peer_scoring.ts +170 -9
  501. package/src/services/reqresp/README.md +194 -0
  502. package/src/services/reqresp/batch-tx-requester/README.md +344 -0
  503. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +660 -0
  504. package/src/services/reqresp/batch-tx-requester/config.ts +40 -0
  505. package/src/services/reqresp/batch-tx-requester/interface.ts +61 -0
  506. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +168 -0
  507. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +249 -0
  508. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +24 -0
  509. package/src/services/reqresp/config.ts +19 -2
  510. package/src/services/reqresp/connection-sampler/connection_sampler.ts +19 -1
  511. package/src/services/reqresp/constants.ts +14 -0
  512. package/src/services/reqresp/interface.ts +48 -46
  513. package/src/services/reqresp/metrics.ts +35 -27
  514. package/src/services/reqresp/protocols/auth.ts +2 -2
  515. package/src/services/reqresp/protocols/block_txs/bitvector.ts +19 -2
  516. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +44 -17
  517. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +109 -17
  518. package/src/services/reqresp/protocols/index.ts +0 -1
  519. package/src/services/reqresp/protocols/status.ts +16 -12
  520. package/src/services/reqresp/protocols/tx.ts +24 -5
  521. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  522. package/src/services/reqresp/rate-limiter/rate_limits.ts +3 -13
  523. package/src/services/reqresp/reqresp.ts +107 -223
  524. package/src/services/service.ts +102 -31
  525. package/src/services/tx_collection/config.ts +42 -37
  526. package/src/services/tx_collection/file_store_tx_collection.ts +153 -0
  527. package/src/services/tx_collection/file_store_tx_source.ts +129 -0
  528. package/src/services/tx_collection/index.ts +2 -1
  529. package/src/services/tx_collection/instrumentation.ts +5 -13
  530. package/src/services/tx_collection/request_tracker.ts +127 -0
  531. package/src/services/tx_collection/tx_collection.ts +368 -115
  532. package/src/services/tx_collection/tx_collection_sink.ts +32 -36
  533. package/src/services/tx_collection/tx_source.ts +29 -8
  534. package/src/services/tx_file_store/config.ts +37 -0
  535. package/src/services/tx_file_store/index.ts +3 -0
  536. package/src/services/tx_file_store/instrumentation.ts +36 -0
  537. package/src/services/tx_file_store/tx_file_store.ts +163 -0
  538. package/src/services/tx_provider.ts +34 -12
  539. package/src/services/tx_provider_instrumentation.ts +24 -14
  540. package/src/test-helpers/index.ts +2 -0
  541. package/src/test-helpers/make-test-p2p-clients.ts +7 -6
  542. package/src/test-helpers/mock-pubsub.ts +138 -15
  543. package/src/test-helpers/mock-tx-helpers.ts +1 -1
  544. package/src/test-helpers/reqresp-nodes.ts +18 -30
  545. package/src/test-helpers/test_tx_provider.ts +69 -0
  546. package/src/test-helpers/testbench-utils.ts +465 -0
  547. package/src/testbench/p2p_client_testbench_worker.ts +406 -127
  548. package/src/testbench/worker_client_manager.ts +355 -46
  549. package/src/util.ts +47 -16
  550. package/src/versioning.ts +3 -33
  551. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +0 -30
  552. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +0 -1
  553. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +0 -190
  554. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +0 -25
  555. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +0 -1
  556. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +0 -197
  557. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -150
  558. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  559. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -617
  560. package/dest/mem_pools/tx_pool/index.d.ts +0 -4
  561. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  562. package/dest/mem_pools/tx_pool/index.js +0 -3
  563. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +0 -80
  564. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +0 -1
  565. package/dest/mem_pools/tx_pool/memory_tx_pool.js +0 -238
  566. package/dest/mem_pools/tx_pool/priority.d.ts +0 -8
  567. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  568. package/dest/mem_pools/tx_pool/priority.js +0 -10
  569. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -122
  570. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  571. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  572. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  573. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  574. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -394
  575. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +0 -12
  576. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +0 -1
  577. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +0 -70
  578. package/dest/msg_validators/block_proposal_validator/index.d.ts +0 -2
  579. package/dest/msg_validators/block_proposal_validator/index.d.ts.map +0 -1
  580. package/dest/msg_validators/block_proposal_validator/index.js +0 -1
  581. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +0 -45
  582. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +0 -1
  583. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +0 -92
  584. package/dest/services/reqresp/protocols/block.d.ts +0 -9
  585. package/dest/services/reqresp/protocols/block.d.ts.map +0 -1
  586. package/dest/services/reqresp/protocols/block.js +0 -31
  587. package/dest/services/tx_collection/fast_tx_collection.d.ts +0 -56
  588. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +0 -1
  589. package/dest/services/tx_collection/fast_tx_collection.js +0 -300
  590. package/dest/services/tx_collection/slow_tx_collection.d.ts +0 -54
  591. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +0 -1
  592. package/dest/services/tx_collection/slow_tx_collection.js +0 -176
  593. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +0 -256
  594. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +0 -253
  595. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -750
  596. package/src/mem_pools/tx_pool/index.ts +0 -3
  597. package/src/mem_pools/tx_pool/memory_tx_pool.ts +0 -283
  598. package/src/mem_pools/tx_pool/priority.ts +0 -13
  599. package/src/mem_pools/tx_pool/tx_pool.ts +0 -135
  600. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -313
  601. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +0 -81
  602. package/src/msg_validators/block_proposal_validator/index.ts +0 -1
  603. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +0 -100
  604. package/src/services/reqresp/protocols/block.ts +0 -36
  605. package/src/services/tx_collection/fast_tx_collection.ts +0 -340
  606. package/src/services/tx_collection/slow_tx_collection.ts +0 -232
@@ -1,21 +1,23 @@
1
- import { Secp256k1Signer } from '@aztec/foundation/crypto';
2
- import { Fr } from '@aztec/foundation/fields';
3
- import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
1
+ import { IndexWithinCheckpoint, SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
+ import { Signature } from '@aztec/foundation/eth-signature';
5
+ import type { BlockProposal, CheckpointProposalCore } from '@aztec/stdlib/p2p';
6
+ import { CheckpointAttestation } from '@aztec/stdlib/p2p';
7
+ import { CheckpointHeader } from '@aztec/stdlib/rollup';
4
8
  import {
5
- BlockProposal as BlockProposalClass,
6
- ConsensusPayload,
7
- SignatureDomainSeparator,
8
- getHashedSignaturePayloadEthSignedMessage,
9
- } from '@aztec/stdlib/p2p';
10
- import { makeL2BlockHeader } from '@aztec/stdlib/testing';
11
- import { TxHash } from '@aztec/stdlib/tx';
9
+ makeBlockHeader,
10
+ makeBlockProposal,
11
+ makeCheckpointHeader,
12
+ makeCheckpointProposal,
13
+ } from '@aztec/stdlib/testing';
12
14
 
13
- import { jest } from '@jest/globals';
14
- import { type MockProxy, mock } from 'jest-mock-extended';
15
-
16
- import type { PoolInstrumentation } from '../instrumentation.js';
17
- import type { AttestationPool } from './attestation_pool.js';
18
- import { mockAttestation } from './mocks.js';
15
+ import {
16
+ type AttestationPool,
17
+ MAX_BLOCK_PROPOSALS_PER_POSITION,
18
+ MAX_CHECKPOINT_PROPOSALS_PER_SLOT,
19
+ } from './attestation_pool.js';
20
+ import { mockCheckpointAttestation } from './mocks.js';
19
21
 
20
22
  const NUMBER_OF_SIGNERS_PER_TEST = 4;
21
23
 
@@ -23,394 +25,872 @@ export function describeAttestationPool(getAttestationPool: () => AttestationPoo
23
25
  let ap: AttestationPool;
24
26
  let signers: Secp256k1Signer[];
25
27
 
26
- // Check that metrics are recorded correctly
27
- let metricsMock: MockProxy<PoolInstrumentation<BlockAttestation>>;
28
-
29
28
  beforeEach(() => {
30
29
  ap = getAttestationPool();
31
30
  signers = Array.from({ length: NUMBER_OF_SIGNERS_PER_TEST }, () => Secp256k1Signer.random());
32
-
33
- metricsMock = mock<PoolInstrumentation<BlockAttestation>>();
34
- // Can i overwrite this like this??
35
- (ap as any).metrics = metricsMock;
36
31
  });
37
32
 
38
- const createAttestationsForSlot = (slotNumber: number) => {
39
- const archive = Fr.random();
40
- return signers.map(signer => mockAttestation(signer, slotNumber, archive));
33
+ /**
34
+ * Build attestations from each signer over the *same* signed payload (same header,
35
+ * archive, feeAssetPriceModifier). Required by the new pool, which deduplicates by
36
+ * payload hash and treats attestations from different signers as distinct entries
37
+ * only when the payload itself matches.
38
+ */
39
+ const createCheckpointAttestationsForSlot = (slotNumber: number, archive?: Fr) => {
40
+ const archiveToUse = archive ?? Fr.random();
41
+ const sharedHeader = CheckpointHeader.random({ slotNumber: SlotNumber(slotNumber) });
42
+ return signers.map(signer => mockCheckpointAttestation(signer, slotNumber, archiveToUse, sharedHeader));
41
43
  };
42
44
 
43
- const mockBlockProposal = (signer: Secp256k1Signer, slotNumber: number, archive: Fr = Fr.random()): BlockProposal => {
44
- const header = makeL2BlockHeader(1, 2, slotNumber);
45
- const payload = new ConsensusPayload(header.toCheckpointHeader(), archive, header.state);
46
-
47
- const hash = getHashedSignaturePayloadEthSignedMessage(payload, SignatureDomainSeparator.blockProposal);
48
- const signature = signer.sign(hash);
49
-
50
- const txHashes = [TxHash.random(), TxHash.random()]; // Mock tx hashes
51
-
52
- return new BlockProposalClass(payload, signature, txHashes);
45
+ const mockBlockProposalForPool = (
46
+ signer: Secp256k1Signer,
47
+ slotNumber: number,
48
+ archive: Fr = Fr.random(),
49
+ ): Promise<BlockProposal> => {
50
+ const header = makeBlockHeader(1, { slotNumber: SlotNumber(slotNumber) });
51
+ return makeBlockProposal({
52
+ signer,
53
+ blockHeader: header,
54
+ archiveRoot: archive,
55
+ });
53
56
  };
54
57
 
55
- // We compare buffers as the objects can have cached values attached to them which are not serialised
56
- // using array containing as the kv store does not respect insertion order
57
- const compareAttestations = (a1: BlockAttestation[], a2: BlockAttestation[]) => {
58
+ // Compare checkpoint attestations buffers
59
+ // Using array containing as the kv store does not respect insertion order
60
+ const compareCheckpointAttestations = (a1: CheckpointAttestation[], a2: CheckpointAttestation[]) => {
58
61
  const a1Buffer = a1.map(attestation => attestation.toBuffer());
59
62
  const a2Buffer = a2.map(attestation => attestation.toBuffer());
60
63
  expect(a1Buffer.length).toBe(a2Buffer.length);
61
64
  expect(a1Buffer).toEqual(expect.arrayContaining(a2Buffer));
62
65
  };
63
66
 
64
- it('should add attestations to pool', async () => {
65
- const slotNumber = 420;
66
- const archive = Fr.random();
67
- const attestations = signers.slice(0, -1).map(signer => mockAttestation(signer, slotNumber, archive));
68
-
69
- await ap.addAttestations(attestations);
70
-
71
- const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
72
- expect(retrievedAttestations.length).toBe(attestations.length);
73
- compareAttestations(retrievedAttestations, attestations);
74
-
75
- // Check hasAttestation for added attestations
76
- for (const attestation of attestations) {
77
- expect(await ap.hasAttestation(attestation)).toBe(true);
78
- }
79
-
80
- const retrievedAttestationsForSlot = await ap.getAttestationsForSlot(BigInt(slotNumber));
81
- expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
82
- compareAttestations(retrievedAttestationsForSlot, attestations);
83
-
84
- // Add another one
85
- const newAttestation = mockAttestation(signers[NUMBER_OF_SIGNERS_PER_TEST - 1], slotNumber, archive);
86
- await ap.addAttestations([newAttestation]);
87
- const retrievedAttestationsAfterAdd = await ap.getAttestationsForSlotAndProposal(
88
- BigInt(slotNumber),
89
- archive.toString(),
90
- );
91
- expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
92
- compareAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
93
- expect(await ap.hasAttestation(newAttestation)).toBe(true);
94
- const retrievedAttestationsForSlotAfterAdd = await ap.getAttestationsForSlot(BigInt(slotNumber));
95
- expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
96
- compareAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
97
-
98
- // Delete by slot
99
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
100
-
101
- const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(
102
- BigInt(slotNumber),
103
- archive.toString(),
67
+ /**
68
+ * Rewrites the attester signature into yParity form (27 -> 0, 28 -> 1), keeping (r, s). The recovery
69
+ * bit is unchanged so it still recovers to the same signer, mimicking a peer that gossips (or mutates
70
+ * in flight) a signature with a non-canonical recovery byte.
71
+ */
72
+ const toYParityForm = (attestation: CheckpointAttestation): CheckpointAttestation => {
73
+ const sig = attestation.signature;
74
+ const yParityV = sig.v === 27 ? 0 : sig.v === 28 ? 1 : sig.v;
75
+ return new CheckpointAttestation(
76
+ attestation.payload,
77
+ new Signature(sig.r, sig.s, yParityV),
78
+ attestation.proposerSignature,
104
79
  );
105
- expect(retreivedAttestationsAfterDelete.length).toBe(0);
106
- // Check hasAttestation after deletion
107
- for (const attestation of attestations) {
108
- expect(await ap.hasAttestation(attestation)).toBe(false);
109
- }
110
- expect(await ap.hasAttestation(newAttestation)).toBe(false);
111
- });
112
-
113
- it('should handle duplicate proposals in a slot', async () => {
114
- const slotNumber = 420;
115
- const archive = Fr.random();
116
-
117
- // Use the same signer for all attestations
118
- const attestations: BlockAttestation[] = [];
119
- const signer = signers[0];
120
- for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
121
- attestations.push(mockAttestation(signer, slotNumber, archive));
122
- }
123
-
124
- // Add them to store and check we end up with only one
125
- await ap.addAttestations(attestations);
126
-
127
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString());
128
- expect(retreivedAttestations.length).toBe(1);
129
- expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
130
- expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
131
-
132
- // Try adding them on another operation and check they are still not duplicated
133
- await ap.addAttestations([attestations[0]]);
134
- expect(await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), archive.toString())).toHaveLength(1);
135
- });
136
-
137
- it('should store attestations by differing slot', async () => {
138
- const slotNumbers = [1, 2, 3, 4];
139
- const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i]));
140
-
141
- await ap.addAttestations(attestations);
80
+ };
142
81
 
143
- for (const attestation of attestations) {
144
- const slot = attestation.payload.header.slotNumber;
145
- const archive = attestation.archive.toString();
82
+ describe('CheckpointAttestation', () => {
83
+ it('normalizes yParity (v=0/v=1) attester signatures on ingress from both gossip and own keys', async () => {
84
+ const slotNumber = 421;
85
+ const canonical = createCheckpointAttestationsForSlot(slotNumber);
86
+ const payloadHash = canonical[0].getPayloadHash();
87
+ const expectedSenders = new Set([canonical[0].getSender()!.toString(), canonical[1].getSender()!.toString()]);
88
+
89
+ const gossiped = toYParityForm(canonical[0]);
90
+ expect([0, 1]).toContain(gossiped.signature.v);
91
+ await ap.tryAddCheckpointAttestation(gossiped);
92
+
93
+ const own = toYParityForm(canonical[1]);
94
+ expect([0, 1]).toContain(own.signature.v);
95
+ await ap.addOwnCheckpointAttestations([own]);
96
+
97
+ const retrieved = await ap.getCheckpointAttestationsForSlotAndProposal(SlotNumber(slotNumber), payloadHash);
98
+ expect(retrieved.length).toBe(2);
99
+ for (const attestation of retrieved) {
100
+ expect([27, 28]).toContain(attestation.signature.v);
101
+ expect(expectedSenders.has(attestation.getSender()!.toString())).toBe(true);
102
+ }
103
+ });
146
104
 
147
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot.toBigInt(), archive);
148
- expect(retreivedAttestations.length).toBe(1);
149
- expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
150
- expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
151
- }
152
- });
105
+ it('should add attestations to pool', async () => {
106
+ const slotNumber = 420;
107
+ const archive = Fr.random();
108
+ const sharedHeader = CheckpointHeader.random({ slotNumber: SlotNumber(slotNumber) });
109
+ const attestations = signers
110
+ .slice(0, -1)
111
+ .map(signer => mockCheckpointAttestation(signer, slotNumber, archive, sharedHeader));
112
+ const payloadHash = attestations[0].getPayloadHash();
113
+
114
+ await ap.addOwnCheckpointAttestations(attestations);
115
+
116
+ const retrievedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(
117
+ SlotNumber(slotNumber),
118
+ payloadHash,
119
+ );
120
+ expect(retrievedAttestations.length).toBe(attestations.length);
121
+ compareCheckpointAttestations(retrievedAttestations, attestations);
122
+
123
+ const retrievedAttestationsForSlot = await ap.getCheckpointAttestationsForSlot(SlotNumber(slotNumber));
124
+ expect(retrievedAttestationsForSlot.length).toBe(attestations.length);
125
+ compareCheckpointAttestations(retrievedAttestationsForSlot, attestations);
126
+
127
+ // Add another one
128
+ const newAttestation = mockCheckpointAttestation(
129
+ signers[NUMBER_OF_SIGNERS_PER_TEST - 1],
130
+ slotNumber,
131
+ archive,
132
+ sharedHeader,
133
+ );
134
+ await ap.addOwnCheckpointAttestations([newAttestation]);
135
+ const retrievedAttestationsAfterAdd = await ap.getCheckpointAttestationsForSlotAndProposal(
136
+ SlotNumber(slotNumber),
137
+ payloadHash,
138
+ );
139
+ expect(retrievedAttestationsAfterAdd.length).toBe(attestations.length + 1);
140
+ compareCheckpointAttestations(retrievedAttestationsAfterAdd, [...attestations, newAttestation]);
141
+ const retrievedAttestationsForSlotAfterAdd = await ap.getCheckpointAttestationsForSlot(SlotNumber(slotNumber));
142
+ expect(retrievedAttestationsForSlotAfterAdd.length).toBe(attestations.length + 1);
143
+ compareCheckpointAttestations(retrievedAttestationsForSlotAfterAdd, [...attestations, newAttestation]);
144
+
145
+ // Delete by slot
146
+ await ap.deleteOlderThan(SlotNumber(slotNumber + 1));
147
+
148
+ const retreivedAttestationsAfterDelete = await ap.getCheckpointAttestationsForSlotAndProposal(
149
+ SlotNumber(slotNumber),
150
+ payloadHash,
151
+ );
152
+ expect(retreivedAttestationsAfterDelete.length).toBe(0);
153
+ });
153
154
 
154
- it('should store attestations by differing slot and archive', async () => {
155
- const slotNumbers = [1, 1, 2, 3];
156
- const archives = [Fr.random(), Fr.random(), Fr.random(), Fr.random()];
157
- const attestations = signers.map((signer, i) => mockAttestation(signer, slotNumbers[i], archives[i]));
155
+ it('should handle duplicate proposals in a slot', async () => {
156
+ const slotNumber = 420;
157
+ const archive = Fr.random();
158
+ const header = CheckpointHeader.random({ slotNumber: SlotNumber(slotNumber) });
158
159
 
159
- await ap.addAttestations(attestations);
160
+ // Use the same signer and header for all attestations
161
+ const attestations: CheckpointAttestation[] = [];
162
+ const signer = signers[0];
163
+ for (let i = 0; i < NUMBER_OF_SIGNERS_PER_TEST; i++) {
164
+ attestations.push(mockCheckpointAttestation(signer, slotNumber, archive, header));
165
+ }
166
+ const payloadHash = attestations[0].getPayloadHash();
160
167
 
161
- for (const attestation of attestations) {
162
- const slot = attestation.payload.header.slotNumber;
163
- const proposalId = attestation.archive.toString();
168
+ // Add them to store and check we end up with only one
169
+ await ap.addOwnCheckpointAttestations(attestations);
164
170
 
165
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(slot.toBigInt(), proposalId);
171
+ const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(
172
+ SlotNumber(slotNumber),
173
+ payloadHash,
174
+ );
166
175
  expect(retreivedAttestations.length).toBe(1);
167
- expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
168
- expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
169
- }
170
- });
171
-
172
- it('should delete attestations', async () => {
173
- const slotNumber = 420;
174
- const archive = Fr.random();
175
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
176
- const proposalId = attestations[0].archive.toString();
177
-
178
- await ap.addAttestations(attestations);
179
-
180
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
181
- expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
182
- compareAttestations(retreivedAttestations, attestations);
183
-
184
- // Check hasAttestation before deletion
185
- for (const attestation of attestations) {
186
- expect(await ap.hasAttestation(attestation)).toBe(true);
187
- }
188
-
189
- await ap.deleteAttestations(attestations);
190
-
191
- const gottenAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
192
- expect(gottenAfterDelete.length).toBe(0);
193
-
194
- // Check hasAttestation after deletion
195
- for (const attestation of attestations) {
196
- expect(await ap.hasAttestation(attestation)).toBe(false);
197
- }
198
- });
199
-
200
- it('should blanket delete attestations per slot', async () => {
201
- const slotNumber = 420;
202
- const archive = Fr.random();
203
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
204
- const proposalId = attestations[0].archive.toString();
205
-
206
- await ap.addAttestations(attestations);
207
-
208
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
209
- expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
210
- compareAttestations(retreivedAttestations, attestations);
211
-
212
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
213
-
214
- const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
215
- expect(retreivedAttestationsAfterDelete.length).toBe(0);
216
- });
217
-
218
- it('should blanket delete attestations per slot and proposal', async () => {
219
- const slotNumber = 420;
220
- const archive = Fr.random();
221
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
222
- const proposalId = attestations[0].archive.toString();
223
-
224
- // Add another set of attestations with a different proposalId, yet the same slot
225
- const archive2 = Fr.random();
226
- const attestations2 = signers.map(signer => mockAttestation(signer, slotNumber, archive2));
227
- const proposalId2 = attestations2[0].archive.toString();
176
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestations[0].toBuffer());
177
+ expect(retreivedAttestations[0].getSender()?.toString()).toEqual(signer.address.toString());
228
178
 
229
- await ap.addAttestations(attestations);
230
- await ap.addAttestations(attestations2);
231
-
232
- const retreivedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
233
- expect(retreivedAttestations.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
234
- compareAttestations(retreivedAttestations, attestations);
235
-
236
- await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
179
+ // Try adding them on another operation and check they are still not duplicated
180
+ await ap.addOwnCheckpointAttestations([attestations[0]]);
181
+ expect(await ap.getCheckpointAttestationsForSlotAndProposal(SlotNumber(slotNumber), payloadHash)).toHaveLength(1);
182
+ });
237
183
 
238
- const retreivedAttestationsAfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
239
- expect(retreivedAttestationsAfterDelete.length).toBe(0);
184
+ it('should store attestations by differing slot', async () => {
185
+ const slotNumbers = [1, 2, 3, 4];
186
+ const attestations = signers.map((signer, i) => mockCheckpointAttestation(signer, slotNumbers[i]));
240
187
 
241
- const retreivedAttestationsAfterDeleteForOtherProposal = await ap.getAttestationsForSlotAndProposal(
242
- BigInt(slotNumber),
243
- proposalId2,
244
- );
245
- expect(retreivedAttestationsAfterDeleteForOtherProposal.length).toBe(NUMBER_OF_SIGNERS_PER_TEST);
246
- compareAttestations(retreivedAttestationsAfterDeleteForOtherProposal, attestations2);
247
- });
188
+ await ap.addOwnCheckpointAttestations(attestations);
248
189
 
249
- it('should delete attestations older than a given slot', async () => {
250
- const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
251
- const attestations = (
252
- await Promise.all(slotNumbers.map(slotNumber => createAttestationsForSlot(slotNumber)))
253
- ).flat();
254
- const proposalId = attestations[0].archive.toString();
190
+ for (const attestation of attestations) {
191
+ const slot = attestation.payload.header.slotNumber;
192
+ const payloadHash = attestation.getPayloadHash();
255
193
 
256
- await ap.addAttestations(attestations);
194
+ const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(slot, payloadHash);
195
+ expect(retreivedAttestations.length).toBe(1);
196
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
197
+ expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
198
+ }
199
+ });
257
200
 
258
- const attestationsForSlot1 = await ap.getAttestationsForSlotAndProposal(BigInt(1), proposalId);
259
- expect(attestationsForSlot1.length).toBe(signers.length);
201
+ it('should store attestations by differing slot and archive', async () => {
202
+ const slotNumbers = [1, 1, 2, 3];
203
+ const archives = [Fr.random(), Fr.random(), Fr.random(), Fr.random()];
204
+ const attestations = signers.map((signer, i) => mockCheckpointAttestation(signer, slotNumbers[i], archives[i]));
260
205
 
261
- const deleteAttestationsSpy = jest.spyOn(ap, 'deleteAttestationsForSlot');
206
+ await ap.addOwnCheckpointAttestations(attestations);
262
207
 
263
- await ap.deleteAttestationsOlderThan(BigInt(73));
208
+ for (const attestation of attestations) {
209
+ const slot = attestation.payload.header.slotNumber;
210
+ const payloadHash = attestation.getPayloadHash();
264
211
 
265
- const attestationsForSlot1AfterDelete = await ap.getAttestationsForSlotAndProposal(BigInt(1), proposalId);
266
- expect(attestationsForSlot1AfterDelete.length).toBe(0);
212
+ const retreivedAttestations = await ap.getCheckpointAttestationsForSlotAndProposal(slot, payloadHash);
213
+ expect(retreivedAttestations.length).toBe(1);
214
+ expect(retreivedAttestations[0].toBuffer()).toEqual(attestation.toBuffer());
215
+ expect(retreivedAttestations[0].payload.header.slotNumber).toEqual(slot);
216
+ }
217
+ });
267
218
 
268
- expect(deleteAttestationsSpy).toHaveBeenCalledTimes(5);
269
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(1));
270
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(2));
271
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(3));
272
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(69));
273
- expect(deleteAttestationsSpy).toHaveBeenCalledWith(BigInt(72));
219
+ it('should delete attestations older than a given slot', async () => {
220
+ const slotNumbers = [1, 2, 3, 69, 72, 74, 88, 420];
221
+ const attestationsPerSlot = await Promise.all(
222
+ slotNumbers.map(slotNumber => createCheckpointAttestationsForSlot(slotNumber)),
223
+ );
224
+ const attestations = attestationsPerSlot.flat();
225
+ const payloadHashForSlot1 = attestationsPerSlot[0][0].getPayloadHash();
226
+
227
+ await ap.addOwnCheckpointAttestations(attestations);
228
+
229
+ const attestationsForSlot1 = await ap.getCheckpointAttestationsForSlotAndProposal(
230
+ SlotNumber(1),
231
+ payloadHashForSlot1,
232
+ );
233
+ expect(attestationsForSlot1.length).toBe(signers.length);
234
+
235
+ await ap.deleteOlderThan(SlotNumber(73));
236
+
237
+ const attestationsForSlot1AfterDelete = await ap.getCheckpointAttestationsForSlotAndProposal(
238
+ SlotNumber(1),
239
+ payloadHashForSlot1,
240
+ );
241
+ expect(attestationsForSlot1AfterDelete.length).toBe(0);
242
+ });
274
243
  });
275
244
 
276
245
  describe('BlockProposal in attestation pool', () => {
277
246
  it('should add and retrieve block proposal', async () => {
278
247
  const slotNumber = 420;
279
248
  const archive = Fr.random();
280
- const proposal = mockBlockProposal(signers[0], slotNumber, archive);
281
- const proposalId = proposal.archive.toString();
249
+ const proposal = await mockBlockProposalForPool(signers[0], slotNumber, archive);
282
250
 
283
- await ap.addBlockProposal(proposal);
251
+ const result = await ap.tryAddBlockProposal(proposal);
284
252
 
285
- const retrievedProposal = await ap.getBlockProposal(proposalId);
253
+ expect(result.added).toBe(true);
254
+ expect(result.alreadyExists).toBe(false);
255
+ expect(result.count).toBe(1);
256
+
257
+ const retrievedProposal = await ap.getBlockProposalByArchive(proposal.archive.toString());
286
258
 
287
259
  expect(retrievedProposal).toBeDefined();
288
260
  expect(retrievedProposal!).toEqual(proposal);
289
-
290
- // Check hasBlockProposal with both id and object
291
- expect(await ap.hasBlockProposal(proposalId)).toBe(true);
292
- expect(await ap.hasBlockProposal(proposal)).toBe(true);
293
261
  });
294
262
 
295
263
  it('should return undefined for non-existent block proposal', async () => {
296
264
  const nonExistentId = Fr.random().toString();
297
- const retrievedProposal = await ap.getBlockProposal(nonExistentId);
265
+ const retrievedProposal = await ap.getBlockProposalByArchive(nonExistentId);
298
266
  expect(retrievedProposal).toBeUndefined();
299
-
300
- // Check hasBlockProposal returns false for non-existent proposal
301
- expect(await ap.hasBlockProposal(nonExistentId)).toBe(false);
302
267
  });
303
268
 
304
- it('should update block proposal if added twice with same id', async () => {
269
+ it('should return alreadyExists when re-adding the same signed payload', async () => {
305
270
  const slotNumber = 420;
306
271
  const archive = Fr.random();
307
- const proposal1 = mockBlockProposal(signers[0], slotNumber, archive);
308
- const proposalId = proposal1.archive.toString();
272
+ const proposal = await mockBlockProposalForPool(signers[0], slotNumber, archive);
309
273
 
310
- await ap.addBlockProposal(proposal1);
274
+ const result1 = await ap.tryAddBlockProposal(proposal);
275
+ expect(result1.added).toBe(true);
276
+ expect(result1.alreadyExists).toBe(false);
311
277
 
312
- // Create a new proposal with same archive but different signer
313
- const proposal2 = mockBlockProposal(signers[1], slotNumber, archive);
278
+ // Re-broadcasting the exact same proposal yields alreadyExists.
279
+ const result2 = await ap.tryAddBlockProposal(proposal);
280
+ expect(result2.added).toBe(false);
281
+ expect(result2.alreadyExists).toBe(true);
314
282
 
315
- await ap.addBlockProposal(proposal2);
316
-
317
- const retrievedProposal = await ap.getBlockProposal(proposalId);
283
+ const retrievedProposal = await ap.getBlockProposalByArchive(proposal.archive.toString());
318
284
  expect(retrievedProposal).toBeDefined();
319
- // Should have the second proposal
320
- expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toBuffer());
321
- expect(retrievedProposal!.getSender()?.toString()).toBe(signers[1].address.toString());
285
+ expect(retrievedProposal!.toBuffer()).toEqual(proposal.toBuffer());
286
+ expect(retrievedProposal!.getSender()?.toString()).toBe(signers[0].address.toString());
322
287
  });
323
288
 
324
- it('should handle block proposals with different slots and same archive', async () => {
325
- const archive = Fr.random();
326
- const proposal1 = mockBlockProposal(signers[0], 100, archive);
327
- const proposal2 = mockBlockProposal(signers[1], 200, archive);
328
- const proposalId = archive.toString();
289
+ it('should retain an exact duplicate block proposal only once', async () => {
290
+ const slotNumber = 420;
291
+ const proposal = await mockBlockProposalForPool(signers[0], slotNumber);
329
292
 
330
- await ap.addBlockProposal(proposal1);
331
- await ap.addBlockProposal(proposal2);
293
+ await ap.tryAddBlockProposal(proposal);
294
+ await ap.tryAddBlockProposal(proposal);
332
295
 
333
- // Should get the latest one added
334
- const retrievedProposal = await ap.getBlockProposal(proposalId);
335
- expect(retrievedProposal).toBeDefined();
336
- expect(retrievedProposal!.toBuffer()).toEqual(proposal2.toBuffer());
337
- expect(retrievedProposal!.slotNumber.toBigInt()).toBe(BigInt(200));
296
+ const proposals = await ap.getProposalsForSlot(SlotNumber(slotNumber));
297
+ expect(proposals.blockProposals.map(proposal => proposal.toBuffer())).toEqual([
298
+ proposal.withoutSignedTxs().toBuffer(),
299
+ ]);
300
+ });
301
+
302
+ it('should retain all accepted block proposals at a position', async () => {
303
+ const slotNumber = 420;
304
+ const blockHeader = makeBlockHeader(1, { slotNumber: SlotNumber(slotNumber) });
305
+ const proposal1 = await makeBlockProposal({
306
+ signer: signers[0],
307
+ blockHeader,
308
+ archiveRoot: Fr.random(),
309
+ indexWithinCheckpoint: IndexWithinCheckpoint(1),
310
+ });
311
+ const proposal2 = await makeBlockProposal({
312
+ signer: signers[0],
313
+ blockHeader,
314
+ archiveRoot: Fr.random(),
315
+ indexWithinCheckpoint: IndexWithinCheckpoint(1),
316
+ });
317
+
318
+ await ap.tryAddBlockProposal(proposal1);
319
+ await ap.tryAddBlockProposal(proposal2);
320
+
321
+ const proposals = await ap.getProposalsForSlot(SlotNumber(slotNumber));
322
+ expect(proposals.blockProposals.map(proposal => proposal.toBuffer())).toEqual(
323
+ expect.arrayContaining([proposal1.withoutSignedTxs().toBuffer(), proposal2.withoutSignedTxs().toBuffer()]),
324
+ );
325
+ expect(await ap.getBlockProposalByArchive(proposal2.archive.toString())).toBeDefined();
338
326
  });
327
+ });
339
328
 
340
- it('should delete block proposal when deleting attestations for slot and proposal', async () => {
329
+ describe('CheckpointProposal in attestation pool', () => {
330
+ const mockCheckpointProposalForPool = async (
331
+ signer: Secp256k1Signer,
332
+ slotNumber: number,
333
+ archive: Fr = Fr.random(),
334
+ checkpointHeader?: CheckpointHeader,
335
+ ): Promise<CheckpointProposalCore> => {
336
+ const headerToUse = checkpointHeader ?? makeCheckpointHeader(1, { slotNumber: SlotNumber(slotNumber) });
337
+ const blockHeader = makeBlockHeader(1);
338
+ const proposal = await makeCheckpointProposal({
339
+ signer,
340
+ checkpointHeader: headerToUse,
341
+ archiveRoot: archive,
342
+ lastBlock: { blockHeader },
343
+ });
344
+ // Return the core version since tryAddCheckpointProposal now takes CheckpointProposalCore
345
+ return proposal.toCore();
346
+ };
347
+
348
+ it('should add and retrieve checkpoint proposal', async () => {
341
349
  const slotNumber = 420;
342
350
  const archive = Fr.random();
343
- const proposal = mockBlockProposal(signers[0], slotNumber, archive);
344
- const proposalId = proposal.archive.toString();
351
+ const proposal = await mockCheckpointProposalForPool(signers[0], slotNumber, archive);
352
+
353
+ const result = await ap.tryAddCheckpointProposal(proposal);
345
354
 
346
- // Add proposal and some attestations
347
- await ap.addBlockProposal(proposal);
348
- const attestations = signers.map(signer => mockAttestation(signer, slotNumber, archive));
349
- await ap.addAttestations(attestations);
355
+ expect(result.added).toBe(true);
356
+ expect(result.alreadyExists).toBe(false);
357
+ expect(result.count).toBe(1);
358
+
359
+ const retrievedProposal = await ap.getCheckpointProposal(SlotNumber(slotNumber));
350
360
 
351
- // Verify proposal exists
352
- let retrievedProposal = await ap.getBlockProposal(proposalId);
353
361
  expect(retrievedProposal).toBeDefined();
354
- expect(await ap.hasBlockProposal(proposalId)).toBe(true);
362
+ expect(retrievedProposal!.toBuffer()).toEqual(proposal.toBuffer());
363
+ });
355
364
 
356
- // Delete attestations for slot and proposal
357
- await ap.deleteAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
365
+ it('should handle checkpoint proposal without lastBlock (caller extracts and adds block separately)', async () => {
366
+ const slotNumber = 420;
367
+ const archive = Fr.random();
368
+ const checkpointHeader = makeCheckpointHeader(1, { slotNumber: SlotNumber(slotNumber) });
369
+ // Create a checkpoint proposal WITHOUT lastBlock
370
+ const proposal = await makeCheckpointProposal({
371
+ signer: signers[0],
372
+ checkpointHeader,
373
+ archiveRoot: archive,
374
+ // No lastBlock
375
+ });
376
+
377
+ // Add the checkpoint core - block extraction is now caller responsibility
378
+ await ap.tryAddCheckpointProposal(proposal.toCore());
379
+
380
+ // The checkpoint proposal should be stored
381
+ const retrievedCheckpointProposal = await ap.getCheckpointProposal(SlotNumber(slotNumber));
382
+ expect(retrievedCheckpointProposal).toBeDefined();
383
+
384
+ // No block proposal was extracted (it had none anyway)
385
+ const retrievedBlockProposal = await ap.getBlockProposalByArchive(proposal.archive.toString());
386
+ expect(retrievedBlockProposal).toBeUndefined();
387
+ });
358
388
 
359
- // Proposal should be deleted
360
- retrievedProposal = await ap.getBlockProposal(proposalId);
389
+ it('should return undefined for non-existent checkpoint proposal', async () => {
390
+ const retrievedProposal = await ap.getCheckpointProposal(SlotNumber(99999));
361
391
  expect(retrievedProposal).toBeUndefined();
362
- expect(await ap.hasBlockProposal(proposalId)).toBe(false);
363
392
  });
364
393
 
365
- it('should delete block proposal when deleting attestations for slot', async () => {
394
+ it('should return alreadyExists when re-adding the same signed payload', async () => {
366
395
  const slotNumber = 420;
367
396
  const archive = Fr.random();
368
- const proposal = mockBlockProposal(signers[0], slotNumber, archive);
369
- const proposalId = proposal.archive.toString();
397
+ const proposal = await mockCheckpointProposalForPool(signers[0], slotNumber, archive);
370
398
 
371
- // Add proposal
372
- await ap.addBlockProposal(proposal);
399
+ const result1 = await ap.tryAddCheckpointProposal(proposal);
400
+ expect(result1.added).toBe(true);
401
+ expect(result1.alreadyExists).toBe(false);
373
402
 
374
- // Verify proposal exists
375
- let retrievedProposal = await ap.getBlockProposal(proposalId);
376
- expect(retrievedProposal).toBeDefined();
377
- expect(await ap.hasBlockProposal(proposal)).toBe(true);
403
+ // Re-broadcasting the exact same signed payload yields alreadyExists.
404
+ const result2 = await ap.tryAddCheckpointProposal(proposal);
405
+ expect(result2.added).toBe(false);
406
+ expect(result2.alreadyExists).toBe(true);
378
407
 
379
- // Delete attestations for slot
380
- await ap.deleteAttestationsForSlot(BigInt(slotNumber));
408
+ // Should still have the first proposal stored at the slot
409
+ const retrievedProposal = await ap.getCheckpointProposal(SlotNumber(slotNumber));
410
+ expect(retrievedProposal).toBeDefined();
411
+ expect(retrievedProposal!.toBuffer()).toEqual(proposal.toBuffer());
412
+ expect(retrievedProposal!.getSender()?.toString()).toBe(signers[0].address.toString());
413
+ });
381
414
 
382
- // Proposal should be deleted
383
- retrievedProposal = await ap.getBlockProposal(proposalId);
384
- expect(retrievedProposal).toBeUndefined();
385
- expect(await ap.hasBlockProposal(proposal)).toBe(false);
415
+ it('should treat distinct payloads at the same slot as equivocations (count = 2)', async () => {
416
+ const slotNumber = 420;
417
+ // Two proposals at the same slot but with different headers (distinct payloads).
418
+ const proposal1 = await mockCheckpointProposalForPool(signers[0], slotNumber, Fr.random());
419
+ const proposal2 = await mockCheckpointProposalForPool(signers[0], slotNumber, Fr.random());
420
+
421
+ const result1 = await ap.tryAddCheckpointProposal(proposal1);
422
+ expect(result1.added).toBe(true);
423
+ expect(result1.count).toBe(1);
424
+
425
+ const result2 = await ap.tryAddCheckpointProposal(proposal2);
426
+ // The second distinct payload is tracked as an equivocation, count goes to 2,
427
+ // and both accepted payloads are retained by payload hash.
428
+ expect(result2.added).toBe(true);
429
+ expect(result2.alreadyExists).toBe(false);
430
+ expect(result2.count).toBe(2);
431
+
432
+ const retrievedProposal = await ap.getCheckpointProposal(SlotNumber(slotNumber));
433
+ const expectedProposal = [proposal1, proposal2].sort((a, b) =>
434
+ a.getPayloadHash().localeCompare(b.getPayloadHash()),
435
+ )[0];
436
+ expect(retrievedProposal!.toBuffer()).toEqual(expectedProposal.toBuffer());
437
+
438
+ const proposals = await ap.getProposalsForSlot(SlotNumber(slotNumber));
439
+ expect(proposals.checkpointProposals.map(proposal => proposal.toBuffer())).toEqual(
440
+ expect.arrayContaining([proposal1.toBuffer(), proposal2.toBuffer()]),
441
+ );
386
442
  });
387
443
 
388
- it('should be able to fetch both block proposal and attestations', async () => {
444
+ it('should detect equivocation when only feeAssetPriceModifier differs', async () => {
389
445
  const slotNumber = 420;
390
446
  const archive = Fr.random();
391
- const proposal = mockBlockProposal(signers[0], slotNumber, archive);
392
- const proposalId = proposal.archive.toString();
447
+ // Same checkpoint header + archive, but two different feeAssetPriceModifier values.
448
+ // This is the audit-finding scenario: archive collides but the signed payload differs.
449
+ const sharedHeader = makeCheckpointHeader(1, { slotNumber: SlotNumber(slotNumber) });
450
+ const proposalA = await makeCheckpointProposal({
451
+ signer: signers[0],
452
+ checkpointHeader: sharedHeader,
453
+ archiveRoot: archive,
454
+ feeAssetPriceModifier: 50n,
455
+ });
456
+ const proposalB = await makeCheckpointProposal({
457
+ signer: signers[0],
458
+ checkpointHeader: sharedHeader,
459
+ archiveRoot: archive,
460
+ feeAssetPriceModifier: -50n,
461
+ });
462
+
463
+ const result1 = await ap.tryAddCheckpointProposal(proposalA.toCore());
464
+ expect(result1.count).toBe(1);
465
+
466
+ const result2 = await ap.tryAddCheckpointProposal(proposalB.toCore());
467
+ // The fix: archive collision no longer hides the equivocation; payload-hash dedup
468
+ // sees the distinct feeMod and bumps `count` to 2 so libp2p can fire the slash callback.
469
+ expect(result2.added).toBe(true);
470
+ expect(result2.alreadyExists).toBe(false);
471
+ expect(result2.count).toBe(2);
472
+ });
393
473
 
394
- // Add proposal first
395
- await ap.addBlockProposal(proposal);
474
+ it('should delete retained proposals older than a given slot', async () => {
475
+ const oldSlot = 100;
476
+ const newSlot = 200;
477
+ const oldBlock = await mockBlockProposalForPool(signers[0], oldSlot);
478
+ const newBlock = await mockBlockProposalForPool(signers[1], newSlot);
479
+ const oldCheckpoint = await mockCheckpointProposalForPool(signers[0], oldSlot);
480
+ const newCheckpoint = await mockCheckpointProposalForPool(signers[1], newSlot);
481
+
482
+ await ap.tryAddBlockProposal(oldBlock);
483
+ await ap.tryAddBlockProposal(newBlock);
484
+ await ap.tryAddCheckpointProposal(oldCheckpoint);
485
+ await ap.tryAddCheckpointProposal(newCheckpoint);
486
+
487
+ await ap.deleteOlderThan(SlotNumber(newSlot));
488
+
489
+ expect(await ap.getProposalsForSlot(SlotNumber(oldSlot))).toEqual({
490
+ blockProposals: [],
491
+ checkpointProposals: [],
492
+ });
493
+ const newProposals = await ap.getProposalsForSlot(SlotNumber(newSlot));
494
+ expect(newProposals.blockProposals.map(proposal => proposal.toBuffer())).toContainEqual(
495
+ newBlock.withoutSignedTxs().toBuffer(),
496
+ );
497
+ expect(newProposals.checkpointProposals.map(proposal => proposal.toBuffer())).toContainEqual(
498
+ newCheckpoint.toBuffer(),
499
+ );
500
+ });
396
501
 
397
- // Add attestations for the same proposal
398
- const attestations = signers.slice(1).map(signer => mockAttestation(signer, slotNumber, archive));
399
- await ap.addAttestations(attestations);
502
+ it('should return added=false when exceeding capacity', async () => {
503
+ const slotNumber = 420;
400
504
 
401
- // Retrieve both proposal and attestations
402
- const retrievedProposal = await ap.getBlockProposal(proposalId);
403
- const retrievedAttestations = await ap.getAttestationsForSlotAndProposal(BigInt(slotNumber), proposalId);
505
+ // Add MAX_CHECKPOINT_PROPOSALS_PER_SLOT distinct proposals.
506
+ for (let i = 0; i < MAX_CHECKPOINT_PROPOSALS_PER_SLOT; i++) {
507
+ const proposal = await mockCheckpointProposalForPool(signers[i % NUMBER_OF_SIGNERS_PER_TEST], slotNumber);
508
+ const result = await ap.tryAddCheckpointProposal(proposal);
509
+ expect(result.added).toBe(true);
510
+ expect(result.count).toBe(i + 1);
511
+ }
404
512
 
405
- expect(retrievedProposal).toBeDefined();
406
- expect(retrievedProposal).toEqual(proposal);
407
- expect(await ap.hasBlockProposal(proposalId)).toBe(true);
513
+ // The next proposal should not be added.
514
+ const extraProposal = await mockCheckpointProposalForPool(signers[0], slotNumber);
515
+ const result = await ap.tryAddCheckpointProposal(extraProposal);
516
+ expect(result.added).toBe(false);
517
+ expect(result.alreadyExists).toBe(false);
518
+ expect(result.count).toBe(MAX_CHECKPOINT_PROPOSALS_PER_SLOT);
519
+ });
520
+ });
408
521
 
409
- compareAttestations(retrievedAttestations, attestations);
410
- // Check hasAttestation for all attestations
411
- for (const attestation of attestations) {
412
- expect(await ap.hasAttestation(attestation)).toBe(true);
413
- }
522
+ describe('Duplicate proposal detection', () => {
523
+ const mockBlockProposalWithIndex = (
524
+ signer: Secp256k1Signer,
525
+ slotNumber: number,
526
+ indexWithinCheckpoint: number,
527
+ archive: Fr = Fr.random(),
528
+ ): Promise<BlockProposal> => {
529
+ const header = makeBlockHeader(1, { slotNumber: SlotNumber(slotNumber) });
530
+ return makeBlockProposal({
531
+ signer,
532
+ blockHeader: header,
533
+ archiveRoot: archive,
534
+ indexWithinCheckpoint: IndexWithinCheckpoint(indexWithinCheckpoint),
535
+ });
536
+ };
537
+
538
+ describe('tryAddBlockProposal duplicate detection', () => {
539
+ it('should return count=1 when pool is empty', async () => {
540
+ const proposal = await mockBlockProposalWithIndex(signers[0], 100, 0);
541
+ const result = await ap.tryAddBlockProposal(proposal);
542
+
543
+ expect(result.added).toBe(true);
544
+ expect(result.alreadyExists).toBe(false);
545
+ expect(result.count).toBe(1);
546
+ });
547
+
548
+ it('should return alreadyExists when same proposal exists', async () => {
549
+ const proposal = await mockBlockProposalWithIndex(signers[0], 100, 0);
550
+ await ap.tryAddBlockProposal(proposal);
551
+
552
+ const result = await ap.tryAddBlockProposal(proposal);
553
+
554
+ expect(result.added).toBe(false);
555
+ expect(result.alreadyExists).toBe(true);
556
+ expect(result.count).toBe(1);
557
+ });
558
+
559
+ it('should detect duplicate via count when different proposal exists at same position', async () => {
560
+ const slotNumber = 100;
561
+ const indexWithinCheckpoint = 2;
562
+
563
+ // Add first proposal
564
+ const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
565
+ const result1 = await ap.tryAddBlockProposal(proposal1);
566
+ expect(result1.count).toBe(1);
567
+
568
+ // Add a different proposal at same position - this is a duplicate (equivocation)
569
+ const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
570
+ const result2 = await ap.tryAddBlockProposal(proposal2);
571
+
572
+ expect(result2.added).toBe(true);
573
+ expect(result2.alreadyExists).toBe(false);
574
+ // count >= 2 indicates duplicate detection
575
+ expect(result2.count).toBe(2);
576
+ });
577
+
578
+ it('should not detect duplicate for different positions in same slot', async () => {
579
+ const slotNumber = 100;
580
+
581
+ // Add proposal at index 0
582
+ const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, 0);
583
+ await ap.tryAddBlockProposal(proposal1);
584
+
585
+ // Add proposal at index 1 (different position)
586
+ const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, 1);
587
+ const result = await ap.tryAddBlockProposal(proposal2);
588
+
589
+ expect(result.added).toBe(true);
590
+ // count = 1 means no duplicate for this position
591
+ expect(result.count).toBe(1);
592
+ });
593
+
594
+ it('should not detect duplicate for same position in different slots', async () => {
595
+ const indexWithinCheckpoint = 0;
596
+
597
+ // Add proposal at slot 100
598
+ const proposal1 = await mockBlockProposalWithIndex(signers[0], 100, indexWithinCheckpoint);
599
+ await ap.tryAddBlockProposal(proposal1);
600
+
601
+ // Add proposal at slot 200 (different slot)
602
+ const proposal2 = await mockBlockProposalWithIndex(signers[1], 200, indexWithinCheckpoint);
603
+ const result = await ap.tryAddBlockProposal(proposal2);
604
+
605
+ expect(result.added).toBe(true);
606
+ // count = 1 means no duplicate for this position
607
+ expect(result.count).toBe(1);
608
+ });
609
+
610
+ it('should track multiple duplicates correctly via count', async () => {
611
+ const slotNumber = 100;
612
+ const indexWithinCheckpoint = 0;
613
+
614
+ // Add multiple proposals for same position
615
+ const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
616
+ const result1 = await ap.tryAddBlockProposal(proposal1);
617
+ expect(result1.count).toBe(1);
618
+
619
+ const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
620
+ const result2 = await ap.tryAddBlockProposal(proposal2);
621
+ expect(result2.count).toBe(2);
622
+
623
+ // Third proposal for same position should be rejected (cap is 2)
624
+ const proposal3 = await mockBlockProposalWithIndex(signers[2], slotNumber, indexWithinCheckpoint);
625
+ const result3 = await ap.tryAddBlockProposal(proposal3);
626
+
627
+ expect(result3.added).toBe(false);
628
+ expect(result3.count).toBe(2);
629
+ });
630
+
631
+ it('should return added=false when exceeding capacity', async () => {
632
+ const slotNumber = 100;
633
+ const indexWithinCheckpoint = 0;
634
+
635
+ // Add MAX_BLOCK_PROPOSALS_PER_POSITION proposals
636
+ for (let i = 0; i < MAX_BLOCK_PROPOSALS_PER_POSITION; i++) {
637
+ const proposal = await mockBlockProposalWithIndex(
638
+ signers[i % NUMBER_OF_SIGNERS_PER_TEST],
639
+ slotNumber,
640
+ indexWithinCheckpoint,
641
+ );
642
+ const result = await ap.tryAddBlockProposal(proposal);
643
+ expect(result.added).toBe(true);
644
+ expect(result.count).toBe(i + 1);
645
+ }
646
+
647
+ // The next proposal should not be added
648
+ const extraProposal = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
649
+ const result = await ap.tryAddBlockProposal(extraProposal);
650
+ expect(result.added).toBe(false);
651
+ expect(result.alreadyExists).toBe(false);
652
+ expect(result.count).toBe(MAX_BLOCK_PROPOSALS_PER_POSITION);
653
+ });
654
+
655
+ it('should clean up block position index when deleting old data', async () => {
656
+ const slotNumber = 100;
657
+ const indexWithinCheckpoint = 0;
658
+
659
+ // Add proposal
660
+ const proposal1 = await mockBlockProposalWithIndex(signers[0], slotNumber, indexWithinCheckpoint);
661
+ await ap.tryAddBlockProposal(proposal1);
662
+
663
+ // Verify it's tracked (adding another should show count = 2)
664
+ const proposal2 = await mockBlockProposalWithIndex(signers[1], slotNumber, indexWithinCheckpoint);
665
+ let result = await ap.tryAddBlockProposal(proposal2);
666
+ expect(result.count).toBe(2);
667
+
668
+ // Delete old data
669
+ await ap.deleteOlderThan(SlotNumber(slotNumber + 1));
670
+
671
+ // Verify position index is cleaned up (count should be 1 now)
672
+ const proposal3 = await mockBlockProposalWithIndex(signers[2], slotNumber, indexWithinCheckpoint);
673
+ result = await ap.tryAddBlockProposal(proposal3);
674
+ expect(result.count).toBe(1);
675
+ });
676
+
677
+ it('should correctly delete block proposals at slot boundary', async () => {
678
+ // Add proposals at slots 99, 100, and 101 with various indices
679
+ const proposalSlot99Idx0 = await mockBlockProposalWithIndex(signers[0], 99, 0);
680
+ const proposalSlot99Idx1 = await mockBlockProposalWithIndex(signers[1], 99, 1);
681
+ const proposalSlot100Idx0 = await mockBlockProposalWithIndex(signers[2], 100, 0);
682
+ const proposalSlot101Idx0 = await mockBlockProposalWithIndex(signers[3], 101, 0);
683
+
684
+ await ap.tryAddBlockProposal(proposalSlot99Idx0);
685
+ await ap.tryAddBlockProposal(proposalSlot99Idx1);
686
+ await ap.tryAddBlockProposal(proposalSlot100Idx0);
687
+ await ap.tryAddBlockProposal(proposalSlot101Idx0);
688
+
689
+ // Delete slots older than 100 (should delete slot 99 only)
690
+ await ap.deleteOlderThan(SlotNumber(100));
691
+
692
+ // Slot 99 proposals should have their index cleaned up
693
+ const newProposal99 = await mockBlockProposalWithIndex(signers[0], 99, 0);
694
+ const result99 = await ap.tryAddBlockProposal(newProposal99);
695
+ expect(result99.count).toBe(1); // Index was cleaned up
696
+
697
+ // Slot 100 and 101 should still be tracked
698
+ const newProposal100 = await mockBlockProposalWithIndex(signers[1], 100, 0);
699
+ const result100 = await ap.tryAddBlockProposal(newProposal100);
700
+ expect(result100.count).toBe(2); // Still has the original
701
+
702
+ const newProposal101 = await mockBlockProposalWithIndex(signers[2], 101, 0);
703
+ const result101 = await ap.tryAddBlockProposal(newProposal101);
704
+ expect(result101.count).toBe(2); // Still has the original
705
+ });
706
+
707
+ it('should delete all indices for a given slot', async () => {
708
+ const slotNumber = 50;
709
+
710
+ // Add proposals at multiple indices for the same slot
711
+ const proposal0 = await mockBlockProposalWithIndex(signers[0], slotNumber, 0);
712
+ const proposal1 = await mockBlockProposalWithIndex(signers[1], slotNumber, 1);
713
+ const proposal2 = await mockBlockProposalWithIndex(signers[2], slotNumber, 2);
714
+
715
+ await ap.tryAddBlockProposal(proposal0);
716
+ await ap.tryAddBlockProposal(proposal1);
717
+ await ap.tryAddBlockProposal(proposal2);
718
+
719
+ // Delete slots older than slotNumber + 1
720
+ await ap.deleteOlderThan(SlotNumber(slotNumber + 1));
721
+
722
+ // All indices should be cleaned up
723
+ const newProposal0 = await mockBlockProposalWithIndex(signers[0], slotNumber, 0);
724
+ const result0 = await ap.tryAddBlockProposal(newProposal0);
725
+ expect(result0.count).toBe(1);
726
+
727
+ const newProposal1 = await mockBlockProposalWithIndex(signers[1], slotNumber, 1);
728
+ const result1 = await ap.tryAddBlockProposal(newProposal1);
729
+ expect(result1.count).toBe(1);
730
+
731
+ const newProposal2 = await mockBlockProposalWithIndex(signers[2], slotNumber, 2);
732
+ const result2 = await ap.tryAddBlockProposal(newProposal2);
733
+ expect(result2.count).toBe(1);
734
+ });
735
+
736
+ it('should delete block proposals from storage when deleting old data', async () => {
737
+ const oldSlot = 50;
738
+ const newSlot = 100;
739
+
740
+ // Add proposals at old and new slots
741
+ const oldProposal = await mockBlockProposalWithIndex(signers[0], oldSlot, 0);
742
+ const newProposal = await mockBlockProposalWithIndex(signers[1], newSlot, 0);
743
+
744
+ await ap.tryAddBlockProposal(oldProposal);
745
+ await ap.tryAddBlockProposal(newProposal);
746
+
747
+ // Verify both proposals exist
748
+ expect(await ap.getBlockProposalByArchive(oldProposal.archive.toString())).toBeDefined();
749
+ expect(await ap.getBlockProposalByArchive(newProposal.archive.toString())).toBeDefined();
750
+
751
+ // Delete slots older than newSlot (should delete oldSlot)
752
+ await ap.deleteOlderThan(SlotNumber(newSlot));
753
+
754
+ // Old proposal should be deleted from storage
755
+ expect(await ap.getBlockProposalByArchive(oldProposal.archive.toString())).toBeUndefined();
756
+
757
+ // New proposal should still exist
758
+ expect(await ap.getBlockProposalByArchive(newProposal.archive.toString())).toBeDefined();
759
+ });
760
+ });
761
+
762
+ describe('tryAddCheckpointProposal duplicate detection', () => {
763
+ const mockCheckpointProposalCoreForPool = async (
764
+ signer: Secp256k1Signer,
765
+ slotNumber: number,
766
+ archive: Fr = Fr.random(),
767
+ checkpointHeader?: CheckpointHeader,
768
+ ): Promise<CheckpointProposalCore> => {
769
+ const headerToUse = checkpointHeader ?? makeCheckpointHeader(1, { slotNumber: SlotNumber(slotNumber) });
770
+ const blockHeader = makeBlockHeader(1);
771
+ const proposal = await makeCheckpointProposal({
772
+ signer,
773
+ checkpointHeader: headerToUse,
774
+ archiveRoot: archive,
775
+ lastBlock: { blockHeader },
776
+ });
777
+ return proposal.toCore();
778
+ };
779
+
780
+ it('should return count=1 when pool is empty', async () => {
781
+ const proposal = await mockCheckpointProposalCoreForPool(signers[0], 100);
782
+ const result = await ap.tryAddCheckpointProposal(proposal);
783
+
784
+ expect(result.added).toBe(true);
785
+ expect(result.alreadyExists).toBe(false);
786
+ expect(result.count).toBe(1);
787
+ });
788
+
789
+ it('should return alreadyExists when same proposal exists', async () => {
790
+ const proposal = await mockCheckpointProposalCoreForPool(signers[0], 100);
791
+ await ap.tryAddCheckpointProposal(proposal);
792
+
793
+ const result = await ap.tryAddCheckpointProposal(proposal);
794
+
795
+ expect(result.added).toBe(false);
796
+ expect(result.alreadyExists).toBe(true);
797
+ expect(result.count).toBe(1);
798
+ });
799
+
800
+ it('should detect duplicate via count when different proposal exists for same slot', async () => {
801
+ const slotNumber = 100;
802
+
803
+ // Add first proposal
804
+ const proposal1 = await mockCheckpointProposalCoreForPool(signers[0], slotNumber);
805
+ const result1 = await ap.tryAddCheckpointProposal(proposal1);
806
+ expect(result1.count).toBe(1);
807
+
808
+ // Add a different proposal for same slot - this is a duplicate (equivocation)
809
+ const proposal2 = await mockCheckpointProposalCoreForPool(signers[1], slotNumber);
810
+ const result2 = await ap.tryAddCheckpointProposal(proposal2);
811
+
812
+ expect(result2.added).toBe(true);
813
+ expect(result2.alreadyExists).toBe(false);
814
+ // count >= 2 indicates duplicate detection
815
+ expect(result2.count).toBe(2);
816
+ });
817
+
818
+ it('should not detect duplicate for different slots', async () => {
819
+ // Add proposal at slot 100
820
+ const proposal1 = await mockCheckpointProposalCoreForPool(signers[0], 100);
821
+ await ap.tryAddCheckpointProposal(proposal1);
822
+
823
+ // Add proposal at slot 200 (different slot)
824
+ const proposal2 = await mockCheckpointProposalCoreForPool(signers[1], 200);
825
+ const result = await ap.tryAddCheckpointProposal(proposal2);
826
+
827
+ expect(result.added).toBe(true);
828
+ // count = 1 means no duplicate for this slot
829
+ expect(result.count).toBe(1);
830
+ });
831
+
832
+ it('should track multiple duplicates correctly via count', async () => {
833
+ const slotNumber = 100;
834
+
835
+ // Add multiple proposals for same slot
836
+ const proposal1 = await mockCheckpointProposalCoreForPool(signers[0], slotNumber);
837
+ const result1 = await ap.tryAddCheckpointProposal(proposal1);
838
+ expect(result1.count).toBe(1);
839
+
840
+ const proposal2 = await mockCheckpointProposalCoreForPool(signers[1], slotNumber);
841
+ const result2 = await ap.tryAddCheckpointProposal(proposal2);
842
+ expect(result2.count).toBe(2);
843
+
844
+ // Third proposal for same slot should be rejected (cap is 2)
845
+ const proposal3 = await mockCheckpointProposalCoreForPool(signers[2], slotNumber);
846
+ const result3 = await ap.tryAddCheckpointProposal(proposal3);
847
+
848
+ expect(result3.added).toBe(false);
849
+ expect(result3.count).toBe(2);
850
+ });
851
+
852
+ it('should not count attestations as proposals for duplicate detection', async () => {
853
+ const slotNumber = 100;
854
+ const archive = Fr.random();
855
+
856
+ // Attestation arrives BEFORE the checkpoint proposal (race condition in p2p)
857
+ const attestation = mockCheckpointAttestation(signers[0], slotNumber, archive);
858
+ await ap.addOwnCheckpointAttestations([attestation]);
859
+
860
+ // Now the checkpoint proposal arrives - this should NOT be detected as a duplicate
861
+ const proposal = await mockCheckpointProposalCoreForPool(signers[1], slotNumber, archive);
862
+ const result = await ap.tryAddCheckpointProposal(proposal);
863
+
864
+ expect(result.added).toBe(true);
865
+ expect(result.alreadyExists).toBe(false);
866
+ // count should be 1, NOT 2 - attestations should not count as proposals
867
+ expect(result.count).toBe(1);
868
+ });
869
+
870
+ it('should not count attestations for different proposals as duplicates', async () => {
871
+ const slotNumber = 100;
872
+ const archive1 = Fr.random();
873
+ const archive2 = Fr.random();
874
+
875
+ // Add attestations for two different proposals in the same slot
876
+ const attestation1 = mockCheckpointAttestation(signers[0], slotNumber, archive1);
877
+ const attestation2 = mockCheckpointAttestation(signers[1], slotNumber, archive2);
878
+ await ap.addOwnCheckpointAttestations([attestation1, attestation2]);
879
+
880
+ // Add the first checkpoint proposal - should not be affected by attestations
881
+ const proposal1 = await mockCheckpointProposalCoreForPool(signers[2], slotNumber, archive1);
882
+ const result1 = await ap.tryAddCheckpointProposal(proposal1);
883
+
884
+ expect(result1.added).toBe(true);
885
+ expect(result1.count).toBe(1);
886
+
887
+ // Add the second checkpoint proposal - this IS a duplicate (different archive, same slot)
888
+ const proposal2 = await mockCheckpointProposalCoreForPool(signers[3], slotNumber, archive2);
889
+ const result2 = await ap.tryAddCheckpointProposal(proposal2);
890
+
891
+ expect(result2.added).toBe(true);
892
+ expect(result2.count).toBe(2);
893
+ });
414
894
  });
415
895
  });
416
896
  }