# Cairo v2.7.0 is coming!

**URL:** <https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362>\
**Category:** Cairo Development\
**Created:** [July 17, 2024, 1:09pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362 "2024-07-17T13:09:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 17, 2024, 1:09pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/1 "2024-07-17T13:09:17Z")

</div>

## TL;DR

Cairo 2.7.0 will be released soon! At the moment, [2.7.0-rc.3](https://github.com/starkware-libs/cairo/releases/tag/v2.7.0-rc.3) is available and can be tested by the community. This version involves a Sierra upgrade to v1.6.0, **which means contracts written with v2.7.0 are only deployable on Starknet ≥ 0.13.2**. The Testnet upgrade is planned for Aug 5, and the Mainnet upgrade is planned for Aug 26 (you can find more details [here](https://community.starknet.io/t/starknet-v0-13-2-pre-release-notes/114223)). As usual, you can continue using older compiler versions for your contracts and deploy them on Starknet.

v2.7.0 is a HUGE version with an abundance of new features & updates:

- [New edition, `2024_07`](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#the-2024_07-edition-3)
- [The `Deref` and `DerefMut` traits are added to the corelib](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#deref-4), which allows the compiler to, given a deref implementation, treat the source type as the target type
- [Contract storage is now much more flexible](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#contract-storage-5):
  - Allowing read/write for [individual members](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#individual-member-access-6) for every type that derives `Store`
  - Introducing the new [`Map` type](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#maps-8) (you no longer have to use legacy maps!)
  - Introducing the [`Vec` type](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#storage-vecs-10)
  - Adding a new [“storage node” concept](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#storage-nodes-12) that allows arbitrary nesting (e.g. structs with maps, or properties that are themselves storage nodes)

- [Phantom types](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#phantom-types-17)
- [Associated items](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#associated-items-18) are introduced to Cairo, allowing you to define types, consts and impls associated with a given trait.
- [for loops](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#for-loops-22) - we now have `for elem in array`
- [sha256](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#sha256-23) support in the corelib
- [default implementations](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#default-implementations-24)
- [fixed-size array](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#fixed-size-arrays-25) type
- [Arithmetic circuits support](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362#arithmetic-circuits-26) - construct and run arithmetic circuits defined over arbitrary modulus up to 384 bits. This is particularly useful to allow efficient verification over Starknet for different proof systems, e.g. groth16 (the [Garaga](https://x.com/feltroidPrime/status/1807612773251039430) project in particular is a good example of a project that relies on this feature)

The above only includes the most significant new features, for a comprehensive list of changes see the [release notes](https://github.com/starkware-libs/cairo/releases/tag/v2.7.0-rc.0). We now proceed to dive into each of the changes mentioned above.

## Breaking changes

While we’re trying to avoid breaking any existing code in minor versions, we may allow changing internal traits or generated code that could affect existing user code. While not affecting the majority of contracts, we cover the list of potential breaking changes below:

- The compiler generated `<storage_var_name>ContractMemberStateTrait` traits, where `storage_var_name` is a name of a property of the `Storage` struct, no longer exist. If your code depended directly on one of these traits, then it will break.
- The return type of `contract_state_for_testing` and `component_state_for_testing` will not have access to the storage members. For example:

```auto
let state = MyContract::contract_state_for_testing();
let value = state.storage_var.read(); // won't compile

```

To fix this, add `mut` or `@` as follows:

```auto
let state = @MyContract::contract_state_for_testing();
state.storage_var.read(...);
let mut state = MyContract::contract_state_for_testing();
state.storage_var.write(...);

```

## The 2024\_07 edition

This new edition no longer auto adds `pub` modifiers to the `Storage` sturct and its members, this is now the responsibility of the developer. This is of particular importance for components, whose `Storage` struct is referred to by external contracts.

We’re also narrowing the prelude, removing several traits which are not common to every contract. For a full diff, you can compare the old and new preule (the old prelude is the same for 2023\_10 and 2023\_11): [v2023\_10.cairo](https://github.com/starkware-libs/cairo/blob/main/corelib/src/prelude/v2023_10.cairo#L1), [v2024\_07.cairo](https://github.com/starkware-libs/cairo/blob/main/corelib/src/prelude/v2024_07.cairo). Note that in particular, all storage access traits were added to 2023\_10 and 2023\_11, but need to be imported with 2024\_07.

## Deref

This version adds the `Deref` and `DerefMut` traits to the compiler. Similarly to [Rust](https://doc.rust-lang.org/std/primitive.array.html), these are special traits known to the compiler:

```auto
pub trait Deref<T> {
    type Target;
    fn deref(self: T) -> Self::Target;
}

pub trait DerefMut<T> {
    type Target;
    fn deref_mut(ref self: T) -> Self::Target;
}

```

When type `T` can be dereferenced to type `K`, then we can access K’s members while holding an instance of `T`. Note that any time has at most one `deref` implementation. Additionally, for now only member access via deref is supported, i.e. impls with functions whose `self` argument is of type `K` will not be applicable when holding an instance of `T`. To illustrate how `Deref` works, consider the following example:

```auto
#[derive(Drop)]
struct Type1 {
    a: u8
}

#[derive(Drop)]
struct Type2 {
    b: u8
}

impl DerefType1ToType2 of Deref<Type1> {
    type Target = Type2;
    fn deref(self: Type1) -> Type2 {
        Type2 { b: self.a }
    }
}

```

Thanks to the above `Deref` implementation, we can write the following:

```auto
let t1 = Type1 { a: 3 };
let b = t1.b;

```

Note that for the following to work, we need an implementation of `DerefMut` rather than `Deref`:

```auto
fn foo(ref t1: Type1) {
    let b = t1.b;
}

impl DerefType1ToType2 of DerefMut<Type1> {
    type Target = Type2;
    fn deref_mut(ref self: Type1) -> Type2 {
        Type2 { b: self.a }
    }
}

```

## Contract Storage

Up until now the storage mechanism solely relied on the `Store` trait. If a type `T` had a `Store<T>` implementation, then `Storage` could contain members of type `T` (the only exception being components, where the member type was the component’s `Storage` type). For example:

```auto
#[derive(starknet::Store)]
struct MyStruct {
    a: u128,
    b: u128
}

#[storage]
struct Storage {
    member: MyStruct
}

```

When reading or writing to `member`, it was only possible to read or write the struct in its entirety, i.e. via `self.member.read()`. In v2.7.0, this mechanism is generalized.

To allow this generalization, much of the code generation around contract storage was refactored. In particular, the `ContractMemberState` traits that were generated per each member of the `Storage` struct no longer exist. That is, if your code uses these generated traits explicitly, it will break. The role of these traits is now fulfilled by the `ContractStorageBase` and `ContractStorageBaseMut` generated structs. To understand those in more detail, read the “under the hood” sections below.

### Individual member access

Consider the above contract; in Cairo v2.7.0 onwards, the following syntax is supported:

```auto
fn storage_access(ref self: ContractState) {
    let member: MyStruct = self.member.read() // old
    let a = self.member.a.read(); // new
    self.member.b.write(5); // new
}

```

Note that this is only supported for types that explicitly derive `Store`, and won’t work for custom `Store` implementation (e.g. ones that are obtained by packing).

### Individual member access - under the hood

In the new version, `derive(Store)` will generate, in addition to a `Store` impl, a corresponding SubPointers type and an implementation of the SubPointers trait for this type. For our above example, the following code will be generated:

```auto
#[derive(Drop, Copy)]
struct MyStructSubPointers {
    a: starknet::storage::StoragePointer<u128>,
    b: starknet::storage::StoragePointer<u128>,
}

struct MutableMyStructSubPointers {
    a: starknet::storage::StoragePointer<Mutable<u128>>,
    b: starknet::storage::StoragePointer<Mutable<u128>>,
}

impl MyStructSubPointersImpl of starknet::storage::SubPointers<MyStruct> {
   type SubPointersType = MyStructSubPointers;

   fn sub_pointers(self: starknet::storage::StoragePointer<MyStruct>) -> MyStructSubPointers {
        let base_address = self.address;
        let mut current_offset = self.offset;
        let a_value = starknet::storage::StoragePointer {
            address: base_address,
            offset: current_offset,
        };
        current_offset = current_offset + starknet::Store::<u128>::size();
        let b_value = starknet::storage::StoragePointer {
            address: base_address,
            offset: current_offset,
        };
        MyStructSubPointers {
           a: a_value,
           b: b_value,
        }
    }
}

impl MutableMyStructSubPointersImpl of starknet::storage::MutableSubPointers<MyStruct> {
   type SubPointersType = MutableMyStructSubPointers;

   fn mutable_sub_pointers(self: starknet::storage::StoragePointer<Mutable<MyStruct>>) -> MutableMyStructSubPointers {
        let base_address = self.address;
        let mut current_offset = self.offset;
        let a_value = starknet::storage::StoragePointer {
            address: base_address,
            offset: current_offset,
        };
        current_offset = current_offset + starknet::Store::<u128>::size();
        let b_value = starknet::storage::StoragePointer {
            address: base_address,
            offset: current_offset,
        };
        MutableMyStructSubPointers {
           a: a_value,
           b: b_value,
        }
    }
}

```

`StoragePointer` is a new type defined in storage.cairo, it points to a concrete storage slot via a base address and an offset. The above generated code explains why only structs that explicitly derive `Store` allow individual member access. The generated code assumes that each member is stored via its type’s `Store` implementation, which is not necessarily the case for custom implementations, e.g. ones based on packing.

To understand how to get from `self:ContractState` to `self.member.a.read()`, we need to look into the types in question. The `ContractState` type is an empty struct generated by the compiler, that can be derefed to the `ContractStorageBase` or `ContractStorageBaseMut` types that are generated based on the `Storage` struct defined in the contract module:

```auto
#[derive(Drop, Copy)]
struct ContractStorageBase {
    member: starknet::storage::StorageBase<MyStruct>,
}

#[derive(Drop, Copy)]
struct ContractStorageBaseMut {
    member: starknet::storage::StorageBase<starknet::storage::Mutable<MyStruct>>,
}

pub struct ContractState {}

impl StorageBaseImpl of starknet::storage::StorageBaseTrait<ContractState> {
    type BaseType = ContractStorageBase;
    type BaseMutType = ContractStorageBaseMut;

    fn storage_base(self: @ContractState) -> ContractStorageBase {
        ContractStorageBase {
           member: starknet::storage::StorageBase{ address: selector!("balance") },
        }
    }
    fn storage_base_mut(ref self: ContractState) -> ContractStorageBaseMut {
        ContractStorageBaseMut {
           member: starknet::storage::StorageBase{ address: selector!("balance") },
        }
    }
}
 
impl ContractStateDeref of core::ops::SnapshotDeref<ContractState> {
    type Target = ContractStorageBase;
    fn snapshot_deref(self: @ContractState) -> ContractStorageBase {
        self.storage_base()
    }
}

impl ContractStateDerefMut of core::ops::DerefMut<ContractState> {
    type Target = ContractStorageBaseMut;
    fn deref_mut(ref self: ContractState) -> ContractStorageBaseMut {
        self.storage_base_mut()
    }
}

```

The above generated code shows us how `self.member` works, via the `DerefMut` implementation between `ref ContractState` and `ContractStorageBaseMut` that has `member` of type `StorageBase<Mutable<MyStruct>>`. To see how we can get from `StorageBase<Mutable<MyStruct>>` to `MyStruct`’s members, we need to follow the chain of derefs defined in storage.cairo:

```auto
// StorageBase<Mutable<MyStruct>> --> StoragePath<Mutable<MyStruct>>
impl StorageBaseDeref<T> of core::ops::Deref<StorageBase<T>> {
    type Target = StoragePath<T>;
    fn deref(self: StorageBase<T>) -> Self::Target {
        self.as_path()
    }
}

```

`StorageBase` represents the initial address of some type in storage. `StoragePath` is a struct that maintains a hash state that can be modified until we reach the storage location we need, and was devised mostly for `Map` accesses (or more complex storage accesses, such as storage nodes that we’ll see in subsequent sections).

We can now convert the `StoragePath` to a storage pointer by finalizing the hash state:

```auto
// StoragePath<Mutable<MyStruct>> --> StoragePointer0Offset<Mutable<MyStruct>>
impl StoragePathDeref<
    T, impl PointerImpl: StorageAsPointer<StoragePath<T>>
> of core::ops::Deref<StoragePath<T>> {
    type Target = StoragePointer0Offset<PointerImpl::Value>;
    fn deref(self: StoragePath<T>) -> StoragePointer0Offset<PointerImpl::Value> {
        self.as_ptr()
    }
}

// T is Mutable<MyStruct>, this impl gives us `as_ptr` that is used above
impl MutableStorableStoragePathAsPointer<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>
> of StorageAsPointer<StoragePath<T>> {
    type Value = T;
    fn as_ptr(self: @StoragePath<T>) -> StoragePointer0Offset<T> {
        StoragePointer0Offset { address: (*self).finalize() }
    }
}

// StoragePointer0Offset<Mutable<MyStruct>> --> StoragePointer<Mutable<MyStruct>>
impl StoragePointer0OffsetDeref<T> of core::ops::Deref<StoragePointer0Offset<T>> {
    type Target = StoragePointer<T>;
    fn deref(self: StoragePointer0Offset<T>) -> StoragePointer<T> {
        StoragePointer::<T> { address: self.address, offset: 0 }
    }
}

pub struct Mutable<T> {}

trait MutableTrait<T> {
    type InnerType;
}

impl MutableImpl<T> of MutableTrait<Mutable<T>> {
    type InnerType = T;
}

```

The above derefs brought us to `StoragePointer<Mutable<MyStruct>>`. This is where the new sub pointers types kick in, via the following two derefs in storage.cairo:

```auto
// StoragePointer<MyStruct> --> MyStructSubPointers
impl SubPointersDeref<T, +SubPointers<T>> of core::ops::Deref<StoragePointer<T>> {
    type Target = SubPointers::<T>::SubPointersType;
    fn deref(self: StoragePointer<T>) -> Self::Target {
        self.sub_pointers()
    }
}

// StoragePointer<Mutable<MyStruct> --> MutableMyStructSubPointers
impl MutableSubPointersDeref<
    T, +MutableSubPointers<T>
> of core::ops::Deref<StoragePointer<Mutable<T>>> {
    type Target = MutableSubPointers::<T>::SubPointersType;
    fn deref(self: StoragePointer<Mutable<T>>) -> Self::Target {
        self.mutable_sub_pointers()
    }
}

```

Now that we hold the `MutableMyStructSubPointers` type, to see why `self.member.a` works, we only need a reminder of the sub pointers type definition:

```auto
struct MutableMyStructSubPointers {
    a: starknet::storage::StoragePointer<Mutable<u128>>,
    b: starknet::storage::StoragePointer<Mutable<u128>>,
}

```

Finally, `self.a.read()` works since `StoragePointer<T>` exposes read, and `self.a.write()` works since `StoragePointer<Mutable<T>>` exposes write:

```auto
// Store-based read for StoragePointer<T>
pub impl StorableStoragePointerReadAccess<
    T, +starknet::Store<T>
> of StoragePointerReadAccess<StoragePointer<T>> {
    type Value = T;
    fn read(self: @StoragePointer<T>) -> T {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<T>::read_at_offset(0, *self.address, *self.offset)
        )
    }
}

// When T is `Mutable<K>`, we need a separate "read" implementation in order to reach the internal type
impl MutableStorableStoragePointerReadAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>
> of StoragePointerReadAccess<StoragePointer<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn read(self: @StoragePointer<T>) -> MutableTrait::<T>::InnerType {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType
            >::read_at_offset(0, *self.address, *self.offset)
        )
    }
}

// Write implementation for StoragePointer<T> where T is Mutable<K>
impl MutableStorableStoragePointerWriteAccess<
    T, +MutableTrait<T>, +starknet::Store<MutableTrait::<T>::InnerType>
> of StoragePointerWriteAccess<StoragePointer<T>> {
    type Value = MutableTrait::<T>::InnerType;
    fn write(self: StoragePointer<T>, value: MutableTrait::<T>::InnerType) {
        starknet::SyscallResultTrait::unwrap_syscall(
            starknet::Store::<
                MutableTrait::<T>::InnerType
            >::write_at_offset(0, self.address, self.offset, value)
        )
    }
}

```

To summarize, we followed the path:

`ref ContractState` → (deref) → `ContractStorageBaseMut` → (`self.member`) → `StorageBase<Mutable<MyStruct>>` → (deref) → `StoragePath<Mutable<MyStruct>>` → (deref) → `StoragePointer0Offset<Mutable<MyStruct>>` → (deref) → `StoragePointer<Mutable<MyStruct>>` → (deref) → `MutableMyStructSubPointers`.

### Maps

Say goodbye to `LegacyMap`. `Map` is a new and more flexible type for maintaining mappings in a contract storage. With `Map<K,V>` we can:

- Have nested Maps (rather than having a tuple type key with `LegacyMap`)
- Have `Map` as a member of a struct (we will dive into this in the following `storage_node` section)

Note that the storage layout of `Map<K, V>` is identical to that `LegacyMap<K,V>`, hence you can safely migrate to the new type.

The `Map` type can not be instantiated via user code.

To illustrate the use of the new type, consider the following simple contract:

```auto
#[starknet::contract]
mod simple_contract {
    use starknet::{ContractAddress, contract_address_const};
    use starknet::storage::{Map, StoragePathEntry};
    /// the latest edition 2024_07 also requires the following imports:
    use starknet::storage::{StorageMapReadAccess, StorageMapWriteAccess}

    #[storage]
    struct Storage {
        basic: u128,
        balances: Map<ContractAddress, u256>,
        nested_balances: Map<ContractAddress, Map<ContractAddress, u256>>,
    }

    #[abi(per_item)]
    #[generate_trait]
    pub impl SimpleContract of SimpleContractTrait {
        #[external(v0)]
        fn test_new_storage(ref self: ContractState) {
            let address = contract_address_const::<1>();
            self.balances.entry(address).read();
            self.nested_balances.entry(address).entry(address).read();   
            self.nested_balances.entry(address).entry(address).write(5);
        }
    }
}

```

### Maps - under the hood

The basic types that the new maps require are `Map` and `EntryInfo`. The purpose of these types is for us to be able to refer to the key type and value type from a `Map` instance, as illustrated by the following code in the corelib:

```auto
#[phantom]
pub struct Map<K, V> {}

/// A trait for making a map like type support implement the `StoragePathEntry` trait.
trait EntryInfo<T> {
    type Key;
    type Value;
}

impl EntryInfoImpl<K, V> of EntryInfo<Map<K, V>> {
    type Key = K;
    type Value = V;
}

```

Accessing entires of a collection `C` is done via implementing the following trait:

```auto
pub trait StoragePathEntry<C> {
    type Key;
    type Value;
    fn entry(self: C, key: Self::Key) -> StoragePath<Self::Value>;
}

```

Now we can proceed to show how the code from our previous example works:

```auto
self.balances.entry(address).read()

```

We already know, from diving into the implementation of individual members access, that `ContractState` can be dereferenced to `ContractStorageBase`, where `balances` is of type `StorageBase<Map<ContractAddress, u256>`, which can then be dereferenced `StoragePath<Map<ContractAddress, u256>>` (to get write access, we would need to start from `ref ContractState`, which can be derefed to `ContractStorageBaseMut`, which in turn has a `balances` member of type `StoragePath<Mutable<Map<ContractAddress, u256>>>`).

From `StoragePath<Map<ContractAddress, u256>>` or `StoragePath<Mutable<Map<ContractAddress, u256>>>` we get the `entry` functionality via one of the following implementations:

```auto
impl EntryInfoStoragePathEntry<
    T, 
    +EntryInfo<T>, 
    +core::hash::Hash<EntryInfo::<T>::Key, 
     StoragePathHashState>
> of StoragePathEntry<StoragePath<T>> {
    type Key = EntryInfo::<T>::Key;
    type Value = EntryInfo::<T>::Value;
    fn entry(self: StoragePath<T>, key: EntryInfo::<T>::Key) -> StoragePath<EntryInfo::<T>::Value> {
        StoragePath::<
            EntryInfo::<T>::Value
        > {
            hash_state: core::hash::Hash::<
                EntryInfo::<T>::Key, StoragePathHashState
            >::update_state(self.hash_state, key)
        }
    }
}

impl MutableEntryStoragePathEntry<
    T,
    +MutableTrait<T>,
    impl EntryImpl: EntryInfo<MutableTrait::<T>::InnerType>,
    +core::hash::Hash<EntryImpl::Key,
    StoragePathHashState>
> of StoragePathEntry<StoragePath<T>> {
    type Key = EntryImpl::Key;
    type Value = Mutable<EntryImpl::Value>;
    fn entry(self: StoragePath<T>, key: EntryImpl::Key) -> StoragePath<Mutable<EntryImpl::Value>> {
        StoragePath::<
            Mutable<EntryImpl::Value>
        > {
            hash_state: core::hash::Hash::<
                EntryImpl::Key, StoragePathHashState
            >::update_state(self.hash_state, key)
        }
    }
}

```

Above, we can see that `entry` modifies the `StoragePath` with a single hash application (specifically, Pedersen hash, as `StoragePathHashState` is just an alias to `PedersenHashState`). After calling entry, we end up with `StoragePath<EntryInfo::<T>::Value>` or `StoragePath<Mutable<EntryImpl::Value>>`. Note that `Value` can either implement `Store`, or itself be another `Map`, over which we can again call `entry`. If `Value` implements `Store`, then read access will be give by one of the following impls:

```auto
impl StorableEntryReadAccess<
    T,
    +EntryInfo<T>,
    +core::hash::Hash<EntryInfo::<T>::Key,StoragePathHashState>,
    +starknet::Store<EntryInfo::<T>::Value>,
> of StorageMapReadAccessTrait<StoragePath<T>> {
    type Key = EntryInfo::<T>::Key;
    type Value = EntryInfo::<T>::Value;
    fn read(self: StoragePath<T>, key: EntryInfo::<T>::Key) -> EntryInfo::<T>::Value {
        self.entry(key).as_ptr().read()
    }
}

impl MutableStorableEntryReadAccess<
    T,
    +MutableTrait<T>,
    +EntryInfo<MutableTrait::<T>::InnerType>,
    +core::hash::Hash<EntryInfo::<MutableTrait::<T>::InnerType>::Key, StoragePathHashState>,
    +starknet::Store<EntryInfo::<MutableTrait::<T>::InnerType>::Value>,
> of StorageMapReadAccessTrait<StoragePath<T>> {
    type Key = EntryInfo::<MutableTrait::<T>::InnerType>::Key;
    type Value = EntryInfo::<MutableTrait::<T>::InnerType>::Value;
    #[inline(always)]
    fn read(
        self: StoragePath<T>, key: EntryInfo::<MutableTrait::<T>::InnerType>::Key
    ) -> EntryInfo::<MutableTrait::<T>::InnerType>::Value {
        self.entry(key).as_ptr().read()
    }
}

```

A similar impl will give us write capabilities with the type `StoragePath<Mutable<EntryImpl::Value>>`.

### Storage vecs

So far, to have sequential access to a collection in storage, one needed to use maps or a custom implementation, e.g., as done by [OpenZeppelin](https://github.com/OpenZeppelin/cairo-contracts/blob/4f4e2e48bd86d99c3ee5ee405140bf1681529a2e/src/utils/structs/storage_array.cairo#L16). This version introduces the `Vec` type, which allows keeping vectors in a contract’s storage.

Below is an example of how one can use storage vectors:

```auto
use starknet::storage::{Vec, VecTrait, MutableVecTrait};

#[storage]
struct Storage {
    var1: Vec<u256>,
    var2: Vec<Map<u8, Vec<u8>>>
}

fn foo(ref self: ContractState) {
  self.var1.append().write(1);
  self.var1.append().write(2);
  assert!(self.var1.len() == 2);
  assert!(self.var1[0].read() == 1 && self.var1[1].read() == 2);
  self.var1[0].write(4);
  self.var2.append().entry(5).append().write(1);
  assert!(self.var2[0].entry(5)[0].read() == 1);
  self.var1[3].read(); // panic (out of bounds)
}

```

### Storage vecs - under the hood

The `VecTrait` and `MutableVecTrait` traits give us the ability to access vec indices and append new elements. These impls operate on `StoragePath<Vec<T>>` and `StoragePath<Mutable<Vec<T>>>`, which are the member types of the generated `ContractStorageBase` and `ContractStorageBaseMut` types, as we’ve seen in “individual storage access - under the hood”.

```auto
pub struct Vec<T> {}

pub trait VecTrait<T> {
    type ElementType;
    fn at(self: T, index: u64) -> StoragePath<Self::ElementType>;
    fn len(self: T) -> u64;
}

pub trait MutableVecTrait<T> {
    type ElementType;
    fn at(self: T, index: u64) -> StoragePath<Mutable<Self::ElementType>>;
    fn len(self: T) -> u64;
    fn append(self: T) -> StoragePath<Mutable<Self::ElementType>>;
}

impl VecImpl<T> of VecTrait<StoragePath<Vec<T>>> {
    type ElementType = T;
    fn get(self: StoragePath<Vec<T>>, index: u64) -> Option<StoragePath<T>> {
        let vec_len = self.len();
        if index < vec_len {
            Option::Some(self.update(index))
        } else {
            Option::None
        }
    }
    fn at(self: StoragePath<Vec<T>>, index: u64) -> StoragePath<T> {
        assert!(index < self.len(), "Index out of bounds");
        self.update(index)
    }
    fn len(self: StoragePath<Vec<T>>) -> u64 {
        self.as_ptr().read()
    }
}

impl MutableVecImpl<T> of MutableVecTrait<StoragePath<Mutable<Vec<T>>>> {
    type ElementType = T;
    fn get(self: StoragePath<Mutable<Vec<T>>>, index: u64) -> Option<StoragePath<Mutable<T>>> {
        let vec_len = self.len();
        if index < vec_len {
            Option::Some(self.update(index))
        } else {
            Option::None
        }
    }
    fn at(self: StoragePath<Mutable<Vec<T>>>, index: u64) -> StoragePath<Mutable<T>> {
        assert!(index < self.len(), "Index out of bounds");
        self.update(index)
    }
    fn len(self: StoragePath<Mutable<Vec<T>>>) -> u64 {
        self.as_ptr().read()
    }
    fn append(self: StoragePath<Mutable<Vec<T>>>) -> StoragePath<Mutable<T>> {
        let vec_len = self.len();
        self.as_ptr().write(vec_len + 1);
        self.update(vec_len)
    }
}

```

Note that the storage layout of `Vec` is determined by the `get` implementation, which computes the address of the n’th element as `h(base_address, n)`, where `h` is the Pedersen hash function. The length of the array is held at `base_address`, where the base address is determined by the location of the array with respect to the `Storage` struct. For example, in the case of `var1` above, the base address is `sn_keccak("var1")`, while the base address of `self.var2[0].entry(5).read()` is `pedersen(sn_keccak("var2"), 5)`.

### Storage nodes

Storage nodes are a new concept introduced in Cairo v2.7.0. The motivation behind them was to have `Map`, or other “special” types that do not implement `Store` but can appear inside `Storage`, as potential members of structs.

You can think of storage nodes as nodes in a tree that lie within the contract storage space. Content is stored in the leaves, and intermediate nodes allow you to point to other locations in storage. Consider the following example:

```auto
struct Storage {
    member: MyNode
}

#[starknet::storage_node]
struct MyNode {
    a: u8,
    b: u256,
    c: Map<u256, u256>
}

fn foo(self: @ContractState) {
   self.member.c.entry(5).read();
}

```

Thanks to the `#[starknet::storage_node]` attribute over `MyNode`, we can have storage variables of type `MyNode`, although it doesn’t implement `Store`.

The storage layout of `MyNode` will be based on the names of its members: `a`, `b`, and `c`. For example, the actual storage key read by `self.member.c.entry(5).read()` is:

`h(sn_keccak("member"), h(sn_keccak("c"), 5))`,

where `h` is the Pedersen hash function.

Maps in structs are not the only thing that you can do with storage nodes. To illustrate their strength, consider the following example:

```auto
struct Storage {
    root: StorageTreeNode
}

#[starknet::storage_node]
struct StorageTreeNode {
    value: u32,
    left: StorageTreeNode,
    right: StorageTreeNode
}

```

Without the `#[starknet::storage_node]` attribute, the above code would not have compiled as `StorageTreeNode` has infinite size. The `#[starknet::storage_node]` attribute tells the compiler that `StorageTreeNode` will never be instantiated directly and will only serve to point to storage locations.

Note that to make the above example interesting, you would need another property on `StorageTreeNode` which tells you whether or not you’re at a leaf (or, e.g., change `value` to `Option<u32>`, where `None` indicates that you hit a leaf). It’s important to emphasize that a storage node does not carry value by itself, it is essentially a path to some storage location from which I can read members. Hence, I cannot ask if `self.root.left` is `None`, it is a path to some location in storage, I can always point to it. Any actual information should be kept in storeable members of the storage node.

### Storage nodes - under the hood

Throughout this section, we’ll use the following storage node as our example:

```auto
#[storage]
struct Storage {
    member: MyNode
}

#[starknet::storage_node]
struct MyNode {
    a: u8,
    b: Map<u256, u256>,
    c: MyNode
}

fn foo(self: @ContractState) {
   self.member.a.read();
   self.member.b.entry(5).read();
   self.c.c.a.read();
}

```

When trying to work out `self.member.a.read()`, without the new `#[storage_node]` attribute, trying to follow the path from “individual member access - under the hood”, we will break when trying to deref from  
`StoragePath<MyNode>` to `StoragePointer0Offset<MyNode>, since the deref implementation needs an impl of the `StorageAsPointer trait, and the following generic implementation in the corelib won’t help since we don’t have `Store`:

```auto
pub trait StorageAsPointer<TMemberState> {
    type Value;
    fn as_ptr(self: @TMemberState) -> StoragePointer0Offset<Self::Value>;
}

impl StorableStoragePathAsPointer<T, +starknet::Store<T>> of StorageAsPointer<StoragePath<T>> {
    type Value = T;
    fn as_ptr(self: @StoragePath<T>) -> StoragePointer0Offset<T> {
        StoragePointer0Offset { address: (*self).finalize() }
    }
}

```

Thus, we need a new way to get `read` from `StoragePath<MyNode>` without relying on `Store` (we will ignore `write` in this section since it is a repetition of the same `Mutable<T>` trick we’ve seen in the previous sections).

When annotating `MyNode` with the `#[starknet::storage_node]` attribute, the following code is generated:

```auto
#[derive(Drop, Copy)]
struct MyNodeStorageNode {
    a: starknet::storage::PendingStoragePath<u8>,
    b: starknet::storage::PendingStoragePath<Map<u256, u256>>,
    c: starknet::storage::PendingStoragePath<MyNode>,
}

impl MyNodeStorageNodeImpl of StorageNode<MyNode> {
   
   type NodeType = BalancePairStorageNode;

   fn storage_node(self: StoragePath<MyNode>) -> MyNodeStorageNode {
        let a_value = PendingStoragePathTrait::new(
                        @self,
                        selector!("a")
                    );
        let b_value = PendingStoragePathTrait::new(
                        @self,
                        selector!("b")
                    );
        let c_value = PendingStoragePathTrait::new(
                        @self,
                        selector!("c")
                    );
        MyNodeStorageNode {
           a: a_value,
           b: b_value,
           c: c_value
        }
    }
}

```

The above is similar to the generated sub pointers type, except now we need to encode `MyNode` member names in the storage path somehow. To this end, the `PendingStoragePath` type was introduced:

```auto
struct PendingStoragePath<T> {
    hash_state: StoragePathHashState, // PedersenHashState
    pending_key: felt252
}

```

Now, the following deref implementation in the corelib completes the picture:

```auto
impl StorageNodeDeref<T, +StorageNode<T>> of core::ops::Deref<StoragePath<T>> {
    type Target = StorageNode::<T>::NodeType;
    fn deref(self: StoragePath<T>) -> Self::Target {
        self.storage_node()
    }
}

```

This is what gets us from `StoragePath<MyNode>` to `MyNodeStorageNode`, a struct whose members are `a`, `b`, and `c` (same as `MyNode`), but with the member types being wrapped by `PendingStoragePath`.

The `read` functionality on `PendingStoragePath<u8>` comes from the following impls in the corelib:

```auto
// PendingStoragePath --> StoragePath
impl PendingStoragePathAsPath<T> of StorageAsPath<PendingStoragePath<T>> {
    type Value = T;
    fn as_path(self: @PendingStoragePath<T>) -> StoragePath<T> {
        StoragePath::<
            T
        > { hash_state: core::hash::HashStateTrait::update(*self.hash_state, *self.pending_key) }
    }
}

// T is PendingStoragePath<u8>
impl StorablePathableStorageAsPointer<
    T,
    impl PathImpl: StorageAsPath<T>,
    // PathImpl::Value is u8, the StorageAsPointer<u8> impl is given by `StorableStoragePathAsPointer`
    impl PtrImpl: StorageAsPointer<StoragePath<PathImpl::Value>>,
> of StorageAsPointer<T> {
    type Value = PtrImpl::Value;
    fn as_ptr(self: @T) -> StoragePointer0Offset<PtrImpl::Value> {
        let path = self.as_path();
        path.as_ptr()
    }
}

// This impl grants us `self.member.a.read()`
impl StorablePointerReadAccessImpl<
    T,
    impl PointerImpl: StorageAsPointer<T>,
    impl AccessImpl: StoragePointerReadAccess<StoragePointer0Offset<PointerImpl::Value>>,
    +Drop<T>,
    +Drop<AccessImpl::Value>,
> of StoragePointerReadAccess<T> {
    type Value = AccessImpl::Value;
    fn read(self: @T) -> Self::Value {
        self.as_ptr().read()
    }
}

```

The above shows us how can we get access to “storable” members of the storage node. But what about `self.member.b.entry(5).read()` or `self.member.c.c.a.read()`.

To get access to the map member via

`self.member.b.entry(5).read()`

we need the following two impls:

```auto
// T is PendingStoragePath<Map<u256, u256>>`
impl PathableStorageEntryImpl<
    T,
    impl PathImpl: StorageAsPath<T>,
    impl EntryImpl: StoragePathEntry<StoragePath<PathImpl::Value>>,
    +Drop<T>,
    +Drop<EntryImpl::Key>,
> of StoragePathEntry<T> {
    type Key = EntryImpl::Key;
    type Value = EntryImpl::Value;
    fn entry(self: T, key: Self::Key) -> StoragePath<Self::Value> {
        let path = PathImpl::as_path(@self);
        EntryImpl::entry(path, key)
    }
}

// T is `StoragePath<Map<u256, u256>>`
impl StorageAsPathReadForward<
    T,
    impl PathImpl: StorageAsPath<T>,
    impl AccessImpl: StorageMapReadAccessTrait<StoragePath<PathImpl::Value>>,
    +Drop<T>,
    +Drop<AccessImpl::Key>,
> of StorageMapReadAccessTrait<T> {
    type Key = AccessImpl::Key;
    type Value = AccessImpl::Value;
    #[inline(always)]
    fn read(self: T, key: AccessImpl::Key) -> AccessImpl::Value {
        self.as_path().read(key)
    }
}

```

To keep reading the next storage node via e.g.

`self.member.c.c.a.read()`

we need to go back from `PendingStoragePath<MyNode>` back to `StoragePath<MyNode>`, from which we can again call the `storage_node()` function and obtain the `PendingStoragePath<MyNode>` type. This is achieve by the following deref impl:

```auto
impl PendingStoragePathDeref<T> of core::ops::Deref<PendingStoragePath<T>> {
    type Target = StoragePath<T>;
    fn deref(self: PendingStoragePath<T>) -> Self::Target {
        self.as_path()
    }
}

```

### New storage design - examples

The new storage primitives that were discussed in the previous sections open new possibilities. We cover a few examples below.

#### += for Storage variables

A common storage access pattern is reading a value, adding/subtracting, and then writing the new value. With `StoragePath<T>` we can get the `+=` functionality for every storage variable whose type has an `AddAsign` implementation as follows:

```auto
#[starknet::contract]
mod numeric_contract {
    use core::ops::AddAssign;

    pub impl AddAsignStorage<
        Lhs, Rhs, +Drop<Lhs>, +Drop<Rhs>, 
        +AddAssign<Lhs, Rhs>,
        +Store<Lhs>
    > of AddAssign<StorageBase<Mutable<Lhs>>, Rhs> {
        fn add_assign(ref self: StorageBase<Mutable<Lhs>>, rhs: Rhs) {
            let mut value: Lhs = self.read();
            value += rhs;
            self.write(value);
        }
    }

    #[storage]
    struct Storage {
        numeric: u128,
    }

    #[abi(per_item)]
    #[generate_trait]
    pub impl NumericContract of NumericContractTrait {
        #[external(v0)]
        fn inc(ref self: ContractState) {
            let mut num = self.numeric;
            num += 1;        
        }
    }
}

```

By implementing `AddAsign` for `StorageBase<Lhs>` we were able to get `+=` for storage variables. Do note that this is not always desirable, since `+=` might hide expensive operations (storage write).

Note that the above will not work for structs members, maps, and storage nodes, as those are not of type `StorageBase<T>`. To extend `+=` to all uints anywhere in storage, we need our impl to work on `StoragePath`, or more specifically anything that implements the `StorageAsPath` trait. This is illustrated below:

```auto
pub impl AddAsignStoragePath<
    Lhs, Rhs, +Drop<Lhs>, +Drop<Rhs>, 
    +AddAssign<Lhs, Rhs>,
    +Store<Lhs>
> of AddAssign<StoragePath<Mutable<Lhs>>, Rhs> {
    fn add_assign(ref self: StoragePath<Mutable<Lhs>>, rhs: Rhs) {
        let mut value: Lhs = self.read();
        value += rhs;
        self.write(value);
    }
}

// Lhs is StorageBase<Mutable<u8>>
// LhsAsPath's value is Mutable<u8>
pub impl AddAsignStorageAsPath<
    Lhs, Rhs, +Drop<Lhs>, +Drop<Rhs>, 
    impl LhsAsPath: StorageAsPath<Lhs>,
    +AddAssign<StoragePath<LhsAsPath::Value>, Rhs>
> of AddAssign<Lhs, Rhs> {
    fn add_assign(ref self: Lhs, rhs: Rhs) {
        let mut value = self.as_path();
        value += rhs;
    }
}

#[starknet::storage_node]
struct Numeric {
    num: u8,
    map: Map<u8, u8>
}

fn foo(ref self: ContractState) {
    let mut numeric = self.numeric.num;
    numeric += 1;
    let mut numeric = self.numeric.map.read(5);
    numeric += 6;
}

```

To avoid the risk of having `+=` for storage variables that may have large hidden cost, one can ignore the `AddAssign` trait and implement a new trait, e.g. `StorageInc`, with an `inc` function that behaves similarly to the above

#### Giving access to storage variables

In previous versions, the only way to access storage outside the contract module was to use components or the `unsafe_new_contract_state` function. With the new storage types, we can call functions that accept `StoragePath<T>`, and thus allow them to modify our storage.

```auto
#[starknet::storage_node]
struct Numeric {
    num: u8,
    map: Map<u8, u8>
}

#[storage]
struct Storage {
    numeric: Numeric,
    map: Map<u8, u8>,
}

fn foo(ref self: ContractState) {
   modify_from_outside(self.numeric.deref(), self.map.deref());
}

pub fn modify_from_outside(
    numeric: StoragePath<Mutable<Numeric>>, 
    map: StoragePath<Mutable<Map<u8,u8>>> 
) {
    numeric.num.write(1);
    map.entry(5).write(3);
}

```

Note that we had to call `deref` explicitly to move from `StorageBase` to `StoragePath`.

This direction can yield a new way of writing components without much of the existing boilerplate. While still experimental, you can examine such an example in [erc20\_mini.cairo](https://github.com/starkware-libs/cairo/blob/dev-v2.7.0/crates/cairo-lang-starknet/cairo_level_tests/components/erc20_mini.cairo), and a contract using it in [with\_erc20\_mini](https://github.com/starkware-libs/cairo/blob/dev-v2.7.0/crates/cairo-lang-starknet/src/plugin/plugin_test_data/contracts/with_erc20_mini#L13). With this approach, instead of using the `component!` macro and denoting a storage member by `#[substorage(v0)]`, you can define the component’s storage struct as a storage node.

## Phantom types

Types annotated by `#[phantom]` are types that cannot be instantiated. They are used to pass on information via traits that are implemented for them. For example, the following are phantom types:

```auto
#[phantom]
pub struct Map<K, V> {}

#[phantom]
pub struct Vec<T> {}

```

This shouldn’t be surprising as the above types are only used as the generic type of `StoragePath`. The `Storage` struct and any struct annotated by `#[starknet::storage_node]` are also phantom types.

## Associated items

Associated items are items that are declared in traits and defined in implementations. They are defined similarly to the same concept in [Rust](https://doc.rust-lang.org/reference/items/associated-items.html). We proceed to dive into each the possible associated items.

### Associated types

The addition trait is a good example of the potential advantage of associated types:

```auto
trait Add<Lhs, Rhs> {
    type Result;
    fn add(lhs: Lhs, rhs: Rhs) -> Self::Result;
}

```

suppose now that a function `foo<A, B>` needs the ability to add A and B. If we had defined the `Add` trait with an additional generic parameter that is used to describe the result, then our code would have looked like this:

```auto
fn foo<A,B,C, +Add<A,B,C>>(a:A, b:B) -> C {
   return a+b;
}

```

However, with associated types, we can get the result type from the impl of `Add`, and we don’t need to pollute `foo` with an additional generic argument:

```auto
fn foo<A,B, AddImpl: Add<A,B>>(a: A, b: B) -> AddImpl::Result {
    return a+b;
}

```

The point is that `foo` doesn’t necessarily need to generic on the addition result type, this information is associated with the impl of the `Add` trait.

### Associated consts

Suppose that we have a game with multiple character types, e.g. `Wizard` and `Warrior`, and each character has some fixed hp based on its type. We can model this scenario as follows:

```auto
#[derive(Drop)]
struct Warrior { ... }
#[derive(Drop)]
struct Wizard { ... }

trait Character<T> {
    const hp: u32;
    fn fight(self: T);
}

impl WizardCharacter of Character<Wizard> {
    const hp: u32 = 70;
    fn fight(self: Wizard) { ... } 
}

impl WarriorCharacter of Character<Warrior> {
    const hp: u32 = 100;
    fn fight(self: Warrior) { ... } 
}

```

Since hp is fixed per character type, associated costs allowed us to bind this number to the character trait rather than adding it to the struct or just hardcoding the value in the implementation.

### Associated impls

The new iterator traits are a good example of when one might need associated impls. Consider the new iterator traits from [iterator.cairo](https://github.com/starkware-libs/cairo/blob/264e588698bec5dab5fbf8aadb21fa27e333e0d5/corelib/src/iter/traits/iterator.cairo#L2):

```auto
// T is the collection type
pub trait Iterator<T> {
    type Item;
    fn next(ref self: T) -> Option<Self::Item>;
}

/// Turn a collection of values into an iterator.
pub trait IntoIterator<T> {
    /// The iterator type that will be created.
    type IntoIter;
    impl Iterator: Iterator<Self::IntoIter>;

    fn into_iter(self: T) -> Self::IntoIter;
}

```

An implementation of `IntoIterator` is expected to take a collection and return a corresponding iterator type `IntoIter`. How can we enforce that the returned type is indeed an iterator, i.e. something that implements that iterator trait? This is where the associated impl `Iterator` comes in, which is by definition an impl of the `Iterator` trait for the associated `IntoIter` iterator type.

The important observation is that **any** implementation of `IntoIterator` should return an iterator. Thus, while we can use generic impl params to enforce a specific implementation of `IntoIterator` returning an actual iterator, it should be already determined at the trait level. Associated impls are exactly the tool that allows us to do it.

Note that an implementation of `IntoIterator` does not necessarily need to specify the `Iterator` impl, if one exists in your context then it will be deduced, similarly to generic impl params. This is illustrated by the corelib’s implementation of `IntoIterator<Array<T>>`:

```auto
#[derive(Drop)]
pub struct ArrayIter<T> {
    array: Array<T>,
}

impl ArrayIterator<T> of Iterator<ArrayIter<T>> {
    type Item = T;
    fn next(ref self: ArrayIter<T>) -> Option<T> {
        self.array.pop_front()
    }
}

impl ArrayIntoIterator<T> of core::iter::IntoIterator<Array<T>> {
    type IntoIter = ArrayIter<T>;
    fn into_iter(self: Array<T>) -> ArrayIter<T> {
        ArrayIter { array: self }
    }
}

```

## for loops

With iterators come for loops. You can now iterate over arrays and spans as follows:

```auto
fn test_for_loop_array_sum() {
    let mut sum = 0;
    for x in array![10, 11, 12] {
        sum += x;
    };
    assert_eq!(sum, 33);
}

```

The above loop is based on the [ArrayIntoIterator](https://github.com/starkware-libs/cairo/blob/88cefed325bd1039f80641b55220a0c84dd02ad8/corelib/src/array.cairo#L414) implementation in the corelib. You can find more examples in [for\_test.cairo](https://github.com/starkware-libs/cairo/blob/83a1129895a90cb536c6125d1599fa29cbdcfede/corelib/src/test/language_features/for_test.cairo#L1).

## SHA256

The `sha256_process_block_syscall` system call is added. You’ll find high level functions for computing sha256 in [sha256.cairo,](https://github.com/starkware-libs/cairo/blob/f5ac2d1d24ae0a626e9925db0c564bd0c4fea433/corelib/src/sha256.cairo#L24) specifically `compute_sha256_u32_array` and `compute_sha256_byte_array`.

Below is an example of computing sha256 in your contract:

```auto
#[external(v0)]
fn test_sha256(ref self: ContractState) {
    let mut input: Array::<u32> = Default::default();
    input.append('aaaa');

    // Test the sha256 syscall computation of the string 'aaaa'.
    let [res, _, _, _, _, _, _, _,] = compute_sha256_u32_array(input, 0, 0);
    assert(res == 0x61be55a8, 'Wrong hash value');
}

```

Each syscall application costs ~ 180 gas. Taking padding into account, we need a syscall invocation per ~ 14 u32 inputs, resulting in ~ 3.2 gas per byte.

## Default implementations

We can now have default implementations of trait functions, similarly to [Rust](https://doc.rust-lang.org/book/ch10-02-traits.html#default-implementations). Default implementations are illustrated in the example below:

```auto
trait TraitWithDefaultImpl {
    fn foo(self: u256);
    fn boo(self: u128) -> u128 {
        self+1
    }
}

impl SomeImpl of TraitWithDefaultImpl {
    fn foo(self: u256) {}
}

impl SomeOverridingImpl of TraitWithDefaultImpl {
    fn foo(self: u256) {}
    fn boo(self: u128) -> u128 { self }
}

```

`SomeImpl::boo(3)` will use the default implementation, while `SomeOverridingImpl::boo(3)` will use its own implementation.

## Fixed size arrays

Fixed size arrays, denoted by `[T; N]`, are a type that represents an N-tuple of T:

```auto
let arr1: [u64; 5] = [1,2,3,4,5];
let arr2: Span<u64> = [1,2,3,4,5].span();

```

To access a member of a fixed size array we can either deconstruct it with something like `let [a, b, c, _, _] = arr1`, or use the `.span()` function. Note that if we plan to repeatedly access the array, then it makes sense to call `.span()` once and keep it available throughout the accesses.

With const fixed size arrays, we can hardcode a potentially long sequence of data in our program, similarly to how `dw` (define word) was used in CairoZero:

```auto
const arr: [u64; 5] = [1,2,3,4,5];

```

To pass the const value cheaply between functions (without copying), you can call `.span()`, which has a trivial implementation (no cairo-steps overhead)

```auto
fn get_arr(arr: Span<u64>) { ... }
get_arr(arr.span());

```

## Arithmetic circuits

We introduce an efficient way to define and run arithmetic circuits with a 384-bit modulus. Arithmetic circuits in Cairo are aimed at applications that need to be as bare metal as possible, and want to avoid the overhead of Cairo by defining raw circuits. Two new builtins, `add_mod` and `mul_mod`, will perform arithmetic operations under the hood. That is, Cairo is only used to describe the circuit.

Four types of gates are supported, `AddModGate`, `SubModGate`, `MulModGate`, and `InverseGate`. To construct a circuit, we use the empty `CircuitElement<T>` struct. The circuit description is encoded within the type `T`. That is, whenever we add a gate to the circuit, we wrap our existing circuit types with the appropriate gate types. For example, adding `CricuitElement<Lhs>` and `CircuitElement<Rhs>` results with `CircuitElement<AddModGate<Lhs, Rhs>>`.

The following code constructs the circuit: \frac{1}{x+y}\left((x+y)^{-1}-y\right):

```auto
use core::circuit::{
    RangeCheck96, AddMod, MulMod, u96, CircuitElement, CircuitInput, circuit_add, circuit_sub,
    circuit_mul, circuit_inverse, EvalCircuitTrait, u384, CircuitOutputsTrait, CircuitModulus,
    AddInputResultTrait, CircuitInputs,
};

let in1 = CircuitElement::<CircuitInput<0>> {};
let in2 = CircuitElement::<CircuitInput<1>> {};
let add = circuit_add(in1, in2);
let inv = circuit_inverse(add);
let sub = circuit_sub(inv, in2);
let mul = circuit_mul(inv, sub);

```

Now, we need to define the output tuple:

```auto
let output_gates = (mul);

```

Note that any of the circuit’s gates can be added to the output tuple. We can access the value of any gate after evaluating, but `outputs` must include all gates whose out degree is 0. The evaluation would have remained the same if we were do define `output_gates` as `(mul, add, sub, inv)`.

Next, we proceed to initialize the circuits with inputs, each input is represented by fixed size array of four u96:

```auto
output_gates.new_inputs()
  .next([3, 0, 0, 0])
  .next([6, 0, 0, 0])
  .done()

```

Note that the `next` function returns a variant of the `AddInputResult` enum:

```auto
pub enum AddInputResult<C> {
    /// All inputs have been filled.
    Done: CircuitData<C>,
    /// More inputs are needed to fill the circuit instance's data.
    More: CircuitInputAccumulator<C>,
}

```

We must fill all the inputs of the circuit, and calling `next` on the `Done` variant, whose type `CircuitData<C>` describes a circuit initialized with inputs, will result in a panic.

Now that we have `CircuitData<C>` (`C` is now the long type encoding the entire circuit), we can define the modules and call eval:

```auto
let modulus = TryInto::<_, CircuitModulus>::try_into([7, 0, 0, 0]).unwrap();

let res = output_gates.eval(modulos).unwrap();

```

Note that `eval` returns `Result`, as the evaluation may err due to division by zero. If the evaluation had been successful, we can ask the value of any intermediate gate, assuming we an instance of the corresponding type:

```auto
assert_eq!(res.get_output(add), u384 { limb0: 2, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(res.get_output(inv), u384 { limb0: 4, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(res.get_output(sub), u384 { limb0: 5, limb1: 0, limb2: 0, limb3: 0 });
assert_eq!(res.get_output(mul), u384 { limb0: 6, limb1: 0, limb2: 0, limb3: 0 });

```

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [July 18, 2024, 9:02am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/2 "2024-07-18T09:02:29Z")

</div>

GM,

Exciting stuff coming!

Few question:

- Regarding `Contract Storage`:
  - Can we still read entire structs?  
If I read correctly `in addition to a Store impl` I believe it is still possible but could you confirm?
  - It is then cheaper to read 1 member of the struct instead of the whole struct, right?

- Regarding `Maps`
  - It is still using Pedersen hash, but Poseidon should be cheaper.  
Is it planned to have a Map using Poseidon to lower the costs?

- Regarding `Storage nodes `
  - Using your MyNode example, does that mean I can do stuff like

```rust
// This allows to read in loops an other behaviour
let member1 = self.member.read();
let member2 = member1.c.read();
let member3 = member2.c.read();
// Or is it mandatory to do like this?:
let member3 = self.member.c.c.read();

```

- Regarding `+= for Storage variables`
  - Would you have a simple code example?
  - Does that mean there is also `-=`, `*=`, … or just `+=` atm?

- Regarding `Phantom types`
  - They cannot be instantiated but can they be passed as fn argument from external/view fn?

Thanks in advance! 🙂

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 18, 2024, 1:09pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/3 "2024-07-18T13:09:31Z")

</div>

Hey, regarding your questions:

> Can we still read entire structs?

Yes, you can still read entire structs (given a `Store` implementation)

> It is then cheaper to read 1 member of the struct instead of the whole struct, right?

Yes, reading only one member is cheaper (less read syscalls are applied)

> Is it planned to have a Map using Poseidon to lower the costs?

We chose Pedersen because, in addition to backward compatibility, it looks like with Stwo, Pedersen will be much easier to prove (due to its friendlier approach to preprocessing and lookups). It looks like we’re changing the direction from Poseidon to Pedersen for new stuff. We’re still considering other options for hashes, but we thought being backward compatible with LegacyMap breaks the symmetry.

> Using your MyNode example, does that mean I can do stuff like

You can’t read a struct marked with `#[storage_node]`. It’s a phantom type, and can’t be instantiated, so nothing can be returned from `read.` Its purpose is to allow the compiler to generate code that allows you to access members of a storage node, via derfing the original struct (which is phantom) to a corresponding storage node type.

> += for Storage variables

+= May have been a bad example, you can ignore the `AddAsign` stuff, the idea is that with `StoragePath` you can now implement generic storage manipulations, see `modify_from_outside`. Note that this code is not part of the corelib, because it’s not a good idea to have += that is implicitly very expensive due to storage writes.

> They cannot be instantiated but can they be passed as fn argument from external/view fn?

You can’t have them as a function argument since the function will never be callable (you can’t instantiate the input). They are useful as generic dependencies, for example, we can implement things for `StoragePath<Map>`, as done in the corelib.

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [July 18, 2024, 1:31pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/4 "2024-07-18T13:31:37Z")

</div>

> Blockquote  
> We chose Pedersen because, in addition to backward compatibility, it looks like with Stwo, Pedersen will be much easier to prove (due to its friendlier approach to preprocessing and lookups). It looks like we’re changing the direction from Poseidon to Pedersen for new stuff. We’re still considering other options for hashes, but we thought being backward compatible with LegacyMap breaks the symmetry.

Wdym?  
Does that mean poseidon should be used for new stuff?  
Do you recommend to stick with Pedersen as it’ll be cheaper with Stwo?  
Or will there be a new Hashing fn optimised for Stwo?

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 21, 2024, 5:21am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/5 "2024-07-21T05:21:55Z")

</div>

Pedersen will be cheaper in stwo. We might choose a different hash altogether that wins on both x86 & proving metrics. If you must choose now, then I suggest to be compatible with SNIP12 (which at the current revision uses Poseidon), and if you don’t need snip12 then I’d probably choose Pedersen.

---

<div class="post-metadata">

**Author:** ![misicnenad](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/misicnenad/32/85183_2.png) [@misicnenad](https://community.starknet.io/u/misicnenad)\
**Post date:** [July 22, 2024, 11:54am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/6 "2024-07-22T11:54:47Z")

</div>

This looks fascinating!

A question about `Vec<T>` and `Map<K, V>` - is there a plan to include these in regular plain Cairo?  
If Cairo is supposed to be a general purpose language, and not just used for Starknet, then it would make sense to have these included in the core language.

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 22, 2024, 7:14pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/7 "2024-07-22T19:14:30Z")

</div>

`Vec` and `Map` are types intended for storage access, both are empty structs that can’t be instantiated, they only serve the purpose of externalizing the ability to access storage. The non-contract analog of `Map` is `Felt252Dict<T>`, and `Array<T>` serves the purpose of vec in memory (we originally thought about naming the new vec as `StorageArray`).

---

<div class="post-metadata">

**Author:** ![eni](https://avatars.discourse-cdn.com/v4/letter/e/a87d85/32.png) [@eni](https://community.starknet.io/u/eni)\
**Post date:** [July 26, 2024, 10:48am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/8 "2024-07-26T10:48:04Z")

</div>

> [@FeedTheFed](#):
>
> (we originally thought about naming the new vec as `StorageArray`).

I think it would have been a much better name. StorageArray is explicit that it’s scope is to put an array in Storage. Vec is extremely confusing, especially for people with a Rust background that will try to use it as an memory-mutable data structure (as the one that has been implemented in Alexandria for almost a year now)

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 28, 2024, 1:15pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/9 "2024-07-28T13:15:24Z")

</div>

I understand your point, but it’s at least mitigated by the fact that both lie under starknet::storage, i.e. to import you need `use starknet::storage::{Vec, Map}`. With the storage prefix, you’d have a somewhat redundant “storage” in the full path.

---

<div class="post-metadata">

**Author:** ![misicnenad](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/misicnenad/32/85183_2.png) [@misicnenad](https://community.starknet.io/u/misicnenad)\
**Post date:** [July 29, 2024, 11:44am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/10 "2024-07-29T11:44:25Z")

</div>

Just curious about the reasoning, how come only `Felt252Dict<T>` is implemented in the base language, but something like `Map<K, V>` is not? Is there a plan to support this?

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [July 29, 2024, 1:41pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/11 "2024-07-29T13:41:42Z")

</div>

These are very different types, anything related to Starknet storage makes no sense in standalone Cairo. This leaves the following interpretation of your question: “why no dicts with non-felt keys”? I think there should be, we can have `Dict<K, V>` where `K` has `Hash`, and under the hood `Felt252Dict` is used, but this is not implemented yet.

---

<div class="post-metadata">

**Author:** ![eni](https://avatars.discourse-cdn.com/v4/letter/e/a87d85/32.png) [@eni](https://community.starknet.io/u/eni)\
**Post date:** [July 30, 2024, 4:43pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/12 "2024-07-30T16:43:10Z")

</div>

The same argument could be used for `StoragePointer`, `StoragePath` and `StorageBaseAddress` 😄

My first concern is for people not experienced, it’s confusing and hurts accessibility a bit (if you see in code X someone using Vec (as in memory Vec) and end up using Vec (as in storage Vec), it’s confusing. And this issue happens constantly with other items.

---

<div class="post-metadata">

**Author:** ![eni](https://avatars.discourse-cdn.com/v4/letter/e/a87d85/32.png) [@eni](https://community.starknet.io/u/eni)\
**Post date:** [July 31, 2024, 9:37am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/13 "2024-07-31T09:37:42Z")

</div>

One more argument in favor of my position:

When I import from `starknet::storage`, I import  
`use core::starknet::storage::{StorageMapReadAccess, StorageMapWriteAccess, Map}`

Why `StorageMapRead` and `StorageMapWrite`, but only `Map` ?

To keep the API consistent, either rename it MapRead, MapWrite and Map, or StorageMapRead, StorageMapWrite and StorageMap.

---

<div class="post-metadata">

**Author:** ![orizi](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/orizi/32/85203_2.png) [@orizi](https://community.starknet.io/u/orizi)\
**Post date:** [July 31, 2024, 2:41pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/14 "2024-07-31T14:41:55Z")

</div>

Since the usage of the traits is not in the structs where i would prefer in general a short name, but in the above usages.  
Having long name for traits is much less of a hassle than for types (since used by `.` and not with full name in normal context).

---

<div class="post-metadata">

**Author:** ![eni](https://avatars.discourse-cdn.com/v4/letter/e/a87d85/32.png) [@eni](https://community.starknet.io/u/eni)\
**Post date:** [August 27, 2024, 4:59pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/15 "2024-08-27T16:59:06Z")

</div>

After seeing a lot of people confused by the `Vec` and `Map` types (not understanding that they’re storage-only types, and trying to use it like an Array) I still stand by my point that explicit naming would have avoided all that.

I actually looked at other languages, and Sway defines `StorageMap` and `StorageVec` types that are explicitly used for storage

---

<div class="post-metadata">

**Author:** ![remybar](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/remybar/32/85292_2.png) [@remybar](https://community.starknet.io/u/remybar)\
**Post date:** [September 5, 2024, 12:18pm UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/16 "2024-09-05T12:18:44Z")

</div>

I agree with @eni about `Vec`/`Map` vs `StorageArray`/`StorageMap` especially because `Vec`/`Map` have some limitations/constraints directly due to the fact that they are used for storage only (for example, at the moment, we cannot remove items from a `Vec` or change its length).

That means we will never use a `Vec`/`Map` as we use in-memory vectors/maps in general.

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [September 11, 2024, 7:29am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/17 "2024-09-11T07:29:11Z")

</div>

+1 for Eni’s remark!

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [September 25, 2024, 7:23am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/18 "2024-09-25T07:23:56Z")

</div>

We can introduce the StorageMap/StorageVec aliases so that existing code doesn’t break, but WDYT about changing the public examples to refer to `Map` explicitly, i.e. instead of

`use starknet::storage::Map`

Write

`use starknet::storage`

and then refer to `Map` or `Vec` via `storage::Vec` or `storage::Map`? Won’t this resolve most of the confusion?

---

<div class="post-metadata">

**Author:** ![FilipLaurentiu](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/filiplaurentiu/32/205_2.png) [@FilipLaurentiu](https://community.starknet.io/u/FilipLaurentiu)\
**Post date:** [September 25, 2024, 9:25am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/19 "2024-09-25T09:25:41Z")

</div>

Why is Rescue hash function not used in Starknet ?

---

<div class="post-metadata">

**Author:** ![FeedTheFed](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/feedthefed/32/72981_2.png) [@FeedTheFed](https://community.starknet.io/u/FeedTheFed)\
**Post date:** [September 25, 2024, 10:49am UTC](https://community.starknet.io/t/cairo-v2-7-0-is-coming/114362/20 "2024-09-25T10:49:48Z")

</div>

We only have builtins for Pedersen, Poseidon, and Keccak. Perhaps the new prover will pave the road for more efficient hashes, and down the line we can replace the hashes used when computing storage addresses.
