-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bytecode test for multiple sources compiler at same time
- Loading branch information
Showing
3 changed files
with
143 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
test/cmdlineTests/~bytecode_equivalence_multiple_sources/inputs.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
==== Source: A.sol ==== | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.0; | ||
|
||
import "D.sol"; | ||
import "B.sol"; | ||
|
||
contract A is B { | ||
function a() public pure { | ||
f(); | ||
} | ||
} | ||
|
||
==== Source: B.sol ==== | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.0; | ||
|
||
import "C.sol"; | ||
|
||
abstract contract B is C {} | ||
|
||
==== Source: C.sol ==== | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.0; | ||
|
||
abstract contract C | ||
{ | ||
function c() public pure returns (uint) { | ||
return 0; | ||
} | ||
} | ||
|
||
==== Source: D.sol ==== | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.0; | ||
|
||
import "F.sol"; | ||
|
||
==== Source: F.sol ==== | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.0; | ||
|
||
function f() pure returns (bytes memory returndata) { | ||
return ""; | ||
} |
86 changes: 86 additions & 0 deletions
86
test/cmdlineTests/~bytecode_equivalence_multiple_sources/test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import os | ||
import re | ||
import sys | ||
import subprocess | ||
from shutil import which | ||
from tempfile import mkdtemp | ||
from pathlib import Path | ||
|
||
PROJECT_ROOT = Path(__file__).parents[3] | ||
CMDLINE_TEST_DIR = f"{PROJECT_ROOT}/test/cmdlineTests" | ||
|
||
sys.path.insert(0, f"{PROJECT_ROOT}/scripts") | ||
from bytecodecompare.prepare_report import FileReport | ||
from bytecodecompare.prepare_report import parse_cli_output | ||
from splitSources import split_sources | ||
|
||
|
||
class FileMismatchError(Exception): | ||
def __str__(self): | ||
return f"Git diff mismatch:\n {self.args[0]}" | ||
|
||
|
||
# diff will return no output if there is no difference between the two inputs, | ||
# or throw CalledProcessError otherwise, i.e. if the process exits with a non-zero exit code. | ||
def diff(a: str, b: str): | ||
try: | ||
if which("git") is None: | ||
raise RuntimeError("git not found.") | ||
subprocess.check_output( | ||
f"git diff --color --word-diff=plain --word-diff-regex=. --ignore-space-change --ignore-blank-lines <(echo \"{a}\") <(echo \"{b}\")", | ||
shell=True, | ||
universal_newlines=True | ||
) | ||
except subprocess.CalledProcessError as e: | ||
raise FileMismatchError(e.output) | ||
|
||
|
||
def run_solc(report_file_path: str, solc_binary_path: str, args=[]): | ||
output = subprocess.check_output( | ||
[solc_binary_path, *args], | ||
shell=False, | ||
encoding="utf8" | ||
) | ||
return parse_cli_output(Path(report_file_path), output) | ||
|
||
|
||
def filter_bytecode_report(contract: str, reports: FileReport): | ||
for report in reports.contract_reports: | ||
if report.contract_name == contract: | ||
return report.bytecode if report.bytecode is not None else '<NO BYTECODE>' | ||
|
||
|
||
def test_bytecode_equivalence(tmp_dir: str): | ||
os.chdir(tmp_dir) | ||
|
||
source_file_name = f"{CMDLINE_TEST_DIR}/~bytecode_equivalence_multiple_sources/inputs.sol" | ||
split_sources(source_file_name) | ||
|
||
solc_binary = os.environ.get("SOLC") | ||
if solc_binary is None: | ||
raise RuntimeError("solc compiler not found.") | ||
|
||
# Compiling multiple files at same time should not affect bytecode generation although it changes AST IDs. | ||
a_bin_output = run_solc(f"{tmp_dir}/A.report", solc_binary, ["--via-ir", "--bin", "A.sol", "B.sol"]) | ||
ab_bin_output = run_solc(f"{tmp_dir}/AB.report", solc_binary, ["--via-ir", "--bin", "A.sol"]) | ||
|
||
diff( | ||
filter_bytecode_report("A", a_bin_output), | ||
filter_bytecode_report("A", ab_bin_output) | ||
) | ||
|
||
|
||
def main(): | ||
try: | ||
tmp_dir = mkdtemp(prefix=f"cmdline-test-bytecode-equivalence-multiple-sources") | ||
test_bytecode_equivalence(tmp_dir) | ||
return 0 | ||
except Exception as e: | ||
print(f"Error: {e}", file=sys.stderr) | ||
return 1 | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |