@lodestar/builder 1.50.0-dev.f2fb26d453 → 1.50.0-dev.fd4f342a40

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.
@@ -0,0 +1,42 @@
1
+ import { LodestarError } from "@lodestar/utils";
2
+ import { type BuildRequest, type BuiltPayload, type PayloadSource } from "./payloadSource.js";
3
+ export type PayloadBuildJob = {
4
+ /** Jobs with the same ID share one build and its result. */
5
+ id: string;
6
+ request: BuildRequest;
7
+ /** Unix timestamp in milliseconds at which the prepared payload should be retrieved. */
8
+ getPayloadAt: number;
9
+ };
10
+ export type PayloadOrchestratorOptions = {
11
+ /** Maximum time in milliseconds to wait for payload retrieval. */
12
+ getPayloadTimeout: number;
13
+ };
14
+ export declare enum PayloadOrchestratorErrorCode {
15
+ PREPARE_DEADLINE_REACHED = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_DEADLINE_REACHED",
16
+ PREPARE_TIMEOUT = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_TIMEOUT",
17
+ GET_PAYLOAD_TIMEOUT = "PAYLOAD_ORCHESTRATOR_ERROR_GET_PAYLOAD_TIMEOUT"
18
+ }
19
+ export type PayloadOrchestratorErrorType = {
20
+ code: PayloadOrchestratorErrorCode.PREPARE_DEADLINE_REACHED;
21
+ jobId: string;
22
+ getPayloadAt: number;
23
+ } | {
24
+ code: PayloadOrchestratorErrorCode.PREPARE_TIMEOUT | PayloadOrchestratorErrorCode.GET_PAYLOAD_TIMEOUT;
25
+ jobId: string;
26
+ };
27
+ export declare class PayloadOrchestratorError extends LodestarError<PayloadOrchestratorErrorType> {
28
+ }
29
+ /**
30
+ * Prepares a payload and retrieves it at the requested time. Preparation retries missing payload IDs until the
31
+ * retrieval time. Transport-level retries remain owned by the source.
32
+ */
33
+ export declare class PayloadOrchestrator {
34
+ private readonly source;
35
+ private readonly options;
36
+ private readonly signal;
37
+ private readonly jobs;
38
+ constructor(source: PayloadSource, options: PayloadOrchestratorOptions, signal: AbortSignal);
39
+ run(job: PayloadBuildJob): Promise<BuiltPayload>;
40
+ private runJob;
41
+ }
42
+ //# sourceMappingURL=payloadOrchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payloadOrchestrator.d.ts","sourceRoot":"","sources":["../../src/services/payloadOrchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAA0C,MAAM,iBAAiB,CAAC;AACvF,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,MAAM,eAAe,GAAG;IAC5B,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,kEAAkE;IAClE,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,oBAAY,4BAA4B;IACtC,wBAAwB,wDAAwD;IAChF,eAAe,+CAA+C;IAC9D,mBAAmB,mDAAmD;CACvE;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,IAAI,EAAE,4BAA4B,CAAC,wBAAwB,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,4BAA4B,CAAC,eAAe,GAAG,4BAA4B,CAAC,mBAAmB,CAAC;IACtG,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,qBAAa,wBAAyB,SAAQ,aAAa,CAAC,4BAA4B,CAAC;CAAG;AAE5F;;;GAGG;AACH,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4C;IAEjE,YACmB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,0BAA0B,EACnC,MAAM,EAAE,WAAW,EAClC;IAEJ,GAAG,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAQ/C;YAEa,MAAM;CAwCrB"}
@@ -0,0 +1,60 @@
1
+ import { LodestarError, TimeoutError, retry, sleep, withTimeout } from "@lodestar/utils";
2
+ import { PayloadSourceError, PayloadSourceErrorCode, } from "./payloadSource.js";
3
+ const PREPARE_RETRY_DELAY = 100;
4
+ export var PayloadOrchestratorErrorCode;
5
+ (function (PayloadOrchestratorErrorCode) {
6
+ PayloadOrchestratorErrorCode["PREPARE_DEADLINE_REACHED"] = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_DEADLINE_REACHED";
7
+ PayloadOrchestratorErrorCode["PREPARE_TIMEOUT"] = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_TIMEOUT";
8
+ PayloadOrchestratorErrorCode["GET_PAYLOAD_TIMEOUT"] = "PAYLOAD_ORCHESTRATOR_ERROR_GET_PAYLOAD_TIMEOUT";
9
+ })(PayloadOrchestratorErrorCode || (PayloadOrchestratorErrorCode = {}));
10
+ export class PayloadOrchestratorError extends LodestarError {
11
+ }
12
+ /**
13
+ * Prepares a payload and retrieves it at the requested time. Preparation retries missing payload IDs until the
14
+ * retrieval time. Transport-level retries remain owned by the source.
15
+ */
16
+ export class PayloadOrchestrator {
17
+ source;
18
+ options;
19
+ signal;
20
+ jobs = new Map();
21
+ constructor(source, options, signal) {
22
+ this.source = source;
23
+ this.options = options;
24
+ this.signal = signal;
25
+ }
26
+ run(job) {
27
+ const { id } = job;
28
+ let promise = this.jobs.get(id);
29
+ if (promise === undefined) {
30
+ promise = this.runJob(job).finally(() => this.jobs.delete(id));
31
+ this.jobs.set(id, promise);
32
+ }
33
+ return promise;
34
+ }
35
+ async runJob({ id, request, getPayloadAt }) {
36
+ const prepareTimeout = getPayloadAt - Date.now();
37
+ if (!(prepareTimeout > 0)) {
38
+ throw new PayloadOrchestratorError({ code: PayloadOrchestratorErrorCode.PREPARE_DEADLINE_REACHED, jobId: id, getPayloadAt }, `Payload preparation deadline reached jobId=${id} getPayloadAt=${getPayloadAt}`);
39
+ }
40
+ const handle = await withTimeout((signal = this.signal) => retry(() => this.source.prepare(request, signal), {
41
+ retries: Infinity,
42
+ retryDelay: PREPARE_RETRY_DELAY,
43
+ shouldRetry: (error) => error instanceof PayloadSourceError && error.type.code === PayloadSourceErrorCode.NO_PAYLOAD_ID,
44
+ signal,
45
+ }), prepareTimeout, this.signal).catch((error) => {
46
+ if (error instanceof TimeoutError) {
47
+ throw new PayloadOrchestratorError({ code: PayloadOrchestratorErrorCode.PREPARE_TIMEOUT, jobId: id });
48
+ }
49
+ throw error;
50
+ });
51
+ await sleep(getPayloadAt - Date.now(), this.signal);
52
+ return withTimeout((signal = this.signal) => this.source.getPayload(handle, signal), this.options.getPayloadTimeout, this.signal).catch((error) => {
53
+ if (error instanceof TimeoutError) {
54
+ throw new PayloadOrchestratorError({ code: PayloadOrchestratorErrorCode.GET_PAYLOAD_TIMEOUT, jobId: id });
55
+ }
56
+ throw error;
57
+ });
58
+ }
59
+ }
60
+ //# sourceMappingURL=payloadOrchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payloadOrchestrator.js","sourceRoot":"","sources":["../../src/services/payloadOrchestrator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lodestar/builder",
3
- "version": "1.50.0-dev.f2fb26d453",
3
+ "version": "1.50.0-dev.fd4f342a40",
4
4
  "description": "A Typescript implementation of the builder client",
5
5
  "author": "ChainSafe Systems",
6
6
  "license": "Apache-2.0",
@@ -48,16 +48,16 @@
48
48
  "dependencies": {
49
49
  "@chainsafe/lodestar-z": "catalog:",
50
50
  "@chainsafe/ssz": "^1.8.0",
51
- "@lodestar/api": "^1.50.0-dev.f2fb26d453",
52
- "@lodestar/config": "^1.50.0-dev.f2fb26d453",
53
- "@lodestar/params": "^1.50.0-dev.f2fb26d453",
54
- "@lodestar/state-transition": "^1.50.0-dev.f2fb26d453",
55
- "@lodestar/types": "^1.50.0-dev.f2fb26d453",
56
- "@lodestar/utils": "^1.50.0-dev.f2fb26d453"
51
+ "@lodestar/api": "^1.50.0-dev.fd4f342a40",
52
+ "@lodestar/config": "^1.50.0-dev.fd4f342a40",
53
+ "@lodestar/params": "^1.50.0-dev.fd4f342a40",
54
+ "@lodestar/state-transition": "^1.50.0-dev.fd4f342a40",
55
+ "@lodestar/types": "^1.50.0-dev.fd4f342a40",
56
+ "@lodestar/utils": "^1.50.0-dev.fd4f342a40"
57
57
  },
58
58
  "devDependencies": {
59
- "@lodestar/logger": "^1.50.0-dev.f2fb26d453",
60
- "@lodestar/test-utils": "^1.50.0-dev.f2fb26d453"
59
+ "@lodestar/logger": "^1.50.0-dev.fd4f342a40",
60
+ "@lodestar/test-utils": "^1.50.0-dev.fd4f342a40"
61
61
  },
62
- "gitHead": "639434e12d5aa481d4e1334c8cd43561f0d1da33"
62
+ "gitHead": "d6b5b265be7298e02833b90a83b8cab3b4decc9c"
63
63
  }
@@ -0,0 +1,107 @@
1
+ import {LodestarError, TimeoutError, retry, sleep, withTimeout} from "@lodestar/utils";
2
+ import {
3
+ type BuildRequest,
4
+ type BuiltPayload,
5
+ type PayloadSource,
6
+ PayloadSourceError,
7
+ PayloadSourceErrorCode,
8
+ } from "./payloadSource.js";
9
+
10
+ const PREPARE_RETRY_DELAY = 100;
11
+
12
+ export type PayloadBuildJob = {
13
+ /** Jobs with the same ID share one build and its result. */
14
+ id: string;
15
+ request: BuildRequest;
16
+ /** Unix timestamp in milliseconds at which the prepared payload should be retrieved. */
17
+ getPayloadAt: number;
18
+ };
19
+
20
+ export type PayloadOrchestratorOptions = {
21
+ /** Maximum time in milliseconds to wait for payload retrieval. */
22
+ getPayloadTimeout: number;
23
+ };
24
+
25
+ export enum PayloadOrchestratorErrorCode {
26
+ PREPARE_DEADLINE_REACHED = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_DEADLINE_REACHED",
27
+ PREPARE_TIMEOUT = "PAYLOAD_ORCHESTRATOR_ERROR_PREPARE_TIMEOUT",
28
+ GET_PAYLOAD_TIMEOUT = "PAYLOAD_ORCHESTRATOR_ERROR_GET_PAYLOAD_TIMEOUT",
29
+ }
30
+
31
+ export type PayloadOrchestratorErrorType =
32
+ | {
33
+ code: PayloadOrchestratorErrorCode.PREPARE_DEADLINE_REACHED;
34
+ jobId: string;
35
+ getPayloadAt: number;
36
+ }
37
+ | {
38
+ code: PayloadOrchestratorErrorCode.PREPARE_TIMEOUT | PayloadOrchestratorErrorCode.GET_PAYLOAD_TIMEOUT;
39
+ jobId: string;
40
+ };
41
+
42
+ export class PayloadOrchestratorError extends LodestarError<PayloadOrchestratorErrorType> {}
43
+
44
+ /**
45
+ * Prepares a payload and retrieves it at the requested time. Preparation retries missing payload IDs until the
46
+ * retrieval time. Transport-level retries remain owned by the source.
47
+ */
48
+ export class PayloadOrchestrator {
49
+ private readonly jobs = new Map<string, Promise<BuiltPayload>>();
50
+
51
+ constructor(
52
+ private readonly source: PayloadSource,
53
+ private readonly options: PayloadOrchestratorOptions,
54
+ private readonly signal: AbortSignal
55
+ ) {}
56
+
57
+ run(job: PayloadBuildJob): Promise<BuiltPayload> {
58
+ const {id} = job;
59
+ let promise = this.jobs.get(id);
60
+ if (promise === undefined) {
61
+ promise = this.runJob(job).finally(() => this.jobs.delete(id));
62
+ this.jobs.set(id, promise);
63
+ }
64
+ return promise;
65
+ }
66
+
67
+ private async runJob({id, request, getPayloadAt}: PayloadBuildJob): Promise<BuiltPayload> {
68
+ const prepareTimeout = getPayloadAt - Date.now();
69
+ if (!(prepareTimeout > 0)) {
70
+ throw new PayloadOrchestratorError(
71
+ {code: PayloadOrchestratorErrorCode.PREPARE_DEADLINE_REACHED, jobId: id, getPayloadAt},
72
+ `Payload preparation deadline reached jobId=${id} getPayloadAt=${getPayloadAt}`
73
+ );
74
+ }
75
+
76
+ const handle = await withTimeout(
77
+ (signal = this.signal) =>
78
+ retry(() => this.source.prepare(request, signal), {
79
+ retries: Infinity,
80
+ retryDelay: PREPARE_RETRY_DELAY,
81
+ shouldRetry: (error) =>
82
+ error instanceof PayloadSourceError && error.type.code === PayloadSourceErrorCode.NO_PAYLOAD_ID,
83
+ signal,
84
+ }),
85
+ prepareTimeout,
86
+ this.signal
87
+ ).catch((error: unknown) => {
88
+ if (error instanceof TimeoutError) {
89
+ throw new PayloadOrchestratorError({code: PayloadOrchestratorErrorCode.PREPARE_TIMEOUT, jobId: id});
90
+ }
91
+ throw error;
92
+ });
93
+
94
+ await sleep(getPayloadAt - Date.now(), this.signal);
95
+
96
+ return withTimeout(
97
+ (signal = this.signal) => this.source.getPayload(handle, signal),
98
+ this.options.getPayloadTimeout,
99
+ this.signal
100
+ ).catch((error: unknown) => {
101
+ if (error instanceof TimeoutError) {
102
+ throw new PayloadOrchestratorError({code: PayloadOrchestratorErrorCode.GET_PAYLOAD_TIMEOUT, jobId: id});
103
+ }
104
+ throw error;
105
+ });
106
+ }
107
+ }