Skip to content

Commit 5f31981

Browse files
liamaharonggwpez
andauthored
remote-externalities: store block header in snapshot (#4349)
The block header is required to derive inherents for a relay chain next block, this is useful in testing environments. --------- Co-authored-by: Oliver Tale-Yazdi <[email protected]>
1 parent 9e0e5fc commit 5f31981

File tree

5 files changed

+61
-39
lines changed

5 files changed

+61
-39
lines changed

.config/lychee.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ exclude = [
3232
"https://github.com/paritytech/polkadot-sdk/substrate/frame/timestamp",
3333
"https://github.com/paritytech/substrate/frame/fast-unstake",
3434
"https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs",
35+
"https://polkadot-try-runtime-node.parity-chains.parity.io/",
3536
"https://polkadot.network/the-path-of-a-parachain-block/",
3637
"https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results",
3738
"https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html",

prdoc/pr_4349.prdoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
title: "Store Header in RemoteExt Snapshot"
2+
3+
doc:
4+
- audience: Runtime Dev
5+
description: Replaces the block hash in the RemoteExt snapshot with the block header.
6+
7+
crates:
8+
- name: frame-remote-externalities
9+
bump: major

substrate/utils/frame/remote-externalities/src/lib.rs

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use sp_core::{
3636
},
3737
};
3838
use sp_runtime::{
39-
traits::{Block as BlockT, Hash, HashingFor},
39+
traits::{Block as BlockT, HashingFor},
4040
StateVersion,
4141
};
4242
use sp_state_machine::TestExternalities;
@@ -58,37 +58,39 @@ type ChildKeyValues = Vec<(ChildInfo, Vec<KeyValue>)>;
5858
type SnapshotVersion = Compact<u16>;
5959

6060
const LOG_TARGET: &str = "remote-ext";
61-
const DEFAULT_HTTP_ENDPOINT: &str = "https://rpc.polkadot.io:443";
62-
const SNAPSHOT_VERSION: SnapshotVersion = Compact(3);
61+
const DEFAULT_HTTP_ENDPOINT: &str = "https://polkadot-try-runtime-node.parity-chains.parity.io:443";
62+
const SNAPSHOT_VERSION: SnapshotVersion = Compact(4);
6363

6464
/// The snapshot that we store on disk.
6565
#[derive(Decode, Encode)]
66-
struct Snapshot<H> {
66+
struct Snapshot<B: BlockT> {
6767
snapshot_version: SnapshotVersion,
6868
state_version: StateVersion,
69-
block_hash: H,
7069
// <Vec<Key, (Value, MemoryDbRefCount)>>
7170
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
72-
storage_root: H,
71+
// The storage root of the state. This may vary from the storage root in the header, if not the
72+
// entire state was fetched.
73+
storage_root: B::Hash,
74+
header: B::Header,
7375
}
7476

75-
impl<H: Decode> Snapshot<H> {
77+
impl<B: BlockT> Snapshot<B> {
7678
pub fn new(
7779
state_version: StateVersion,
78-
block_hash: H,
7980
raw_storage: Vec<(Vec<u8>, (Vec<u8>, i32))>,
80-
storage_root: H,
81+
storage_root: B::Hash,
82+
header: B::Header,
8183
) -> Self {
8284
Self {
8385
snapshot_version: SNAPSHOT_VERSION,
8486
state_version,
85-
block_hash,
8687
raw_storage,
8788
storage_root,
89+
header,
8890
}
8991
}
9092

91-
fn load(path: &PathBuf) -> Result<Snapshot<H>, &'static str> {
93+
fn load(path: &PathBuf) -> Result<Snapshot<B>, &'static str> {
9294
let bytes = fs::read(path).map_err(|_| "fs::read failed.")?;
9395
// The first item in the SCALE encoded struct bytes is the snapshot version. We decode and
9496
// check that first, before proceeding to decode the rest of the snapshot.
@@ -105,21 +107,21 @@ impl<H: Decode> Snapshot<H> {
105107

106108
/// An externalities that acts exactly the same as [`sp_io::TestExternalities`] but has a few extra
107109
/// bits and pieces to it, and can be loaded remotely.
108-
pub struct RemoteExternalities<H: Hash> {
110+
pub struct RemoteExternalities<B: BlockT> {
109111
/// The inner externalities.
110-
pub inner_ext: TestExternalities<H>,
111-
/// The block hash with which we created this externality env.
112-
pub block_hash: H::Out,
112+
pub inner_ext: TestExternalities<HashingFor<B>>,
113+
/// The block header which we created this externality env.
114+
pub header: B::Header,
113115
}
114116

115-
impl<H: Hash> Deref for RemoteExternalities<H> {
116-
type Target = TestExternalities<H>;
117+
impl<B: BlockT> Deref for RemoteExternalities<B> {
118+
type Target = TestExternalities<HashingFor<B>>;
117119
fn deref(&self) -> &Self::Target {
118120
&self.inner_ext
119121
}
120122
}
121123

122-
impl<H: Hash> DerefMut for RemoteExternalities<H> {
124+
impl<B: BlockT> DerefMut for RemoteExternalities<B> {
123125
fn deref_mut(&mut self) -> &mut Self::Target {
124126
&mut self.inner_ext
125127
}
@@ -859,7 +861,7 @@ where
859861
}
860862
}
861863

862-
impl<B: BlockT + DeserializeOwned> Builder<B>
864+
impl<B: BlockT> Builder<B>
863865
where
864866
B::Hash: DeserializeOwned,
865867
B::Header: DeserializeOwned,
@@ -1030,6 +1032,21 @@ where
10301032
Ok(())
10311033
}
10321034

1035+
async fn load_header(&self) -> Result<B::Header, &'static str> {
1036+
let retry_strategy =
1037+
FixedInterval::new(Self::KEYS_PAGE_RETRY_INTERVAL).take(Self::MAX_RETRIES);
1038+
let get_header_closure = || {
1039+
ChainApi::<(), _, B::Header, ()>::header(
1040+
self.as_online().rpc_client(),
1041+
Some(self.as_online().at_expected()),
1042+
)
1043+
};
1044+
Retry::spawn(retry_strategy, get_header_closure)
1045+
.await
1046+
.map_err(|_| "Failed to fetch header for block from network")?
1047+
.ok_or("Network returned None block header")
1048+
}
1049+
10331050
/// Load the data from a remote server. The main code path is calling into `load_top_remote` and
10341051
/// `load_child_remote`.
10351052
///
@@ -1058,13 +1075,11 @@ where
10581075
// If we need to save a snapshot, save the raw storage and root hash to the snapshot.
10591076
if let Some(path) = self.as_online().state_snapshot.clone().map(|c| c.path) {
10601077
let (raw_storage, storage_root) = pending_ext.into_raw_snapshot();
1061-
let snapshot = Snapshot::<B::Hash>::new(
1078+
let snapshot = Snapshot::<B>::new(
10621079
state_version,
1063-
self.as_online()
1064-
.at
1065-
.expect("set to `Some` in `init_remote_client`; must be called before; qed"),
10661080
raw_storage.clone(),
10671081
storage_root,
1082+
self.load_header().await?,
10681083
);
10691084
let encoded = snapshot.encode();
10701085
log::info!(
@@ -1086,22 +1101,21 @@ where
10861101
Ok(pending_ext)
10871102
}
10881103

1089-
async fn do_load_remote(&mut self) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
1104+
async fn do_load_remote(&mut self) -> Result<RemoteExternalities<B>, &'static str> {
10901105
self.init_remote_client().await?;
1091-
let block_hash = self.as_online().at_expected();
10921106
let inner_ext = self.load_remote_and_maybe_save().await?;
1093-
Ok(RemoteExternalities { block_hash, inner_ext })
1107+
Ok(RemoteExternalities { header: self.load_header().await?, inner_ext })
10941108
}
10951109

10961110
fn do_load_offline(
10971111
&mut self,
10981112
config: OfflineConfig,
1099-
) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
1113+
) -> Result<RemoteExternalities<B>, &'static str> {
11001114
let mut sp = Spinner::with_timer(Spinners::Dots, "Loading snapshot...".into());
11011115
let start = Instant::now();
11021116
info!(target: LOG_TARGET, "Loading snapshot from {:?}", &config.state_snapshot.path);
1103-
let Snapshot { snapshot_version: _, block_hash, state_version, raw_storage, storage_root } =
1104-
Snapshot::<B::Hash>::load(&config.state_snapshot.path)?;
1117+
let Snapshot { snapshot_version: _, header, state_version, raw_storage, storage_root } =
1118+
Snapshot::<B>::load(&config.state_snapshot.path)?;
11051119

11061120
let inner_ext = TestExternalities::from_raw_snapshot(
11071121
raw_storage,
@@ -1110,12 +1124,10 @@ where
11101124
);
11111125
sp.stop_with_message(format!("✅ Loaded snapshot ({:.2}s)", start.elapsed().as_secs_f32()));
11121126

1113-
Ok(RemoteExternalities { inner_ext, block_hash })
1127+
Ok(RemoteExternalities { inner_ext, header })
11141128
}
11151129

1116-
pub(crate) async fn pre_build(
1117-
mut self,
1118-
) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
1130+
pub(crate) async fn pre_build(mut self) -> Result<RemoteExternalities<B>, &'static str> {
11191131
let mut ext = match self.mode.clone() {
11201132
Mode::Offline(config) => self.do_load_offline(config)?,
11211133
Mode::Online(_) => self.do_load_remote().await?,
@@ -1154,7 +1166,7 @@ where
11541166
}
11551167

11561168
// Public methods
1157-
impl<B: BlockT + DeserializeOwned> Builder<B>
1169+
impl<B: BlockT> Builder<B>
11581170
where
11591171
B::Hash: DeserializeOwned,
11601172
B::Header: DeserializeOwned,
@@ -1191,7 +1203,7 @@ where
11911203
self
11921204
}
11931205

1194-
pub async fn build(self) -> Result<RemoteExternalities<HashingFor<B>>, &'static str> {
1206+
pub async fn build(self) -> Result<RemoteExternalities<B>, &'static str> {
11951207
let mut ext = self.pre_build().await?;
11961208
ext.commit_all().unwrap();
11971209

@@ -1226,7 +1238,7 @@ mod tests {
12261238
init_logger();
12271239
Builder::<Block>::new()
12281240
.mode(Mode::Offline(OfflineConfig {
1229-
state_snapshot: SnapshotConfig::new("test_data/proxy_test"),
1241+
state_snapshot: SnapshotConfig::new("test_data/test.snap"),
12301242
}))
12311243
.build()
12321244
.await
@@ -1241,7 +1253,7 @@ mod tests {
12411253
// get the first key from the snapshot file.
12421254
let some_key = Builder::<Block>::new()
12431255
.mode(Mode::Offline(OfflineConfig {
1244-
state_snapshot: SnapshotConfig::new("test_data/proxy_test"),
1256+
state_snapshot: SnapshotConfig::new("test_data/test.snap"),
12451257
}))
12461258
.build()
12471259
.await
@@ -1255,7 +1267,7 @@ mod tests {
12551267

12561268
Builder::<Block>::new()
12571269
.mode(Mode::Offline(OfflineConfig {
1258-
state_snapshot: SnapshotConfig::new("test_data/proxy_test"),
1270+
state_snapshot: SnapshotConfig::new("test_data/test.snap"),
12591271
}))
12601272
.blacklist_hashed_key(&some_key)
12611273
.build()
@@ -1341,7 +1353,7 @@ mod remote_tests {
13411353
.await
13421354
.unwrap();
13431355

1344-
assert_eq!(ext.block_hash, cached_ext.block_hash);
1356+
assert_eq!(ext.header.hash(), cached_ext.header.hash());
13451357
}
13461358

13471359
#[tokio::test]
-236 KB
Binary file not shown.
1.31 MB
Binary file not shown.

0 commit comments

Comments
 (0)