Skip to content

Instantly share code, notes, and snippets.

@spalladino
Created January 29, 2020 21:41
Show Gist options
  • Save spalladino/3c27d8d9c90d8a9566d11091165a87c1 to your computer and use it in GitHub Desktop.
Save spalladino/3c27d8d9c90d8a9566d11091165a87c1 to your computer and use it in GitHub Desktop.
Guess solc settings used to compile a given contract
#!/usr/bin/env python3
import json
import subprocess
import sys
import re
VERSIONS = [f'0.5.{minor}' for minor in range(0,16)]
RUNS = [0, 100, 200, 300]
TARGETS = ['byzantium', 'constantinople', 'petersburg', 'istanbul']
OPTIMIZERS = [False, True]
def guess(contractname, expected):
for version in VERSIONS:
for target in TARGETS:
for optimizer in OPTIMIZERS:
for runs in (RUNS if optimizer else [0]):
result = compile(contractname, version, target, optimizer, runs)
if result:
if check(result, expected):
log(version, target, optimizer, runs, "MATCH FOUND")
return (version, target, optimizer, runs)
else: log(version, target, optimizer, runs, "NO MATCH")
def compile(contractname, version, target, optimizer, runs):
optimizerstr = "on" if optimizer else "off"
result = subprocess.run([
"openzeppelin", "compile",
"--solc-version", str(version),
"--optimizer", optimizerstr,
"--optimizer-runs", str(runs),
"--evm-version", target,
"--no-interactive"], shell=False)
if result.returncode != 0:
log(version, target, optimizer, runs, "COMPILATION FAILED")
return
with open(f'build/contracts/{contractname}.json') as artifactfile:
artifact = json.load(artifactfile)
return artifact['deployedBytecode']
def check(result, expected):
return removemetadata(result) == removemetadata(expected)
def removemetadata(bytecode):
length = int(bytecode[-4:], 16) * 2
return bytecode[:-length]
def log(version, target, optimizer, runs, log):
print(f'version={version} target={target} optimizer={optimizer} runs={runs} | {log}')
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python3 guess.py CONTRACTNAME BYTECODE_OR_PATH_TO_BYTECODE")
else:
contractname = sys.argv[1]
expected = sys.argv[2]
if expected[:2] != '0x':
with open(expected) as f:
expected = f.read().strip()
if expected[:2] != '0x':
raise Exception("Expected bytecode to start with 0x")
if not re.match("\A0x[a-f0-9]+\Z", expected):
raise Exception("Non-hex character in expected bytecode")
guess(contractname, expected)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment