@aztec/p2p 0.53.0 → 0.55.0

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 (48) hide show
  1. package/dest/attestation_pool/mocks.d.ts.map +1 -1
  2. package/dest/attestation_pool/mocks.js +6 -4
  3. package/dest/client/p2p_client.d.ts +27 -2
  4. package/dest/client/p2p_client.d.ts.map +1 -1
  5. package/dest/client/p2p_client.js +33 -4
  6. package/dest/config.d.ts +2 -1
  7. package/dest/config.d.ts.map +1 -1
  8. package/dest/config.js +3 -1
  9. package/dest/errors/reqresp.error.d.ts +17 -0
  10. package/dest/errors/reqresp.error.d.ts.map +1 -0
  11. package/dest/errors/reqresp.error.js +21 -0
  12. package/dest/mocks/index.d.ts.map +1 -1
  13. package/dest/mocks/index.js +6 -2
  14. package/dest/service/libp2p_service.js +3 -3
  15. package/dest/service/reqresp/config.d.ts +16 -0
  16. package/dest/service/reqresp/config.d.ts.map +1 -0
  17. package/dest/service/reqresp/config.js +21 -0
  18. package/dest/service/reqresp/interface.d.ts +30 -3
  19. package/dest/service/reqresp/interface.d.ts.map +1 -1
  20. package/dest/service/reqresp/interface.js +4 -4
  21. package/dest/service/reqresp/rate_limiter/index.d.ts +2 -0
  22. package/dest/service/reqresp/rate_limiter/index.d.ts.map +1 -0
  23. package/dest/service/reqresp/rate_limiter/index.js +2 -0
  24. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts +97 -0
  25. package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -0
  26. package/dest/service/reqresp/rate_limiter/rate_limiter.js +148 -0
  27. package/dest/service/reqresp/rate_limiter/rate_limits.d.ts +3 -0
  28. package/dest/service/reqresp/rate_limiter/rate_limits.d.ts.map +1 -0
  29. package/dest/service/reqresp/rate_limiter/rate_limits.js +35 -0
  30. package/dest/service/reqresp/reqresp.d.ts +5 -1
  31. package/dest/service/reqresp/reqresp.d.ts.map +1 -1
  32. package/dest/service/reqresp/reqresp.js +55 -17
  33. package/dest/service/service.d.ts +1 -1
  34. package/dest/service/service.d.ts.map +1 -1
  35. package/package.json +6 -6
  36. package/src/attestation_pool/mocks.ts +6 -3
  37. package/src/client/p2p_client.ts +44 -5
  38. package/src/config.ts +4 -1
  39. package/src/errors/reqresp.error.ts +21 -0
  40. package/src/mocks/index.ts +6 -1
  41. package/src/service/libp2p_service.ts +2 -2
  42. package/src/service/reqresp/config.ts +35 -0
  43. package/src/service/reqresp/interface.ts +33 -3
  44. package/src/service/reqresp/rate_limiter/index.ts +1 -0
  45. package/src/service/reqresp/rate_limiter/rate_limiter.ts +198 -0
  46. package/src/service/reqresp/rate_limiter/rate_limits.ts +35 -0
  47. package/src/service/reqresp/reqresp.ts +78 -20
  48. package/src/service/service.ts +1 -1
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @attribution Rate limiter approach implemented in the lodestar ethereum 2 client.
3
+ * Rationale is that if it was good enough for them, then it should be good enough for us.
4
+ * https://github.com/ChainSafe/lodestar
5
+ */
6
+ import { type PeerId } from '@libp2p/interface';
7
+ import { type ReqRespSubProtocol, type ReqRespSubProtocolRateLimits } from '../interface.js';
8
+ /**
9
+ * GCRARateLimiter: A Generic Cell Rate Algorithm (GCRA) based rate limiter.
10
+ *
11
+ * How it works:
12
+ * 1. The rate limiter allows a certain number of operations (quotaCount) within a specified
13
+ * time interval (quotaTimeMs).
14
+ * 2. It uses a "virtual scheduling time" (VST) to determine when the next operation should be allowed.
15
+ * 3. When an operation is requested, the limiter checks if enough time has passed since the last
16
+ * allowed operation.
17
+ * 4. If sufficient time has passed, the operation is allowed, and the VST is updated.
18
+ * 5. If not enough time has passed, the operation is denied.
19
+ *
20
+ * The limiter also allows for short bursts of activity, as long as the overall rate doesn't exceed
21
+ * the specified quota over time.
22
+ *
23
+ * Usage example:
24
+ * ```
25
+ * const limiter = new GCRARateLimiter(100, 60000); // 100 operations per minute
26
+ * ```
27
+ */
28
+ export declare class GCRARateLimiter {
29
+ private vst;
30
+ private readonly emissionInterval;
31
+ private readonly limitInterval;
32
+ /**
33
+ * @param quotaCount - The number of requests to allow over the limit interval
34
+ * @param quotaTimeMs - The time interval over which the quotaCount applies
35
+ */
36
+ constructor(quotaCount: number, quotaTimeMs: number);
37
+ allow(): boolean;
38
+ }
39
+ /**
40
+ * SubProtocolRateLimiter: A rate limiter for managing request rates on a per-peer and global basis for a specific subprotocol.
41
+ *
42
+ * This class provides a two-tier rate limiting system:
43
+ * 1. A global rate limit for all requests across all peers for this subprotocol.
44
+ * 2. Individual rate limits for each peer.
45
+ *
46
+ * How it works:
47
+ * - When a request comes in, it first checks against the global rate limit.
48
+ * - If the global limit allows, it then checks against the specific peer's rate limit.
49
+ * - The request is only allowed if both the global and peer-specific limits allow it.
50
+ * - It automatically creates and manages rate limiters for new peers as they make requests.
51
+ * - It periodically cleans up rate limiters for inactive peers to conserve memory.
52
+ *
53
+ * Note: Remember to call `start()` to begin the cleanup process and `stop()` when shutting down to clear the cleanup interval.
54
+ */
55
+ export declare class SubProtocolRateLimiter {
56
+ private peerLimiters;
57
+ private globalLimiter;
58
+ private readonly peerQuotaCount;
59
+ private readonly peerQuotaTimeMs;
60
+ constructor(peerQuotaCount: number, peerQuotaTimeMs: number, globalQuotaCount: number, globalQuotaTimeMs: number);
61
+ allow(peerId: PeerId): boolean;
62
+ cleanupInactivePeers(): void;
63
+ }
64
+ /**
65
+ * RequestResponseRateLimiter.
66
+ *
67
+ * A rate limiter that is protocol aware, then peer aware.
68
+ * SubProtocols can have their own global / peer level rate limits.
69
+ *
70
+ * How it works:
71
+ * - Initializes with a set of rate limit configurations for different subprotocols.
72
+ * - Creates a separate SubProtocolRateLimiter for each configured subprotocol.
73
+ * - When a request comes in, it routes the rate limiting decision to the appropriate subprotocol limiter.
74
+ *
75
+ * Usage:
76
+ * ```
77
+ * const rateLimits = {
78
+ * subprotocol1: { peerLimit: { quotaCount: 10, quotaTimeMs: 1000 }, globalLimit: { quotaCount: 100, quotaTimeMs: 1000 } },
79
+ * subprotocol2: { peerLimit: { quotaCount: 5, quotaTimeMs: 1000 }, globalLimit: { quotaCount: 50, quotaTimeMs: 1000 } }
80
+ * };
81
+ * const limiter = new RequestResponseRateLimiter(rateLimits);
82
+ *
83
+ * Note: Ensure to call `stop()` when shutting down to properly clean up all subprotocol limiters.
84
+ */
85
+ export declare class RequestResponseRateLimiter {
86
+ private subProtocolRateLimiters;
87
+ private cleanupInterval;
88
+ constructor(rateLimits?: ReqRespSubProtocolRateLimits);
89
+ start(): void;
90
+ allow(subProtocol: ReqRespSubProtocol, peerId: PeerId): boolean;
91
+ cleanupInactivePeers(): void;
92
+ /**
93
+ * Make sure to call destroy on each of the sub protocol rate limiters when cleaning up
94
+ */
95
+ stop(): void;
96
+ }
97
+ //# sourceMappingURL=rate_limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate_limiter.d.ts","sourceRoot":"","sources":["../../../../src/service/reqresp/rate_limiter/rate_limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAM7F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,eAAe;IAE1B,OAAO,CAAC,GAAG,CAAS;IAEpB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC;;;OAGG;gBACS,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAMnD,KAAK,IAAI,OAAO;CAWjB;AASD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,YAAY,CAA2C;IAC/D,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM;IAOhH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAoB9B,oBAAoB;CAQrB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,uBAAuB,CAAkD;IAEjF,OAAO,CAAC,eAAe,CAAyC;gBAEpD,UAAU,GAAE,4BAAkD;IAgB1E,KAAK;IAML,KAAK,CAAC,WAAW,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAS/D,oBAAoB;IAIpB;;OAEG;IACH,IAAI;CAGL"}
@@ -0,0 +1,148 @@
1
+ import { DEFAULT_RATE_LIMITS } from './rate_limits.js';
2
+ // Check for disconnected peers every 10 minutes
3
+ const CHECK_DISCONNECTED_PEERS_INTERVAL_MS = 10 * 60 * 1000;
4
+ /**
5
+ * GCRARateLimiter: A Generic Cell Rate Algorithm (GCRA) based rate limiter.
6
+ *
7
+ * How it works:
8
+ * 1. The rate limiter allows a certain number of operations (quotaCount) within a specified
9
+ * time interval (quotaTimeMs).
10
+ * 2. It uses a "virtual scheduling time" (VST) to determine when the next operation should be allowed.
11
+ * 3. When an operation is requested, the limiter checks if enough time has passed since the last
12
+ * allowed operation.
13
+ * 4. If sufficient time has passed, the operation is allowed, and the VST is updated.
14
+ * 5. If not enough time has passed, the operation is denied.
15
+ *
16
+ * The limiter also allows for short bursts of activity, as long as the overall rate doesn't exceed
17
+ * the specified quota over time.
18
+ *
19
+ * Usage example:
20
+ * ```
21
+ * const limiter = new GCRARateLimiter(100, 60000); // 100 operations per minute
22
+ * ```
23
+ */
24
+ export class GCRARateLimiter {
25
+ /**
26
+ * @param quotaCount - The number of requests to allow over the limit interval
27
+ * @param quotaTimeMs - The time interval over which the quotaCount applies
28
+ */
29
+ constructor(quotaCount, quotaTimeMs) {
30
+ this.emissionInterval = quotaTimeMs / quotaCount;
31
+ this.limitInterval = quotaTimeMs;
32
+ this.vst = Date.now();
33
+ }
34
+ allow() {
35
+ const now = Date.now();
36
+ const newVst = Math.max(this.vst, now) + this.emissionInterval;
37
+ if (newVst - now <= this.limitInterval) {
38
+ this.vst = newVst;
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * SubProtocolRateLimiter: A rate limiter for managing request rates on a per-peer and global basis for a specific subprotocol.
46
+ *
47
+ * This class provides a two-tier rate limiting system:
48
+ * 1. A global rate limit for all requests across all peers for this subprotocol.
49
+ * 2. Individual rate limits for each peer.
50
+ *
51
+ * How it works:
52
+ * - When a request comes in, it first checks against the global rate limit.
53
+ * - If the global limit allows, it then checks against the specific peer's rate limit.
54
+ * - The request is only allowed if both the global and peer-specific limits allow it.
55
+ * - It automatically creates and manages rate limiters for new peers as they make requests.
56
+ * - It periodically cleans up rate limiters for inactive peers to conserve memory.
57
+ *
58
+ * Note: Remember to call `start()` to begin the cleanup process and `stop()` when shutting down to clear the cleanup interval.
59
+ */
60
+ export class SubProtocolRateLimiter {
61
+ constructor(peerQuotaCount, peerQuotaTimeMs, globalQuotaCount, globalQuotaTimeMs) {
62
+ this.peerLimiters = new Map();
63
+ this.peerLimiters = new Map();
64
+ this.globalLimiter = new GCRARateLimiter(globalQuotaCount, globalQuotaTimeMs);
65
+ this.peerQuotaCount = peerQuotaCount;
66
+ this.peerQuotaTimeMs = peerQuotaTimeMs;
67
+ }
68
+ allow(peerId) {
69
+ if (!this.globalLimiter.allow()) {
70
+ return false;
71
+ }
72
+ const peerIdStr = peerId.toString();
73
+ let peerLimiter = this.peerLimiters.get(peerIdStr);
74
+ if (!peerLimiter) {
75
+ // Create a limiter for this peer
76
+ peerLimiter = {
77
+ limiter: new GCRARateLimiter(this.peerQuotaCount, this.peerQuotaTimeMs),
78
+ lastAccess: Date.now(),
79
+ };
80
+ this.peerLimiters.set(peerIdStr, peerLimiter);
81
+ }
82
+ else {
83
+ peerLimiter.lastAccess = Date.now();
84
+ }
85
+ return peerLimiter.limiter.allow();
86
+ }
87
+ cleanupInactivePeers() {
88
+ const now = Date.now();
89
+ this.peerLimiters.forEach((peerLimiter, peerId) => {
90
+ if (now - peerLimiter.lastAccess > CHECK_DISCONNECTED_PEERS_INTERVAL_MS) {
91
+ this.peerLimiters.delete(peerId);
92
+ }
93
+ });
94
+ }
95
+ }
96
+ /**
97
+ * RequestResponseRateLimiter.
98
+ *
99
+ * A rate limiter that is protocol aware, then peer aware.
100
+ * SubProtocols can have their own global / peer level rate limits.
101
+ *
102
+ * How it works:
103
+ * - Initializes with a set of rate limit configurations for different subprotocols.
104
+ * - Creates a separate SubProtocolRateLimiter for each configured subprotocol.
105
+ * - When a request comes in, it routes the rate limiting decision to the appropriate subprotocol limiter.
106
+ *
107
+ * Usage:
108
+ * ```
109
+ * const rateLimits = {
110
+ * subprotocol1: { peerLimit: { quotaCount: 10, quotaTimeMs: 1000 }, globalLimit: { quotaCount: 100, quotaTimeMs: 1000 } },
111
+ * subprotocol2: { peerLimit: { quotaCount: 5, quotaTimeMs: 1000 }, globalLimit: { quotaCount: 50, quotaTimeMs: 1000 } }
112
+ * };
113
+ * const limiter = new RequestResponseRateLimiter(rateLimits);
114
+ *
115
+ * Note: Ensure to call `stop()` when shutting down to properly clean up all subprotocol limiters.
116
+ */
117
+ export class RequestResponseRateLimiter {
118
+ constructor(rateLimits = DEFAULT_RATE_LIMITS) {
119
+ this.cleanupInterval = undefined;
120
+ this.subProtocolRateLimiters = new Map();
121
+ for (const [subProtocol, protocolLimits] of Object.entries(rateLimits)) {
122
+ this.subProtocolRateLimiters.set(subProtocol, new SubProtocolRateLimiter(protocolLimits.peerLimit.quotaCount, protocolLimits.peerLimit.quotaTimeMs, protocolLimits.globalLimit.quotaCount, protocolLimits.globalLimit.quotaTimeMs));
123
+ }
124
+ }
125
+ start() {
126
+ this.cleanupInterval = setInterval(() => {
127
+ this.cleanupInactivePeers();
128
+ }, CHECK_DISCONNECTED_PEERS_INTERVAL_MS);
129
+ }
130
+ allow(subProtocol, peerId) {
131
+ const limiter = this.subProtocolRateLimiters.get(subProtocol);
132
+ if (!limiter) {
133
+ // TODO: maybe throw an error here if no rate limiter is configured?
134
+ return true;
135
+ }
136
+ return limiter.allow(peerId);
137
+ }
138
+ cleanupInactivePeers() {
139
+ this.subProtocolRateLimiters.forEach(limiter => limiter.cleanupInactivePeers());
140
+ }
141
+ /**
142
+ * Make sure to call destroy on each of the sub protocol rate limiters when cleaning up
143
+ */
144
+ stop() {
145
+ clearInterval(this.cleanupInterval);
146
+ }
147
+ }
148
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZV9saW1pdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3NlcnZpY2UvcmVxcmVzcC9yYXRlX2xpbWl0ZXIvcmF0ZV9saW1pdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXZELGdEQUFnRDtBQUNoRCxNQUFNLG9DQUFvQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBRTVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFRMUI7OztPQUdHO0lBQ0gsWUFBWSxVQUFrQixFQUFFLFdBQW1CO1FBQ2pELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxXQUFXLEdBQUcsVUFBVSxDQUFDO1FBQ2pELElBQUksQ0FBQyxhQUFhLEdBQUcsV0FBVyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxLQUFLO1FBQ0gsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRXZCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7UUFDL0QsSUFBSSxNQUFNLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQztZQUNsQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRjtBQVNEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sT0FBTyxzQkFBc0I7SUFNakMsWUFBWSxjQUFzQixFQUFFLGVBQXVCLEVBQUUsZ0JBQXdCLEVBQUUsaUJBQXlCO1FBTHhHLGlCQUFZLEdBQWlDLElBQUksR0FBRyxFQUFFLENBQUM7UUFNN0QsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQzlCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxlQUFlLENBQUMsZ0JBQWdCLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUM5RSxJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUNyQyxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztJQUN6QyxDQUFDO0lBRUQsS0FBSyxDQUFDLE1BQWM7UUFDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztZQUNoQyxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDcEMsSUFBSSxXQUFXLEdBQWdDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2hGLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixpQ0FBaUM7WUFDakMsV0FBVyxHQUFHO2dCQUNaLE9BQU8sRUFBRSxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUM7Z0JBQ3ZFLFVBQVUsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFO2FBQ3ZCLENBQUM7WUFDRixJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDaEQsQ0FBQzthQUFNLENBQUM7WUFDTixXQUFXLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsT0FBTyxXQUFXLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JDLENBQUM7SUFFRCxvQkFBb0I7UUFDbEIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2hELElBQUksR0FBRyxHQUFHLFdBQVcsQ0FBQyxVQUFVLEdBQUcsb0NBQW9DLEVBQUUsQ0FBQztnQkFDeEUsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbkMsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxPQUFPLDBCQUEwQjtJQUtyQyxZQUFZLGFBQTJDLG1CQUFtQjtRQUZsRSxvQkFBZSxHQUErQixTQUFTLENBQUM7UUFHOUQsSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFFekMsS0FBSyxNQUFNLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUN2RSxJQUFJLENBQUMsdUJBQXVCLENBQUMsR0FBRyxDQUM5QixXQUFpQyxFQUNqQyxJQUFJLHNCQUFzQixDQUN4QixjQUFjLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFDbkMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQ3BDLGNBQWMsQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUNyQyxjQUFjLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FDdkMsQ0FDRixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLO1FBQ0gsSUFBSSxDQUFDLGVBQWUsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQ3RDLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO1FBQzlCLENBQUMsRUFBRSxvQ0FBb0MsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRCxLQUFLLENBQUMsV0FBK0IsRUFBRSxNQUFjO1FBQ25ELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDOUQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2Isb0VBQW9FO1lBQ3BFLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBRUQsb0JBQW9CO1FBQ2xCLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO0lBQ2xGLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUk7UUFDRixhQUFhLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7Q0FDRiJ9
@@ -0,0 +1,3 @@
1
+ import { type ReqRespSubProtocolRateLimits } from '../interface.js';
2
+ export declare const DEFAULT_RATE_LIMITS: ReqRespSubProtocolRateLimits;
3
+ //# sourceMappingURL=rate_limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate_limits.d.ts","sourceRoot":"","sources":["../../../../src/service/reqresp/rate_limiter/rate_limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,4BAA4B,EAAoC,MAAM,iBAAiB,CAAC;AAGrH,eAAO,MAAM,mBAAmB,EAAE,4BA+BjC,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { PING_PROTOCOL, STATUS_PROTOCOL, TX_REQ_PROTOCOL } from '../interface.js';
2
+ // TODO(md): these defaults need to be tuned
3
+ export const DEFAULT_RATE_LIMITS = {
4
+ [PING_PROTOCOL]: {
5
+ peerLimit: {
6
+ quotaTimeMs: 1000,
7
+ quotaCount: 5,
8
+ },
9
+ globalLimit: {
10
+ quotaTimeMs: 1000,
11
+ quotaCount: 10,
12
+ },
13
+ },
14
+ [STATUS_PROTOCOL]: {
15
+ peerLimit: {
16
+ quotaTimeMs: 1000,
17
+ quotaCount: 5,
18
+ },
19
+ globalLimit: {
20
+ quotaTimeMs: 1000,
21
+ quotaCount: 10,
22
+ },
23
+ },
24
+ [TX_REQ_PROTOCOL]: {
25
+ peerLimit: {
26
+ quotaTimeMs: 1000,
27
+ quotaCount: 5,
28
+ },
29
+ globalLimit: {
30
+ quotaTimeMs: 1000,
31
+ quotaCount: 10,
32
+ },
33
+ },
34
+ };
35
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZV9saW1pdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc2VydmljZS9yZXFyZXNwL3JhdGVfbGltaXRlci9yYXRlX2xpbWl0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFxQyxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFckgsNENBQTRDO0FBQzVDLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFpQztJQUMvRCxDQUFDLGFBQWEsQ0FBQyxFQUFFO1FBQ2YsU0FBUyxFQUFFO1lBQ1QsV0FBVyxFQUFFLElBQUk7WUFDakIsVUFBVSxFQUFFLENBQUM7U0FDZDtRQUNELFdBQVcsRUFBRTtZQUNYLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLFVBQVUsRUFBRSxFQUFFO1NBQ2Y7S0FDRjtJQUNELENBQUMsZUFBZSxDQUFDLEVBQUU7UUFDakIsU0FBUyxFQUFFO1lBQ1QsV0FBVyxFQUFFLElBQUk7WUFDakIsVUFBVSxFQUFFLENBQUM7U0FDZDtRQUNELFdBQVcsRUFBRTtZQUNYLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLFVBQVUsRUFBRSxFQUFFO1NBQ2Y7S0FDRjtJQUNELENBQUMsZUFBZSxDQUFDLEVBQUU7UUFDakIsU0FBUyxFQUFFO1lBQ1QsV0FBVyxFQUFFLElBQUk7WUFDakIsVUFBVSxFQUFFLENBQUM7U0FDZDtRQUNELFdBQVcsRUFBRTtZQUNYLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLFVBQVUsRUFBRSxFQUFFO1NBQ2Y7S0FDRjtDQUNGLENBQUMifQ==
@@ -2,6 +2,7 @@
2
2
  import { type Logger } from '@aztec/foundation/log';
3
3
  import { type PeerId } from '@libp2p/interface';
4
4
  import { type Libp2p } from 'libp2p';
5
+ import { type P2PReqRespConfig } from './config.js';
5
6
  import { type ReqRespSubProtocol, type ReqRespSubProtocolHandlers } from './interface.js';
6
7
  /**
7
8
  * The Request Response Service
@@ -18,8 +19,11 @@ export declare class ReqResp {
18
19
  protected readonly libp2p: Libp2p;
19
20
  protected readonly logger: Logger;
20
21
  private abortController;
22
+ private overallRequestTimeoutMs;
23
+ private individualRequestTimeoutMs;
21
24
  private subProtocolHandlers;
22
- constructor(libp2p: Libp2p);
25
+ private rateLimiter;
26
+ constructor(config: P2PReqRespConfig, libp2p: Libp2p);
23
27
  /**
24
28
  * Start the reqresp service
25
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"reqresp.d.ts","sourceRoot":"","sources":["../../../src/service/reqresp/reqresp.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAA2B,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGrC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAChC,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAON,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAN7C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,eAAe,CAA0C;IAEjE,OAAO,CAAC,mBAAmB,CAA6D;gBAEzD,MAAM,EAAE,MAAM;IAI7C;;OAEG;IACG,KAAK,CAAC,mBAAmB,EAAE,0BAA0B;IAQ3D;;OAEG;IACG,IAAI;IASV;;;;;;OAMG;IACG,WAAW,CAAC,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAiBhG;;;;;;;OAOG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAY9B;;OAEG;YACW,WAAW;IASzB;;;;;OAKG;YACW,aAAa;CAqB5B"}
1
+ {"version":3,"file":"reqresp.d.ts","sourceRoot":"","sources":["../../../src/service/reqresp/reqresp.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,uBAAuB,CAAC;AAGvE,OAAO,EAA2B,KAAK,MAAM,EAAe,MAAM,mBAAmB,CAAC;AAEtF,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIrC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAChC,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAWoB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAVvE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,eAAe,CAA0C;IAEjE,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,0BAA0B,CAAS;IAE3C,OAAO,CAAC,mBAAmB,CAA6D;IACxF,OAAO,CAAC,WAAW,CAA6B;gBAEpC,MAAM,EAAE,gBAAgB,EAAqB,MAAM,EAAE,MAAM;IASvE;;OAEG;IACG,KAAK,CAAC,mBAAmB,EAAE,0BAA0B;IAS3D;;OAEG;IACG,IAAI;IAUV;;;;;;OAMG;IACG,WAAW,CAAC,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA8BhG;;;;;;;OAOG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAkC9B;;OAEG;YACW,WAAW;IASzB;;;;;OAKG;YACW,aAAa;CA6B5B"}
@@ -1,7 +1,10 @@
1
1
  // @attribution: lodestar impl for inspiration
2
2
  import { createDebugLogger } from '@aztec/foundation/log';
3
+ import { executeTimeoutWithCustomError } from '@aztec/foundation/timer';
3
4
  import { pipe } from 'it-pipe';
5
+ import { CollectiveReqRespTimeoutError, IndiviualReqRespTimeoutError } from '../../errors/reqresp.error.js';
4
6
  import { DEFAULT_SUB_PROTOCOL_HANDLERS, } from './interface.js';
7
+ import { RequestResponseRateLimiter } from './rate_limiter/rate_limiter.js';
5
8
  /**
6
9
  * The Request Response Service
7
10
  *
@@ -14,11 +17,14 @@ import { DEFAULT_SUB_PROTOCOL_HANDLERS, } from './interface.js';
14
17
  * see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#the-reqresp-domain
15
18
  */
16
19
  export class ReqResp {
17
- constructor(libp2p) {
20
+ constructor(config, libp2p) {
18
21
  this.libp2p = libp2p;
19
22
  this.abortController = new AbortController();
20
23
  this.subProtocolHandlers = DEFAULT_SUB_PROTOCOL_HANDLERS;
21
24
  this.logger = createDebugLogger('aztec:p2p:reqresp');
25
+ this.overallRequestTimeoutMs = config.overallRequestTimeoutMs;
26
+ this.individualRequestTimeoutMs = config.individualRequestTimeoutMs;
27
+ this.rateLimiter = new RequestResponseRateLimiter();
22
28
  }
23
29
  /**
24
30
  * Start the reqresp service
@@ -29,6 +35,7 @@ export class ReqResp {
29
35
  for (const subProtocol of Object.keys(this.subProtocolHandlers)) {
30
36
  await this.libp2p.handle(subProtocol, this.streamHandler.bind(this, subProtocol));
31
37
  }
38
+ this.rateLimiter.start();
32
39
  }
33
40
  /**
34
41
  * Stop the reqresp service
@@ -38,6 +45,7 @@ export class ReqResp {
38
45
  for (const protocol of Object.keys(this.subProtocolHandlers)) {
39
46
  await this.libp2p.unhandle(protocol);
40
47
  }
48
+ this.rateLimiter.stop();
41
49
  await this.libp2p.stop();
42
50
  this.abortController.abort();
43
51
  }
@@ -49,18 +57,27 @@ export class ReqResp {
49
57
  * @returns - The response from the peer, otherwise undefined
50
58
  */
51
59
  async sendRequest(subProtocol, payload) {
52
- // Get active peers
53
- const peers = this.libp2p.getPeers();
54
- // Attempt to ask all of our peers
55
- for (const peer of peers) {
56
- const response = await this.sendRequestToPeer(peer, subProtocol, payload);
57
- // If we get a response, return it, otherwise we iterate onto the next peer
58
- // We do not consider it a success if we have an empty buffer
59
- if (response && response.length > 0) {
60
- return response;
60
+ const requestFunction = async () => {
61
+ // Get active peers
62
+ const peers = this.libp2p.getPeers();
63
+ // Attempt to ask all of our peers
64
+ for (const peer of peers) {
65
+ const response = await this.sendRequestToPeer(peer, subProtocol, payload);
66
+ // If we get a response, return it, otherwise we iterate onto the next peer
67
+ // We do not consider it a success if we have an empty buffer
68
+ if (response && response.length > 0) {
69
+ return response;
70
+ }
61
71
  }
72
+ return undefined;
73
+ };
74
+ try {
75
+ return await executeTimeoutWithCustomError(requestFunction, this.overallRequestTimeoutMs, () => new CollectiveReqRespTimeoutError());
76
+ }
77
+ catch (e) {
78
+ this.logger.error(`${e.message} | subProtocol: ${subProtocol}`);
79
+ return undefined;
62
80
  }
63
- return undefined;
64
81
  }
65
82
  /**
66
83
  * Sends a request to a specific peer
@@ -71,15 +88,30 @@ export class ReqResp {
71
88
  * @returns If the request is successful, the response is returned, otherwise undefined
72
89
  */
73
90
  async sendRequestToPeer(peerId, subProtocol, payload) {
91
+ let stream;
74
92
  try {
75
- const stream = await this.libp2p.dialProtocol(peerId, subProtocol);
76
- const result = await pipe([payload], stream, this.readMessage);
93
+ stream = await this.libp2p.dialProtocol(peerId, subProtocol);
94
+ this.logger.debug(`Stream opened with ${peerId.toString()} for ${subProtocol}`);
95
+ const result = await executeTimeoutWithCustomError(() => pipe([payload], stream, this.readMessage), this.individualRequestTimeoutMs, () => new IndiviualReqRespTimeoutError());
96
+ await stream.close();
97
+ this.logger.debug(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
77
98
  return result;
78
99
  }
79
100
  catch (e) {
80
- this.logger.warn(`Failed to send request to peer ${peerId.publicKey}`);
81
- return undefined;
101
+ this.logger.error(`${e.message} | peerId: ${peerId.toString()} | subProtocol: ${subProtocol}`);
82
102
  }
103
+ finally {
104
+ if (stream) {
105
+ try {
106
+ await stream.close();
107
+ this.logger.debug(`Stream closed with ${peerId.toString()} for ${subProtocol}`);
108
+ }
109
+ catch (closeError) {
110
+ this.logger.error(`Error closing stream: ${closeError instanceof Error ? closeError.message : 'Unknown error'}`);
111
+ }
112
+ }
113
+ }
114
+ return undefined;
83
115
  }
84
116
  /**
85
117
  * Read a message returned from a stream into a single buffer
@@ -98,8 +130,14 @@ export class ReqResp {
98
130
  *
99
131
  * @param param0 - The incoming stream data
100
132
  */
101
- async streamHandler(protocol, { stream }) {
133
+ async streamHandler(protocol, { stream, connection }) {
102
134
  // Store a reference to from this for the async generator
135
+ if (!this.rateLimiter.allow(protocol, connection.remotePeer)) {
136
+ this.logger.warn(`Rate limit exceeded for ${protocol} from ${connection.remotePeer}`);
137
+ // TODO(#8483): handle changing peer scoring for failed rate limit, maybe differentiate between global and peer limits here when punishing
138
+ await stream.close();
139
+ return;
140
+ }
103
141
  const handler = this.subProtocolHandlers[protocol];
104
142
  try {
105
143
  await pipe(stream, async function* (source) {
@@ -117,4 +155,4 @@ export class ReqResp {
117
155
  }
118
156
  }
119
157
  }
120
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxcmVzcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlL3JlcXJlc3AvcmVxcmVzcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw4Q0FBOEM7QUFDOUMsT0FBTyxFQUFlLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFHdkUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUkvQixPQUFPLEVBQ0wsNkJBQTZCLEdBRzlCLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEI7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sT0FBTyxPQUFPO0lBT2xCLFlBQStCLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBSnJDLG9CQUFlLEdBQW9CLElBQUksZUFBZSxFQUFFLENBQUM7UUFFekQsd0JBQW1CLEdBQStCLDZCQUE2QixDQUFDO1FBR3RGLElBQUksQ0FBQyxNQUFNLEdBQUcsaUJBQWlCLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsS0FBSyxDQUFDLG1CQUErQztRQUN6RCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsbUJBQW1CLENBQUM7UUFDL0MsaUNBQWlDO1FBQ2pDLEtBQUssTUFBTSxXQUFXLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDO1lBQ2hFLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxXQUFpQyxDQUFDLENBQUMsQ0FBQztRQUMxRyxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLElBQUk7UUFDUiwwQkFBMEI7UUFDMUIsS0FBSyxNQUFNLFFBQVEsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7WUFDN0QsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxXQUFXLENBQUMsV0FBK0IsRUFBRSxPQUFlO1FBQ2hFLG1CQUFtQjtRQUNuQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRXJDLGtDQUFrQztRQUNsQyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFFMUUsMkVBQTJFO1lBQzNFLDZEQUE2RDtZQUM3RCxJQUFJLFFBQVEsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNwQyxPQUFPLFFBQVEsQ0FBQztZQUNsQixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLGlCQUFpQixDQUNyQixNQUFjLEVBQ2QsV0FBK0IsRUFDL0IsT0FBZTtRQUVmLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBRW5FLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMvRCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUN2RSxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFxQztRQUM3RCxNQUFNLE1BQU0sR0FBaUIsRUFBRSxDQUFDO1FBQ2hDLElBQUksS0FBSyxFQUFFLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDaEMsQ0FBQztRQUNELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNwQyxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssS0FBSyxDQUFDLGFBQWEsQ0FBQyxRQUE0QixFQUFFLEVBQUUsTUFBTSxFQUFzQjtRQUN0Rix5REFBeUQ7UUFDekQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRW5ELElBQUksQ0FBQztZQUNILE1BQU0sSUFBSSxDQUNSLE1BQU0sRUFDTixLQUFLLFNBQVMsQ0FBQyxFQUFFLE1BQVc7Z0JBQzFCLElBQUksS0FBSyxFQUFFLE1BQU0sU0FBUyxJQUFJLE1BQU0sRUFBRSxDQUFDO29CQUNyQyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO29CQUM5QyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDckIsQ0FBQztZQUNILENBQUMsRUFDRCxNQUFNLENBQ1AsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RCLENBQUM7Z0JBQVMsQ0FBQztZQUNULE1BQU0sTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3ZCLENBQUM7SUFDSCxDQUFDO0NBQ0YifQ==
158
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxcmVzcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlL3JlcXJlc3AvcmVxcmVzcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSw4Q0FBOEM7QUFDOUMsT0FBTyxFQUFlLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdkUsT0FBTyxFQUFFLDZCQUE2QixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFHeEUsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUkvQixPQUFPLEVBQUUsNkJBQTZCLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUU1RyxPQUFPLEVBQ0wsNkJBQTZCLEdBRzlCLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFNUU7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sT0FBTyxPQUFPO0lBV2xCLFlBQVksTUFBd0IsRUFBcUIsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7UUFSL0Qsb0JBQWUsR0FBb0IsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUt6RCx3QkFBbUIsR0FBK0IsNkJBQTZCLENBQUM7UUFJdEYsSUFBSSxDQUFDLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBRXJELElBQUksQ0FBQyx1QkFBdUIsR0FBRyxNQUFNLENBQUMsdUJBQXVCLENBQUM7UUFDOUQsSUFBSSxDQUFDLDBCQUEwQixHQUFHLE1BQU0sQ0FBQywwQkFBMEIsQ0FBQztRQUVwRSxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksMEJBQTBCLEVBQUUsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsS0FBSyxDQUFDLG1CQUErQztRQUN6RCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsbUJBQW1CLENBQUM7UUFDL0MsaUNBQWlDO1FBQ2pDLEtBQUss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
@@ -35,7 +35,7 @@ export interface P2PService {
35
35
  * @returns The response type, corresponding to the protocol
36
36
  */
37
37
  sendRequest<Protocol extends ReqRespSubProtocol>(protocol: Protocol, request: InstanceType<SubProtocolMap[Protocol]['request']>): Promise<InstanceType<SubProtocolMap[Protocol]['response']> | undefined>;
38
- registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation>): void;
38
+ registerBlockReceivedCallback(callback: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
39
39
  getEnr(): ENR | undefined;
40
40
  }
41
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service/service.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEtF,oBAAY,kBAAkB;IAC5B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;OAGG;IACH,SAAS,CAAC,CAAC,SAAS,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;IAElD;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,SAAS,kBAAkB,EAC7C,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,GACzD,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAG3E,6BAA6B,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;IAEnG,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD;;SAEK;IACL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;SAEK;IACL,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;OAGG;IACH,WAAW,IAAI,GAAG,EAAE,CAAC;IAErB;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC;;;;OAIG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAEzC;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAElD,SAAS,IAAI,kBAAkB,CAAC;IAEhC,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC;CAC3B"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service/service.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAEvC,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEtF,oBAAY,kBAAkB;IAC5B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;OAGG;IACH,SAAS,CAAC,CAAC,SAAS,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC;IAElD;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,SAAS,kBAAkB,EAC7C,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,GACzD,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAG3E,6BAA6B,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;IAE/G,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD;;SAEK;IACL,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;SAEK;IACL,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;;OAGG;IACH,WAAW,IAAI,GAAG,EAAE,CAAC;IAErB;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC;;;;OAIG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAEzC;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAElD,SAAS,IAAI,kBAAkB,CAAC;IAEhC,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC;CAC3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/p2p",
3
- "version": "0.53.0",
3
+ "version": "0.55.0",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "typedocOptions": {
@@ -56,11 +56,11 @@
56
56
  "testTimeout": 15000
57
57
  },
58
58
  "dependencies": {
59
- "@aztec/circuit-types": "0.53.0",
60
- "@aztec/circuits.js": "0.53.0",
61
- "@aztec/foundation": "0.53.0",
62
- "@aztec/kv-store": "0.53.0",
63
- "@aztec/telemetry-client": "0.53.0",
59
+ "@aztec/circuit-types": "0.55.0",
60
+ "@aztec/circuits.js": "0.55.0",
61
+ "@aztec/foundation": "0.55.0",
62
+ "@aztec/kv-store": "0.55.0",
63
+ "@aztec/telemetry-client": "0.55.0",
64
64
  "@chainsafe/discv5": "9.0.0",
65
65
  "@chainsafe/enr": "3.0.0",
66
66
  "@chainsafe/libp2p-gossipsub": "13.0.0",
@@ -1,6 +1,7 @@
1
- import { BlockAttestation, Signature } from '@aztec/circuit-types';
1
+ import { BlockAttestation, Signature, TxHash } from '@aztec/circuit-types';
2
2
  import { makeHeader } from '@aztec/circuits.js/testing';
3
3
  import { Fr } from '@aztec/foundation/fields';
4
+ import { serializeToBuffer } from '@aztec/foundation/serialize';
4
5
 
5
6
  import { type PrivateKeyAccount } from 'viem';
6
7
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
@@ -25,9 +26,11 @@ export const mockAttestation = async (signer: PrivateKeyAccount, slot: number =
25
26
  // Use arbitrary numbers for all other than slot
26
27
  const header = makeHeader(1, 2, slot);
27
28
  const archive = Fr.random();
28
- const message = archive.toString();
29
+ const txs = [0, 1, 2, 3, 4, 5].map(() => TxHash.random());
30
+
31
+ const message: `0x${string}` = `0x${serializeToBuffer([archive, txs]).toString('hex')}`;
29
32
  const sigString = await signer.signMessage({ message });
30
33
 
31
34
  const signature = Signature.from0xString(sigString);
32
- return new BlockAttestation(header, archive, signature);
35
+ return new BlockAttestation(header, archive, txs, signature);
33
36
  };
@@ -70,7 +70,14 @@ export interface P2P {
70
70
  */
71
71
  // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
72
72
  // ^ This pattern is not my favorite (md)
73
- registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation>): void;
73
+ registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void;
74
+
75
+ /**
76
+ * Request a list of transactions from another peer by their tx hashes.
77
+ * @param txHashes - Hashes of the txs to query.
78
+ * @returns A list of transactions or undefined if the transactions are not found.
79
+ */
80
+ requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]>;
74
81
 
75
82
  /**
76
83
  * Request a transaction from another peer by its tx hash.
@@ -270,6 +277,7 @@ export class P2PClient implements P2P {
270
277
  }
271
278
 
272
279
  public broadcastProposal(proposal: BlockProposal): void {
280
+ this.log.verbose(`Broadcasting proposal ${proposal.p2pMessageIdentifier()} to peers`);
273
281
  return this.p2pService.propagate(proposal);
274
282
  }
275
283
 
@@ -279,13 +287,44 @@ export class P2PClient implements P2P {
279
287
 
280
288
  // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963
281
289
  // ^ This pattern is not my favorite (md)
282
- public registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation>): void {
290
+ public registerBlockProposalHandler(handler: (block: BlockProposal) => Promise<BlockAttestation | undefined>): void {
283
291
  this.p2pService.registerBlockReceivedCallback(handler);
284
292
  }
285
293
 
286
- public requestTxByHash(txHash: TxHash): Promise<Tx | undefined> {
287
- // Underlying I want to use the libp2p service to just have a request method where the subprotocol is defined here
288
- return this.p2pService.sendRequest(TX_REQ_PROTOCOL, txHash);
294
+ /**
295
+ * Requests the transactions with the given hashes from the network.
296
+ *
297
+ * If a transaction can be retrieved, it will be returned, if not an undefined
298
+ * will be returned. In place.
299
+ *
300
+ * @param txHashes - The hashes of the transactions to request.
301
+ * @returns A promise that resolves to an array of transactions or undefined.
302
+ */
303
+ public requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
304
+ const requestPromises = txHashes.map(txHash => this.requestTxByHash(txHash));
305
+ return Promise.all(requestPromises);
306
+ }
307
+
308
+ /**
309
+ * Uses the Request Response protocol to request a transaction from the network.
310
+ *
311
+ * If the underlying request response protocol fails, then we return undefined.
312
+ * If it succeeds then we add the transaction to our transaction pool and return.
313
+ *
314
+ * @param txHash - The hash of the transaction to request.
315
+ * @returns A promise that resolves to a transaction or undefined.
316
+ */
317
+ public async requestTxByHash(txHash: TxHash): Promise<Tx | undefined> {
318
+ const tx = await this.p2pService.sendRequest(TX_REQ_PROTOCOL, txHash);
319
+
320
+ this.log.debug(`Requested ${txHash.toString()} from peer | success = ${!!tx}`);
321
+ if (tx) {
322
+ // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8485): This check is not sufficient to validate the transaction. We need to validate the entire proof.
323
+ // TODO(https://github.com/AztecProtocol/aztec-packages/issues/8483): alter peer scoring system for a validator that returns an invalid transcation
324
+ await this.txPool.addTxs([tx]);
325
+ }
326
+
327
+ return tx;
289
328
  }
290
329
 
291
330
  /**