@chainsafe/lodestar 1.47.0-dev.ec596194e2 → 1.47.0-dev.f0f26cd2b6
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/.git-data.json +1 -1
- package/lib/cmds/beacon/handler.d.ts.map +1 -1
- package/lib/cmds/beacon/handler.js +10 -4
- package/lib/cmds/beacon/handler.js.map +1 -1
- package/lib/cmds/builder/handler.d.ts.map +1 -1
- package/lib/cmds/builder/handler.js +19 -3
- package/lib/cmds/builder/handler.js.map +1 -1
- package/lib/cmds/builder/loadKeypair.d.ts +2 -1
- package/lib/cmds/builder/loadKeypair.d.ts.map +1 -1
- package/lib/cmds/builder/loadKeypair.js +3 -2
- package/lib/cmds/builder/loadKeypair.js.map +1 -1
- package/lib/cmds/builder/options.d.ts +8 -0
- package/lib/cmds/builder/options.d.ts.map +1 -1
- package/lib/cmds/builder/options.js +24 -0
- package/lib/cmds/builder/options.js.map +1 -1
- package/lib/cmds/dev/options.d.ts +4 -0
- package/lib/cmds/dev/options.d.ts.map +1 -1
- package/lib/cmds/validator/blsToExecutionChange.js +1 -1
- package/lib/cmds/validator/blsToExecutionChange.js.map +1 -1
- package/lib/cmds/validator/handler.d.ts.map +1 -1
- package/lib/cmds/validator/handler.js +15 -2
- package/lib/cmds/validator/handler.js.map +1 -1
- package/lib/cmds/validator/keymanager/decryptKeystoreDefinitions.js +1 -1
- package/lib/cmds/validator/keymanager/decryptKeystoreDefinitions.js.map +1 -1
- package/lib/cmds/validator/keymanager/impl.d.ts +13 -2
- package/lib/cmds/validator/keymanager/impl.d.ts.map +1 -1
- package/lib/cmds/validator/keymanager/impl.js +41 -4
- package/lib/cmds/validator/keymanager/impl.js.map +1 -1
- package/lib/cmds/validator/keymanager/keystoreCache.js +1 -1
- package/lib/cmds/validator/keymanager/keystoreCache.js.map +1 -1
- package/lib/cmds/validator/keymanager/persistedKeys.d.ts.map +1 -1
- package/lib/cmds/validator/keymanager/persistedKeys.js +3 -1
- package/lib/cmds/validator/keymanager/persistedKeys.js.map +1 -1
- package/lib/cmds/validator/options.d.ts +4 -0
- package/lib/cmds/validator/options.d.ts.map +1 -1
- package/lib/cmds/validator/options.js +24 -0
- package/lib/cmds/validator/options.js.map +1 -1
- package/lib/cmds/validator/signers/index.js +1 -1
- package/lib/cmds/validator/signers/index.js.map +1 -1
- package/lib/cmds/validator/voluntaryExit.js +1 -1
- package/lib/cmds/validator/voluntaryExit.js.map +1 -1
- package/lib/networks/chiado.d.ts.map +1 -1
- package/lib/networks/chiado.js +4 -10
- package/lib/networks/chiado.js.map +1 -1
- package/lib/options/beaconNodeOptions/builder.d.ts.map +1 -1
- package/lib/options/beaconNodeOptions/builder.js +2 -2
- package/lib/options/beaconNodeOptions/builder.js.map +1 -1
- package/lib/options/beaconNodeOptions/chain.d.ts.map +1 -1
- package/lib/options/beaconNodeOptions/chain.js +1 -1
- package/lib/options/beaconNodeOptions/chain.js.map +1 -1
- package/lib/util/format.js +1 -1
- package/lib/util/format.js.map +1 -1
- package/lib/util/proposerConfig.d.ts +16 -11
- package/lib/util/proposerConfig.d.ts.map +1 -1
- package/lib/util/proposerConfig.js +128 -11
- package/lib/util/proposerConfig.js.map +1 -1
- package/package.json +21 -21
- package/src/cmds/beacon/handler.ts +10 -4
- package/src/cmds/builder/handler.ts +24 -4
- package/src/cmds/builder/loadKeypair.ts +5 -1
- package/src/cmds/builder/options.ts +33 -0
- package/src/cmds/validator/blsToExecutionChange.ts +1 -1
- package/src/cmds/validator/handler.ts +29 -2
- package/src/cmds/validator/keymanager/decryptKeystoreDefinitions.ts +1 -1
- package/src/cmds/validator/keymanager/impl.ts +56 -4
- package/src/cmds/validator/keymanager/keystoreCache.ts +1 -1
- package/src/cmds/validator/keymanager/persistedKeys.ts +5 -1
- package/src/cmds/validator/options.ts +36 -0
- package/src/cmds/validator/signers/index.ts +1 -1
- package/src/cmds/validator/voluntaryExit.ts +1 -1
- package/src/networks/chiado.ts +4 -10
- package/src/options/beaconNodeOptions/builder.ts +4 -2
- package/src/options/beaconNodeOptions/chain.ts +2 -1
- package/src/util/format.ts +1 -1
- package/src/util/proposerConfig.ts +152 -13
|
@@ -48,6 +48,10 @@ export type IValidatorCliArgs = AccountValidatorArgs &
|
|
|
48
48
|
builder?: boolean;
|
|
49
49
|
"builder.selection"?: string;
|
|
50
50
|
"builder.boostFactor"?: string;
|
|
51
|
+
"builder.minBid"?: string;
|
|
52
|
+
"builder.urls"?: string[];
|
|
53
|
+
"builder.maxExecutionPayment"?: string;
|
|
54
|
+
allowDangerousTrustedPayments?: boolean;
|
|
51
55
|
|
|
52
56
|
/** @deprecated */
|
|
53
57
|
useProduceBlockV3?: boolean;
|
|
@@ -276,6 +280,38 @@ export const validatorOptions: CliCommandOptions<IValidatorCliArgs> = {
|
|
|
276
280
|
group: "builder",
|
|
277
281
|
},
|
|
278
282
|
|
|
283
|
+
"builder.minBid": {
|
|
284
|
+
type: "string",
|
|
285
|
+
description:
|
|
286
|
+
"Minimum counted total payment in Gwei accepted from a builder bid. The total is the bid value plus its execution payment up to the configured cap. Only used post-Gloas",
|
|
287
|
+
defaultDescription: `${defaultOptions.builderMinBid}`,
|
|
288
|
+
group: "builder",
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
"builder.urls": {
|
|
292
|
+
description:
|
|
293
|
+
"URL(s) of external builders to request execution payload bids from. Auth data agreed with a builder may be appended as a hex fragment, e.g. https://builder.example.com#0x0123, otherwise the UTF-8 bytes of the URL are used. Only used post-Gloas",
|
|
294
|
+
type: "array",
|
|
295
|
+
string: true,
|
|
296
|
+
coerce: (urls: string[]): string[] => urls.flatMap((url) => url.split(",")),
|
|
297
|
+
group: "builder",
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
"builder.maxExecutionPayment": {
|
|
301
|
+
type: "string",
|
|
302
|
+
description:
|
|
303
|
+
"Maximum execution layer payment in Gwei counted toward a builder bid. A value of 0 means only trustless payments via the builder's staked collateral count toward the bid. Values above 0 require `--allowDangerousTrustedPayments`. Only used post-Gloas",
|
|
304
|
+
defaultDescription: `${defaultOptions.builderMaxExecutionPayment}`,
|
|
305
|
+
group: "builder",
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
allowDangerousTrustedPayments: {
|
|
309
|
+
type: "boolean",
|
|
310
|
+
description:
|
|
311
|
+
"Allow configuring a builder max execution payment above 0. Trusted execution layer payments are only backed by the builder's promise to pay, not by its staked collateral, a builder that fails to pay cannot be penalized in protocol",
|
|
312
|
+
group: "builder",
|
|
313
|
+
},
|
|
314
|
+
|
|
279
315
|
useProduceBlockV3: {
|
|
280
316
|
hidden: true,
|
|
281
317
|
deprecated: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import {deriveEth2ValidatorKeys, deriveKeyFromMnemonic} from "@chainsafe/bls-keygen";
|
|
3
|
-
import {SecretKey} from "@chainsafe/blst";
|
|
3
|
+
import {SecretKey} from "@chainsafe/lodestar-z/blst";
|
|
4
4
|
import {interopSecretKey} from "@lodestar/state-transition";
|
|
5
5
|
import {LogLevel, Logger, isValidHttpUrl} from "@lodestar/utils";
|
|
6
6
|
import {Signer, SignerType, externalSignerGetKeys} from "@lodestar/validator";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import inquirer from "inquirer";
|
|
4
|
-
import {Signature} from "@chainsafe/blst";
|
|
4
|
+
import {Signature} from "@chainsafe/lodestar-z/blst";
|
|
5
5
|
import {ApiClient, getClient} from "@lodestar/api";
|
|
6
6
|
import {BeaconConfig, createBeaconConfig} from "@lodestar/config";
|
|
7
7
|
import {
|
package/src/networks/chiado.ts
CHANGED
|
@@ -5,14 +5,8 @@ export const genesisStateRoot = "0xa48419160f8f146ecaa53d12a5d6e1e6af414a328afdc
|
|
|
5
5
|
export const bootnodesFileUrl = "https://raw.githubusercontent.com/gnosischain/configs/main/chiado/bootnodes.yaml";
|
|
6
6
|
|
|
7
7
|
export const bootEnrs = [
|
|
8
|
-
"enr:-
|
|
9
|
-
"enr:-
|
|
10
|
-
"enr:-
|
|
11
|
-
"enr:-
|
|
12
|
-
"enr:-Ly4QLYLNqrjvSxD3lpAPBUNlxa6cIbe79JqLZLFcZZjWoCjZcw-85agLUErHiygG2weRSCLnd5V460qTbLbwJQsfZkoh2F0dG5ldHOI__________-EZXRoMpAxNnBDAgAAb___________gmlkgnY0gmlwhKq7mu-Jc2VjcDI1NmsxoQP900YAYa9kdvzlSKGjVo-F3XVzATjOYp3BsjLjSophO4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA",
|
|
13
|
-
"enr:-Ly4QCGeYvTCNOGKi0mKRUd45rLj96b4pH98qG7B9TCUGXGpHZALtaL2-XfjASQyhbCqENccI4PGXVqYTIehNT9KJMQgh2F0dG5ldHOI__________-EZXRoMpAxNnBDAgAAb___________gmlkgnY0gmlwhIuQrVSJc2VjcDI1NmsxoQP9iDchx2PGl3JyJ29B9fhLCvVMN6n23pPAIIeFV-sHOIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA",
|
|
14
|
-
"enr:-Ly4QAtr21x5Ps7HYhdZkIBRBgcBkvlIfEel1YNjtFWf4cV3au2LgBGICz9PtEs9-p2HUl_eME8m1WImxTxSB3AkCMwBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAxNnBDAgAAb___________gmlkgnY0gmlwhANHhOeJc2VjcDI1NmsxoQNLp1QPV8-pyMCohOtj6xGtSBM_GtVTqzlbvNsCF4ezkYhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA",
|
|
15
|
-
"enr:-Ly4QLgn8Bx6faigkKUGZQvd1HDToV2FAxZIiENK-lczruzQb90qJK-4E65ADly0s4__dQOW7IkLMW7ZAyJy2vtiLy8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpAxNnBDAgAAb___________gmlkgnY0gmlwhANFIw2Jc2VjcDI1NmsxoQMa-fWEy9UJHfOl_lix3wdY5qust78sHAqZnWwEiyqKgYhzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA",
|
|
16
|
-
"enr:-KG4QF7z4LUdMfgwvh-fS-MDv_1hPSUCqGfyOWGLNJuoBHKFAMSHz8geQn8v3qDDbuSQKud3WIAjKqR4gqJoLBUEJ08ZhGV0aDKQDc1ElgAAAG___________4JpZIJ2NIJpcIQjzq5ciXNlY3AyNTZrMaECt7YO363pV54d3QdgnluL5kxzhCR_k0yM9C-G6bqMGoKDdGNwgiMog3VkcIIjKA",
|
|
17
|
-
"enr:-LK4QCUTEmZrT1AgCKdyVgwnHL5J0VSoxsyjruAtwo-owBTBVEOyAnQRVNXlcW5aL-ycntk5oHDrKCR-DXZAlUAKpjEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCdM7Z1BAAAb___________gmlkgnY0gmlwhCPSfheJc2VjcDI1NmsxoQNpdf8U9pzsU9m6Hzgd1rmTI-On-QImJnkZBGqDp4org4N0Y3CCIyiDdWRwgiMo",
|
|
8
|
+
"enr:-IS4QC9xcSNOKeUBrjOX1-qwcPDGOvRK-Aql_YnRfuYsuXElQawANMLTOz1YfrZTMI07B7DAl9hmk3ic5G7ZHQbq4HsUgmlkgnY0gmlwhDNL9gKJc2VjcDI1NmsxoQOzB8HdKe07eQBOxu5nexAWECV47zxlau23oEYqoToy9YN1ZHCCIyg",
|
|
9
|
+
"enr:-IS4QMpCWNqXmqbtXg7vQyYBwV2xTDpgTNpgAz060TY5cpJ3JdjuwAkLG01Vf9Vlfb0jtRhJEpj0CfteG-3K_V36bmECgmlkgnY0gmlwhDmBRt6Jc2VjcDI1NmsxoQNkoifSsk1ijP3-OR9pcL2VWCSfD5_syapyrXA83GcAvYN1ZHCCIyg",
|
|
10
|
+
"enr:-IS4QBa3hl_BcjrY4z_OvhRBx7qUMBFGkjkoedGNMXgC_fzLRBsg161SipeHWAkUnSuvBg_7529-Qfxcc7CAbokn4fMCgmlkgnY0gmlwhDmA_HuJc2VjcDI1NmsxoQL8xX-V_pyU_l3AIfVokHKMN1OMUG02vcy4AMOxdyi5jIN1ZHCCIyg",
|
|
11
|
+
"enr:-IS4QEuUku9zL0V3hFHt41fqmEdvphEvrOg0D4K_TgiiaePCDH2IPzt6B3O6NLHtgJNXk3UW68DL6KVBD4rjoW-nW9ACgmlkgnY0gmlwhDYnlGKJc2VjcDI1NmsxoQP3W66lisn2YOJF4B0QDEnURZ6tqzpi5gBy9rbMfpC70YN1ZHCCIyg",
|
|
18
12
|
];
|
|
@@ -31,7 +31,8 @@ export function parseArgs(args: ExecutionBuilderArgs): IBeaconNodeOptions["execu
|
|
|
31
31
|
|
|
32
32
|
export const options: CliCommandOptions<ExecutionBuilderArgs> = {
|
|
33
33
|
builder: {
|
|
34
|
-
description:
|
|
34
|
+
description:
|
|
35
|
+
"Enable external builder. Pre-Gloas only, deprecated post-Gloas where builders are configured on the validator client",
|
|
35
36
|
type: "boolean",
|
|
36
37
|
default: defaultExecutionBuilderHttpOpts.enabled,
|
|
37
38
|
group: "builder",
|
|
@@ -39,7 +40,8 @@ export const options: CliCommandOptions<ExecutionBuilderArgs> = {
|
|
|
39
40
|
|
|
40
41
|
"builder.url": {
|
|
41
42
|
alias: ["builder.urls"],
|
|
42
|
-
description:
|
|
43
|
+
description:
|
|
44
|
+
"Url hosting the builder API. Pre-Gloas only, deprecated post-Gloas where builders are configured on the validator client",
|
|
43
45
|
defaultDescription: defaultExecutionBuilderHttpOpts.url,
|
|
44
46
|
type: "string",
|
|
45
47
|
group: "builder",
|
|
@@ -343,7 +343,8 @@ Will double processing times. Use only for debugging purposes.",
|
|
|
343
343
|
|
|
344
344
|
"chain.maxCPStateEpochsOnDisk": {
|
|
345
345
|
hidden: true,
|
|
346
|
-
description:
|
|
346
|
+
description:
|
|
347
|
+
"Max number of checkpoint state epochs to keep on disk. Default (Infinity) uses tiered pruning to bound disk usage during long non-finality; set a finite N to keep only the last N epochs instead (previous behavior)",
|
|
347
348
|
type: "number",
|
|
348
349
|
default: defaultOptions.chain.maxCPStateEpochsOnDisk,
|
|
349
350
|
group: "chain",
|
package/src/util/format.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import {routes} from "@lodestar/api";
|
|
4
|
+
import {BuilderEntryConfig, builderConfigDataFromJson} from "@lodestar/api/keymanager";
|
|
5
|
+
import {MAX_BUILDER_AUTH_DATA_SIZE, MAX_BUILDER_ENTRIES, MAX_BUILDER_URL_SIZE} from "@lodestar/params";
|
|
6
|
+
import {fromHex, isValidAsciiHttpUrl, toHex} from "@lodestar/utils";
|
|
4
7
|
import {ValidatorProposerConfig} from "@lodestar/validator";
|
|
5
8
|
import {parseFeeRecipient} from "./feeRecipient.js";
|
|
6
9
|
import {readFile} from "./file.js";
|
|
7
10
|
|
|
11
|
+
const UINT64_MAX = 2n ** 64n - 1n;
|
|
12
|
+
const BUILDER_AUTH_DATA_PATTERN = new RegExp(`^0x(?:[a-fA-F0-9]{2}){1,${MAX_BUILDER_AUTH_DATA_SIZE}}$`);
|
|
13
|
+
|
|
8
14
|
type ProposerConfig = ValidatorProposerConfig["defaultConfig"];
|
|
9
15
|
|
|
10
16
|
type ProposerConfigFileSection = {
|
|
@@ -17,6 +23,9 @@ type ProposerConfigFileSection = {
|
|
|
17
23
|
gas_limit?: number;
|
|
18
24
|
selection?: routes.validator.BuilderSelection;
|
|
19
25
|
boost_factor?: bigint;
|
|
26
|
+
min_bid?: bigint;
|
|
27
|
+
max_execution_payment?: bigint;
|
|
28
|
+
builders?: unknown;
|
|
20
29
|
};
|
|
21
30
|
};
|
|
22
31
|
|
|
@@ -54,7 +63,14 @@ function parseProposerConfigSection(
|
|
|
54
63
|
overrideConfig?: ProposerConfig
|
|
55
64
|
): ProposerConfig {
|
|
56
65
|
const {graffiti, strict_fee_recipient_check, fee_recipient, builder} = proposerFileSection;
|
|
57
|
-
const {
|
|
66
|
+
const {
|
|
67
|
+
gas_limit,
|
|
68
|
+
selection: builderSelection,
|
|
69
|
+
boost_factor,
|
|
70
|
+
min_bid,
|
|
71
|
+
max_execution_payment,
|
|
72
|
+
builders,
|
|
73
|
+
} = builder || {};
|
|
58
74
|
|
|
59
75
|
if (graffiti !== undefined && typeof graffiti !== "string") {
|
|
60
76
|
throw Error("graffiti is not 'string");
|
|
@@ -79,6 +95,29 @@ function parseProposerConfigSection(
|
|
|
79
95
|
if (boost_factor !== undefined && typeof boost_factor !== "string") {
|
|
80
96
|
throw Error("boost_factor is not 'string");
|
|
81
97
|
}
|
|
98
|
+
if (min_bid !== undefined && typeof min_bid !== "string") {
|
|
99
|
+
throw Error("min_bid is not 'string");
|
|
100
|
+
}
|
|
101
|
+
if (max_execution_payment !== undefined && typeof max_execution_payment !== "string") {
|
|
102
|
+
throw Error("max_execution_payment is not 'string");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const parsedBuilder =
|
|
106
|
+
overrideConfig?.builder || builder
|
|
107
|
+
? {
|
|
108
|
+
gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined),
|
|
109
|
+
selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection),
|
|
110
|
+
boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor),
|
|
111
|
+
minBid: overrideConfig?.builder?.minBid ?? parseBuilderMinBid(min_bid),
|
|
112
|
+
maxExecutionPayment:
|
|
113
|
+
overrideConfig?.builder?.maxExecutionPayment ?? parseBuilderGweiAmount(max_execution_payment),
|
|
114
|
+
builders: overrideConfig?.builder?.builders ?? parseBuilderEntries(builders),
|
|
115
|
+
}
|
|
116
|
+
: undefined;
|
|
117
|
+
|
|
118
|
+
if (overrideConfig?.builder?.builders !== undefined && builders !== undefined) {
|
|
119
|
+
throw Error("Cannot configure both --builder.urls and builders in the proposer settings file");
|
|
120
|
+
}
|
|
82
121
|
|
|
83
122
|
return {
|
|
84
123
|
graffiti: overrideConfig?.graffiti ?? graffiti,
|
|
@@ -86,21 +125,27 @@ function parseProposerConfigSection(
|
|
|
86
125
|
overrideConfig?.strictFeeRecipientCheck ??
|
|
87
126
|
(strict_fee_recipient_check ? stringtoBool(strict_fee_recipient_check) : undefined),
|
|
88
127
|
feeRecipient: overrideConfig?.feeRecipient ?? (fee_recipient ? parseFeeRecipient(fee_recipient) : undefined),
|
|
89
|
-
builder:
|
|
90
|
-
overrideConfig?.builder || builder
|
|
91
|
-
? {
|
|
92
|
-
gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined),
|
|
93
|
-
selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection),
|
|
94
|
-
boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor),
|
|
95
|
-
}
|
|
96
|
-
: undefined,
|
|
128
|
+
builder: parsedBuilder,
|
|
97
129
|
};
|
|
98
130
|
}
|
|
99
131
|
|
|
100
|
-
export function readProposerConfigDir(filepath: string, filename: string):
|
|
132
|
+
export function readProposerConfigDir(filepath: string, filename: string): ProposerConfig {
|
|
101
133
|
const proposerConfigStr = fs.readFileSync(path.join(filepath, filename), "utf8");
|
|
102
|
-
|
|
103
|
-
|
|
134
|
+
// Persisted via `writeProposerConfig` with BigInt values serialized as strings
|
|
135
|
+
const persisted = JSON.parse(proposerConfigStr) as ProposerConfig;
|
|
136
|
+
if (persisted.builder) {
|
|
137
|
+
const {boostFactor, minBid, maxExecutionPayment, builders} = persisted.builder;
|
|
138
|
+
persisted.builder.boostFactor = boostFactor !== undefined ? BigInt(boostFactor) : undefined;
|
|
139
|
+
persisted.builder.minBid = minBid !== undefined ? BigInt(minBid) : undefined;
|
|
140
|
+
persisted.builder.maxExecutionPayment = maxExecutionPayment !== undefined ? BigInt(maxExecutionPayment) : undefined;
|
|
141
|
+
persisted.builder.builders = builders?.map((entry) => ({
|
|
142
|
+
...entry,
|
|
143
|
+
maxExecutionPayment: entry.maxExecutionPayment !== undefined ? BigInt(entry.maxExecutionPayment) : undefined,
|
|
144
|
+
minBid: entry.minBid !== undefined ? BigInt(entry.minBid) : undefined,
|
|
145
|
+
builderBoostFactor: entry.builderBoostFactor !== undefined ? BigInt(entry.builderBoostFactor) : undefined,
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
return persisted;
|
|
104
149
|
}
|
|
105
150
|
|
|
106
151
|
export function parseBuilderSelection(builderSelection?: string): routes.validator.BuilderSelection | undefined {
|
|
@@ -131,6 +176,100 @@ export function parseBuilderBoostFactor(boostFactor?: string): bigint | undefine
|
|
|
131
176
|
if (!/^\d+$/.test(boostFactor)) {
|
|
132
177
|
throw Error("Invalid input for builder boost factor, must be a valid number without decimals");
|
|
133
178
|
}
|
|
179
|
+
const parsed = BigInt(boostFactor);
|
|
180
|
+
if (parsed > UINT64_MAX) {
|
|
181
|
+
throw Error("Invalid input for builder boost factor, must not exceed 2**64 - 1");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return parsed;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function parseBuilderMinBid(minBid?: string | bigint): bigint | undefined {
|
|
188
|
+
if (minBid === undefined) return;
|
|
189
|
+
|
|
190
|
+
if (!/^\d+$/.test(minBid.toString())) {
|
|
191
|
+
throw Error("Invalid input for builder min bid, must be a valid number without decimals");
|
|
192
|
+
}
|
|
193
|
+
const parsed = BigInt(minBid);
|
|
194
|
+
if (parsed > UINT64_MAX) {
|
|
195
|
+
throw Error("Invalid input for builder min bid, must not exceed 2**64 - 1");
|
|
196
|
+
}
|
|
134
197
|
|
|
135
|
-
return
|
|
198
|
+
return parsed;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function parseBuilderGweiAmount(amount?: string | bigint): bigint | undefined {
|
|
202
|
+
if (amount === undefined) return;
|
|
203
|
+
|
|
204
|
+
if (!/^\d+$/.test(amount.toString())) {
|
|
205
|
+
throw Error("Invalid input for builder Gwei amount, must be a valid number without decimals");
|
|
206
|
+
}
|
|
207
|
+
const parsed = BigInt(amount);
|
|
208
|
+
if (parsed > UINT64_MAX) {
|
|
209
|
+
throw Error("Invalid input for builder Gwei amount, must not exceed 2**64 - 1");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return parsed;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Parse per-builder entries from the proposer settings file, same shape and validation as the
|
|
217
|
+
* keymanager builders api. No two entries may share both their url and their auth data, an
|
|
218
|
+
* omitted auth data is compared as the value derived from the entry url.
|
|
219
|
+
*/
|
|
220
|
+
export function parseBuilderEntries(builders?: unknown): BuilderEntryConfig[] | undefined {
|
|
221
|
+
if (builders === undefined) return undefined;
|
|
222
|
+
|
|
223
|
+
const {builders: entries} = builderConfigDataFromJson({builders});
|
|
224
|
+
const seenEntries = new Set<string>();
|
|
225
|
+
for (const entry of entries ?? []) {
|
|
226
|
+
if (!isValidAsciiHttpUrl(entry.url)) {
|
|
227
|
+
throw Error(`Invalid builder url: ${entry.url}`);
|
|
228
|
+
}
|
|
229
|
+
const authData = entry.authData !== undefined ? toHex(fromHex(entry.authData)) : toHex(Buffer.from(entry.url));
|
|
230
|
+
const entryKey = `${entry.url}|${authData}`;
|
|
231
|
+
if (seenEntries.has(entryKey)) {
|
|
232
|
+
throw Error(`Duplicate builder entry url=${entry.url}`);
|
|
233
|
+
}
|
|
234
|
+
seenEntries.add(entryKey);
|
|
235
|
+
}
|
|
236
|
+
return entries;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Parse builder urls into builder entries. Auth data agreed with a builder out of band may be
|
|
241
|
+
* appended as a hex fragment (`https://builder.example.com#0x0123`), it is stripped from the url
|
|
242
|
+
* and never sent on the wire. Without a fragment the auth data derives from the url.
|
|
243
|
+
*/
|
|
244
|
+
export function parseBuilderUrls(urls?: string[]): BuilderEntryConfig[] | undefined {
|
|
245
|
+
if (urls === undefined) return undefined;
|
|
246
|
+
|
|
247
|
+
const entries: BuilderEntryConfig[] = [];
|
|
248
|
+
const seenEntries = new Set<string>();
|
|
249
|
+
for (const value of urls) {
|
|
250
|
+
const fragmentIndex = value.indexOf("#");
|
|
251
|
+
const url = fragmentIndex === -1 ? value : value.slice(0, fragmentIndex);
|
|
252
|
+
const authData = fragmentIndex === -1 ? undefined : value.slice(fragmentIndex + 1);
|
|
253
|
+
if (!isValidAsciiHttpUrl(url)) {
|
|
254
|
+
throw Error(`Invalid builder url: ${url}`);
|
|
255
|
+
}
|
|
256
|
+
if (Buffer.byteLength(url, "utf8") > MAX_BUILDER_URL_SIZE) {
|
|
257
|
+
throw Error(`Invalid builder url, must not exceed ${MAX_BUILDER_URL_SIZE} bytes: ${url}`);
|
|
258
|
+
}
|
|
259
|
+
if (authData !== undefined && !BUILDER_AUTH_DATA_PATTERN.test(authData)) {
|
|
260
|
+
throw Error(
|
|
261
|
+
`Invalid builder url auth data, must be a 0x-prefixed hex string of 1 to ${MAX_BUILDER_AUTH_DATA_SIZE} bytes: ${url}`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
const entryKey = `${url}|${authData !== undefined ? toHex(fromHex(authData)) : toHex(Buffer.from(url))}`;
|
|
265
|
+
if (seenEntries.has(entryKey)) {
|
|
266
|
+
throw Error(`Duplicate builder url: ${url}`);
|
|
267
|
+
}
|
|
268
|
+
seenEntries.add(entryKey);
|
|
269
|
+
entries.push({url, authData});
|
|
270
|
+
}
|
|
271
|
+
if (entries.length > MAX_BUILDER_ENTRIES) {
|
|
272
|
+
throw Error(`Number of builder urls must not exceed ${MAX_BUILDER_ENTRIES}, got ${entries.length}`);
|
|
273
|
+
}
|
|
274
|
+
return entries;
|
|
136
275
|
}
|