Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Internal improvement: Make source-fetcher throw on invalid network #3559

Merged
merged 4 commits into from
Nov 24, 2020
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
67 changes: 29 additions & 38 deletions packages/core/lib/debug/external.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const debugModule = require("debug");
const debug = debugModule("lib:debug:external");

const Web3 = require("web3");

const Codec = require("@truffle/codec");
const Fetchers = require("@truffle/source-fetcher").default;
const {InvalidNetworkError} = require("@truffle/source-fetcher");

const { DebugCompiler } = require("./compiler");
const {DebugCompiler} = require("./compiler");

class DebugExternalHandler {
constructor(bugger, config) {
Expand All @@ -20,52 +19,44 @@ class DebugExternalHandler {
let addressesToSkip = new Set(); //addresses we know we can't get source for
//note: this should always be a subset of unknownAddresses! [see below]
//get the network id
const networkId = await new Web3(this.config.provider).eth.net.getId(); //note: this is a number
//make fetcher instances
debug("Fetchers: %o", Fetchers);
const allFetchers = await Promise.all(
Fetchers.map(
async Fetcher =>
await Fetcher.forNetworkId(
networkId,
this.config[Fetcher.fetcherName]
)
)
);
const userFetcherNames = this.config.sourceFetchers;
//sort/filter fetchers by user's order, if given; otherwise use default order
let sortedFetchers = [];
if (userFetcherNames) {
for (let name of userFetcherNames) {
let Fetcher = allFetchers.find(Fetcher => Fetcher.fetcherName === name);
let Fetcher = Fetchers.find(Fetcher => Fetcher.fetcherName === name);
if (Fetcher) {
sortedFetchers.push(Fetcher);
} else {
throw new Error(`Unknown external source service ${name}.`);
}
}
} else {
sortedFetchers = allFetchers;
sortedFetchers = Fetchers;
}
//to get the final list, we'll filter out ones that don't support this
const networkId = this.config.network_id; //note: this is a number
//make fetcher instances. we'll filter out ones that don't support this
//network (and note ones that yielded errors)
let fetchers = [];
for (const fetcher of sortedFetchers) {
let isValid;
let failure = false;
try {
isValid = await fetcher.isNetworkValid();
} catch (_) {
isValid = false;
failure = true;
}
if (isValid) {
fetchers.push(fetcher);
}
if (failure) {
badFetchers.push(fetcher.fetcherName);
}
}
debug("Fetchers: %o", Fetchers);
const fetchers = (
await Promise.all(
Fetchers.map(async Fetcher => {
try {
return await Fetcher.forNetworkId(
networkId,
this.config[Fetcher.fetcherName]
);
} catch (error) {
if (!(error instanceof InvalidNetworkError)) {
//if it's *not* just an invalid network, log the error.
badFetchers.push(Fetcher.fetcherName);
}
//either way, filter this fetcher out
return null;
}
})
)
).filter(fetcher => fetcher !== null);
//now: the main loop!
let address;
while (
Expand Down Expand Up @@ -94,7 +85,7 @@ class DebugExternalHandler {
}
//if we do have it, extract sources & options
debug("got sources!");
const { sources, options } = result;
const {sources, options} = result;
if (options.language !== "Solidity") {
//if it's not Solidity, bail out now
debug("not Solidity, bailing out!");
Expand Down Expand Up @@ -142,7 +133,7 @@ class DebugExternalHandler {
}
}
}
return { badAddresses, badFetchers }; //main result is that we've mutated bugger,
return {badAddresses, badFetchers}; //main result is that we've mutated bugger,
//not the return value!
}
}
Expand All @@ -154,7 +145,7 @@ function getUnknownAddresses(bugger) {
);
debug("got instances");
return Object.entries(instances)
.filter(([_, { contractName }]) => contractName === undefined)
.filter(([_, {contractName}]) => contractName === undefined)
.map(([address, _]) => address);
}

Expand Down
15 changes: 12 additions & 3 deletions packages/source-fetcher/lib/common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//these imports aren't actually necessary, but why not :)
import util from "util";
import { setTimeout } from "timers";
import {setTimeout} from "timers";
import * as Types from "./types";

export const networksById: { [id: number]: string } = {
export const networksById: {[id: number]: string} = {
1: "mainnet",
3: "ropsten",
4: "rinkeby",
Expand All @@ -29,7 +29,16 @@ export const makeTimer: (
export function removeLibraries(
settings: Types.SolcSettings
): Types.SolcSettings {
let copySettings: Types.SolcSettings = { ...settings };
let copySettings: Types.SolcSettings = {...settings};
delete copySettings.libraries;
return copySettings;
}

export class InvalidNetworkError extends Error {
public networkId: number;
constructor(networkId: number) {
super(`Invalid network ID ${networkId}`);
this.networkId = networkId;
this.name = "InvalidNetworkError";
}
}
18 changes: 6 additions & 12 deletions packages/source-fetcher/lib/etherscan.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import debugModule from "debug";
const debug = debugModule("source-fetcher:etherscan");

import { Fetcher, FetcherConstructor } from "./types";
import {Fetcher, FetcherConstructor} from "./types";
import * as Types from "./types";
import {
networksById,
makeFilename,
makeTimer,
removeLibraries
removeLibraries,
InvalidNetworkError
} from "./common";
import request from "request-promise-native";

Expand Down Expand Up @@ -45,11 +46,9 @@ const EtherscanFetcher: FetcherConstructor = class EtherscanFetcher
"goerli"
];
if (networkName === undefined || !supportedNetworks.includes(networkName)) {
this.validNetwork = false;
} else {
this.validNetwork = true;
this.suffix = networkName === "mainnet" ? "" : `-${networkName}`;
throw new InvalidNetworkError(networkId);
}
this.suffix = networkName === "mainnet" ? "" : `-${networkName}`;
debug("apiKey: %s", apiKey);
this.apiKey = apiKey;
const baseDelay = this.apiKey ? 200 : 3000; //etherscan permits 5 requests/sec w/a key, 1/3sec w/o
Expand All @@ -58,13 +57,8 @@ const EtherscanFetcher: FetcherConstructor = class EtherscanFetcher
this.ready = makeTimer(0); //at start, it's ready to go immediately
}

private readonly validNetwork: boolean;
private readonly suffix: string;

async isNetworkValid(): Promise<boolean> {
return this.validNetwork;
}

async fetchSourcesForAddress(
address: string
): Promise<Types.SourceInfo | null> {
Expand Down Expand Up @@ -217,7 +211,7 @@ const EtherscanFetcher: FetcherConstructor = class EtherscanFetcher
): Types.SourcesByPath {
return Object.assign(
{},
...Object.entries(sources).map(([path, { content: source }]) => ({
...Object.entries(sources).map(([path, {content: source}]) => ({
[makeFilename(path)]: source
}))
);
Expand Down
5 changes: 3 additions & 2 deletions packages/source-fetcher/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import "source-map-support/register";

import { Fetcher, FetcherConstructor } from "./types";
export { Fetcher, FetcherConstructor };
import {Fetcher, FetcherConstructor} from "./types";
import {InvalidNetworkError} from "./common";
export {Fetcher, FetcherConstructor, InvalidNetworkError};

import EtherscanFetcher from "./etherscan";
import SourcifyFetcher from "./sourcify";
Expand Down
20 changes: 9 additions & 11 deletions packages/source-fetcher/lib/sourcify.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import debugModule from "debug";
const debug = debugModule("source-fetcher:sourcify");

import { Fetcher, FetcherConstructor } from "./types";
import {Fetcher, FetcherConstructor} from "./types";
import * as Types from "./types";
import { networksById, removeLibraries } from "./common";
import {networksById, removeLibraries, InvalidNetworkError} from "./common";
import request from "request-promise-native";

//this looks awkward but the TS docs actually suggest this :P
Expand All @@ -28,7 +28,6 @@ const SourcifyFetcher: FetcherConstructor = class SourcifyFetcher
private readonly networkId: number;
private readonly networkName: string; //not really used as a class member atm
//but may be in the future
private readonly validNetwork: boolean;

private readonly domain: string = "contractrepo.komputing.org";

Expand All @@ -42,13 +41,12 @@ const SourcifyFetcher: FetcherConstructor = class SourcifyFetcher
"rinkeby",
"goerli"
];
this.validNetwork =
this.networkName !== undefined &&
supportedNetworks.includes(this.networkName);
}

async isNetworkValid(): Promise<boolean> {
return this.validNetwork;
if (
this.networkName === undefined ||
!supportedNetworks.includes(this.networkName)
) {
throw new InvalidNetworkError(networkId);
}
}

async fetchSourcesForAddress(
Expand All @@ -64,7 +62,7 @@ const SourcifyFetcher: FetcherConstructor = class SourcifyFetcher
{},
...(await Promise.all(
Object.entries(metadata.sources).map(
async ([sourcePath, { content: source }]) => ({
async ([sourcePath, {content: source}]) => ({
[sourcePath]:
source !== undefined
? source //sourcify doesn't support this yet but they're planning it
Expand Down
1 change: 0 additions & 1 deletion packages/source-fetcher/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export interface Fetcher {
* should have same name as the static version
*/
readonly fetcherName: string;
isNetworkValid(): Promise<boolean>;
/**
* returns null if no Solidity sources for address
* (address not in system, sources are Vyper, whatever)
Expand Down