@aztec/p2p 0.76.4 → 0.77.0-testnet-ignition.21

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 (241) hide show
  1. package/dest/bootstrap/bootstrap.d.ts +2 -2
  2. package/dest/bootstrap/bootstrap.d.ts.map +1 -1
  3. package/dest/bootstrap/bootstrap.js +55 -41
  4. package/dest/client/factory.d.ts +8 -6
  5. package/dest/client/factory.d.ts.map +1 -1
  6. package/dest/client/factory.js +8 -10
  7. package/dest/client/index.js +0 -1
  8. package/dest/client/p2p_client.d.ts +7 -4
  9. package/dest/client/p2p_client.d.ts.map +1 -1
  10. package/dest/client/p2p_client.js +492 -514
  11. package/dest/config.d.ts +8 -10
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +54 -47
  14. package/dest/enr/generate-enr.d.ts +9 -0
  15. package/dest/enr/generate-enr.d.ts.map +1 -0
  16. package/dest/enr/generate-enr.js +30 -0
  17. package/dest/enr/index.d.ts +2 -0
  18. package/dest/enr/index.d.ts.map +1 -0
  19. package/dest/enr/index.js +1 -0
  20. package/dest/errors/reqresp.error.js +6 -10
  21. package/dest/index.js +0 -1
  22. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +1 -1
  23. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/attestation_pool.js +6 -2
  25. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts +1 -1
  26. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +65 -33
  28. package/dest/mem_pools/attestation_pool/index.js +0 -1
  29. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +3 -3
  30. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  31. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +23 -20
  32. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +2 -2
  33. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  34. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +22 -26
  35. package/dest/mem_pools/attestation_pool/mocks.d.ts +3 -2
  36. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  37. package/dest/mem_pools/attestation_pool/mocks.js +12 -7
  38. package/dest/mem_pools/index.d.ts +2 -2
  39. package/dest/mem_pools/index.d.ts.map +1 -1
  40. package/dest/mem_pools/index.js +1 -2
  41. package/dest/mem_pools/instrumentation.d.ts +1 -1
  42. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  43. package/dest/mem_pools/instrumentation.js +35 -39
  44. package/dest/mem_pools/interface.d.ts +3 -3
  45. package/dest/mem_pools/interface.d.ts.map +1 -1
  46. package/dest/mem_pools/interface.js +3 -2
  47. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +2 -2
  48. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +129 -136
  50. package/dest/mem_pools/tx_pool/index.js +0 -1
  51. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +2 -2
  52. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  53. package/dest/mem_pools/tx_pool/memory_tx_pool.js +46 -44
  54. package/dest/mem_pools/tx_pool/priority.d.ts +1 -1
  55. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  56. package/dest/mem_pools/tx_pool/priority.js +1 -3
  57. package/dest/mem_pools/tx_pool/tx_pool.d.ts +1 -1
  58. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  59. package/dest/mem_pools/tx_pool/tx_pool.js +3 -2
  60. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  61. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  62. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +109 -39
  63. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts +2 -2
  64. package/dest/msg_validators/attestation_validator/attestation_validator.d.ts.map +1 -1
  65. package/dest/msg_validators/attestation_validator/attestation_validator.js +4 -4
  66. package/dest/msg_validators/attestation_validator/index.js +0 -1
  67. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts +2 -2
  68. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.d.ts.map +1 -1
  69. package/dest/msg_validators/block_proposal_validator/block_proposal_validator.js +3 -3
  70. package/dest/msg_validators/block_proposal_validator/index.js +0 -1
  71. package/dest/msg_validators/index.js +0 -1
  72. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +1 -1
  73. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  74. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +9 -11
  75. package/dest/msg_validators/tx_validator/block_header_validator.d.ts +2 -2
  76. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  77. package/dest/msg_validators/tx_validator/block_header_validator.js +18 -13
  78. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  79. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  80. package/dest/msg_validators/tx_validator/data_validator.js +102 -33
  81. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts +1 -1
  82. package/dest/msg_validators/tx_validator/double_spend_validator.d.ts.map +1 -1
  83. package/dest/msg_validators/tx_validator/double_spend_validator.js +34 -20
  84. package/dest/msg_validators/tx_validator/index.js +0 -1
  85. package/dest/msg_validators/tx_validator/metadata_validator.d.ts +2 -2
  86. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  87. package/dest/msg_validators/tx_validator/metadata_validator.js +30 -27
  88. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts +2 -1
  89. package/dest/msg_validators/tx_validator/tx_proof_validator.d.ts.map +1 -1
  90. package/dest/msg_validators/tx_validator/tx_proof_validator.js +17 -12
  91. package/dest/services/data_store.js +57 -57
  92. package/dest/services/discv5/discV5_service.d.ts +2 -0
  93. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  94. package/dest/services/discv5/discV5_service.js +64 -36
  95. package/dest/services/dummy_service.d.ts +4 -2
  96. package/dest/services/dummy_service.d.ts.map +1 -1
  97. package/dest/services/dummy_service.js +41 -59
  98. package/dest/services/encoding.d.ts +3 -3
  99. package/dest/services/encoding.d.ts.map +1 -1
  100. package/dest/services/encoding.js +10 -9
  101. package/dest/services/gossipsub/scoring.d.ts +7 -0
  102. package/dest/services/gossipsub/scoring.d.ts.map +1 -0
  103. package/dest/services/gossipsub/scoring.js +10 -0
  104. package/dest/services/index.js +0 -1
  105. package/dest/services/libp2p/libp2p_service.d.ts +10 -33
  106. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  107. package/dest/services/libp2p/libp2p_service.js +682 -673
  108. package/dest/services/peer-manager/metrics.js +14 -7
  109. package/dest/services/peer-manager/peer_manager.d.ts +24 -6
  110. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  111. package/dest/services/peer-manager/peer_manager.js +390 -340
  112. package/dest/services/peer-manager/peer_scoring.d.ts +3 -3
  113. package/dest/services/peer-manager/peer_scoring.d.ts.map +1 -1
  114. package/dest/services/peer-manager/peer_scoring.js +21 -19
  115. package/dest/services/reqresp/config.js +4 -5
  116. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts +2 -2
  117. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.d.ts.map +1 -1
  118. package/dest/services/reqresp/connection-sampler/batch_connection_sampler.js +35 -28
  119. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +1 -1
  120. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  121. package/dest/services/reqresp/connection-sampler/connection_sampler.js +67 -61
  122. package/dest/services/reqresp/index.js +1 -3
  123. package/dest/services/reqresp/interface.d.ts +2 -2
  124. package/dest/services/reqresp/interface.d.ts.map +1 -1
  125. package/dest/services/reqresp/interface.js +27 -31
  126. package/dest/services/reqresp/metrics.d.ts +1 -1
  127. package/dest/services/reqresp/metrics.d.ts.map +1 -1
  128. package/dest/services/reqresp/metrics.js +23 -10
  129. package/dest/services/reqresp/protocols/block.d.ts +2 -2
  130. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  131. package/dest/services/reqresp/protocols/block.js +1 -2
  132. package/dest/services/reqresp/protocols/goodbye.d.ts +5 -5
  133. package/dest/services/reqresp/protocols/goodbye.d.ts.map +1 -1
  134. package/dest/services/reqresp/protocols/goodbye.js +36 -41
  135. package/dest/services/reqresp/protocols/index.js +1 -3
  136. package/dest/services/reqresp/protocols/ping.js +1 -3
  137. package/dest/services/reqresp/protocols/status.js +1 -3
  138. package/dest/services/reqresp/protocols/tx.d.ts +3 -3
  139. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  140. package/dest/services/reqresp/protocols/tx.js +6 -9
  141. package/dest/services/reqresp/rate-limiter/index.js +0 -1
  142. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +9 -9
  143. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  144. package/dest/services/reqresp/rate-limiter/rate_limiter.js +53 -46
  145. package/dest/services/reqresp/rate-limiter/rate_limits.js +16 -17
  146. package/dest/services/reqresp/reqresp.d.ts +4 -4
  147. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  148. package/dest/services/reqresp/reqresp.js +467 -464
  149. package/dest/services/reqresp/status.js +16 -17
  150. package/dest/services/service.d.ts +3 -2
  151. package/dest/services/service.d.ts.map +1 -1
  152. package/dest/services/service.js +3 -4
  153. package/dest/test-helpers/generate-peer-id-private-keys.js +2 -4
  154. package/dest/test-helpers/get-ports.js +3 -3
  155. package/dest/test-helpers/index.js +0 -1
  156. package/dest/test-helpers/make-enrs.d.ts +1 -1
  157. package/dest/test-helpers/make-enrs.d.ts.map +1 -1
  158. package/dest/test-helpers/make-enrs.js +3 -6
  159. package/dest/test-helpers/make-test-p2p-clients.d.ts +7 -6
  160. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  161. package/dest/test-helpers/make-test-p2p-clients.js +10 -12
  162. package/dest/test-helpers/reqresp-nodes.d.ts +18 -7
  163. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  164. package/dest/test-helpers/reqresp-nodes.js +64 -40
  165. package/dest/testbench/p2p_client_testbench_worker.js +61 -45
  166. package/dest/testbench/parse_log_file.d.ts +2 -0
  167. package/dest/testbench/parse_log_file.d.ts.map +1 -0
  168. package/dest/testbench/parse_log_file.js +131 -0
  169. package/dest/testbench/testbench.d.ts +2 -0
  170. package/dest/testbench/testbench.d.ts.map +1 -0
  171. package/dest/testbench/testbench.js +141 -0
  172. package/dest/{services/types.d.ts → types/index.d.ts} +1 -1
  173. package/dest/types/index.d.ts.map +1 -0
  174. package/dest/types/index.js +28 -0
  175. package/dest/util.d.ts +5 -5
  176. package/dest/util.d.ts.map +1 -1
  177. package/dest/util.js +23 -34
  178. package/dest/versioning.d.ts +3 -3
  179. package/dest/versioning.d.ts.map +1 -1
  180. package/dest/versioning.js +7 -12
  181. package/package.json +15 -13
  182. package/src/bootstrap/bootstrap.ts +30 -17
  183. package/src/client/factory.ts +9 -12
  184. package/src/client/p2p_client.ts +13 -24
  185. package/src/config.ts +14 -15
  186. package/src/enr/generate-enr.ts +39 -0
  187. package/src/enr/index.ts +1 -0
  188. package/src/mem_pools/attestation_pool/attestation_pool.ts +1 -1
  189. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +4 -3
  190. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +3 -3
  191. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +2 -2
  192. package/src/mem_pools/attestation_pool/mocks.ts +5 -5
  193. package/src/mem_pools/index.ts +2 -2
  194. package/src/mem_pools/instrumentation.ts +4 -3
  195. package/src/mem_pools/interface.ts +3 -3
  196. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +4 -4
  197. package/src/mem_pools/tx_pool/memory_tx_pool.ts +3 -3
  198. package/src/mem_pools/tx_pool/priority.ts +1 -1
  199. package/src/mem_pools/tx_pool/tx_pool.ts +1 -1
  200. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +4 -3
  201. package/src/msg_validators/attestation_validator/attestation_validator.ts +2 -2
  202. package/src/msg_validators/block_proposal_validator/block_proposal_validator.ts +2 -2
  203. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +1 -1
  204. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  205. package/src/msg_validators/tx_validator/data_validator.ts +57 -4
  206. package/src/msg_validators/tx_validator/double_spend_validator.ts +17 -12
  207. package/src/msg_validators/tx_validator/metadata_validator.ts +2 -2
  208. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -6
  209. package/src/services/discv5/discV5_service.ts +33 -8
  210. package/src/services/dummy_service.ts +4 -2
  211. package/src/services/encoding.ts +3 -3
  212. package/src/services/gossipsub/scoring.ts +13 -0
  213. package/src/services/libp2p/libp2p_service.ts +124 -146
  214. package/src/services/peer-manager/peer_manager.ts +71 -13
  215. package/src/services/peer-manager/peer_scoring.ts +3 -3
  216. package/src/services/reqresp/connection-sampler/batch_connection_sampler.ts +2 -2
  217. package/src/services/reqresp/connection-sampler/connection_sampler.ts +9 -3
  218. package/src/services/reqresp/interface.ts +4 -3
  219. package/src/services/reqresp/metrics.ts +1 -1
  220. package/src/services/reqresp/protocols/block.ts +3 -3
  221. package/src/services/reqresp/protocols/goodbye.ts +7 -7
  222. package/src/services/reqresp/protocols/tx.ts +5 -5
  223. package/src/services/reqresp/rate-limiter/rate_limiter.ts +22 -18
  224. package/src/services/reqresp/reqresp.ts +18 -11
  225. package/src/services/service.ts +3 -2
  226. package/src/test-helpers/make-enrs.ts +1 -1
  227. package/src/test-helpers/make-test-p2p-clients.ts +9 -7
  228. package/src/test-helpers/reqresp-nodes.ts +32 -18
  229. package/src/testbench/p2p_client_testbench_worker.ts +16 -9
  230. package/src/testbench/parse_log_file.ts +175 -0
  231. package/src/testbench/testbench.ts +157 -0
  232. package/src/util.ts +5 -5
  233. package/src/versioning.ts +7 -7
  234. package/dest/services/libp2p/libp2p_logger.d.ts +0 -7
  235. package/dest/services/libp2p/libp2p_logger.d.ts.map +0 -1
  236. package/dest/services/libp2p/libp2p_logger.js +0 -67
  237. package/dest/services/types.d.ts.map +0 -1
  238. package/dest/services/types.js +0 -35
  239. package/src/services/libp2p/libp2p_logger.ts +0 -78
  240. package/src/testbench/scripts/run_testbench.sh +0 -7
  241. /package/src/{services/types.ts → types/index.ts} +0 -0
@@ -1,17 +1,22 @@
1
- import { __esDecorate, __runInitializers } from "tslib";
2
1
  // @attribution: lodestar impl for inspiration
3
- import { PeerErrorSeverity } from '@aztec/circuit-types';
2
+ function _ts_decorate(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ }
4
8
  import { createLogger } from '@aztec/foundation/log';
5
9
  import { executeTimeout } from '@aztec/foundation/timer';
10
+ import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
6
11
  import { Attributes, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
7
12
  import { pipe } from 'it-pipe';
8
- import { CollectiveReqRespTimeoutError, IndividualReqRespTimeoutError, InvalidResponseError, } from '../../errors/reqresp.error.js';
13
+ import { CollectiveReqRespTimeoutError, IndividualReqRespTimeoutError, InvalidResponseError } from '../../errors/reqresp.error.js';
9
14
  import { SnappyTransform } from '../encoding.js';
10
15
  import { BatchConnectionSampler } from './connection-sampler/batch_connection_sampler.js';
11
16
  import { ConnectionSampler } from './connection-sampler/connection_sampler.js';
12
- import { DEFAULT_SUB_PROTOCOL_HANDLERS, DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, subProtocolMap, } from './interface.js';
17
+ import { DEFAULT_SUB_PROTOCOL_HANDLERS, DEFAULT_SUB_PROTOCOL_VALIDATORS, ReqRespSubProtocol, subProtocolMap } from './interface.js';
13
18
  import { ReqRespMetrics } from './metrics.js';
14
- import { RequestResponseRateLimiter } from './rate-limiter/rate_limiter.js';
19
+ import { RateLimitStatus, RequestResponseRateLimiter, prettyPrintRateLimitStatus } from './rate-limiter/rate_limiter.js';
15
20
  import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqRespStatus } from './status.js';
16
21
  /**
17
22
  * The Request Response Service
@@ -26,488 +31,486 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
26
31
  * so they get decompressed in readMessage
27
32
  *
28
33
  * see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-reqresp-domain
29
- */
30
- let ReqResp = (() => {
31
- var _a;
32
- let _instanceExtraInitializers = [];
33
- let _sendBatchRequest_decorators;
34
- let _sendRequestToPeer_decorators;
35
- let _streamHandler_decorators;
36
- return _a = class ReqResp {
37
- constructor(config, libp2p, peerScoring, telemetryClient = getTelemetryClient()) {
38
- this.libp2p = (__runInitializers(this, _instanceExtraInitializers), libp2p);
39
- this.peerScoring = peerScoring;
40
- // Warning, if the `start` function is not called as the parent class constructor, then the default sub protocol handlers will be used ( not good )
41
- this.subProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
42
- this.subProtocolValidators = DEFAULT_SUB_PROTOCOL_VALIDATORS;
43
- this.logger = createLogger('p2p:reqresp');
44
- this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
45
- this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
46
- this.rateLimiter = new RequestResponseRateLimiter(peerScoring);
47
- // Connection sampler is used to sample our connected peers
48
- this.connectionSampler = new ConnectionSampler(libp2p);
49
- this.snappyTransform = new SnappyTransform();
50
- this.metrics = new ReqRespMetrics(telemetryClient);
34
+ */ export class ReqResp {
35
+ libp2p;
36
+ peerScoring;
37
+ logger;
38
+ overallRequestTimeoutMs;
39
+ individualRequestTimeoutMs;
40
+ // Warning, if the `start` function is not called as the parent class constructor, then the default sub protocol handlers will be used ( not good )
41
+ subProtocolHandlers;
42
+ subProtocolValidators;
43
+ connectionSampler;
44
+ rateLimiter;
45
+ snappyTransform;
46
+ metrics;
47
+ constructor(config, libp2p, peerScoring, telemetryClient = getTelemetryClient()){
48
+ this.libp2p = libp2p;
49
+ this.peerScoring = peerScoring;
50
+ this.subProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
51
+ this.subProtocolValidators = DEFAULT_SUB_PROTOCOL_VALIDATORS;
52
+ this.logger = createLogger('p2p:reqresp');
53
+ this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
54
+ this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
55
+ this.rateLimiter = new RequestResponseRateLimiter(peerScoring);
56
+ // Connection sampler is used to sample our connected peers
57
+ this.connectionSampler = new ConnectionSampler(libp2p);
58
+ this.snappyTransform = new SnappyTransform();
59
+ this.metrics = new ReqRespMetrics(telemetryClient);
60
+ }
61
+ get tracer() {
62
+ return this.metrics.tracer;
63
+ }
64
+ /**
65
+ * Start the reqresp service
66
+ */ async start(subProtocolHandlers, subProtocolValidators) {
67
+ this.subProtocolHandlers = subProtocolHandlers;
68
+ this.subProtocolValidators = subProtocolValidators;
69
+ // Register all protocol handlers
70
+ for (const subProtocol of Object.keys(this.subProtocolHandlers)){
71
+ await this.libp2p.handle(subProtocol, (data)=>void this.streamHandler(subProtocol, data).catch((err)=>this.logger.error(`Error on libp2p subprotocol ${subProtocol} handler`, err)));
72
+ }
73
+ this.rateLimiter.start();
74
+ }
75
+ /**
76
+ * Stop the reqresp service
77
+ */ async stop() {
78
+ // Unregister handlers in parallel
79
+ const unregisterPromises = Object.keys(this.subProtocolHandlers).map((protocol)=>this.libp2p.unhandle(protocol));
80
+ await Promise.all(unregisterPromises);
81
+ // Close connection sampler
82
+ await this.connectionSampler.stop();
83
+ this.logger.debug('ReqResp: Connection sampler stopped');
84
+ // Close streams in parallel
85
+ const closeStreamPromises = this.libp2p.getConnections().map((connection)=>connection.close());
86
+ await Promise.all(closeStreamPromises);
87
+ this.logger.debug('ReqResp: All active streams closed');
88
+ this.rateLimiter.stop();
89
+ this.logger.debug('ReqResp: Rate limiter stopped');
90
+ // NOTE: We assume libp2p instance is managed by the caller
91
+ }
92
+ /**
93
+ * Send a request to peers, returns the first response
94
+ *
95
+ * @param subProtocol - The protocol being requested
96
+ * @param request - The request to send
97
+ * @returns - The response from the peer, otherwise undefined
98
+ *
99
+ * @description
100
+ * This method attempts to send a request to all active peers using the specified sub-protocol.
101
+ * It opens a stream with each peer, sends the request, and awaits a response.
102
+ * If a valid response is received, it returns the response; otherwise, it continues to the next peer.
103
+ * If no response is received from any peer, it returns undefined.
104
+ *
105
+ * The method performs the following steps:
106
+ * - Sample a peer to send the request to.
107
+ * - Opens a stream with the peer using the specified sub-protocol.
108
+ *
109
+ * When a response is received, it is validated using the given sub protocols response validator.
110
+ * To see the interface for the response validator - see `interface.ts`
111
+ *
112
+ * Failing a response validation requests in a severe peer penalty, and will
113
+ * prompt the node to continue to search to the next peer.
114
+ * For example, a transaction request validator will check that the payload returned does in fact
115
+ * match the txHash that was requested. A peer that fails this check an only be an extremely naughty peer.
116
+ *
117
+ * This entire operation is wrapped in an overall timeout, that is independent of the
118
+ * peer it is requesting data from.
119
+ *
120
+ */ async sendRequest(subProtocol, request) {
121
+ const responseValidator = this.subProtocolValidators[subProtocol];
122
+ const requestBuffer = request.toBuffer();
123
+ const requestFunction = async ()=>{
124
+ // Attempt to ask all of our peers, but sampled in a random order
125
+ // This function is wrapped in a timeout, so we will exit the loop if we have not received a response
126
+ const numberOfPeers = this.libp2p.getPeers().length;
127
+ if (numberOfPeers === 0) {
128
+ this.logger.debug('No active peers to send requests to');
129
+ return undefined;
51
130
  }
52
- get tracer() {
53
- return this.metrics.tracer;
54
- }
55
- /**
56
- * Start the reqresp service
57
- */
58
- async start(subProtocolHandlers, subProtocolValidators) {
59
- this.subProtocolHandlers = subProtocolHandlers;
60
- this.subProtocolValidators = subProtocolValidators;
61
- // Register all protocol handlers
62
- for (const subProtocol of Object.keys(this.subProtocolHandlers)) {
63
- await this.libp2p.handle(subProtocol, (data) => void this.streamHandler(subProtocol, data).catch(err => this.logger.error(`Error on libp2p subprotocol ${subProtocol} handler`, err)));
131
+ const attemptedPeers = new Map();
132
+ for(let i = 0; i < numberOfPeers; i++){
133
+ // Sample a peer to make a request to
134
+ const peer = this.connectionSampler.getPeer(attemptedPeers);
135
+ this.logger.trace(`Attempting to send request to peer: ${peer?.toString()}`);
136
+ if (!peer) {
137
+ this.logger.debug('No peers available to send requests to');
138
+ return undefined;
139
+ }
140
+ attemptedPeers.set(peer.toString(), true);
141
+ this.logger.trace(`Sending request to peer: ${peer.toString()}`);
142
+ const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffer);
143
+ if (response && response.status !== ReqRespStatus.SUCCESS) {
144
+ this.logger.debug(`Request to peer ${peer.toString()} failed with status ${prettyPrintReqRespStatus(response.status)}`);
145
+ continue;
146
+ }
147
+ // If we get a response, return it, otherwise we iterate onto the next peer
148
+ // We do not consider it a success if we have an empty buffer
149
+ if (response && response.data.length > 0) {
150
+ const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
151
+ // The response validator handles peer punishment within
152
+ const isValid = await responseValidator(request, object, peer);
153
+ if (!isValid) {
154
+ throw new InvalidResponseError();
155
+ }
156
+ return object;
64
157
  }
65
- this.rateLimiter.start();
66
158
  }
67
- /**
68
- * Stop the reqresp service
69
- */
70
- async stop() {
71
- // Unregister handlers in parallel
72
- const unregisterPromises = Object.keys(this.subProtocolHandlers).map(protocol => this.libp2p.unhandle(protocol));
73
- await Promise.all(unregisterPromises);
74
- // Close connection sampler
75
- await this.connectionSampler.stop();
76
- this.logger.debug('ReqResp: Connection sampler stopped');
77
- // Close streams in parallel
78
- const closeStreamPromises = this.libp2p.getConnections().map(connection => connection.close());
79
- await Promise.all(closeStreamPromises);
80
- this.logger.debug('ReqResp: All active streams closed');
81
- this.rateLimiter.stop();
82
- this.logger.debug('ReqResp: Rate limiter stopped');
83
- // NOTE: We assume libp2p instance is managed by the caller
159
+ };
160
+ try {
161
+ return await executeTimeout(requestFunction, this.overallRequestTimeoutMs, ()=>new CollectiveReqRespTimeoutError());
162
+ } catch (e) {
163
+ this.logger.debug(`${e.message} | subProtocol: ${subProtocol}`);
164
+ return undefined;
165
+ }
166
+ }
167
+ /**
168
+ * Request multiple messages over the same sub protocol, balancing the requests across peers.
169
+ *
170
+ * @devnote
171
+ * - The function prioritizes sending requests to free peers using a batch sampling strategy.
172
+ * - If a peer fails to respond or returns an invalid response, it is removed from the sampling pool and replaced.
173
+ * - The function stops retrying once all requests are processed, no active peers remain, or the maximum retry attempts are reached.
174
+ * - Responses are validated using a custom validator for the sub-protocol.*
175
+ *
176
+ * Requests are sent in parallel to each peer, but multiple requests are sent to the same peer in series
177
+ * - If a peer fails to respond or returns an invalid response, it is removed from the sampling pool and replaced.
178
+ * - The function stops retrying once all requests are processed, no active peers remain, or the maximum retry attempts are reached.
179
+ * - Responses are validated using a custom validator for the sub-protocol.*
180
+ *
181
+ * @param subProtocol
182
+ * @param requests
183
+ * @param timeoutMs
184
+ * @param maxPeers
185
+ * @returns
186
+ *
187
+ * @throws {CollectiveReqRespTimeoutError} - If the request batch exceeds the specified timeout (`timeoutMs`).
188
+ */ async sendBatchRequest(subProtocol, requests, timeoutMs = 10000, maxPeers = Math.min(10, requests.length), maxRetryAttempts = 3) {
189
+ const responseValidator = this.subProtocolValidators[subProtocol];
190
+ const responses = new Array(requests.length);
191
+ const requestBuffers = requests.map((req)=>req.toBuffer());
192
+ const requestFunction = async ()=>{
193
+ // Track which requests still need to be processed
194
+ const pendingRequestIndices = new Set(requestBuffers.map((_, i)=>i));
195
+ // Create batch sampler with the total number of requests and max peers
196
+ const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers);
197
+ if (batchSampler.activePeerCount === 0) {
198
+ this.logger.debug('No active peers to send requests to');
199
+ return [];
84
200
  }
85
- /**
86
- * Send a request to peers, returns the first response
87
- *
88
- * @param subProtocol - The protocol being requested
89
- * @param request - The request to send
90
- * @returns - The response from the peer, otherwise undefined
91
- *
92
- * @description
93
- * This method attempts to send a request to all active peers using the specified sub-protocol.
94
- * It opens a stream with each peer, sends the request, and awaits a response.
95
- * If a valid response is received, it returns the response; otherwise, it continues to the next peer.
96
- * If no response is received from any peer, it returns undefined.
97
- *
98
- * The method performs the following steps:
99
- * - Sample a peer to send the request to.
100
- * - Opens a stream with the peer using the specified sub-protocol.
101
- *
102
- * When a response is received, it is validated using the given sub protocols response validator.
103
- * To see the interface for the response validator - see `interface.ts`
104
- *
105
- * Failing a response validation requests in a severe peer penalty, and will
106
- * prompt the node to continue to search to the next peer.
107
- * For example, a transaction request validator will check that the payload returned does in fact
108
- * match the txHash that was requested. A peer that fails this check an only be an extremely naughty peer.
109
- *
110
- * This entire operation is wrapped in an overall timeout, that is independent of the
111
- * peer it is requesting data from.
112
- *
113
- */
114
- async sendRequest(subProtocol, request) {
115
- const responseValidator = this.subProtocolValidators[subProtocol];
116
- const requestBuffer = request.toBuffer();
117
- const requestFunction = async () => {
118
- // Attempt to ask all of our peers, but sampled in a random order
119
- // This function is wrapped in a timeout, so we will exit the loop if we have not received a response
120
- const numberOfPeers = this.libp2p.getPeers().length;
121
- if (numberOfPeers === 0) {
122
- this.logger.debug('No active peers to send requests to');
123
- return undefined;
201
+ // This is where it gets fun
202
+ // The outer loop is the retry loop, we will continue to retry until we process all indices we have
203
+ // not received a response for, or we have reached the max retry attempts
204
+ // The inner loop is the batch loop, we will process all requests for each peer in parallel
205
+ // We will then process the results of the requests, and resample any peers that failed to respond
206
+ // We will continue to retry until we have processed all indices, or we have reached the max retry attempts
207
+ let retryAttempts = 0;
208
+ while(pendingRequestIndices.size > 0 && batchSampler.activePeerCount > 0 && retryAttempts < maxRetryAttempts){
209
+ // Process requests in parallel for each available peer
210
+ const requestBatches = new Map();
211
+ // Group requests by peer
212
+ for (const requestIndex of pendingRequestIndices){
213
+ const peer = batchSampler.getPeerForRequest(requestIndex);
214
+ if (!peer) {
215
+ break;
124
216
  }
125
- const attemptedPeers = new Map();
126
- for (let i = 0; i < numberOfPeers; i++) {
127
- // Sample a peer to make a request to
128
- const peer = this.connectionSampler.getPeer(attemptedPeers);
129
- this.logger.trace(`Attempting to send request to peer: ${peer?.toString()}`);
130
- if (!peer) {
131
- this.logger.debug('No peers available to send requests to');
132
- return undefined;
133
- }
134
- attemptedPeers.set(peer.toString(), true);
135
- this.logger.trace(`Sending request to peer: ${peer.toString()}`);
136
- const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffer);
137
- if (response && response.status !== ReqRespStatus.SUCCESS) {
138
- this.logger.debug(`Request to peer ${peer.toString()} failed with status ${prettyPrintReqRespStatus(response.status)}`);
139
- continue;
140
- }
141
- // If we get a response, return it, otherwise we iterate onto the next peer
142
- // We do not consider it a success if we have an empty buffer
143
- if (response && response.data.length > 0) {
144
- const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
145
- // The response validator handles peer punishment within
146
- const isValid = await responseValidator(request, object, peer);
147
- if (!isValid) {
148
- throw new InvalidResponseError();
149
- }
150
- return object;
151
- }
217
+ if (!requestBatches.has(peer)) {
218
+ requestBatches.set(peer, []);
152
219
  }
153
- };
154
- try {
155
- return await executeTimeout(requestFunction, this.overallRequestTimeoutMs, () => new CollectiveReqRespTimeoutError());
220
+ requestBatches.get(peer).push(requestIndex);
156
221
  }
157
- catch (e) {
158
- this.logger.debug(`${e.message} | subProtocol: ${subProtocol}`);
159
- return undefined;
160
- }
161
- }
162
- /**
163
- * Request multiple messages over the same sub protocol, balancing the requests across peers.
164
- *
165
- * @devnote
166
- * - The function prioritizes sending requests to free peers using a batch sampling strategy.
167
- * - If a peer fails to respond or returns an invalid response, it is removed from the sampling pool and replaced.
168
- * - The function stops retrying once all requests are processed, no active peers remain, or the maximum retry attempts are reached.
169
- * - Responses are validated using a custom validator for the sub-protocol.*
170
- *
171
- * Requests are sent in parallel to each peer, but multiple requests are sent to the same peer in series
172
- * - If a peer fails to respond or returns an invalid response, it is removed from the sampling pool and replaced.
173
- * - The function stops retrying once all requests are processed, no active peers remain, or the maximum retry attempts are reached.
174
- * - Responses are validated using a custom validator for the sub-protocol.*
175
- *
176
- * @param subProtocol
177
- * @param requests
178
- * @param timeoutMs
179
- * @param maxPeers
180
- * @returns
181
- *
182
- * @throws {CollectiveReqRespTimeoutError} - If the request batch exceeds the specified timeout (`timeoutMs`).
183
- */
184
- async sendBatchRequest(subProtocol, requests, timeoutMs = 10000, maxPeers = Math.min(10, requests.length), maxRetryAttempts = 3) {
185
- const responseValidator = this.subProtocolValidators[subProtocol];
186
- const responses = new Array(requests.length);
187
- const requestBuffers = requests.map(req => req.toBuffer());
188
- const requestFunction = async () => {
189
- // Track which requests still need to be processed
190
- const pendingRequestIndices = new Set(requestBuffers.map((_, i) => i));
191
- // Create batch sampler with the total number of requests and max peers
192
- const batchSampler = new BatchConnectionSampler(this.connectionSampler, requests.length, maxPeers);
193
- if (batchSampler.activePeerCount === 0) {
194
- this.logger.debug('No active peers to send requests to');
195
- return [];
196
- }
197
- // This is where it gets fun
198
- // The outer loop is the retry loop, we will continue to retry until we process all indices we have
199
- // not received a response for, or we have reached the max retry attempts
200
- // The inner loop is the batch loop, we will process all requests for each peer in parallel
201
- // We will then process the results of the requests, and resample any peers that failed to respond
202
- // We will continue to retry until we have processed all indices, or we have reached the max retry attempts
203
- let retryAttempts = 0;
204
- while (pendingRequestIndices.size > 0 && batchSampler.activePeerCount > 0 && retryAttempts < maxRetryAttempts) {
205
- // Process requests in parallel for each available peer
206
- const requestBatches = new Map();
207
- // Group requests by peer
208
- for (const requestIndex of pendingRequestIndices) {
209
- const peer = batchSampler.getPeerForRequest(requestIndex);
210
- if (!peer) {
211
- break;
212
- }
213
- if (!requestBatches.has(peer)) {
214
- requestBatches.set(peer, []);
215
- }
216
- requestBatches.get(peer).push(requestIndex);
217
- }
218
- // Make parallel requests for each peer's batch
219
- // A batch entry will look something like this:
220
- // PeerId0: [0, 1, 2, 3]
221
- // PeerId1: [4, 5, 6, 7]
222
- // Peer Id 0 will send requests 0, 1, 2, 3 in serial
223
- // while simultaneously Peer Id 1 will send requests 4, 5, 6, 7 in serial
224
- const batchResults = await Promise.all(Array.from(requestBatches.entries()).map(async ([peer, indices]) => {
225
- try {
226
- // Requests all going to the same peer are sent synchronously
227
- const peerResults = [];
228
- for (const index of indices) {
229
- const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffers[index]);
230
- // Check the status of the response buffer
231
- if (response && response.status !== ReqRespStatus.SUCCESS) {
232
- this.logger.debug(`Request to peer ${peer.toString()} failed with status ${prettyPrintReqRespStatus(response.status)}`);
233
- // If we hit a rate limit or some failure, we remove the peer and return the results,
234
- // they will be split among remaining peers and the new sampled peer
235
- batchSampler.removePeerAndReplace(peer);
236
- return { peer, results: peerResults };
237
- }
238
- if (response && response.data.length > 0) {
239
- const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
240
- const isValid = await responseValidator(requests[index], object, peer);
241
- if (isValid) {
242
- peerResults.push({ index, response: object });
243
- }
244
- }
245
- }
246
- return { peer, results: peerResults };
247
- }
248
- catch (error) {
249
- this.logger.debug(`Failed batch request to peer ${peer.toString()}:`, error);
222
+ // Make parallel requests for each peer's batch
223
+ // A batch entry will look something like this:
224
+ // PeerId0: [0, 1, 2, 3]
225
+ // PeerId1: [4, 5, 6, 7]
226
+ // Peer Id 0 will send requests 0, 1, 2, 3 in serial
227
+ // while simultaneously Peer Id 1 will send requests 4, 5, 6, 7 in serial
228
+ const batchResults = await Promise.all(Array.from(requestBatches.entries()).map(async ([peer, indices])=>{
229
+ try {
230
+ // Requests all going to the same peer are sent synchronously
231
+ const peerResults = [];
232
+ for (const index of indices){
233
+ const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffers[index]);
234
+ // Check the status of the response buffer
235
+ if (response && response.status !== ReqRespStatus.SUCCESS) {
236
+ this.logger.debug(`Request to peer ${peer.toString()} failed with status ${prettyPrintReqRespStatus(response.status)}`);
237
+ // If we hit a rate limit or some failure, we remove the peer and return the results,
238
+ // they will be split among remaining peers and the new sampled peer
250
239
  batchSampler.removePeerAndReplace(peer);
251
- return { peer, results: [] };
240
+ return {
241
+ peer,
242
+ results: peerResults
243
+ };
252
244
  }
253
- }));
254
- // Process results
255
- for (const { results } of batchResults) {
256
- for (const { index, response } of results) {
257
- if (response) {
258
- responses[index] = response;
259
- pendingRequestIndices.delete(index);
245
+ if (response && response.data.length > 0) {
246
+ const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
247
+ const isValid = await responseValidator(requests[index], object, peer);
248
+ if (isValid) {
249
+ peerResults.push({
250
+ index,
251
+ response: object
252
+ });
260
253
  }
261
254
  }
262
255
  }
263
- retryAttempts++;
256
+ return {
257
+ peer,
258
+ results: peerResults
259
+ };
260
+ } catch (error) {
261
+ this.logger.debug(`Failed batch request to peer ${peer.toString()}:`, error);
262
+ batchSampler.removePeerAndReplace(peer);
263
+ return {
264
+ peer,
265
+ results: []
266
+ };
264
267
  }
265
- if (retryAttempts >= maxRetryAttempts) {
266
- this.logger.debug(`Max retry attempts ${maxRetryAttempts} reached for batch request`);
268
+ }));
269
+ // Process results
270
+ for (const { results } of batchResults){
271
+ for (const { index, response } of results){
272
+ if (response) {
273
+ responses[index] = response;
274
+ pendingRequestIndices.delete(index);
275
+ }
267
276
  }
268
- return responses;
269
- };
270
- try {
271
- return await executeTimeout(requestFunction, timeoutMs, () => new CollectiveReqRespTimeoutError());
272
- }
273
- catch (e) {
274
- this.logger.debug(`${e.message} | subProtocol: ${subProtocol}`);
275
- return [];
276
277
  }
278
+ retryAttempts++;
277
279
  }
278
- /**
279
- * Sends a request to a specific peer
280
- *
281
- * We first dial a particular protocol for the peer, this ensures that the peer knows
282
- * what to respond with
283
- *
284
- *
285
- * @param peerId - The peer to send the request to
286
- * @param subProtocol - The protocol to use to request
287
- * @param payload - The payload to send
288
- * @returns If the request is successful, the response is returned, otherwise undefined
289
- *
290
- * @description
291
- * This method attempts to open a stream with the specified peer, send the payload,
292
- * and await a response.
293
- * If an error occurs, it penalizes the peer and returns undefined.
294
- *
295
- * The method performs the following steps:
296
- * - Opens a stream with the peer using the specified sub-protocol.
297
- * - Sends the payload and awaits a response with a timeout.
298
- *
299
- * If the stream is not closed by the dialled peer, and a timeout occurs, then
300
- * the stream is closed on the requester's end and sender (us) updates its peer score
301
- */
302
- async sendRequestToPeer(peerId, subProtocol, payload) {
303
- let stream;
280
+ if (retryAttempts >= maxRetryAttempts) {
281
+ this.logger.debug(`Max retry attempts ${maxRetryAttempts} reached for batch request`);
282
+ }
283
+ return responses;
284
+ };
285
+ try {
286
+ return await executeTimeout(requestFunction, timeoutMs, ()=>new CollectiveReqRespTimeoutError());
287
+ } catch (e) {
288
+ this.logger.debug(`${e.message} | subProtocol: ${subProtocol}`);
289
+ return [];
290
+ }
291
+ }
292
+ /**
293
+ * Sends a request to a specific peer
294
+ *
295
+ * We first dial a particular protocol for the peer, this ensures that the peer knows
296
+ * what to respond with
297
+ *
298
+ *
299
+ * @param peerId - The peer to send the request to
300
+ * @param subProtocol - The protocol to use to request
301
+ * @param payload - The payload to send
302
+ * @returns If the request is successful, the response is returned, otherwise undefined
303
+ *
304
+ * @description
305
+ * This method attempts to open a stream with the specified peer, send the payload,
306
+ * and await a response.
307
+ * If an error occurs, it penalizes the peer and returns undefined.
308
+ *
309
+ * The method performs the following steps:
310
+ * - Opens a stream with the peer using the specified sub-protocol.
311
+ * - Sends the payload and awaits a response with a timeout.
312
+ *
313
+ * If the stream is not closed by the dialled peer, and a timeout occurs, then
314
+ * the stream is closed on the requester's end and sender (us) updates its peer score
315
+ */ async sendRequestToPeer(peerId, subProtocol, payload) {
316
+ let stream;
317
+ try {
318
+ this.metrics.recordRequestSent(subProtocol);
319
+ stream = await this.connectionSampler.dialProtocol(peerId, subProtocol);
320
+ // Open the stream with a timeout
321
+ const result = await executeTimeout(()=>pipe([
322
+ payload
323
+ ], stream, this.readMessage.bind(this)), this.individualRequestTimeoutMs, ()=>new IndividualReqRespTimeoutError());
324
+ return result;
325
+ } catch (e) {
326
+ this.metrics.recordRequestError(subProtocol);
327
+ this.handleResponseError(e, peerId, subProtocol);
328
+ } finally{
329
+ // Only close the stream if we created it
330
+ if (stream) {
304
331
  try {
305
- this.metrics.recordRequestSent(subProtocol);
306
- stream = await this.connectionSampler.dialProtocol(peerId, subProtocol);
307
- // Open the stream with a timeout
308
- const result = await executeTimeout(() => pipe([payload], stream, this.readMessage.bind(this)), this.individualRequestTimeoutMs, () => new IndividualReqRespTimeoutError());
309
- return result;
310
- }
311
- catch (e) {
312
- this.metrics.recordRequestError(subProtocol);
313
- this.handleResponseError(e, peerId, subProtocol);
314
- }
315
- finally {
316
- // Only close the stream if we created it
317
- if (stream) {
318
- try {
319
- await this.connectionSampler.close(stream.id);
320
- }
321
- catch (closeError) {
322
- this.logger.error(`Error closing stream: ${closeError instanceof Error ? closeError.message : 'Unknown error'}`);
323
- }
324
- }
332
+ await this.connectionSampler.close(stream.id);
333
+ } catch (closeError) {
334
+ this.logger.error(`Error closing stream: ${closeError instanceof Error ? closeError.message : 'Unknown error'}`);
325
335
  }
326
336
  }
327
- /**
328
- * Handle a response error
329
- *
330
- * ReqResp errors are punished differently depending on the severity of the offense
331
- *
332
- * @param e - The error
333
- * @param peerId - The peer id
334
- * @param subProtocol - The sub protocol
335
- * @returns If the error is non pubishable, then undefined is returned, otherwise the peer is penalized
336
- */
337
- handleResponseError(e, peerId, subProtocol) {
338
- const severity = this.categorizeError(e, peerId, subProtocol);
339
- if (severity) {
340
- this.peerScoring.penalizePeer(peerId, severity);
337
+ }
338
+ }
339
+ /**
340
+ * Handle a response error
341
+ *
342
+ * ReqResp errors are punished differently depending on the severity of the offense
343
+ *
344
+ * @param e - The error
345
+ * @param peerId - The peer id
346
+ * @param subProtocol - The sub protocol
347
+ * @returns If the error is non pubishable, then undefined is returned, otherwise the peer is penalized
348
+ */ handleResponseError(e, peerId, subProtocol) {
349
+ const severity = this.categorizeError(e, peerId, subProtocol);
350
+ if (severity) {
351
+ this.peerScoring.penalizePeer(peerId, severity);
352
+ }
353
+ }
354
+ /**
355
+ * Categorize the error and log it.
356
+ */ categorizeError(e, peerId, subProtocol) {
357
+ // Non punishable errors - we do not expect a response for goodbye messages
358
+ if (subProtocol === ReqRespSubProtocol.GOODBYE) {
359
+ this.logger.debug('Error encountered on goodbye sub protocol, no penalty', {
360
+ peerId: peerId.toString(),
361
+ subProtocol
362
+ });
363
+ return undefined;
364
+ }
365
+ // We do not punish a collective timeout, as the node triggers this interupt, independent of the peer's behaviour
366
+ const logTags = {
367
+ peerId: peerId.toString(),
368
+ subProtocol
369
+ };
370
+ if (e instanceof CollectiveReqRespTimeoutError || e instanceof InvalidResponseError) {
371
+ this.logger.debug(`Non-punishable error: ${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`, logTags);
372
+ return undefined;
373
+ }
374
+ // Pubishable errors
375
+ // Connection reset errors in the networking stack are punished with high severity
376
+ // it just signals an unreliable peer
377
+ // We assume that the requesting node has a functioning networking stack.
378
+ if (e?.code === 'ECONNRESET' || e?.code === 'EPIPE') {
379
+ this.logger.debug(`Connection reset: ${peerId.toString()}`, logTags);
380
+ return PeerErrorSeverity.HighToleranceError;
381
+ }
382
+ if (e?.code === 'ECONNREFUSED') {
383
+ this.logger.debug(`Connection refused: ${peerId.toString()}`, logTags);
384
+ return PeerErrorSeverity.HighToleranceError;
385
+ }
386
+ // Timeout errors are punished with high tolerance, they can be due to a geogrpahically far away peer or an
387
+ // overloaded peer
388
+ if (e instanceof IndividualReqRespTimeoutError) {
389
+ this.logger.debug(`Timeout error: ${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`, logTags);
390
+ return PeerErrorSeverity.HighToleranceError;
391
+ }
392
+ // Catch all error
393
+ this.logger.error(`Unexpected error sending request to peer`, e, logTags);
394
+ return PeerErrorSeverity.HighToleranceError;
395
+ }
396
+ /**
397
+ * Read a message returned from a stream into a single buffer
398
+ *
399
+ * The message is split into two components
400
+ * - The first chunk should contain a control byte, indicating the status of the response see `ReqRespStatus`
401
+ * - The second chunk should contain the response data
402
+ */ async readMessage(source) {
403
+ let statusBuffer;
404
+ const chunks = [];
405
+ try {
406
+ for await (const chunk of source){
407
+ if (statusBuffer === undefined) {
408
+ const firstChunkBuffer = chunk.subarray();
409
+ statusBuffer = parseStatusChunk(firstChunkBuffer);
410
+ } else {
411
+ chunks.push(chunk.subarray());
341
412
  }
342
413
  }
343
- /**
344
- * Categorize the error and log it.
345
- */
346
- categorizeError(e, peerId, subProtocol) {
347
- // Non punishable errors - we do not expect a response for goodbye messages
348
- if (subProtocol === ReqRespSubProtocol.GOODBYE) {
349
- this.logger.debug('Error encountered on goodbye sub protocol, no penalty', {
350
- peerId: peerId.toString(),
351
- subProtocol,
352
- });
353
- return undefined;
354
- }
355
- // We do not punish a collective timeout, as the node triggers this interupt, independent of the peer's behaviour
356
- const logTags = {
357
- peerId: peerId.toString(),
358
- subProtocol,
359
- };
360
- if (e instanceof CollectiveReqRespTimeoutError || e instanceof InvalidResponseError) {
361
- this.logger.debug(`Non-punishable error: ${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`, logTags);
362
- return undefined;
363
- }
364
- // Pubishable errors
365
- // Connection reset errors in the networking stack are punished with high severity
366
- // it just signals an unreliable peer
367
- // We assume that the requesting node has a functioning networking stack.
368
- if (e?.code === 'ECONNRESET' || e?.code === 'EPIPE') {
369
- this.logger.debug(`Connection reset: ${peerId.toString()}`, logTags);
370
- return PeerErrorSeverity.HighToleranceError;
371
- }
372
- if (e?.code === 'ECONNREFUSED') {
373
- this.logger.debug(`Connection refused: ${peerId.toString()}`, logTags);
374
- return PeerErrorSeverity.HighToleranceError;
375
- }
376
- // Timeout errors are punished with high tolerance, they can be due to a geogrpahically far away peer or an
377
- // overloaded peer
378
- if (e instanceof IndividualReqRespTimeoutError) {
379
- this.logger.debug(`Timeout error: ${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`, logTags);
380
- return PeerErrorSeverity.HighToleranceError;
381
- }
382
- // Catch all error
383
- this.logger.error(`Unexpected error sending request to peer`, e, logTags);
384
- return PeerErrorSeverity.HighToleranceError;
414
+ const messageData = Buffer.concat(chunks);
415
+ const message = this.snappyTransform.inboundTransformNoTopic(messageData);
416
+ return {
417
+ status: statusBuffer ?? ReqRespStatus.UNKNOWN,
418
+ data: message
419
+ };
420
+ } catch (e) {
421
+ this.logger.debug(`Reading message failed: ${e.message}`);
422
+ let status = ReqRespStatus.UNKNOWN;
423
+ if (e instanceof ReqRespStatusError) {
424
+ status = e.status;
385
425
  }
386
- /**
387
- * Read a message returned from a stream into a single buffer
388
- *
389
- * The message is split into two components
390
- * - The first chunk should contain a control byte, indicating the status of the response see `ReqRespStatus`
391
- * - The second chunk should contain the response data
392
- */
393
- async readMessage(source) {
394
- let statusBuffer;
395
- const chunks = [];
396
- try {
397
- for await (const chunk of source) {
398
- if (statusBuffer === undefined) {
399
- const firstChunkBuffer = chunk.subarray();
400
- statusBuffer = parseStatusChunk(firstChunkBuffer);
401
- }
402
- else {
403
- chunks.push(chunk.subarray());
404
- }
405
- }
406
- const messageData = Buffer.concat(chunks);
407
- const message = this.snappyTransform.inboundTransformNoTopic(messageData);
408
- return {
409
- status: statusBuffer ?? ReqRespStatus.UNKNOWN,
410
- data: message,
411
- };
412
- }
413
- catch (e) {
414
- this.logger.debug(`Reading message failed: ${e.message}`);
415
- let status = ReqRespStatus.UNKNOWN;
416
- if (e instanceof ReqRespStatusError) {
417
- status = e.status;
418
- }
419
- return {
420
- status,
421
- data: Buffer.from([]),
422
- };
423
- }
426
+ return {
427
+ status,
428
+ data: Buffer.from([])
429
+ };
430
+ }
431
+ }
432
+ /**
433
+ * Stream Handler
434
+ * Reads the incoming stream, determines the protocol, then triggers the appropriate handler
435
+ *
436
+ * @param param0 - The incoming stream data
437
+ *
438
+ * @description
439
+ * An individual stream handler will be bound to each sub protocol, and handles returning data back
440
+ * to the requesting peer.
441
+ *
442
+ * The sub protocol handler interface is defined within `interface.ts` and will be assigned to the
443
+ * req resp service on start up.
444
+ *
445
+ * We check rate limits for each peer, note the peer will be penalised within the rate limiter implementation
446
+ * if they exceed their peer specific limits.
447
+ */ async streamHandler(protocol, { stream, connection }) {
448
+ this.metrics.recordRequestReceived(protocol);
449
+ try {
450
+ // Store a reference to from this for the async generator
451
+ const rateLimitStatus = this.rateLimiter.allow(protocol, connection.remotePeer);
452
+ if (rateLimitStatus != RateLimitStatus.Allowed) {
453
+ this.logger.warn(`Rate limit exceeded ${prettyPrintRateLimitStatus(rateLimitStatus)} for ${protocol} from ${connection.remotePeer}`);
454
+ throw new ReqRespStatusError(ReqRespStatus.RATE_LIMIT_EXCEEDED);
424
455
  }
425
- /**
426
- * Stream Handler
427
- * Reads the incoming stream, determines the protocol, then triggers the appropriate handler
428
- *
429
- * @param param0 - The incoming stream data
430
- *
431
- * @description
432
- * An individual stream handler will be bound to each sub protocol, and handles returning data back
433
- * to the requesting peer.
434
- *
435
- * The sub protocol handler interface is defined within `interface.ts` and will be assigned to the
436
- * req resp service on start up.
437
- *
438
- * We check rate limits for each peer, note the peer will be penalised within the rate limiter implementation
439
- * if they exceed their peer specific limits.
440
- */
441
- async streamHandler(protocol, { stream, connection }) {
442
- this.metrics.recordRequestReceived(protocol);
443
- try {
444
- // Store a reference to from this for the async generator
445
- if (!this.rateLimiter.allow(protocol, connection.remotePeer)) {
446
- this.logger.warn(`Rate limit exceeded for ${protocol} from ${connection.remotePeer}`);
447
- throw new ReqRespStatusError(ReqRespStatus.RATE_LIMIT_EXCEEDED);
456
+ const handler = this.subProtocolHandlers[protocol];
457
+ const transform = this.snappyTransform;
458
+ await pipe(stream, async function*(source) {
459
+ for await (const chunkList of source){
460
+ const msg = Buffer.from(chunkList.subarray());
461
+ const response = await handler(connection.remotePeer, msg);
462
+ if (protocol === ReqRespSubProtocol.GOODBYE) {
463
+ // Don't respond
464
+ await stream.close();
465
+ return;
448
466
  }
449
- const handler = this.subProtocolHandlers[protocol];
450
- const transform = this.snappyTransform;
451
- this.logger.info(`Stream handler for ${protocol}`);
452
- await pipe(stream, async function* (source) {
453
- for await (const chunkList of source) {
454
- const msg = Buffer.from(chunkList.subarray());
455
- const response = await handler(connection.remotePeer, msg);
456
- if (protocol === ReqRespSubProtocol.GOODBYE) {
457
- // Don't respond
458
- await stream.close();
459
- return;
460
- }
461
- // Send success code first, then the response
462
- const successChunk = Buffer.from([ReqRespStatus.SUCCESS]);
463
- yield new Uint8Array(successChunk);
464
- yield new Uint8Array(transform.outboundTransformNoTopic(response));
465
- }
466
- }, stream);
467
- }
468
- catch (e) {
469
- this.logger.warn('Reqresp Response error: ', e);
470
- this.metrics.recordResponseError(protocol);
471
- // If we receive a known error, we use the error status in the response chunk, otherwise we categorize as unknown
472
- let errorStatus = ReqRespStatus.UNKNOWN;
473
- if (e instanceof ReqRespStatusError) {
474
- errorStatus = e.status;
475
- }
476
- const sendErrorChunk = this.sendErrorChunk(errorStatus);
477
- // Return and yield the response chunk
478
- await pipe(stream, async function* (_source) {
479
- yield* sendErrorChunk;
480
- }, stream);
481
- }
482
- finally {
483
- await stream.close();
467
+ // Send success code first, then the response
468
+ const successChunk = Buffer.from([
469
+ ReqRespStatus.SUCCESS
470
+ ]);
471
+ yield new Uint8Array(successChunk);
472
+ yield new Uint8Array(transform.outboundTransformNoTopic(response));
484
473
  }
474
+ }, stream);
475
+ } catch (e) {
476
+ this.logger.warn('Reqresp Response error: ', e);
477
+ this.metrics.recordResponseError(protocol);
478
+ // If we receive a known error, we use the error status in the response chunk, otherwise we categorize as unknown
479
+ let errorStatus = ReqRespStatus.UNKNOWN;
480
+ if (e instanceof ReqRespStatusError) {
481
+ errorStatus = e.status;
485
482
  }
486
- async *sendErrorChunk(error) {
487
- const errorChunk = Buffer.from([error]);
488
- yield new Uint8Array(errorChunk);
489
- }
490
- },
491
- (() => {
492
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
493
- _sendBatchRequest_decorators = [trackSpan('ReqResp.sendBatchRequest', (subProtocol, requests) => ({
494
- [Attributes.P2P_REQ_RESP_PROTOCOL]: subProtocol,
495
- [Attributes.P2P_REQ_RESP_BATCH_REQUESTS_COUNT]: requests.length,
496
- }))];
497
- _sendRequestToPeer_decorators = [trackSpan('ReqResp.sendRequestToPeer', (peerId, subProtocol, _) => ({
498
- [Attributes.P2P_ID]: peerId.toString(),
499
- [Attributes.P2P_REQ_RESP_PROTOCOL]: subProtocol,
500
- }))];
501
- _streamHandler_decorators = [trackSpan('ReqResp.streamHandler', (protocol, { connection }) => ({
502
- [Attributes.P2P_REQ_RESP_PROTOCOL]: protocol,
503
- [Attributes.P2P_ID]: connection.remotePeer.toString(),
504
- }))];
505
- __esDecorate(_a, null, _sendBatchRequest_decorators, { kind: "method", name: "sendBatchRequest", static: false, private: false, access: { has: obj => "sendBatchRequest" in obj, get: obj => obj.sendBatchRequest }, metadata: _metadata }, null, _instanceExtraInitializers);
506
- __esDecorate(_a, null, _sendRequestToPeer_decorators, { kind: "method", name: "sendRequestToPeer", static: false, private: false, access: { has: obj => "sendRequestToPeer" in obj, get: obj => obj.sendRequestToPeer }, metadata: _metadata }, null, _instanceExtraInitializers);
507
- __esDecorate(_a, null, _streamHandler_decorators, { kind: "method", name: "streamHandler", static: false, private: false, access: { has: obj => "streamHandler" in obj, get: obj => obj.streamHandler }, metadata: _metadata }, null, _instanceExtraInitializers);
508
- if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
509
- })(),
510
- _a;
511
- })();
512
- export { ReqResp };
513
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxcmVzcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9yZXFyZXNwL3JlcXJlc3AudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDhDQUE4QztBQUM5QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RCxPQUFPLEVBQWUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxVQUFVLEVBQXdCLGtCQUFrQixFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRzFHLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFJL0IsT0FBTyxFQUNMLDZCQUE2QixFQUM3Qiw2QkFBNkIsRUFDN0Isb0JBQW9CLEdBQ3JCLE1BQU0sK0JBQStCLENBQUM7QUFDdkMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBR2pELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGtEQUFrRCxDQUFDO0FBQzFGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQy9FLE9BQU8sRUFDTCw2QkFBNkIsRUFDN0IsK0JBQStCLEVBRS9CLGtCQUFrQixFQUlsQixjQUFjLEdBQ2YsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzlDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxhQUFhLEVBQUUsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFNUc7Ozs7Ozs7Ozs7Ozs7R0FhRztJQUNVLE9BQU87Ozs7OztzQkFBUCxPQUFPO1lBaUJsQixZQUNFLE1BQXdCLEVBQ2hC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
483
+ const sendErrorChunk = this.sendErrorChunk(errorStatus);
484
+ // Return and yield the response chunk
485
+ await pipe(stream, async function*(_source) {
486
+ yield* sendErrorChunk;
487
+ }, stream);
488
+ } finally{
489
+ await stream.close();
490
+ }
491
+ }
492
+ async *sendErrorChunk(error) {
493
+ const errorChunk = Buffer.from([
494
+ error
495
+ ]);
496
+ yield new Uint8Array(errorChunk);
497
+ }
498
+ }
499
+ _ts_decorate([
500
+ trackSpan('ReqResp.sendBatchRequest', (subProtocol, requests)=>({
501
+ [Attributes.P2P_REQ_RESP_PROTOCOL]: subProtocol,
502
+ [Attributes.P2P_REQ_RESP_BATCH_REQUESTS_COUNT]: requests.length
503
+ }))
504
+ ], ReqResp.prototype, "sendBatchRequest", null);
505
+ _ts_decorate([
506
+ trackSpan('ReqResp.sendRequestToPeer', (peerId, subProtocol, _)=>({
507
+ [Attributes.P2P_ID]: peerId.toString(),
508
+ [Attributes.P2P_REQ_RESP_PROTOCOL]: subProtocol
509
+ }))
510
+ ], ReqResp.prototype, "sendRequestToPeer", null);
511
+ _ts_decorate([
512
+ trackSpan('ReqResp.streamHandler', (protocol, { connection })=>({
513
+ [Attributes.P2P_REQ_RESP_PROTOCOL]: protocol,
514
+ [Attributes.P2P_ID]: connection.remotePeer.toString()
515
+ }))
516
+ ], ReqResp.prototype, "streamHandler", null);