Skip to content
This repository has been archived by the owner on Dec 15, 2023. It is now read-only.

Make compiler args customizable #504

Merged
merged 2 commits into from
Jun 16, 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
2 changes: 2 additions & 0 deletions page/docs/guide/cairo1-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Make sure your Devnet is using the same compiler version that you used for the c
- `--cairo-compiler-manifest <PATH_TO_CARGO_TOML>`
- `--sierra-compiler-path <PATH_TO_SIERRA_EXECUTABLE>`

By default, Devnet runs the compiler with `--add-pythonic-hints` and `--allowed-libfuncs-list-name experimental_v0.1.0`. Modify this with Devnet's `--compiler-args` CLI argument.

## Compiler binaries

Other than cloning [the compiler repo](https://github.com/starkware-libs/cairo) and checking out and building the desired version, you can find statically linked **prebuilt** executable binaries under `Assets` of every release [on the GitHub release page](https://github.com/starkware-libs/cairo/releases) (usually x86 and Apple sillicon binaries are included).
Expand Down
5 changes: 3 additions & 2 deletions page/docs/guide/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ optional arguments:
Specify the initial balance of accounts to be predeployed; defaults to 1e+21
--seed SEED Specify the seed for randomness of accounts to be predeployed
--hide-predeployed-contracts, --hide-predeployed-accounts
Prevents from printing the predeployed contracts details. Argument --hide-predeployed-accounts is deprecated
Prevents from printing the predeployed contracts details. Argument --hide-predeployed-accounts is deprecated
--start-time START_TIME
Specify the start time of the genesis block in Unix time seconds
--gas-price GAS_PRICE, -g GAS_PRICE
Expand All @@ -61,8 +61,9 @@ optional arguments:
Specify the path to the manifest (Cargo.toml) of the Cairo 1.0 compiler to be used for contract recompilation; if omitted, the default x86-compatible compiler (from cairo-lang package) is used
--sierra-compiler-path SIERRA_COMPILER_PATH
Specify the path to the binary executable of starknet-sierra-compile

--hide-server-logs Hide server access logging
--compiler-args COMPILER_ARGS
Specify the CLI args used internally by the Cairo 1.0 compiler for recompiling. Provide them as a single space-separated string. No validation is done on the arguments on Devnet startup, only when they are put to use. Defaults to '--add-pythonic-hints --allowed-libfuncs-list-name experimental_v0.1.0'
```

<!-- Developer note: the previous section should be a copy-paste of `starknet-devnet --help` -->
Expand Down
26 changes: 16 additions & 10 deletions starknet_devnet/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
class ContractClassCompiler(ABC):
"""Base class of contract class compilers"""

def __init__(self, compiler_args: List[str]):
self._compiler_args = compiler_args

def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass:
"""Take the sierra and return the compiled instance"""
raise NotImplementedError
Expand All @@ -41,7 +44,7 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass
try:
return compile_contract_class(
contract_class,
compiler_args="--add-pythonic-hints --allowed-libfuncs-list-name experimental_v0.1.0",
compiler_args=" ".join(self._compiler_args),
)
except PermissionError as permission_error:
raise StarknetDevnetException(
Expand Down Expand Up @@ -74,9 +77,7 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass

compilation_args = [
*self.get_sierra_compiler_command(),
"--allowed-libfuncs-list-name",
"experimental_v0.1.0",
"--add-pythonic-hints",
*self._compiler_args,
contract_json,
contract_casm,
]
Expand All @@ -98,8 +99,8 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass
class ManifestContractClassCompiler(CustomContractClassCompiler):
"""Sierra compiler relying on the compiler repo manifest"""

def __init__(self, compiler_manifest: str):
super().__init__()
def __init__(self, compiler_manifest: str, compiler_args: List[str]):
super().__init__(compiler_args)
self._compiler_command = [
"cargo",
"run",
Expand All @@ -117,7 +118,8 @@ def get_sierra_compiler_command(self) -> List[str]:
class BinaryContractClassCompiler(CustomContractClassCompiler):
"""Sierra compiler relying on the starknet-sierra-compile binary executable"""

def __init__(self, executable_path: str):
def __init__(self, executable_path: str, compiler_args: List[str]):
super().__init__(compiler_args)
self._compiler_command = [executable_path]

def get_sierra_compiler_command(self) -> List[str]:
Expand All @@ -127,9 +129,13 @@ def get_sierra_compiler_command(self) -> List[str]:
def select_compiler(config: DevnetConfig) -> ContractClassCompiler:
"""Selects the compiler class according to the specification in the config object"""
if config.cairo_compiler_manifest:
return ManifestContractClassCompiler(config.cairo_compiler_manifest)
return ManifestContractClassCompiler(
config.cairo_compiler_manifest, config.compiler_args
)

if config.sierra_compiler_path:
return BinaryContractClassCompiler(config.sierra_compiler_path)
return BinaryContractClassCompiler(
config.sierra_compiler_path, config.compiler_args
)

return DefaultContractClassCompiler()
return DefaultContractClassCompiler(config.compiler_args)
20 changes: 20 additions & 0 deletions starknet_devnet/devnet_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
CHAIN_IDS = ", ".join([member.name for member in StarknetChainId])
DEFAULT_CHAIN_ID = StarknetChainId.TESTNET

DEFAULT_COMPILER_ARGS = [
"--add-pythonic-hints",
"--allowed-libfuncs-list-name",
"experimental_v0.1.0",
]


def _fork_network(network_id: str):
"""
Expand Down Expand Up @@ -267,6 +273,10 @@ def _parse_sierra_compiler_path(compiler_path: str):
return compiler_path


def _parse_compiler_args(compiler_args: str):
return compiler_args.split()


def parse_args(raw_args: List[str]):
"""
Parses CLI arguments.
Expand Down Expand Up @@ -426,6 +436,15 @@ def parse_args(raw_args: List[str]):
type=_parse_sierra_compiler_path,
help="Specify the path to the binary executable of starknet-sierra-compile",
)
parser.add_argument(
"--compiler-args",
type=_parse_compiler_args,
default=DEFAULT_COMPILER_ARGS,
help="Specify the CLI args used internally by the Cairo 1.0 compiler for recompiling. "
"Provide them as a single space-separated string. "
"No validation is done on the arguments on Devnet startup, only when they are put to use. "
f"Defaults to '{' '.join(DEFAULT_COMPILER_ARGS)}'",
)

parsed_args = parser.parse_args(raw_args)
if parsed_args.dump_on and not parsed_args.dump_path:
Expand Down Expand Up @@ -473,4 +492,5 @@ def __init__(self, args: argparse.Namespace = None):
self.validate_rpc_responses = not self.args.disable_rpc_response_validation
self.cairo_compiler_manifest = self.args.cairo_compiler_manifest
self.sierra_compiler_path = self.args.sierra_compiler_path
self.compiler_args = self.args.compiler_args
self.verbose = self.args.verbose
73 changes: 69 additions & 4 deletions test/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
DefaultContractClassCompiler,
ManifestContractClassCompiler,
)
from starknet_devnet.devnet_config import DEFAULT_COMPILER_ARGS

from .account import send_declare_v2
from .shared import (
Expand All @@ -26,7 +27,13 @@
PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
)
from .test_declare_v2 import assert_declare_v2_accepted, load_cairo1_contract
from .util import DevnetBackgroundProc, read_stream, terminate_and_wait
from .util import (
DevnetBackgroundProc,
assert_tx_status,
devnet_in_background,
read_stream,
terminate_and_wait,
)

CAIRO_1_COMPILER_MANIFEST = os.getenv("CAIRO_1_COMPILER_MANIFEST")
if not CAIRO_1_COMPILER_MANIFEST:
Expand Down Expand Up @@ -58,9 +65,9 @@ def run_before_and_after_test():
@pytest.mark.parametrize(
"compiler",
[
DefaultContractClassCompiler(),
ManifestContractClassCompiler(CAIRO_1_COMPILER_MANIFEST),
BinaryContractClassCompiler(SIERRA_COMPILER_PATH),
DefaultContractClassCompiler(DEFAULT_COMPILER_ARGS),
ManifestContractClassCompiler(CAIRO_1_COMPILER_MANIFEST, DEFAULT_COMPILER_ARGS),
BinaryContractClassCompiler(SIERRA_COMPILER_PATH, DEFAULT_COMPILER_ARGS),
],
)
def test_contract_class_compiler_happy_path(compiler: ContractClassCompiler):
Expand Down Expand Up @@ -176,3 +183,61 @@ def test_manifest_and_sierra_compiler_specified():
"Only one of {--cairo-compiler-manifest,--sierra-compiler-path} can be provided"
in read_stream(execution.stderr)
)


@pytest.mark.usefixtures("run_devnet_in_background")
@pytest.mark.parametrize(
"run_devnet_in_background",
[
(
*PREDEPLOY_ACCOUNT_CLI_ARGS,
"--cairo-compiler-manifest",
CAIRO_1_COMPILER_MANIFEST,
"--compiler-args",
" ".join(DEFAULT_COMPILER_ARGS),
),
(
*PREDEPLOY_ACCOUNT_CLI_ARGS,
"--sierra-compiler-path",
SIERRA_COMPILER_PATH,
"--compiler-args",
" ".join(DEFAULT_COMPILER_ARGS),
),
(
*PREDEPLOY_ACCOUNT_CLI_ARGS,
"--compiler-args",
" ".join(DEFAULT_COMPILER_ARGS),
),
],
indirect=True,
)
def test_compiler_args_happy_path():
"""Expect success with the default compiler args"""
contract_class, _, compiled_class_hash = load_cairo1_contract()
resp = send_declare_v2(
contract_class=contract_class,
compiled_class_hash=compiled_class_hash,
sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
sender_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
)
assert_declare_v2_accepted(resp)


@devnet_in_background(
*PREDEPLOY_ACCOUNT_CLI_ARGS,
"--compiler-args",
"--allowed-libfuncs-list-name experimental_v0.1.0",
)
def test_compiler_args_without_pythonic_hints():
"""Expect failure if --add-pythonic-hints is not provided"""
contract_class, _, compiled_class_hash = load_cairo1_contract()
resp = send_declare_v2(
contract_class=contract_class,
compiled_class_hash=compiled_class_hash,
sender_address=PREDEPLOYED_ACCOUNT_ADDRESS,
sender_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY,
)

assert resp.status_code == 200
resp_body = resp.json()
assert_tx_status(resp_body["transaction_hash"], "REJECTED")