parent
5f79db8020
commit
f83465c641
299
lib/Compiler.js
299
lib/Compiler.js
|
@ -3,43 +3,10 @@ const shelljs = require('shelljs');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
function compileSolcContract(logger, file, allowedDirectories, remappings, solcConfig, callback) {
|
function compileSolcContract(logger, compileSettings, allowedDirectories, callback) {
|
||||||
let input = {};
|
|
||||||
|
|
||||||
const filename = file.pluginPath ? path.join(file.pluginPath, file.filename) : file.filename;
|
|
||||||
input[filename] = {content: file.parsedContent.replace(/\r\n/g, '\n'), path: filename};
|
|
||||||
|
|
||||||
let jsonObj = {
|
|
||||||
language: 'Solidity',
|
|
||||||
sources: input,
|
|
||||||
settings: {
|
|
||||||
optimizer: {
|
|
||||||
enabled: solcConfig['optimize'],
|
|
||||||
runs: solcConfig['optimize-runs']
|
|
||||||
},
|
|
||||||
remappings,
|
|
||||||
outputSelection: {
|
|
||||||
'*': {
|
|
||||||
'': ['ast'],
|
|
||||||
'*': [
|
|
||||||
'abi',
|
|
||||||
'devdoc',
|
|
||||||
'evm.bytecode',
|
|
||||||
'evm.deployedBytecode',
|
|
||||||
'evm.gasEstimates',
|
|
||||||
'evm.legacyAssembly',
|
|
||||||
'evm.methodIdentifiers',
|
|
||||||
'metadata',
|
|
||||||
'userdoc'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const command = `solc --standard-json --allow-paths ${allowedDirectories.join(',')}`;
|
const command = `solc --standard-json --allow-paths ${allowedDirectories.join(',')}`;
|
||||||
|
|
||||||
shelljs.ShellString(JSON.stringify(jsonObj)).exec(command, {silent: true}, (code, stdout, stderr) => {
|
shelljs.ShellString(JSON.stringify(compileSettings)).exec(command, {silent: true}, (code, stdout, stderr) => {
|
||||||
if (stderr) {
|
if (stderr) {
|
||||||
logger.warn(stderr);
|
logger.warn(stderr);
|
||||||
}
|
}
|
||||||
|
@ -75,9 +42,9 @@ function getSolcVersion(logger, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileSolc(embark, contractFiles, contractDirectories, cb) {
|
function compileSolc(embark, contractFiles, contractDirectories, callback) {
|
||||||
if (!contractFiles || !contractFiles.length) {
|
if (!contractFiles || !contractFiles.length) {
|
||||||
return cb();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
const logger = embark.logger;
|
const logger = embark.logger;
|
||||||
|
@ -85,113 +52,165 @@ function compileSolc(embark, contractFiles, contractDirectories, cb) {
|
||||||
const outputDir = embark.config.buildDir + embark.config.contractDirectories[0];
|
const outputDir = embark.config.buildDir + embark.config.contractDirectories[0];
|
||||||
const solcConfig = embark.config.embarkConfig.options.solc;
|
const solcConfig = embark.config.embarkConfig.options.solc;
|
||||||
|
|
||||||
const solc = shelljs.which('solc');
|
let allowedDirectories;
|
||||||
if (!solc) {
|
const remappings = [];
|
||||||
logger.error('solc is not installed on your machine');
|
const compilationSettings = {
|
||||||
logger.info('You can install it by following the instructions on: http://solidity.readthedocs.io/en/latest/installing-solidity.html');
|
language: 'Solidity',
|
||||||
return cb('Compiler not installed');
|
sources: {},
|
||||||
}
|
settings: {
|
||||||
|
optimizer: {
|
||||||
logger.info("compiling solidity contracts with command line solc...");
|
enabled: solcConfig['optimize'],
|
||||||
|
runs: solcConfig['optimize-runs']
|
||||||
const allowedDirectories = contractFiles.map((contractFile) => path.join(process.cwd(), path.dirname(contractFile.path) + '/'))
|
|
||||||
.filter((x, i, a) => a.indexOf(x) === i);
|
|
||||||
// Add default contract paths
|
|
||||||
allowedDirectories.push(
|
|
||||||
path.join(process.cwd(), 'node_modules/'),
|
|
||||||
path.join(process.cwd(), '.embark/contracts/')
|
|
||||||
);
|
|
||||||
|
|
||||||
const remappings = []; // Will get populated by compilations
|
|
||||||
// Get content and remappings
|
|
||||||
async.each(contractFiles, (file, eachCb) => {
|
|
||||||
file.content(content => {
|
|
||||||
file.parsedContent = content;
|
|
||||||
const newRemappings = file.importRemappings.map((mapping) => `${mapping.prefix}=${mapping.target}`);
|
|
||||||
newRemappings.forEach(newRemapping => {
|
|
||||||
if (!remappings.includes(newRemapping)) {
|
|
||||||
remappings.push(newRemapping);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
eachCb();
|
|
||||||
});
|
|
||||||
}, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
let compiled_object = {};
|
|
||||||
async.each(contractFiles,
|
|
||||||
function(file, callback) {
|
|
||||||
compileSolcContract(logger, file, allowedDirectories, remappings, solcConfig, (err, compileString) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
let json;
|
|
||||||
try {
|
|
||||||
json = JSON.parse(compileString);
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(e.message || e);
|
|
||||||
return callback(`Compiling ${file} returned an unreadable result`);
|
|
||||||
}
|
|
||||||
const contracts = json.contracts;
|
|
||||||
|
|
||||||
if (json.errors) {
|
|
||||||
let isError = false;
|
|
||||||
json.errors.forEach(error => {
|
|
||||||
if (error.severity === 'error') {
|
|
||||||
isError = true;
|
|
||||||
logger.error(error.formattedMessage);
|
|
||||||
} else {
|
|
||||||
logger.warn(error.formattedMessage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isError) {
|
|
||||||
return callback(`Error while compiling ${file.filename}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let contractFile in contracts) {
|
|
||||||
for (let contractName in contracts[contractFile]) {
|
|
||||||
let contract = contracts[contractFile][contractName];
|
|
||||||
let filename = contractFile;
|
|
||||||
const originalFilename = filename;
|
|
||||||
for (let directory of contractDirectories) {
|
|
||||||
let match = new RegExp("^" + directory);
|
|
||||||
filename = filename.replace(match, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
const className = contractName;
|
|
||||||
|
|
||||||
compiled_object[className] = {};
|
|
||||||
compiled_object[className].code = contract.evm.bytecode.object;
|
|
||||||
compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object;
|
|
||||||
compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
|
|
||||||
compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);
|
|
||||||
compiled_object[className].gasEstimates = contract.evm.gasEstimates;
|
|
||||||
compiled_object[className].functionHashes = contract.evm.methodIdentifiers;
|
|
||||||
compiled_object[className].abiDefinition = contract.abi;
|
|
||||||
compiled_object[className].filename = filename;
|
|
||||||
compiled_object[className].originalFilename = originalFilename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
function(err) {
|
remappings,
|
||||||
cb(err, compiled_object);
|
outputSelection: {
|
||||||
if (outputBinary) {
|
'*': {
|
||||||
embark.events.on("outputDone", function() {
|
'': ['ast'],
|
||||||
Object.keys(compiled_object).map(function(className, _index) {
|
'*': [
|
||||||
fs.writeFile(path.join(outputDir, className + ".bin"), compiled_object[className].code, (err) => {
|
'abi',
|
||||||
if (err) {
|
'devdoc',
|
||||||
logger.error("Error writing binary file: " + JSON.stringify(err));
|
'evm.bytecode',
|
||||||
}
|
'evm.deployedBytecode',
|
||||||
});
|
'evm.gasEstimates',
|
||||||
});
|
'evm.legacyAssembly',
|
||||||
|
'evm.methodIdentifiers',
|
||||||
|
'metadata',
|
||||||
|
'userdoc'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function checkSolc(next) {
|
||||||
|
const solc = shelljs.which('solc');
|
||||||
|
if (!solc) {
|
||||||
|
logger.error('solc is not installed on your machine');
|
||||||
|
logger.info('You can install it by following the instructions on: http://solidity.readthedocs.io/en/latest/installing-solidity.html');
|
||||||
|
return next('Compiler not installed');
|
||||||
|
}
|
||||||
|
logger.info("compiling solidity contracts with command line solc...");
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
function getAllowedDirectories(next) {
|
||||||
|
allowedDirectories = contractFiles.map((contractFile) => path.join(process.cwd(), path.dirname(contractFile.path) + '/'))
|
||||||
|
.filter((x, i, a) => a.indexOf(x) === i);
|
||||||
|
// Add default contract paths
|
||||||
|
allowedDirectories.push(
|
||||||
|
path.join(process.cwd(), 'node_modules/'),
|
||||||
|
path.join(process.cwd(), '.embark/contracts/')
|
||||||
|
);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
function getContentAndRemappings(next) {
|
||||||
|
async.each(contractFiles, (file, eachCb) => {
|
||||||
|
file.content(content => {
|
||||||
|
file.parsedContent = content;
|
||||||
|
|
||||||
|
const newRemappings = file.importRemappings.map((mapping) => `${mapping.prefix}=${mapping.target}`);
|
||||||
|
newRemappings.forEach(newRemapping => {
|
||||||
|
if (!remappings.includes(newRemapping)) {
|
||||||
|
remappings.push(newRemapping);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
eachCb();
|
||||||
|
});
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
|
||||||
|
function getCompilationSettings(next) {
|
||||||
|
contractFiles.forEach(file => {
|
||||||
|
const filename = file.pluginPath ? path.join(file.pluginPath, file.filename) : file.filename;
|
||||||
|
compilationSettings.sources[filename] = {
|
||||||
|
content: file.parsedContent.replace(/\r\n/g, '\n'),
|
||||||
|
path: filename
|
||||||
|
};
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
|
||||||
|
function compile(next) {
|
||||||
|
compileSolcContract(logger, compilationSettings, allowedDirectories, (err, compileString) => {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
let json;
|
||||||
|
try {
|
||||||
|
json = JSON.parse(compileString);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(e.message || e);
|
||||||
|
return callback(`Compiling returned an unreadable result`);
|
||||||
|
}
|
||||||
|
const contracts = json.contracts;
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
if (json.errors) {
|
||||||
|
let isError = false;
|
||||||
|
json.errors.forEach(error => {
|
||||||
|
if (error.severity === 'error') {
|
||||||
|
isError = true;
|
||||||
|
logger.error(error.formattedMessage);
|
||||||
|
} else {
|
||||||
|
logger.warn(error.formattedMessage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (isError) {
|
||||||
|
return next(`Error while compiling`);
|
||||||
|
}
|
||||||
|
|
||||||
|
next(null, contracts);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function populateCompiledObject(contracts, next) {
|
||||||
|
const compiledObject = {};
|
||||||
|
for (let contractFile in contracts) {
|
||||||
|
for (let contractName in contracts[contractFile]) {
|
||||||
|
let contract = contracts[contractFile][contractName];
|
||||||
|
let filename = contractFile;
|
||||||
|
const originalFilename = filename;
|
||||||
|
for (let directory of contractDirectories) {
|
||||||
|
let match = new RegExp("^" + directory);
|
||||||
|
filename = filename.replace(match, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
const className = contractName;
|
||||||
|
|
||||||
|
compiledObject[className] = {};
|
||||||
|
compiledObject[className].code = contract.evm.bytecode.object;
|
||||||
|
compiledObject[className].runtimeBytecode = contract.evm.deployedBytecode.object;
|
||||||
|
compiledObject[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
|
||||||
|
compiledObject[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);
|
||||||
|
compiledObject[className].gasEstimates = contract.evm.gasEstimates;
|
||||||
|
compiledObject[className].functionHashes = contract.evm.methodIdentifiers;
|
||||||
|
compiledObject[className].abiDefinition = contract.abi;
|
||||||
|
compiledObject[className].filename = filename;
|
||||||
|
compiledObject[className].originalFilename = originalFilename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next(null, compiledObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
], (err, compiledObject) => {
|
||||||
|
callback(err, compiledObject);
|
||||||
|
|
||||||
|
if (outputBinary) {
|
||||||
|
embark.events.once("outputDone", function() {
|
||||||
|
Object.keys(compiledObject).map(function(className, _index) {
|
||||||
|
fs.writeFile(path.join(outputDir, className + ".bin"), compiledObject[className].code, (err) => {
|
||||||
|
if (err) {
|
||||||
|
logger.error("Error writing binary file: " + JSON.stringify(err));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue