diff options
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | packages/order-watcher/CHANGELOG.json | 8 | ||||
-rw-r--r-- | packages/order-watcher/package.json | 4 | ||||
-rw-r--r-- | packages/sol-cov/src/ast_visitor.ts | 33 | ||||
-rw-r--r-- | packages/sol-cov/src/collect_coverage_entries.ts | 21 | ||||
-rw-r--r-- | packages/sol-cov/test/collect_coverage_entries_test.ts | 30 | ||||
-rw-r--r-- | packages/sol-cov/test/fixtures/contracts/SolcovIgnore.sol | 22 | ||||
-rw-r--r-- | packages/typescript-typings/CHANGELOG.json | 4 | ||||
-rw-r--r-- | packages/typescript-typings/package.json | 2 | ||||
-rw-r--r-- | packages/typescript-typings/types/ethers/index.d.ts | 3 | ||||
-rw-r--r-- | packages/utils/CHANGELOG.json | 9 | ||||
-rw-r--r-- | packages/utils/package.json | 4 | ||||
-rw-r--r-- | packages/utils/src/abi_decoder.ts | 15 |
13 files changed, 148 insertions, 9 deletions
diff --git a/package.json b/package.json index 9279327c3..a960fd569 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "name": "0x-monorepo", "engines": { - "node" : ">=6.12" + "node": ">=6.12" }, "workspaces": [ "packages/*" diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index 4afd4b9b5..00f6ad1b9 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,5 +1,13 @@ [ { + "version": "0.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { "timestamp": 1529397769, "version": "0.0.6", "changes": [ diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 6cee9da16..3335713a3 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/order-watcher", - "version": "0.0.6", + "version": "0.0.7", "description": "An order watcher daemon that watches for order validity", "keywords": [ "0x", @@ -85,7 +85,7 @@ "@0xproject/order-utils": "^0.0.7", "@0xproject/types": "^0.8.1", "@0xproject/typescript-typings": "^0.4.1", - "@0xproject/utils": "^0.7.1", + "@0xproject/utils": "^0.7.3", "@0xproject/web3-wrapper": "^0.7.1", "ethereum-types": "^0.0.1", "bintrees": "^1.0.2", diff --git a/packages/sol-cov/src/ast_visitor.ts b/packages/sol-cov/src/ast_visitor.ts index 564f0f7d2..a6bca4704 100644 --- a/packages/sol-cov/src/ast_visitor.ts +++ b/packages/sol-cov/src/ast_visitor.ts @@ -23,8 +23,13 @@ export class ASTVisitor { private _modifiersStatementIds: number[] = []; private _statementMap: StatementMap = {}; private _locationByOffset: LocationByOffset; - constructor(locationByOffset: LocationByOffset) { + private _ignoreRangesBeginningAt: number[]; + // keep track of contract/function ranges that are to be ignored + // so we can also ignore any children nodes within the contract/function + private _ignoreRangesWithin: Array<[number, number]> = []; + constructor(locationByOffset: LocationByOffset, ignoreRangesBeginningAt: number[] = []) { this._locationByOffset = locationByOffset; + this._ignoreRangesBeginningAt = ignoreRangesBeginningAt; } public getCollectedCoverageEntries(): CoverageEntriesDescription { const coverageEntriesDescription = { @@ -42,6 +47,11 @@ export class ASTVisitor { public FunctionDefinition(ast: Parser.FunctionDefinition): void { this._visitFunctionLikeDefinition(ast); } + public ContractDefinition(ast: Parser.ContractDefinition): void { + if (this._shouldIgnoreExpression(ast)) { + this._ignoreRangesWithin.push(ast.range as [number, number]); + } + } public ModifierDefinition(ast: Parser.ModifierDefinition): void { this._visitFunctionLikeDefinition(ast); } @@ -96,6 +106,9 @@ export class ASTVisitor { public ModifierInvocation(ast: Parser.ModifierInvocation): void { const BUILTIN_MODIFIERS = ['public', 'view', 'payable', 'external', 'internal', 'pure', 'constant']; if (!_.includes(BUILTIN_MODIFIERS, ast.name)) { + if (this._shouldIgnoreExpression(ast)) { + return; + } this._modifiersStatementIds.push(this._entryId); this._visitStatement(ast); } @@ -106,6 +119,9 @@ export class ASTVisitor { right: Parser.ASTNode, type: BranchType, ): void { + if (this._shouldIgnoreExpression(ast)) { + return; + } this._branchMap[this._entryId++] = { line: this._getExpressionRange(ast).start.line, type, @@ -113,6 +129,9 @@ export class ASTVisitor { }; } private _visitStatement(ast: Parser.ASTNode): void { + if (this._shouldIgnoreExpression(ast)) { + return; + } this._statementMap[this._entryId++] = this._getExpressionRange(ast); } private _getExpressionRange(ast: Parser.ASTNode): SingleFileSourceRange { @@ -125,7 +144,19 @@ export class ASTVisitor { }; return range; } + private _shouldIgnoreExpression(ast: Parser.ASTNode): boolean { + const [astStart, astEnd] = ast.range as [number, number]; + const isRangeIgnored = _.some( + this._ignoreRangesWithin, + ([rangeStart, rangeEnd]: [number, number]) => astStart >= rangeStart && astEnd <= rangeEnd, + ); + return this._ignoreRangesBeginningAt.includes(astStart) || isRangeIgnored; + } private _visitFunctionLikeDefinition(ast: Parser.ModifierDefinition | Parser.FunctionDefinition): void { + if (this._shouldIgnoreExpression(ast)) { + this._ignoreRangesWithin.push(ast.range as [number, number]); + return; + } const loc = this._getExpressionRange(ast); this._fnMap[this._entryId++] = { name: ast.name, diff --git a/packages/sol-cov/src/collect_coverage_entries.ts b/packages/sol-cov/src/collect_coverage_entries.ts index 3fc85008c..bdbcd613e 100644 --- a/packages/sol-cov/src/collect_coverage_entries.ts +++ b/packages/sol-cov/src/collect_coverage_entries.ts @@ -5,6 +5,8 @@ import * as parser from 'solidity-parser-antlr'; import { ASTVisitor, CoverageEntriesDescription } from './ast_visitor'; import { getLocationByOffset } 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 coverageEntriesBySourceHash: { [sourceHash: string]: CoverageEntriesDescription } = {}; @@ -13,10 +15,27 @@ export const collectCoverageEntries = (contractSource: string) => { if (_.isUndefined(coverageEntriesBySourceHash[sourceHash]) && !_.isUndefined(contractSource)) { const ast = parser.parse(contractSource, { range: true }); const locationByOffset = getLocationByOffset(contractSource); - const visitor = new ASTVisitor(locationByOffset); + const ignoreRangesBegingingAt = gatherRangesToIgnore(contractSource); + const visitor = new ASTVisitor(locationByOffset, ignoreRangesBegingingAt); parser.visit(ast, visitor); coverageEntriesBySourceHash[sourceHash] = visitor.getCollectedCoverageEntries(); } const coverageEntriesDescription = coverageEntriesBySourceHash[sourceHash]; return coverageEntriesDescription; }; + +// Gather the start index of all code blocks preceeded by "/* solcov ignore next */" +function gatherRangesToIgnore(contractSource: string): number[] { + const ignoreRangesStart = []; + + let match; + do { + match = IGNORE_RE.exec(contractSource); + if (match) { + const matchLen = match[0].length; + ignoreRangesStart.push(match.index + matchLen); + } + } while (match); + + return ignoreRangesStart; +} diff --git a/packages/sol-cov/test/collect_coverage_entries_test.ts b/packages/sol-cov/test/collect_coverage_entries_test.ts index f88f3b3c3..7832ec316 100644 --- a/packages/sol-cov/test/collect_coverage_entries_test.ts +++ b/packages/sol-cov/test/collect_coverage_entries_test.ts @@ -121,5 +121,35 @@ describe('Collect coverage entries', () => { const branchTypes = _.map(branchDescriptions, branchDescription => branchDescription.type); expect(branchTypes).to.be.deep.equal(['if', 'if', 'if', 'if', 'binary-expr', 'if']); }); + + it('correctly ignores all coverage entries for Ignore contract', () => { + const solcovIgnoreContractBaseName = 'SolcovIgnore.sol'; + const solcovIgnoreContractFileName = path.resolve( + __dirname, + 'fixtures/contracts', + solcovIgnoreContractBaseName, + ); + const solcovIgnoreContract = fs.readFileSync(solcovIgnoreContractFileName).toString(); + const coverageEntries = collectCoverageEntries(solcovIgnoreContract); + const fnIds = _.keys(coverageEntries.fnMap); + + expect(fnIds.length).to.be.equal(1); + expect(coverageEntries.fnMap[fnIds[0]].name).to.be.equal('set'); + // tslint:disable-next-line:custom-no-magic-numbers + expect(coverageEntries.fnMap[fnIds[0]].line).to.be.equal(6); + const setFunction = `function set(uint x) public { + /* solcov ignore next */ + storedData = x; + }`; + expect(utils.getRange(solcovIgnoreContract, coverageEntries.fnMap[fnIds[0]].loc)).to.be.equal(setFunction); + + expect(coverageEntries.branchMap).to.be.deep.equal({}); + const statementIds = _.keys(coverageEntries.statementMap); + expect(utils.getRange(solcovIgnoreContract, coverageEntries.statementMap[statementIds[0]])).to.be.equal( + setFunction, + ); + expect(statementIds.length).to.be.equal(1); + expect(coverageEntries.modifiersStatementIds.length).to.be.equal(0); + }); }); }); diff --git a/packages/sol-cov/test/fixtures/contracts/SolcovIgnore.sol b/packages/sol-cov/test/fixtures/contracts/SolcovIgnore.sol new file mode 100644 index 000000000..a7977ffb4 --- /dev/null +++ b/packages/sol-cov/test/fixtures/contracts/SolcovIgnore.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.4.21; + +contract SolcovIgnore { + uint public storedData; + + function set(uint x) public { + /* solcov ignore next */ + storedData = x; + } + + /* solcov ignore next */ + function get() constant public returns (uint retVal) { + return storedData; + } +} + +/* solcov ignore next */ +contract Ignore { + function ignored() public returns (bool) { + return false; + } +} diff --git a/packages/typescript-typings/CHANGELOG.json b/packages/typescript-typings/CHANGELOG.json index c76e0d4c0..25ff73274 100644 --- a/packages/typescript-typings/CHANGELOG.json +++ b/packages/typescript-typings/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Improve 'web3-provider-engine' typings", "pr": 768 + }, + { + "note": "Additional error type for `ethers.js`", + "pr": 763 } ] }, diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json index f10d35666..3ba7c10ba 100644 --- a/packages/typescript-typings/package.json +++ b/packages/typescript-typings/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/typescript-typings", - "version": "0.4.1", + "version": "0.4.2", "engines": { "node": ">=6.12" }, diff --git a/packages/typescript-typings/types/ethers/index.d.ts b/packages/typescript-typings/types/ethers/index.d.ts index d40428a9b..f869196e0 100644 --- a/packages/typescript-typings/types/ethers/index.d.ts +++ b/packages/typescript-typings/types/ethers/index.d.ts @@ -31,4 +31,7 @@ declare module 'ethers' { public static getDeployTransaction(bytecode: string, abi: any, ...args: any[]): Partial<TxData>; constructor(address: string, abi: any, provider: any); } + const enum errors { + INVALID_ARGUMENT = 'INVALID_ARGUMENT', + } } diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index ed5558981..c6736dc4d 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "0.7.3", + "changes": [ + { + "note": "Fixes uncaught Error in abi_decoder", + "pr": 763 + } + ] + }, + { "version": "0.7.2", "changes": [ { diff --git a/packages/utils/package.json b/packages/utils/package.json index 06d67566c..f4f39956c 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/utils", - "version": "0.7.1", + "version": "0.7.3", "engines": { "node": ">=6.12" }, @@ -36,7 +36,7 @@ }, "dependencies": { "ethereum-types": "^0.0.1", - "@0xproject/typescript-typings": "^0.4.1", + "@0xproject/typescript-typings": "^0.4.2", "@types/node": "^8.0.53", "ethereumjs-util": "^5.1.1", "bignumber.js": "~4.1.0", diff --git a/packages/utils/src/abi_decoder.ts b/packages/utils/src/abi_decoder.ts index 931cb94b2..d0c1ddc7d 100644 --- a/packages/utils/src/abi_decoder.ts +++ b/packages/utils/src/abi_decoder.ts @@ -32,7 +32,20 @@ export class AbiDecoder { const decodedParams: DecodedLogArgs = {}; let topicsIndex = 1; - const decodedData = ethersInterface.events[event.name].parse(log.data); + let decodedData: any[]; + try { + decodedData = ethersInterface.events[event.name].parse(log.data); + } catch (error) { + if (error.code === ethers.errors.INVALID_ARGUMENT) { + // Because we index events by Method ID, and Method IDs are derived from the method + // name and the input parameters, it's possible that the return value of the event + // does not match our ABI. If that's the case, then ethers will throw an error + // when we try to parse the event. We handle that case here by returning the log rather + // than throwing an error. + return log; + } + throw error; + } let didFailToDecode = false; _.forEach(event.inputs, (param: EventParameter, i: number) => { |