remove substrate compat (#1850)

* remove substrate compat

* add hacky example

* simplify substrate-compat example

* simplify substrate-compat example

* cargo fmt

* fix build

* add more examples

* fix nit

* fix test build

* Update subxt/examples/substrate_compat_signer.rs

Co-authored-by: James Wilson <james@jsdw.me>

* keep only polkadot signer example

* remove more substrate compat related stuff

* fix example

* link to substrate signer example in book

* Update subxt/src/book/usage/transactions.rs

* Update subxt/src/book/usage/transactions.rs

* address grumbles

* fix nits

---------

Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
Niklas Adolfsson
2024-11-27 16:46:38 +01:00
committed by GitHub
parent 09ab839ff2
commit f5e9ce0d2c
18 changed files with 143 additions and 305 deletions
+4 -9
View File
@@ -64,11 +64,6 @@ jsonrpsee = [
"runtime"
]
# Enable this to pull in extra Substrate dependencies which make it possible to
# use the `sp_core::crypto::Pair` Signer implementation, as well as adding some
# `From` impls for types like `AccountId32`. Cannot be used with "web".
substrate-compat = ["subxt-core/substrate-compat"]
# Enable this to fetch and utilize the latest unstable metadata from a node.
# The unstable metadata is subject to breaking changes and the subxt might
# fail to decode the metadata properly. Use this to experiment with the
@@ -95,6 +90,7 @@ futures = { workspace = true }
hex = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true, features = ["default", "raw_value"] }
polkadot-sdk = { workspace = true, features = ["sp-crypto-hashing"] }
thiserror = { workspace = true }
tracing = { workspace = true }
frame-metadata = { workspace = true }
@@ -104,7 +100,6 @@ web-time = { workspace = true }
# Provides some deserialization, types like U256/H256 and hashing impls like twox/blake256:
impl-serde = { workspace = true }
primitive-types = { workspace = true, features = ["codec", "scale-info", "serde"] }
polkadot-sdk = { workspace = true, features = ["sp-crypto-hashing"] }
# Included if the "jsonrpsee" feature is enabled.
jsonrpsee = { workspace = true, optional = true, features = ["jsonrpsee-types"] }
@@ -136,7 +131,7 @@ bitvec = { workspace = true }
codec = { workspace = true, features = ["derive", "bit-vec"] }
scale-info = { workspace = true, features = ["bit-vec"] }
tokio = { workspace = true, features = ["macros", "time", "rt-multi-thread", "sync"] }
polkadot-sdk = { workspace = true, features = ["sp-core", "sp-keyring", "sp-runtime", "sp-crypto-hashing"] }
polkadot-sdk = { workspace = true, features = ["sp-core", "sp-keyring", "sp-runtime", "std"] }
assert_matches = { workspace = true }
subxt-signer = { path = "../signer", features = ["unstable-eth"] }
# Tracing subscriber is useful for light-client examples to ensure that
@@ -166,8 +161,8 @@ path = "examples/setup_reconnecting_rpc_client.rs"
required-features = ["reconnecting-rpc-client"]
[package.metadata.docs.rs]
features = ["default", "substrate-compat", "unstable-light-client"]
features = ["default", "unstable-light-client"]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.playground]
features = ["default", "substrate-compat", "unstable-light-client"]
features = ["default", "unstable-light-client"]
+121
View File
@@ -0,0 +1,121 @@
//! This example demonstrates how to use to add a custom signer implementation to `subxt`
//! by using the signer implementation from polkadot-sdk.
//!
//! Similar functionality was provided by the `substrate-compat` feature in the original `subxt` crate.
//! which is now removed.
#![allow(missing_docs, unused)]
use polkadot_sdk::sp_core::{sr25519, Pair as _};
use subxt::config::substrate::MultiAddress;
use subxt::{Config, OnlineClient, PolkadotConfig};
#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")]
pub mod polkadot {}
/// A concrete PairSigner implementation which relies on `sr25519::Pair` for signing
/// and that PolkadotConfig is the runtime configuration.
mod pair_signer {
use super::*;
use polkadot_sdk::sp_runtime::{
traits::{IdentifyAccount, Verify},
MultiSignature as SpMultiSignature,
};
use subxt::{
config::substrate::{AccountId32, MultiSignature},
tx::Signer,
};
/// A [`Signer`] implementation for [`polkadot_sdk::sp_core::sr25519::Pair`].
#[derive(Clone)]
pub struct PairSigner {
account_id: <PolkadotConfig as Config>::AccountId,
signer: sr25519::Pair,
}
impl PairSigner {
/// Creates a new [`Signer`] from an [`sp_core::sr25519::Pair`].
pub fn new(signer: sr25519::Pair) -> Self {
let account_id =
<SpMultiSignature as Verify>::Signer::from(signer.public()).into_account();
Self {
// Convert `sp_core::AccountId32` to `subxt::config::substrate::AccountId32`.
//
// This is necessary because we use `subxt::config::substrate::AccountId32` and no
// From/Into impls are provided between `sp_core::AccountId32` because `polkadot-sdk` isn't a direct
// dependency in subxt.
//
// This can also be done by provided a wrapper type around `subxt::config::substrate::AccountId32` to implement
// such conversions but that also most likely requires a custom `Config` with a separate `AccountId` type to work
// properly without additional hacks.
account_id: AccountId32(account_id.into()),
signer,
}
}
/// Returns the [`sp_core::sr25519::Pair`] implementation used to construct this.
pub fn signer(&self) -> &sr25519::Pair {
&self.signer
}
/// Return the account ID.
pub fn account_id(&self) -> &AccountId32 {
&self.account_id
}
}
impl Signer<PolkadotConfig> for PairSigner {
fn account_id(&self) -> <PolkadotConfig as Config>::AccountId {
self.account_id.clone()
}
fn address(&self) -> <PolkadotConfig as Config>::Address {
self.account_id.clone().into()
}
fn sign(&self, signer_payload: &[u8]) -> <PolkadotConfig as Config>::Signature {
let signature = self.signer.sign(signer_payload);
MultiSignature::Sr25519(signature.0)
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt::init();
// Create a new API client, configured to talk to Polkadot nodes.
let api = OnlineClient::<PolkadotConfig>::new().await?;
let signer = {
let acc = sr25519::Pair::from_string("//Alice", None)?;
pair_signer::PairSigner::new(acc)
};
let dest = {
let acc = sr25519::Pair::from_string("//Bob", None)?;
MultiAddress::Address32(acc.public().0)
};
// Build a balance transfer extrinsic.
let balance_transfer_tx = polkadot::tx()
.balances()
.transfer_allow_death(dest, 100_000);
// Submit the balance transfer extrinsic from Alice, and wait for it to be successful
// and in a finalized block. We get back the extrinsic events if all is well.
let events = api
.tx()
.sign_and_submit_then_watch_default(&balance_transfer_tx, &signer)
.await?
.wait_for_finalized_success()
.await?;
// Find a Transfer event and print it.
let transfer_event = events.find_first::<polkadot::balances::events::Transfer>()?;
if let Some(event) = transfer_event {
println!("Balance transfer success: {event:?}");
}
Ok(())
}
+8 -34
View File
@@ -66,24 +66,23 @@
//! There are two main ways to create a compatible signer instance:
//! 1. The `subxt_signer` crate provides a WASM compatible implementation of [`crate::tx::Signer`]
//! for chains which require sr25519 or ecdsa signatures (requires the `subxt` feature to be enabled).
//! 2. Alternately, Subxt can use instances of Substrate's `sp_core::Pair` to sign things by wrapping
//! them in a `crate::tx::PairSigner` (requires the `substrate-compat` feature to be enabled).
//! 2. Alternately, implement your own [`crate::tx::Signer`] instance by wrapping it in a new type pattern.
//!
//! Going for 1 leads to fewer dependencies being imported and WASM compatibility out of the box via
//! the `web` feature flag. Going for 2 is useful if you're already using the Substrate dependencies or
//! need additional signing algorithms that `subxt_signer` doesn't support, and don't care about WASM
//! compatibility.
//!
//! Let's see how to use each of these approaches:
//! Because 2 is more complex and require more code, we'll focus on 1 here.
//! For 2, see the example in `subxt/examples/substrate_compat_signer.rs` how
//! you can integrate things like sp_core's signer in subxt.
//!
//! Let's go through how to create a signer using the `subxt_signer` crate:
//!
//! ```rust
//! # #[cfg(feature = "substrate-compat")]
//! # {
//! use subxt::config::PolkadotConfig;
//! use std::str::FromStr;
//! use polkadot_sdk::{sp_core, sp_keyring};
//!
//! //// 1. Use a `subxt_signer` impl:
//! use subxt_signer::{SecretUri, sr25519};
//!
//! // Get hold of a `Signer` for a test account:
@@ -94,34 +93,9 @@
//! .expect("valid URI");
//! let keypair = sr25519::Keypair::from_uri(&uri)
//! .expect("valid keypair");
//!```
//!
//! //// 2. Use the corresponding `sp_core::Pair` impl:
//! use subxt::tx::PairSigner;
//! use sp_core::Pair;
//!
//! // Get hold of a `Signer` for a test account:
//! let alice = sp_keyring::AccountKeyring::Alice.pair();
//! let alice = PairSigner::<PolkadotConfig,_>::new(alice);
//!
//! // Or generate a keypair, here from an SURI:
//! let keypair = sp_core::sr25519::Pair::from_string("vessel ladder alter error federal sibling chat ability sun glass valve picture/0/1///Password", None)
//! .expect("valid URI");
//! let keypair = PairSigner::<PolkadotConfig,_>::new(keypair);
//! #
//! # // Test that these all impl Signer trait while we're here:
//! #
//! # fn is_subxt_signer(_signer: impl subxt::tx::Signer<PolkadotConfig>) {}
//! # is_subxt_signer(subxt_signer::sr25519::dev::alice());
//! # is_subxt_signer(subxt_signer::ecdsa::dev::alice());
//! # is_subxt_signer(PairSigner::<PolkadotConfig,_>::new(sp_keyring::AccountKeyring::Alice.pair()));
//! # }
//! ```
//!
//! See the `subxt_signer` crate or the `sp_core::Pair` docs for more ways to construct
//! and work with key pairs.
//!
//! If this isn't suitable/available, you can either implement [`crate::tx::Signer`] yourself to use
//! custom signing logic, or you can use some external signing logic, like so:
//! After initializing the signer, let's also go through how to create a transaction and sign it:
//!
//! ```rust,no_run
//! # #[tokio::main]
-7
View File
@@ -18,9 +18,6 @@
))]
compile_error!("subxt: exactly one of the 'web' and 'native' features should be used.");
#[cfg(all(feature = "web", feature = "substrate-compat"))]
compile_error!("subxt: the 'substrate-compat' feature is not compatible with the 'web' feature.");
// The guide is here.
pub mod book;
@@ -115,10 +112,6 @@ pub mod ext {
cfg_jsonrpsee! {
pub use jsonrpsee;
}
cfg_substrate_compat! {
pub use subxt_core::ext::{sp_runtime, sp_core};
}
}
/// Generate a strongly typed API for interacting with a Substrate runtime from its metadata.
+1 -8
View File
@@ -12,12 +12,6 @@ macro_rules! cfg_feature {
}
}
macro_rules! cfg_substrate_compat {
($($item:item)*) => {
crate::macros::cfg_feature!("substrate-compat", $($item)*);
};
}
macro_rules! cfg_unstable_light_client {
($($item:item)*) => {
crate::macros::cfg_feature!("unstable-light-client", $($item)*);
@@ -64,8 +58,7 @@ macro_rules! cfg_reconnecting_rpc_client {
}
pub(crate) use {
cfg_feature, cfg_jsonrpsee, cfg_reconnecting_rpc_client, cfg_substrate_compat,
cfg_unstable_light_client,
cfg_feature, cfg_jsonrpsee, cfg_reconnecting_rpc_client, cfg_unstable_light_client,
};
// Only used by light-client.
-8
View File
@@ -9,17 +9,9 @@
//! additional and signed extra parameters are used when constructing an extrinsic, and is a part
//! of the chain configuration (see [`crate::config::Config`]).
use crate::macros::cfg_substrate_compat;
mod tx_client;
mod tx_progress;
// The PairSigner impl currently relies on Substrate bits and pieces, so make it an optional
// feature if we want to avoid needing sp_core and sp_runtime.
cfg_substrate_compat! {
pub use subxt_core::tx::signer::PairSigner;
}
pub use subxt_core::tx::payload::{dynamic, DefaultPayload, DynamicPayload, Payload};
pub use subxt_core::tx::signer::{self, Signer};
pub use tx_client::{