Skip to content

Commit

Permalink
Cairo v0.13.3.
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoni-Starkware committed Nov 13, 2024
1 parent a86e92b commit 8e11b8c
Show file tree
Hide file tree
Showing 39 changed files with 1,513 additions and 327 deletions.
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.13.2)
[github](https://github.com/starkware-libs/cairo-lang/releases/tag/v0.13.3)
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.13.2.zip .
> docker cp ${container_id}:/app/cairo-lang-0.13.3.zip .
> docker rm -v ${container_id}
```

2 changes: 2 additions & 0 deletions src/starkware/cairo/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ cairo_library(
"bitwise.cairo",
"bool.cairo",
"cairo_builtins.cairo",
"copy_indices.cairo",
"default_dict.cairo",
"dict.cairo",
"dict_access.cairo",
Expand All @@ -22,6 +23,7 @@ cairo_library(
"invoke.cairo",
"keccak.cairo",
"keccak_state.cairo",
"log2_ceil.cairo",
"math.cairo",
"math_cmp.cairo",
"memcpy.cairo",
Expand Down
36 changes: 36 additions & 0 deletions src/starkware/cairo/common/copy_indices.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copies len field elements from src to dst at the given indices.
// I.e., dst = [src[i] for i in indices].
func copy_indices(dst: felt*, src: felt*, indices: felt*, len: felt) {
struct LoopFrame {
dst: felt*,
indices: felt*,
}

if (len == 0) {
return ();
}

%{ vm_enter_scope({'n': ids.len}) %}
tempvar frame = LoopFrame(dst=dst, indices=indices);

loop:
let frame = [cast(ap - LoopFrame.SIZE, LoopFrame*)];
assert [frame.dst] = src[[frame.indices]];

let continue_copying = [ap];
// Reserve space for continue_copying.
let next_frame = cast(ap + 1, LoopFrame*);
next_frame.dst = frame.dst + 1, ap++;
next_frame.indices = frame.indices + 1, ap++;
%{
n -= 1
ids.continue_copying = 1 if n > 0 else 0
%}
static_assert next_frame + LoopFrame.SIZE == ap + 1;
jmp loop if continue_copying != 0, ap++;
// Assert that the loop executed len times.
len = cast(next_frame.indices, felt) - cast(indices, felt);

%{ vm_exit_scope() %}
return ();
}
28 changes: 28 additions & 0 deletions src/starkware/cairo/common/log2_ceil.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from starkware.cairo.common.math import assert_in_range, assert_not_zero
from starkware.cairo.common.pow import pow

// Returns the ceil value of the log2 of the given value.
// Enforces that 1 <= value <= RANGE_CHECK_BOUND.
func log2_ceil{range_check_ptr}(value: felt) -> felt {
alloc_locals;
assert_not_zero(value);
if (value == 1) {
return 0;
}

local res;
%{
from starkware.python.math_utils import log2_ceil
ids.res = log2_ceil(ids.value)
%}

// Verify that 1 <= 2**(res - 1) < value <= 2**res <= RANGE_CHECK_BOUND.
// The RANGE_CHECK_BOUND bound is required by the `assert_in_range` function.
assert_in_range(res, 1, 128 + 1);
let (lower_bound) = pow(2, res - 1);
let min = lower_bound + 1;
let max = 2 * lower_bound;
assert_in_range(value, min, max + 1);

return res;
}
1 change: 1 addition & 0 deletions src/starkware/cairo/lang/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ py_library(
],
data = [
"@" + CAIRO_COMPILER_ARCHIVE,
"//src/starkware/starknet/core/os:starknet_os_program_cairo_lib",
],
visibility = ["//visibility:public"],
deps = [
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.13.2
0.13.3
2 changes: 1 addition & 1 deletion src/starkware/cairo/lang/ide/vscode-cairo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "cairo",
"displayName": "CairoZero",
"description": "Support Cairo syntax",
"version": "0.13.2",
"version": "0.13.3",
"engines": {
"vscode": "^1.30.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from starkware.starknet.core.os.deprecated_syscall_handler import DeprecatedBlSyscallHandler
from starkware.starknet.core.os.syscall_handler import BusinessLogicSyscallHandler
from starkware.starknet.definitions import fields
from starkware.starknet.definitions.constants import GasCost
from starkware.starknet.definitions.constants import VERSIONED_CONSTANTS, GasCost
from starkware.starknet.definitions.error_codes import StarknetErrorCode
from starkware.starknet.definitions.execution_mode import ExecutionMode
from starkware.starknet.definitions.general_config import (
Expand Down Expand Up @@ -133,7 +133,7 @@ def sync_execute_for_testing(
state=state,
resources_manager=ExecutionResourcesManager.empty(),
tx_execution_context=TransactionExecutionContext.create_for_testing(
n_steps=general_config.invoke_tx_max_n_steps
n_steps=VERSIONED_CONSTANTS.invoke_tx_max_n_steps,
),
general_config=general_config,
support_reverted=support_reverted,
Expand All @@ -146,10 +146,13 @@ async def execute_for_testing(
resources_manager: Optional[ExecutionResourcesManager] = None,
tx_execution_context: Optional[TransactionExecutionContext] = None,
execution_mode: ExecutionMode = ExecutionMode.EXECUTE,
invoke_tx_max_n_steps: Optional[int] = None,
) -> CallInfo:
if invoke_tx_max_n_steps is None:
invoke_tx_max_n_steps = VERSIONED_CONSTANTS.invoke_tx_max_n_steps
if tx_execution_context is None:
tx_execution_context = TransactionExecutionContext.create_for_testing(
n_steps=general_config.invoke_tx_max_n_steps, execution_mode=execution_mode
n_steps=invoke_tx_max_n_steps, execution_mode=execution_mode
)

if resources_manager is None:
Expand Down
1 change: 1 addition & 0 deletions src/starkware/starknet/business_logic/fact_state/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ py_library(
"//src/starkware/cairo/lang/vm:cairo_vm_crypto_lib",
"//src/starkware/python:starkware_python_utils_lib",
"//src/starkware/starknet/business_logic/state:starknet_business_logic_state_lib",
"//src/starkware/starknet/core/aggregator:cairo_aggregator_lib",
"//src/starkware/starknet/definitions:starknet_definitions_lib",
"//src/starkware/starknet/definitions:starknet_general_config_lib",
"//src/starkware/starkware_utils:starkware_config_utils_lib",
Expand Down
120 changes: 112 additions & 8 deletions src/starkware/starknet/business_logic/fact_state/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from starkware.starknet.business_logic.state.state import CachedState
from starkware.starknet.business_logic.state.state_api import StateReader
from starkware.starknet.business_logic.state.state_api_objects import BlockInfo
from starkware.starknet.core.aggregator.output_parser import ContractChanges, OsStateDiff
from starkware.starknet.definitions import constants, fields
from starkware.starknet.definitions.data_availability_mode import DataAvailabilityMode
from starkware.starknet.definitions.general_config import StarknetGeneralConfig
Expand Down Expand Up @@ -479,14 +480,6 @@ def backward_compatibility_before_data_availability_modes(

return data

async def write(self, storage: Storage) -> bytes:
"""
Writes an entry containing the state diff to the storage under its hash, as a fact object.
"""
hash_value = self.calculate_hash()
await self.set(storage=storage, suffix=hash_value)
return hash_value

@classmethod
def empty(cls, block_info: BlockInfo):
"""
Expand All @@ -500,6 +493,32 @@ def empty(cls, block_info: BlockInfo):
block_info=block_info,
)

async def write(self, storage: Storage, batch_id: int) -> bytes:
"""
Writes the state diff to the storage under the given batch_id.
Returns the key suffix (serialized batch_id).
"""
suffix = str(batch_id).encode("ascii")
await self.set(storage=storage, suffix=suffix)
return suffix

@classmethod
def create_l1_da_mode(
cls,
address_to_class_hash: Mapping[int, int],
nonces: Mapping[int, int],
storage_updates: Mapping[int, Mapping[int, int]],
declared_classes: Mapping[int, int],
block_info: BlockInfo,
) -> "StateDiff":
return cls(
address_to_class_hash=address_to_class_hash,
nonces={DataAvailabilityMode.L1: nonces},
storage_updates={DataAvailabilityMode.L1: storage_updates},
declared_classes=declared_classes,
block_info=block_info,
)

@classmethod
def from_cached_state(cls, cached_state: CachedState) -> "StateDiff":
state_cache = cached_state.cache
Expand Down Expand Up @@ -582,6 +601,91 @@ async def commit(
block_info=self.block_info,
)

def get_os_encoded_length(self) -> int:
"""
Returns the length of the OS encoded representation of the state diff.
See src/starkware/starknet/core/os/state/output.cairo.
"""
return len(self.to_os_state_diff().encode())

def get_marginal_os_encoded_length(self, previous_state_diff: Optional["StateDiff"]) -> int:
"""
Returns the marginal addition of self to the given state diff's length.
E.g., the following are equivalent:
* (a + b).get_os_encoded_length()
* a.get_os_encoded_length() + b.get_marginal_os_encoded_length(a)
"""
if previous_state_diff is None:
return self.get_os_encoded_length()

pre_squash_size = previous_state_diff.get_os_encoded_length()
post_squash_size = previous_state_diff.squash(other=self).get_os_encoded_length()
return post_squash_size - pre_squash_size

def to_os_state_diff(self) -> OsStateDiff:
self.assert_l1_da_mode()
nonces = self.nonces.get(DataAvailabilityMode.L1, {})
storage_updates = self.storage_updates.get(DataAvailabilityMode.L1, {})
modified_contracts = sorted(
self.address_to_class_hash.keys() | nonces.keys() | storage_updates.keys()
)
return OsStateDiff(
contracts=[
ContractChanges(
addr=addr,
new_nonce=nonces.get(addr, None),
new_class_hash=self.address_to_class_hash.get(addr, None),
storage_changes={
key: (None, value) for key, value in storage_updates.get(addr, {}).items()
},
# Only relevant for `full_output` mode.
prev_nonce=None,
prev_class_hash=None,
)
for addr in modified_contracts
],
classes={
class_hash: (None, compiled_class_hash)
for class_hash, compiled_class_hash in self.declared_classes.items()
},
)

@classmethod
def from_os_state_diff(cls, os_state_diff: OsStateDiff, block_info: BlockInfo) -> "StateDiff":
contracts = os_state_diff.contracts
return cls.create_l1_da_mode(
address_to_class_hash={
contract.addr: contract.new_class_hash
for contract in contracts
if contract.new_class_hash is not None
},
nonces={
contract.addr: contract.new_nonce
for contract in contracts
if contract.new_nonce is not None
},
storage_updates={
contract.addr: {
key: value for key, (_prev, value) in contract.storage_changes.items()
}
for contract in contracts
if len(contract.storage_changes) > 0
},
declared_classes={
class_hash: compiled_class_hash
for class_hash, (_prev, compiled_class_hash) in os_state_diff.classes.items()
},
block_info=block_info,
)

def assert_l1_da_mode(self):
supported_da_modes = {DataAvailabilityMode.L1}
unsupported_da_modes = (
set(self.nonces.keys() | self.storage_updates.keys()) - supported_da_modes
)
assert len(unsupported_da_modes) == 0, f"Unsupported DA modes: {unsupported_da_modes}."


@marshmallow_dataclass.dataclass(frozen=True)
class DeprecatedStateDiff(EverestStateDiff, DBObject):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class BlockInfo(ValidatedMarshmallowDataclass):
# The sequencer address of this block.
sequencer_address: Optional[int] = field(metadata=fields.optional_sequencer_address_metadata)

# The version of Starknet system (e.g., "0.13.2").
# The version of Starknet system (e.g., "0.13.3").
starknet_version: Optional[str] = field(metadata=fields.starknet_version_metadata)

# Indicates whether to use KZG commitment scheme for the block's Data Avilability.
Expand All @@ -105,12 +105,12 @@ def rename_old_gas_price_fields(
return rename_old_gas_price_fields(data=data)

@classmethod
def empty(cls, sequencer_address: Optional[int]) -> "BlockInfo":
def empty(cls, sequencer_address: Optional[int], block_number: int = -1) -> "BlockInfo":
"""
Returns an empty BlockInfo object; i.e., the one before the first in the chain.
"""
return cls(
block_number=-1,
block_number=block_number,
block_timestamp=0,
# As gas prices must be non-zero, just use 1 for all prices.
l1_gas_price=ResourcePrice(price_in_wei=1, price_in_fri=1),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ def run_validate_entrypoint(
resources_manager=resources_manager,
general_config=general_config,
tx_execution_context=self.get_execution_context(
n_steps=general_config.validate_max_n_steps, execution_mode=ExecutionMode.VALIDATE
n_steps=general_config.get_validate_max_n_steps(),
execution_mode=ExecutionMode.VALIDATE,
),
)

Expand Down Expand Up @@ -336,7 +337,8 @@ def charge_fee(
general_config=general_config,
state=state,
tx_execution_context=self.get_execution_context(
n_steps=general_config.invoke_tx_max_n_steps, execution_mode=ExecutionMode.EXECUTE
n_steps=constants.VERSIONED_CONSTANTS.invoke_tx_max_n_steps,
execution_mode=ExecutionMode.EXECUTE,
),
actual_fee=actual_fee,
)
Expand Down Expand Up @@ -885,7 +887,8 @@ def run_constructor_entrypoint(
resources_manager=resources_manager,
general_config=general_config,
tx_execution_context=self.get_execution_context(
n_steps=general_config.validate_max_n_steps, execution_mode=ExecutionMode.VALIDATE
n_steps=general_config.get_validate_max_n_steps(),
execution_mode=ExecutionMode.VALIDATE,
),
)

Expand Down Expand Up @@ -1098,7 +1101,7 @@ def invoke_constructor(
signature=[],
max_fee=0,
nonce=0,
n_steps=general_config.invoke_tx_max_n_steps,
n_steps=constants.VERSIONED_CONSTANTS.invoke_tx_max_n_steps,
version=self.version,
execution_mode=ExecutionMode.EXECUTE,
)
Expand Down Expand Up @@ -1384,7 +1387,7 @@ def run_execute_entrypoint(
resources_manager=resources_manager,
general_config=general_config,
tx_execution_context=self.get_execution_context(
n_steps=general_config.invoke_tx_max_n_steps,
n_steps=constants.VERSIONED_CONSTANTS.invoke_tx_max_n_steps,
execution_mode=ExecutionMode.EXECUTE,
),
)
Expand Down Expand Up @@ -1510,7 +1513,7 @@ def _apply_specific_concurrent_changes(
resources_manager=resources_manager,
general_config=general_config,
tx_execution_context=self.get_execution_context(
n_steps=general_config.invoke_tx_max_n_steps
n_steps=constants.VERSIONED_CONSTANTS.invoke_tx_max_n_steps,
),
)

Expand Down
Loading

0 comments on commit 8e11b8c

Please sign in to comment.