@aztec/p2p 0.54.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.
- package/dest/attestation_pool/mocks.d.ts.map +1 -1
- package/dest/attestation_pool/mocks.js +6 -4
- package/dest/client/p2p_client.d.ts +27 -2
- package/dest/client/p2p_client.d.ts.map +1 -1
- package/dest/client/p2p_client.js +33 -4
- package/dest/config.d.ts +2 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +3 -1
- package/dest/errors/reqresp.error.d.ts +17 -0
- package/dest/errors/reqresp.error.d.ts.map +1 -0
- package/dest/errors/reqresp.error.js +21 -0
- package/dest/mocks/index.d.ts.map +1 -1
- package/dest/mocks/index.js +6 -2
- package/dest/service/libp2p_service.js +3 -3
- package/dest/service/reqresp/config.d.ts +16 -0
- package/dest/service/reqresp/config.d.ts.map +1 -0
- package/dest/service/reqresp/config.js +21 -0
- package/dest/service/reqresp/interface.d.ts +30 -3
- package/dest/service/reqresp/interface.d.ts.map +1 -1
- package/dest/service/reqresp/interface.js +4 -4
- package/dest/service/reqresp/rate_limiter/index.d.ts +2 -0
- package/dest/service/reqresp/rate_limiter/index.d.ts.map +1 -0
- package/dest/service/reqresp/rate_limiter/index.js +2 -0
- package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts +97 -0
- package/dest/service/reqresp/rate_limiter/rate_limiter.d.ts.map +1 -0
- package/dest/service/reqresp/rate_limiter/rate_limiter.js +148 -0
- package/dest/service/reqresp/rate_limiter/rate_limits.d.ts +3 -0
- package/dest/service/reqresp/rate_limiter/rate_limits.d.ts.map +1 -0
- package/dest/service/reqresp/rate_limiter/rate_limits.js +35 -0
- package/dest/service/reqresp/reqresp.d.ts +5 -1
- package/dest/service/reqresp/reqresp.d.ts.map +1 -1
- package/dest/service/reqresp/reqresp.js +55 -17
- package/dest/service/service.d.ts +1 -1
- package/dest/service/service.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/attestation_pool/mocks.ts +6 -3
- package/src/client/p2p_client.ts +44 -5
- package/src/config.ts +4 -1
- package/src/errors/reqresp.error.ts +21 -0
- package/src/mocks/index.ts +6 -1
- package/src/service/libp2p_service.ts +2 -2
- package/src/service/reqresp/config.ts +35 -0
- package/src/service/reqresp/interface.ts +33 -3
- package/src/service/reqresp/rate_limiter/index.ts +1 -0
- package/src/service/reqresp/rate_limiter/rate_limiter.ts +198 -0
- package/src/service/reqresp/rate_limiter/rate_limits.ts +35 -0
- package/src/service/reqresp/reqresp.ts +78 -20
- 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZV9saW1pdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3NlcnZpY2UvcmVxcmVzcC9yYXRlX2xpbWl0ZXIvcmF0ZV9saW1pdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRXZELGdEQUFnRDtBQUNoRCxNQUFNLG9DQUFvQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBRTVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFRMUI7OztPQUdHO0lBQ0gsWUFBWSxVQUFrQixFQUFFLFdBQW1CO1FBQ2pELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxXQUFXLEdBQUcsVUFBVSxDQUFDO1FBQ2pELElBQUksQ0FBQyxhQUFhLEdBQUcsV0FBVyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxLQUFLO1FBQ0gsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRXZCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUM7UUFDL0QsSUFBSSxNQUFNLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQztZQUNsQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRjtBQVNEOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUNILE1BQU0sT0FBTyxzQkFBc0I7SUFNakMsWUFBWSxjQUFzQixFQUFFLGVBQXVCLEVBQUUsZ0JBQXdCLEVBQUUs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
|
|
@@ -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
|
-
|
|
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;
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
76
|
-
|
|
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.
|
|
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,
|
|
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;
|
|
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.
|
|
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.
|
|
60
|
-
"@aztec/circuits.js": "0.
|
|
61
|
-
"@aztec/foundation": "0.
|
|
62
|
-
"@aztec/kv-store": "0.
|
|
63
|
-
"@aztec/telemetry-client": "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
|
|
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
|
};
|
package/src/client/p2p_client.ts
CHANGED
|
@@ -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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
/**
|