From 870063a7c505e9400a906b6c434232083f4433d3 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 26 Jul 2023 22:25:12 -0500 Subject: [PATCH 1/4] raise error if compile libraries argument does not yield matches --- crytic_compile/crytic_compile.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crytic_compile/crytic_compile.py b/crytic_compile/crytic_compile.py index 7b81bbaa..f952c6cb 100644 --- a/crytic_compile/crytic_compile.py +++ b/crytic_compile/crytic_compile.py @@ -68,8 +68,9 @@ def _extract_libraries(libraries_str: Optional[str]) -> Optional[Dict[str, int]] matches = re.findall(pattern, libraries_str) if not matches: - logging.info(f"Libraries {libraries_str} could not be parsed") - return None + raise ValueError( + f"Invalid library linking directive\nGot:\n{libraries_str}\nExpected format:\n(libname1, 0x00),(libname2, 0x02)" + ) ret: Dict[str, int] = {} for key, value in matches: From 0bfef2f18eec570af32856b68b465ea47f1b2fc9 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 7 Aug 2023 10:41:14 -0500 Subject: [PATCH 2/4] allow 20 byte addresses for linking and add test --- crytic_compile/crytic_compile.py | 4 +-- tests/library_linking.sol | 16 ++++++++++ tests/test_library_linking.py | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tests/library_linking.sol create mode 100644 tests/test_library_linking.py diff --git a/crytic_compile/crytic_compile.py b/crytic_compile/crytic_compile.py index f952c6cb..e437afef 100644 --- a/crytic_compile/crytic_compile.py +++ b/crytic_compile/crytic_compile.py @@ -63,8 +63,8 @@ def _extract_libraries(libraries_str: Optional[str]) -> Optional[Dict[str, int]] if not libraries_str: return None - - pattern = r"\((?P\w+),\s*(?P0x[0-9a-fA-F]{2})\),?" + # Extract tuple like (libname1, 0x00) + pattern = r"\((?P\w+),\s*(?P0x[0-9a-fA-F]{2,40})\),?" matches = re.findall(pattern, libraries_str) if not matches: diff --git a/tests/library_linking.sol b/tests/library_linking.sol new file mode 100644 index 00000000..a8704e7e --- /dev/null +++ b/tests/library_linking.sol @@ -0,0 +1,16 @@ +library NeedsLinkingA { + function testA() external pure returns (uint) { + return type(uint).max; + } +} +library NeedsLinkingB { + function testB() external pure returns (uint) { + return type(uint).min; + } +} +contract TestLibraryLinking { + function test() external { + NeedsLinkingA.testA(); + NeedsLinkingB.testB(); + } +} diff --git a/tests/test_library_linking.py b/tests/test_library_linking.py new file mode 100644 index 00000000..210efe56 --- /dev/null +++ b/tests/test_library_linking.py @@ -0,0 +1,53 @@ +""" +Test library linking +""" +import re +import pytest +from pathlib import Path +from crytic_compile.crytic_compile import CryticCompile + +TEST_DIR = Path(__file__).resolve().parent + +LIBRARY_PLACEHOLDER_REGEX = r"__.{36}__" + + +def test_library_linking(): + cc = CryticCompile( + Path(TEST_DIR / "library_linking.sol").as_posix(), + compile_libraries="(NeedsLinkingA, 0xdead),(NeedsLinkingB, 0x000000000000000000000000000000000000beef)", + ) + for compilation_unit in cc.compilation_units.values(): + for source_unit in compilation_unit.source_units.values(): + assert ( + len(re.findall(r"__.{36}__", source_unit.bytecode_init("TestLibraryLinking"))) == 2 + ) + assert ( + len(re.findall(r"__.{36}__", source_unit.bytecode_runtime("TestLibraryLinking"))) + == 2 + ) + # Test that the placeholder is not present in the bytecode when the libraries are provided + libraries = compilation_unit.crytic_compile.libraries + assert ( + len( + re.findall( + r"__.{36}__", source_unit.bytecode_init("TestLibraryLinking", libraries) + ) + ) + == 0 + ) + assert ( + len( + re.findall( + r"__.{36}__", source_unit.bytecode_runtime("TestLibraryLinking", libraries) + ) + ) + == 0 + ) + + +def test_library_linking_validation(): + with pytest.raises(ValueError): + cc = CryticCompile( + Path(TEST_DIR / "library_linking.sol").as_posix(), + compile_libraries="(NeedsLinkingA, 0x)", + ) From 138c32ad1908b543f0062a292f920c9538b9cd6c Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 7 Aug 2023 10:45:09 -0500 Subject: [PATCH 3/4] mypy --- tests/test_library_linking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_library_linking.py b/tests/test_library_linking.py index 210efe56..ee24eb92 100644 --- a/tests/test_library_linking.py +++ b/tests/test_library_linking.py @@ -11,7 +11,7 @@ LIBRARY_PLACEHOLDER_REGEX = r"__.{36}__" -def test_library_linking(): +def test_library_linking() -> None: cc = CryticCompile( Path(TEST_DIR / "library_linking.sol").as_posix(), compile_libraries="(NeedsLinkingA, 0xdead),(NeedsLinkingB, 0x000000000000000000000000000000000000beef)", @@ -45,7 +45,7 @@ def test_library_linking(): ) -def test_library_linking_validation(): +def test_library_linking_validation() -> None: with pytest.raises(ValueError): cc = CryticCompile( Path(TEST_DIR / "library_linking.sol").as_posix(), From 9a0cb863be366ee9b07d5287be1ca3415e991c51 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 7 Aug 2023 10:50:57 -0500 Subject: [PATCH 4/4] pylint --- tests/test_library_linking.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_library_linking.py b/tests/test_library_linking.py index ee24eb92..d863f4f9 100644 --- a/tests/test_library_linking.py +++ b/tests/test_library_linking.py @@ -2,8 +2,8 @@ Test library linking """ import re -import pytest from pathlib import Path +import pytest from crytic_compile.crytic_compile import CryticCompile TEST_DIR = Path(__file__).resolve().parent @@ -12,6 +12,7 @@ def test_library_linking() -> None: + """Test that the placeholder is not present in the bytecode when the libraries are provided""" cc = CryticCompile( Path(TEST_DIR / "library_linking.sol").as_posix(), compile_libraries="(NeedsLinkingA, 0xdead),(NeedsLinkingB, 0x000000000000000000000000000000000000beef)", @@ -25,7 +26,6 @@ def test_library_linking() -> None: len(re.findall(r"__.{36}__", source_unit.bytecode_runtime("TestLibraryLinking"))) == 2 ) - # Test that the placeholder is not present in the bytecode when the libraries are provided libraries = compilation_unit.crytic_compile.libraries assert ( len( @@ -46,8 +46,9 @@ def test_library_linking() -> None: def test_library_linking_validation() -> None: + """Test that invalid compile libraries argument raises an error""" with pytest.raises(ValueError): - cc = CryticCompile( + CryticCompile( Path(TEST_DIR / "library_linking.sol").as_posix(), compile_libraries="(NeedsLinkingA, 0x)", )