@aztec/p2p 1.2.1 → 2.0.0-nightly.20250813

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 (221) hide show
  1. package/dest/client/factory.d.ts +5 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +29 -12
  4. package/dest/client/interface.d.ts +8 -13
  5. package/dest/client/interface.d.ts.map +1 -1
  6. package/dest/client/p2p_client.d.ts +18 -22
  7. package/dest/client/p2p_client.d.ts.map +1 -1
  8. package/dest/client/p2p_client.js +86 -83
  9. package/dest/config.d.ts +30 -1
  10. package/dest/config.d.ts.map +1 -1
  11. package/dest/config.js +34 -1
  12. package/dest/index.d.ts +1 -0
  13. package/dest/index.d.ts.map +1 -1
  14. package/dest/index.js +1 -0
  15. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +13 -1
  16. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  17. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.d.ts.map +1 -1
  18. package/dest/mem_pools/attestation_pool/attestation_pool_test_suite.js +117 -10
  19. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts +4 -1
  20. package/dest/mem_pools/attestation_pool/kv_attestation_pool.d.ts.map +1 -1
  21. package/dest/mem_pools/attestation_pool/kv_attestation_pool.js +22 -1
  22. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts +4 -1
  23. package/dest/mem_pools/attestation_pool/memory_attestation_pool.d.ts.map +1 -1
  24. package/dest/mem_pools/attestation_pool/memory_attestation_pool.js +21 -1
  25. package/dest/mem_pools/attestation_pool/mocks.d.ts +1 -2
  26. package/dest/mem_pools/attestation_pool/mocks.d.ts.map +1 -1
  27. package/dest/mem_pools/attestation_pool/mocks.js +2 -10
  28. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts +8 -3
  29. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.d.ts.map +1 -1
  30. package/dest/mem_pools/tx_pool/aztec_kv_tx_pool.js +64 -37
  31. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts +8 -3
  32. package/dest/mem_pools/tx_pool/memory_tx_pool.d.ts.map +1 -1
  33. package/dest/mem_pools/tx_pool/memory_tx_pool.js +18 -10
  34. package/dest/mem_pools/tx_pool/tx_pool.d.ts +11 -2
  35. package/dest/mem_pools/tx_pool/tx_pool.d.ts.map +1 -1
  36. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +73 -44
  38. package/dest/msg_validators/attestation_validator/attestation_validator.js +1 -1
  39. package/dest/msg_validators/tx_validator/block_header_validator.d.ts.map +1 -1
  40. package/dest/msg_validators/tx_validator/block_header_validator.js +2 -2
  41. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  42. package/dest/msg_validators/tx_validator/data_validator.js +35 -59
  43. package/dest/msg_validators/tx_validator/double_spend_validator.js +2 -2
  44. package/dest/msg_validators/tx_validator/gas_validator.js +4 -4
  45. package/dest/msg_validators/tx_validator/metadata_validator.d.ts.map +1 -1
  46. package/dest/msg_validators/tx_validator/metadata_validator.js +21 -21
  47. package/dest/msg_validators/tx_validator/phases_validator.js +3 -3
  48. package/dest/msg_validators/tx_validator/tx_proof_validator.js +3 -3
  49. package/dest/services/discv5/discV5_service.d.ts.map +1 -1
  50. package/dest/services/discv5/discV5_service.js +4 -1
  51. package/dest/services/dummy_service.d.ts +13 -3
  52. package/dest/services/dummy_service.d.ts.map +1 -1
  53. package/dest/services/dummy_service.js +26 -3
  54. package/dest/services/index.d.ts +3 -1
  55. package/dest/services/index.d.ts.map +1 -1
  56. package/dest/services/index.js +3 -1
  57. package/dest/services/libp2p/libp2p_service.d.ts +13 -20
  58. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  59. package/dest/services/libp2p/libp2p_service.js +123 -46
  60. package/dest/services/peer-manager/interface.d.ts +8 -1
  61. package/dest/services/peer-manager/interface.d.ts.map +1 -1
  62. package/dest/services/peer-manager/peer_manager.d.ts +70 -3
  63. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  64. package/dest/services/peer-manager/peer_manager.js +369 -39
  65. package/dest/services/reqresp/config.d.ts +3 -3
  66. package/dest/services/reqresp/config.d.ts.map +1 -1
  67. package/dest/services/reqresp/config.js +3 -3
  68. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts +3 -4
  69. package/dest/services/reqresp/connection-sampler/connection_sampler.d.ts.map +1 -1
  70. package/dest/services/reqresp/connection-sampler/connection_sampler.js +35 -52
  71. package/dest/services/reqresp/index.d.ts +2 -1
  72. package/dest/services/reqresp/index.d.ts.map +1 -1
  73. package/dest/services/reqresp/index.js +2 -1
  74. package/dest/services/reqresp/interface.d.ts +61 -10
  75. package/dest/services/reqresp/interface.d.ts.map +1 -1
  76. package/dest/services/reqresp/interface.js +41 -6
  77. package/dest/services/reqresp/protocols/auth.d.ts +43 -0
  78. package/dest/services/reqresp/protocols/auth.d.ts.map +1 -0
  79. package/dest/services/reqresp/protocols/auth.js +71 -0
  80. package/dest/services/reqresp/protocols/block.d.ts +5 -0
  81. package/dest/services/reqresp/protocols/block.d.ts.map +1 -1
  82. package/dest/services/reqresp/protocols/block.js +28 -5
  83. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts +30 -0
  84. package/dest/services/reqresp/protocols/block_txs/bitvector.d.ts.map +1 -0
  85. package/dest/services/reqresp/protocols/block_txs/bitvector.js +75 -0
  86. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts +11 -0
  87. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.d.ts.map +1 -0
  88. package/dest/services/reqresp/protocols/block_txs/block_txs_handler.js +39 -0
  89. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts +49 -0
  90. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.d.ts.map +1 -0
  91. package/dest/services/reqresp/protocols/block_txs/block_txs_reqresp.js +75 -0
  92. package/dest/services/reqresp/protocols/block_txs/index.d.ts +4 -0
  93. package/dest/services/reqresp/protocols/block_txs/index.d.ts.map +1 -0
  94. package/dest/services/reqresp/protocols/block_txs/index.js +3 -0
  95. package/dest/services/reqresp/protocols/goodbye.js +3 -5
  96. package/dest/services/reqresp/protocols/index.d.ts +2 -0
  97. package/dest/services/reqresp/protocols/index.d.ts.map +1 -1
  98. package/dest/services/reqresp/protocols/index.js +2 -0
  99. package/dest/services/reqresp/protocols/status.d.ts +2 -0
  100. package/dest/services/reqresp/protocols/status.d.ts.map +1 -1
  101. package/dest/services/reqresp/protocols/status.js +7 -0
  102. package/dest/services/reqresp/protocols/tx.d.ts +12 -1
  103. package/dest/services/reqresp/protocols/tx.d.ts.map +1 -1
  104. package/dest/services/reqresp/protocols/tx.js +34 -6
  105. package/dest/services/reqresp/rate-limiter/rate_limits.d.ts.map +1 -1
  106. package/dest/services/reqresp/rate-limiter/rate_limits.js +20 -0
  107. package/dest/services/reqresp/reqresp.d.ts +37 -39
  108. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  109. package/dest/services/reqresp/reqresp.js +220 -220
  110. package/dest/services/reqresp/status.d.ts +8 -3
  111. package/dest/services/reqresp/status.d.ts.map +1 -1
  112. package/dest/services/reqresp/status.js +6 -2
  113. package/dest/services/service.d.ts +10 -10
  114. package/dest/services/service.d.ts.map +1 -1
  115. package/dest/services/tx_collection/config.d.ts +25 -0
  116. package/dest/services/tx_collection/config.d.ts.map +1 -0
  117. package/dest/services/tx_collection/config.js +58 -0
  118. package/dest/services/tx_collection/fast_tx_collection.d.ts +56 -0
  119. package/dest/services/tx_collection/fast_tx_collection.d.ts.map +1 -0
  120. package/dest/services/tx_collection/fast_tx_collection.js +295 -0
  121. package/dest/services/tx_collection/index.d.ts +3 -0
  122. package/dest/services/tx_collection/index.d.ts.map +1 -0
  123. package/dest/services/tx_collection/index.js +2 -0
  124. package/dest/services/tx_collection/instrumentation.d.ts +10 -0
  125. package/dest/services/tx_collection/instrumentation.d.ts.map +1 -0
  126. package/dest/services/tx_collection/instrumentation.js +34 -0
  127. package/dest/services/tx_collection/slow_tx_collection.d.ts +54 -0
  128. package/dest/services/tx_collection/slow_tx_collection.d.ts.map +1 -0
  129. package/dest/services/tx_collection/slow_tx_collection.js +176 -0
  130. package/dest/services/tx_collection/tx_collection.d.ts +109 -0
  131. package/dest/services/tx_collection/tx_collection.d.ts.map +1 -0
  132. package/dest/services/tx_collection/tx_collection.js +127 -0
  133. package/dest/services/tx_collection/tx_collection_sink.d.ts +30 -0
  134. package/dest/services/tx_collection/tx_collection_sink.d.ts.map +1 -0
  135. package/dest/services/tx_collection/tx_collection_sink.js +81 -0
  136. package/dest/services/tx_collection/tx_source.d.ts +18 -0
  137. package/dest/services/tx_collection/tx_source.d.ts.map +1 -0
  138. package/dest/services/tx_collection/tx_source.js +31 -0
  139. package/dest/services/tx_provider.d.ts +49 -0
  140. package/dest/services/tx_provider.d.ts.map +1 -0
  141. package/dest/services/tx_provider.js +206 -0
  142. package/dest/services/{tx_collect_instrumentation.d.ts → tx_provider_instrumentation.d.ts} +2 -2
  143. package/dest/services/tx_provider_instrumentation.d.ts.map +1 -0
  144. package/dest/services/{tx_collect_instrumentation.js → tx_provider_instrumentation.js} +5 -5
  145. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  146. package/dest/test-helpers/make-test-p2p-clients.js +4 -3
  147. package/dest/test-helpers/mock-pubsub.d.ts +2 -1
  148. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  149. package/dest/test-helpers/mock-pubsub.js +2 -1
  150. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  151. package/dest/test-helpers/reqresp-nodes.js +8 -4
  152. package/dest/testbench/p2p_client_testbench_worker.js +11 -5
  153. package/dest/util.d.ts +1 -1
  154. package/dest/util.d.ts.map +1 -1
  155. package/package.json +14 -15
  156. package/src/client/factory.ts +87 -12
  157. package/src/client/interface.ts +19 -15
  158. package/src/client/p2p_client.ts +108 -92
  159. package/src/config.ts +52 -1
  160. package/src/index.ts +1 -0
  161. package/src/mem_pools/attestation_pool/attestation_pool.ts +15 -1
  162. package/src/mem_pools/attestation_pool/attestation_pool_test_suite.ts +155 -4
  163. package/src/mem_pools/attestation_pool/kv_attestation_pool.ts +28 -1
  164. package/src/mem_pools/attestation_pool/memory_attestation_pool.ts +28 -2
  165. package/src/mem_pools/attestation_pool/mocks.ts +1 -3
  166. package/src/mem_pools/tx_pool/aztec_kv_tx_pool.ts +59 -41
  167. package/src/mem_pools/tx_pool/memory_tx_pool.ts +19 -9
  168. package/src/mem_pools/tx_pool/tx_pool.ts +7 -2
  169. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +63 -40
  170. package/src/msg_validators/attestation_validator/attestation_validator.ts +1 -1
  171. package/src/msg_validators/tx_validator/block_header_validator.ts +2 -2
  172. package/src/msg_validators/tx_validator/data_validator.ts +36 -27
  173. package/src/msg_validators/tx_validator/double_spend_validator.ts +2 -2
  174. package/src/msg_validators/tx_validator/gas_validator.ts +4 -4
  175. package/src/msg_validators/tx_validator/metadata_validator.ts +22 -28
  176. package/src/msg_validators/tx_validator/phases_validator.ts +2 -2
  177. package/src/msg_validators/tx_validator/tx_proof_validator.ts +2 -2
  178. package/src/services/discv5/discV5_service.ts +4 -1
  179. package/src/services/dummy_service.ts +44 -4
  180. package/src/services/index.ts +3 -1
  181. package/src/services/libp2p/libp2p_service.ts +147 -55
  182. package/src/services/peer-manager/interface.ts +10 -1
  183. package/src/services/peer-manager/peer_manager.ts +441 -41
  184. package/src/services/reqresp/config.ts +3 -3
  185. package/src/services/reqresp/connection-sampler/connection_sampler.ts +38 -63
  186. package/src/services/reqresp/index.ts +2 -0
  187. package/src/services/reqresp/interface.ts +63 -17
  188. package/src/services/reqresp/protocols/auth.ts +83 -0
  189. package/src/services/reqresp/protocols/block.ts +24 -3
  190. package/src/services/reqresp/protocols/block_txs/bitvector.ts +90 -0
  191. package/src/services/reqresp/protocols/block_txs/block_txs_handler.ts +53 -0
  192. package/src/services/reqresp/protocols/block_txs/block_txs_reqresp.ts +79 -0
  193. package/src/services/reqresp/protocols/block_txs/index.ts +3 -0
  194. package/src/services/reqresp/protocols/goodbye.ts +3 -3
  195. package/src/services/reqresp/protocols/index.ts +2 -0
  196. package/src/services/reqresp/protocols/status.ts +20 -0
  197. package/src/services/reqresp/protocols/tx.ts +35 -6
  198. package/src/services/reqresp/rate-limiter/rate_limits.ts +20 -0
  199. package/src/services/reqresp/reqresp.ts +294 -264
  200. package/src/services/reqresp/status.ts +9 -3
  201. package/src/services/service.ts +23 -14
  202. package/src/services/tx_collection/config.ts +84 -0
  203. package/src/services/tx_collection/fast_tx_collection.ts +338 -0
  204. package/src/services/tx_collection/index.ts +2 -0
  205. package/src/services/tx_collection/instrumentation.ts +43 -0
  206. package/src/services/tx_collection/slow_tx_collection.ts +232 -0
  207. package/src/services/tx_collection/tx_collection.ts +214 -0
  208. package/src/services/tx_collection/tx_collection_sink.ts +98 -0
  209. package/src/services/tx_collection/tx_source.ts +37 -0
  210. package/src/services/tx_provider.ts +215 -0
  211. package/src/services/{tx_collect_instrumentation.ts → tx_provider_instrumentation.ts} +5 -5
  212. package/src/test-helpers/make-test-p2p-clients.ts +4 -2
  213. package/src/test-helpers/mock-pubsub.ts +1 -0
  214. package/src/test-helpers/reqresp-nodes.ts +7 -1
  215. package/src/testbench/p2p_client_testbench_worker.ts +9 -2
  216. package/src/util.ts +1 -1
  217. package/dest/services/tx_collect_instrumentation.d.ts.map +0 -1
  218. package/dest/services/tx_collector.d.ts +0 -23
  219. package/dest/services/tx_collector.d.ts.map +0 -1
  220. package/dest/services/tx_collector.js +0 -95
  221. package/src/services/tx_collector.ts +0 -134
@@ -7,9 +7,8 @@ import { PeerErrorSeverity } from '@aztec/stdlib/p2p';
7
7
  import { Attributes, type TelemetryClient, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
8
8
 
9
9
  import type { IncomingStreamData, PeerId, Stream } from '@libp2p/interface';
10
- import { abortableDuplex, abortableSink } from 'abortable-iterator';
11
- import { pipe } from 'it-pipe';
12
10
  import type { Libp2p } from 'libp2p';
11
+ import { pipeline } from 'node:stream/promises';
13
12
  import type { Uint8ArrayList } from 'uint8arraylist';
14
13
 
15
14
  import {
@@ -21,7 +20,6 @@ import { SnappyTransform } from '../encoding.js';
21
20
  import type { PeerScoring } from '../peer-manager/peer_scoring.js';
22
21
  import {
23
22
  DEFAULT_INDIVIDUAL_REQUEST_TIMEOUT_MS,
24
- DEFAULT_OVERALL_REQUEST_TIMEOUT_MS,
25
23
  DEFAULT_REQRESP_DIAL_TIMEOUT_MS,
26
24
  type P2PReqRespConfig,
27
25
  } from './config.js';
@@ -33,11 +31,12 @@ import {
33
31
  type ReqRespInterface,
34
32
  type ReqRespResponse,
35
33
  ReqRespSubProtocol,
34
+ type ReqRespSubProtocolHandler,
36
35
  type ReqRespSubProtocolHandlers,
37
36
  type ReqRespSubProtocolRateLimits,
38
37
  type ReqRespSubProtocolValidators,
39
38
  type SubProtocolMap,
40
- subProtocolMap,
39
+ responseFromBuffer,
41
40
  } from './interface.js';
42
41
  import { ReqRespMetrics } from './metrics.js';
43
42
  import {
@@ -62,7 +61,6 @@ import { ReqRespStatus, ReqRespStatusError, parseStatusChunk, prettyPrintReqResp
62
61
  * see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-reqresp-domain
63
62
  */
64
63
  export class ReqResp implements ReqRespInterface {
65
- private overallRequestTimeoutMs: number = DEFAULT_OVERALL_REQUEST_TIMEOUT_MS;
66
64
  private individualRequestTimeoutMs: number = DEFAULT_INDIVIDUAL_REQUEST_TIMEOUT_MS;
67
65
  private dialTimeoutMs: number = DEFAULT_REQRESP_DIAL_TIMEOUT_MS;
68
66
 
@@ -102,10 +100,6 @@ export class ReqResp implements ReqRespInterface {
102
100
  }
103
101
 
104
102
  public updateConfig(config: Partial<P2PReqRespConfig>): void {
105
- if (typeof config.overallRequestTimeoutMs === 'number') {
106
- this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
107
- }
108
-
109
103
  if (typeof config.individualRequestTimeoutMs === 'number') {
110
104
  this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
111
105
  }
@@ -139,6 +133,22 @@ export class ReqResp implements ReqRespInterface {
139
133
  this.rateLimiter.start();
140
134
  }
141
135
 
136
+ async addSubProtocol(
137
+ subProtocol: ReqRespSubProtocol,
138
+ handler: ReqRespSubProtocolHandler,
139
+ validator: ReqRespSubProtocolValidators[ReqRespSubProtocol] = DEFAULT_SUB_PROTOCOL_VALIDATORS[subProtocol],
140
+ ): Promise<void> {
141
+ this.subProtocolHandlers[subProtocol] = handler;
142
+ this.subProtocolValidators[subProtocol] = validator;
143
+ await this.libp2p.handle(
144
+ subProtocol,
145
+ (data: IncomingStreamData) =>
146
+ void this.streamHandler(subProtocol as ReqRespSubProtocol, data).catch(err =>
147
+ this.logger.error(`Error on libp2p subprotocol ${subProtocol} handler`, err),
148
+ ),
149
+ );
150
+ }
151
+
142
152
  /**
143
153
  * Stop the reqresp service
144
154
  */
@@ -162,103 +172,6 @@ export class ReqResp implements ReqRespInterface {
162
172
  // NOTE: We assume libp2p instance is managed by the caller
163
173
  }
164
174
 
165
- /**
166
- * Send a request to peers, returns the first response
167
- *
168
- * @param subProtocol - The protocol being requested
169
- * @param request - The request to send
170
- * @returns - The response from the peer, otherwise undefined
171
- *
172
- * @description
173
- * This method attempts to send a request to all active peers using the specified sub-protocol.
174
- * It opens a stream with each peer, sends the request, and awaits a response.
175
- * If a valid response is received, it returns the response; otherwise, it continues to the next peer.
176
- * If no response is received from any peer, it returns undefined.
177
- *
178
- * The method performs the following steps:
179
- * - Sample a peer to send the request to.
180
- * - Opens a stream with the peer using the specified sub-protocol.
181
- *
182
- * When a response is received, it is validated using the given sub protocols response validator.
183
- * To see the interface for the response validator - see `interface.ts`
184
- *
185
- * Failing a response validation requests in a severe peer penalty, and will
186
- * prompt the node to continue to search to the next peer.
187
- * For example, a transaction request validator will check that the payload returned does in fact
188
- * match the txHash that was requested. A peer that fails this check an only be an extremely naughty peer.
189
- *
190
- * This entire operation is wrapped in an overall timeout, that is independent of the
191
- * peer it is requesting data from.
192
- *
193
- */
194
- async sendRequest<SubProtocol extends ReqRespSubProtocol>(
195
- subProtocol: SubProtocol,
196
- request: InstanceType<SubProtocolMap[SubProtocol]['request']>,
197
- ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined> {
198
- const responseValidator = this.subProtocolValidators[subProtocol];
199
- const requestBuffer = request.toBuffer();
200
-
201
- const requestFunction = async (signal: AbortSignal) => {
202
- // Attempt to ask all of our peers, but sampled in a random order
203
- // This function is wrapped in a timeout, so we will exit the loop if we have not received a response
204
- const numberOfPeers = this.libp2p.getPeers().length;
205
-
206
- if (numberOfPeers === 0) {
207
- this.logger.debug('No active peers to send requests to');
208
- return undefined;
209
- }
210
-
211
- const attemptedPeers: Map<string, boolean> = new Map();
212
- for (let i = 0; i < numberOfPeers; i++) {
213
- if (signal.aborted) {
214
- throw new AbortError('Request has been aborted');
215
- }
216
- // Sample a peer to make a request to
217
- const peer = this.connectionSampler.getPeer(attemptedPeers);
218
- this.logger.trace(`Attempting to send request to peer: ${peer?.toString()}`);
219
- if (!peer) {
220
- this.logger.debug('No peers available to send requests to');
221
- return undefined;
222
- }
223
-
224
- attemptedPeers.set(peer.toString(), true);
225
-
226
- this.logger.trace(`Sending request to peer: ${peer.toString()}`);
227
- const response = await this.sendRequestToPeer(peer, subProtocol, requestBuffer);
228
-
229
- if (response.status !== ReqRespStatus.SUCCESS) {
230
- this.logger.debug(
231
- `Request to peer ${peer.toString()} failed with status ${prettyPrintReqRespStatus(response.status)}`,
232
- );
233
- continue;
234
- }
235
-
236
- // If we get a response, return it, otherwise we iterate onto the next peer
237
- // We do not consider it a success if we have an empty buffer
238
- if (response && response.data.length > 0) {
239
- const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
240
- // The response validator handles peer punishment within
241
- const isValid = await responseValidator(request, object, peer);
242
- if (!isValid) {
243
- throw new InvalidResponseError();
244
- }
245
- return object;
246
- }
247
- }
248
- };
249
-
250
- try {
251
- return await executeTimeout<InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined>(
252
- requestFunction,
253
- this.overallRequestTimeoutMs,
254
- () => new CollectiveReqRespTimeoutError(),
255
- );
256
- } catch (e: any) {
257
- this.logger.debug(`${e.message} | subProtocol: ${subProtocol}`);
258
- return undefined;
259
- }
260
- }
261
-
262
175
  /**
263
176
  * Request multiple messages over the same sub protocol, balancing the requests across peers.
264
177
  *
@@ -295,9 +208,9 @@ export class ReqResp implements ReqRespInterface {
295
208
  timeoutMs = 10000,
296
209
  maxPeers = Math.max(10, Math.ceil(requests.length / 3)),
297
210
  maxRetryAttempts = 3,
298
- ): Promise<(InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined)[]> {
211
+ ): Promise<InstanceType<SubProtocolMap[SubProtocol]['response']>[]> {
299
212
  const responseValidator = this.subProtocolValidators[subProtocol];
300
- const responses: (InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined)[] = new Array(requests.length);
213
+ const responses: InstanceType<SubProtocolMap[SubProtocol]['response']>[] = new Array(requests.length);
301
214
  const requestBuffers = requests.map(req => req.toBuffer());
302
215
 
303
216
  const requestFunction = async (signal: AbortSignal) => {
@@ -389,7 +302,7 @@ export class ReqResp implements ReqRespInterface {
389
302
  }
390
303
 
391
304
  if (response && response.data.length > 0) {
392
- const object = subProtocolMap[subProtocol].response.fromBuffer(response.data);
305
+ const object = responseFromBuffer(subProtocol, response.data);
393
306
  const isValid = await responseValidator(requests[index], object, peer);
394
307
 
395
308
  if (isValid) {
@@ -428,7 +341,7 @@ export class ReqResp implements ReqRespInterface {
428
341
  };
429
342
 
430
343
  try {
431
- return await executeTimeout<(InstanceType<SubProtocolMap[SubProtocol]['response']> | undefined)[]>(
344
+ return await executeTimeout<InstanceType<SubProtocolMap[SubProtocol]['response']>[]>(
432
345
  requestFunction,
433
346
  timeoutMs,
434
347
  () => new CollectiveReqRespTimeoutError(),
@@ -484,24 +397,34 @@ export class ReqResp implements ReqRespInterface {
484
397
  `Opened stream ${stream.id} for sending request to peer ${peerId.toString()} on sub protocol ${subProtocol}`,
485
398
  );
486
399
 
487
- // Open the stream with a timeout
488
- const result = await executeTimeout<ReqRespResponse>(
489
- (signal): Promise<ReqRespResponse> =>
490
- pipe([payload], abortableDuplex(stream!, signal), abortableSink(this.readMessage.bind(this), signal)),
400
+ const timeoutErr = new IndividualReqRespTimeoutError();
401
+ const [_, resp] = await executeTimeout(
402
+ signal =>
403
+ Promise.all([
404
+ pipeline([payload], stream!.sink, { signal }),
405
+ pipeline(stream!.source, this.readMessage.bind(this), { signal }),
406
+ ]),
491
407
  this.individualRequestTimeoutMs,
492
- () => new IndividualReqRespTimeoutError(),
408
+ () => timeoutErr,
493
409
  );
494
-
495
- return result;
410
+ return resp;
496
411
  } catch (e: any) {
412
+ // On error we immediately abort the stream, this is preferred way,
413
+ // because it signals to the sender that error happened, whereas
414
+ // closing the stream only closes our side and is much slower
415
+ if (stream) {
416
+ stream!.abort(e);
417
+ }
418
+
497
419
  this.metrics.recordRequestError(subProtocol);
498
420
  this.handleResponseError(e, peerId, subProtocol);
499
421
 
500
422
  // If there is an exception, we return an unknown response
501
423
  this.logger.debug(`Error sending request to peer ${peerId.toString()} on sub protocol ${subProtocol}: ${e}`);
502
- return { status: ReqRespStatus.FAILURE, data: Buffer.from([]) };
424
+ return { status: ReqRespStatus.FAILURE };
503
425
  } finally {
504
426
  // Only close the stream if we created it
427
+ // Note even if we aborted the stream, calling close on it is ok, it's just a no-op
505
428
  if (stream) {
506
429
  try {
507
430
  this.logger.trace(
@@ -528,80 +451,12 @@ export class ReqResp implements ReqRespInterface {
528
451
  * @returns If the error is non pubishable, then undefined is returned, otherwise the peer is penalized
529
452
  */
530
453
  private handleResponseError(e: any, peerId: PeerId, subProtocol: ReqRespSubProtocol): void {
531
- const severity = this.categorizeError(e, peerId, subProtocol);
454
+ const severity = this.categorizeResponseError(e, peerId, subProtocol);
532
455
  if (severity) {
533
456
  this.peerScoring.penalizePeer(peerId, severity);
534
457
  }
535
458
  }
536
459
 
537
- /**
538
- * Categorize the error and log it.
539
- */
540
- private categorizeError(e: any, peerId: PeerId, subProtocol: ReqRespSubProtocol): PeerErrorSeverity | undefined {
541
- const logTags = { peerId: peerId.toString(), subProtocol };
542
-
543
- // Non punishable errors - we do not expect a response for goodbye messages
544
- if (subProtocol === ReqRespSubProtocol.GOODBYE) {
545
- this.logger.debug('Error encountered on goodbye sub protocol, no penalty', logTags);
546
- return undefined;
547
- }
548
-
549
- // We do not punish a collective timeout, as the node triggers this interupt, independent of the peer's behaviour
550
- if (e instanceof CollectiveReqRespTimeoutError || e instanceof InvalidResponseError) {
551
- this.logger.debug(`Non-punishable error in ${subProtocol}: ${e.message}`, logTags);
552
- return undefined;
553
- }
554
-
555
- // Do not punish if we are stopping the service
556
- if (e && (e instanceof AbortError || e.code === 'ABORT_ERR')) {
557
- this.logger.debug(`Request aborted: ${e.message}`, logTags);
558
- return undefined;
559
- }
560
-
561
- // Do not punish if we are the ones closing the connection
562
- if (
563
- e?.code === 'ERR_CONNECTION_BEING_CLOSED' ||
564
- e?.code === 'ERR_CONNECTION_CLOSED' ||
565
- e?.code === 'ERR_TRANSIENT_CONNECTION' ||
566
- e?.message?.includes('Muxer already closed')
567
- ) {
568
- this.logger.debug(
569
- `Connection closed to peer from our side: ${peerId.toString()} (${e?.message ?? 'missing error message'})`,
570
- logTags,
571
- );
572
- return undefined;
573
- }
574
-
575
- // Pubishable errors
576
- // Connection reset errors in the networking stack are punished with high severity
577
- // it just signals an unreliable peer
578
- // We assume that the requesting node has a functioning networking stack.
579
- if (e?.code === 'ECONNRESET' || e?.code === 'EPIPE') {
580
- this.logger.debug(`Connection reset: ${peerId.toString()}`, logTags);
581
- return PeerErrorSeverity.HighToleranceError;
582
- }
583
-
584
- if (e?.code === 'ECONNREFUSED') {
585
- this.logger.debug(`Connection refused: ${peerId.toString()}`, logTags);
586
- return PeerErrorSeverity.HighToleranceError;
587
- }
588
-
589
- if (e?.code === 'ERR_UNEXPECTED_EOF') {
590
- this.logger.debug(`Connection unexpected EOF: ${peerId.toString()}`, logTags);
591
- return PeerErrorSeverity.HighToleranceError;
592
- }
593
-
594
- // Timeout errors are punished with high tolerance, they can be due to a geographically far away or overloaded peer
595
- if (e instanceof IndividualReqRespTimeoutError || e instanceof TimeoutError) {
596
- this.logger.debug(`Timeout error in ${subProtocol}: ${e.message}`, logTags);
597
- return PeerErrorSeverity.HighToleranceError;
598
- }
599
-
600
- // Catch all error
601
- this.logger.debug(`Unexpected error sending request to peer`, { err: e, logTags });
602
- return PeerErrorSeverity.HighToleranceError;
603
- }
604
-
605
460
  /**
606
461
  * Read a message returned from a stream into a single buffer
607
462
  *
@@ -610,16 +465,26 @@ export class ReqResp implements ReqRespInterface {
610
465
  * - The second chunk should contain the response data
611
466
  */
612
467
  private async readMessage(source: AsyncIterable<Uint8ArrayList>): Promise<ReqRespResponse> {
613
- let statusBuffer: ReqRespStatus | undefined;
468
+ let status: ReqRespStatus | undefined;
614
469
  const chunks: Uint8Array[] = [];
615
470
 
616
471
  try {
617
472
  for await (const chunk of source) {
618
- if (statusBuffer === undefined) {
619
- const firstChunkBuffer = chunk.subarray();
620
- statusBuffer = parseStatusChunk(firstChunkBuffer);
621
- } else {
473
+ const statusParsed = status !== undefined;
474
+ if (statusParsed) {
622
475
  chunks.push(chunk.subarray());
476
+ continue;
477
+ }
478
+
479
+ const firstChunkBuffer = chunk.subarray();
480
+ status = parseStatusChunk(firstChunkBuffer);
481
+
482
+ // In case status is not SUCCESS, we do not expect any data in the response
483
+ // we can return early
484
+ if (status !== ReqRespStatus.SUCCESS) {
485
+ return {
486
+ status,
487
+ };
623
488
  }
624
489
  }
625
490
 
@@ -627,7 +492,7 @@ export class ReqResp implements ReqRespInterface {
627
492
  const message: Buffer = this.snappyTransform.inboundTransformNoTopic(messageData);
628
493
 
629
494
  return {
630
- status: statusBuffer ?? ReqRespStatus.UNKNOWN,
495
+ status: status ?? ReqRespStatus.UNKNOWN,
631
496
  data: message,
632
497
  };
633
498
  } catch (e: any) {
@@ -640,7 +505,6 @@ export class ReqResp implements ReqRespInterface {
640
505
 
641
506
  return {
642
507
  status,
643
- data: Buffer.from([]),
644
508
  };
645
509
  }
646
510
  }
@@ -649,7 +513,8 @@ export class ReqResp implements ReqRespInterface {
649
513
  * Stream Handler
650
514
  * Reads the incoming stream, determines the protocol, then triggers the appropriate handler
651
515
  *
652
- * @param param0 - The incoming stream data
516
+ * @param protocol - The sub protocol to handle
517
+ * @param incomingStream - The incoming stream data containing the stream and connection
653
518
  *
654
519
  * @description
655
520
  * An individual stream handler will be bound to each sub protocol, and handles returning data back
@@ -665,13 +530,12 @@ export class ReqResp implements ReqRespInterface {
665
530
  [Attributes.P2P_REQ_RESP_PROTOCOL]: protocol,
666
531
  [Attributes.P2P_ID]: connection.remotePeer.toString(),
667
532
  }))
668
- private async streamHandler(protocol: ReqRespSubProtocol, { stream, connection }: IncomingStreamData) {
669
- this.metrics.recordRequestReceived(protocol);
670
-
533
+ private async streamHandler(protocol: ReqRespSubProtocol, incomingStream: IncomingStreamData) {
534
+ const { stream, connection } = incomingStream;
671
535
  try {
672
- // Store a reference to from this for the async generator
536
+ this.metrics.recordRequestReceived(protocol);
673
537
  const rateLimitStatus = this.rateLimiter.allow(protocol, connection.remotePeer);
674
- if (rateLimitStatus != RateLimitStatus.Allowed) {
538
+ if (rateLimitStatus !== RateLimitStatus.Allowed) {
675
539
  this.logger.verbose(
676
540
  `Rate limit exceeded ${prettyPrintRateLimitStatus(rateLimitStatus)} for ${protocol} from ${
677
541
  connection.remotePeer
@@ -681,78 +545,244 @@ export class ReqResp implements ReqRespInterface {
681
545
  throw new ReqRespStatusError(ReqRespStatus.RATE_LIMIT_EXCEEDED);
682
546
  }
683
547
 
684
- const handler = this.subProtocolHandlers[protocol];
685
- const transform = this.snappyTransform;
686
-
687
- await pipe(
688
- stream,
689
- async function* (source: any) {
690
- for await (const chunkList of source) {
691
- const msg = Buffer.from(chunkList.subarray());
692
- const response = await handler(connection.remotePeer, msg);
693
-
694
- if (protocol === ReqRespSubProtocol.GOODBYE) {
695
- // NOTE: The stream was already closed by Goodbye handler
696
- // peerManager.goodbyeReceived(peerId, reason); will call libp2p.hangUp closing all active streams and connections
697
- // Don't respond
698
- return;
699
- }
700
-
701
- // Send success code first, then the response
702
- const successChunk = Buffer.from([ReqRespStatus.SUCCESS]);
703
- yield new Uint8Array(successChunk);
548
+ await this.processStream(protocol, incomingStream);
549
+ } catch (err: any) {
550
+ this.metrics.recordResponseError(protocol);
551
+ this.handleRequestError(err, connection.remotePeer, protocol);
552
+
553
+ if (err instanceof ReqRespStatusError) {
554
+ const errorSent = await this.trySendError(stream, connection.remotePeer, protocol, err.status);
555
+ const logMessage = errorSent
556
+ ? 'Protocol error sent successfully.'
557
+ : 'Stream already closed or poisoned, not sending error response.';
558
+
559
+ const isRateLimit = err.status === ReqRespStatus.RATE_LIMIT_EXCEEDED;
560
+
561
+ const level = isRateLimit ? 'debug' : 'warn';
562
+ this.logger[level](logMessage + ` Status: ${ReqRespStatus[err.status]}`, {
563
+ protocol,
564
+ err,
565
+ errorStatus: err.status,
566
+ cause: err.cause ?? 'Cause unknown',
567
+ });
568
+ } else {
569
+ // In erroneous case we abort the stream, this will signal the peer that something went wrong
570
+ // and that this stream should be dropped
571
+ const isMessageToNotWarn =
572
+ err instanceof Error &&
573
+ ['stream reset', 'Cannot push value onto an ended pushable'].some(msg => err.message.includes(msg));
574
+ const level = isMessageToNotWarn ? 'debug' : 'warn';
575
+ this.logger[level]('Unknown stream error while handling the stream, aborting', {
576
+ protocol,
577
+ err,
578
+ });
579
+
580
+ stream.abort(err);
581
+ }
582
+ } finally {
583
+ //NOTE: This is idempotent action, so it's ok to call it even if stream was aborted
584
+ await stream.close();
585
+ }
586
+ }
704
587
 
705
- yield new Uint8Array(transform.outboundTransformNoTopic(response));
588
+ /**
589
+ * Reads incoming data from the stream, processes it according to the sub protocol,
590
+ * and puts response back into the stream.
591
+ *
592
+ * @param protocol - The sub protocol to use for processing the stream
593
+ * @param incomingStream - The incoming stream data containing the stream and connection
594
+ *
595
+ * */
596
+ private async processStream(protocol: ReqRespSubProtocol, { stream, connection }: IncomingStreamData): Promise<void> {
597
+ const handler = this.subProtocolHandlers[protocol]!;
598
+ const snappy = this.snappyTransform;
599
+ const SUCCESS = Uint8Array.of(ReqRespStatus.SUCCESS);
600
+
601
+ await pipeline(
602
+ stream.source,
603
+ async function* (source: any) {
604
+ for await (const chunk of source) {
605
+ const response = await handler(connection.remotePeer, chunk.subarray());
606
+
607
+ if (protocol === ReqRespSubProtocol.GOODBYE) {
608
+ // NOTE: The stream was already closed by Goodbye handler
609
+ // peerManager.goodbyeReceived(peerId, reason); will call libp2p.hangUp closing all active streams and connections
610
+ // Don't try to respond
611
+ return;
706
612
  }
707
- },
708
- stream,
709
- );
613
+
614
+ stream.metadata.written = true; // Mark the stream as written to;
615
+
616
+ yield SUCCESS;
617
+ yield snappy.outboundTransformNoTopic(response);
618
+ }
619
+ },
620
+ stream.sink,
621
+ );
622
+ }
623
+
624
+ /**
625
+ * Try to send error status to the peer. We say try, because the stream,
626
+ * might already be closed
627
+ * @param stream - The stream opened between us and the peer
628
+ * @param status - The error status to send back to the peer
629
+ * @returns true if error was sent successfully, otherwise false
630
+ *
631
+ */
632
+ private async trySendError(
633
+ stream: Stream,
634
+ peerId: PeerId,
635
+ protocol: ReqRespSubProtocol,
636
+ status: ReqRespStatus,
637
+ ): Promise<boolean> {
638
+ const canWriteToStream =
639
+ // 'writing' is a bit weird naming, but it actually means that the stream is ready to write
640
+ // 'ready' means that stream ready to be opened for writing
641
+ stream.status === 'open' && (stream.writeStatus === 'writing' || stream.writeStatus === 'ready');
642
+
643
+ // Stream was already written to, we consider it poisoned, in a sense,
644
+ // that even if we write an error response, it will not be interpreted correctly by the peer
645
+ const streamPoisoned = stream.metadata.written === true;
646
+ const shouldWriteToStream = canWriteToStream && !streamPoisoned;
647
+
648
+ if (!shouldWriteToStream) {
649
+ return false;
650
+ }
651
+
652
+ try {
653
+ await pipeline(function* () {
654
+ yield Uint8Array.of(status);
655
+ }, stream.sink);
656
+
657
+ return true;
710
658
  } catch (e: any) {
711
- let level: 'warn' | 'debug' = 'warn';
712
- if (
713
- e &&
714
- ((e instanceof ReqRespStatusError && e.status === ReqRespStatus.RATE_LIMIT_EXCEEDED) ||
715
- (e instanceof Error &&
716
- ['stream reset', 'Cannot push value onto an ended pushable'].some(msg => e.message.includes(msg))))
717
- ) {
718
- level = 'debug';
719
- }
720
- this.logger[level](`Reqresp response error: ${String(e)}`, e);
721
- this.metrics.recordResponseError(protocol);
659
+ this.logger.warn('Error while sending error response', e);
660
+ stream.abort(e);
722
661
 
723
- // If we receive a known error, we use the error status in the response chunk, otherwise we categorize as unknown
724
- let errorStatus = ReqRespStatus.UNKNOWN;
725
- if (e instanceof ReqRespStatusError) {
726
- errorStatus = e.status;
727
- }
662
+ this.handleRequestError(e, peerId, protocol);
663
+ return false;
664
+ }
665
+ }
728
666
 
729
- const canWriteToStream =
730
- stream.status === 'open' && (stream.writeStatus === 'writing' || stream.writeStatus === 'ready');
731
- if (!canWriteToStream) {
732
- this.logger.debug('Stream already closed, not sending error response', { protocol, err: e, errorStatus });
733
- return;
734
- }
667
+ private handleRequestError(e: any, peerId: PeerId, subProtocol: ReqRespSubProtocol): void {
668
+ const severity = this.categorizeRequestError(e, peerId, subProtocol);
669
+ if (severity) {
670
+ this.peerScoring.penalizePeer(peerId, severity);
671
+ }
672
+ }
735
673
 
736
- // Return and yield the response chunk
737
- try {
738
- const sendErrorChunk = this.sendErrorChunk(errorStatus);
739
- await pipe(
740
- stream,
741
- async function* (_source: any) {
742
- yield* sendErrorChunk;
743
- },
744
- stream,
745
- );
746
- } catch (e: any) {
747
- this.logger.warn('Error while sending error response', { protocol, err: e, errorStatus });
748
- }
749
- } finally {
750
- await stream.close();
674
+ /**
675
+ * Categorize the request error and log it.
676
+ *
677
+ * @returns Severity of the error, or undefined if the error is not punishable.
678
+ */
679
+ private categorizeRequestError(
680
+ e: any,
681
+ peerId: PeerId,
682
+ subProtocol: ReqRespSubProtocol,
683
+ ): PeerErrorSeverity | undefined {
684
+ const logTags = { peerId: peerId.toString(), subProtocol };
685
+
686
+ //Punishable error - peer should never send badly formed request
687
+ if (e instanceof ReqRespStatusError && e.status === ReqRespStatus.BADLY_FORMED_REQUEST) {
688
+ this.logger.debug(`Punishable error in ${subProtocol}: ${e.cause}`, logTags);
689
+ return PeerErrorSeverity.LowToleranceError;
751
690
  }
691
+
692
+ //TODO: (mralj): think if we should penalize peer here based on connection errors
693
+ return undefined;
752
694
  }
753
695
 
754
- private async *sendErrorChunk(error: ReqRespStatus): AsyncIterable<Uint8Array> {
755
- const errorChunk = Buffer.from([error]);
756
- yield new Uint8Array(errorChunk);
696
+ /**
697
+ * Categorize the response error and log it.
698
+ *
699
+ * @returns Severity of the error, or undefined if the error is not punishable.
700
+ */
701
+ private categorizeResponseError(
702
+ e: any,
703
+ peerId: PeerId,
704
+ subProtocol: ReqRespSubProtocol,
705
+ ): PeerErrorSeverity | undefined {
706
+ const logTags = { peerId: peerId.toString(), subProtocol };
707
+
708
+ // Non punishable errors - we do not expect a response for goodbye messages
709
+ if (subProtocol === ReqRespSubProtocol.GOODBYE) {
710
+ this.logger.debug('Error encountered on goodbye sub protocol, no penalty', logTags);
711
+ return undefined;
712
+ }
713
+
714
+ // We do not punish a collective timeout, as the node triggers this interupt, independent of the peer's behaviour
715
+ if (e instanceof CollectiveReqRespTimeoutError || e instanceof InvalidResponseError) {
716
+ this.logger.debug(`Non-punishable error in ${subProtocol}: ${e.message}`, logTags);
717
+ return undefined;
718
+ }
719
+
720
+ return this.categorizeConnectionErrors(e, peerId, subProtocol);
721
+ }
722
+
723
+ /*
724
+ * Errors specific to connection handling
725
+ * These can happen both when sending request and response*/
726
+ private categorizeConnectionErrors(
727
+ e: any,
728
+ peerId: PeerId,
729
+ subProtocol: ReqRespSubProtocol,
730
+ ): PeerErrorSeverity | undefined {
731
+ const logTags = { peerId: peerId.toString(), subProtocol };
732
+ // Do not punish if we are stopping the service
733
+ if (e instanceof AbortError || e?.code == 'ABORT_ERR') {
734
+ this.logger.debug(`Request aborted: ${e.message}`, logTags);
735
+ return undefined;
736
+ }
737
+
738
+ // Do not punish if we are the ones closing the connection
739
+ if (
740
+ e?.code === 'ERR_CONNECTION_BEING_CLOSED' ||
741
+ e?.code === 'ERR_CONNECTION_CLOSED' ||
742
+ e?.code === 'ERR_TRANSIENT_CONNECTION' ||
743
+ e?.message?.includes('Muxer already closed') ||
744
+ e?.message?.includes('muxer closed') ||
745
+ e?.message?.includes('ended pushable')
746
+ ) {
747
+ this.logger.debug(
748
+ `Connection closed to peer from our side: ${peerId.toString()} (${e?.message ?? 'missing error message'})`,
749
+ logTags,
750
+ );
751
+ return undefined;
752
+ }
753
+
754
+ // Pubishable errors
755
+ // Connection reset errors in the networking stack are punished with high severity
756
+ // it just signals an unreliable peer
757
+ // We assume that the requesting node has a functioning networking stack.
758
+ if (e?.code === 'ECONNRESET' || e?.code === 'EPIPE') {
759
+ this.logger.debug(`Connection reset: ${peerId.toString()}`, logTags);
760
+ return PeerErrorSeverity.HighToleranceError;
761
+ }
762
+
763
+ if (e?.code === 'ECONNREFUSED') {
764
+ this.logger.debug(`Connection refused: ${peerId.toString()}`, logTags);
765
+ return PeerErrorSeverity.HighToleranceError;
766
+ }
767
+
768
+ if (e?.code === 'ERR_UNEXPECTED_EOF') {
769
+ this.logger.debug(`Connection unexpected EOF: ${peerId.toString()}`, logTags);
770
+ return PeerErrorSeverity.HighToleranceError;
771
+ }
772
+
773
+ if (e?.code === 'ERR_UNSUPPORTED_PROTOCOL') {
774
+ this.logger.debug(`Sub protocol not supported by peer: ${peerId.toString()}`, logTags);
775
+ return PeerErrorSeverity.HighToleranceError;
776
+ }
777
+
778
+ // Timeout errors are punished with high tolerance, they can be due to a geographically far away or overloaded peer
779
+ if (e instanceof IndividualReqRespTimeoutError || e instanceof TimeoutError) {
780
+ this.logger.debug(`Timeout error in ${subProtocol}: ${e.message}`, logTags);
781
+ return PeerErrorSeverity.HighToleranceError;
782
+ }
783
+
784
+ // Catch all error
785
+ this.logger.error(`Unexpected error in ReqResp protocol`, e, logTags);
786
+ return PeerErrorSeverity.HighToleranceError;
757
787
  }
758
788
  }