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

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 (283) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +2 -2
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +25 -11
  5. package/dest/client/interface.d.ts +9 -2
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +3 -2
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +37 -36
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +17 -6
  11. package/dest/config.d.ts +24 -2
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +66 -7
  14. package/dest/errors/p2p-service.error.d.ts +9 -0
  15. package/dest/errors/p2p-service.error.d.ts.map +1 -0
  16. package/dest/errors/p2p-service.error.js +10 -0
  17. package/dest/index.d.ts +1 -2
  18. package/dest/index.d.ts.map +1 -1
  19. package/dest/index.js +0 -1
  20. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +4 -4
  21. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  22. package/dest/mem_pools/attestation_pool/attestation_pool.js +6 -5
  23. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +6 -6
  24. package/dest/mem_pools/index.d.ts +1 -2
  25. package/dest/mem_pools/index.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  27. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +2 -1
  29. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  32. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  33. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  34. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  35. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  36. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  37. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +9 -5
  38. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  39. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  40. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +25 -10
  41. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  42. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +38 -11
  43. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  44. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  45. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +26 -43
  46. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +4 -2
  47. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  48. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  49. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -1
  50. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  51. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +21 -6
  52. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +1 -1
  53. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  54. package/dest/msg_validators/attestation_validator/attestation_validator.js +5 -4
  55. package/dest/msg_validators/clock_tolerance.d.ts +1 -1
  56. package/dest/msg_validators/clock_tolerance.d.ts.map +1 -1
  57. package/dest/msg_validators/clock_tolerance.js +4 -3
  58. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
  59. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  60. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  61. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
  62. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  63. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  64. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
  65. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  66. package/dest/msg_validators/proposal_validator/proposal_validator.js +51 -49
  67. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  68. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  69. package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
  70. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  71. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  72. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  73. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  74. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  75. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  76. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  77. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  78. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  79. package/dest/msg_validators/tx_validator/factory.d.ts +23 -4
  80. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  81. package/dest/msg_validators/tx_validator/factory.js +36 -10
  82. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  83. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  84. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  85. package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
  86. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  87. package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
  88. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  89. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  90. package/dest/msg_validators/tx_validator/index.js +1 -0
  91. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +1 -1
  92. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  93. package/dest/msg_validators/tx_validator/metadata_validator.js +4 -4
  94. package/dest/msg_validators/tx_validator/phases_validator.d.ts +21 -1
  95. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  96. package/dest/msg_validators/tx_validator/phases_validator.js +49 -2
  97. package/dest/services/dummy_service.d.ts +5 -3
  98. package/dest/services/dummy_service.d.ts.map +1 -1
  99. package/dest/services/dummy_service.js +5 -1
  100. package/dest/services/encoding.d.ts +5 -1
  101. package/dest/services/encoding.d.ts.map +1 -1
  102. package/dest/services/encoding.js +7 -1
  103. package/dest/services/libp2p/libp2p_service.d.ts +14 -11
  104. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  105. package/dest/services/libp2p/libp2p_service.js +146 -74
  106. package/dest/services/peer-manager/peer_manager.d.ts +6 -2
  107. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  108. package/dest/services/peer-manager/peer_manager.js +22 -8
  109. package/dest/services/peer-manager/peer_scoring.d.ts +5 -2
  110. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  111. package/dest/services/peer-manager/peer_scoring.js +28 -10
  112. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +11 -8
  113. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  114. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +69 -65
  115. package/dest/services/reqresp/batch-tx-requester/interface.d.ts +3 -2
  116. package/dest/services/reqresp/batch-tx-requester/interface.d.ts.map +1 -1
  117. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts +5 -4
  118. package/dest/services/reqresp/batch-tx-requester/missing_txs.d.ts.map +1 -1
  119. package/dest/services/reqresp/batch-tx-requester/missing_txs.js +13 -7
  120. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +3 -1
  121. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  122. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +3 -0
  123. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  124. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  125. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  126. package/dest/services/reqresp/reqresp.d.ts +1 -1
  127. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  128. package/dest/services/reqresp/reqresp.js +17 -9
  129. package/dest/services/service.d.ts +5 -2
  130. package/dest/services/service.d.ts.map +1 -1
  131. package/dest/services/tx_collection/fast_tx_collection.d.ts +1 -4
  132. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -1
  133. package/dest/services/tx_collection/fast_tx_collection.js +57 -73
  134. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  135. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  136. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  137. package/dest/services/tx_collection/proposal_tx_collector.d.ts +6 -7
  138. package/dest/services/tx_collection/proposal_tx_collector.d.ts.map +1 -1
  139. package/dest/services/tx_collection/proposal_tx_collector.js +4 -4
  140. package/dest/services/tx_collection/request_tracker.d.ts +53 -0
  141. package/dest/services/tx_collection/request_tracker.d.ts.map +1 -0
  142. package/dest/services/tx_collection/request_tracker.js +84 -0
  143. package/dest/services/tx_collection/slow_tx_collection.js +1 -1
  144. package/dest/services/tx_collection/tx_collection.d.ts +3 -6
  145. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -1
  146. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  147. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  148. package/dest/services/tx_collection/tx_source.js +9 -7
  149. package/dest/test-helpers/make-test-p2p-clients.d.ts +1 -1
  150. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  151. package/dest/test-helpers/reqresp-nodes.d.ts +1 -1
  152. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  153. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  154. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  155. package/dest/test-helpers/testbench-utils.js +22 -3
  156. package/dest/testbench/p2p_client_testbench_worker.js +46 -16
  157. package/dest/testbench/worker_client_manager.d.ts +3 -1
  158. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  159. package/dest/testbench/worker_client_manager.js +6 -3
  160. package/dest/util.d.ts +1 -1
  161. package/package.json +14 -14
  162. package/src/client/factory.ts +43 -14
  163. package/src/client/interface.ts +9 -1
  164. package/src/client/p2p_client.ts +39 -36
  165. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +19 -9
  166. package/src/config.ts +92 -4
  167. package/src/errors/p2p-service.error.ts +11 -0
  168. package/src/index.ts +0 -1
  169. package/src/mem_pools/attestation_pool/attestation_pool.ts +7 -5
  170. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +6 -6
  171. package/src/mem_pools/index.ts +0 -3
  172. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  173. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  174. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  175. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  176. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  177. package/src/mem_pools/tx_pool_v2/interfaces.ts +9 -4
  178. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +59 -13
  179. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +29 -43
  180. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +13 -1
  181. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +23 -6
  182. package/src/msg_validators/attestation_validator/README.md +49 -0
  183. package/src/msg_validators/attestation_validator/attestation_validator.ts +5 -4
  184. package/src/msg_validators/clock_tolerance.ts +4 -3
  185. package/src/msg_validators/proposal_validator/README.md +123 -0
  186. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
  187. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
  188. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -53
  189. package/src/msg_validators/tx_validator/README.md +5 -1
  190. package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
  191. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  192. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  193. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  194. package/src/msg_validators/tx_validator/factory.ts +43 -3
  195. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  196. package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
  197. package/src/msg_validators/tx_validator/index.ts +1 -0
  198. package/src/msg_validators/tx_validator/metadata_validator.ts +12 -4
  199. package/src/msg_validators/tx_validator/phases_validator.ts +60 -1
  200. package/src/services/dummy_service.ts +7 -2
  201. package/src/services/encoding.ts +9 -1
  202. package/src/services/libp2p/libp2p_service.ts +147 -87
  203. package/src/services/peer-manager/peer_manager.ts +26 -8
  204. package/src/services/peer-manager/peer_scoring.ts +21 -5
  205. package/src/services/reqresp/README.md +229 -0
  206. package/src/services/reqresp/batch-tx-requester/README.md +46 -7
  207. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +64 -69
  208. package/src/services/reqresp/batch-tx-requester/interface.ts +2 -1
  209. package/src/services/reqresp/batch-tx-requester/missing_txs.ts +13 -6
  210. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +5 -0
  211. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  212. package/src/services/reqresp/reqresp.ts +19 -11
  213. package/src/services/service.ts +6 -1
  214. package/src/services/tx_collection/fast_tx_collection.ts +57 -83
  215. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  216. package/src/services/tx_collection/proposal_tx_collector.ts +8 -13
  217. package/src/services/tx_collection/request_tracker.ts +127 -0
  218. package/src/services/tx_collection/slow_tx_collection.ts +1 -1
  219. package/src/services/tx_collection/tx_collection.ts +3 -5
  220. package/src/services/tx_collection/tx_source.ts +8 -7
  221. package/src/test-helpers/make-test-p2p-clients.ts +1 -1
  222. package/src/test-helpers/reqresp-nodes.ts +1 -1
  223. package/src/test-helpers/testbench-utils.ts +29 -3
  224. package/src/testbench/p2p_client_testbench_worker.ts +45 -15
  225. package/src/testbench/worker_client_manager.ts +13 -6
  226. package/src/util.ts +1 -1
  227. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +0 -125
  228. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +0 -1
  229. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +0 -596
  230. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts +0 -32
  231. package/dest/mem_pools/tx_pool/eviction/eviction_manager.d.ts.map +0 -1
  232. package/dest/mem_pools/tx_pool/eviction/eviction_manager.js +0 -112
  233. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts +0 -157
  234. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.d.ts.map +0 -1
  235. package/dest/mem_pools/tx_pool/eviction/eviction_strategy.js +0 -52
  236. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +0 -16
  237. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +0 -1
  238. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +0 -122
  239. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts +0 -17
  240. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.d.ts.map +0 -1
  241. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.js +0 -84
  242. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts +0 -19
  243. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.d.ts.map +0 -1
  244. package/dest/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.js +0 -78
  245. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts +0 -26
  246. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.d.ts.map +0 -1
  247. package/dest/mem_pools/tx_pool/eviction/low_priority_eviction_rule.js +0 -84
  248. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts +0 -25
  249. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.d.ts.map +0 -1
  250. package/dest/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.js +0 -57
  251. package/dest/mem_pools/tx_pool/index.d.ts +0 -3
  252. package/dest/mem_pools/tx_pool/index.d.ts.map +0 -1
  253. package/dest/mem_pools/tx_pool/index.js +0 -2
  254. package/dest/mem_pools/tx_pool/priority.d.ts +0 -12
  255. package/dest/mem_pools/tx_pool/priority.d.ts.map +0 -1
  256. package/dest/mem_pools/tx_pool/priority.js +0 -15
  257. package/dest/mem_pools/tx_pool/tx_pool.d.ts +0 -127
  258. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +0 -1
  259. package/dest/mem_pools/tx_pool/tx_pool.js +0 -3
  260. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +0 -7
  261. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +0 -1
  262. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +0 -400
  263. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
  264. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  265. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
  266. package/dest/services/tx_collection/missing_txs_tracker.d.ts +0 -32
  267. package/dest/services/tx_collection/missing_txs_tracker.d.ts.map +0 -1
  268. package/dest/services/tx_collection/missing_txs_tracker.js +0 -27
  269. package/src/mem_pools/tx_pool/README.md +0 -270
  270. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +0 -746
  271. package/src/mem_pools/tx_pool/eviction/eviction_manager.ts +0 -132
  272. package/src/mem_pools/tx_pool/eviction/eviction_strategy.ts +0 -208
  273. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +0 -162
  274. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_mining_rule.ts +0 -104
  275. package/src/mem_pools/tx_pool/eviction/invalid_txs_after_reorg_rule.ts +0 -93
  276. package/src/mem_pools/tx_pool/eviction/low_priority_eviction_rule.ts +0 -106
  277. package/src/mem_pools/tx_pool/eviction/nullifier_conflict_pre_add_rule.ts +0 -75
  278. package/src/mem_pools/tx_pool/index.ts +0 -2
  279. package/src/mem_pools/tx_pool/priority.ts +0 -20
  280. package/src/mem_pools/tx_pool/tx_pool.ts +0 -141
  281. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +0 -319
  282. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
  283. package/src/services/tx_collection/missing_txs_tracker.ts +0 -52
@@ -0,0 +1,229 @@
1
+ # ReqResp Protocols
2
+
3
+ This module implements libp2p request-response protocols for the Aztec P2P network. All protocols share common transport-level validation (rate limiting, timeouts, Snappy decompression, error penalties) with protocol-specific logic layered on top.
4
+
5
+ ## Common Transport Validation
6
+
7
+ ### Rate Limiting (Responder Side)
8
+
9
+ Applied before the protocol handler runs.
10
+
11
+ | Protocol | Peer Limit | Global Limit | File |
12
+ |----------|-----------|-------------|------|
13
+ | PING | 5/s | 10/s | `rate-limiter/rate_limits.ts` |
14
+ | STATUS | 5/s | 10/s | same |
15
+ | AUTH | 5/s | 10/s | same |
16
+ | GOODBYE | 5/s | 10/s | same |
17
+ | BLOCK | 2/s | 5/s | same |
18
+ | BLOCK_TXS | 10/s | 200/s | same |
19
+ | TX | (see rate limits file) | (see rate limits file) | same |
20
+
21
+ - Per-peer limit exceeded: `HighToleranceError` penalty + `RATE_LIMIT_EXCEEDED` status. Penalty fires inside `RequestResponseRateLimiter.allow()`, not the stream handler.
22
+ - Global limit exceeded: `RATE_LIMIT_EXCEEDED` status only (no peer penalty).
23
+
24
+ ### Response Status Byte (Requester Side)
25
+
26
+ | Rule | Consequence | File |
27
+ |------|-------------|------|
28
+ | First chunk must be exactly 1 byte | `ReqRespStatusError(UNKNOWN)` | `status.ts` |
29
+ | Byte must be valid `ReqRespStatus` enum (0-4, 126, 127) | `ReqRespStatusError(UNKNOWN)` | same |
30
+
31
+ Note: `prettyPrintReqRespStatus` is missing a `NOT_FOUND` case (minor logging bug).
32
+
33
+ ### Snappy Decompression (Requester Side)
34
+
35
+ Per-protocol size limits checked via preamble before decompression.
36
+
37
+ ### Timeouts (Requester Side)
38
+
39
+ | Timeout | Default | Penalty |
40
+ |---------|---------|---------|
41
+ | Individual request | 10s | HighToleranceError |
42
+ | Dial | 5s | HighToleranceError |
43
+
44
+ ### Error Penalty Categorization (Requester Side)
45
+
46
+ | Error Type | Severity |
47
+ |------------|----------|
48
+ | GOODBYE subprotocol errors | None |
49
+ | `CollectiveReqRespTimeoutError` / `InvalidResponseError` | None |
50
+ | `AbortError` / connection close / muxer closed | None |
51
+ | `ECONNRESET` / `EPIPE` / `ECONNREFUSED` / `ERR_UNEXPECTED_EOF` | HighToleranceError |
52
+ | `ERR_UNSUPPORTED_PROTOCOL` | HighToleranceError |
53
+ | `IndividualReqRespTimeoutError` / `TimeoutError` | HighToleranceError |
54
+ | Catch-all | HighToleranceError |
55
+
56
+ ### Request Error Penalty (Responder Side)
57
+
58
+ | Error Type | Severity |
59
+ |------------|----------|
60
+ | `BADLY_FORMED_REQUEST` | LowToleranceError |
61
+ | All others | None |
62
+
63
+ ### Notes
64
+
65
+ - Request payloads are NOT snappy-compressed (asymmetric: only responses use snappy).
66
+
67
+ ---
68
+
69
+ ## Handshake Protocols
70
+
71
+ ### Connection-Level Gating (Before Any Handshake)
72
+
73
+ | Rule | Consequence | File |
74
+ |------|-------------|------|
75
+ | Deny inbound connection from IP/peerId with too many failed auth handshakes | Connection denied | `libp2p_service.ts` |
76
+ | Threshold: `p2pMaxFailedAuthAttemptsAllowed` (default 3) | Tracked per peerId AND per IP | `peer_manager.ts` |
77
+ | Failed auth entries expire after 1 hour | Peer can reconnect; no escalating penalty for repeat offenders | same |
78
+
79
+ ### Handshake Trigger Logic (`peer:connect`)
80
+
81
+ 1. `p2pDisableStatusHandshake` = true: no handshake
82
+ 2. `p2pAllowOnlyValidators` = false: STATUS handshake
83
+ 3. Peer is protected (trusted/private/preferred): STATUS handshake
84
+ 4. Otherwise: AUTH handshake (superset of STATUS)
85
+
86
+ Config constraint: `p2pDisableStatusHandshake && p2pAllowOnlyValidators` is disallowed.
87
+
88
+ ### STATUS Protocol (`/aztec/req/status/1.0.0`)
89
+
90
+ **Requester side** (`peer_manager.ts`):
91
+
92
+ | Rule | Consequence |
93
+ |------|-------------|
94
+ | Response status must be SUCCESS | Peer scheduled for disconnect |
95
+ | `compressedComponentsVersion` must match | Peer scheduled for disconnect |
96
+ | Any exception | Peer scheduled for disconnect |
97
+
98
+ `StatusMessage.validate()` currently only checks `compressedComponentsVersion`. Fields `latestBlockNumber`, `latestBlockHash`, `finalizedBlockNumber` are NOT validated (TODO in code).
99
+
100
+ **Responder side**: no validation of incoming request content (always responds with own status). This means the requester leaks its blockchain state to any peer before validation.
101
+
102
+ **Deserialization bounds**: `MAX_VERSION_STRING_LENGTH` = 64 bytes, `MAX_BLOCK_HASH_STRING_LENGTH` = 128 bytes. Expected response size: 1 KB.
103
+
104
+ ### AUTH Protocol (`/aztec/req/auth/1.0.0`)
105
+
106
+ **Requester side** (`peer_manager.ts`):
107
+
108
+ | # | Rule | Consequence |
109
+ |---|------|-------------|
110
+ | 1 | Response status is SUCCESS | `markAuthHandshakeFailed` + disconnect |
111
+ | 2 | `compressedComponentsVersion` match | `markAuthHandshakeFailed` + disconnect |
112
+ | 3 | Valid ECDSA signature recovery from challenge response | `markAuthHandshakeFailed` + disconnect |
113
+ | 4 | Recovered address is a registered validator | `markAuthHandshakeFailed` + disconnect |
114
+ | 5 | Validator address not already authenticated to different peerId | Silent return (no disconnect, no failure marking -- peer stays connected but unauthenticated) |
115
+ | 6 | Any exception | `markAuthHandshakeFailed` + disconnect |
116
+
117
+ Challenge: random `Fr`, payload = `keccak256("Aztec Validator Challenge:" + challenge)`, signed with `eth_sign` style. Challenge is NOT bound to peer identity (transport encryption via Noise is the binding layer).
118
+
119
+ On success: peer added to authenticated maps, prior failures cleared (including IP-based ones -- shared-IP peers benefit from a legitimate validator's success).
120
+
121
+ **Responder side** (`validator-client/src/validator.ts` + `peer_manager.ts`):
122
+
123
+ | # | Rule | Consequence |
124
+ |---|------|-------------|
125
+ | 1 | Peer must be protected (`shouldTrustWithIdentity` in `peer_manager.ts`) | Returns empty buffer (SUCCESS status + empty payload -> requester gets parse error -> `markAuthHandshakeFailed`) |
126
+ | 2 | Node must have registered validator address | Returns empty buffer (same consequence) |
127
+
128
+ **Unauthenticated peer gossip**: when `p2pAllowOnlyValidators` is true, unauthenticated peers get `appSpecificScore = -Infinity`, completely excluding them from all gossip.
129
+
130
+ ### PING Protocol (`/aztec/req/ping/1.0.0`)
131
+
132
+ No validation on either side. Responder returns `Buffer.from('pong')`. Expected response: 1 KB.
133
+
134
+ ### GOODBYE Protocol (`/aztec/req/goodbye/1.0.0`)
135
+
136
+ **Responder**: buffer must be 1 byte (defaults to `UNKNOWN` on invalid length). Goodbye reason byte is NOT validated against the enum -- any byte 0-255 accepted. Peer scheduled for disconnect regardless of reason.
137
+
138
+ **Requester**: response errors are never penalized (GOODBYE subprotocol exempt from error categorization).
139
+
140
+ ### Periodic Re-validation
141
+
142
+ | Rule | Interval | File |
143
+ |------|----------|------|
144
+ | Authenticated validators re-checked against current validator set | Every heartbeat (`peerCheckIntervalMS`) | `peer_manager.ts` |
145
+ | If validator address no longer registered, auth entry removed | Same | same |
146
+
147
+ Protected peers (private/trusted/preferred) are always considered "authenticated" without AUTH handshake.
148
+
149
+ ---
150
+
151
+ ## Block Data Protocols
152
+
153
+ ### BLOCK Protocol (`/aztec/req/block/1.0.0`)
154
+
155
+ **Server side**:
156
+
157
+ | Rule | Consequence | File |
158
+ |------|-------------|------|
159
+ | Request must parse as `Fr` | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/block.ts` |
160
+ | Block lookup throws | `INTERNAL_ERROR` status | same |
161
+ | Block not found | SUCCESS + empty buffer (design choice; no `NOT_FOUND` status used) | same |
162
+
163
+ **Requester side** (Snappy limit: 3 MB):
164
+
165
+ | Rule | Consequence | File |
166
+ |------|-------------|------|
167
+ | Response block number must match requested | LowToleranceError; rejected | `libp2p_service.ts` (`validateRequestedBlock`) |
168
+ | Local block must exist for hash verification | Rejected (no penalty) | same |
169
+ | Response block hash must equal local block hash | MidToleranceError; rejected | same |
170
+
171
+ **Limitation**: the local-block requirement means BLOCK req/resp is unusable for initial P2P-only sync (before L1 sync provides local copies for verification). A TODO in the code acknowledges this.
172
+
173
+ ### BLOCK_TXS Protocol (`/aztec/req/block_txs/1.0.0`)
174
+
175
+ **Server side**:
176
+
177
+ | Rule | Consequence | File |
178
+ |------|-------------|------|
179
+ | Request must parse as `BlockTxsRequest` (Fr + TxHashArray + BitVector) | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/block_txs/block_txs_handler.ts` |
180
+ | BitVector length: non-negative and <= `MAX_TXS_PER_BLOCK` (65536) | Deserialization throws -> `BADLY_FORMED_REQUEST` | `protocols/block_txs/bitvector.ts` |
181
+ | Archive root not found and no explicit txHashes | `NOT_FOUND` status | handler |
182
+ | Internal error during lookup | Unhandled exception -> stream abort (no `INTERNAL_ERROR` status, unlike BLOCK) | handler |
183
+
184
+ Conditional registration: BLOCK_TXS handler only registered when `config.disableTransactions` is false. Otherwise peers get `ERR_UNSUPPORTED_PROTOCOL`.
185
+
186
+ **Requester side via `sendBatchRequest`** (Snappy limit: `max(N, 1) * 512 + 1` KB):
187
+
188
+ | Rule | Consequence | File |
189
+ |------|-------------|------|
190
+ | Archive root must match request | MidToleranceError | `libp2p_service.ts` (`validateRequestedBlockTxs`) |
191
+ | BitVector length must match request | MidToleranceError | same |
192
+ | No duplicate tx hashes | MidToleranceError | same |
193
+ | Tx count within bounds | MidToleranceError | same |
194
+ | Local block proposal must exist for archive root | Rejected (no penalty) | same |
195
+ | All tx hashes must be in proposal's tx list at allowed indices | LowToleranceError | same |
196
+ | Txs in strictly increasing index order | LowToleranceError | same |
197
+ | Each tx passes well-formedness (Metadata [4 fields], Size, Data, Proof) | LowToleranceError | same |
198
+
199
+ **Requester side via `BatchTxRequester`** (separate validation path):
200
+
201
+ | Rule | Consequence | File |
202
+ |------|-------------|------|
203
+ | Non-SUCCESS status: `FAILURE`/`UNKNOWN` | HighToleranceError + "bad peer" tracking | `batch-tx-requester/batch_tx_requester.ts` |
204
+ | `RATE_LIMIT_EXCEEDED` | Peer marked rate-limited (cooldown) | same |
205
+ | `NOT_FOUND` / `BADLY_FORMED_REQUEST` / `INTERNAL_ERROR` | Falls through silently (no penalty) | same |
206
+ | Each tx validated (Metadata + Size + Data + Proof) | LowToleranceError per invalid tx; valid txs from same response still accepted | same |
207
+ | Archive root match + non-empty txIndices | No penalty on mismatch; peer not promoted to "smart" | same |
208
+
209
+ **Double penalty on transport errors**: when `BatchTxRequester` encounters a transport error (e.g., ECONNRESET), both `sendRequestToPeer`'s internal handler and the `BatchTxRequester`'s catch block penalize the peer, resulting in double HighToleranceError.
210
+
211
+ See [BatchTxRequester README](batch-tx-requester/README.md) for the full architecture (peer classification, worker model, wire protocol).
212
+
213
+ ### TX Protocol (`/aztec/req/tx/1.0.0`)
214
+
215
+ **Server side**:
216
+
217
+ | Rule | Consequence | File |
218
+ |------|-------------|------|
219
+ | Request must parse as `TxHashArray` | `BADLY_FORMED_REQUEST` + LowToleranceError | `protocols/tx.ts` |
220
+
221
+ **Requester side** (validator registered at startup, not the default noop):
222
+
223
+ | Rule | Consequence | File |
224
+ |------|-------------|------|
225
+ | Each returned tx hash must be in the requested set | MidToleranceError | `libp2p_service.ts` (`validateRequestedTxs`) |
226
+ | Each tx passes well-formedness (Metadata + Size + Data + Proof) | LowToleranceError | same |
227
+
228
+ Snappy limit: `max(N, 1) * 512 + 1` KB.
229
+
@@ -170,6 +170,37 @@ class BlockTxsResponse {
170
170
 
171
171
  The `BitVector` is a compact representation where each bit corresponds to a transaction index in the block proposal. This allows efficient capability advertisement without repeating full hashes.
172
172
 
173
+ ## Cancellation
174
+
175
+ All cancellation is managed by a single `RequestTracker` instance, shared across the entire collection
176
+ flow. The `RequestTracker` owns the deadline, tracks which txs are still missing, and exposes a
177
+ `cancellationToken` promise that resolves when the request should stop (deadline hit, all txs fetched,
178
+ or external `cancel()` call).
179
+
180
+ Cancellation propagates from the deepest stack level upward:
181
+
182
+ ```
183
+ RequestTracker.finish()
184
+ ├── resolves cancellationToken promise
185
+
186
+ ├── BatchTxRequester workers (deepest)
187
+ │ ├── shouldStop() checks requestTracker.cancelled → exit loop
188
+ │ ├── sleepClampedToDeadline races sleep vs cancellationToken → wakes
189
+ │ └── semaphore.acquire races vs cancellationToken → wakes
190
+ │ │
191
+ │ ▼ workers settle → txQueue.end() → generator returns
192
+
193
+ ├── Node collection loops
194
+ │ ├── notFinished() checks requestTracker.cancelled → exit loop
195
+ │ └── inter-retry sleep races vs cancellationToken → wakes
196
+ │ │
197
+ │ ▼ all node loops settle
198
+
199
+ └── collectFast (outermost)
200
+ awaits Promise.allSettled([reqresp, nodes]) → settles after inner tasks
201
+ finally: requestTracker.cancel() (idempotent), cleanup
202
+ ```
203
+
173
204
  ## Key Files
174
205
 
175
206
  | File | Description |
@@ -179,15 +210,16 @@ The `BitVector` is a compact representation where each bit corresponds to a tran
179
210
  | `peer_collection.ts` | Manages peer classification (dumb/smart/bad) and rate limiting |
180
211
  | `interface.ts` | Type definitions for dependencies |
181
212
  | `../protocols/block_txs/` | Wire protocol definitions (`BlockTxsRequest`, `BlockTxsResponse`, `BitVector`) |
213
+ | `../../tx_collection/request_tracker.ts` | Centralized deadline, missing tx tracking, and cancellation signal |
182
214
 
183
215
  ## Stopping Conditions
184
216
 
185
- The `BatchTxRequester` stops when any of these conditions are met:
217
+ The `BatchTxRequester` stops when any of these conditions are met, all managed by the `RequestTracker`:
186
218
 
187
- 1. **All transactions fetched** - Success!
188
- 2. **Deadline exceeded** - Timeout configured by caller
189
- 3. **Abort signal** - External cancellation
190
- 4. **No transactions to fetch** - Nothing was missing
219
+ 1. **All transactions fetched** - `markFetched()` removes the last missing tx, triggering `finish()`
220
+ 2. **Deadline exceeded** - `setTimeout` in `RequestTracker` fires, triggering `finish()`
221
+ 3. **External cancellation** - `RequestTracker.cancel()` called (e.g., from `stop()`, `stopCollectingForBlocksUpTo`)
222
+ 4. **No transactions to fetch** - Empty hash set at construction, `RequestTracker` finishes immediately
191
223
 
192
224
  ## Configuration
193
225
 
@@ -228,11 +260,15 @@ Request to peer fails
228
260
  ## Usage Example
229
261
 
230
262
  ```typescript
263
+ const requestTracker = RequestTracker.create(
264
+ missingTxHashes, // TxHash[] - what we need
265
+ new Date(Date.now() + 5_000), // deadline
266
+ );
267
+
231
268
  const requester = new BatchTxRequester(
232
- missingTxHashes, // TxHash[] - what we need
269
+ requestTracker, // IRequestTracker - tracks missing txs, deadline, and cancellation
233
270
  blockTxsSource, // BlockTxsSource - the proposal or block we need txs for
234
271
  pinnedPeer, // PeerId | undefined - peer expected to have the txs
235
- timeoutMs, // number - how long to try
236
272
  p2pService, // BatchTxRequesterLibP2PService
237
273
  );
238
274
 
@@ -273,6 +309,8 @@ const txs = await BatchTxRequester.collectAllTxs(requester.run());
273
309
  │ 1. Try RPC nodes first (fast) │ │ Periodic polling of RPC nodes │
274
310
  │ 2. Fall back to BatchTxRequester │ │ and peers for missing txs │
275
311
  │ │ │ │
312
+ │ Creates RequestTracker per │ │ │
313
+ │ request with deadline │ │ │
276
314
  └───────────────────┬───────────────┘ └─────────────────────────────────────┘
277
315
 
278
316
  │ For 'proposal' and 'block' requests
@@ -281,6 +319,7 @@ const txs = await BatchTxRequester.collectAllTxs(requester.run());
281
319
  │ BatchTxRequester │
282
320
  │ │
283
321
  │ Aggressive parallel fetching from multiple peers │
322
+ │ Shares RequestTracker with FastTxCollection for unified cancellation │
284
323
  │ Uses BLOCK_TXS sub-protocol for efficient batching │
285
324
  └───────────────────┬─────────────────────────────────────────────────────────┘
286
325
 
@@ -1,15 +1,14 @@
1
1
  import { chunkWrapAround } from '@aztec/foundation/collection';
2
- import { TimeoutError } from '@aztec/foundation/error';
3
2
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
3
  import { FifoMemoryQueue, type ISemaphore, Semaphore } from '@aztec/foundation/queue';
5
4
  import { sleep } from '@aztec/foundation/sleep';
6
- import { DateProvider, executeTimeout } from '@aztec/foundation/timer';
5
+ import { DateProvider } from '@aztec/foundation/timer';
7
6
  import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
8
7
  import { Tx, TxArray, TxHash } from '@aztec/stdlib/tx';
9
8
 
10
9
  import type { PeerId } from '@libp2p/interface';
11
10
 
12
- import type { IMissingTxsTracker } from '../../tx_collection/missing_txs_tracker.js';
11
+ import type { IRequestTracker } from '../../tx_collection/request_tracker.js';
13
12
  import { ReqRespSubProtocol } from '.././interface.js';
14
13
  import { BlockTxsRequest, BlockTxsResponse, type BlockTxsSource } from '.././protocols/index.js';
15
14
  import { ReqRespStatus } from '.././status.js';
@@ -42,16 +41,14 @@ import { BatchRequestTxValidator, type IBatchRequestTxValidator } from './tx_val
42
41
  * - Is the peer which was unable to send us successful response N times in a row
43
42
  * */
44
43
  export class BatchTxRequester {
44
+ private readonly requestTracker: IRequestTracker;
45
45
  private readonly blockTxsSource: BlockTxsSource;
46
46
  private readonly pinnedPeer: PeerId | undefined;
47
- private readonly timeoutMs: number;
48
47
  private readonly p2pService: BatchTxRequesterLibP2PService;
49
48
  private readonly logger: Logger;
50
- private readonly dateProvider: DateProvider;
51
49
  private readonly opts: BatchTxRequesterOptions;
52
50
  private readonly peers: IPeerCollection;
53
51
  private readonly txsMetadata: ITxMetadataCollection;
54
- private readonly deadline: number;
55
52
  private readonly smartRequesterSemaphore: ISemaphore;
56
53
  private readonly txQueue: FifoMemoryQueue<Tx>;
57
54
  private readonly txValidator: IBatchRequestTxValidator;
@@ -60,21 +57,19 @@ export class BatchTxRequester {
60
57
  private readonly txBatchSize: number;
61
58
 
62
59
  constructor(
63
- missingTxsTracker: IMissingTxsTracker,
60
+ requestTracker: IRequestTracker,
64
61
  blockTxsSource: BlockTxsSource,
65
62
  pinnedPeer: PeerId | undefined,
66
- timeoutMs: number,
67
63
  p2pService: BatchTxRequesterLibP2PService,
68
64
  logger?: Logger,
69
65
  dateProvider?: DateProvider,
70
66
  opts?: BatchTxRequesterOptions,
71
67
  ) {
68
+ this.requestTracker = requestTracker;
72
69
  this.blockTxsSource = blockTxsSource;
73
70
  this.pinnedPeer = pinnedPeer;
74
- this.timeoutMs = timeoutMs;
75
71
  this.p2pService = p2pService;
76
72
  this.logger = logger ?? createLogger('p2p:reqresp_batch');
77
- this.dateProvider = dateProvider ?? new DateProvider();
78
73
  this.opts = opts ?? {};
79
74
 
80
75
  this.smartParallelWorkerCount =
@@ -82,7 +77,6 @@ export class BatchTxRequester {
82
77
  this.dumbParallelWorkerCount =
83
78
  this.opts.dumbParallelWorkerCount ?? DEFAULT_BATCH_TX_REQUESTER_DUMB_PARALLEL_WORKER_COUNT;
84
79
  this.txBatchSize = this.opts.txBatchSize ?? DEFAULT_BATCH_TX_REQUESTER_TX_BATCH_SIZE;
85
- this.deadline = this.dateProvider.now() + this.timeoutMs;
86
80
  this.txQueue = new FifoMemoryQueue(this.logger);
87
81
  this.txValidator = this.opts.txValidator ?? new BatchRequestTxValidator(this.p2pService.txValidatorConfig);
88
82
 
@@ -93,12 +87,12 @@ export class BatchTxRequester {
93
87
  this.peers = new PeerCollection(
94
88
  this.p2pService.connectionSampler,
95
89
  this.pinnedPeer,
96
- this.dateProvider,
90
+ dateProvider ?? new DateProvider(),
97
91
  badPeerThreshold,
98
92
  this.p2pService.peerScoring,
99
93
  );
100
94
  }
101
- this.txsMetadata = new MissingTxMetadataCollection(missingTxsTracker, this.txBatchSize);
95
+ this.txsMetadata = new MissingTxMetadataCollection(requestTracker, this.txBatchSize);
102
96
  this.smartRequesterSemaphore = this.opts.semaphore ?? new Semaphore(0);
103
97
  }
104
98
 
@@ -106,40 +100,30 @@ export class BatchTxRequester {
106
100
  * Fetches all missing transactions and yields them one by one
107
101
  * */
108
102
  public async *run(): AsyncGenerator<Tx, Tx | undefined, unknown> {
109
- // Our timeout is represented in milliseconds but queue expects seconds
110
- // We also want to make sure we wait at least 1 second in case of very low timeouts
111
- const timeoutQueueAfter = Math.max(Math.ceil(this.timeoutMs / 1_000), 1);
112
103
  try {
113
104
  if (this.txsMetadata.getMissingTxHashes().size === 0) {
114
105
  return undefined;
115
106
  }
116
107
 
117
- // Start workers in background
118
- const workersPromise = executeTimeout(
119
- () => Promise.allSettled([this.smartRequester(), this.dumbRequester(), this.pinnedPeerRequester()]),
120
- this.timeoutMs,
121
- ).finally(() => {
108
+ // Start workers in background. Workers stop themselves via requestTracker.checkCancelled().
109
+ const workersPromise = Promise.allSettled([
110
+ this.smartRequester(),
111
+ this.dumbRequester(),
112
+ this.pinnedPeerRequester(),
113
+ ]).finally(() => {
122
114
  this.txQueue.end();
123
115
  });
124
116
 
117
+ // Yield txs as workers put them on the queue. The queue's end() drains remaining items
118
+ // before returning null, so we don't lose any txs.
125
119
  while (true) {
126
- const tx = await this.txQueue.get(timeoutQueueAfter);
120
+ const tx = await this.txQueue.get();
127
121
 
128
- // null indicates that the queue has ended
129
122
  if (tx === null) {
130
123
  break;
131
124
  }
132
125
 
133
126
  yield tx;
134
-
135
- if (this.shouldStop()) {
136
- // Drain queue before ending
137
- let remaining;
138
- while ((remaining = this.txQueue.getImmediate()) !== undefined) {
139
- yield remaining;
140
- }
141
- break;
142
- }
143
127
  }
144
128
 
145
129
  this.unlockSmartRequesterSemaphores();
@@ -360,7 +344,10 @@ export class BatchTxRequester {
360
344
  ) {
361
345
  try {
362
346
  this.logger.trace(`Smart worker ${workerIndex} started`);
363
- await executeTimeout((_: AbortSignal) => this.smartRequesterSemaphore.acquire(), this.timeoutMs);
347
+ await Promise.race([this.smartRequesterSemaphore.acquire(), this.requestTracker.cancellationToken]);
348
+ if (this.requestTracker.checkCancelled()) {
349
+ return;
350
+ }
364
351
  this.logger.trace(`Smart worker ${workerIndex} acquired semaphore`);
365
352
 
366
353
  while (!this.shouldStop()) {
@@ -384,7 +371,10 @@ export class BatchTxRequester {
384
371
  //
385
372
  // When a dumb peer responds with valid txIndices, it gets
386
373
  // promoted to smart and releases the semaphore, waking this worker.
387
- await executeTimeout((_: AbortSignal) => this.smartRequesterSemaphore.acquire(), this.timeoutMs);
374
+ await Promise.race([this.smartRequesterSemaphore.acquire(), this.requestTracker.cancellationToken]);
375
+ if (this.requestTracker.checkCancelled()) {
376
+ break;
377
+ }
388
378
  this.logger.debug(`Worker loop smart: acquired next smart peer`);
389
379
  continue;
390
380
  }
@@ -411,11 +401,7 @@ export class BatchTxRequester {
411
401
  });
412
402
  }
413
403
  } catch (err: any) {
414
- if (err instanceof TimeoutError) {
415
- this.logger.debug(`Smart worker ${workerIndex} timed out waiting for semaphore`);
416
- } else {
417
- this.logger.error(`Smart worker ${workerIndex} encountered an error: ${err}`);
418
- }
404
+ this.logger.error(`Smart worker ${workerIndex} encountered an error: ${err}`);
419
405
  } finally {
420
406
  this.logger.debug(`Smart worker ${workerIndex} finished`);
421
407
  }
@@ -463,9 +449,18 @@ export class BatchTxRequester {
463
449
  * this implies we will query these peers couple of more times and give them a chance to "redeem" themselves before completely ignoring them
464
450
  */
465
451
  private handleFailResponseFromPeer(peerId: PeerId, responseStatus: ReqRespStatus) {
466
- //TODO: Should we ban these peers?
467
452
  if (responseStatus === ReqRespStatus.FAILURE || responseStatus === ReqRespStatus.UNKNOWN) {
468
453
  this.peers.penalisePeer(peerId, PeerErrorSeverity.HighToleranceError);
454
+ this.peers.markPeerDumb(peerId);
455
+ this.txsMetadata.clearPeerData(peerId);
456
+ return;
457
+ }
458
+
459
+ // NOT_FOUND means the peer pruned its block proposal — it can no longer serve
460
+ // index-based requests, but this is a legitimate state so we don't penalize.
461
+ if (responseStatus === ReqRespStatus.NOT_FOUND) {
462
+ this.peers.markPeerDumb(peerId);
463
+ this.txsMetadata.clearPeerData(peerId);
469
464
  return;
470
465
  }
471
466
 
@@ -519,6 +514,9 @@ export class BatchTxRequester {
519
514
  });
520
515
 
521
516
  if (hasInvalidTx) {
517
+ this.logger.warn(`Penalizing peer ${peerId.toString()} for sending invalid transactions in batch response`, {
518
+ peerId,
519
+ });
522
520
  this.peers.penalisePeer(peerId, PeerErrorSeverity.LowToleranceError);
523
521
  } else {
524
522
  // If we have received successful response from the peer, they have "redeemed" themselves and not considered bad anymore
@@ -555,10 +553,9 @@ export class BatchTxRequester {
555
553
  return;
556
554
  }
557
555
 
558
- // If block response is invalid we still want to query this peer in the future
559
- // Because they sent successful response, so they might become smart peer in the future
560
- // Or send us needed txs
561
- if (!this.isBlockResponseValid(response)) {
556
+ const hasArchiveRootMismatch = this.blockTxsSource.archive.toString() !== response.archiveRoot.toString();
557
+ if (hasArchiveRootMismatch) {
558
+ this.handleArchiveRootMismatch(peerId, response);
562
559
  return;
563
560
  }
564
561
 
@@ -576,13 +573,25 @@ export class BatchTxRequester {
576
573
  this.smartRequesterSemaphore.release();
577
574
  }
578
575
 
579
- private isBlockResponseValid(response: BlockTxsResponse): boolean {
580
- const archiveRootsMatch = this.blockTxsSource.archive.toString() === response.archiveRoot.toString();
581
- const peerHasSomeTxsFromProposal = !response.txIndices.isEmpty();
582
- return archiveRootsMatch && peerHasSomeTxsFromProposal;
576
+ /**
577
+ * Handles an archive root mismatch between local state and peer response.
578
+ *
579
+ * - Response archive is Fr.ZERO (peer pruned proposal, legitimate): marks peer dumb.
580
+ * - Non-zero archive mismatch (malicious response): penalises + marks dumb.
581
+ */
582
+ private handleArchiveRootMismatch(peerId: PeerId, response: BlockTxsResponse): void {
583
+ if (!response.archiveRoot.isZero()) {
584
+ this.peers.penalisePeer(peerId, PeerErrorSeverity.LowToleranceError);
585
+ }
586
+
587
+ this.peers.markPeerDumb(peerId);
588
+ this.txsMetadata.clearPeerData(peerId);
583
589
  }
584
590
 
585
591
  private peerHasSomeTxsWeAreMissing(_peerId: PeerId, response: BlockTxsResponse): boolean {
592
+ if (response.txIndices.isEmpty()) {
593
+ return false;
594
+ }
586
595
  const txsPeerHas = new Set(this.extractHashesPeerHasFromResponse(response).map(h => h.toString()));
587
596
  return this.txsMetadata.getMissingTxHashes().intersection(txsPeerHas).size > 0;
588
597
  }
@@ -631,27 +640,14 @@ export class BatchTxRequester {
631
640
  }
632
641
 
633
642
  /*
634
- * @returns true if all missing txs have been fetched */
635
- private fetchedAllTxs() {
636
- return this.txsMetadata.getMissingTxHashes().size == 0;
637
- }
638
-
639
- /*
640
- * Checks if the BatchTxRequester should stop fetching missing txs
641
- * Conditions for stopping are:
642
- * - There have been no missing transactions to start with
643
- * - All transactions have been fetched
644
- * - The deadline has been hit (no more time to fetch)
645
- * - This process has been cancelled via abortSignal
646
- *
647
- * @returns true if BatchTxRequester should stop, otherwise false*/
643
+ * Checks if the BatchTxRequester should stop fetching missing txs.
644
+ * Delegates to requestTracker which covers: deadline hit, all txs fetched, or external cancellation. */
648
645
  private shouldStop() {
649
- const aborted = this.opts.abortSignal?.aborted ?? false;
650
- if (aborted) {
646
+ if (this.requestTracker.checkCancelled()) {
651
647
  this.unlockSmartRequesterSemaphores();
652
648
  }
653
649
 
654
- return aborted || this.fetchedAllTxs() || this.dateProvider.now() > this.deadline;
650
+ return this.requestTracker.checkCancelled();
655
651
  }
656
652
 
657
653
  /*
@@ -669,10 +665,9 @@ export class BatchTxRequester {
669
665
  * This ensures we don't sleep past the deadline.
670
666
  * */
671
667
  private async sleepClampedToDeadline(durationMs: number) {
672
- const remaining = this.deadline - this.dateProvider.now();
673
- const thereIsTimeRemaining = remaining > 0;
674
- if (thereIsTimeRemaining) {
675
- await sleep(Math.min(durationMs, remaining));
668
+ if (this.requestTracker.checkCancelled()) {
669
+ return;
676
670
  }
671
+ await Promise.race([sleep(durationMs), this.requestTracker.cancellationToken]);
677
672
  }
678
673
  }
@@ -23,6 +23,8 @@ export interface ITxMetadataCollection {
23
23
  alreadyFetched(txHash: TxHash): boolean;
24
24
  // Returns true if tx was marked as fetched, false if it was already marked as fetched
25
25
  markPeerHas(peerId: PeerId, txHashes: TxHash[]): void;
26
+ /** Remove all tx metadata associations for a peer (e.g. on demotion from smart to dumb). */
27
+ clearPeerData(peerId: PeerId): void;
26
28
  }
27
29
 
28
30
  /**
@@ -47,7 +49,6 @@ export interface BatchTxRequesterOptions {
47
49
  //Injectable for testing purposes
48
50
  semaphore?: ISemaphore;
49
51
  peerCollection?: IPeerCollection;
50
- abortSignal?: AbortSignal;
51
52
  /** Optional tx validator for testing - if not provided, one is created from p2pService.txValidatorConfig */
52
53
  txValidator?: IBatchRequestTxValidator;
53
54
  }