Skip to content

Commit

Permalink
Cairo v0.9.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
liorgold2 committed Jun 5, 2022
1 parent 2abd303 commit 167b28b
Show file tree
Hide file tree
Showing 263 changed files with 5,963 additions and 2,110 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
@@ -1,5 +1,7 @@
cmake_minimum_required (VERSION 3.22)

set (PYTHON_COMMAND python3.7)

project(CairoLang VERSION 0.1.0)
include(CTest)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -54,7 +54,7 @@ Once the docker image is built, you can fetch the python package zip file using:

```bash
> container_id=$(docker create cairo)
> docker cp ${container_id}:/app/cairo-lang-0.8.2.1.zip .
> docker cp ${container_id}:/app/cairo-lang-0.9.0.zip .
> docker rm -v ${container_id}
```

2 changes: 1 addition & 1 deletion src/cmake_utils/CMakeLists.txt
Expand Up @@ -6,7 +6,7 @@ python_lib(gen_solidity_lib
)

python_venv(gen_solidity_venv
PYTHON python3.7
PYTHON ${PYTHON_COMMAND}
LIBS
gen_solidity_lib
)
Expand Down
55 changes: 51 additions & 4 deletions src/cmake_utils/python_rules.cmake
Expand Up @@ -217,15 +217,29 @@ endfunction()

function(python_test TEST_NAME)
# Parse arguments.
set(options)
set(options NO_CODE_COVERAGE)
set(oneValueArgs VENV TESTED_MODULES TEST_ARGS ENVIRONMENT_VARS)
set(multiValueArgs)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# If code coverage is enabled, and the target is run as part of the nightly run, need to add
# command line options + an environment variable.
set(COVERAGE_ARGS "")
if(NOT ARGS_NO_CODE_COVERAGE AND ("$ENV{NIGHTLY_TEST}" EQUAL "1"))
# Set COVERAGE_DEBUG environment variable for debugging coverage-related failures, as suggested
# here: https://github.com/pytest-dev/pytest-cov/issues/237.
set(ENV{COVERAGE_DEBUG} "process,config")
set(COVERAGE_ARGS "--cov-report html:{VENV_SITE_DIR}/coverage_py_html \
--cov {VENV_SITE_DIR}/${ARGS_TESTED_MODULES}"
)
string(REPLACE "/" "." COVERAGE_FILE_SUFFIX "${ARGS_TESTED_MODULES}")
string(APPEND ARGS_ENVIRONMENT_VARS " COVERAGE_FILE=.coverage.${COVERAGE_FILE_SUFFIX}")
endif()

python_exe(${TEST_NAME}
VENV ${ARGS_VENV}
MODULE pytest
ARGS "{VENV_SITE_DIR}/${ARGS_TESTED_MODULES} ${ARGS_TEST_ARGS}"
ARGS "${COVERAGE_ARGS} {VENV_SITE_DIR}/${ARGS_TESTED_MODULES} ${ARGS_TEST_ARGS}"
WORKING_DIR ${CMAKE_BINARY_DIR}
ENVIRONMENT_VARS ${ARGS_ENVIRONMENT_VARS}
)
Expand All @@ -238,12 +252,44 @@ endfunction()

function(full_python_test TEST_NAME)
# Parse arguments.
set(options)
set(options NO_CODE_COVERAGE)
set(oneValueArgs TESTED_MODULES TEST_ARGS PYTHON ENVIRONMENT_VARS)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN})
set(multiValueArgs LIBS ARTIFACTS PY_EXE_DEPENDENCIES)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# If code coverage is suppressed, the option needs to be passed to the python_exe macro.
# Otherwise, need to add the pytest-cov dependency.
set(CODE_COVERAGE_SUPPRESSION_FLAG)
if(ARGS_NO_CODE_COVERAGE OR NOT ("$ENV{NIGHTLY_TEST}" EQUAL "1"))
set(CODE_COVERAGE_SUPPRESSION_FLAG NO_CODE_COVERAGE)
else()
list(APPEND ARGS_LIBS "pip_pytest_cov")
endif()

# Use a 3rd-party Python debugger (instead of `pdb`).
#
# Usage: Override both args below before CMake imports this file.
# The contents of the variables should be as follows:
#
# PYTHON_DEBUGGER_LIB: the name of the python_lib for the debugger package.
# format: "pip_<lib_name>" # For more on this format, see the definition
# of `python_lib` above.
# PYTHON_BREAKPOINT_HANDLER: the cmd that triggers the debugger
# (will be run when `breakpoint()` is called).
# format: "PYTHONBREAKPOINT=<debugger_start_command>"
#
# Example (for the package `ipdb`):
#
# PYTHON_DEBUGGER_LIB="pip_ipdb"
# PYTHON_BREAKPOINT_HANDLER="PYTHONBREAKPOINT=ipdb.set_trace"
list(APPEND ARGS_LIBS ${PYTHON_DEBUGGER_LIB})
list(APPEND ARGS_ENVIRONMENT_VARS ${PYTHON_BREAKPOINT_HANDLER})

python_lib(${TEST_NAME}_lib
${ARGS_UNPARSED_ARGUMENTS}
LIBS ${ARGS_LIBS}
ARTIFACTS ${ARGS_ARTIFACTS}
PY_EXE_DEPENDENCIES ${ARGS_PY_EXE_DEPENDENCIES}
)
python_venv(${TEST_NAME}_venv
PYTHON ${ARGS_PYTHON}
Expand All @@ -254,5 +300,6 @@ function(full_python_test TEST_NAME)
TESTED_MODULES ${ARGS_TESTED_MODULES}
TEST_ARGS ${ARGS_TEST_ARGS}
ENVIRONMENT_VARS ${ARGS_ENVIRONMENT_VARS}
${CODE_COVERAGE_SUPPRESSION_FLAG}
)
endfunction()
5 changes: 2 additions & 3 deletions src/demo/amm_demo/amm.cairo
Expand Up @@ -28,7 +28,7 @@ struct AmmState:
end

func modify_account{range_check_ptr}(state : AmmState, account_id, diff_a, diff_b) -> (
state : AmmState, key
state : AmmState, key : felt
):
alloc_locals

Expand Down Expand Up @@ -186,15 +186,14 @@ const LOG_N_ACCOUNTS = 10
# Hint argument: initial_account_dict should be a dictionary
# from account_id to an address in memory of the Account struct.
func compute_merkle_roots{pedersen_ptr : HashBuiltin*, range_check_ptr}(state : AmmState) -> (
root_before, root_after
root_before : felt, root_after : felt
):
alloc_locals

# Squash the account dictionary.
let (squashed_dict_start, squashed_dict_end) = dict_squash(
dict_accesses_start=state.account_dict_start, dict_accesses_end=state.account_dict_end
)
local range_check_ptr = range_check_ptr

# Hash the dict values.
%{
Expand Down
10 changes: 5 additions & 5 deletions src/demo/amm_demo/demo.py
Expand Up @@ -20,7 +20,7 @@

N_ACCOUNTS = 5
N_BATCHES = 3
MIN_OPERATOR_BALANCE = 0.1 * 10 ** 18
MIN_OPERATOR_BALANCE = 0.1 * 10**18
BATCH_SIZE = 10
GAS_PRICE = 10000000000
AMM_SOURCE_PATH = os.path.join(os.path.dirname(__file__), "amm.cairo")
Expand All @@ -33,11 +33,11 @@ def init_prover(bin_dir: str, node_rpc_url: str) -> BatchProver:
node_rpc_url: a URL of an Ethereum node RPC.
"""
balance = Balance(a=random.randint(10 ** 6, 10 ** 8), b=random.randint(10 ** 6, 10 ** 8))
balance = Balance(a=random.randint(10**6, 10**8), b=random.randint(10**6, 10**8))
accounts = {
i: Account(
pub_key=i,
balance=Balance(a=random.randint(10 ** 5, 10 ** 7), b=random.randint(10 ** 5, 10 ** 7)),
balance=Balance(a=random.randint(10**5, 10**7), b=random.randint(10**5, 10**7)),
)
for i in range(N_ACCOUNTS)
}
Expand Down Expand Up @@ -133,7 +133,7 @@ def main():
operator_private_key = int(operator_private_key_str, 16)
except ValueError:
print("Generating a random key...")
operator_private_key = random.randint(0, 2 ** 256)
operator_private_key = random.randint(0, 2**256)
operator_private_key = "0x{:064x}".format(operator_private_key)
operator = eth.Account.from_key(operator_private_key)

Expand Down Expand Up @@ -190,7 +190,7 @@ def tx_kwargs(w3: Web3, sender_account: eth.Account):
sender_account: the account sending the transaction.
"""
nonce = w3.eth.getTransactionCount(sender_account)
return {"from": sender_account, "gas": 10 ** 6, "gasPrice": GAS_PRICE, "nonce": nonce}
return {"from": sender_account, "gas": 10**6, "gasPrice": GAS_PRICE, "nonce": nonce}


def send_transaction(w3, transaction, sender_account: BaseAccount):
Expand Down
@@ -1,10 +1,10 @@
import json
from typing import ClassVar

from services.external_api.base_client import BaseClient
from services.external_api.client import ClientBase


class EverestFeederGatewayClient(BaseClient):
class EverestFeederGatewayClient(ClientBase):
"""
Base class to FeederGatewayClient classes.
"""
Expand Down
4 changes: 2 additions & 2 deletions src/services/everest/api/gateway/gateway_client.py
Expand Up @@ -2,10 +2,10 @@
from typing import ClassVar, Dict

from services.everest.api.gateway.transaction import EverestAddTransactionRequest
from services.external_api.base_client import BaseClient
from services.external_api.client import ClientBase


class EverestGatewayClient(BaseClient):
class EverestGatewayClient(ClientBase):
"""
Base class to GatewayClient classes.
"""
Expand Down
7 changes: 6 additions & 1 deletion src/services/everest/api/gateway/transaction.py
@@ -1,4 +1,4 @@
from typing import ClassVar, Type
from typing import Callable, ClassVar, Type

import marshmallow_oneofschema

Expand All @@ -13,6 +13,11 @@ class EverestTransaction(ValidatedMarshmallowDataclass):

Schema: ClassVar[Type[marshmallow_oneofschema.OneOfSchema]]

def log_additional_data(self, logger: Callable[[str], None]) -> None:
"""
Logs additional data that isn't present in the __repr__ or __str__ functions.
"""



class EverestAddTransactionRequest(ValidatedMarshmallowDataclass):
Expand Down
4 changes: 1 addition & 3 deletions src/services/everest/business_logic/CMakeLists.txt
Expand Up @@ -23,9 +23,7 @@ python_lib(everest_internal_transaction_lib
everest_transaction_lib
starkware_config_utils_lib
starkware_dataclasses_utils_lib
pip_marshmallow
pip_marshmallow_enum
pip_marshmallow_oneofschema
pip_marshmallow_dataclass
)

python_lib(everest_transaction_execution_objects_lib
Expand Down
70 changes: 9 additions & 61 deletions src/services/everest/business_logic/internal_transaction.py
@@ -1,54 +1,17 @@
import functools
import operator
from abc import abstractmethod
from typing import Any, ClassVar, Dict, Iterable, Optional, Type
from typing import Iterable, Iterator, Optional, Type

import marshmallow
import marshmallow_dataclass
from marshmallow_oneofschema import OneOfSchema

from services.everest.api.gateway.transaction import EverestTransaction
from services.everest.business_logic.state import CarriedStateBase, StateSelectorBase
from starkware.starkware_utils.config_base import Config
from starkware.starkware_utils.one_of_schema_tracker import SubclassSchemaTracker
from starkware.starkware_utils.validated_dataclass import ValidatedMarshmallowDataclass


class SchemaTracker:
"""
Tracks a set of classes and provides a OneOfSchema which can be used to serialize them.
"""

def __init__(self):
self.classes: Dict[str, Any] = {}
classes = self.classes

class TransactionSchema(OneOfSchema):

type_schemas: Dict[str, Type[marshmallow.Schema]] = {}

def get_obj_type(self, obj):
name = type(obj).__name__
assert name in classes.keys() and classes[name] == type(
obj
), f"Trying to serialized the object {obj} that was not registered first."
# We register the Schema object here, since it might not exists when the object
# itself is registered.
if name not in self.type_schemas.keys():
self.type_schemas[name] = obj.Schema
return name

self.Schema = TransactionSchema

def add_class(self, cls: type):
cls_name = cls.__name__
if cls_name in self.classes:
assert (
self.classes[cls_name] == cls
), f"Trying to register two classes with the same name {cls_name}"
else:
self.classes[cls_name] = cls


class EverestTransactionExecutionInfo(ValidatedMarshmallowDataclass):
"""
Base class of classes containing information generated from an execution of a transaction on
Expand All @@ -64,33 +27,12 @@ class TransactionExecutionInfo(EverestTransactionExecutionInfo):
"""


class EverestInternalStateTransaction(ValidatedMarshmallowDataclass):
class EverestInternalStateTransaction(SubclassSchemaTracker):
"""
Base class of application-specific internal transaction base classes.
Contains the API of an internal transaction that can apply changes on the state.
"""

schema_tracker: ClassVar[Optional[SchemaTracker]] = None

@classmethod
def track_subclasses(cls):
"""
Creates a OneOfSchema schema for this class, and adds each subclass to this schema.
"""
cls.schema_tracker = SchemaTracker()
cls.Schema = cls.schema_tracker.Schema

@classmethod
def __init_subclass__(cls, **kwargs):
"""
Registers the given cls class as a subclass of its first parent that called
track_subclasses (if such a parent exists).
"""
super().__init_subclass__(**kwargs) # type: ignore[call-arg]
if cls.schema_tracker is None:
return
cls.schema_tracker.add_class(cls)

@abstractmethod
async def apply_state_updates(
self, state: CarriedStateBase, general_config: Config
Expand Down Expand Up @@ -176,3 +118,9 @@ def verify_signatures(self):
"""
Verifies the signatures in the transaction.
"""


class HasInnerTxs:
@abstractmethod
def _txs(self) -> Iterator[EverestInternalTransaction]:
raise NotImplementedError("_txs is not implemented for {type(self).__name__}.")
2 changes: 1 addition & 1 deletion src/services/external_api/CMakeLists.txt
Expand Up @@ -9,7 +9,7 @@ python_lib(services_external_api_lib
PREFIX services/external_api

FILES
base_client.py
client.py
has_uri_prefix.py
${SERVICES_EXTERNAL_API_LIB_ADDITIONAL_FILES}

Expand Down
Expand Up @@ -14,11 +14,12 @@
from starkware.starkware_utils.validated_dataclass import ValidatedDataclass

logger = logging.getLogger(__name__)
JsonObject = Dict[str, Any]


class BadRequest(Exception):
"""
Base class to exceptions raised by BaseClient and its derived classes.
Base class to exceptions raised by ClientBase and its derived classes.
"""

def __init__(self, status_code: int, text: str):
Expand Down Expand Up @@ -50,7 +51,7 @@ class RetryConfig(ValidatedDataclass):
)


class BaseClient(HasUriPrefix):
class ClientBase(HasUriPrefix):
"""
A base class for HTTP clients.
"""
Expand Down
2 changes: 1 addition & 1 deletion src/starkware/cairo/bootloaders/CMakeLists.txt
Expand Up @@ -20,7 +20,7 @@ python_lib(cairo_hash_program_lib
)

python_venv(cairo_hash_program_venv
PYTHON python3.7
PYTHON ${PYTHON_COMMAND}
LIBS
cairo_hash_program_lib
)
Expand Down

0 comments on commit 167b28b

Please sign in to comment.