Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow 20 byte address for --compile-libraries and raise error if argument is invalid #477

Merged
merged 4 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions crytic_compile/crytic_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ def _extract_libraries(libraries_str: Optional[str]) -> Optional[Dict[str, int]]

if not libraries_str:
return None

pattern = r"\((?P<name>\w+),\s*(?P<value1>0x[0-9a-fA-F]{2})\),?"
# Extract tuple like (libname1, 0x00)
pattern = r"\((?P<name>\w+),\s*(?P<value1>0x[0-9a-fA-F]{2,40})\),?"
matches = re.findall(pattern, libraries_str)
0xalpharush marked this conversation as resolved.
Show resolved Hide resolved

if not matches:
logging.info(f"Libraries {libraries_str} could not be parsed")
0xalpharush marked this conversation as resolved.
Show resolved Hide resolved
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:
Expand Down
16 changes: 16 additions & 0 deletions tests/library_linking.sol
Original file line number Diff line number Diff line change
@@ -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();
}
}
54 changes: 54 additions & 0 deletions tests/test_library_linking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Test library linking
"""
import re
from pathlib import Path
import pytest
from crytic_compile.crytic_compile import CryticCompile

TEST_DIR = Path(__file__).resolve().parent

LIBRARY_PLACEHOLDER_REGEX = r"__.{36}__"


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)",
)
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
)
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() -> None:
"""Test that invalid compile libraries argument raises an error"""
with pytest.raises(ValueError):
CryticCompile(
Path(TEST_DIR / "library_linking.sol").as_posix(),
compile_libraries="(NeedsLinkingA, 0x)",
)