default or from implementation for mortality

This commit is contained in:
Tadeo hepperle
2024-02-16 17:33:40 +01:00
parent 5447035716
commit bd0539a259
7 changed files with 172 additions and 7 deletions
+2
View File
@@ -167,3 +167,5 @@ where
};
Ok(account_nonce)
}
pub struct LatestBlockHeader {}
+72
View File
@@ -0,0 +1,72 @@
// use crate::{backend::Backend, Config};
// use super::OfflineClientT;
use crate::{Config, Error, OfflineClient, OnlineClient};
use core::future::Future;
use super::OfflineClientT;
pub type FetchBlockHeader<Header> =
Box<dyn Future<Output = Result<Header, Error>> + Send + 'static>;
/// An object-safe trait abstracting over capabilities of offline and online-clients.
///
/// Implemented by [`subxt::OfflineClient`], [`subxt::OnlineClient`] and [`subxt::LightClient`] the like.
pub trait ClientCapabilities<T: Config> {
fn latest_block_header(&self) -> Option<FetchBlockHeader<T::Header>>
where
T::Header: Clone;
}
impl<T: Config> ClientCapabilities<T> for OfflineClient<T> {
fn latest_block_header(&self) -> Option<FetchBlockHeader<T::Header>>
where
T::Header: Clone,
{
None
}
}
impl<T: Config> ClientCapabilities<T> for OnlineClient<T> {
fn latest_block_header(&self) -> Option<FetchBlockHeader<T::Header>>
where
T::Header: Clone,
{
let client = self.clone();
Some(Box::new(async move {
let block = client.blocks().at_latest().await?;
let header: T::Header = block.header().clone();
Ok(header)
}))
}
}
crate::macros::cfg_unstable_light_client! {
use super::LightClient;
impl<T: Config> ClientCapabilities<T> for LightClient<T> {
fn latest_block_header(&self) -> Option<FetchBlockHeader<T::Header>>
where
T::Header: Clone,
{
let client = self.clone();
Some(Box::new(async move {
let block = client.blocks().at_latest().await?;
let header: T::Header = block.header().clone();
Ok(header)
}))
}
}
}
#[cfg(test)]
mod tests {
use super::ClientCapabilities;
use crate::PolkadotConfig;
use core::panic;
fn is_object_safe(client: Box<dyn ClientCapabilities<PolkadotConfig>>) {
_ = client.latest_block_header();
unreachable!("Do not call this function, it just needs to compile.")
}
}
+1
View File
@@ -8,6 +8,7 @@
//! require network access. The [`OnlineClient`] requires network
//! access.
mod client_capabilities;
mod offline_client;
mod online_client;
+54
View File
@@ -79,3 +79,57 @@ pub trait ExtrinsicParamsEncoder: 'static {
/// signing it, meaning the client and node must agree on their values.
fn encode_additional_to(&self, _v: &mut Vec<u8>) {}
}
/// Like the `From<T>` trait, if value is Some(_), but it lets us circumvent the orphan rule, because we want to implement
/// `DefaultOrFrom<Header>` for `()`, such that DefaultOrFrom<Header> is implemented by `((),(),(),CheckMortalityParams)`, if `CheckMortalityParams` implements `DefaultFrom<Header>`
pub trait DefaultOrFrom<T> {
/// If value
fn default_or_from(value: Option<&T>) -> Self;
}
impl<T> DefaultOrFrom<T> for () {
fn default_or_from(_value: Option<&T>) -> () {}
}
macro_rules! impl_default_from_tuples {
($($ident:ident),+) => {
// We do some magic when the tuple is wrapped in AnyOf. We
// look at the metadata, and use this to select and make use of only the extensions
// that we actually need for the chain we're dealing with.
impl <T, $($ident),+> DefaultOrFrom<T> for ($($ident,)+)
where
$($ident: DefaultOrFrom<T>,)+
{
fn default_or_from(value: Option<&T>) -> Self {
($(
(<$ident as DefaultOrFrom<T>>::default_or_from(value)),
)+)
}
}
}
}
#[rustfmt::skip]
const _: () = {
impl_default_from_tuples!(A);
impl_default_from_tuples!(A, B);
impl_default_from_tuples!(A, B, C);
impl_default_from_tuples!(A, B, C, D);
impl_default_from_tuples!(A, B, C, D, E);
impl_default_from_tuples!(A, B, C, D, E, F);
impl_default_from_tuples!(A, B, C, D, E, F, G);
impl_default_from_tuples!(A, B, C, D, E, F, G, H);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, U);
impl_default_from_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, U, V);
};
+3 -1
View File
@@ -23,7 +23,9 @@ use scale_encode::EncodeAsType;
use serde::{de::DeserializeOwned, Serialize};
pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder};
pub use extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError};
pub use extrinsic_params::{
DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError,
};
pub use polkadot::{PolkadotConfig, PolkadotExtrinsicParams, PolkadotExtrinsicParamsBuilder};
pub use signed_extensions::SignedExtension;
pub use substrate::{SubstrateConfig, SubstrateExtrinsicParams, SubstrateExtrinsicParamsBuilder};
+27 -1
View File
@@ -7,7 +7,10 @@
//! [`AnyOf`] to configure the set of signed extensions which are known about
//! when interacting with a chain.
use super::extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError};
use super::extrinsic_params::{
DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError,
};
use crate::config::Header;
use crate::utils::Era;
use crate::{client::OfflineClientT, Config};
use codec::{Compact, Encode};
@@ -166,6 +169,17 @@ impl<T: Config> Default for CheckMortalityParams<T> {
}
}
impl<T: Config> DefaultOrFrom<T::Header> for CheckMortalityParams<T> {
fn default_or_from(value: Option<&T::Header>) -> Self {
if let Some(header) = value {
const FOR_N_BLOCKS: u64 = 32;
CheckMortalityParams::mortal(FOR_N_BLOCKS, header.number().into(), header.hash())
} else {
Default::default()
}
}
}
impl<T: Config> CheckMortalityParams<T> {
/// Configure a mortal transaction. The `period` is (roughly) how many
/// blocks the transaction will be valid for. The `block_number` and
@@ -253,6 +267,12 @@ impl<T: Config> Default for ChargeAssetTxPaymentParams<T> {
}
}
impl<T: Config> DefaultOrFrom<T::Header> for ChargeAssetTxPaymentParams<T> {
fn default_or_from(_value: Option<&T::Header>) -> Self {
Default::default()
}
}
impl<T: Config> ChargeAssetTxPaymentParams<T> {
/// Don't provide a tip to the extrinsic author.
pub fn no_tip() -> Self {
@@ -324,6 +344,12 @@ pub struct ChargeTransactionPaymentParams {
tip: u128,
}
impl<T> DefaultOrFrom<T> for ChargeTransactionPaymentParams {
fn default_or_from(_value: Option<&T>) -> Self {
Default::default()
}
}
impl ChargeTransactionPaymentParams {
/// Don't provide a tip to the extrinsic author.
pub fn no_tip() -> Self {
+13 -5
View File
@@ -7,7 +7,7 @@ use std::borrow::Cow;
use crate::{
backend::{BackendExt, BlockRef, TransactionStatus},
client::{OfflineClientT, OnlineClientT},
config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher},
config::{Config, DefaultOrFrom, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher},
error::{Error, MetadataError},
tx::{Signer as SignerT, TxPayload, TxProgress},
utils::{Encoded, PhantomDataSendSync},
@@ -213,9 +213,13 @@ where
where
Call: TxPayload,
Signer: SignerT<T>,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: Default,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: DefaultOrFrom<T::Header>,
{
self.sign_and_submit_then_watch(call, signer, Default::default())
let latest_block = self.client.blocks().at_latest().await.ok();
let latest_header = latest_block.as_ref().map(|b| b.header());
let other_params =
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams::default_or_from(latest_header);
self.sign_and_submit_then_watch(call, signer, other_params)
.await
}
@@ -257,9 +261,13 @@ where
where
Call: TxPayload,
Signer: SignerT<T>,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: Default,
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams: DefaultOrFrom<T::Header>,
{
self.sign_and_submit(call, signer, Default::default()).await
let latest_block = self.client.blocks().at_latest().await.ok();
let latest_header = latest_block.as_ref().map(|b| b.header());
let other_params =
<T::ExtrinsicParams as ExtrinsicParams<T>>::OtherParams::default_or_from(latest_header);
self.sign_and_submit(call, signer, other_params).await
}
/// Creates and signs an extrinsic and submits to the chain for block inclusion.