diff --git a/docs/ADR/0024-rust-sdk-storage-api.md b/docs/ADR/0024-rust-sdk-storage-api.md new file mode 100644 index 0000000..b84eaae --- /dev/null +++ b/docs/ADR/0024-rust-sdk-storage-api.md @@ -0,0 +1,139 @@ +# ADR_0024: Rust SDK storage API + +## Date + +Decision date: YYYY-MM-DD +Last status update: 2025-10-01 + +## Status + +- [ ] Proposed +- [ ] Accepted +- [ ] Deprecated +- [ ] Superseded + +### Implementation Status + +- [ ] Planned +- [ ] In Development +- [ ] Implemented +- [ ] Verified +- [ ] Discontinued + +## People + +### Author/Decision Owner + +Alisher Khassanov, [@khssnv](https://github.com/khssnv). + +### Consulted + +- Sviatoslav Alekseev, [@zotho](https://github.com/zotho). + +### Informed + +- [ ] Alex Vyatkin, [@actinfer](https://github.com/actinfer). +- [ ] Alexander Lygin, [@alexlygin](https://github.com/AlexLgn). + +## Decision + +We will add an API for on-chain storage. It will improve storage operations ergonomics. + +## Context + +## Options + +Common properties: + +- Automatic key generation by default. Optional user-defined key. + +### Option 1: TODO + +### Option 2: `qf-polkavm-sdk@v0.1.0::safe_api` + +Storage operations with SCALE codec serialization. + +**Rejected because:** + +- Insufficient encapsulation. Similar operations already available in `pallet-revive`'s API'. +- Intended for adding API safety. Irrelevant for already safe API of the `pallet-revive`. + +**Rejected despite:** + +- Automatic SCALE encoding/decoding. +- Simplified `StorageCell` interface. + +#### Public API + +```rust +// Load user data from contract input +pub fn load_data() -> Result + +// Load value from storage by key +pub fn load(key: &StorageKey) -> Result, LoadError> + +// Save value to storage with key +pub fn save(value: &T, key: &StorageKey) -> Result<(), SaveError> + +// Convert string to storage key +pub fn try_into_key(s: &str) -> Result + +// Storage cell abstraction +struct StorageCell { + pub data: T, + pub storage_key: StorageKey, +} + +impl StorageCell { + pub fn load_from_key(storage_key: K) -> Result, LoadError> + pub fn load(&self) -> Result, LoadError> + pub fn save(&self) -> Result<(), SaveError> +} +``` + +### Option 3: REST-like + +Focus on resources and operations on them. +On-chain storage is accessible through an object (similar to an endpoint) with a given set of operations (similar to HTTP verbs). +Could look familiar to frontend engineers. + +```rust +use sdk::storage; + +struct StudentId(u32); +struct Student { + name: String +} + +let alice = Student { name: "Alice".to_string() }; +let id: StudentId = storage::post(alice); + +let mut bob = storage::get(id); + +bob.name = "Bob".to_string(); +storage::put(id, &bob); +``` + +### Option 4: GraphQL-like + +GraphQL ideas: schema-first, selection-driven i/o, mutations, partial errors, subscriptions. +Could look familiar to frontend engineers. + +**Rejected because**: + +- Core ideas of the approach address another set of problems and irrelevant for smart contracts case. + +### Option 5: CRUD-like + +Could look familiar to backend engineers. + +### Option 6: Substrate-like + +The storage layout of the smart contract is defined by a set of structs annotated with a macro that makes them the interface to the on-chain storage. + +## References + +1. Rust API Guidelines, . +1. Elegant Library APIs in Rust, +1. Pragmatic Rust Guidelines, +1. GraphQL Core Concepts, .