diff --git a/js/resolc/src/bin.ts b/js/resolc/src/bin.ts index a607ad3..3b64757 100755 --- a/js/resolc/src/bin.ts +++ b/js/resolc/src/bin.ts @@ -6,6 +6,7 @@ import * as os from 'os' import * as path from 'path' import * as resolc from '.' import { SolcInput } from '.' +import { execSync } from 'child_process' async function main() { // hold on to any exception handlers that existed prior to this script running, we'll be adding them back at the end @@ -17,11 +18,15 @@ async function main() { const program = new commander.Command() - program.name('solcjs') + program.name('resolcjs') program.version(resolc.version()) program .option('--bin', 'Binary of the contracts in hex.') .option('--abi', 'ABI of the contracts.') + .option( + '--diff-stats', + 'Print statistics about Resolc vs Solc compilation.' + ) .option( '--base-path ', 'Root of the project source tree. ' + @@ -49,8 +54,20 @@ async function main() { outputDir?: string prettyJson: boolean basePath?: string + diffStats: boolean includePath?: string[] }>() + + // when using --stats option, we want to run solc as well to compare outputs size + if (options.diffStats) { + const args = process.argv.filter((arg) => !arg.startsWith('--diff-stats')) + try { + execSync(`npx --yes solc@latest ${args.slice(2).join(' ')}`) + } catch (err) { + abort(`Failed to run solc: ${err}`) + } + } + const files: string[] = program.args const destination = options.outputDir ?? '.' @@ -137,7 +154,7 @@ async function main() { if (!output) { abort('No output from compiler') - } else if (output.errors) { + } else if (output.errors && !options.diffStats) { for (const error in output.errors) { const message = output.errors[error] if (message.severity === 'warning') { @@ -160,19 +177,41 @@ async function main() { }) } + const contractStats = [] + for (const fileName in output.contracts) { for (const contractName in output.contracts[fileName]) { let contractFileName = fileName + ':' + contractName contractFileName = contractFileName.replace(/[:./\\]/g, '_') - - if (options.bin) { - writeFile( - contractFileName + '.polkavm', - Buffer.from( - output.contracts[fileName][contractName].evm.bytecode.object, - 'hex' - ) + let polkavmSize = 0 + let binSize = 0 + if ( + options.bin && + output.contracts?.[fileName]?.[contractName]?.evm?.bytecode?.object + ) { + const pvmData = Buffer.from( + output.contracts[fileName][contractName].evm.bytecode.object, + 'hex' ) + writeFile(contractFileName + '.polkavm', pvmData) + polkavmSize = pvmData.length + + const binOutPath = path.join(destination, `${contractFileName}.bin`) + if (fs.existsSync(binOutPath)) { + try { + binSize = fs.statSync(binOutPath).size || 0 + } catch {} + } + contractStats.push({ + file: fileName, + contract: contractName, + ['resolc (kB)']: Number((polkavmSize / 1024).toFixed(2)), + ['solc (kB)']: Number((binSize / 1024).toFixed(2)), + ['diff (%)']: + binSize > 0 + ? Number(((polkavmSize / binSize - 1) * 100).toFixed(2)) + : Number.NaN, + }) } if (options.abi) { @@ -184,6 +223,12 @@ async function main() { } } + if (options.diffStats && contractStats.length > 0) { + console.table( + contractStats.sort((a, b) => b['resolc (kB)'] - a['resolc (kB)']) + ) + } + // Put back original exception handlers. originalUncaughtExceptionListeners.forEach(function (listener) { process.addListener('uncaughtException', listener) diff --git a/js/resolc/src/index.ts b/js/resolc/src/index.ts index 9b3ab60..ea61bf4 100644 --- a/js/resolc/src/index.ts +++ b/js/resolc/src/index.ts @@ -50,11 +50,7 @@ export function resolveInputs(sources: SolcInput): SolcInput { language: 'Solidity', sources, settings: { - outputSelection: { - '*': { - '*': ['evm.bytecode.object'], - }, - }, + outputSelection: {}, // no outputs requested, only resolves imports }, } @@ -106,7 +102,7 @@ export async function compile( enabled: true, runs: 200, }, - bin, + bin = process.env.RESOLC_BIN, } = option const input = JSON.stringify({