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

Implement EIP1193 #608

Merged
merged 25 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
41157ef
Implement EIP1193
alcuadrado May 25, 2020
44e728c
Fix accidentally modified doc
alcuadrado May 25, 2020
1e70abc
Fix compile errors after merging development
fvictorio Sep 7, 2020
d6eaee0
Remove some unused variables
fvictorio Sep 7, 2020
454fe59
Update the Make RequestArguments type
alcuadrado Sep 14, 2020
f4085e7
Make the missing error code error code -1
alcuadrado Sep 14, 2020
32fe217
Throw an error in BEVM if a params object is given
alcuadrado Sep 14, 2020
68a892a
Throw an error in the provider warpper if a param object is used
alcuadrado Sep 14, 2020
a3ebba3
Document and clean up the provider construction module
alcuadrado Sep 14, 2020
76ca9ba
Fix construction module type
alcuadrado Sep 14, 2020
72cdb3d
Fix array params restriction
alcuadrado Sep 14, 2020
8974d9c
export CustomError so it can be used in other places
alcuadrado Sep 16, 2020
485e647
Make BuidlerEVM provider errors a CustomError
alcuadrado Sep 16, 2020
0b10b24
Add a ProviderError in Buidler core provider's module
alcuadrado Sep 16, 2020
790d027
Make our EIP-1993 TS types match the EIP
alcuadrado Sep 16, 2020
fa92512
Throw the new Error in http provider
alcuadrado Sep 16, 2020
f04aa92
Throw the right error in the provider wrapper
alcuadrado Sep 16, 2020
b5f9929
Make BuidlerEVMProvider compliant with the EIP
alcuadrado Sep 16, 2020
2fa9cd2
Fix linter error
alcuadrado Sep 16, 2020
aa476b5
Fix error in buidler evm provider
alcuadrado Sep 16, 2020
3fdbfa7
Test the new subscriptions behavior
alcuadrado Sep 17, 2020
ca74dbe
Remove connect event
alcuadrado Sep 18, 2020
1613834
Don't report ProviderError
alcuadrado Sep 18, 2020
1c04ffa
Fix nonce race condition in BEVM test runner
alcuadrado Sep 18, 2020
0b859c3
Increase the timeout in BEVM test runner
alcuadrado Sep 18, 2020
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: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"private": true,
"devDependencies": {
"@types/mocha": "^5.2.6",
"@types/node": "^8.10.44",
"@types/node": "^10.17.24",
"@types/shelljs": "^0.8.6",
"chai": "^4.2.0",
"ganache-cli": "^6.4.3",
Expand Down
13 changes: 6 additions & 7 deletions packages/buidler-core/src/builtin-tasks/utils/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
SOLC_OUTPUT_FILENAME,
} from "../../internal/constants";
import { Reporter } from "../../internal/sentry/reporter";
import { EthereumProvider, ProjectPaths, SolcConfig } from "../../types";
import { EIP1193Provider, ProjectPaths, SolcConfig } from "../../types";

const log = debug("buidler:core:compilation-watcher");

export async function watchCompilerOutput(
provider: EthereumProvider,
provider: EIP1193Provider,
solcConfig: SolcConfig,
paths: ProjectPaths
) {
Expand Down Expand Up @@ -46,11 +46,10 @@ export async function watchCompilerOutput(
encoding: "utf8",
});

await provider.send("buidler_addCompilationResult", [
compilerVersion,
compilerInput,
compilerOutput,
]);
await provider.request({
method: "buidler_addCompilationResult",
params: [compilerVersion, compilerInput, compilerOutput],
});
} catch (error) {
console.warn(
chalk.yellow(
Expand Down
21 changes: 10 additions & 11 deletions packages/buidler-core/src/internal/buidler-evm/jsonrpc/handler.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import debug from "debug";
import { IncomingMessage, ServerResponse } from "http";
import getRawBody from "raw-body";
import WebSocket from "ws";

import { EthereumProvider } from "../../../types";
import { EIP1193Provider } from "../../../types";
import {
isSuccessfulJsonResponse,
isValidJsonRequest,
Expand All @@ -20,14 +19,8 @@ import {

// tslint:disable only-buidler-error

const log = debug("buidler:core:buidler-evm:jsonrpc");

export default class JsonRpcHandler {
private _provider: EthereumProvider;

constructor(provider: EthereumProvider) {
this._provider = provider;
}
constructor(private readonly _provider: EIP1193Provider) {}

public handleHttp = async (req: IncomingMessage, res: ServerResponse) => {
this._setCorsHeaders(res);
Expand Down Expand Up @@ -132,7 +125,10 @@ export default class JsonRpcHandler {
// Clear any active subscriptions for the closed websocket connection.
isClosed = true;
subscriptions.forEach(async (subscriptionId) => {
await this._provider.send("eth_unsubscribe", [subscriptionId]);
await this._provider.request({
method: "eth_unsubscribe",
params: [subscriptionId],
});
});
});
};
Expand Down Expand Up @@ -188,7 +184,10 @@ export default class JsonRpcHandler {
private _handleRequest = async (
req: JsonRpcRequest
): Promise<JsonRpcResponse> => {
const result = await this._provider.send(req.method, req.params);
const result = await this._provider.request({
method: req.method,
params: req.params,
});

return {
jsonrpc: "2.0",
Expand Down
12 changes: 7 additions & 5 deletions packages/buidler-core/src/internal/buidler-evm/jsonrpc/server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import debug from "debug";
import http, { Server } from "http";
import { AddressInfo } from "net";
import { Server as WSServer } from "ws";

import { EthereumProvider } from "../../../types";
import { EIP1193Provider } from "../../../types";
import { HttpProvider } from "../../core/providers/http";

import JsonRpcHandler from "./handler";
Expand All @@ -13,7 +14,7 @@ export interface JsonRpcServerConfig {
hostname: string;
port: number;

provider: EthereumProvider;
provider: EIP1193Provider;
}

export class JsonRpcServer {
Expand All @@ -35,8 +36,8 @@ export class JsonRpcServer {
this._wsServer.on("connection", handler.handleWs);
}

public getProvider = (name = "json-rpc"): EthereumProvider => {
const { address, port } = this._httpServer.address();
public getProvider = (name = "json-rpc"): EIP1193Provider => {
const { address, port } = this._httpServer.address() as AddressInfo; // TCP sockets return AddressInfo

return new HttpProvider(`http://${address}:${port}/`, name);
};
Expand All @@ -46,7 +47,8 @@ export class JsonRpcServer {
log(`Starting JSON-RPC server on port ${this._config.port}`);
this._httpServer.listen(this._config.port, this._config.hostname, () => {
// We get the address and port directly from the server in order to handle random port allocation with `0`.
resolve(this._httpServer.address());
const address = this._httpServer.address() as AddressInfo; // TCP sockets return AddressInfo
resolve(address);
});
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
// -32002 Resource unavailable Requested resource not available non-standard
// -32003 Transaction rejected Transaction creation failed non-standard

export class BuidlerEVMProviderError extends Error {
import { ProviderRpcError } from "../../../types";
import { CustomError } from "../../core/errors";

export class BuidlerEVMProviderError extends CustomError
implements ProviderRpcError {
public static isBuidlerEVMProviderError(
other: any
): other is BuidlerEVMProviderError {
Expand Down
60 changes: 46 additions & 14 deletions packages/buidler-core/src/internal/buidler-evm/provider/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import path from "path";
import semver from "semver";
import util from "util";

import {
import type {
BoundExperimentalBuidlerEVMMessageTraceHook,
EthereumProvider,
EIP1193Provider,
EthSubscription,
ProjectPaths,
ProviderConnectInfo,
RequestArguments,
} from "../../../types";
import { SOLC_INPUT_FILENAME, SOLC_OUTPUT_FILENAME } from "../../constants";
import { CompilerInput, CompilerOutput } from "../stack-traces/compiler-types";
Expand All @@ -22,6 +25,7 @@ import { Mutex } from "../vendor/await-semaphore";

import {
BuidlerEVMProviderError,
InvalidInputError,
MethodNotFoundError,
MethodNotSupportedError,
} from "./errors";
Expand All @@ -41,7 +45,7 @@ const PRIVATE_RPC_METHODS = new Set(["buidler_getStackTraceFailuresCount"]);
// tslint:disable only-buidler-error

export class BuidlerEVMProvider extends EventEmitter
implements EthereumProvider {
implements EIP1193Provider {
private _common?: Common;
private _node?: BuidlerNode;
private _ethModule?: EthModule;
Expand Down Expand Up @@ -74,15 +78,21 @@ export class BuidlerEVMProvider extends EventEmitter
super();
}

public async send(method: string, params: any[] = []): Promise<any> {
public async request(args: RequestArguments): Promise<unknown> {
const release = await this._mutex.acquire();

if (args.params !== undefined && !Array.isArray(args.params)) {
throw new InvalidInputError(
"Buidler EVM doesn't support JSON-RPC params sent as an object"
);
}

try {
if (this._loggingEnabled && !PRIVATE_RPC_METHODS.has(method)) {
return await this._sendWithLogging(method, params);
if (this._loggingEnabled && !PRIVATE_RPC_METHODS.has(args.method)) {
return await this._sendWithLogging(args.method, args.params);
}

return await this._send(method, params);
return await this._send(args.method, args.params);
} finally {
release();
}
Expand Down Expand Up @@ -300,15 +310,37 @@ export class BuidlerEVMProvider extends EventEmitter
this._evmModule = new EvmModule(node);
this._buidlerModule = new BuidlerModule(node);

const listener = (payload: { filterId: BN; result: any }) => {
this.emit("notifications", {
subscription: `0x${payload.filterId.toString(16)}`,
result: payload.result,
});
};
this._forwardNodeEvents(node);
}

private _forwardNodeEvents(node: BuidlerNode) {
// TODO: This can leak a listener when the provider is restarted
// Handle eth_subscribe events and proxy them to handler
this._node.addListener("ethEvent", listener);
node.addListener("ethEvent", (payload: { filterId: BN; result: any }) => {
const subscription = `0x${payload.filterId.toString(16)}`;
const result = payload.result;
this._emitLegacySubscriptionEvent(subscription, result);
this._emitEip1193SubscriptionEvent(subscription, result);
});
}

private _emitLegacySubscriptionEvent(subscription: string, result: any) {
this.emit("notifications", {
subscription,
result,
});
}

private _emitEip1193SubscriptionEvent(subscription: string, result: unknown) {
const message: EthSubscription = {
type: "eth_subscription",
data: {
subscription,
result,
},
};

this.emit("message", message);
}

private _logModuleMessages(): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { bufferToHex } from "ethereumjs-util";
import { inspect } from "util";

import { decodeRevertReason } from "./revert-reasons";
import {
Expand All @@ -14,6 +13,8 @@ import {
UNRECOGNIZED_FUNCTION_NAME,
} from "./solidity-stack-trace";

const inspect = Symbol.for("nodejs.util.inspect.custom");

export function getCurrentStack(): NodeJS.CallSite[] {
const previousPrepareStackTrace = Error.prepareStackTrace;

Expand Down Expand Up @@ -286,7 +287,7 @@ export class SolidityError extends Error {
this.stackTrace = stackTrace;
}

public [inspect.custom](): string {
public [inspect](): string {
return this.inspect();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/buidler-core/src/internal/core/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ErrorDescriptor, ERRORS, getErrorCode } from "./errors-list";

const inspect = Symbol.for("nodejs.util.inspect.custom");

class CustomError extends Error {
export class CustomError extends Error {
constructor(message: string, public readonly parent?: Error) {
// WARNING: Using super when extending a builtin class doesn't work well
// with TS if you are compiling to a version of JavaScript that doesn't have
Expand Down
Loading