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

Parameterize AccountData #409

Merged
merged 20 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,6 @@ impl RuntimeGenerator {
#( #modules )*
#types_mod

/// The default storage entry from which to fetch an account nonce, required for
/// constructing a transaction.
pub type DefaultAccountData = self::system::storage::Account;

/// The default error type returned when there is a runtime issue.
pub type DispatchError = self::runtime_types::sp_runtime::DispatchError;

Expand All @@ -241,40 +237,52 @@ impl RuntimeGenerator {
#error_fn
}

impl ::subxt::AccountData<::subxt::DefaultConfig> for DefaultAccountData {
fn nonce(result: &<Self as ::subxt::StorageEntry>::Value) -> <::subxt::DefaultConfig as ::subxt::Config>::Index {
result.nonce
/// The default storage entry from which to fetch an account nonce, required for
/// constructing a transaction.
pub struct DefaultAccountData<T: ::subxt::Config>(::core::marker::PhantomData<T>);

impl<T> ::subxt::AccountData<T> for DefaultAccountData<T>
where
T: ::subxt::Config,
{
type StorageEntry = self::system::storage::Account;
type AccountId = ::subxt::sp_core::crypto::AccountId32;

fn nonce(result: &<Self::StorageEntry as ::subxt::StorageEntry>::Value) -> T::Index {
result.nonce.into()
}
fn storage_entry(account_id: <::subxt::DefaultConfig as ::subxt::Config>::AccountId) -> Self {
Self(account_id)
fn storage_entry(account_id: Self::AccountId) -> Self::StorageEntry {
self::system::storage::Account(account_id)
}
}

pub struct RuntimeApi<T: ::subxt::Config, X> {
pub struct RuntimeApi<T: ::subxt::Config, X, A = DefaultAccountData<T>> {
pub client: ::subxt::Client<T>,
marker: ::core::marker::PhantomData<X>,
marker: ::core::marker::PhantomData<(X, A)>,
}

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

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

pub fn tx(&'a self) -> TransactionApi<'a, T, X, DefaultAccountData> {
pub fn tx(&'a self) -> TransactionApi<'a, T, X, A> {
TransactionApi { client: &self.client, marker: ::core::marker::PhantomData }
}
}
Expand Down
61 changes: 61 additions & 0 deletions examples/custom_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// This file is part of 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 subxt. If not, see <http://www.gnu.org/licenses/>.

use sp_keyring::AccountKeyring;
use subxt::{
ClientBuilder,
Config,
DefaultConfig,
DefaultExtra,
PairSigner,
};

#[subxt::subxt(runtime_metadata_path = "examples/polkadot_metadata.scale")]
pub mod polkadot {}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MyConfig;
impl Config for MyConfig {
type Index = <DefaultConfig as Config>::Index;
type BlockNumber = <DefaultConfig as Config>::BlockNumber;
type Hash = <DefaultConfig as Config>::Hash;
type Hashing = <DefaultConfig as Config>::Hashing;
type AccountId = <DefaultConfig as Config>::AccountId;
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this example would be more useful if we made a more plausible change to the config, something a project might actually want to do. Not for this PR, it'd be more like a tutorial I reckon.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it would be best accompanied with an actual runtime with the different type

type Address = <DefaultConfig as Config>::Address;
type Header = <DefaultConfig as Config>::Header;
type Signature = <DefaultConfig as Config>::Signature;
type Extrinsic = <DefaultConfig as Config>::Extrinsic;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just for the sake of the example, could we actually override one or more of these types perhaps (maybe then with a comment saying what's going on), just to make it clear that that's sortof the point of this impl? (I realise that doing so may prevent it from actually working below; something that would want to be made clear also.)


#[async_std::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let api = ClientBuilder::new()
.build()
.await?
.to_runtime_api::<polkadot::RuntimeApi<MyConfig, DefaultExtra<MyConfig>>>();

let signer = PairSigner::new(AccountKeyring::Alice.pair());
let dest = AccountKeyring::Bob.to_account_id().into();

let _ = api
.tx()
.balances()
.transfer(dest, 10_000)
.sign_and_submit(&signer)
.await?;

Ok(())
}
6 changes: 5 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ where
where
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
<A as AccountData<T>>::AccountId: From<<T as Config>::AccountId>,
{
// Sign the call data to create our extrinsic.
let extrinsic = self.create_signed(signer, Default::default()).await?;
Expand Down Expand Up @@ -249,6 +250,7 @@ where
where
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
<A as AccountData<T>>::AccountId: From<<T as Config>::AccountId>,
{
let extrinsic = self.create_signed(signer, Default::default()).await?;
self.client.rpc().submit_extrinsic(extrinsic).await
Expand All @@ -263,11 +265,13 @@ where
where
<<X as SignedExtra<T>>::Extra as SignedExtension>::AdditionalSigned:
Send + Sync + 'static,
<A as AccountData<T>>::AccountId: From<<T as Config>::AccountId>,
{
let account_nonce = if let Some(nonce) = signer.nonce() {
nonce
} else {
let account_storage_entry = A::storage_entry(signer.account_id().clone());
let account_storage_entry =
A::storage_entry(signer.account_id().clone().into());
let account_data = self
.client
.storage()
Expand Down
17 changes: 11 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,17 @@ impl Config for DefaultConfig {
}

/// Trait to fetch data about an account.
///
/// Should be implemented on a type implementing `StorageEntry`,
/// usually generated by the `subxt` macro.
pub trait AccountData<T: Config>: StorageEntry {
pub trait AccountData<T: Config> {
/// The runtime storage entry from which the account data can be fetched.
/// Usually generated by the `subxt` macro.
type StorageEntry: StorageEntry;

/// The type of the account id to fetch the account data for.
type AccountId;

/// Create a new storage entry key from the account id.
fn storage_entry(account_id: T::AccountId) -> Self;
fn storage_entry(account_id: Self::AccountId) -> Self::StorageEntry;

/// Get the nonce from the storage entry value.
fn nonce(result: &<Self as StorageEntry>::Value) -> T::Index;
fn nonce(result: &<Self::StorageEntry as StorageEntry>::Value) -> T::Index;
}
Loading