prepare_report.py: Add --force-no-optimize-yul flag to work around a bug in solc 0.6.0/0.6.1

This commit is contained in:
Kamil Śliwak 2020-12-22 05:59:46 +01:00
parent 7e48aeb848
commit 49aede680b
2 changed files with 52 additions and 5 deletions

View File

@ -13,7 +13,10 @@ from tempfile import TemporaryDirectory
from typing import List, Optional, Tuple, Union from typing import List, Optional, Tuple, Union
CONTRACT_SEPARATOR_PATTERN = re.compile(r'^ *======= +(?:(?P<file_name>.+) *:)? *(?P<contract_name>[^:]+) +======= *$', re.MULTILINE) CONTRACT_SEPARATOR_PATTERN = re.compile(
r'^ *======= +(?:(?P<file_name>.+) *:)? *(?P<contract_name>[^:]+) +======= *$',
re.MULTILINE
)
BYTECODE_REGEX = re.compile(r'^ *Binary: *\n(?P<bytecode>.*[0-9a-f$_]+.*)$', re.MULTILINE) BYTECODE_REGEX = re.compile(r'^ *Binary: *\n(?P<bytecode>.*[0-9a-f$_]+.*)$', re.MULTILINE)
METADATA_REGEX = re.compile(r'^ *Metadata: *\n *(?P<metadata>\{.*\}) *$', re.MULTILINE) METADATA_REGEX = re.compile(r'^ *Metadata: *\n *(?P<metadata>\{.*\}) *$', re.MULTILINE)
@ -136,13 +139,15 @@ def parse_cli_output(source_file_name: Path, cli_output: str) -> FileReport:
return file_report return file_report
def prepare_compiler_input( def prepare_compiler_input( # pylint: disable=too-many-arguments
compiler_path: Path, compiler_path: Path,
source_file_name: Path, source_file_name: Path,
optimize: bool, optimize: bool,
force_no_optimize_yul: bool,
interface: CompilerInterface, interface: CompilerInterface,
smt_use: SMTUse, smt_use: SMTUse,
) -> Tuple[List[str], str]: ) -> Tuple[List[str], str]:
if interface == CompilerInterface.STANDARD_JSON: if interface == CompilerInterface.STANDARD_JSON:
json_input: dict = { json_input: dict = {
'language': 'Solidity', 'language': 'Solidity',
@ -166,6 +171,8 @@ def prepare_compiler_input(
compiler_options = [str(source_file_name), '--bin', '--metadata'] compiler_options = [str(source_file_name), '--bin', '--metadata']
if optimize: if optimize:
compiler_options.append('--optimize') compiler_options.append('--optimize')
elif force_no_optimize_yul:
compiler_options.append('--no-optimize-yul')
if smt_use == SMTUse.DISABLE: if smt_use == SMTUse.DISABLE:
compiler_options += ['--model-checker-engine', 'none'] compiler_options += ['--model-checker-engine', 'none']
@ -175,10 +182,11 @@ def prepare_compiler_input(
return (command_line, compiler_input) return (command_line, compiler_input)
def run_compiler( def run_compiler( # pylint: disable=too-many-arguments
compiler_path: Path, compiler_path: Path,
source_file_name: Path, source_file_name: Path,
optimize: bool, optimize: bool,
force_no_optimize_yul: bool,
interface: CompilerInterface, interface: CompilerInterface,
smt_use: SMTUse, smt_use: SMTUse,
tmp_dir: Path, tmp_dir: Path,
@ -189,6 +197,7 @@ def run_compiler(
compiler_path, compiler_path,
Path(source_file_name.name), Path(source_file_name.name),
optimize, optimize,
force_no_optimize_yul,
interface, interface,
smt_use, smt_use,
) )
@ -210,6 +219,7 @@ def run_compiler(
compiler_path.absolute(), compiler_path.absolute(),
Path(source_file_name.name), Path(source_file_name.name),
optimize, optimize,
force_no_optimize_yul,
interface, interface,
smt_use, smt_use,
) )
@ -232,7 +242,13 @@ def run_compiler(
return parse_cli_output(Path(source_file_name), process.stdout) return parse_cli_output(Path(source_file_name), process.stdout)
def generate_report(source_file_names: List[str], compiler_path: Path, interface: CompilerInterface, smt_use: SMTUse): def generate_report(
source_file_names: List[str],
compiler_path: Path,
interface: CompilerInterface,
smt_use: SMTUse,
force_no_optimize_yul: bool
):
with open('report.txt', mode='w', encoding='utf8', newline='\n') as report_file: with open('report.txt', mode='w', encoding='utf8', newline='\n') as report_file:
for optimize in [False, True]: for optimize in [False, True]:
with TemporaryDirectory(prefix='prepare_report-') as tmp_dir: with TemporaryDirectory(prefix='prepare_report-') as tmp_dir:
@ -242,6 +258,7 @@ def generate_report(source_file_names: List[str], compiler_path: Path, interface
compiler_path, compiler_path,
Path(source_file_name), Path(source_file_name),
optimize, optimize,
force_no_optimize_yul,
interface, interface,
smt_use, smt_use,
Path(tmp_dir), Path(tmp_dir),
@ -287,6 +304,13 @@ def commandline_parser() -> ArgumentParser:
choices=[s.value for s in SMTUse], choices=[s.value for s in SMTUse],
help="What to do about contracts that use the experimental SMT checker." help="What to do about contracts that use the experimental SMT checker."
) )
parser.add_argument(
'--force-no-optimize-yul',
dest='force_no_optimize_yul',
default=False,
action='store_true',
help="Explicitly disable Yul optimizer in CLI runs without optimization to work around a bug in solc 0.6.0 and 0.6.1."
)
return parser; return parser;
@ -297,4 +321,5 @@ if __name__ == "__main__":
Path(options.compiler_path), Path(options.compiler_path),
CompilerInterface(options.interface), CompilerInterface(options.interface),
SMTUse(options.smt_use), SMTUse(options.smt_use),
options.force_no_optimize_yul,
) )

View File

@ -173,6 +173,7 @@ class TestPrepareCompilerInput(PrepareReportTestBase):
Path('solc'), Path('solc'),
SMT_SMOKE_TEST_SOL_PATH, SMT_SMOKE_TEST_SOL_PATH,
optimize=True, optimize=True,
force_no_optimize_yul=False,
interface=CompilerInterface.STANDARD_JSON, interface=CompilerInterface.STANDARD_JSON,
smt_use=SMTUse.DISABLE, smt_use=SMTUse.DISABLE,
) )
@ -185,6 +186,7 @@ class TestPrepareCompilerInput(PrepareReportTestBase):
Path('solc'), Path('solc'),
SMT_SMOKE_TEST_SOL_PATH, SMT_SMOKE_TEST_SOL_PATH,
optimize=True, optimize=True,
force_no_optimize_yul=False,
interface=CompilerInterface.CLI, interface=CompilerInterface.CLI,
smt_use=SMTUse.DISABLE, smt_use=SMTUse.DISABLE,
) )
@ -218,6 +220,7 @@ class TestPrepareCompilerInput(PrepareReportTestBase):
Path('solc'), Path('solc'),
SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_PATH, SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_PATH,
optimize=True, optimize=True,
force_no_optimize_yul=False,
interface=CompilerInterface.STANDARD_JSON, interface=CompilerInterface.STANDARD_JSON,
smt_use=SMTUse.DISABLE, smt_use=SMTUse.DISABLE,
) )
@ -230,12 +233,29 @@ class TestPrepareCompilerInput(PrepareReportTestBase):
Path('solc'), Path('solc'),
SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_PATH, SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_PATH,
optimize=True, optimize=True,
force_no_optimize_yul=True,
interface=CompilerInterface.CLI, interface=CompilerInterface.CLI,
smt_use=SMTUse.DISABLE, smt_use=SMTUse.DISABLE,
) )
self.assertEqual(compiler_input, SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_CODE) self.assertEqual(compiler_input, SMT_CONTRACT_WITH_MIXED_NEWLINES_SOL_CODE)
def test_prepare_compiler_input_for_cli_should_handle_force_no_optimize_yul_flag(self):
(command_line, compiler_input) = prepare_compiler_input(
Path('solc'),
SMT_SMOKE_TEST_SOL_PATH,
optimize=False,
force_no_optimize_yul=True,
interface=CompilerInterface.CLI,
smt_use=SMTUse.DISABLE,
)
self.assertEqual(
command_line,
['solc', str(SMT_SMOKE_TEST_SOL_PATH), '--bin', '--metadata', '--no-optimize-yul', '--model-checker-engine', 'none'],
)
self.assertEqual(compiler_input, SMT_SMOKE_TEST_SOL_CODE)
class TestParseStandardJSONOutput(PrepareReportTestBase): class TestParseStandardJSONOutput(PrepareReportTestBase):
def test_parse_standard_json_output(self): def test_parse_standard_json_output(self):
@ -506,7 +526,9 @@ class TestParseCLIOutput(PrepareReportTestBase):
expected_report = FileReport( expected_report = FileReport(
file_name=Path('contract.sol'), file_name=Path('contract.sol'),
contract_reports=[ContractReport(contract_name='C', file_name=Path('contract.sol'), bytecode='60806040523480156', metadata='{ }')] contract_reports=[
ContractReport(contract_name='C', file_name=Path('contract.sol'), bytecode='60806040523480156', metadata='{ }')
]
) )
self.assertEqual(parse_cli_output(Path('contract.sol'), compiler_output), expected_report) self.assertEqual(parse_cli_output(Path('contract.sol'), compiler_output), expected_report)