Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: contract eth_call bug and made some improvements #5785

Merged
merged 5 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/prover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
"type": "module",
"exports": {
".": {
"import": "./lib/index.js",
"browser": "./lib/index.web.js"
"import": "./lib/index.js"
},
"./browser": {
"import": "./lib/browser/index.js"
Comment on lines +18 to +21
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to make this chance, because conditional exports were not equally compatible with different libraries and tools.

Named exports on the other hand make it more easy for all web builders and tools.

}
},
"bin": {
Expand Down
3 changes: 3 additions & 0 deletions packages/prover/src/browser/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "../interfaces.js";
export * from "../proof_provider/index.js";
export {createVerifiedExecutionProvider} from "../web3_provider.js";
2 changes: 1 addition & 1 deletion packages/prover/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#configuration
export const MAX_REQUEST_LIGHT_CLIENT_UPDATES = 128;
export const MAX_PAYLOAD_HISTORY = 32;
export const UNVERIFIED_RESPONSE_CODE = -33091;
export const VERIFICATION_FAILED_RESPONSE_CODE = -33091;
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
export const DEFAULT_PROXY_REQUEST_TIMEOUT = 3000;
2 changes: 2 additions & 0 deletions packages/prover/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./interfaces.js";
export * from "./proof_provider/index.js";
export {createVerifiedExecutionProvider} from "./web3_provider.js";
export {createVerifiedExecutionProxy} from "./web3_proxy.js";
export {isVerificationFailedError} from "./utils/json_rpc.js";
2 changes: 0 additions & 2 deletions packages/prover/src/index.web.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/prover/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ProofProvider} from "./proof_provider/proof_provider.js";
import {JsonRpcRequest, JsonRpcRequestOrBatch, JsonRpcResponse, JsonRpcResponseOrBatch} from "./types.js";
import {ELRpc} from "./utils/rpc.js";

export {NetworkName} from "@lodestar/config/networks";
export enum LCTransport {
Rest = "Rest",
P2P = "P2P",
Expand Down
1 change: 1 addition & 0 deletions packages/prover/src/proof_provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./proof_provider.js";
15 changes: 13 additions & 2 deletions packages/prover/src/utils/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,19 @@ export async function getVMWithState({

const batchRequests = [];
for (const [address, storageKeys] of Object.entries(storageKeysMap)) {
batchRequests.push({jsonrpc: "2.0", method: "eth_getProof", params: [address, storageKeys, blockHashHex]});
batchRequests.push({jsonrpc: "2.0", method: "eth_getCode", params: [address, blockHashHex]});
batchRequests.push({
jsonrpc: "2.0",
id: rpc.getRequestId(),
method: "eth_getProof",
params: [address, storageKeys, blockHashHex],
});

batchRequests.push({
jsonrpc: "2.0",
id: rpc.getRequestId(),
method: "eth_getCode",
params: [address, blockHashHex],
});
}

// If all responses are valid then we will have even number of responses
Expand Down
16 changes: 12 additions & 4 deletions packages/prover/src/utils/json_rpc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Logger} from "@lodestar/logger";
import {UNVERIFIED_RESPONSE_CODE} from "../constants.js";
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../constants.js";
import {
JsonRpcErrorPayload,
JsonRpcNotificationPayload,
Expand Down Expand Up @@ -44,18 +44,26 @@ export function getResponseForRequest<P, R, E = unknown>(
throw new Error("Either result or error must be defined.");
}

export function getErrorResponseForUnverifiedRequest<P, D = unknown>(
export function getVerificationFailedMessage(method: string): string {
return `verification for '${method}' request failed.`;
}

export function isVerificationFailedError<P>(payload: JsonRpcResponseWithErrorPayload<P>): boolean {
return !isValidResponsePayload(payload) && payload.error.code === VERIFICATION_FAILED_RESPONSE_CODE;
}

export function getErrorResponseForRequestWithFailedVerification<P, D = unknown>(
payload: JsonRpcRequest<P>,
message: string,
data?: D
): JsonRpcResponseWithErrorPayload<D> {
return isNullish(data)
? (getResponseForRequest(payload, undefined, {
code: UNVERIFIED_RESPONSE_CODE,
code: VERIFICATION_FAILED_RESPONSE_CODE,
message,
}) as JsonRpcResponseWithErrorPayload<D>)
: (getResponseForRequest(payload, undefined, {
code: UNVERIFIED_RESPONSE_CODE,
code: VERIFICATION_FAILED_RESPONSE_CODE,
message,
data,
}) as JsonRpcResponseWithErrorPayload<D>);
Expand Down
2 changes: 1 addition & 1 deletion packages/prover/src/utils/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class ELRpc {
}
}

private getRequestId(): string {
getRequestId(): string {
// TODO: Find better way to generate random id
return (Math.random() * 10000).toFixed(0);
}
Expand Down
8 changes: 6 additions & 2 deletions packages/prover/src/verified_requests/eth_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import {ELVerifiedRequestHandler} from "../interfaces.js";
import {ELApiParams, ELApiReturn} from "../types.js";
import {bufferToHex} from "../utils/conversion.js";
import {createVM, executeVMCall, getVMWithState} from "../utils/evm.js";
import {getResponseForRequest, getErrorResponseForUnverifiedRequest} from "../utils/json_rpc.js";
import {
getResponseForRequest,
getErrorResponseForRequestWithFailedVerification,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_call: ELVerifiedRequestHandler<ELApiParams["eth_call"], ELApiReturn["eth_call"]> = async ({
Expand Down Expand Up @@ -42,6 +46,6 @@ export const eth_call: ELVerifiedRequestHandler<ELApiParams["eth_call"], ELApiRe
{method: payload.method, params: JSON.stringify(payload.params)},
err as Error
);
return getErrorResponseForUnverifiedRequest(payload, "eth_call request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_call"));
}
};
8 changes: 6 additions & 2 deletions packages/prover/src/verified_requests/eth_estimateGas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import {ELVerifiedRequestHandler} from "../interfaces.js";
import {ELApiParams, ELApiReturn} from "../types.js";
import {bigIntToHex} from "../utils/conversion.js";
import {createVM, executeVMTx, getVMWithState} from "../utils/evm.js";
import {getErrorResponseForUnverifiedRequest, getResponseForRequest} from "../utils/json_rpc.js";
import {
getErrorResponseForRequestWithFailedVerification,
getResponseForRequest,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_estimateGas: ELVerifiedRequestHandler<
Expand Down Expand Up @@ -41,6 +45,6 @@ export const eth_estimateGas: ELVerifiedRequestHandler<
{method: payload.method, params: JSON.stringify(payload.params)},
err as Error
);
return getErrorResponseForUnverifiedRequest(payload, "eth_estimateGas request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_estimateGas"));
}
};
8 changes: 6 additions & 2 deletions packages/prover/src/verified_requests/eth_getBalance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {ELVerifiedRequestHandler} from "../interfaces.js";
import {verifyAccount} from "../utils/verification.js";
import {getErrorResponseForUnverifiedRequest, getResponseForRequest} from "../utils/json_rpc.js";
import {
getErrorResponseForRequestWithFailedVerification,
getResponseForRequest,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_getBalance: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({
Expand All @@ -19,5 +23,5 @@ export const eth_getBalance: ELVerifiedRequestHandler<[address: string, block?:
}

logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "eth_getBalance request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getBalance"));
};
8 changes: 6 additions & 2 deletions packages/prover/src/verified_requests/eth_getBlockByHash.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {ELVerifiedRequestHandler} from "../interfaces.js";
import {ELBlock} from "../types.js";
import {verifyBlock} from "../utils/verification.js";
import {getErrorResponseForUnverifiedRequest, getResponseForRequest} from "../utils/json_rpc.js";
import {
getErrorResponseForRequestWithFailedVerification,
getResponseForRequest,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_getBlockByHash: ELVerifiedRequestHandler<[block: string, hydrated: boolean], ELBlock> = async ({
Expand All @@ -17,5 +21,5 @@ export const eth_getBlockByHash: ELVerifiedRequestHandler<[block: string, hydrat
}

logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "eth_getBlockByHash request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getBlockByHash"));
};
11 changes: 9 additions & 2 deletions packages/prover/src/verified_requests/eth_getBlockByNumber.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import {ELVerifiedRequestHandler} from "../interfaces.js";
import {ELBlock} from "../types.js";
import {verifyBlock} from "../utils/verification.js";
import {getErrorResponseForUnverifiedRequest, getResponseForRequest} from "../utils/json_rpc.js";
import {
getErrorResponseForRequestWithFailedVerification,
getResponseForRequest,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_getBlockByNumber: ELVerifiedRequestHandler<
Expand All @@ -15,5 +19,8 @@ export const eth_getBlockByNumber: ELVerifiedRequestHandler<
}

logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "eth_getBlockByNumber request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(
payload,
getVerificationFailedMessage("eth_getBlockByNumber")
);
};
13 changes: 10 additions & 3 deletions packages/prover/src/verified_requests/eth_getCode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {ELVerifiedRequestHandler} from "../interfaces.js";
import {verifyAccount, verifyCode} from "../utils/verification.js";
import {getErrorResponseForUnverifiedRequest, getResponseForRequest} from "../utils/json_rpc.js";
import {
getErrorResponseForRequestWithFailedVerification,
getResponseForRequest,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: number | string], string> = async ({
Expand All @@ -23,7 +27,10 @@ export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: num

if (!accountProof.valid) {
logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "account for eth_getCode request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(
payload,
"account for eth_getCode request can not be verified."
);
}

const codeProof = await verifyCode({
Expand All @@ -40,5 +47,5 @@ export const eth_getCode: ELVerifiedRequestHandler<[address: string, block?: num
}

logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "eth_getCode request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(payload, getVerificationFailedMessage("eth_getCode"));
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {ELVerifiedRequestHandler} from "../interfaces.js";
import {verifyAccount} from "../utils/verification.js";
import {getResponseForRequest, getErrorResponseForUnverifiedRequest} from "../utils/json_rpc.js";
import {
getResponseForRequest,
getErrorResponseForRequestWithFailedVerification,
getVerificationFailedMessage,
} from "../utils/json_rpc.js";

// eslint-disable-next-line @typescript-eslint/naming-convention
export const eth_getTransactionCount: ELVerifiedRequestHandler<
Expand All @@ -17,5 +21,8 @@ export const eth_getTransactionCount: ELVerifiedRequestHandler<
}

logger.error("Request could not be verified.", {method: payload.method, params: JSON.stringify(payload.params)});
return getErrorResponseForUnverifiedRequest(payload, "eth_getTransactionCount request can not be verified.");
return getErrorResponseForRequestWithFailedVerification(
payload,
getVerificationFailedMessage("eth_getTransactionCount")
);
};
3 changes: 2 additions & 1 deletion packages/prover/src/web3_proxy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import http from "node:http";
import https from "node:https";
import url from "node:url";
import httpProxy from "http-proxy";
import {getNodeLogger} from "@lodestar/logger/node";
Expand Down Expand Up @@ -78,7 +79,7 @@ export function createVerifiedExecutionProxy(opts: VerifiedProxyOptions): {
const proxy = httpProxy.createProxy({
target: executionRpcUrl,
ws: executionRpcUrl.startsWith("ws"),
agent: http.globalAgent,
agent: executionRpcUrl.startsWith("https") ? https.globalAgent : http.globalAgent,
xfwd: true,
ignorePath: true,
changeOrigin: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/prover/test/e2e/web3_batch_request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Web3 from "web3";
import {LCTransport} from "../../src/interfaces.js";
import {createVerifiedExecutionProvider} from "../../src/web3_provider.js";
import {rpcUrl, beaconUrl, config} from "../utils/e2e_env.js";
import {getVerificationFailedMessage} from "../../src/utils/json_rpc.js";

describe("web3_batch_requests", function () {
// Give some margin to sync light client
Expand Down Expand Up @@ -94,7 +95,7 @@ describe("web3_batch_requests", function () {
batch.execute();

await expect(successRequest).to.be.fulfilled;
await expect(errorRequest).to.be.rejectedWith("eth_getBlockByHash request can not be verified");
await expect(errorRequest).to.be.rejectedWith(getVerificationFailedMessage("eth_getBlockByHash"));
});
});
});
1 change: 1 addition & 0 deletions packages/prover/test/mocks/request_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export function generateReqHandlerOptionsMock(
rpc: {
request: sinon.stub(),
batchRequest: sinon.stub(),
getRequestId: () => (Math.random() * 10000).toFixed(0),
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import deepmerge from "deepmerge";
import {createForkConfig} from "@lodestar/config";
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
import {ELTransaction} from "../../../lib/types.js";
import {UNVERIFIED_RESPONSE_CODE} from "../../../src/constants.js";
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
import {eth_call} from "../../../src/verified_requests/eth_call.js";
import ethCallCase1 from "../../fixtures/mainnet/eth_call.json" assert {type: "json"};
import {generateReqHandlerOptionsMock} from "../../mocks/request_handler.js";
import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js";
import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js";

const testCases = [ethCallCase1];

Expand Down Expand Up @@ -60,7 +61,7 @@ describe("verified_requests / eth_call", () => {
expect(response).to.eql({
jsonrpc: "2.0",
id: testCase.request.id,
error: {code: UNVERIFIED_RESPONSE_CODE, message: "eth_call request can not be verified."},
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_call")},
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import deepmerge from "deepmerge";
import {createForkConfig} from "@lodestar/config";
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
import {ELTransaction} from "../../../lib/types.js";
import {UNVERIFIED_RESPONSE_CODE} from "../../../src/constants.js";
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
import {eth_estimateGas} from "../../../src/verified_requests/eth_estimateGas.js";
import ethEstimateGasCase1 from "../../fixtures/mainnet/eth_estimateGas_simple_transfer.json" assert {type: "json"};
import ethEstimateGasCase2 from "../../fixtures/mainnet/eth_estimateGas_contract_call.json" assert {type: "json"};
import {TestFixture, generateReqHandlerOptionsMock} from "../../mocks/request_handler.js";
import {JsonRpcRequest, JsonRpcResponseWithResultPayload} from "../../../src/types.js";
import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js";

const testCases = [ethEstimateGasCase1, ethEstimateGasCase2] as TestFixture[];

Expand Down Expand Up @@ -62,7 +63,7 @@ describe("verified_requests / eth_estimateGas", () => {
expect(response).to.eql({
jsonrpc: "2.0",
id: testCase.request.id,
error: {code: UNVERIFIED_RESPONSE_CODE, message: "eth_estimateGas request can not be verified."},
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_estimateGas")},
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import {expect} from "chai";
import deepmerge from "deepmerge";
import {createForkConfig} from "@lodestar/config";
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
import {UNVERIFIED_RESPONSE_CODE} from "../../../src/constants.js";
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
import {eth_getBalance} from "../../../src/verified_requests/eth_getBalance.js";
import eth_getBalance_eoa from "../../fixtures/sepolia/eth_getBalance_eoa.json" assert {type: "json"};
import eth_getBalance_contract from "../../fixtures/sepolia/eth_getBalance_contract.json" assert {type: "json"};
import {generateReqHandlerOptionsMock} from "../../mocks/request_handler.js";
import {getVerificationFailedMessage} from "../../../src/utils/json_rpc.js";

const testCases = [eth_getBalance_eoa, eth_getBalance_contract];

Expand Down Expand Up @@ -46,7 +47,7 @@ describe("verified_requests / eth_getBalance", () => {
expect(response).to.eql({
jsonrpc: "2.0",
id: data.request.id,
error: {code: UNVERIFIED_RESPONSE_CODE, message: "eth_getBalance request can not be verified."},
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getBalance")},
});
});
});
Expand Down
Loading