Skip to content

Commit 426df27

Browse files
committed
storage-plus: document SnapshotItem
1 parent 52ecd6e commit 426df27

File tree

4 files changed

+115
-2
lines changed

4 files changed

+115
-2
lines changed

docs-test-gen/templates/storage.tpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ mod users {
6161
}
6262
}
6363

64+
fn advance_height(env: &mut Env, blocks: u64) {
65+
env.block.height += blocks;
66+
}
67+
6468
#[test]
6569
fn doctest() {
6670
#[allow(unused_variables, unused_mut)]
6771
let mut storage = cosmwasm_std::testing::MockStorage::new();
72+
let mut env = cosmwasm_std::testing::mock_env();
6873
6974
let users = cw_storage_plus::IndexedMap::<Addr, _, _>::new(
7075
"uu",

src/pages/cw-storage-plus/_meta.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"basics": "Basics",
33
"containers": "Containers",
4-
"snapshots": "Snapshots",
54
"multi-indexes": "Multi index collections"
65
}

src/pages/cw-storage-plus/containers/_meta.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
"item": "Item",
33
"map": "Map",
44
"deque": "Deque",
5-
"indexed-map": "IndexedMap"
5+
"indexed-map": "IndexedMap",
6+
"snapshot-item": "SnapshotItem",
7+
"snapshot-map": "SnapshotMap"
68
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
tags: ["storage-plus", "containers"]
3+
---
4+
5+
import { Callout } from "nextra/components";
6+
7+
# SnapshotItem
8+
9+
A `SnapshotItem` is a container that contains a single value that is potentially stored in some
10+
storage identified by a unique key - just like an [`Item`]. It's worth familiarizing yourself with
11+
the `Item` type first, as everything we talked about there is applicable to `SnapshotItem`.
12+
13+
On top of that, `SnapshotItem` makes it a little simpler to maintain a history of values at various
14+
block heights. This involves saving "checkpoints" at some points in time - just how that is done is
15+
decided by the [`Strategy`] type passed to the `SnapshotItem` constructor.
16+
17+
# Strategy
18+
19+
There are currently 3 built-in strategies, although in the future this might be open to extension.
20+
21+
- `EveryBlock` - a checkpoint is (conceptually) added at the beginning of every block, and
22+
historical data is available for any height
23+
- `Never` - there's never a checkpoint saved, and the `SnapshotItem` is no different from a regular
24+
`Item` in terms of features. Any call to [`may_load_at_height`] will return `StdError::NotFound`
25+
- `Selected` - the [`add_checkpoint`] method has to be called manually to add a checkpoint at the
26+
given height. Keep in mind that when calling [`may_load_at_height`] later, the height has to be
27+
the same as the one passed to [`add_checkpoint`]. If you try to load a value at a height when no
28+
checkpoint was saved, the method will return [`StdError::NotFound`].
29+
30+
## Usage examples
31+
32+
### Maintaining a price history
33+
34+
<Callout>
35+
The constructor of `SnapshotItem` takes 3 "namespace" arguments: - the main namespace, similar to
36+
the `Item` constructor - two additional unique namespaces, which are used to store the changelog
37+
metadata
38+
</Callout>
39+
40+
```rust template="storage"
41+
use cw_storage_plus::{SnapshotItem, Strategy};
42+
43+
let price: SnapshotItem<Decimal> = SnapshotItem::new("p", "p1", "p2", Strategy::EveryBlock);
44+
45+
price
46+
.save(&mut storage, &Decimal::percent(81), env.block.height)
47+
.unwrap();
48+
49+
advance_height(&mut env, 50); // fast forward 50 blocks
50+
51+
price
52+
.save(&mut storage, &Decimal::percent(92), env.block.height)
53+
.unwrap();
54+
55+
// Before/at the first save, the price was unknown (uninitialized state)
56+
assert_eq!(
57+
price
58+
.may_load_at_height(&storage, env.block.height - 60)
59+
.unwrap(),
60+
None
61+
);
62+
assert_eq!(
63+
price
64+
.may_load_at_height(&storage, env.block.height - 50)
65+
.unwrap(),
66+
None
67+
);
68+
69+
// Before/at the current block, the price was 81%
70+
assert_eq!(
71+
price
72+
.may_load_at_height(&storage, env.block.height - 49)
73+
.unwrap(),
74+
Some(Decimal::percent(81))
75+
);
76+
assert_eq!(
77+
price
78+
.may_load_at_height(&storage, env.block.height)
79+
.unwrap(),
80+
Some(Decimal::percent(81))
81+
);
82+
83+
// After the current block, the price will come up as 92%
84+
assert_eq!(
85+
price
86+
.may_load_at_height(&storage, env.block.height + 1)
87+
.unwrap(),
88+
Some(Decimal::percent(92))
89+
);
90+
assert_eq!(
91+
price
92+
.may_load_at_height(&storage, env.block.height + 50)
93+
.unwrap(),
94+
Some(Decimal::percent(92))
95+
);
96+
```
97+
98+
[`Item`]: item
99+
[`Strategy`]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/enum.Strategy.html
100+
[`add_checkpoint`]:
101+
https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.SnapshotItem.html#method.add_checkpoint
102+
[`may_load_at_height`]:
103+
https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.SnapshotItem.html#method.may_load_at_height
104+
[`StdError::NotFound`]:
105+
https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.StdError.html#variant.NotFound
106+
[`serde`]: https://serde.rs/
107+
[API docs]: https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.SnapshotItem.html

0 commit comments

Comments
 (0)