mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
prepare_report.py: Make parsing more lax to handle output from older compiler versions
This commit is contained in:
parent
b06de9a2d5
commit
7e48aeb848
@ -16,6 +16,13 @@ function loadSource(sourceFileName, stripSMTPragmas)
|
|||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanString(string)
|
||||||
|
{
|
||||||
|
if (string !== undefined)
|
||||||
|
string = string.trim()
|
||||||
|
return (string !== '' ? string : undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let stripSMTPragmas = false
|
let stripSMTPragmas = false
|
||||||
let firstFileArgumentIndex = 2
|
let firstFileArgumentIndex = 2
|
||||||
@ -78,10 +85,15 @@ for (const optimize of [false, true])
|
|||||||
let bytecode = '<NO BYTECODE>'
|
let bytecode = '<NO BYTECODE>'
|
||||||
let metadata = '<NO METADATA>'
|
let metadata = '<NO METADATA>'
|
||||||
|
|
||||||
if ('evm' in contractResults && 'bytecode' in contractResults['evm'] && 'object' in contractResults['evm']['bytecode'])
|
if (
|
||||||
bytecode = contractResults.evm.bytecode.object
|
'evm' in contractResults &&
|
||||||
|
'bytecode' in contractResults['evm'] &&
|
||||||
|
'object' in contractResults['evm']['bytecode'] &&
|
||||||
|
cleanString(contractResults.evm.bytecode.object) !== undefined
|
||||||
|
)
|
||||||
|
bytecode = cleanString(contractResults.evm.bytecode.object)
|
||||||
|
|
||||||
if ('metadata' in contractResults)
|
if ('metadata' in contractResults && cleanString(contractResults.metadata) !== undefined)
|
||||||
metadata = contractResults.metadata
|
metadata = contractResults.metadata
|
||||||
|
|
||||||
console.log(filename + ':' + contractName + ' ' + bytecode)
|
console.log(filename + ':' + contractName + ' ' + bytecode)
|
||||||
|
@ -13,9 +13,9 @@ 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>.*)$', 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)
|
||||||
|
|
||||||
|
|
||||||
class CompilerInterface(Enum):
|
class CompilerInterface(Enum):
|
||||||
@ -32,7 +32,7 @@ class SMTUse(Enum):
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ContractReport:
|
class ContractReport:
|
||||||
contract_name: str
|
contract_name: str
|
||||||
file_name: Path
|
file_name: Optional[Path]
|
||||||
bytecode: Optional[str]
|
bytecode: Optional[str]
|
||||||
metadata: Optional[str]
|
metadata: Optional[str]
|
||||||
|
|
||||||
@ -72,6 +72,11 @@ def load_source(path: Union[Path, str], smt_use: SMTUse) -> str:
|
|||||||
return file_content
|
return file_content
|
||||||
|
|
||||||
|
|
||||||
|
def clean_string(value: Optional[str]) -> Optional[str]:
|
||||||
|
value = value.strip() if value is not None else None
|
||||||
|
return value if value != '' else None
|
||||||
|
|
||||||
|
|
||||||
def parse_standard_json_output(source_file_name: Path, standard_json_output: str) -> FileReport:
|
def parse_standard_json_output(source_file_name: Path, standard_json_output: str) -> FileReport:
|
||||||
decoded_json_output = json.loads(standard_json_output.strip())
|
decoded_json_output = json.loads(standard_json_output.strip())
|
||||||
|
|
||||||
@ -98,8 +103,8 @@ def parse_standard_json_output(source_file_name: Path, standard_json_output: str
|
|||||||
file_report.contract_reports.append(ContractReport(
|
file_report.contract_reports.append(ContractReport(
|
||||||
contract_name=contract_name,
|
contract_name=contract_name,
|
||||||
file_name=Path(file_name),
|
file_name=Path(file_name),
|
||||||
bytecode=contract_results.get('evm', {}).get('bytecode', {}).get('object'),
|
bytecode=clean_string(contract_results.get('evm', {}).get('bytecode', {}).get('object')),
|
||||||
metadata=contract_results.get('metadata'),
|
metadata=clean_string(contract_results.get('metadata')),
|
||||||
))
|
))
|
||||||
|
|
||||||
return file_report
|
return file_report
|
||||||
@ -122,10 +127,10 @@ def parse_cli_output(source_file_name: Path, cli_output: str) -> FileReport:
|
|||||||
|
|
||||||
assert file_report.contract_reports is not None
|
assert file_report.contract_reports is not None
|
||||||
file_report.contract_reports.append(ContractReport(
|
file_report.contract_reports.append(ContractReport(
|
||||||
contract_name=contract_name,
|
contract_name=contract_name.strip(),
|
||||||
file_name=Path(file_name),
|
file_name=Path(file_name.strip()) if file_name is not None else None,
|
||||||
bytecode=bytecode_match['bytecode'] if bytecode_match is not None else None,
|
bytecode=clean_string(bytecode_match['bytecode'] if bytecode_match is not None else None),
|
||||||
metadata=metadata_match['metadata'] if metadata_match is not None else None,
|
metadata=clean_string(metadata_match['metadata'] if metadata_match is not None else None),
|
||||||
))
|
))
|
||||||
|
|
||||||
return file_report
|
return file_report
|
||||||
|
8
test/scripts/fixtures/solc_0.4.0_cli_output.txt
Normal file
8
test/scripts/fixtures/solc_0.4.0_cli_output.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
contract.sol:1:1: Warning: Source file does not specify required compiler version! Consider adding "pragma solidity ^0.4.0;".
|
||||||
|
contract C {}
|
||||||
|
^
|
||||||
|
Spanning multiple lines.
|
||||||
|
|
||||||
|
======= C =======
|
||||||
|
Binary:
|
||||||
|
6060604052600c8060106000396000f360606040526008565b600256
|
10
test/scripts/fixtures/solc_0.4.8_cli_output.txt
Normal file
10
test/scripts/fixtures/solc_0.4.8_cli_output.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
contract.sol:1:1: Warning: Source file does not specify required compiler version!Consider adding "pragma solidity ^0.4.8
|
||||||
|
contract C {}
|
||||||
|
^
|
||||||
|
Spanning multiple lines.
|
||||||
|
|
||||||
|
======= C =======
|
||||||
|
Binary:
|
||||||
|
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a72305820ccf9337430b4c4f7d6ad41efb10a94411a2af6a9f173ef52daeadd31f4bf11890029
|
||||||
|
Metadata:
|
||||||
|
{"compiler":{"version":"0.4.8+commit.60cc1668.mod.Darwin.appleclang"},"language":"Solidity","output":{"abi":[],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"contract.sol":"C"},"libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"contract.sol":{"keccak256":"0xbe86d3681a198587296ad6d4a834606197e1a8f8944922c501631b04e21eeba2","urls":["bzzr://af16957d3d86013309d64d3cc572d007b1d8b08a821f2ff366840deb54a78524"]}},"version":1}
|
@ -41,6 +41,9 @@ STACK_TOO_DEEP_CLI_OUTPUT = load_fixture('stack_too_deep_cli_output.txt')
|
|||||||
CODE_GENERATION_ERROR_JSON_OUTPUT = load_fixture('code_generation_error_json_output.json')
|
CODE_GENERATION_ERROR_JSON_OUTPUT = load_fixture('code_generation_error_json_output.json')
|
||||||
CODE_GENERATION_ERROR_CLI_OUTPUT = load_fixture('code_generation_error_cli_output.txt')
|
CODE_GENERATION_ERROR_CLI_OUTPUT = load_fixture('code_generation_error_cli_output.txt')
|
||||||
|
|
||||||
|
SOLC_0_4_0_CLI_OUTPUT = load_fixture('solc_0.4.0_cli_output.txt')
|
||||||
|
SOLC_0_4_8_CLI_OUTPUT = load_fixture('solc_0.4.8_cli_output.txt')
|
||||||
|
|
||||||
|
|
||||||
class PrepareReportTestBase(unittest.TestCase):
|
class PrepareReportTestBase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -334,6 +337,34 @@ class TestParseStandardJSONOutput(PrepareReportTestBase):
|
|||||||
|
|
||||||
|
|
||||||
class TestParseCLIOutput(PrepareReportTestBase):
|
class TestParseCLIOutput(PrepareReportTestBase):
|
||||||
|
def test_parse_standard_json_output_should_report_missing_if_value_is_just_whitespace(self):
|
||||||
|
compiler_output = dedent("""\
|
||||||
|
{
|
||||||
|
"contracts": {
|
||||||
|
"contract.sol": {
|
||||||
|
"A": {
|
||||||
|
"evm": {"bytecode": {"object": ""}},
|
||||||
|
"metadata": ""
|
||||||
|
},
|
||||||
|
"B": {
|
||||||
|
"evm": {"bytecode": {"object": " "}},
|
||||||
|
"metadata": " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
contract_reports=[
|
||||||
|
ContractReport(contract_name='A', file_name=Path('contract.sol'), bytecode=None, metadata=None),
|
||||||
|
ContractReport(contract_name='B', file_name=Path('contract.sol'), bytecode=None, metadata=None),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(parse_standard_json_output(Path('contract.sol'), compiler_output), expected_report)
|
||||||
|
|
||||||
def test_parse_cli_output(self):
|
def test_parse_cli_output(self):
|
||||||
expected_report = FileReport(
|
expected_report = FileReport(
|
||||||
file_name=Path('syntaxTests/scoping/library_inherited2.sol'),
|
file_name=Path('syntaxTests/scoping/library_inherited2.sol'),
|
||||||
@ -431,3 +462,107 @@ class TestParseCLIOutput(PrepareReportTestBase):
|
|||||||
expected_report = FileReport(file_name=Path('file.sol'), contract_reports=None)
|
expected_report = FileReport(file_name=Path('file.sol'), contract_reports=None)
|
||||||
|
|
||||||
self.assertEqual(parse_cli_output(Path('file.sol'), CODE_GENERATION_ERROR_CLI_OUTPUT), expected_report)
|
self.assertEqual(parse_cli_output(Path('file.sol'), CODE_GENERATION_ERROR_CLI_OUTPUT), expected_report)
|
||||||
|
|
||||||
|
def test_parse_cli_output_should_handle_output_from_solc_0_4_0(self):
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
contract_reports=[
|
||||||
|
ContractReport(
|
||||||
|
contract_name='C',
|
||||||
|
file_name=None,
|
||||||
|
bytecode='6060604052600c8060106000396000f360606040526008565b600256',
|
||||||
|
metadata=None,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(parse_cli_output(Path('contract.sol'), SOLC_0_4_0_CLI_OUTPUT), expected_report)
|
||||||
|
|
||||||
|
def test_parse_cli_output_should_handle_output_from_solc_0_4_8(self):
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
contract_reports=[
|
||||||
|
# pragma pylint: disable=line-too-long
|
||||||
|
ContractReport(
|
||||||
|
contract_name='C',
|
||||||
|
file_name=None,
|
||||||
|
bytecode='6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a72305820ccf9337430b4c4f7d6ad41efb10a94411a2af6a9f173ef52daeadd31f4bf11890029',
|
||||||
|
metadata='{"compiler":{"version":"0.4.8+commit.60cc1668.mod.Darwin.appleclang"},"language":"Solidity","output":{"abi":[],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"contract.sol":"C"},"libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"contract.sol":{"keccak256":"0xbe86d3681a198587296ad6d4a834606197e1a8f8944922c501631b04e21eeba2","urls":["bzzr://af16957d3d86013309d64d3cc572d007b1d8b08a821f2ff366840deb54a78524"]}},"version":1}',
|
||||||
|
)
|
||||||
|
# pragma pylint: enable=line-too-long
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(parse_cli_output(Path('contract.sol'), SOLC_0_4_8_CLI_OUTPUT), expected_report)
|
||||||
|
|
||||||
|
def test_parse_cli_output_should_handle_leading_and_trailing_spaces(self):
|
||||||
|
compiler_output = (
|
||||||
|
' ======= contract.sol : C ======= \n'
|
||||||
|
' Binary: \n'
|
||||||
|
' 60806040523480156 \n'
|
||||||
|
' Metadata: \n'
|
||||||
|
' { } \n'
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
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)
|
||||||
|
|
||||||
|
def test_parse_cli_output_should_handle_empty_bytecode_and_metadata_lines(self):
|
||||||
|
compiler_output = dedent("""\
|
||||||
|
======= contract.sol:C =======
|
||||||
|
Binary:
|
||||||
|
60806040523480156
|
||||||
|
Metadata:
|
||||||
|
|
||||||
|
|
||||||
|
======= contract.sol:D =======
|
||||||
|
Binary:
|
||||||
|
|
||||||
|
Metadata:
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
======= contract.sol:E =======
|
||||||
|
Binary:
|
||||||
|
|
||||||
|
Metadata:
|
||||||
|
|
||||||
|
|
||||||
|
""")
|
||||||
|
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
contract_reports=[
|
||||||
|
ContractReport(contract_name='C', file_name=Path('contract.sol'), bytecode='60806040523480156', metadata=None),
|
||||||
|
ContractReport(contract_name='D', file_name=Path('contract.sol'), bytecode=None, metadata='{}'),
|
||||||
|
ContractReport(contract_name='E', file_name=Path('contract.sol'), bytecode=None, metadata=None),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(parse_cli_output(Path('contract.sol'), compiler_output), expected_report)
|
||||||
|
|
||||||
|
def test_parse_cli_output_should_handle_link_references_in_bytecode(self):
|
||||||
|
compiler_output = dedent("""\
|
||||||
|
======= contract.sol:C =======
|
||||||
|
Binary:
|
||||||
|
73123456789012345678901234567890123456789073__$fb58009a6b1ecea3b9d99bedd645df4ec3$__5050
|
||||||
|
======= contract.sol:D =======
|
||||||
|
Binary:
|
||||||
|
__$fb58009a6b1ecea3b9d99bedd645df4ec3$__
|
||||||
|
""")
|
||||||
|
|
||||||
|
# pragma pylint: disable=line-too-long
|
||||||
|
expected_report = FileReport(
|
||||||
|
file_name=Path('contract.sol'),
|
||||||
|
contract_reports=[
|
||||||
|
ContractReport(contract_name='C', file_name=Path('contract.sol'), bytecode='73123456789012345678901234567890123456789073__$fb58009a6b1ecea3b9d99bedd645df4ec3$__5050', metadata=None),
|
||||||
|
ContractReport(contract_name='D', file_name=Path('contract.sol'), bytecode='__$fb58009a6b1ecea3b9d99bedd645df4ec3$__', metadata=None),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
# pragma pylint: enable=line-too-long
|
||||||
|
|
||||||
|
self.assertEqual(parse_cli_output(Path('contract.sol'), compiler_output), expected_report)
|
||||||
|
Loading…
Reference in New Issue
Block a user