SnapshotItem
A SnapshotItem
is a container that contains a single value that is potentially stored in some
storage identified by a unique key - just like an Item
. It's worth familiarizing yourself with
the Item
type first, as everything we talked about there is applicable to SnapshotItem
.
On top of that, SnapshotItem
makes it a little simpler to maintain a history of values at various
block heights. This involves saving "checkpoints" at some points in time - just how that is done is
decided by the Strategy
(opens in a new tab) type passed to the SnapshotItem
constructor.
Strategy
There are currently 3 built-in strategies, although in the future this might be open to extension.
EveryBlock
- a checkpoint is (conceptually) added at the beginning of every block, and historical data is available for any heightNever
- there's never a checkpoint saved, and theSnapshotItem
is no different from a regularItem
in terms of features. Any call tomay_load_at_height
(opens in a new tab) will returnStdError::NotFound
Selected
- theadd_checkpoint
(opens in a new tab) method has to be called manually to add a checkpoint at the given height. Keep in mind that when callingmay_load_at_height
(opens in a new tab) later, the height has to be the same as the one passed toadd_checkpoint
(opens in a new tab). If you try to load a value at a height when no checkpoint was saved, the method will returnStdError::NotFound
(opens in a new tab).
Usage examples
Maintaining a price history
The constructor of SnapshotItem
takes 3 "namespace" arguments: - the main namespace, similar to
the Item
constructor - two additional unique namespaces, which are used to store the changelog
metadata
Let's say we want to keep a history of prices for a specific trading pair.
use cw_storage_plus::{SnapshotItem, Strategy};
let price: SnapshotItem<Decimal> = SnapshotItem::new("p", "p1", "p2", Strategy::EveryBlock);
price
.save(&mut storage, &Decimal::percent(81), env.block.height)
.unwrap();
advance_height(&mut env, 50); // fast forward 50 blocks
price
.save(&mut storage, &Decimal::percent(92), env.block.height)
.unwrap();
// Before/at the first save, the price was unknown (uninitialized state)
assert_eq!(
price
.may_load_at_height(&storage, env.block.height - 60)
.unwrap(),
None
);
assert_eq!(
price
.may_load_at_height(&storage, env.block.height - 50)
.unwrap(),
None
);
// Before/at the current block, the price was 0.81
assert_eq!(
price
.may_load_at_height(&storage, env.block.height - 49)
.unwrap(),
Some(Decimal::percent(81))
);
assert_eq!(
price
.may_load_at_height(&storage, env.block.height)
.unwrap(),
Some(Decimal::percent(81))
);
// After the current block, the price will come up as 0.92
assert_eq!(
price
.may_load_at_height(&storage, env.block.height + 1)
.unwrap(),
Some(Decimal::percent(92))
);
assert_eq!(
price
.may_load_at_height(&storage, env.block.height + 50)
.unwrap(),
Some(Decimal::percent(92))
);