Skip to content

Commit

Permalink
developer docs: document how get_storage_at works in db (#234)
Browse files Browse the repository at this point in the history
Co-authored-by: antiyro <[email protected]>
  • Loading branch information
cchudant and antiyro authored Sep 6, 2024
1 parent fc44980 commit 002a09b
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Next release

- code docs: documented how get_storage_at is implemented
- fix: L1 rpc <=> network mismatch
- feat: rpc versioning
- feat: bumping Starknet version from v0.13.2 to Starknet v0.13.2.1
Expand Down
28 changes: 28 additions & 0 deletions crates/client/db/docs/flat_storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Key value flat storage

We are interested in the operation `get_storage_at(block_id, contract_address, storage_key) -> value` here.
Bonsai-trie does not have an history of the key-values, it only has a flat storage for the latest state.
We may want to remove that flat storage from bonsai-trie as it's not used and we don't plan on using it.

Instead, we have implemented our own optimized lookup, which is implemented with a column that looks like this:

![schema flat_storage](./flat_storage.png)

The trick here is to rely on the fact that rocksdb columns are sorted trees.
The rocksdb `get` operation does not allow getting the value of (contract_1, key_1) at block 15 here, because
the key has not been modified at that block.
Instead, we use rocksdb iterators.

![schema flat_storage_iterator](./flat_storage_iterator.png)

This allows us to get the most recent value for a (contract, key) at that block, by using a single rocksdb lookup.

In addition, we also set up a [rocksdb prefix extractor](https://github.com/facebook/rocksdb/wiki/Prefix-Seek) for
that column, so that rocksdb can know
to treat the `<contract> || <key>` part differently from the block_n part, which allows optimisations.

## Other columns

We also use this exact technique to store contract class hash history and contract nonce history - so that we're
able to quickly get the nonce/class hash of a
contract at a specific block.
Binary file added crates/client/db/docs/flat_storage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added crates/client/db/docs/flat_storage_iterator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 1 addition & 7 deletions crates/client/db/src/contract_db.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
//! Contract history values are stored using a fixed prefix extractor in rocksdb.
//!
//! This means that we can access the last value of a history column (e.g. the last class hash of a contract)
//! from a any block in the blockchain by seeking to it using a rocksdb iterator, setting iteration to reverse mode,
//! and getting the next value.
//!
//! Insertion is batched and done in parallel using rayon: this is not intended for use in the RPCs.
#![doc = include_str!("../docs/flat_storage.md")]

use std::sync::Arc;

Expand Down

0 comments on commit 002a09b

Please sign in to comment.