diff --git a/examples/kusama_balance_transfer.rs b/examples/kusama_balance_transfer.rs index dba35b8771..d3fc44a766 100644 --- a/examples/kusama_balance_transfer.rs +++ b/examples/kusama_balance_transfer.rs @@ -29,7 +29,7 @@ async fn main() -> Result<(), Box> { let signer = PairSigner::new(AccountKeyring::Alice.pair()); let dest = AccountKeyring::Bob.to_account_id().into(); - let client = ClientBuilder::::new().build().await?; + let client = ClientBuilder::::new().build().await?; let hash = client.transfer(&signer, &dest, 10_000).await?; println!("Balance transfer extrinsic submitted: {}", hash); diff --git a/src/lib.rs b/src/lib.rs index 23a990d694..a647f0c3b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,7 @@ pub struct ClientBuilder { url: Option, client: Option, page_size: Option, + mortal_period: Option>, } impl ClientBuilder { @@ -138,6 +139,7 @@ impl ClientBuilder { url: None, client: None, page_size: None, + mortal_period: None, } } @@ -159,6 +161,12 @@ impl ClientBuilder { self } + /// Set the mortal period. Must be set if `Metadata::derive_mortal_period` results in an error. + pub fn set_mortal_period(mut self, mortal_period: u64) -> Self { + self.mortal_period = Some(Some(mortal_period)); + self + } + /// Creates a new Client. pub async fn build(self) -> Result, Error> { let client = if let Some(client) = self.client { @@ -180,7 +188,18 @@ impl ClientBuilder { ) .await; let metadata = metadata?; - let mortal_period = Some(metadata.derive_mortal_period()?); + let mortal_period = if let Some(period) = self.mortal_period { + period + } else { + match metadata.derive_mortal_period() { + Err(e) => { + log::error!("`Metadata::derive_mortal_period` failed. Set `mortal_period` prior to invoking `Client::build`."); + return Err(e.into()) + } + Ok(period) => Some(period) + } + }; + Ok(Client { rpc, genesis_hash: genesis_hash?, @@ -202,7 +221,7 @@ struct ClientSignedOptions { /// /// Substrate reference: /// https://docs.rs/sp-runtime/2.0.0/sp_runtime/generic/enum.Era.html#variant.Mortal - pub mortal_period: Option, + pub(crate) mortal_period: Option, } /// Client to interface with a substrate node. diff --git a/src/metadata.rs b/src/metadata.rs index fd25ef3e24..51c5e6cc52 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -40,15 +40,9 @@ use sp_core::storage::StorageKey; use crate::Encoded; -/// 5 min `mortal_period`in milliseconds, to be adjusted based on expected block time +/// 5 min `mortal_period` in milliseconds, to be adjusted based on expected block time pub const BASELINE_MORTAL_PERIOD: u64 = 5 * 60 * 1000; -/// Fallback `BlockHashCount` -pub const FALLBACK_BLOCK_HASH_COUNT: u64 = 2_400; - -/// Fallback expected block time in milliseconds -pub const FALLBACK_EXPECTED_BLOCK_TIME: u64 = 6_000; - /// Metadata error. #[derive(Debug, thiserror::Error)] pub enum MetadataError { @@ -85,6 +79,9 @@ pub enum MetadataError { /// Constant is not in metadata. #[error("Constant {0} not found")] ConstantNotFound(&'static str), + /// A value was 0 when a non-zero value was expected. + #[error("A value was unexpectedly 0: {0}")] + ZeroValue(&'static str), } /// Runtime metadata. @@ -175,30 +172,26 @@ impl Metadata { string } - /// Derive a default mortal period + /// Derive a mortal period pub(crate) fn derive_mortal_period(&self) -> Result { - let block_hash_count = if let Ok(system_meta) = self.module("System") { - if let Ok(count) = system_meta.constant("BlockHashCount") { - count.value::()?.into() - } else { - FALLBACK_BLOCK_HASH_COUNT - } - } else { - FALLBACK_BLOCK_HASH_COUNT - }; - let block_time = if let Ok(babe_meta) = self.module("Babe") { - if let Ok(milliseconds) = babe_meta.constant("ExpectedBlockTime") { - milliseconds.value::()? - } else { - FALLBACK_EXPECTED_BLOCK_TIME - } - } else { - FALLBACK_EXPECTED_BLOCK_TIME - }; + let block_hash_count: u64 = self + .module("System") + .and_then(|sys| sys.constant("BlockHashCount")) + .and_then(|count| count.value::()) + .map(Into::into)?; + let expected_block_time = self + .module("Babe") + .and_then(|babe| babe.constant("ExpectedBlockTime")) + .and_then(|e| e.value::())?; - Ok((BASELINE_MORTAL_PERIOD / block_time) - .next_power_of_two() - .min(block_hash_count.next_power_of_two())) + match expected_block_time { + 0 => Err(MetadataError::ZeroValue("Babe::ExpectedBlockTime")), + expected_block_time => { + Ok((BASELINE_MORTAL_PERIOD / expected_block_time) + .next_power_of_two() + .min(block_hash_count.next_power_of_two())) + } + } } }