code-substitute: Switch from block_hash to block_number (#10600)

* code-substitute: Switch from `block_hash` to `block_number`

This will make it easier for light clients to work with the code-substitute.

For more information on this see: https://github.com/paritytech/substrate/issues/10589

Closes: https://github.com/paritytech/substrate/issues/10589

* FMT

* Update client/service/src/client/wasm_substitutes.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update client/service/src/builder.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2022-01-09 20:48:24 +01:00
committed by GitHub
parent 03a7738ed8
commit 3093bed933
4 changed files with 20 additions and 50 deletions
@@ -176,10 +176,10 @@ struct ClientSpec<E> {
#[serde(skip_serializing)]
#[allow(unused)]
genesis: serde::de::IgnoredAny,
/// Mapping from `block_hash` to `wasm_code`.
/// Mapping from `block_number` to `wasm_code`.
///
/// The given `wasm_code` will be used to substitute the on-chain wasm code from the given
/// block hash onwards.
/// The given `wasm_code` will be used to substitute the on-chain wasm code starting with the
/// given block number until the `spec_version` on chain changes.
#[serde(default)]
code_substitutes: BTreeMap<String, Bytes>,
}
+8 -8
View File
@@ -57,7 +57,7 @@ use sp_core::traits::{CodeExecutor, SpawnNamed};
use sp_keystore::{CryptoStore, SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, BlockIdTo, Zero},
traits::{Block as BlockT, BlockIdTo, NumberFor, Zero},
BuildStorage,
};
use std::{str::FromStr, sync::Arc, time::SystemTime};
@@ -227,7 +227,6 @@ pub fn new_full_client<TBl, TRtApi, TExec>(
where
TBl: BlockT,
TExec: CodeExecutor + RuntimeVersionOf + Clone,
TBl::Hash: FromStr,
{
new_full_parts(config, telemetry, executor).map(|parts| parts.0)
}
@@ -241,7 +240,6 @@ pub fn new_full_parts<TBl, TRtApi, TExec>(
where
TBl: BlockT,
TExec: CodeExecutor + RuntimeVersionOf + Clone,
TBl::Hash: FromStr,
{
let keystore_container = KeystoreContainer::new(&config.keystore)?;
@@ -281,14 +279,16 @@ where
.chain_spec
.code_substitutes()
.into_iter()
.map(|(h, c)| {
let hash = TBl::Hash::from_str(&h).map_err(|_| {
.map(|(n, c)| {
let number = NumberFor::<TBl>::from_str(&n).map_err(|_| {
Error::Application(Box::from(format!(
"Failed to parse `{}` as block hash for code substitutes.",
h
"Failed to parse `{}` as block number for code substitutes. \
In an old version the key for code substitute was a block hash. \
Please update the chain spec to a version that is compatible with your node.",
n
)))
})?;
Ok((hash, c))
Ok((number, c))
})
.collect::<Result<std::collections::HashMap<_, _>, Error>>()?;
@@ -194,7 +194,7 @@ pub struct ClientConfig<Block: BlockT> {
pub no_genesis: bool,
/// Map of WASM runtime substitute starting at the child of the given block until the runtime
/// version doesn't match anymore.
pub wasm_runtime_substitutes: HashMap<Block::Hash, Vec<u8>>,
pub wasm_runtime_substitutes: HashMap<NumberFor<Block>, Vec<u8>>,
}
impl<Block: BlockT> Default for ClientConfig<Block> {
@@ -18,7 +18,6 @@
//! # WASM substitutes
use parking_lot::RwLock;
use sc_client_api::backend;
use sc_executor::RuntimeVersionOf;
use sp_blockchain::{HeaderBackend, Result};
@@ -40,21 +39,14 @@ use std::{
struct WasmSubstitute<Block: BlockT> {
code: Vec<u8>,
hash: Vec<u8>,
/// The hash of the block from that on we should use the substitute.
block_hash: Block::Hash,
/// The block number of `block_hash`. If `None`, the block is still unknown.
block_number: RwLock<Option<NumberFor<Block>>>,
/// The block number on which we should start using the substitute.
block_number: NumberFor<Block>,
}
impl<Block: BlockT> WasmSubstitute<Block> {
fn new(
code: Vec<u8>,
block_hash: Block::Hash,
backend: &impl backend::Backend<Block>,
) -> Result<Self> {
let block_number = RwLock::new(backend.blockchain().number(block_hash)?);
fn new(code: Vec<u8>, block_number: NumberFor<Block>) -> Self {
let hash = make_hash(&code);
Ok(Self { code, hash, block_hash, block_number })
Self { code, hash, block_number }
}
fn runtime_code(&self, heap_pages: Option<u64>) -> RuntimeCode {
@@ -63,32 +55,10 @@ impl<Block: BlockT> WasmSubstitute<Block> {
/// Returns `true` when the substitute matches for the given `block_id`.
fn matches(&self, block_id: &BlockId<Block>, backend: &impl backend::Backend<Block>) -> bool {
let block_number = *self.block_number.read();
let block_number = if let Some(block_number) = block_number {
block_number
} else {
let block_number = match backend.blockchain().number(self.block_hash) {
Ok(Some(n)) => n,
// still unknown
Ok(None) => return false,
Err(e) => {
log::debug!(
target: "wasm_substitutes",
"Failed to get block number for block hash {:?}: {:?}",
self.block_hash,
e,
);
return false
},
};
*self.block_number.write() = Some(block_number);
block_number
};
let requested_block_number =
backend.blockchain().block_number_from_id(&block_id).ok().flatten();
Some(block_number) <= requested_block_number
Some(self.block_number) <= requested_block_number
}
}
@@ -145,14 +115,14 @@ where
{
/// Create a new instance.
pub fn new(
substitutes: HashMap<Block::Hash, Vec<u8>>,
substitutes: HashMap<NumberFor<Block>, Vec<u8>>,
executor: Executor,
backend: Arc<Backend>,
) -> Result<Self> {
let substitutes = substitutes
.into_iter()
.map(|(parent_block_hash, code)| {
let substitute = WasmSubstitute::new(code, parent_block_hash, &*backend)?;
.map(|(block_number, code)| {
let substitute = WasmSubstitute::new(code, block_number);
let version = Self::runtime_version(&executor, &substitute)?;
Ok((version.spec_version, substitute))
})