Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable Config and Extra types #373

Merged
merged 12 commits into from
Jan 6, 2022
13 changes: 8 additions & 5 deletions codegen/src/api/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn generate_calls(
pub fn #fn_name(
&self,
#( #call_fn_args, )*
) -> ::subxt::SubmittableExtrinsic<'a, T, #call_struct_name> {
) -> ::subxt::SubmittableExtrinsic<'a, T, E, A, #call_struct_name> {
let call = #call_struct_name { #( #call_args, )* };
::subxt::SubmittableExtrinsic::new(self.client, call)
}
Expand All @@ -82,16 +82,19 @@ pub fn generate_calls(
use super::#types_mod_ident;
#( #call_structs )*

pub struct TransactionApi<'a, T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>> {
pub struct TransactionApi<'a, T: ::subxt::Config, E, A> {
client: &'a ::subxt::Client<T>,
marker: ::core::marker::PhantomData<(E, A)>,
}

impl<'a, T: ::subxt::Config> TransactionApi<'a, T>
impl<'a, T, E, A> TransactionApi<'a, T, E, A>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
T: ::subxt::Config,
E: ::subxt::SignedExtra<T>,
A: ::subxt::AccountData<T>,
{
pub fn new(client: &'a ::subxt::Client<T>) -> Self {
Self { client }
Self { client, marker: ::core::marker::PhantomData }
}

#( #call_fns )*
Expand Down
71 changes: 27 additions & 44 deletions codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ impl RuntimeGenerator {
)
})
.collect::<Vec<_>>();

let modules = pallets_with_mod_names.iter().map(|(pallet, mod_name)| {
let calls = if let Some(ref calls) = pallet.calls {
calls::generate_calls(&type_gen, pallet, calls, types_mod_ident)
Expand Down Expand Up @@ -222,76 +223,55 @@ impl RuntimeGenerator {
#( #modules )*
#types_mod

/// Default configuration of common types for a target Substrate runtime.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DefaultConfig;

impl ::subxt::Config for DefaultConfig {
type Index = u32;
type BlockNumber = u32;
type Hash = ::subxt::sp_core::H256;
type Hashing = ::subxt::sp_runtime::traits::BlakeTwo256;
type AccountId = ::subxt::sp_runtime::AccountId32;
type Address = ::subxt::sp_runtime::MultiAddress<Self::AccountId, u32>;
type Header = ::subxt::sp_runtime::generic::Header<
Self::BlockNumber, ::subxt::sp_runtime::traits::BlakeTwo256
>;
type Signature = ::subxt::sp_runtime::MultiSignature;
type Extrinsic = ::subxt::sp_runtime::OpaqueExtrinsic;
}

impl ::subxt::ExtrinsicExtraData<DefaultConfig> for DefaultConfig {
type AccountData = AccountData;
type Extra = ::subxt::DefaultExtra<DefaultConfig>;
}
/// The default storage entry from which to fetch an account nonce, required for
/// constructing a transaction.
pub type DefaultAccountData = self::system::storage::Account;

pub type AccountData = self::system::storage::Account;

impl ::subxt::AccountData<DefaultConfig> for AccountData {
fn nonce(result: &<Self as ::subxt::StorageEntry>::Value) -> <DefaultConfig as ::subxt::Config>::Index {
impl ::subxt::AccountData<::subxt::DefaultConfig> for DefaultAccountData {
fn nonce(result: &<Self as ::subxt::StorageEntry>::Value) -> <::subxt::DefaultConfig as ::subxt::Config>::Index {
result.nonce
}
fn storage_entry(account_id: <DefaultConfig as ::subxt::Config>::AccountId) -> Self {
fn storage_entry(account_id: <::subxt::DefaultConfig as ::subxt::Config>::AccountId) -> Self {
Self(account_id)
}
}

pub struct RuntimeApi<T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>> {
pub struct RuntimeApi<T: ::subxt::Config, E> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth defaulting these generic params eg

pub struct RuntimeApi<T: ::subxt::Config = ::subxt::DefaultConfig, E = ::subxt::DefaultExtra<::subxt::DefaultConfig>> {

so that we don't have to specify them when instantiating the RuntimeApi unless they differ? Or is the common case that you'll need to specify different ones, so it may as well be explicit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure TBH, on the one hand it is very convenient if you are using the defaults, on the other if they are hidden then there is not the clue that it is configurable.

I'd lean towards leaving it explicit for now, until the api has solidified and we have an idea of the common usage.

pub client: ::subxt::Client<T>,
marker: ::core::marker::PhantomData<E>,
}

impl<T> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T>
impl<T, E> ::core::convert::From<::subxt::Client<T>> for RuntimeApi<T, E>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
T: ::subxt::Config,
E: ::subxt::SignedExtra<T>,
{
fn from(client: ::subxt::Client<T>) -> Self {
Self { client }
Self { client, marker: ::core::marker::PhantomData }
}
}

impl<'a, T> RuntimeApi<T>
impl<'a, T, E> RuntimeApi<T, E>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
T: ::subxt::Config,
E: ::subxt::SignedExtra<T>,
{
pub fn storage(&'a self) -> StorageApi<'a, T> {
StorageApi { client: &self.client }
}

pub fn tx(&'a self) -> TransactionApi<'a, T> {
TransactionApi { client: &self.client }
pub fn tx(&'a self) -> TransactionApi<'a, T, E, DefaultAccountData> {
TransactionApi { client: &self.client, marker: ::core::marker::PhantomData }
}
}

pub struct StorageApi<'a, T>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
{
pub struct StorageApi<'a, T: ::subxt::Config> {
client: &'a ::subxt::Client<T>,
}

impl<'a, T> StorageApi<'a, T>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
T: ::subxt::Config,
{
#(
pub fn #pallets_with_storage(&self) -> #pallets_with_storage::storage::StorageApi<'a, T> {
Expand All @@ -300,16 +280,19 @@ impl RuntimeGenerator {
)*
}

pub struct TransactionApi<'a, T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>> {
pub struct TransactionApi<'a, T: ::subxt::Config, E, A> {
client: &'a ::subxt::Client<T>,
marker: ::core::marker::PhantomData<(E, A)>,
}

impl<'a, T> TransactionApi<'a, T>
impl<'a, T, E, A> TransactionApi<'a, T, E, A>
where
T: ::subxt::Config + ::subxt::ExtrinsicExtraData<T>,
T: ::subxt::Config,
E: ::subxt::SignedExtra<T>,
A: ::subxt::AccountData<T>,
{
#(
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T> {
pub fn #pallets_with_calls(&self) -> #pallets_with_calls::calls::TransactionApi<'a, T, E, A> {
#pallets_with_calls::calls::TransactionApi::new(self.client)
}
)*
Expand Down
1 change: 0 additions & 1 deletion codegen/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ impl ItemMod {

#[allow(clippy::large_enum_variant)]
#[derive(Debug, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum Item {
Rust(syn::Item),
Subxt(SubxtItem),
Expand Down
8 changes: 6 additions & 2 deletions examples/fetch_all_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
//! polkadot --dev --tmp
//! ```

use subxt::ClientBuilder;
use subxt::{
ClientBuilder,
DefaultConfig,
DefaultExtra,
};

#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
pub mod polkadot {}
Expand All @@ -34,7 +38,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();

let mut iter = api.storage().system().account_iter(None).await?;

Expand Down
8 changes: 6 additions & 2 deletions examples/fetch_remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
// You should have received a copy of the GNU General Public License
// along with subxt. If not, see <http://www.gnu.org/licenses/>.

use subxt::ClientBuilder;
use subxt::{
ClientBuilder,
DefaultConfig,
DefaultExtra,
};

#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
pub mod polkadot {}
Expand All @@ -27,7 +31,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.set_url("wss://rpc.polkadot.io")
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();

let block_number = 1;

Expand Down
4 changes: 3 additions & 1 deletion examples/polkadot_balance_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
use sp_keyring::AccountKeyring;
use subxt::{
ClientBuilder,
DefaultConfig,
DefaultExtra,
PairSigner,
};

Expand All @@ -41,7 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();
let hash = api
.tx()
.balances()
Expand Down
8 changes: 5 additions & 3 deletions examples/submit_and_watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use futures::StreamExt;
use sp_keyring::AccountKeyring;
use subxt::{
ClientBuilder,
DefaultConfig,
DefaultExtra,
PairSigner,
};

Expand Down Expand Up @@ -53,7 +55,7 @@ async fn simple_transfer() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();

let balance_transfer = api
.tx()
Expand Down Expand Up @@ -85,7 +87,7 @@ async fn simple_transfer_separate_events() -> Result<(), Box<dyn std::error::Err
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();

let balance_transfer = api
.tx()
Expand Down Expand Up @@ -136,7 +138,7 @@ async fn handle_transfer_events() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<_>>>();

let mut balance_transfer_progress = api
.tx()
Expand Down
6 changes: 4 additions & 2 deletions examples/transfer_subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
use sp_keyring::AccountKeyring;
use subxt::{
ClientBuilder,
DefaultConfig,
DefaultExtra,
EventSubscription,
PairSigner,
};
Expand All @@ -42,11 +44,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<polkadot::DefaultConfig>>();
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>();

let sub = api.client.rpc().subscribe_events().await?;
let decoder = api.client.events_decoder();
let mut sub = EventSubscription::<polkadot::DefaultConfig>::new(sub, decoder);
let mut sub = EventSubscription::<DefaultConfig>::new(sub, decoder);
sub.filter_event::<polkadot::balances::events::Transfer>();

api.tx()
Expand Down
42 changes: 24 additions & 18 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ use crate::{
AccountData,
Call,
Config,
ExtrinsicExtraData,
Metadata,
};
use std::sync::Arc;
Expand Down Expand Up @@ -185,19 +184,26 @@ impl<T: Config> Client<T> {
}

/// A constructed call ready to be signed and submitted.
pub struct SubmittableExtrinsic<'client, T: Config, C> {
pub struct SubmittableExtrinsic<'client, T: Config, E, A, C> {
client: &'client Client<T>,
call: C,
marker: std::marker::PhantomData<(E, A)>,
}

impl<'client, T, C> SubmittableExtrinsic<'client, T, C>
impl<'client, T, E, A, C> SubmittableExtrinsic<'client, T, E, A, C>
where
T: Config + ExtrinsicExtraData<T>,
T: Config,
E: SignedExtra<T>,
A: AccountData<T>,
C: Call + Send + Sync,
{
/// Create a new [`SubmittableExtrinsic`].
pub fn new(client: &'client Client<T>, call: C) -> Self {
Self { client, call }
Self {
client,
call,
marker: Default::default(),
}
}

/// Creates and signs an extrinsic and submits it to the chain.
Expand All @@ -206,10 +212,11 @@ where
/// and obtain details about it, once it has made it into a block.
pub async fn sign_and_submit_then_watch(
self,
signer: &(dyn Signer<T> + Send + Sync),
signer: &(dyn Signer<T, E> + Send + Sync),
) -> Result<TransactionProgress<'client, T>, Error>
where
<<<T as ExtrinsicExtraData<T>>::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned: Send + Sync + 'static
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
{
// Sign the call data to create our extrinsic.
let extrinsic = self.create_signed(signer, Default::default()).await?;
Expand All @@ -231,10 +238,11 @@ where
/// and has been included in the transaction pool.
pub async fn sign_and_submit(
self,
signer: &(dyn Signer<T> + Send + Sync),
signer: &(dyn Signer<T, E> + Send + Sync),
) -> Result<T::Hash, Error>
where
<<<T as ExtrinsicExtraData<T>>::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned: Send + Sync + 'static
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
{
let extrinsic = self.create_signed(signer, Default::default()).await?;
self.client.rpc().submit_extrinsic(extrinsic).await
Expand All @@ -243,25 +251,23 @@ where
/// Creates a signed extrinsic.
pub async fn create_signed(
&self,
signer: &(dyn Signer<T> + Send + Sync),
additional_params: <T::Extra as SignedExtra<T>>::Parameters,
) -> Result<UncheckedExtrinsic<T>, Error>
signer: &(dyn Signer<T, E> + Send + Sync),
additional_params: E::Parameters,
) -> Result<UncheckedExtrinsic<T, E>, Error>
where
<<<T as ExtrinsicExtraData<T>>::Extra as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned: Send + Sync + 'static
<<E as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
{
let account_nonce = if let Some(nonce) = signer.nonce() {
nonce
} else {
let account_storage_entry =
<<T as ExtrinsicExtraData<T>>::AccountData as AccountData<T>>::storage_entry(signer.account_id().clone());
let account_storage_entry = A::storage_entry(signer.account_id().clone());
let account_data = self
.client
.storage()
.fetch_or_default(&account_storage_entry, None)
.await?;
<<T as ExtrinsicExtraData<T>>::AccountData as AccountData<T>>::nonce(
&account_data,
)
A::nonce(&account_data)
};
let call = self
.client
Expand Down
Loading