Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Commit

Permalink
Merge pull request #1542 from 0xProject/feature/solc-docker
Browse files Browse the repository at this point in the history
Implement docker as another backend for sol-compiler
  • Loading branch information
LogvinovLeon authored Feb 1, 2019
2 parents 78bdc2d + 79adf5c commit ae8d2ae
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 39 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- run:
name: yarn
command: yarn --frozen-lockfile --ignore-engines install
- setup_remote_docker
- run: yarn build:ci:no_website
- run: yarn build:ts
- save_cache:
Expand Down
1 change: 1 addition & 0 deletions contracts/asset-proxy/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/erc20/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/erc721/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/exchange-forwarder/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/exchange-libs/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/exchange/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/extensions/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/multisig/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
1 change: 1 addition & 0 deletions contracts/utils/compiler.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": true,
"compilerSettings": {
"optimizer": {
"enabled": true,
Expand Down
2 changes: 2 additions & 0 deletions packages/ethereum-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ export interface Source {
* (http://solidity.readthedocs.io/en/v0.4.24/using-the-compiler.html#compiler-input-and-output-json-description)
* contracts: List of contract names you wish to compile, or alternatively ['*'] to compile all contracts in the
* specified directory.
* useDockerisedSolc: If set to true - sol-compiler will try calling a dockerized installations of solc to achieve faster compilation times. Otherwise and by default - solcjs will be used. Defaults to false.
* solcVersion: If you don't want to compile each contract with the Solidity version specified in-file, you can force all
* contracts to compile with the the version specified here.
*/
Expand All @@ -517,5 +518,6 @@ export interface CompilerOptions {
artifactsDir?: string;
compilerSettings?: CompilerSettings;
contracts?: string[] | '*';
useDockerisedSolc?: boolean;
solcVersion?: string;
} // tslint:disable-line:max-file-line-count
75 changes: 57 additions & 18 deletions packages/sol-compiler/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
URLResolver,
} from '@0x/sol-resolver';
import { logUtils } from '@0x/utils';
import { execSync } from 'child_process';
import * as chokidar from 'chokidar';
import { CompilerOptions, ContractArtifact, ContractVersionData, StandardOutput } from 'ethereum-types';
import * as fs from 'fs';
Expand All @@ -23,13 +24,16 @@ import { compilerOptionsSchema } from './schemas/compiler_options_schema';
import { binPaths } from './solc/bin_paths';
import {
addHexPrefixToContractBytecode,
compile,
compileDockerAsync,
compileSolcJSAsync,
createDirIfDoesNotExistAsync,
getContractArtifactIfExistsAsync,
getSolcAsync,
getDependencyNameToPackagePath,
getSourcesWithDependencies,
getSourceTreeHash,
makeContractPathsRelative,
parseSolidityVersionRange,
printCompilationErrorsAndWarnings,
} from './utils/compiler';
import { constants } from './utils/constants';
import { fsWrapper } from './utils/fs_wrapper';
Expand All @@ -40,6 +44,7 @@ const ALL_CONTRACTS_IDENTIFIER = '*';
const ALL_FILES_IDENTIFIER = '*';
const DEFAULT_CONTRACTS_DIR = path.resolve('contracts');
const DEFAULT_ARTIFACTS_DIR = path.resolve('artifacts');
const DEFAULT_USE_DOCKERISED_SOLC = false;
// Solc compiler settings cannot be configured from the commandline.
// If you need this configured, please create a `compiler.json` config file
// with your desired configurations.
Expand Down Expand Up @@ -84,6 +89,7 @@ export class Compiler {
private readonly _artifactsDir: string;
private readonly _solcVersionIfExists: string | undefined;
private readonly _specifiedContracts: string[] | TYPE_ALL_FILES_IDENTIFIER;
private readonly _useDockerisedSolc: boolean;
/**
* Instantiates a new instance of the Compiler class.
* @param opts Optional compiler options
Expand All @@ -97,16 +103,17 @@ export class Compiler {
: {};
const passedOpts = opts || {};
assert.doesConformToSchema('compiler.json', config, compilerOptionsSchema);
this._contractsDir = passedOpts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR;
this._contractsDir = path.resolve(passedOpts.contractsDir || config.contractsDir || DEFAULT_CONTRACTS_DIR);
this._solcVersionIfExists = passedOpts.solcVersion || config.solcVersion;
this._compilerSettings = passedOpts.compilerSettings || config.compilerSettings || DEFAULT_COMPILER_SETTINGS;
this._artifactsDir = passedOpts.artifactsDir || config.artifactsDir || DEFAULT_ARTIFACTS_DIR;
this._specifiedContracts = passedOpts.contracts || config.contracts || ALL_CONTRACTS_IDENTIFIER;
this._nameResolver = new NameResolver(path.resolve(this._contractsDir));
this._useDockerisedSolc =
passedOpts.useDockerisedSolc || config.useDockerisedSolc || DEFAULT_USE_DOCKERISED_SOLC;
this._nameResolver = new NameResolver(this._contractsDir);
const resolver = new FallthroughResolver();
resolver.appendResolver(new URLResolver());
const packagePath = path.resolve('');
resolver.appendResolver(new NPMResolver(packagePath));
resolver.appendResolver(new NPMResolver(this._contractsDir));
resolver.appendResolver(new RelativeFSResolver(this._contractsDir));
resolver.appendResolver(new FSResolver());
resolver.appendResolver(this._nameResolver);
Expand Down Expand Up @@ -206,10 +213,12 @@ export class Compiler {
// map contract paths to data about them for later verification and persistence
const contractPathToData: ContractPathToData = {};

const resolvedContractSources = [];
for (const contractName of contractNames) {
const contractSource = this._resolver.resolve(contractName);
const spyResolver = new SpyResolver(this._resolver);
const contractSource = spyResolver.resolve(contractName);
const sourceTreeHashHex = getSourceTreeHash(
this._resolver,
spyResolver,
path.join(this._contractsDir, contractSource.path),
).toString('hex');
const contractData = {
Expand All @@ -236,26 +245,54 @@ export class Compiler {
};
}
// add input to the right version batch
versionToInputs[solcVersion].standardInput.sources[contractSource.path] = {
content: contractSource.source,
};
for (const resolvedContractSource of spyResolver.resolvedContractSources) {
versionToInputs[solcVersion].standardInput.sources[resolvedContractSource.absolutePath] = {
content: resolvedContractSource.source,
};
}
resolvedContractSources.push(...spyResolver.resolvedContractSources);
versionToInputs[solcVersion].contractsToCompile.push(contractSource.path);
}

const compilerOutputs: StandardOutput[] = [];
const dependencyNameToPath = getDependencyNameToPackagePath(resolvedContractSources);

const solcVersions = _.keys(versionToInputs);
for (const solcVersion of solcVersions) {
const compilerOutputs: StandardOutput[] = [];
for (const solcVersion of _.keys(versionToInputs)) {
const input = versionToInputs[solcVersion];
logUtils.warn(
`Compiling ${input.contractsToCompile.length} contracts (${
input.contractsToCompile
}) with Solidity v${solcVersion}...`,
);

const { solcInstance, fullSolcVersion } = await getSolcAsync(solcVersion);
const compilerOutput = compile(this._resolver, solcInstance, input.standardInput);
compilerOutputs.push(compilerOutput);
let compilerOutput;
let fullSolcVersion;
input.standardInput.settings.remappings = _.map(
dependencyNameToPath,
(dependencyPackagePath: string, dependencyName: string) => `${dependencyName}=${dependencyPackagePath}`,
);
if (this._useDockerisedSolc) {
const dockerCommand = `docker run ethereum/solc:${solcVersion} --version`;
const versionCommandOutput = execSync(dockerCommand).toString();
const versionCommandOutputParts = versionCommandOutput.split(' ');
fullSolcVersion = versionCommandOutputParts[versionCommandOutputParts.length - 1].trim();
compilerOutput = await compileDockerAsync(solcVersion, input.standardInput);
} else {
fullSolcVersion = binPaths[solcVersion];
compilerOutput = await compileSolcJSAsync(solcVersion, input.standardInput);
}
if (!_.isUndefined(compilerOutput.errors)) {
printCompilationErrorsAndWarnings(compilerOutput.errors);
}
compilerOutput.sources = makeContractPathsRelative(
compilerOutput.sources,
this._contractsDir,
dependencyNameToPath,
);
compilerOutput.contracts = makeContractPathsRelative(
compilerOutput.contracts,
this._contractsDir,
dependencyNameToPath,
);

for (const contractPath of input.contractsToCompile) {
const contractName = contractPathToData[contractPath].contractName;
Expand All @@ -280,6 +317,8 @@ export class Compiler {
);
}
}

compilerOutputs.push(compilerOutput);
}

return compilerOutputs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const compilerOptionsSchema = {
},
],
},
useDockerisedSolc: { type: 'boolean' },
},
type: 'object',
required: [],
Expand Down
Loading

0 comments on commit ae8d2ae

Please sign in to comment.