use codec::{Compact, Decode, Encode};
use sp_runtime::{traits::Block as BlockT, StateVersion};
use std::{
fs,
path::{Path, PathBuf},
};
use crate::Result;
pub(crate) const DEFAULT_WS_ENDPOINT: &str = "wss://try-runtime.polkadot.io:443";
pub(crate) type SnapshotVersion = Compact<u16>;
pub(crate) const SNAPSHOT_VERSION: SnapshotVersion = Compact(4);
#[derive(Clone)]
pub enum Mode<H> {
Online(OnlineConfig<H>),
Offline(OfflineConfig),
OfflineOrElseOnline(OfflineConfig, OnlineConfig<H>),
}
impl<H> Default for Mode<H> {
fn default() -> Self {
Mode::Online(OnlineConfig::default())
}
}
#[derive(Clone)]
pub struct OfflineConfig {
pub state_snapshot: SnapshotConfig,
}
#[derive(Clone)]
pub struct OnlineConfig<H> {
pub at: Option<H>,
pub state_snapshot: Option<SnapshotConfig>,
pub pallets: Vec<String>,
pub transport_uris: Vec<String>,
pub child_trie: bool,
pub hashed_prefixes: Vec<Vec<u8>>,
pub hashed_keys: Vec<Vec<u8>>,
}
impl<H: Clone> OnlineConfig<H> {
pub(crate) fn at_expected(&self) -> H {
self.at.clone().expect("block at must be initialized; qed")
}
}
impl<H> Default for OnlineConfig<H> {
fn default() -> Self {
Self {
transport_uris: vec![DEFAULT_WS_ENDPOINT.to_owned()],
child_trie: true,
at: None,
state_snapshot: None,
pallets: Default::default(),
hashed_keys: Default::default(),
hashed_prefixes: Default::default(),
}
}
}
impl<H> From<String> for OnlineConfig<H> {
fn from(uri: String) -> Self {
Self { transport_uris: vec![uri], ..Default::default() }
}
}
#[derive(Clone)]
pub struct SnapshotConfig {
pub path: PathBuf,
}
impl SnapshotConfig {
pub fn new<P: Into<PathBuf>>(path: P) -> Self {
Self { path: path.into() }
}
}
impl From<String> for SnapshotConfig {
fn from(s: String) -> Self {
Self::new(s)
}
}
impl Default for SnapshotConfig {
fn default() -> Self {
Self { path: Path::new("SNAPSHOT").into() }
}
}
#[derive(Decode, Encode)]
pub(crate) struct Snapshot<B: BlockT> {
snapshot_version: SnapshotVersion,
pub(crate) state_version: StateVersion,
pub(crate) raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
pub(crate) storage_root: B::Hash,
pub(crate) header: B::Header,
}
impl<B: BlockT> Snapshot<B> {
pub(crate) fn new(
state_version: StateVersion,
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
storage_root: B::Hash,
header: B::Header,
) -> Self {
Self {
snapshot_version: SNAPSHOT_VERSION,
state_version,
raw_storage,
storage_root,
header,
}
}
pub(crate) fn load(path: &PathBuf) -> Result<Snapshot<B>> {
let bytes = fs::read(path).map_err(|_| "fs::read failed.")?;
let snapshot_version = SnapshotVersion::decode(&mut &*bytes)
.map_err(|_| "Failed to decode snapshot version")?;
if snapshot_version != SNAPSHOT_VERSION {
return Err("Unsupported snapshot version detected. Please create a new snapshot.");
}
Decode::decode(&mut &*bytes).map_err(|_| "Decode failed")
}
}