From ce65ac0c1c34913027ff4ea9e512d01a5e20abdf Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 15:28:39 +0100 Subject: [PATCH 01/17] SolCompilerArtifactsAdapter now uses SolResolver under the hood which allows to resolve NPM dependencies properly --- packages/sol-tracing-utils/CHANGELOG.json | 9 +++++++++ packages/sol-tracing-utils/package.json | 1 + .../sol_compiler_artifact_adapter.ts | 15 +++++++++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index ef96dc69b0..3df9ffc161 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "6.0.0", + "changes": [ + { + "note": "`SolCompilerArtifactsAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", + "pr": "TODO" + } + ] + }, { "version": "5.0.0", "changes": [ diff --git a/packages/sol-tracing-utils/package.json b/packages/sol-tracing-utils/package.json index cabb752d28..4b0fff222a 100644 --- a/packages/sol-tracing-utils/package.json +++ b/packages/sol-tracing-utils/package.json @@ -44,6 +44,7 @@ "dependencies": { "@0x/dev-utils": "^1.0.24", "@0x/sol-compiler": "^2.0.2", + "@0x/sol-resolver": "^1.2.3", "@0x/subproviders": "^2.1.11", "@0x/typescript-typings": "^3.0.8", "@0x/utils": "^3.0.1", diff --git a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts index d52587f2c6..4798f20a6a 100644 --- a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts +++ b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts @@ -1,3 +1,4 @@ +import { FallthroughResolver, FSResolver, NPMResolver, RelativeFSResolver, URLResolver } from '@0x/sol-resolver'; import { logUtils } from '@0x/utils'; import { CompilerOptions, ContractArtifact } from 'ethereum-types'; import * as fs from 'fs'; @@ -14,6 +15,7 @@ const CONFIG_FILE = 'compiler.json'; export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter { private readonly _artifactsPath: string; private readonly _sourcesPath: string; + private readonly _resolver: FallthroughResolver; /** * Instantiates a SolCompilerArtifactAdapter * @param artifactsPath Path to your artifacts directory @@ -32,6 +34,12 @@ export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter { throw new Error(`contractsDir not found in ${CONFIG_FILE}`); } this._sourcesPath = (sourcesPath || config.contractsDir) as string; + this._resolver = new FallthroughResolver(); + this._resolver.appendResolver(new URLResolver()); + const packagePath = path.resolve(''); + this._resolver.appendResolver(new NPMResolver(packagePath)); + this._resolver.appendResolver(new RelativeFSResolver(this._sourcesPath)); + this._resolver.appendResolver(new FSResolver()); } public async collectContractsDataAsync(): Promise { const artifactsGlob = `${this._artifactsPath}/**/*.json`; @@ -46,10 +54,9 @@ export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter { const sources: Sources = {}; const sourceCodes: SourceCodes = {}; _.map(artifact.sources, (value: { id: number }, relativeFilePath: string) => { - const filePath = path.resolve(this._sourcesPath, relativeFilePath); - const fileContent = fs.readFileSync(filePath).toString(); - sources[value.id] = filePath; - sourceCodes[value.id] = fileContent; + const source = this._resolver.resolve(relativeFilePath); + sources[value.id] = source.absolutePath; + sourceCodes[value.id] = source.source; }); const contractData = { sourceCodes, From 9d9ab2f1ee926d74df00799705bbecb39b2b5d99 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 15:44:08 +0100 Subject: [PATCH 02/17] Cache bytecode lookup --- packages/sol-tracing-utils/CHANGELOG.json | 4 + packages/sol-tracing-utils/src/utils.ts | 9 +- yarn.lock | 122 ++-------------------- 3 files changed, 21 insertions(+), 114 deletions(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 3df9ffc161..2c2698e0e0 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "`SolCompilerArtifactsAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", "pr": "TODO" + }, + { + "note": "Cache the `utils.getContractDataIfExists` leading to faster execution", + "pr": "TODO" } ] }, diff --git a/packages/sol-tracing-utils/src/utils.ts b/packages/sol-tracing-utils/src/utils.ts index 89c158ee71..40aa3e98a4 100644 --- a/packages/sol-tracing-utils/src/utils.ts +++ b/packages/sol-tracing-utils/src/utils.ts @@ -10,6 +10,8 @@ import { ContractData, LineColumn, SingleFileSourceRange } from './types'; const MIN_CONTRACT_BYTECODE_LENGTH = 88; const STATICCALL_GAS_COST = 40; +const bytecodeToContractDataIfExists: { [bytecode: string]: ContractData | undefined } = {}; + export const utils = { compareLineColumn(lhs: LineColumn, rhs: LineColumn): number { return lhs.line !== rhs.line ? lhs.line - rhs.line : lhs.column - rhs.column; @@ -47,6 +49,11 @@ export const utils = { if (!bytecode.startsWith('0x')) { throw new Error(`0x hex prefix missing: ${bytecode}`); } + // HACK(leo): We want to cache the values that are possibly undefined. + // That's why we can't check for undefined as we usually do, but need to use `hasOwnProperty`. + if (bytecodeToContractDataIfExists.hasOwnProperty(bytecode)) { + return bytecodeToContractDataIfExists[bytecode]; + } const contractData = _.find(contractsData, contractDataCandidate => { const bytecodeRegex = utils.bytecodeToBytecodeRegex(contractDataCandidate.bytecode); // If the bytecode is less than the minimum length, we are probably @@ -62,7 +69,7 @@ export const utils = { // collisions are practically impossible and it allows us to reuse that code return !_.isNull(bytecode.match(bytecodeRegex)) || !_.isNull(bytecode.match(runtimeBytecodeRegex)); }); - return contractData; + return (bytecodeToContractDataIfExists[bytecode] = contractData); }, isCallLike(op: OpCode): boolean { return _.includes([OpCode.CallCode, OpCode.StaticCall, OpCode.Call, OpCode.DelegateCall], op); diff --git a/yarn.lock b/yarn.lock index e4db8d4e8a..9edcc8e501 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4106,7 +4106,7 @@ checkpoint-store@^1.1.0: dependencies: functional-red-black-tree "^1.0.1" -cheerio@1.0.0-rc.2, cheerio@^1.0.0-rc.2: +cheerio@^1.0.0-rc.2: version "1.0.0-rc.2" resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" dependencies: @@ -4228,7 +4228,7 @@ classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" -clean-css@4.2.1, clean-css@4.2.x: +clean-css@4.2.x: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" dependencies: @@ -4544,7 +4544,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.6.2, concat-stream@^1.4.6, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.2: +concat-stream@^1.4.6, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -5067,20 +5067,6 @@ css-to-react-native@^2.2.2: fbjs "^0.8.5" postcss-value-parser "^3.3.0" -css-tree@1.0.0-alpha.28: - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.28.tgz#8e8968190d886c9477bc8d61e96f61af3f7ffa7f" - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - -css-tree@1.0.0-alpha.29: - version "1.0.0-alpha.29" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - css-vendor@^0.3.8: version "0.3.8" resolved "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa" @@ -5148,12 +5134,6 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" -csso@~3.5.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" - dependencies: - css-tree "1.0.0-alpha.29" - cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.4" resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797" @@ -6058,10 +6038,6 @@ es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" -es6-promise@^4.1.1: - version "4.2.5" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" - es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -6723,11 +6699,7 @@ expect@^23.6.0: jest-message-util "^23.4.0" jest-regex-util "^23.3.0" -express-history-api-fallback@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/express-history-api-fallback/-/express-history-api-fallback-2.2.1.tgz#3a2ad27f7bebc90fc533d110d7c6d83097bcd057" - -express@4.16.3, express@^4.14.0, express@^4.15.2, express@^4.16.2: +express@^4.14.0, express@^4.15.2, express@^4.16.2: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: @@ -6860,15 +6832,6 @@ extract-comments@^1.1.0: esprima-extract-comments "^1.1.0" parse-code-context "^1.0.0" -extract-zip@^1.6.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" - extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -7048,7 +7011,7 @@ fileset@^2.0.2: glob "^7.0.3" minimatch "^3.0.3" -filesize@^3.5.11, filesize@^3.6.1: +filesize@^3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" @@ -8165,12 +8128,6 @@ heap@0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" -highland@2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/highland/-/highland-2.13.0.tgz#a4394d8dcb970cd071a79a20f0762b906258dc19" - dependencies: - util-deprecate "^1.0.2" - highlight.js@^9.0.0, highlight.js@^9.11.0, highlight.js@~9.12.0: version "9.12.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" @@ -8265,7 +8222,7 @@ html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" -html-minifier@3.5.20, html-minifier@^3.2.3: +html-minifier@^3.2.3: version "3.5.20" resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.20.tgz#7b19fd3caa0cb79f7cde5ee5c3abdf8ecaa6bb14" dependencies: @@ -10839,10 +10796,6 @@ mdast-add-list-metadata@1.0.1: dependencies: unist-util-visit-parents "1.1.2" -mdn-data@~1.1.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -11060,17 +11013,6 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" -minimalcss@0.7.10: - version "0.7.10" - resolved "https://registry.yarnpkg.com/minimalcss/-/minimalcss-0.7.10.tgz#453b642e43065cfebcaf21344171b9c34fb4e00e" - dependencies: - cheerio "1.0.0-rc.2" - css-tree "1.0.0-alpha.28" - csso "~3.5.0" - filesize "^3.5.11" - minimist "^1.2.0" - puppeteer "^1.4.0" - minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -13069,10 +13011,6 @@ proxy-addr@~2.0.4: forwarded "~0.1.2" ipaddr.js "1.8.0" -proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -13219,19 +13157,6 @@ punycode@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" -puppeteer@^1.4.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.9.0.tgz#56dba79e7ea4faac807877bee3b23d63291fc59e" - dependencies: - debug "^3.1.0" - extract-zip "^1.6.6" - https-proxy-agent "^2.2.1" - mime "^2.0.3" - progress "^2.0.0" - proxy-from-env "^1.0.0" - rimraf "^2.6.1" - ws "^5.1.1" - q@^1.1.2, q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -13533,8 +13458,8 @@ react-highlight@0xproject/react-highlight#fix/react-version: dependencies: highlight.js "^9.11.0" highlightjs-solidity "^1.0.5" - react "^16.4.2" - react-dom "^16.4.2" + react "^16.5.2" + react-dom "^16.5.2" react-hot-loader@^4.3.3: version "4.3.4" @@ -13709,21 +13634,6 @@ react-side-effect@^1.0.2, react-side-effect@^1.1.0: exenv "^1.2.1" shallowequal "^1.0.1" -react-snap@^1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/react-snap/-/react-snap-1.19.0.tgz#125883c95434987d78a55a3a72c733227721acb3" - dependencies: - clean-css "4.2.1" - express "4.16.3" - express-history-api-fallback "2.2.1" - highland "2.13.0" - html-minifier "3.5.20" - minimalcss "0.7.10" - mkdirp "0.5.1" - puppeteer "^1.4.0" - serve-static "1.13.2" - sourcemapped-stacktrace-node "2.1.8" - react-svg-core@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/react-svg-core/-/react-svg-core-2.1.0.tgz#3700322af70117c91f83f18febb481128de3cfbb" @@ -15323,14 +15233,6 @@ source-map@~0.2.0: dependencies: amdefine ">=0.0.4" -sourcemapped-stacktrace-node@2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/sourcemapped-stacktrace-node/-/sourcemapped-stacktrace-node-2.1.8.tgz#96fd64263051e252ce8dabf9801bea29dc7e5990" - dependencies: - es6-promise "^4.1.1" - isomorphic-fetch "^2.2.1" - source-map "^0.6.1" - space-separated-tokens@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.2.tgz#e95ab9d19ae841e200808cd96bc7bd0adbbb3412" @@ -16970,7 +16872,7 @@ utf8@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -18277,12 +18179,6 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" - yauzl@^2.4.2: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" From ddb0e29253817c29e990a20750ce5c458a703e9f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 15:52:37 +0100 Subject: [PATCH 03/17] SolCompilerArtifactAdapter now doesn't return the ContractData for interfaces --- packages/sol-tracing-utils/CHANGELOG.json | 6 +++++- .../src/artifact_adapters/sol_compiler_artifact_adapter.ts | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 2c2698e0e0..c3c4bd0585 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -3,12 +3,16 @@ "version": "6.0.0", "changes": [ { - "note": "`SolCompilerArtifactsAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", + "note": "`SolCompilerArtifactAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", "pr": "TODO" }, { "note": "Cache the `utils.getContractDataIfExists` leading to faster execution", "pr": "TODO" + }, + { + "note": "`SolCompilerArtifactAdapter` now doesn't return the `ContractData` for interfaces", + "pr": "TODO" } ] }, diff --git a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts index 4798f20a6a..bf6dc3b2fb 100644 --- a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts +++ b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts @@ -66,6 +66,10 @@ export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter { runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object, sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap, }; + if (contractData.bytecode === '0x' && contractData.runtimeBytecode === '0x') { + // That's an interface contract + continue; + } contractsData.push(contractData); } return contractsData; From 61910f264c4671f057f774a415c673f10c09ddb1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 15:55:06 +0100 Subject: [PATCH 04/17] Print reasonable warnings on bytecode collisions --- packages/sol-tracing-utils/CHANGELOG.json | 4 ++++ packages/sol-tracing-utils/src/utils.ts | 27 +++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index c3c4bd0585..202fb9bd06 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -13,6 +13,10 @@ { "note": "`SolCompilerArtifactAdapter` now doesn't return the `ContractData` for interfaces", "pr": "TODO" + }, + { + "note": "Print resasonable error message on bytecode collision", + "pr": "TODO" } ] }, diff --git a/packages/sol-tracing-utils/src/utils.ts b/packages/sol-tracing-utils/src/utils.ts index 40aa3e98a4..7dc1844a55 100644 --- a/packages/sol-tracing-utils/src/utils.ts +++ b/packages/sol-tracing-utils/src/utils.ts @@ -1,13 +1,10 @@ -import { addressUtils, BigNumber } from '@0x/utils'; +import { addressUtils, BigNumber, logUtils } from '@0x/utils'; import { OpCode, StructLog } from 'ethereum-types'; import { addHexPrefix } from 'ethereumjs-util'; import * as _ from 'lodash'; import { ContractData, LineColumn, SingleFileSourceRange } from './types'; -// This is the minimum length of valid contract bytecode. The Solidity compiler -// metadata is 86 bytes. If you add the '0x' prefix, we get 88. -const MIN_CONTRACT_BYTECODE_LENGTH = 88; const STATICCALL_GAS_COST = 40; const bytecodeToContractDataIfExists: { [bytecode: string]: ContractData | undefined } = {}; @@ -54,22 +51,24 @@ export const utils = { if (bytecodeToContractDataIfExists.hasOwnProperty(bytecode)) { return bytecodeToContractDataIfExists[bytecode]; } - const contractData = _.find(contractsData, contractDataCandidate => { + const contractDataCandidates = _.filter(contractsData, contractDataCandidate => { const bytecodeRegex = utils.bytecodeToBytecodeRegex(contractDataCandidate.bytecode); - // If the bytecode is less than the minimum length, we are probably - // dealing with an interface. This isn't what we're looking for. - if (bytecodeRegex.length < MIN_CONTRACT_BYTECODE_LENGTH) { - return false; - } const runtimeBytecodeRegex = utils.bytecodeToBytecodeRegex(contractDataCandidate.runtimeBytecode); - if (runtimeBytecodeRegex.length < MIN_CONTRACT_BYTECODE_LENGTH) { - return false; - } // We use that function to find by bytecode or runtimeBytecode. Those are quasi-random strings so // collisions are practically impossible and it allows us to reuse that code return !_.isNull(bytecode.match(bytecodeRegex)) || !_.isNull(bytecode.match(runtimeBytecodeRegex)); }); - return (bytecodeToContractDataIfExists[bytecode] = contractData); + if (contractDataCandidates.length > 1) { + const candidates = contractDataCandidates.map( + contractDataCandidate => _.values(contractDataCandidate.sources)[0], + ); + const errMsg = + "We've found more than one artifact that contains the exact same bytecode and therefore are unable to detect which contract was executed. " + + "We'll be assigning all traces to the first one."; + logUtils.warn(errMsg); + logUtils.warn(candidates); + } + return (bytecodeToContractDataIfExists[bytecode] = contractDataCandidates[0]); }, isCallLike(op: OpCode): boolean { return _.includes([OpCode.CallCode, OpCode.StaticCall, OpCode.Call, OpCode.DelegateCall], op); From e5c4390489b02f87a4d497095ea83d0737047afc Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 16:32:12 +0100 Subject: [PATCH 05/17] Fix a bug when some parts of the profiling report were missing because of the coverage ignore lines --- packages/sol-coverage/src/coverage_subprovider.ts | 4 +++- packages/sol-profiler/CHANGELOG.json | 9 +++++++++ .../src/collect_coverage_entries.ts | 12 ++++++------ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/sol-coverage/src/coverage_subprovider.ts b/packages/sol-coverage/src/coverage_subprovider.ts index d03963ed6a..2d92b25cab 100644 --- a/packages/sol-coverage/src/coverage_subprovider.ts +++ b/packages/sol-coverage/src/coverage_subprovider.ts @@ -50,6 +50,8 @@ export class CoverageSubprovider extends TraceInfoSubprovider { } } +const IGNORE_REGEXP = /\/\*\s*solcov\s+ignore\s+next\s*\*\/\s*/gm; + /** * Computed partial coverage for a single file & subtrace. * @param contractData Contract metadata (source, srcMap, bytecode) @@ -65,7 +67,7 @@ export const coverageHandler: SingleFileSubtraceHandler = ( fileIndex: number, ): Coverage => { const absoluteFileName = contractData.sources[fileIndex]; - const coverageEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex]); + const coverageEntriesDescription = collectCoverageEntries(contractData.sourceCodes[fileIndex], IGNORE_REGEXP); // if the source wasn't provided for the fileIndex, we can't cover the file if (_.isUndefined(coverageEntriesDescription)) { diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json index 550ca2feb9..de1f09fa80 100644 --- a/packages/sol-profiler/CHANGELOG.json +++ b/packages/sol-profiler/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.0.1", + "changes": [ + { + "note": "Fix a bug when some parts of the profiling report were missing because of the coverage ignore lines", + "pr": "TODO" + } + ] + }, { "version": "2.0.0", "changes": [ diff --git a/packages/sol-tracing-utils/src/collect_coverage_entries.ts b/packages/sol-tracing-utils/src/collect_coverage_entries.ts index 9e3591d746..964095b53a 100644 --- a/packages/sol-tracing-utils/src/collect_coverage_entries.ts +++ b/packages/sol-tracing-utils/src/collect_coverage_entries.ts @@ -5,17 +5,17 @@ import * as parser from 'solidity-parser-antlr'; import { ASTVisitor, CoverageEntriesDescription } from './ast_visitor'; import { getOffsetToLocation } from './source_maps'; -const IGNORE_RE = /\/\*\s*solcov\s+ignore\s+next\s*\*\/\s*/gm; - // Parsing source code for each transaction/code is slow and therefore we cache it const sourceHashToCoverageEntries: { [sourceHash: string]: CoverageEntriesDescription } = {}; -export const collectCoverageEntries = (contractSource: string) => { +export const collectCoverageEntries = (contractSource: string, ignoreRegexp?: RegExp) => { const sourceHash = ethUtil.sha3(contractSource).toString('hex'); if (_.isUndefined(sourceHashToCoverageEntries[sourceHash]) && !_.isUndefined(contractSource)) { const ast = parser.parse(contractSource, { range: true }); const offsetToLocation = getOffsetToLocation(contractSource); - const ignoreRangesBegingingAt = gatherRangesToIgnore(contractSource); + const ignoreRangesBegingingAt = _.isUndefined(ignoreRegexp) + ? [] + : gatherRangesToIgnore(contractSource, ignoreRegexp as RegExp); const visitor = new ASTVisitor(offsetToLocation, ignoreRangesBegingingAt); parser.visit(ast, visitor); sourceHashToCoverageEntries[sourceHash] = visitor.getCollectedCoverageEntries(); @@ -25,12 +25,12 @@ export const collectCoverageEntries = (contractSource: string) => { }; // Gather the start index of all code blocks preceeded by "/* solcov ignore next */" -function gatherRangesToIgnore(contractSource: string): number[] { +function gatherRangesToIgnore(contractSource: string, ignoreRegexp: RegExp): number[] { const ignoreRangesStart = []; let match; do { - match = IGNORE_RE.exec(contractSource); + match = ignoreRegexp.exec(contractSource); if (match) { const matchLen = match[0].length; ignoreRangesStart.push(match.index + matchLen); From 7e60138e9d1a19004b1ad5337d2ee751a777129f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 Jan 2019 16:37:50 +0100 Subject: [PATCH 06/17] Fix imports in TestContracts and testLibBytes to be relative. This way they show up correctly in coverage reports --- contracts/utils/CHANGELOG.json | 9 +++++++++ .../utils/contracts/test/TestConstants/TestConstants.sol | 2 +- .../utils/contracts/test/TestLibBytes/TestLibBytes.sol | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index 724ab1e4a5..0658d12395 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.0.1", + "changes": [ + { + "note": "Fix imports in `TestConstants` and `TestLibBytes` to be relative. This way they show up correctly in coverage reports", + "pr": "TODO" + } + ] + }, { "version": "2.0.0", "changes": [ diff --git a/contracts/utils/contracts/test/TestConstants/TestConstants.sol b/contracts/utils/contracts/test/TestConstants/TestConstants.sol index 3c852173bc..1275d007b8 100644 --- a/contracts/utils/contracts/test/TestConstants/TestConstants.sol +++ b/contracts/utils/contracts/test/TestConstants/TestConstants.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "../../utils/LibBytes/LibBytes.sol"; // solhint-disable max-line-length diff --git a/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol b/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol index 444a3e7178..00d861e613 100644 --- a/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol +++ b/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol @@ -18,7 +18,7 @@ pragma solidity 0.4.24; -import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; +import "../../utils/LibBytes/LibBytes.sol"; contract TestLibBytes { From 7015fc4dbca1aa275b4b771dd1198ca1a72d71cf Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 Jan 2019 13:02:16 +0100 Subject: [PATCH 07/17] Fix tests --- packages/sol-tracing-utils/src/collect_coverage_entries.ts | 2 +- .../sol-tracing-utils/test/collect_coverage_entries_test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/sol-tracing-utils/src/collect_coverage_entries.ts b/packages/sol-tracing-utils/src/collect_coverage_entries.ts index 964095b53a..b32be12dd1 100644 --- a/packages/sol-tracing-utils/src/collect_coverage_entries.ts +++ b/packages/sol-tracing-utils/src/collect_coverage_entries.ts @@ -15,7 +15,7 @@ export const collectCoverageEntries = (contractSource: string, ignoreRegexp?: Re const offsetToLocation = getOffsetToLocation(contractSource); const ignoreRangesBegingingAt = _.isUndefined(ignoreRegexp) ? [] - : gatherRangesToIgnore(contractSource, ignoreRegexp as RegExp); + : gatherRangesToIgnore(contractSource, ignoreRegexp); const visitor = new ASTVisitor(offsetToLocation, ignoreRangesBegingingAt); parser.visit(ast, visitor); sourceHashToCoverageEntries[sourceHash] = visitor.getCollectedCoverageEntries(); diff --git a/packages/sol-tracing-utils/test/collect_coverage_entries_test.ts b/packages/sol-tracing-utils/test/collect_coverage_entries_test.ts index 7832ec3164..d3ca8930c6 100644 --- a/packages/sol-tracing-utils/test/collect_coverage_entries_test.ts +++ b/packages/sol-tracing-utils/test/collect_coverage_entries_test.ts @@ -130,7 +130,8 @@ describe('Collect coverage entries', () => { solcovIgnoreContractBaseName, ); const solcovIgnoreContract = fs.readFileSync(solcovIgnoreContractFileName).toString(); - const coverageEntries = collectCoverageEntries(solcovIgnoreContract); + const IGNORE_REGEXP = /\/\*\s*solcov\s+ignore\s+next\s*\*\/\s*/gm; + const coverageEntries = collectCoverageEntries(solcovIgnoreContract, IGNORE_REGEXP); const fnIds = _.keys(coverageEntries.fnMap); expect(fnIds.length).to.be.equal(1); From 4a6bdfae236c9977c9b2b1cfa7e43240bb8b9fb5 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 13:29:07 +0100 Subject: [PATCH 08/17] Update contracts/utils/CHANGELOG.json Co-Authored-By: LogvinovLeon --- contracts/utils/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index 0658d12395..dcc03ecf71 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": "Fix imports in `TestConstants` and `TestLibBytes` to be relative. This way they show up correctly in coverage reports", - "pr": "TODO" + "pr": "1535" } ] }, From d8890a03bbcf3c9a74a9ea6f57a83e324914f3d4 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 13:29:22 +0100 Subject: [PATCH 09/17] Update packages/sol-profiler/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/sol-profiler/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json index de1f09fa80..ec3a03c68d 100644 --- a/packages/sol-profiler/CHANGELOG.json +++ b/packages/sol-profiler/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": "Fix a bug when some parts of the profiling report were missing because of the coverage ignore lines", - "pr": "TODO" + "pr": "1535" } ] }, From 19f929761ba37b0c40c9953e272cd7bba4979737 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 15:10:05 +0100 Subject: [PATCH 10/17] Update packages/sol-tracing-utils/src/collect_coverage_entries.ts Co-Authored-By: LogvinovLeon --- packages/sol-tracing-utils/src/collect_coverage_entries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/src/collect_coverage_entries.ts b/packages/sol-tracing-utils/src/collect_coverage_entries.ts index b32be12dd1..9ac52343cb 100644 --- a/packages/sol-tracing-utils/src/collect_coverage_entries.ts +++ b/packages/sol-tracing-utils/src/collect_coverage_entries.ts @@ -13,7 +13,7 @@ export const collectCoverageEntries = (contractSource: string, ignoreRegexp?: Re if (_.isUndefined(sourceHashToCoverageEntries[sourceHash]) && !_.isUndefined(contractSource)) { const ast = parser.parse(contractSource, { range: true }); const offsetToLocation = getOffsetToLocation(contractSource); - const ignoreRangesBegingingAt = _.isUndefined(ignoreRegexp) + const ignoreRangesBeginningAt = _.isUndefined(ignoreRegexp) ? [] : gatherRangesToIgnore(contractSource, ignoreRegexp); const visitor = new ASTVisitor(offsetToLocation, ignoreRangesBegingingAt); From 3297b5ea34fa241e015bb842d813269fa11115d1 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 15:10:17 +0100 Subject: [PATCH 11/17] Update packages/sol-tracing-utils/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/sol-tracing-utils/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 202fb9bd06..bbca5b874c 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": "`SolCompilerArtifactAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", - "pr": "TODO" + "pr": "1535" }, { "note": "Cache the `utils.getContractDataIfExists` leading to faster execution", From c3ecbd3063977d4f62daa1d44b7094fc7ee08a2f Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 15:10:24 +0100 Subject: [PATCH 12/17] Update packages/sol-tracing-utils/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/sol-tracing-utils/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index bbca5b874c..7d28f7395c 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -16,7 +16,7 @@ }, { "note": "Print resasonable error message on bytecode collision", - "pr": "TODO" + "pr": "1535" } ] }, From aedd6503d143188498f3a19d1b98ec8b291ba14f Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 15:10:32 +0100 Subject: [PATCH 13/17] Update packages/sol-tracing-utils/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/sol-tracing-utils/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 7d28f7395c..cf7751aa33 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -12,7 +12,7 @@ }, { "note": "`SolCompilerArtifactAdapter` now doesn't return the `ContractData` for interfaces", - "pr": "TODO" + "pr": "1535" }, { "note": "Print resasonable error message on bytecode collision", From 148f12a753bf084dfdaa09ccb1960495ec413b19 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 22 Jan 2019 15:10:37 +0100 Subject: [PATCH 14/17] Update packages/sol-tracing-utils/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/sol-tracing-utils/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index cf7751aa33..c3fc9e6497 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -8,7 +8,7 @@ }, { "note": "Cache the `utils.getContractDataIfExists` leading to faster execution", - "pr": "TODO" + "pr": "1535" }, { "note": "`SolCompilerArtifactAdapter` now doesn't return the `ContractData` for interfaces", From 7c47c52fac8b65c893d313587cf443c0e84bd8cb Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 Jan 2019 21:11:55 +0100 Subject: [PATCH 15/17] Fix a typo --- packages/sol-tracing-utils/src/collect_coverage_entries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sol-tracing-utils/src/collect_coverage_entries.ts b/packages/sol-tracing-utils/src/collect_coverage_entries.ts index 9ac52343cb..d5045b106d 100644 --- a/packages/sol-tracing-utils/src/collect_coverage_entries.ts +++ b/packages/sol-tracing-utils/src/collect_coverage_entries.ts @@ -16,7 +16,7 @@ export const collectCoverageEntries = (contractSource: string, ignoreRegexp?: Re const ignoreRangesBeginningAt = _.isUndefined(ignoreRegexp) ? [] : gatherRangesToIgnore(contractSource, ignoreRegexp); - const visitor = new ASTVisitor(offsetToLocation, ignoreRangesBegingingAt); + const visitor = new ASTVisitor(offsetToLocation, ignoreRangesBeginningAt); parser.visit(ast, visitor); sourceHashToCoverageEntries[sourceHash] = visitor.getCollectedCoverageEntries(); } From 3e910c0e0371589da3cf4a67b420c781a1338e59 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 Jan 2019 21:20:02 +0100 Subject: [PATCH 16/17] Refactor out isInterfaceContract --- .../src/artifact_adapters/sol_compiler_artifact_adapter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts index bf6dc3b2fb..bfd3a504a5 100644 --- a/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts +++ b/packages/sol-tracing-utils/src/artifact_adapters/sol_compiler_artifact_adapter.ts @@ -66,8 +66,8 @@ export class SolCompilerArtifactAdapter extends AbstractArtifactAdapter { runtimeBytecode: artifact.compilerOutput.evm.deployedBytecode.object, sourceMapRuntime: artifact.compilerOutput.evm.deployedBytecode.sourceMap, }; - if (contractData.bytecode === '0x' && contractData.runtimeBytecode === '0x') { - // That's an interface contract + const isInterfaceContract = contractData.bytecode === '0x' && contractData.runtimeBytecode === '0x'; + if (isInterfaceContract) { continue; } contractsData.push(contractData); From 8ce885089e20e8695d8aa5b3b8d246704fc1133c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 Jan 2019 21:23:58 +0100 Subject: [PATCH 17/17] Change strings to numbers in CHANGELOGs --- contracts/utils/CHANGELOG.json | 2 +- packages/sol-profiler/CHANGELOG.json | 2 +- packages/sol-tracing-utils/CHANGELOG.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index dcc03ecf71..d44a81fef5 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": "Fix imports in `TestConstants` and `TestLibBytes` to be relative. This way they show up correctly in coverage reports", - "pr": "1535" + "pr": 1535 } ] }, diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json index ec3a03c68d..fc928b5161 100644 --- a/packages/sol-profiler/CHANGELOG.json +++ b/packages/sol-profiler/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": "Fix a bug when some parts of the profiling report were missing because of the coverage ignore lines", - "pr": "1535" + "pr": 1535 } ] }, diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index c3fc9e6497..16a12ca632 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -4,19 +4,19 @@ "changes": [ { "note": "`SolCompilerArtifactAdapter` now uses `SolResolver` under the hood which allows to resolve `NPM` dependencies properly", - "pr": "1535" + "pr": 1535 }, { "note": "Cache the `utils.getContractDataIfExists` leading to faster execution", - "pr": "1535" + "pr": 1535 }, { "note": "`SolCompilerArtifactAdapter` now doesn't return the `ContractData` for interfaces", - "pr": "1535" + "pr": 1535 }, { "note": "Print resasonable error message on bytecode collision", - "pr": "1535" + "pr": 1535 } ] },