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

Support custom sierra compiler #471

Merged
merged 5 commits into from
May 15, 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
23 changes: 23 additions & 0 deletions page/docs/guide/cairo1-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
sidebar_position: 18
---

# Cairo 1 support

Declaring, deploying and interacting with Cairo 1 contracts is supported in the latest version. To successfully declare, if on an x86 machine, you don't have to do anything. If on another architecture, or if you want to specify a custom version of the Cairo 1 compiler, you need to specify a local compiler for recompilation (a necessary step in the declaraion of Cairo 1 contracts). Use one of:

- `--cairo-compiler-manifest <PATH_TO_CARGO_TOML>`
- `--sierra-compiler-path <PATH_TO_SIERRA_EXECUTABLE>`

## Docker support

Devnet's Docker image has a recompiler set up internally, so Cairo 1 is supported out-of-the-box. But to use a custom compiler, you should have a statically linked executable binary sierra compiler on your host and use it like this (use absolute paths when mounting):

```
$ docker run -it \
-p <YOUR_PORT>:5050 \
--mount type=bind,source=<YOUR_PATH>,target=/starknet-sierra-compile \
-it \
shardlabs/starknet-devnet:<TAG> \
--sierra-compiler-path /starknet-sierra-compile
```
2 changes: 1 addition & 1 deletion page/docs/guide/development.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 18
sidebar_position: 19
---

# Development
Expand Down
2 changes: 2 additions & 0 deletions page/docs/guide/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ optional arguments:
Disable RPC schema validation for devnet responses
--cairo-compiler-manifest CAIRO_COMPILER_MANIFEST
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
```

You can run `starknet-devnet` in a separate shell, or you can run it in background with `starknet-devnet &`.
Expand Down
9 changes: 4 additions & 5 deletions scripts/install_dev_tools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@ if [ -z "$CAIRO_1_COMPILER_MANIFEST" ]; then
fi

echo "Using Cairo compiler at $CAIRO_1_COMPILER_MANIFEST"

cargo run --bin starknet-compile \
--manifest-path "$CAIRO_1_COMPILER_MANIFEST" \
-- \
--version
cargo build \
--bin starknet-compile \
--bin starknet-sierra-compile \
--manifest-path "$CAIRO_1_COMPILER_MANIFEST"

# install dependencies
poetry install --no-ansi
Expand Down
57 changes: 47 additions & 10 deletions starknet_devnet/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import os
import subprocess
import tempfile
from abc import ABC
from abc import ABC, abstractmethod
from typing import List

from starkware.starknet.definitions.error_codes import StarknetErrorCode
from starkware.starknet.services.api.contract_class.contract_class import (
Expand All @@ -16,6 +17,7 @@
)
from starkware.starkware_utils.error_handling import StarkException

from starknet_devnet.devnet_config import DevnetConfig
from starknet_devnet.util import StarknetDevnetException


Expand Down Expand Up @@ -52,8 +54,9 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass
class CustomContractClassCompiler(ContractClassCompiler):
"""Uses the compiler according to the compiler_manifest provided in initialization"""

def __init__(self, compiler_manifest: str):
self.compiler_manifest = compiler_manifest
@abstractmethod
def get_sierra_compiler_command(self) -> List[str]:
"""Returns the shell command of the sierra compiler"""

def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass:
with tempfile.TemporaryDirectory() as tmp_dir:
Expand All @@ -66,13 +69,7 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass
json.dump(contract_class_dumped, tmp_file)

compilation_args = [
"cargo",
"run",
"--bin",
"starknet-sierra-compile",
"--manifest-path",
self.compiler_manifest,
"--",
*self.get_sierra_compiler_command(),
"--allowed-libfuncs-list-name",
"experimental_v0.1.0",
"--add-pythonic-hints",
Expand All @@ -92,3 +89,43 @@ def compile_contract_class(self, contract_class: ContractClass) -> CompiledClass
with open(contract_casm, encoding="utf-8") as casm_file:
compiled_class = CompiledClass.loads(casm_file.read())
return compiled_class


class ManifestContractClassCompiler(CustomContractClassCompiler):
"""Sierra compiler relying on the compiler repo manifest"""

def __init__(self, compiler_manifest: str):
super().__init__()
self._compiler_command = [
"cargo",
"run",
"--bin",
"starknet-sierra-compile",
"--manifest-path",
compiler_manifest,
"--",
]

def get_sierra_compiler_command(self) -> List[str]:
return self._compiler_command


class BinaryContractClassCompiler(CustomContractClassCompiler):
"""Sierra compiler relying on the starknet-sierra-compile binary executable"""

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

def get_sierra_compiler_command(self) -> List[str]:
return self._compiler_command


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)

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

return DefaultContractClassCompiler()
46 changes: 35 additions & 11 deletions starknet_devnet/devnet_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,19 +210,10 @@ def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, value)


def _parse_cairo_compiler_manifest(manifest_path: str):
def _assert_valid_compiler(command: List[str]):
"""Assert user machine can compile with cairo 1"""
check = subprocess.run(
[
"cargo",
"run",
"--bin",
"starknet-compile",
"--manifest-path",
manifest_path,
"--",
"--version",
],
command,
check=False,
capture_output=True,
)
Expand All @@ -234,9 +225,31 @@ def _parse_cairo_compiler_manifest(manifest_path: str):
version_used = check.stdout.decode("utf-8")
print(f"Using cairo compiler: {version_used}")


def _parse_cairo_compiler_manifest(manifest_path: str):
command = [
"cargo",
"run",
"--bin",
"starknet-sierra-compile",
"--manifest-path",
manifest_path,
"--",
"--version",
]
_assert_valid_compiler(command)

return manifest_path


def _parse_sierra_compiler_path(compiler_path: str):
if not (os.path.isfile(compiler_path) and os.access(compiler_path, os.X_OK)):
sys.exit("Error: The argument of --sierra-compiler-path must be an executable")

_assert_valid_compiler([compiler_path, "--version"])
return compiler_path


def parse_args(raw_args: List[str]):
"""
Parses CLI arguments.
Expand Down Expand Up @@ -380,6 +393,11 @@ def parse_args(raw_args: List[str]):
help="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",
)
parser.add_argument(
"--sierra-compiler-path",
type=_parse_sierra_compiler_path,
help="Specify the path to the binary executable of starknet-sierra-compile",
)

parsed_args = parser.parse_args(raw_args)
if parsed_args.dump_on and not parsed_args.dump_path:
Expand All @@ -394,6 +412,11 @@ def parse_args(raw_args: List[str]):
parsed_args.fork_network, parsed_args.fork_block, parsed_args.fork_retries
)

if parsed_args.cairo_compiler_manifest and parsed_args.sierra_compiler_path:
sys.exit(
"Error: Only one of {--cairo-compiler-manifest,--sierra-compiler-path} can be provided"
)

return parsed_args


Expand Down Expand Up @@ -421,3 +444,4 @@ def __init__(self, args: argparse.Namespace = None):
self.validate_rpc_requests = not self.args.disable_rpc_request_validation
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
8 changes: 2 additions & 6 deletions starknet_devnet/starknet_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
from .blocks import DevnetBlocks
from .blueprints.rpc.structures.types import BlockId, Felt
from .chargeable_account import ChargeableAccount
from .compiler import CustomContractClassCompiler, DefaultContractClassCompiler
from .compiler import select_compiler
from .constants import (
DUMMY_STATE_ROOT,
LEGACY_TX_VERSION,
Expand Down Expand Up @@ -145,11 +145,7 @@ def __init__(self, config: DevnetConfig):
self._contract_classes: Dict[int, Union[DeprecatedCompiledClass, ContractClass]]
"""If v2 - store sierra, otherwise store old class; needed for get_class_by_hash"""
self.genesis_block_number = None
self._compiler = (
CustomContractClassCompiler(config.cairo_compiler_manifest)
if config.cairo_compiler_manifest
else DefaultContractClassCompiler()
)
self._compiler = select_compiler(config)

if config.start_time is not None:
self.set_block_time(config.start_time)
Expand Down
Loading