diff options
author | Jacob Evans <dekz@dekz.net> | 2018-06-18 19:50:35 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-18 19:50:35 +0800 |
commit | 190eafc30e2e444ed15b76217a6162ec04b33f73 (patch) | |
tree | b20cbad73ff7a069dc0f0ef43ebc0373c714ad02 /packages/metacoin | |
parent | d4ee0e862297c16f8ee62efccd31f1193052c64e (diff) | |
parent | 0c238448fda99c4d7997901d0fe4d72cb06b79cc (diff) | |
download | dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar.gz dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar.bz2 dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar.lz dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar.xz dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.tar.zst dexon-sol-tools-190eafc30e2e444ed15b76217a6162ec04b33f73.zip |
Merge branch 'v2-prototype' into bug/contracts/eip712-191-prefix
Diffstat (limited to 'packages/metacoin')
-rw-r--r-- | packages/metacoin/README.md | 97 | ||||
-rw-r--r-- | packages/metacoin/package.json | 17 | ||||
-rw-r--r-- | packages/metacoin/test/global_hooks.ts | 7 | ||||
-rw-r--r-- | packages/metacoin/test/metacoin_test.ts | 8 | ||||
-rw-r--r-- | packages/metacoin/test/utils/config.ts | 1 | ||||
-rw-r--r-- | packages/metacoin/test/utils/profiler.ts | 27 | ||||
-rw-r--r-- | packages/metacoin/test/utils/web3_wrapper.ts | 70 |
7 files changed, 204 insertions, 23 deletions
diff --git a/packages/metacoin/README.md b/packages/metacoin/README.md new file mode 100644 index 000000000..15816cc67 --- /dev/null +++ b/packages/metacoin/README.md @@ -0,0 +1,97 @@ +## @0xproject/metacoin + +This is an example project that demonstrates how the many Ethereum dev tools developed by 0x can be used in any Solidity/TS project. +It supports: + +* Compiling & testing smart contracts +* Generating typed contract wrappers +* Solidity coverage +* Solidity gas profiling +* Running tests against Ganache +* Running tests against our fork of Geth (it supports snapshotting & time travel) + +## Contributing + +We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: + +```bash +PKG=@0xproject/metacoin yarn build +``` + +Or continuously rebuild on change: + +```bash +PKG=@0xproject/metacoin yarn watch +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Test providers + +By default tests run against an in-process Ganache instance. If you want to use Geth you'll need to [start a Geth dev node](https://github.com/0xProject/0x-monorepo/blob/v2-prototype/packages/devnet/README.md) first. + +```bash +cd ../devnet +docker build -t 0x-devnet . +docker run -it --rm -p 8501:8501 0x-devnet +``` + +This Geth version supports snapshots and time travel. Then - run your tests against it. + +``` +TEST_PROVIDER=geth yarn test +``` + +### Coverage + +```bash +yarn test:coverage +yarn coverage:report:html +``` + +### Profiling + +Please note that traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling. + +```bash +TEST_PROVIDER=geth yarn test:profile +``` + +You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile. + +```typescript +import { profiler } from './utils/profiler'; +profiler.start(); +// Some solidity stuff +profiler.stop(); +``` diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index a85bf8f77..9b706fa09 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -7,18 +7,21 @@ "private": true, "description": "Example solidity project using 0x dev tools", "scripts": { - "watch": "tsc -w", - "lint": "tslint --project .", + "lint": "tslint --project . --exclude **/src/contract_wrappers/**/*", + "watch_without_deps": "yarn pre_build && tsc -w", + "build": "yarn pre_build && tsc", + "pre_build": "run-s compile generate_contract_wrappers copy_artifacts", "clean": "shx rm -rf lib artifacts src/contract_wrappers", - "prebuild": "run-s clean compile generate_contract_wrappers copy_artifacts", "copy_artifacts": "copyfiles './artifacts/**/*' './contracts/**/*' ./lib", - "build": "tsc", - "test": "run-s build run_mocha", + "test": "yarn run_mocha", + "rebuild_and_test": "run-s build test", "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", - "run_mocha": "mocha lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit", - "generate_contract_wrappers": "abi-gen --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers && prettier --write 'src/contract_wrappers/**.ts'", + "test:profile": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", + "run_mocha": "mocha --require source-map-support/register lib/test/**/*_test.js lib/test/global_hooks.js --bail --exit --timeout 10000", + "generate_contract_wrappers": "abi-gen --abis 'artifacts/Metacoin.json' --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/contract_wrappers --backend ethers", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", + "profiler:report:html": "istanbul report html && open coverage/index.html", "coverage:report:lcov": "istanbul report lcov", "test:circleci": "yarn test:coverage", "compile": "sol-compiler compile" diff --git a/packages/metacoin/test/global_hooks.ts b/packages/metacoin/test/global_hooks.ts index 509dc6837..7328531e4 100644 --- a/packages/metacoin/test/global_hooks.ts +++ b/packages/metacoin/test/global_hooks.ts @@ -1,10 +1,15 @@ import { env, EnvVars } from '@0xproject/dev-utils'; import { coverage } from './utils/coverage'; +import { profiler } from './utils/profiler'; -after('generate coverage report', async () => { +after('generate coverage || profiler report', async () => { if (env.parseBoolean(EnvVars.SolidityCoverage)) { const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); await coverageSubprovider.writeCoverageAsync(); } + if (env.parseBoolean(EnvVars.SolidityProfiler)) { + const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); + await profilerSubprovider.writeProfilerOutputAsync(); + } }); diff --git a/packages/metacoin/test/metacoin_test.ts b/packages/metacoin/test/metacoin_test.ts index 3436fb49e..78de57a2a 100644 --- a/packages/metacoin/test/metacoin_test.ts +++ b/packages/metacoin/test/metacoin_test.ts @@ -1,7 +1,6 @@ import { BlockchainLifecycle, devConstants } from '@0xproject/dev-utils'; import { ContractArtifact } from '@0xproject/sol-compiler'; import { BigNumber } from '@0xproject/utils'; -import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; import { LogWithDecodedArgs } from 'ethereum-types'; import 'make-promises-safe'; @@ -11,6 +10,8 @@ import { MetacoinContract, TransferContractEventArgs } from '../src/contract_wra import { chaiSetup } from './utils/chai_setup'; import { config } from './utils/config'; +// Comment out the next line enable profiling +// import { profiler } from './utils/profiler'; import { provider, web3Wrapper } from './utils/web3_wrapper'; const artifact: ContractArtifact = MetacoinArtifact as any; @@ -18,7 +19,7 @@ const artifact: ContractArtifact = MetacoinArtifact as any; chaiSetup.configure(); const { expect } = chai; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - +// tslint:disable:no-unnecessary-type-assertion describe('Metacoin', () => { let metacoin: MetacoinContract; const ownerAddress = devConstants.TESTRPC_FIRST_ADDRESS; @@ -45,6 +46,7 @@ describe('Metacoin', () => { const amount = INITIAL_BALANCE.div(2); const oldBalance = await metacoin.balances.callAsync(ZERO_ADDRESS); expect(oldBalance).to.be.bignumber.equal(0); + // profiler.start(); const txHash = await metacoin.transfer1.sendTransactionAsync( { to: ZERO_ADDRESS, @@ -52,6 +54,7 @@ describe('Metacoin', () => { }, { from: devConstants.TESTRPC_FIRST_ADDRESS }, ); + // profiler.stop(); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); const transferLogs = txReceipt.logs[0] as LogWithDecodedArgs<TransferContractEventArgs>; expect(transferLogs.args).to.be.deep.equal({ @@ -116,3 +119,4 @@ describe('Metacoin', () => { }); }); }); +// tslint:enable:no-unnecessary-type-assertion diff --git a/packages/metacoin/test/utils/config.ts b/packages/metacoin/test/utils/config.ts index ef4932845..c26fe5f25 100644 --- a/packages/metacoin/test/utils/config.ts +++ b/packages/metacoin/test/utils/config.ts @@ -1,5 +1,4 @@ import { devConstants } from '@0xproject/dev-utils'; -import * as path from 'path'; export const config = { networkId: 50, diff --git a/packages/metacoin/test/utils/profiler.ts b/packages/metacoin/test/utils/profiler.ts new file mode 100644 index 000000000..701337451 --- /dev/null +++ b/packages/metacoin/test/utils/profiler.ts @@ -0,0 +1,27 @@ +import { devConstants } from '@0xproject/dev-utils'; +import { ProfilerSubprovider, SolCompilerArtifactAdapter } from '@0xproject/sol-cov'; +import * as _ from 'lodash'; + +import { config } from './config'; + +let profilerSubprovider: ProfilerSubprovider; + +export const profiler = { + start(): void { + profiler.getProfilerSubproviderSingleton().start(); + }, + stop(): void { + profiler.getProfilerSubproviderSingleton().stop(); + }, + getProfilerSubproviderSingleton(): ProfilerSubprovider { + if (_.isUndefined(profilerSubprovider)) { + profilerSubprovider = profiler._getProfilerSubprovider(); + } + return profilerSubprovider; + }, + _getProfilerSubprovider(): ProfilerSubprovider { + const defaultFromAddress = devConstants.TESTRPC_FIRST_ADDRESS; + const zeroExArtifactsAdapter = new SolCompilerArtifactAdapter(config.artifactsDir, config.contractsDir); + return new ProfilerSubprovider(zeroExArtifactsAdapter, defaultFromAddress); + }, +}; diff --git a/packages/metacoin/test/utils/web3_wrapper.ts b/packages/metacoin/test/utils/web3_wrapper.ts index 724ed4e1f..d3655cb6a 100644 --- a/packages/metacoin/test/utils/web3_wrapper.ts +++ b/packages/metacoin/test/utils/web3_wrapper.ts @@ -1,32 +1,78 @@ import { env, EnvVars } from '@0xproject/dev-utils'; import { GanacheSubprovider, prependSubprovider } from '@0xproject/subproviders'; +import { errorUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as fs from 'fs'; -import * as _ from 'lodash'; import ProviderEngine = require('web3-provider-engine'); +import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); import { config } from './config'; import { coverage } from './coverage'; +import { profiler } from './profiler'; + +enum ProviderType { + Ganache = 'ganache', + Geth = 'geth', +} + +let testProvider: ProviderType; +switch (process.env.TEST_PROVIDER) { + case undefined: + testProvider = ProviderType.Ganache; + break; + case 'ganache': + testProvider = ProviderType.Ganache; + break; + case 'geth': + testProvider = ProviderType.Geth; + break; + default: + throw errorUtils.spawnSwitchErr('TEST_PROVIDER', process.env.TEST_PROVIDER); +} export const provider = new ProviderEngine(); -provider.addProvider( - new GanacheSubprovider({ - logger: { - log: (arg: any) => { - fs.appendFileSync(config.ganacheLogFile, `${arg}\n`); +if (testProvider === ProviderType.Ganache) { + provider.addProvider( + new GanacheSubprovider({ + logger: { + log: (arg: any) => { + fs.appendFileSync(config.ganacheLogFile, `${arg}\n`); + }, }, - }, - verbose: env.parseBoolean(EnvVars.SolidityCoverage), - networkId: config.networkId, - mnemonic: config.mnemonic, - }), -); + verbose: env.parseBoolean(EnvVars.SolidityCoverage), + networkId: config.networkId, + mnemonic: config.mnemonic, + }), + ); +} else { + provider.addProvider(new RpcSubprovider({ rpcUrl: 'http://localhost:8501' })); +} provider.start(); const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage); +const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler); +if (isCoverageEnabled && isProfilerEnabled) { + throw new Error( + `Unfortunately for now you can't enable both coverage and profiler at the same time. They both use coverage.json file and there is no way to configure that.`, + ); +} if (isCoverageEnabled) { const coverageSubprovider = coverage.getCoverageSubproviderSingleton(); prependSubprovider(provider, coverageSubprovider); } +if (isProfilerEnabled) { + if (testProvider === ProviderType.Ganache) { + logUtils.warn( + "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth. Check README for more details", + ); + process.exit(1); + } + const profilerSubprovider = profiler.getProfilerSubproviderSingleton(); + logUtils.log( + "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards", + ); + profilerSubprovider.stop(); + prependSubprovider(provider, profilerSubprovider); +} export const web3Wrapper = new Web3Wrapper(provider); |