Skip to content

Commit

Permalink
feat: store using packing optimisation
Browse files Browse the repository at this point in the history
  • Loading branch information
julio4 committed Aug 28, 2023
1 parent 3e9bbe3 commit 3f393aa
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ Summary

- [Upgradeable Contract](./ch02-01-upgradeable_contract.md)
- [Defi Vault](./ch02-02-simple_vault.md)

- [Optimisations](./ch03-00-optimisations.md)

- [Storage Optimisations](./ch03-01-store_using_packing.md)
3 changes: 3 additions & 0 deletions src/ch03-00-optimisations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Optimisations

A collection of optimisation patterns to save gas and steps.
32 changes: 32 additions & 0 deletions src/ch03-01-store_using_packing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Storage optimisation

A smart contract has a limited amount of **storage slots**. Each slot can store a single `felt252` value.
Writing to a storage slot has a cost, so we want to use as few storage slots as possible.

In Cairo, every type is derived from the `felt252` type, which uses 252 bits to store a value.
This design is quite simple, but it does have a drawback: it is not storage efficient. For example, if we want to store a `u8` value, we need to use an entire slot, even though we only need 8 bits.

## Packing

When storing multiple values, we can use a technique called **packing**. Packing is a technique that allows us to store multiple values in a single felt value. This is done by using the bits of the felt value to store multiple values.

For example, if we want to store two `u8` values, we can use the first 8 bits of the felt value to store the first `u8` value, and the last 8 bits to store the second `u8` value. This way, we can store two `u8` values in a single felt value.

Cairo provides a built-in store using packing that you can use with the `StorePacking` trait.

```rust
trait StorePacking<T, PackedT> {
fn pack(value: T) -> PackedT;
fn unpack(value: PackedT) -> T;
}
```

This allows to store the type `T` by first packing it into the type `PackedT` with the `pack` function, and then storing the `PackedT` value with it's `Store` implementation. When reading the value, we first retrieve the `PackedT` value, and then unpack it into the type `T` using the `unpack` function.

Here's an example of storing a `Time` struct with two `u8` values using the `StorePacking` trait:

```rust
{{#include ../listings/ch03-optimisations/store_using_packing/src/packing.cairo:Packing}}
```

Play with this contract in [Remix](https://remix.ethereum.org/?#activate=Starknet-cairo1-compiler&url=https://github.com/NethermindEth/StarknetByExample/blob/main/listings/ch03-optimisations/store_using_packing/src/packing.cairo).

0 comments on commit 3f393aa

Please sign in to comment.