@lodestar/prover 1.35.0-dev.8ea34e52ba → 1.35.0-dev.91dadf81de

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 (111) hide show
  1. package/bin/lodestar-prover.js +3 -0
  2. package/lib/browser/index.d.ts.map +1 -0
  3. package/lib/cli/applyPreset.d.ts.map +1 -0
  4. package/lib/cli/cli.d.ts.map +1 -0
  5. package/lib/cli/cli.js +1 -1
  6. package/lib/cli/cli.js.map +1 -1
  7. package/lib/cli/cmds/index.d.ts.map +1 -0
  8. package/lib/cli/cmds/index.js.map +1 -1
  9. package/lib/cli/cmds/start/handler.d.ts.map +1 -0
  10. package/lib/cli/cmds/start/index.d.ts.map +1 -0
  11. package/lib/cli/cmds/start/options.d.ts.map +1 -0
  12. package/lib/cli/index.d.ts.map +1 -0
  13. package/lib/cli/index.js.map +1 -1
  14. package/lib/cli/options.d.ts.map +1 -0
  15. package/lib/constants.d.ts.map +1 -0
  16. package/lib/index.d.ts +1 -1
  17. package/lib/index.d.ts.map +1 -0
  18. package/lib/index.js +1 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/interfaces.d.ts.map +1 -0
  21. package/lib/proof_provider/index.d.ts.map +1 -0
  22. package/lib/proof_provider/ordered_map.d.ts.map +1 -0
  23. package/lib/proof_provider/payload_store.d.ts.map +1 -0
  24. package/lib/proof_provider/proof_provider.d.ts.map +1 -0
  25. package/lib/provider_types/eip1193_provider_type.d.ts.map +1 -0
  26. package/lib/provider_types/ethers_provider_type.d.ts.map +1 -0
  27. package/lib/provider_types/legacy_provider_type.d.ts.map +1 -0
  28. package/lib/provider_types/web3_js_provider_type.d.ts.map +1 -0
  29. package/lib/types.d.ts.map +1 -0
  30. package/lib/utils/assertion.d.ts.map +1 -0
  31. package/lib/utils/consensus.d.ts.map +1 -0
  32. package/lib/utils/conversion.d.ts.map +1 -0
  33. package/lib/utils/errors.d.ts.map +1 -0
  34. package/lib/utils/evm.d.ts.map +1 -0
  35. package/lib/utils/execution.d.ts.map +1 -0
  36. package/lib/utils/file.d.ts.map +1 -0
  37. package/lib/utils/file.js.map +1 -1
  38. package/lib/utils/gitData/gitDataPath.d.ts.map +1 -0
  39. package/lib/utils/gitData/index.d.ts.map +1 -0
  40. package/lib/utils/gitData/index.js.map +1 -1
  41. package/lib/utils/gitData/writeGitData.d.ts.map +1 -0
  42. package/lib/utils/json_rpc.d.ts.map +1 -0
  43. package/lib/utils/process.d.ts.map +1 -0
  44. package/lib/utils/req_resp.d.ts.map +1 -0
  45. package/lib/utils/rpc_provider.d.ts.map +1 -0
  46. package/lib/utils/validation.d.ts.map +1 -0
  47. package/lib/utils/validation.js.map +1 -1
  48. package/lib/utils/verification.d.ts.map +1 -0
  49. package/lib/utils/version.d.ts.map +1 -0
  50. package/lib/verified_requests/eth_call.d.ts.map +1 -0
  51. package/lib/verified_requests/eth_estimateGas.d.ts.map +1 -0
  52. package/lib/verified_requests/eth_getBalance.d.ts.map +1 -0
  53. package/lib/verified_requests/eth_getBlockByHash.d.ts.map +1 -0
  54. package/lib/verified_requests/eth_getBlockByNumber.d.ts.map +1 -0
  55. package/lib/verified_requests/eth_getCode.d.ts.map +1 -0
  56. package/lib/verified_requests/eth_getTransactionCount.d.ts.map +1 -0
  57. package/lib/web3_provider.d.ts.map +1 -0
  58. package/lib/web3_provider_inspector.d.ts.map +1 -0
  59. package/lib/web3_provider_inspector.js.map +1 -1
  60. package/lib/web3_proxy.d.ts.map +1 -0
  61. package/lib/web3_proxy.js +1 -1
  62. package/lib/web3_proxy.js.map +1 -1
  63. package/package.json +16 -15
  64. package/src/browser/index.ts +3 -0
  65. package/src/cli/applyPreset.ts +83 -0
  66. package/src/cli/cli.ts +58 -0
  67. package/src/cli/cmds/index.ts +7 -0
  68. package/src/cli/cmds/start/handler.ts +27 -0
  69. package/src/cli/cmds/start/index.ts +18 -0
  70. package/src/cli/cmds/start/options.ts +85 -0
  71. package/src/cli/index.ts +30 -0
  72. package/src/cli/options.ts +73 -0
  73. package/src/constants.ts +6 -0
  74. package/src/index.ts +5 -0
  75. package/src/interfaces.ts +90 -0
  76. package/src/proof_provider/index.ts +1 -0
  77. package/src/proof_provider/ordered_map.ts +25 -0
  78. package/src/proof_provider/payload_store.ts +223 -0
  79. package/src/proof_provider/proof_provider.ts +210 -0
  80. package/src/provider_types/eip1193_provider_type.ts +32 -0
  81. package/src/provider_types/ethers_provider_type.ts +44 -0
  82. package/src/provider_types/legacy_provider_type.ts +123 -0
  83. package/src/provider_types/web3_js_provider_type.ts +35 -0
  84. package/src/types.ts +163 -0
  85. package/src/utils/assertion.ts +11 -0
  86. package/src/utils/consensus.ts +122 -0
  87. package/src/utils/conversion.ts +107 -0
  88. package/src/utils/errors.ts +4 -0
  89. package/src/utils/evm.ts +284 -0
  90. package/src/utils/execution.ts +76 -0
  91. package/src/utils/file.ts +51 -0
  92. package/src/utils/gitData/gitDataPath.ts +48 -0
  93. package/src/utils/gitData/index.ts +70 -0
  94. package/src/utils/gitData/writeGitData.ts +10 -0
  95. package/src/utils/json_rpc.ts +170 -0
  96. package/src/utils/process.ts +111 -0
  97. package/src/utils/req_resp.ts +34 -0
  98. package/src/utils/rpc_provider.ts +117 -0
  99. package/src/utils/validation.ts +161 -0
  100. package/src/utils/verification.ts +112 -0
  101. package/src/utils/version.ts +74 -0
  102. package/src/verified_requests/eth_call.ts +50 -0
  103. package/src/verified_requests/eth_estimateGas.ts +49 -0
  104. package/src/verified_requests/eth_getBalance.ts +26 -0
  105. package/src/verified_requests/eth_getBlockByHash.ts +24 -0
  106. package/src/verified_requests/eth_getBlockByNumber.ts +25 -0
  107. package/src/verified_requests/eth_getCode.ts +50 -0
  108. package/src/verified_requests/eth_getTransactionCount.ts +26 -0
  109. package/src/web3_provider.ts +58 -0
  110. package/src/web3_provider_inspector.ts +88 -0
  111. package/src/web3_proxy.ts +175 -0
@@ -0,0 +1,112 @@
1
+ import {Logger} from "@lodestar/utils";
2
+ import {ProofProvider} from "../proof_provider/proof_provider.js";
3
+ import {ELBlock, ELProof, HexString, JsonRpcRequest} from "../types.js";
4
+ import {bufferToHex} from "./conversion.js";
5
+ import {getELBlock, getELCode, getELProof} from "./execution.js";
6
+ import {ELRpcProvider} from "./rpc_provider.js";
7
+ import {isValidAccount, isValidBlock, isValidCodeHash, isValidStorageKeys} from "./validation.js";
8
+
9
+ type VerificationResult<T> = {data: T; valid: true} | {valid: false; data?: undefined};
10
+
11
+ export async function verifyAccount({
12
+ address,
13
+ proofProvider,
14
+ logger,
15
+ rpc,
16
+ block,
17
+ }: {
18
+ address: HexString;
19
+ rpc: ELRpcProvider;
20
+ proofProvider: ProofProvider;
21
+ logger: Logger;
22
+ block?: number | string;
23
+ }): Promise<VerificationResult<ELProof>> {
24
+ try {
25
+ const executionPayload = await proofProvider.getExecutionPayload(block ?? "latest");
26
+ const proof = await getELProof(rpc, [address, [], bufferToHex(executionPayload.blockHash)]);
27
+ const validAccount = await isValidAccount({
28
+ address: address,
29
+ stateRoot: executionPayload.stateRoot,
30
+ proof,
31
+ logger,
32
+ });
33
+
34
+ // If account is invalid don't check the storage
35
+ const validStorage = validAccount && (await isValidStorageKeys({storageKeys: [], proof, logger}));
36
+
37
+ if (validAccount && validStorage) {
38
+ return {data: proof, valid: true};
39
+ }
40
+
41
+ return {valid: false};
42
+ } catch (err) {
43
+ logger.error("Error while verifying account", {address}, err as Error);
44
+ return {valid: false};
45
+ }
46
+ }
47
+
48
+ export async function verifyCode({
49
+ address,
50
+ proofProvider,
51
+ logger,
52
+ rpc,
53
+ codeHash,
54
+ block,
55
+ }: {
56
+ address: HexString;
57
+ rpc: ELRpcProvider;
58
+ proofProvider: ProofProvider;
59
+ logger: Logger;
60
+ codeHash: HexString;
61
+ block?: number | string;
62
+ }): Promise<VerificationResult<string>> {
63
+ try {
64
+ const executionPayload = await proofProvider.getExecutionPayload(block ?? "latest");
65
+ const code = await getELCode(rpc, [address, bufferToHex(executionPayload.blockHash)]);
66
+
67
+ if (await isValidCodeHash({codeHash, codeResponse: code, logger})) {
68
+ return {data: code, valid: true};
69
+ }
70
+ return {valid: false};
71
+ } catch (err) {
72
+ logger.error("Error while verifying code", {address}, err as Error);
73
+ return {valid: false};
74
+ }
75
+ }
76
+
77
+ export async function verifyBlock({
78
+ payload,
79
+ proofProvider,
80
+ logger,
81
+ rpc,
82
+ }: {
83
+ payload: JsonRpcRequest<[block: string | number, hydrated: boolean]>;
84
+ rpc: ELRpcProvider;
85
+ proofProvider: ProofProvider;
86
+ logger: Logger;
87
+ }): Promise<VerificationResult<ELBlock>> {
88
+ try {
89
+ const blockNumber = payload.params[0];
90
+ const executionPayload = await proofProvider.getExecutionPayload(blockNumber);
91
+ const block = await getELBlock(rpc, [blockNumber, true]); // Always request hydrated blocks as we need access to `transactions` details
92
+
93
+ // If response is not valid from the EL we don't need to verify it
94
+ if (!block) return {data: block, valid: false};
95
+
96
+ if (
97
+ await isValidBlock({
98
+ logger,
99
+ block,
100
+ executionPayload,
101
+ config: proofProvider.config,
102
+ })
103
+ ) {
104
+ return {data: block, valid: true};
105
+ }
106
+
107
+ return {valid: false};
108
+ } catch (err) {
109
+ logger.error("Error while verifying block", {block: payload.params[0]}, err as Error);
110
+ return {valid: false};
111
+ }
112
+ }
@@ -0,0 +1,74 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {fileURLToPath} from "node:url";
4
+ import {findUpSync} from "find-up";
5
+ import {readAndGetGitData} from "./gitData/index.js";
6
+
7
+ // Global variable __dirname no longer available in ES6 modules.
8
+ // Solutions: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ type VersionJson = {
12
+ /** "0.28.2" */
13
+ version: string;
14
+ };
15
+
16
+ const BRANCH_IGNORE = /^(HEAD|master|unstable|main)$/;
17
+
18
+ /**
19
+ * Gathers all information on package version including Git data.
20
+ * @returns a version string, e.g.
21
+ * - Stable release: `v0.36.0/80c248bb`
22
+ * - Dev release: `v0.36.0-dev.80c248bb/80c248bb`
23
+ * - Test branch: `v0.36.0/developer-feature/80c248bb`
24
+ */
25
+ export function getVersionData(): {
26
+ version: string;
27
+ commit: string;
28
+ } {
29
+ const parts: string[] = [];
30
+
31
+ /** Returns local version from `lerna.json` or `package.json` as `"0.28.2"` */
32
+ const localVersion = readCliPackageJson() || readVersionFromLernaJson();
33
+ if (localVersion) {
34
+ parts.push(`v${localVersion}`);
35
+ }
36
+
37
+ const {branch, commit} = readAndGetGitData();
38
+
39
+ // Add branch only if not present and not an ignore value
40
+ if (branch && !BRANCH_IGNORE.test(branch)) parts.push(branch);
41
+
42
+ // Add commit only if present. 7 characters to be consistent with Github
43
+ if (commit) {
44
+ const commitShort = commit.slice(0, 7);
45
+ // Don't add commit if it's already in the version string (dev versions)
46
+ if (!localVersion || !localVersion.includes(commitShort)) {
47
+ parts.push(commitShort);
48
+ }
49
+ }
50
+
51
+ return {
52
+ // Guard against empty parts array
53
+ version: parts.length > 0 ? parts.join("/") : "unknown",
54
+ commit,
55
+ };
56
+ }
57
+
58
+ /** Read version information from lerna.json */
59
+ function readVersionFromLernaJson(): string | undefined {
60
+ const filePath = findUpSync("lerna.json", {cwd: __dirname});
61
+ if (!filePath) return undefined;
62
+
63
+ const lernaJson = JSON.parse(fs.readFileSync(filePath, "utf8")) as VersionJson;
64
+ return lernaJson.version;
65
+ }
66
+
67
+ /** Read version information from package.json */
68
+ function readCliPackageJson(): string | undefined {
69
+ const filePath = findUpSync("package.json", {cwd: __dirname});
70
+ if (!filePath) return undefined;
71
+
72
+ const packageJson = JSON.parse(fs.readFileSync(filePath, "utf8")) as VersionJson;
73
+ return packageJson.version;
74
+ }
@@ -0,0 +1,50 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {ELApiParams, ELApiReturn} from "../types.js";
3
+ import {bufferToHex} from "../utils/conversion.js";
4
+ import {createVM, executeVMCall, getVMWithState} from "../utils/evm.js";
5
+ import {
6
+ getErrorResponseForRequestWithFailedVerification,
7
+ getResponseForRequest,
8
+ getVerificationFailedMessage,
9
+ } from "../utils/json_rpc.js";
10
+
11
+ export const eth_call: ELVerifiedRequestHandler<ELApiParams["eth_call"], ELApiReturn["eth_call"]> = async ({
12
+ rpc,
13
+ payload,
14
+ logger,
15
+ proofProvider,
16
+ }) => {
17
+ const {
18
+ params: [tx, block],
19
+ } = payload;
20
+ // We assume that standard tx validation already been done by the caller (web3, ethers.js, etc.)
21
+ const executionPayload = await proofProvider.getExecutionPayload(block ?? "latest");
22
+
23
+ try {
24
+ // TODO: Optimize the creation of the evm
25
+ const vm = await createVM({proofProvider});
26
+ const vmWithState = await getVMWithState({
27
+ rpc,
28
+ executionPayload,
29
+ tx,
30
+ vm,
31
+ logger,
32
+ });
33
+ const result = await executeVMCall({
34
+ vm: vmWithState,
35
+ tx,
36
+ rpc,
37
+ executionPayload,
38
+ network: proofProvider.network,
39
+ });
40
+
41
+ return getResponseForRequest(payload, bufferToHex(result.returnValue));
42
+ } catch (err) {
43
+ logger.error(
44
+ "Request could not be verified.",
45
+ {method: payload.method, params: JSON.stringify(payload.params)},
46
+ err as Error
47
+ );
48
+ return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_call"));
49
+ }
50
+ };
@@ -0,0 +1,49 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {ELApiParams, ELApiReturn} from "../types.js";
3
+ import {bigIntToHex} from "../utils/conversion.js";
4
+ import {createVM, executeVMTx, getVMWithState} from "../utils/evm.js";
5
+ import {
6
+ getErrorResponseForRequestWithFailedVerification,
7
+ getResponseForRequest,
8
+ getVerificationFailedMessage,
9
+ } from "../utils/json_rpc.js";
10
+
11
+ export const eth_estimateGas: ELVerifiedRequestHandler<
12
+ ELApiParams["eth_estimateGas"],
13
+ ELApiReturn["eth_estimateGas"]
14
+ > = async ({rpc, payload, logger, proofProvider}) => {
15
+ const {
16
+ params: [tx, block],
17
+ } = payload;
18
+ // We assume that standard tx validation already been done by the caller (web3, ethers.js, etc.)
19
+ const executionPayload = await proofProvider.getExecutionPayload(block ?? "latest");
20
+
21
+ try {
22
+ // TODO: Optimize the creation of the evm
23
+ const vm = await createVM({proofProvider});
24
+ const vmWithState = await getVMWithState({
25
+ rpc,
26
+ executionPayload,
27
+ tx,
28
+ vm,
29
+ logger,
30
+ });
31
+
32
+ const result = await executeVMTx({
33
+ vm: vmWithState,
34
+ tx,
35
+ rpc,
36
+ executionPayload,
37
+ network: proofProvider.network,
38
+ });
39
+
40
+ return getResponseForRequest(payload, bigIntToHex(result.totalGasSpent));
41
+ } catch (err) {
42
+ logger.error(
43
+ "Request could not be verified.",
44
+ {method: payload.method, params: JSON.stringify(payload.params)},
45
+ err as Error
46
+ );
47
+ return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_estimateGas"));
48
+ }
49
+ };
@@ -0,0 +1,26 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {
3
+ getErrorResponseForRequestWithFailedVerification,
4
+ getResponseForRequest,
5
+ getVerificationFailedMessage,
6
+ } from "../utils/json_rpc.js";
7
+ import {verifyAccount} from "../utils/verification.js";
8
+
9
+ export const eth_getBalance: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({
10
+ rpc,
11
+ payload,
12
+ logger,
13
+ proofProvider,
14
+ }) => {
15
+ const {
16
+ params: [address, block],
17
+ } = payload;
18
+ const result = await verifyAccount({proofProvider, logger, rpc, address, block});
19
+
20
+ if (result.valid) {
21
+ return getResponseForRequest(payload, result.data.balance);
22
+ }
23
+
24
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
25
+ return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getBalance"));
26
+ };
@@ -0,0 +1,24 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {ELBlock} from "../types.js";
3
+ import {
4
+ getErrorResponseForRequestWithFailedVerification,
5
+ getResponseForRequest,
6
+ getVerificationFailedMessage,
7
+ } from "../utils/json_rpc.js";
8
+ import {verifyBlock} from "../utils/verification.js";
9
+
10
+ export const eth_getBlockByHash: ELVerifiedRequestHandler<[block: string, hydrated: boolean], ELBlock> = async ({
11
+ rpc,
12
+ payload,
13
+ logger,
14
+ proofProvider,
15
+ }) => {
16
+ const result = await verifyBlock({payload, proofProvider, logger, rpc});
17
+
18
+ if (result.valid) {
19
+ return getResponseForRequest(payload, result.data);
20
+ }
21
+
22
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
23
+ return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getBlockByHash"));
24
+ };
@@ -0,0 +1,25 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {ELBlock} from "../types.js";
3
+ import {
4
+ getErrorResponseForRequestWithFailedVerification,
5
+ getResponseForRequest,
6
+ getVerificationFailedMessage,
7
+ } from "../utils/json_rpc.js";
8
+ import {verifyBlock} from "../utils/verification.js";
9
+
10
+ export const eth_getBlockByNumber: ELVerifiedRequestHandler<
11
+ [block: string | number, hydrated: boolean],
12
+ ELBlock
13
+ > = async ({rpc, payload, logger, proofProvider}) => {
14
+ const result = await verifyBlock({payload, proofProvider, logger, rpc});
15
+
16
+ if (result.valid) {
17
+ return getResponseForRequest(payload, result.data);
18
+ }
19
+
20
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
21
+ return getErrorResponseForRequestWithFailedVerification(
22
+ payload,
23
+ getVerificationFailedMessage("eth_getBlockByNumber")
24
+ );
25
+ };
@@ -0,0 +1,50 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {
3
+ getErrorResponseForRequestWithFailedVerification,
4
+ getResponseForRequest,
5
+ getVerificationFailedMessage,
6
+ } from "../utils/json_rpc.js";
7
+ import {verifyAccount, verifyCode} from "../utils/verification.js";
8
+
9
+ export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({
10
+ rpc,
11
+ payload,
12
+ logger,
13
+ proofProvider,
14
+ }) => {
15
+ const {
16
+ params: [address, block],
17
+ } = payload;
18
+ // TODO: When batch requests are supported merged these two requests into one
19
+ const accountProof = await verifyAccount({
20
+ proofProvider,
21
+ logger,
22
+ rpc,
23
+ address,
24
+ block,
25
+ });
26
+
27
+ if (!accountProof.valid) {
28
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
29
+ return getErrorResponseForRequestWithFailedVerification(
30
+ payload,
31
+ "account for eth_getCode request can not be verified."
32
+ );
33
+ }
34
+
35
+ const codeProof = await verifyCode({
36
+ proofProvider,
37
+ logger,
38
+ rpc,
39
+ address,
40
+ block,
41
+ codeHash: accountProof.data.codeHash,
42
+ });
43
+
44
+ if (codeProof.valid) {
45
+ return getResponseForRequest(payload, codeProof.data);
46
+ }
47
+
48
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
49
+ return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getCode"));
50
+ };
@@ -0,0 +1,26 @@
1
+ import {ELVerifiedRequestHandler} from "../interfaces.js";
2
+ import {
3
+ getErrorResponseForRequestWithFailedVerification,
4
+ getResponseForRequest,
5
+ getVerificationFailedMessage,
6
+ } from "../utils/json_rpc.js";
7
+ import {verifyAccount} from "../utils/verification.js";
8
+
9
+ export const eth_getTransactionCount: ELVerifiedRequestHandler<
10
+ [address: string, block?: number | string],
11
+ string
12
+ > = async ({rpc, payload, logger, proofProvider}) => {
13
+ const {
14
+ params: [address, block],
15
+ } = payload;
16
+ const result = await verifyAccount({proofProvider, logger, rpc, address, block});
17
+ if (result.valid) {
18
+ return getResponseForRequest(payload, result.data.nonce);
19
+ }
20
+
21
+ logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
22
+ return getErrorResponseForRequestWithFailedVerification(
23
+ payload,
24
+ getVerificationFailedMessage("eth_getTransactionCount")
25
+ );
26
+ };
@@ -0,0 +1,58 @@
1
+ import {LogLevel} from "@lodestar/logger";
2
+ import {getBrowserLogger} from "@lodestar/logger/browser";
3
+ import {Logger} from "@lodestar/utils";
4
+ import {AnyWeb3Provider, ELRequestHandler, VerifiedExecutionInitOptions} from "./interfaces.js";
5
+ import {ProofProvider} from "./proof_provider/proof_provider.js";
6
+ import {processAndVerifyRequest} from "./utils/process.js";
7
+ import {ELRpcProvider} from "./utils/rpc_provider.js";
8
+ import {Web3ProviderInspector} from "./web3_provider_inspector.js";
9
+
10
+ export type Web3ProviderTypeHandler<T extends AnyWeb3Provider> = (
11
+ provider: T,
12
+ proofProvider: ProofProvider,
13
+ logger: Logger
14
+ ) => {provider: T; handler: ELRpcProvider["handler"]};
15
+
16
+ export function createVerifiedExecutionProvider<
17
+ T extends AnyWeb3Provider,
18
+ Mutate extends undefined | boolean = true,
19
+ Return = {provider: Mutate extends undefined | true ? T : ELRpcProvider; proofProvider: ProofProvider},
20
+ >(provider: T, opts: VerifiedExecutionInitOptions<Mutate>): Return {
21
+ const signal = opts.signal ?? new AbortController().signal;
22
+ const logger = opts.logger ?? getBrowserLogger({level: opts.logLevel ?? LogLevel.info});
23
+ const mutateProvider = opts.mutateProvider === undefined;
24
+ const customProviderTypes = opts.providerTypes ?? [];
25
+
26
+ const providerInspector = Web3ProviderInspector.initWithDefault({logger});
27
+ for (const providerType of customProviderTypes.reverse()) {
28
+ providerInspector.register(providerType, {index: 0});
29
+ }
30
+ const providerType = providerInspector.detect(provider);
31
+ logger.debug(`Provider is detected as '${providerType.name}' provider.`);
32
+
33
+ const proofProvider = ProofProvider.init({
34
+ ...opts,
35
+ signal,
36
+ logger,
37
+ });
38
+
39
+ const nonVerifiedHandler = providerType.handler(provider);
40
+ const nonVerifiedRpc = new ELRpcProvider(nonVerifiedHandler, logger);
41
+
42
+ nonVerifiedRpc.verifyCompatibility().catch((err) => {
43
+ logger.error(err);
44
+ logger.error("Due to compatibility issues, verified execution may not work properly.");
45
+ });
46
+
47
+ const verifiedHandler: ELRequestHandler = function newVerifiedHandler(payload) {
48
+ return processAndVerifyRequest({payload, rpc: nonVerifiedRpc, logger, proofProvider});
49
+ };
50
+
51
+ if (mutateProvider) {
52
+ providerType.mutateProvider(provider, verifiedHandler);
53
+ return {provider, proofProvider} as Return;
54
+ }
55
+
56
+ // Verified RPC
57
+ return {provider: new ELRpcProvider(verifiedHandler, logger), proofProvider} as Return;
58
+ }
@@ -0,0 +1,88 @@
1
+ import {Logger} from "@lodestar/logger";
2
+ import {AnyWeb3Provider, Web3ProviderType} from "./interfaces.js";
3
+ import eip1193ProviderType from "./provider_types/eip1193_provider_type.js";
4
+ import ethersProviderType from "./provider_types/ethers_provider_type.js";
5
+ import legacyProviderType from "./provider_types/legacy_provider_type.js";
6
+ import web3jsProviderType from "./provider_types/web3_js_provider_type.js";
7
+
8
+ export class Web3ProviderInspector {
9
+ protected providerTypes: Web3ProviderType<AnyWeb3Provider>[] = [];
10
+ logger: Logger;
11
+
12
+ protected constructor(opts: {logger: Logger}) {
13
+ this.logger = opts.logger;
14
+ }
15
+
16
+ static initWithDefault(opts: {logger: Logger}): Web3ProviderInspector {
17
+ const inspector = new Web3ProviderInspector(opts);
18
+ inspector.register(web3jsProviderType, {index: 0});
19
+ inspector.register(ethersProviderType, {index: 1});
20
+ inspector.register(eip1193ProviderType, {index: 2});
21
+ inspector.register(legacyProviderType, {index: 3});
22
+
23
+ return inspector;
24
+ }
25
+
26
+ getProviderTypes(): Web3ProviderType<AnyWeb3Provider>[] {
27
+ // Destruct so user can not mutate the output
28
+ return [...this.providerTypes];
29
+ }
30
+
31
+ register(providerType: Web3ProviderType<AnyWeb3Provider>, opts?: {index?: number}): void {
32
+ // If user does not provider index, we will register the provider type to last
33
+ let index = opts?.index ?? this.providerTypes.length;
34
+
35
+ // If index is larger, let's add type at the end
36
+ if (index > this.providerTypes.length) {
37
+ index = this.providerTypes.length;
38
+ }
39
+
40
+ // If a lower index is provided let's add type at the start
41
+ if (index < 0) {
42
+ index = 0;
43
+ }
44
+
45
+ if (this.providerTypes.map((p) => p.name).includes(providerType.name)) {
46
+ throw new Error(`Provider type '${providerType.name}' is already registered.`);
47
+ }
48
+
49
+ // If some provider type is already register on that index, we will make space for new
50
+ if (this.providerTypes.at(index)) {
51
+ this.logger.debug(
52
+ `A provider type '${this.providerTypes[index].name}' already existed at index '${index}', now moved down.`
53
+ );
54
+ this.providerTypes.splice(index, 0, providerType);
55
+ }
56
+
57
+ this.logger.debug(`Registered provider type "${providerType.name}" at index ${index}`);
58
+ this.providerTypes[index] = providerType;
59
+ }
60
+
61
+ unregister(indexOrName: string | number): void {
62
+ if (typeof indexOrName === "number") {
63
+ if (indexOrName > this.providerTypes.length || indexOrName < 0) {
64
+ throw new Error(`Provider type at index '${indexOrName}' is not registered.`);
65
+ }
66
+ this.providerTypes.splice(indexOrName, 1);
67
+ return;
68
+ }
69
+
70
+ const index = this.providerTypes.findIndex((p) => p.name === indexOrName);
71
+ if (index < 0) {
72
+ throw Error(`Provider type '${indexOrName}' is not registered.`);
73
+ }
74
+ this.providerTypes.splice(index, 1);
75
+ }
76
+
77
+ detect(provider: AnyWeb3Provider): Web3ProviderType<AnyWeb3Provider> {
78
+ for (const providerType of Object.values(this.providerTypes)) {
79
+ if (providerType.matched(provider)) {
80
+ return providerType;
81
+ }
82
+ }
83
+
84
+ throw new Error(
85
+ `Given provider could not be detected of any type. Supported types are ${Object.keys(this.providerTypes).join()}`
86
+ );
87
+ }
88
+ }