Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add store/introduction #1726

Merged
merged 2 commits into from
Oct 11, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions next-docs/pages/store/introduction.mdx
Original file line number Diff line number Diff line change
@@ -1 +1,66 @@
# Introduction

`Store` is an alternative to Solidity's storage engine.
It enforces a data model that can be mapped directly to a relational database,
enables [automatic indexing](../services/indexer) by emitting events on each storage operation,
and [packs data more tightly](./encoding) than Solidity's storage engine.
It also allows external contract storage to be read onchain without being limited
by existing `view` functions and [without a new opcode](https://eips.ethereum.org/EIPS/eip-2330).

## Data model

Each piece of data in `Store` is stored as a _record_ in a _table_.
You can think of tables in two ways, either as a relational database,
or as a key-value store.

- Each table is identified by a unique `ResourceId tableId`.
- Each record in a table is identified by a unique `bytes32[] keyTuple`.
You can think of the key tuple as a composite key in a relational database,
or as a nested mapping in a key-value store.
- Each table has a `ValueSchema` that defines the types of data stored in the table.
You can think of the value schema as the column types in a table in a relational database,
or the type of structs stored in a key-value store.

## Reading and writing data

The [`StoreCore`](./reference) library implements low level methods for reading and writing data
in a `Store` contract and the [`IStore`](./reference) interface exposes some of these methods
to external callers.

Due to the lack of generics in Solidity, the only way to allow functions act on
data of different types is to cast the data to raw "untyped" `bytes`.
To improve the developer experience, `Store` automatically [generates
a library for each table](./table-libraries) which acts as a type wrapper.
These libraries provide getter and setter functions with strong types
for the table's keys and values, encode them using the [Store encoding](./encoding)
before passing them to the Store, and decode them before passing them back to the user.

```solidity
// Example: reading and writing data via table libraries

// The Position table library turns the typed
// address parameter into a bytes32[] keyTuple,
// and decodes the return value to (uint32, uint32).
(uint32 x, uint32 y) = Position.get(msg.sender);

// The Position table library turns the typed
// address parameter into a bytes32[] keyTyple,
// and encodes the (uint32,uint32) tuple into
// a tightly packed bytes blob.
Position.set(msg.sender, x, y);
```

## Schema definition at runtime

Unlike Solidity's storage engine,
which requires the storage types to be known at compile time,
`Store` allows new tables with new schemas to be registered after the `Store` contract has been deployed.
This allows advanced use-cases like the [`World` protocol](../world/introduction).

## Automatic indexing

`Store` automatically emits events on every write operation,
including when a new table is registered in the `Store` at runtime.
These events allow [automatic indexers](../services/indexer) to replicate the onchain state of each
table in each `Store` contract in a relational database for offchain use,
without the need for custom integrations.