js: Add stats and override options (#348)

- Add `RESOLC_BIN` env variable to force use a binary compiler instead
of the wasm
- Add `--diff-stats` options to print file path 

e.g

```
~/github/redstone-oracles-monorepo main*
❯ npx @parity/resolc@latest --diff-stats \
  --base-path . \
  --include-path node_modules \
  --bin packages/evm-connector/contracts/samples/SampleWithEvents.sol
┌─────────┬──────────────────────────────────────────────────────────────────────────┬───────────────────────────────┬────────────┬────────────┬───────────┐
│ (index) │ file                                                                     │ contract                      │ polkavm    │ bin        │ diff      │
├─────────┼──────────────────────────────────────────────────────────────────────────┼───────────────────────────────┼────────────┼────────────┼───────────┤
│ 0       │ 'packages/evm-connector/contracts/core/CalldataExtractor.sol'            │ 'CalldataExtractor'           │ '4.31 kB'  │ '2.53 kB'  │ '70.12%'  │
│ 1       │ 'packages/evm-connector/contracts/core/RedstoneConstants.sol'            │ 'RedstoneConstants'           │ '0.80 kB'  │ '0.17 kB'  │ '368.18%' │
│ 2       │ 'packages/evm-connector/contracts/core/RedstoneDefaultsLib.sol'          │ 'RedstoneDefaultsLib'         │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 3       │ 'packages/evm-connector/contracts/libs/BitmapLib.sol'                    │ 'BitmapLib'                   │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 4       │ 'packages/evm-connector/contracts/libs/NumericArrayLib.sol'              │ 'NumericArrayLib'             │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 5       │ 'packages/evm-connector/contracts/libs/SignatureLib.sol'                 │ 'SignatureLib'                │ '0.90 kB'  │ '0.31 kB'  │ '189.06%' │
│ 6       │ 'packages/evm-connector/contracts/mocks/RedstoneConsumerNumericMock.sol' │ 'RedstoneConsumerNumericMock' │ '13.62 kB' │ '10.17 kB' │ '33.96%'  │
│ 7       │ 'packages/evm-connector/contracts/samples/SampleWithEvents.sol'          │ 'SampleWithEvents'            │ '29.34 kB' │ '15.60 kB' │ '88.03%'  │
└─────────┴──────────────────────────────────────────────────────────────────────────┴───────────────────────────────┴────────────┴────────────┴───────────┘
```
This commit is contained in:
PG Herveou
2025-06-19 12:17:09 +02:00
committed by GitHub
parent 8754d802fa
commit 7656c6a8b4
2 changed files with 57 additions and 16 deletions
+55 -10
View File
@@ -6,6 +6,7 @@ import * as os from 'os'
import * as path from 'path' import * as path from 'path'
import * as resolc from '.' import * as resolc from '.'
import { SolcInput } from '.' import { SolcInput } from '.'
import { execSync } from 'child_process'
async function main() { 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 // 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() const program = new commander.Command()
program.name('solcjs') program.name('resolcjs')
program.version(resolc.version()) program.version(resolc.version())
program program
.option('--bin', 'Binary of the contracts in hex.') .option('--bin', 'Binary of the contracts in hex.')
.option('--abi', 'ABI of the contracts.') .option('--abi', 'ABI of the contracts.')
.option(
'--diff-stats',
'Print statistics about Resolc vs Solc compilation.'
)
.option( .option(
'--base-path <path>', '--base-path <path>',
'Root of the project source tree. ' + 'Root of the project source tree. ' +
@@ -49,8 +54,20 @@ async function main() {
outputDir?: string outputDir?: string
prettyJson: boolean prettyJson: boolean
basePath?: string basePath?: string
diffStats: boolean
includePath?: string[] 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 files: string[] = program.args
const destination = options.outputDir ?? '.' const destination = options.outputDir ?? '.'
@@ -137,7 +154,7 @@ async function main() {
if (!output) { if (!output) {
abort('No output from compiler') abort('No output from compiler')
} else if (output.errors) { } else if (output.errors && !options.diffStats) {
for (const error in output.errors) { for (const error in output.errors) {
const message = output.errors[error] const message = output.errors[error]
if (message.severity === 'warning') { if (message.severity === 'warning') {
@@ -160,19 +177,41 @@ async function main() {
}) })
} }
const contractStats = []
for (const fileName in output.contracts) { for (const fileName in output.contracts) {
for (const contractName in output.contracts[fileName]) { for (const contractName in output.contracts[fileName]) {
let contractFileName = fileName + ':' + contractName let contractFileName = fileName + ':' + contractName
contractFileName = contractFileName.replace(/[:./\\]/g, '_') contractFileName = contractFileName.replace(/[:./\\]/g, '_')
let polkavmSize = 0
if (options.bin) { let binSize = 0
writeFile( if (
contractFileName + '.polkavm', options.bin &&
Buffer.from( output.contracts?.[fileName]?.[contractName]?.evm?.bytecode?.object
output.contracts[fileName][contractName].evm.bytecode.object, ) {
'hex' 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) { 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. // Put back original exception handlers.
originalUncaughtExceptionListeners.forEach(function (listener) { originalUncaughtExceptionListeners.forEach(function (listener) {
process.addListener('uncaughtException', listener) process.addListener('uncaughtException', listener)
+2 -6
View File
@@ -50,11 +50,7 @@ export function resolveInputs(sources: SolcInput): SolcInput {
language: 'Solidity', language: 'Solidity',
sources, sources,
settings: { settings: {
outputSelection: { outputSelection: {}, // no outputs requested, only resolves imports
'*': {
'*': ['evm.bytecode.object'],
},
},
}, },
} }
@@ -106,7 +102,7 @@ export async function compile(
enabled: true, enabled: true,
runs: 200, runs: 200,
}, },
bin, bin = process.env.RESOLC_BIN,
} = option } = option
const input = JSON.stringify({ const input = JSON.stringify({