Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit a6654de

Browse files
authored
Merge pull request #410 from LefterisJP/add_extra_args_to_solc
Add extra args to solc
2 parents b118aef + aa0180b commit a6654de

File tree

2 files changed

+67
-53
lines changed

2 files changed

+67
-53
lines changed

ethereum/_solidity.py

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import re
44
import subprocess
55
import warnings
6+
import shlex
67

78
import yaml
89

@@ -45,16 +46,22 @@ def get_solidity():
4546
return solc_wrapper
4647

4748

48-
def solc_arguments(libraries=None, combined='bin,abi', optimize=True):
49+
def solc_arguments(libraries=None, combined='bin,abi', optimize=True, extra_args=None):
4950
""" Build the arguments to call the solc binary. """
5051
args = [
5152
'--combined-json', combined,
52-
'--add-std',
53+
'--add-std'
5354
]
5455

5556
if optimize:
5657
args.append('--optimize')
5758

59+
if extra_args:
60+
try:
61+
args.extend(shlex.split(extra_args))
62+
except: # if not a parseable string then treat it as a list
63+
args.extend(extra_args)
64+
5865
if libraries is not None and len(libraries):
5966
addresses = [
6067
'{name}:{address}'.format(name=name, address=address.decode('utf8'))
@@ -70,6 +77,10 @@ def solc_arguments(libraries=None, combined='bin,abi', optimize=True):
7077

7178
def solc_parse_output(compiler_output):
7279
""" Parses the compiler output. """
80+
# At the moment some solc output like --hashes or -- gas will not output
81+
# json at all so if used with those arguments the logic here will break.
82+
# Perhaps solidity will slowly switch to a json only output and this comment
83+
# can eventually go away and we will not need to add more logic here at all.
7384
result = yaml.safe_load(compiler_output)['contracts']
7485

7586
if 'bin' in tuple(result.values())[0]:
@@ -98,7 +109,7 @@ def solc_parse_output(compiler_output):
98109
def compiler_version():
99110
""" Return the version of the installed solc. """
100111
version_info = subprocess.check_output(['solc', '--version'])
101-
match = re.search('^Version: ([0-9a-z.-]+)/', version_info, re.MULTILINE)
112+
match = re.search(b'^Version: ([0-9a-z.-]+)/', version_info, re.MULTILINE)
102113

103114
if match:
104115
return match.group(1)
@@ -190,7 +201,7 @@ def solidity_resolve_address(hex_code, library_symbol, library_address):
190201
raise ValueError('Address should not contain the 0x prefix')
191202

192203
try:
193-
_ = decode_hex(library_address)
204+
decode_hex(library_address)
194205
except TypeError:
195206
raise ValueError('library_address contains invalid characters, it must be hex encoded.')
196207

@@ -226,7 +237,7 @@ def solidity_unresolved_symbols(hex_code):
226237
return set(re.findall(r"_.{39}", hex_code))
227238

228239

229-
def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True):
240+
def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True, extra_args=None):
230241
""" Return the compile contract code.
231242
232243
Args:
@@ -241,7 +252,7 @@ def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True):
241252

242253
workdir, filename = os.path.split(filepath)
243254

244-
args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize)
255+
args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize, extra_args=extra_args)
245256
args.insert(0, get_compiler_path())
246257
args.append(filename)
247258

@@ -250,18 +261,19 @@ def compile_file(filepath, libraries=None, combined='bin,abi', optimize=True):
250261
return solc_parse_output(output)
251262

252263

253-
def compile_contract(filepath, contract_name, libraries=None, combined='bin,abi', optimize=True):
264+
def compile_contract(filepath, contract_name, libraries=None, combined='bin,abi', optimize=True, extra_args=None):
254265
all_contracts = compile_file(
255266
filepath,
256267
libraries=libraries,
257268
combined=combined,
258269
optimize=optimize,
270+
extra_args=extra_args
259271
)
260272

261273
return all_contracts[contract_name]
262274

263275

264-
def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize=True):
276+
def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize=True, extra_args=None):
265277
with open(filepath) as handler:
266278
all_names = solidity_names(handler.read())
267279

@@ -278,11 +290,12 @@ def compile_last_contract(filepath, libraries=None, combined='bin,abi', optimize
278290
libraries=libraries,
279291
combined=combined,
280292
optimize=optimize,
293+
extra_args=extra_args
281294
)
282295

283296

284-
def compile_code(sourcecode, libraries=None, combined='bin,abi', optimize=True):
285-
args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize)
297+
def compile_code(sourcecode, libraries=None, combined='bin,abi', optimize=True, extra_args=None):
298+
args = solc_arguments(libraries=libraries, combined=combined, optimize=optimize, extra_args=extra_args)
286299
args.insert(0, get_compiler_path())
287300

288301
process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -302,17 +315,17 @@ class Solc(object):
302315
compiler_version = staticmethod(compiler_version)
303316

304317
@staticmethod
305-
def _code_or_path(sourcecode, path, contract_name, libraries, combined):
318+
def _code_or_path(sourcecode, path, contract_name, libraries, combined, extra_args):
306319
warnings.warn('solc_wrapper is deprecated, please use the functions compile_file or compile_code')
307320

308321
if sourcecode and path:
309322
raise ValueError('sourcecode and path are mutually exclusive.')
310323

311324
if path and contract_name:
312-
return compile_contract(path, contract_name, libraries=libraries, combined=combined)
325+
return compile_contract(path, contract_name, libraries=libraries, combined=combined, extra_args=extra_args)
313326

314327
if path:
315-
return compile_last_contract(path, libraries=libraries, combined=combined)
328+
return compile_last_contract(path, libraries=libraries, combined=combined, extra_args=extra_args)
316329

317330
all_names = solidity_names(sourcecode)
318331
all_contract_names = [
@@ -321,41 +334,44 @@ def _code_or_path(sourcecode, path, contract_name, libraries, combined):
321334
]
322335
last_contract = all_contract_names[-1]
323336

324-
result = compile_code(sourcecode, libraries=libraries, combined=combined)
337+
result = compile_code(sourcecode, libraries=libraries, combined=combined, extra_args=extra_args)
325338
return result[last_contract]
326339

327340
@classmethod
328-
def compile(cls, code, path=None, libraries=None, contract_name=''):
341+
def compile(cls, code, path=None, libraries=None, contract_name='', extra_args=None):
329342
""" Return the binary of last contract in code. """
330-
result = cls._code_or_path(code, path, contract_name, libraries, 'bin')
343+
result = cls._code_or_path(code, path, contract_name, libraries, 'bin', extra_args)
331344
return result['bin']
332345

333346
@classmethod
334-
def mk_full_signature(cls, code, path=None, libraries=None, contract_name=''):
347+
def mk_full_signature(cls, code, path=None, libraries=None, contract_name='', extra_args=None):
335348
"returns signature of last contract in code"
336349

337-
result = cls._code_or_path(code, path, contract_name, libraries, 'abi')
350+
result = cls._code_or_path(code, path, contract_name, libraries, 'abi', extra_args)
338351
return result['abi']
339352

340353
@classmethod
341-
def combined(cls, code, path=None):
354+
def combined(cls, code, path=None, extra_args=None):
342355
""" Compile combined-json with abi,bin,devdoc,userdoc.
343356
344357
@param code: literal solidity code as a string.
345-
@param path: absolute path to solidity-file. Note: code & path are exclusive!
358+
@param path: absolute path to solidity-file. Note: code & path are
359+
mutually exclusive!
360+
@param extra_args: Either a space separated string or a list of extra
361+
arguments to be passed to the solidity compiler.
346362
"""
347363

348364
if code and path:
349365
raise ValueError('sourcecode and path are mutually exclusive.')
350366

351367
if path:
352-
contracts = compile_file(path)
368+
contracts = compile_file(path, extra_args=extra_args)
353369

354370
with open(path) as handler:
355371
code = handler.read()
356372

357373
elif code:
358-
contracts = compile_code(code)
374+
contracts = compile_code(code, extra_args=extra_args)
359375

360376
else:
361377
raise ValueError('either code or path needs to be supplied.')
@@ -366,7 +382,7 @@ def combined(cls, code, path=None):
366382
return sorted_contracts
367383

368384
@classmethod
369-
def compile_rich(cls, code, path=None):
385+
def compile_rich(cls, code, path=None, extra_args=None):
370386
"""full format as returned by jsonrpc"""
371387

372388
return {
@@ -383,7 +399,7 @@ def compile_rich(cls, code, path=None):
383399
},
384400
}
385401
for contract_name, contract
386-
in cls.combined(code, path=path)
402+
in cls.combined(code, path=path, extra_args=extra_args)
387403
}
388404

389405

ethereum/tests/test_solidity.py

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
CONTRACTS_DIR = path.join(path.dirname(__file__), 'contracts')
1515

1616

17+
def bytecode_is_generated(cinfo, cname):
18+
return 'code' in cinfo[cname] and len(cinfo[cname]['code']) > 10
19+
1720
@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available')
1821
def test_library_from_file():
1922
state = tester.state()
@@ -188,7 +191,6 @@ def test_constructor():
188191
assert contract.getValue() == 2
189192

190193

191-
@pytest.mark.xfail(reason='bytecode in test seems to be wrong')
192194
@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available')
193195
def test_solidity_compile_rich():
194196
compile_rich_contract = """
@@ -211,22 +213,9 @@ def test_solidity_compile_rich():
211213
'language', 'languageVersion', 'abiDefinition', 'source',
212214
'compilerVersion', 'developerDoc', 'userDoc'
213215
}
214-
assert contract_info['contract_add']['code'] == (
215-
'0x606060405260ad8060116000396000f30060606040526000357c0100000000000000'
216-
'00000000000000000000000000000000000000000090048063651ae239146041578063'
217-
'cb02919f14606657603f565b005b6050600480359060200150608b565b604051808281'
218-
'5260200191505060405180910390f35b6075600480359060200150609c565b60405180'
219-
'82815260200191505060405180910390f35b60006007820190506097565b919050565b'
220-
'6000602a8201905060a8565b91905056'
221-
)
222-
assert contract_info['contract_sub']['code'] == (
223-
'0x606060405260ad8060116000396000f30060606040526000357c0100000000000000'
224-
'0000000000000000000000000000000000000000009004806361752024146041578063'
225-
'7aaef1a014606657603f565b005b6050600480359060200150608b565b604051808281'
226-
'5260200191505060405180910390f35b6075600480359060200150609c565b60405180'
227-
'82815260200191505060405180910390f35b60006007820390506097565b919050565b'
228-
'6000602a8203905060a8565b91905056'
229-
)
216+
assert bytecode_is_generated(contract_info, 'contract_add')
217+
assert bytecode_is_generated(contract_info, 'contract_sub')
218+
230219
assert {
231220
defn['name']
232221
for defn
@@ -252,22 +241,31 @@ def test_abi_contract():
252241
}
253242
"""
254243

255-
two_contracts = one_contract + """
256-
contract baz {
257-
function echo(address a) returns (address b) {
258-
b = a;
259-
return b;
260-
}
261-
function eight() returns (int256 y) {
262-
y = 8;
263-
}
264-
}
265-
"""
266-
267244
state = tester.state()
268245
contract = state.abi_contract(one_contract, language='solidity')
269246

270247
# pylint: disable=no-member
271248
assert contract.seven() == 7
272249
assert contract.mul2(2) == 4
273250
assert contract.mul2(-2) == -4
251+
252+
@pytest.mark.skipif(not SOLIDITY_AVAILABLE, reason='solc compiler not available')
253+
def test_extra_args():
254+
src = """
255+
contract foo {
256+
function add7(uint a) returns(uint d) { return a + 7; }
257+
function add42(uint a) returns(uint d) { return a + 42; }
258+
}
259+
"""
260+
261+
contract_info = get_solidity().compile_rich(
262+
src,
263+
extra_args="--optimize-runs 100"
264+
)
265+
assert bytecode_is_generated(contract_info, 'foo')
266+
267+
contract_info = get_solidity().compile_rich(
268+
src,
269+
extra_args=["--optimize-runs", "100"]
270+
)
271+
assert bytecode_is_generated(contract_info, 'foo')

0 commit comments

Comments
 (0)