Skip to content

Commit

Permalink
Cairo v0.10.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
liorgold2 committed Oct 4, 2022
1 parent 4fb8301 commit 55a26f4
Show file tree
Hide file tree
Showing 80 changed files with 2,125 additions and 638 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RUN pip install cmake==3.22
RUN curl https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.6.12+commit.27d51765 -o /usr/local/bin/solc-0.6.12
RUN echo 'f6cb519b01dabc61cab4c184a3db11aa591d18151e362fcae850e42cffdfb09a /usr/local/bin/solc-0.6.12' | sha256sum --check
RUN chmod +x /usr/local/bin/solc-0.6.12
RUN npm install -g --unsafe-perm ganache[email protected]
RUN npm install -g --unsafe-perm ganache@7.4.3

COPY . /app/

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ We recommend starting from [Setting up the environment](https://cairo-lang.org/d
# Installation instructions

You should be able to download the python package zip file directly from
[github](https://github.com/starkware-libs/cairo-lang/releases/tag/v0.10.0)
[github](https://github.com/starkware-libs/cairo-lang/releases/tag/v0.10.1)
and install it using ``pip``.
See [Setting up the environment](https://cairo-lang.org/docs/quickstart.html).

Expand Down 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.10.0.zip .
> docker cp ${container_id}:/app/cairo-lang-0.10.1.zip .
> docker rm -v ${container_id}
```

6 changes: 3 additions & 3 deletions scripts/requirements-deps.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,9 @@
{
"dependencies": [],
"package": {
"installed_version": "0.12.0",
"key": "lark-parser",
"package_name": "lark-parser"
"installed_version": "1.1.2",
"key": "lark",
"package_name": "lark"
}
},
{
Expand Down
3 changes: 1 addition & 2 deletions src/services/everest/business_logic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ python_lib(everest_internal_transaction_lib
LIBS
everest_business_logic_lib
everest_business_logic_state_api_lib
everest_transaction_execution_objects_lib
everest_transaction_lib
starkware_config_utils_lib
starkware_dataclasses_utils_lib
starkware_one_of_schema_utils_lib
pip_marshmallow_dataclass
)

python_lib(everest_transaction_execution_objects_lib
Expand Down
21 changes: 3 additions & 18 deletions src/services/everest/business_logic/internal_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,14 @@
from abc import abstractmethod
from typing import Iterable, Iterator, Optional, Type

import marshmallow_dataclass

from services.everest.api.gateway.transaction import EverestTransaction
from services.everest.business_logic.state import StateSelectorBase
from services.everest.business_logic.state_api import StateProxy
from services.everest.business_logic.transaction_execution_objects import (
EverestTransactionExecutionInfo,
)
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 EverestTransactionExecutionInfo(ValidatedMarshmallowDataclass):
"""
Base class of classes containing information generated from an execution of a transaction on
the state. Each Everest application may implement it specifically.
Note that this object will only be relevant if the transaction executed successfully.
"""


@marshmallow_dataclass.dataclass(frozen=True)
class TransactionExecutionInfo(EverestTransactionExecutionInfo):
"""
A non-abstract derived class for completeness of AggregatedScope. Used by StarkEx and Perpetual.
"""


class EverestInternalStateTransaction(SubclassSchemaTracker):
Expand Down
8 changes: 6 additions & 2 deletions src/services/everest/business_logic/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,12 @@ async def commit(
"""

@classmethod
def squash_many(cls: Type[TStateDiff], state_diffs: Iterable[TStateDiff]) -> TStateDiff:
def squash_many(
cls: Type[TStateDiff],
state_diffs: Iterable[TStateDiff],
initial_state_diff: TStateDiff,
) -> TStateDiff:
"""
Creates a state diff. object with the given changes applied in chronological order.
"""
return functools.reduce(lambda x, y: x.squash(other=y), state_diffs)
return functools.reduce(lambda x, y: x.squash(other=y), state_diffs, initial_state_diff)
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,25 @@
import marshmallow
import marshmallow_dataclass

from starkware.starkware_utils.error_handling import StarkException
from starkware.starkware_utils.validated_dataclass import ValidatedMarshmallowDataclass


class EverestTransactionExecutionInfo(ValidatedMarshmallowDataclass):
"""
Base class of classes containing information generated from an execution of a transaction on
the state. Each Everest application may implement it specifically.
Note that this object will only be relevant if the transaction executed successfully.
"""


@marshmallow_dataclass.dataclass(frozen=True)
class TransactionExecutionInfo(EverestTransactionExecutionInfo):
"""
A non-abstract derived class for completeness of AggregatedScope. Used by StarkEx and Perpetual.
"""


@marshmallow_dataclass.dataclass(frozen=True)
class TransactionFailureReason(ValidatedMarshmallowDataclass):
"""
Expand All @@ -30,3 +46,7 @@ def truncate_error_message(self, data: Dict[str, Any], many: bool, **kwargs) ->

data["error_message"] = error_message[:5000]
return data

@classmethod
def from_exception(cls, exception: StarkException) -> "TransactionFailureReason":
return cls(code=exception.code.name, error_message=exception.message)
1 change: 1 addition & 0 deletions src/starkware/cairo/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ python_lib(cairo_common_validate_utils_lib
cairo_run_builtins_lib
cairo_run_lib
cairo_vm_lib
starkware_python_utils_lib
)

python_lib(cairo_function_runner_lib
Expand Down
58 changes: 52 additions & 6 deletions src/starkware/cairo/common/cairo_function_runner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections.abc import Iterable
from typing import Any, Dict, Optional, Union, cast
from typing import Any, Dict, Optional, Tuple, Union, cast

from starkware.cairo.common.structs import CairoStructFactory
from starkware.cairo.lang.builtins.bitwise.bitwise_builtin_runner import BitwiseBuiltinRunner
Expand All @@ -23,6 +23,7 @@
from starkware.cairo.lang.vm.security import verify_secure_runner
from starkware.cairo.lang.vm.utils import RunResources
from starkware.cairo.lang.vm.vm_exceptions import SecurityError, VmException
from starkware.python.utils import safe_zip


class CairoFunctionRunner(CairoRunner):
Expand Down Expand Up @@ -130,26 +131,33 @@ def run(
trace_on_failure: bool = False,
apply_modulo_to_args: Optional[bool] = None,
use_full_name: bool = False,
verify_implicit_args_segment: bool = False,
**kwargs,
):
) -> Tuple[Tuple[MaybeRelocatable, ...], Tuple[MaybeRelocatable, ...]]:
"""
Runs func_name(*args).
args are converted to Cairo-friendly ones using gen_arg.
Returns the return values of the function, splitted into 2 tuples of implicit values and
explicit values. Structs will be flattened to a sequence of felts as part of the returned
tuple.
Additional params:
verify_secure - Run verify_secure_runner to do extra verifications.
trace_on_failure - Run the tracer in case of failure to help debugging.
apply_modulo_to_args - Apply modulo operation on integer arguments.
use_full_name - Treat 'func_name' as a fully qualified identifier name, rather than a
relative one.
relative one.
verify_implicit_args_segment - For each implicit argument, verify that the argument and the
return value are in the same segment.
"""
assert isinstance(self.program, Program)
entrypoint = self.program.get_label(func_name, full_name_lookup=use_full_name)

structs_factory = CairoStructFactory.from_program(program=self.program)
full_args_struct = structs_factory.build_func_args(
func=ScopedName.from_string(scope=func_name)
)
func = ScopedName.from_string(scope=func_name)

full_args_struct = structs_factory.build_func_args(func=func)
all_args = full_args_struct(*args, **kwargs)

try:
Expand All @@ -173,6 +181,44 @@ def run(
trace_runner(runner=self)
raise

# The number of implicit arguments is identical to the number of implicit return values.
n_implicit_ret_vals = structs_factory.get_implicit_args_length(func=func)
n_explicit_ret_vals = structs_factory.get_explicit_return_values_length(func=func)
n_ret_vals = n_explicit_ret_vals + n_implicit_ret_vals
implicit_retvals = tuple(
self.vm_memory.get_range(
addr=self.vm.run_context.ap - n_ret_vals, size=n_implicit_ret_vals
)
)

explicit_retvals = tuple(
self.vm_memory.get_range(
addr=self.vm.run_context.ap - n_explicit_ret_vals, size=n_explicit_ret_vals
)
)

# Verify the memory segments of the implicit arguments.
if verify_implicit_args_segment:
implicit_args = all_args[:n_implicit_ret_vals]
for implicit_arg, implicit_retval in safe_zip(implicit_args, implicit_retvals):
assert isinstance(
implicit_arg, RelocatableValue
), f"Implicit arguments must be RelocatableValues, {implicit_arg} is not."
assert isinstance(implicit_retval, RelocatableValue), (
f"Argument {implicit_arg} is a RelocatableValue, but the returned value "
f"{implicit_retval} is not."
)
assert implicit_arg.segment_index == implicit_retval.segment_index, (
f"Implicit argument {implicit_arg} is not on the same segment as the returned "
f"{implicit_retval}."
)
assert implicit_retval.offset >= implicit_arg.offset, (
f"The offset of the returned implicit argument {implicit_retval} is less than "
f"the offset of the input {implicit_arg}."
)

return implicit_retvals, explicit_retvals

def run_from_entrypoint(
self,
entrypoint: Union[str, int],
Expand Down
54 changes: 53 additions & 1 deletion src/starkware/cairo/common/structs.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
from typing import List, MutableMapping, NamedTuple, Optional

from starkware.cairo.lang.compiler.ast.cairo_types import (
CairoType,
TypeCodeoffset,
TypeFelt,
TypePointer,
TypeStruct,
TypeTuple,
)
from starkware.cairo.lang.compiler.ast.code_elements import CodeElementFunction
from starkware.cairo.lang.compiler.identifier_definition import StructDefinition
from starkware.cairo.lang.compiler.identifier_manager import IdentifierManager
from starkware.cairo.lang.compiler.identifier_utils import get_struct_definition
from starkware.cairo.lang.compiler.identifier_utils import (
get_struct_definition,
get_type_definition,
)
from starkware.cairo.lang.compiler.program import Program
from starkware.cairo.lang.compiler.scoped_name import ScopedName
from starkware.python.utils import WriteOnceDict
Expand Down Expand Up @@ -91,6 +102,47 @@ def build_func_args(self, func: ScopedName):

return NamedTuple(f"{func[-1:]}_full_args", typed_fields)

def size_of(self, typ: CairoType) -> int:
"""
Returns the total size (in felts) of the given type. Pointer types count as one felt.
"""
size = 0
if isinstance(typ, TypeStruct):
struct_def = get_struct_definition(
struct_name=typ.scope, identifier_manager=self.identifiers
)
size = struct_def.size
elif isinstance(typ, TypeTuple):
for item in typ.members:
size += self.size_of(typ=item.typ)
else:
assert isinstance(
typ, (TypeFelt, TypeCodeoffset, TypePointer)
), f"Unsupported Cairo type {typ}."
size = 1

return size

def get_explicit_return_values_length(self, func: ScopedName) -> int:
"""
Returns the length of the explicit return values of a function
"""
full_name = self._get_full_name(func)
type_def = get_type_definition(
full_name + CodeElementFunction.RETURN_SCOPE, self.identifiers
)
return self.size_of(typ=type_def.cairo_type)

def get_implicit_args_length(self, func: ScopedName) -> int:
"""
Returns the length of the implicit arguments of a function
"""
full_name = self._get_full_name(func)
struct_def = get_struct_definition(
full_name + CodeElementFunction.IMPLICIT_ARGUMENT_SCOPE, self.identifiers
)
return struct_def.size

@property
def structs(self):
"""
Expand Down
58 changes: 58 additions & 0 deletions src/starkware/cairo/common/uint256.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,64 @@ func uint256_unsigned_div_rem{range_check_ptr}(a: Uint256, div: Uint256) -> (
return (quotient=quotient, remainder=remainder);
}

// Computes:
// 1. The integer division `(a * b) // div` (as a 512-bit number).
// 2. The remainder `(a * b) modulo div`.
// Assumption: div != 0.
func uint256_mul_div_mod{range_check_ptr}(a: Uint256, b: Uint256, div: Uint256) -> (
quotient_low: Uint256, quotient_high: Uint256, remainder: Uint256
) {
alloc_locals;

// Compute a * b (512 bits).
let (ab_low, ab_high) = uint256_mul(a, b);

// Guess the quotient and remainder of (a * b) / d.
local quotient_low: Uint256;
local quotient_high: Uint256;
local remainder: Uint256;

%{
a = (ids.a.high << 128) + ids.a.low
b = (ids.b.high << 128) + ids.b.low
div = (ids.div.high << 128) + ids.div.low
quotient, remainder = divmod(a * b, div)

ids.quotient_low.low = quotient & ((1 << 128) - 1)
ids.quotient_low.high = (quotient >> 128) & ((1 << 128) - 1)
ids.quotient_high.low = (quotient >> 256) & ((1 << 128) - 1)
ids.quotient_high.high = quotient >> 384
ids.remainder.low = remainder & ((1 << 128) - 1)
ids.remainder.high = remainder >> 128
%}

// Compute x = quotient * div + remainder.
uint256_check(quotient_high);
let (quotient_mod10, quotient_mod11) = uint256_mul(quotient_high, div);
uint256_check(quotient_low);
let (quotient_mod00, quotient_mod01) = uint256_mul(quotient_low, div);
// Since x should equal a * b, the high 256 bits must be zero.
assert quotient_mod11 = Uint256(0, 0);

// The low 256 bits of x must be ab_low.
uint256_check(remainder);
let (x0, carry0) = uint256_add(quotient_mod00, remainder);
assert x0 = ab_low;

let (x1, carry1) = uint256_add(quotient_mod01, quotient_mod10);
assert carry1 = 0;
let (x1, carry2) = uint256_add(x1, Uint256(low=carry0, high=0));
assert carry2 = 0;

assert x1 = ab_high;

// Verify that 0 <= remainder < div.
let (is_valid) = uint256_lt(remainder, div);
assert is_valid = 1;

return (quotient_low=quotient_low, quotient_high=quotient_high, remainder=remainder);
}

// Returns the bitwise NOT of an integer.
func uint256_not{range_check_ptr}(a: Uint256) -> (res: Uint256) {
return (res=Uint256(low=ALL_ONES - a.low, high=ALL_ONES - a.high));
Expand Down
2 changes: 1 addition & 1 deletion src/starkware/cairo/lang/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.10.0
0.10.1
Loading

0 comments on commit 55a26f4

Please sign in to comment.