@aztec/p2p 0.0.1-commit.96bb3f7 → 0.0.1-commit.993d240

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