diff --git a/src/extrinsic/mod.rs b/src/extrinsic/mod.rs index d4c175792a..c3b90feac0 100644 --- a/src/extrinsic/mod.rs +++ b/src/extrinsic/mod.rs @@ -17,6 +17,7 @@ //! Create signed or unsigned extrinsics. mod extra; +mod mortal_period; mod signer; pub use self::{ @@ -25,6 +26,7 @@ pub use self::{ Extra, SignedExtra, }, + mortal_period::derive_mortal_period, signer::{ PairSigner, Signer, @@ -44,9 +46,6 @@ use crate::{ Error, }; -/// A reasonable default for `mortal_period` -pub const DEFAULT_MORTAL_PERIOD: u64 = 64; - /// UncheckedExtrinsic type. pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< ::Address, diff --git a/src/extrinsic/mortal_period.rs b/src/extrinsic/mortal_period.rs new file mode 100644 index 0000000000..115705438a --- /dev/null +++ b/src/extrinsic/mortal_period.rs @@ -0,0 +1,55 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of substrate-subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with substrate-subxt. If not, see . + +use crate::{ + Error, + Metadata, +}; + +/// 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` of 2,400 blocks +pub const FALLBACK_BLOCK_HASH_COUNT: u64 = 2_400; + +/// Fallback expected block time of 6,000 milliseconds +pub const FALLBACK_EXPECTED_BLOCK_TIME: u64 = 6_000; + +/// Derive a default mortal period based on a chain's metadata +pub fn derive_mortal_period(metadata: &Metadata) -> Result { + let block_hash_count = if let Ok(system_meta) = metadata.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) = metadata.module("Babe") { + if let Ok(milliseconds) = babe_meta.constant("ExpectedBlockTime") { + milliseconds.value::()? + } else { + FALLBACK_EXPECTED_BLOCK_TIME + } + } else { + FALLBACK_EXPECTED_BLOCK_TIME + }; + + Ok((BASELINE_MORTAL_PERIOD / block_time) + .next_power_of_two() + .min(block_hash_count.next_power_of_two())) +} diff --git a/src/lib.rs b/src/lib.rs index b775680af3..b69fead1ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,7 @@ pub use sp_core; pub use sp_runtime; use codec::Decode; +use core::convert::Into; use futures::future; use jsonrpsee::client::Subscription; use sp_core::{ @@ -88,11 +89,11 @@ pub use crate::{ RawEvent, }, extrinsic::{ + derive_mortal_period, PairSigner, SignedExtra, Signer, UncheckedExtrinsic, - DEFAULT_MORTAL_PERIOD, }, frame::*, metadata::{ @@ -179,17 +180,17 @@ impl ClientBuilder { rpc.system_properties(), ) .await; + let metadata = metadata?; + let mortal_period = derive_mortal_period(&metadata).ok(); Ok(Client { rpc, genesis_hash: genesis_hash?, - metadata: metadata?, + metadata, properties: properties.unwrap_or_else(|_| Default::default()), runtime_version: runtime_version?, _marker: PhantomData, page_size: self.page_size.unwrap_or(10), - signed_options: ClientSignedOptions { - mortal_period: Some(DEFAULT_MORTAL_PERIOD), - }, + signed_options: ClientSignedOptions { mortal_period }, }) } }