From 702f4c8457b0b9f62924157a910644edbd4f4c22 Mon Sep 17 00:00:00 2001 From: Greg Hill Date: Thu, 3 Feb 2022 11:54:23 +0000 Subject: [PATCH 01/10] export RuntimeError struct (#427) Signed-off-by: Gregory Hill --- subxt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 02077fcd8c..723280f501 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -82,6 +82,7 @@ pub use crate::{ BasicError, Error, PalletError, + RuntimeError, TransactionError, }, events::{ From 75ea2cbf150ef96d74283d82229688b30596584f Mon Sep 17 00:00:00 2001 From: Greg Hill Date: Thu, 3 Feb 2022 15:09:08 +0000 Subject: [PATCH 02/10] remove unused PalletError struct (#425) Signed-off-by: Gregory Hill --- subxt/src/error.rs | 12 ------------ subxt/src/lib.rs | 1 - 2 files changed, 13 deletions(-) diff --git a/subxt/src/error.rs b/subxt/src/error.rs index 650f091536..59a0bdf731 100644 --- a/subxt/src/error.rs +++ b/subxt/src/error.rs @@ -155,18 +155,6 @@ impl RuntimeError { } } -/// Module error. -#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)] -#[error("{error} from {pallet}")] -pub struct PalletError { - /// The module where the error originated. - pub pallet: String, - /// The actual error code. - pub error: String, - /// The error description. - pub description: Vec, -} - /// Transaction error. #[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)] pub enum TransactionError { diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 723280f501..e4e5668fc6 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -81,7 +81,6 @@ pub use crate::{ error::{ BasicError, Error, - PalletError, RuntimeError, TransactionError, }, From 9f88761e4655efb575a04336dddf17059609a219 Mon Sep 17 00:00:00 2001 From: Fabio Lama Date: Thu, 3 Feb 2022 17:40:46 +0100 Subject: [PATCH 03/10] Get event context on EventSubscription (#423) * implement next_context * write test_context for method next_context * change how events are uniquely identified * undo local changes for test-runtime * introduce EventContext struct * adjust test_context to EventContext struct * fix return type for next_context * add suggestions by jsdw * ran cargo fmt and clippy --- subxt/src/subscription.rs | 163 +++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 20 deletions(-) diff --git a/subxt/src/subscription.rs b/subxt/src/subscription.rs index 307bfea222..0adc6f929a 100644 --- a/subxt/src/subscription.rs +++ b/subxt/src/subscription.rs @@ -39,6 +39,16 @@ use sp_core::{ use sp_runtime::traits::Header; use std::collections::VecDeque; +/// Raw bytes for an Event, including the block hash where it occurred and its +/// corresponding event index. +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq, Clone))] +pub struct EventContext { + pub block_hash: Hash, + pub event_idx: usize, + pub event: RawEvent, +} + /// Event subscription simplifies filtering a storage change set stream for /// events of interest. pub struct EventSubscription<'a, T: Config> { @@ -46,7 +56,7 @@ pub struct EventSubscription<'a, T: Config> { block: Option, extrinsic: Option, event: Option<(&'static str, &'static str)>, - events: VecDeque, + events: VecDeque>, finished: bool, } @@ -57,13 +67,19 @@ enum BlockReader<'a, T: Config> { }, /// Mock event listener for unit tests #[cfg(test)] - Mock(Box, BasicError>)>>), + Mock( + Box< + dyn Iterator< + Item = (T::Hash, Result, BasicError>), + >, + >, + ), } impl<'a, T: Config> BlockReader<'a, T> { async fn next( &mut self, - ) -> Option<(T::Hash, Result, BasicError>)> { + ) -> Option<(T::Hash, Result, BasicError>)> { match self { BlockReader::Decoder { subscription, @@ -78,7 +94,13 @@ impl<'a, T: Config> BlockReader<'a, T> { }) .collect(); - let flattened_events = events.map(|x| x.into_iter().flatten().collect()); + let flattened_events = events.map(|x| { + x.into_iter() + .flatten() + .enumerate() + .map(|(event_idx, (phase, raw))| (phase, event_idx, raw)) + .collect() + }); Some((change_set.block, flattened_events)) } #[cfg(test)] @@ -124,6 +146,15 @@ impl<'a, T: Config> EventSubscription<'a, T> { /// Gets the next event. pub async fn next(&mut self) -> Option> { + self.next_context() + .await + .map(|res| res.map(|ctx| ctx.event)) + } + /// Gets the next event with the associated block hash and its corresponding + /// event index. + pub async fn next_context( + &mut self, + ) -> Option, BasicError>> { loop { if let Some(raw_event) = self.events.pop_front() { return Some(Ok(raw_event)) @@ -144,7 +175,7 @@ impl<'a, T: Config> EventSubscription<'a, T> { match events { Err(err) => return Some(Err(err)), Ok(raw_events) => { - for (phase, raw) in raw_events { + for (phase, event_idx, raw) in raw_events { if let Some(ext_index) = self.extrinsic { if !matches!(phase, Phase::ApplyExtrinsic(i) if i as usize == ext_index) { @@ -156,7 +187,11 @@ impl<'a, T: Config> EventSubscription<'a, T> { continue } } - self.events.push_back(raw); + self.events.push_back(EventContext { + block_hash: received_hash, + event_idx, + event: raw, + }); } } } @@ -276,7 +311,7 @@ mod tests { #[async_std::test] /// test that filters work correctly, and are independent of each other async fn test_filters() { - let mut events = vec![]; + let mut events: Vec<(H256, Phase, usize, RawEvent)> = vec![]; // create all events for block_hash in [H256::from([0; 32]), H256::from([1; 32])] { for phase in [ @@ -285,14 +320,24 @@ mod tests { Phase::ApplyExtrinsic(1), Phase::Finalization, ] { - for event in [named_event("a"), named_event("b")] { - events.push((block_hash, phase.clone(), event)) - } + [named_event("a"), named_event("b")] + .iter() + .enumerate() + .for_each(|(idx, event)| { + events.push(( + block_hash, + phase.clone(), + // The event index + idx, + event.clone(), + )) + }); } } + // set variant index so we can uniquely identify the event events.iter_mut().enumerate().for_each(|(idx, event)| { - event.2.variant_index = idx as u8; + event.3.variant_index = idx as u8; }); let half_len = events.len() / 2; @@ -309,8 +354,8 @@ mod tests { Ok(events .iter() .take(half_len) - .map(|(_, phase, event)| { - (phase.clone(), event.clone()) + .map(|(_, phase, idx, event)| { + (phase.clone(), *idx, event.clone()) }) .collect()), ), @@ -319,8 +364,8 @@ mod tests { Ok(events .iter() .skip(half_len) - .map(|(_, phase, event)| { - (phase.clone(), event.clone()) + .map(|(_, phase, idx, event)| { + (phase.clone(), *idx, event.clone()) }) .collect()), ), @@ -333,21 +378,24 @@ mod tests { events: Default::default(), finished: false, }; - let mut expected_events = events.clone(); + + let mut expected_events: Vec<(H256, Phase, usize, RawEvent)> = + events.clone(); + if let Some(hash) = block_filter { - expected_events.retain(|(h, _, _)| h == &hash); + expected_events.retain(|(h, _, _, _)| h == &hash); } if let Some(idx) = extrinsic_filter { - expected_events.retain(|(_, phase, _)| matches!(phase, Phase::ApplyExtrinsic(i) if *i as usize == idx)); + expected_events.retain(|(_, phase, _, _)| matches!(phase, Phase::ApplyExtrinsic(i) if *i as usize == idx)); } if let Some(name) = event_filter { - expected_events.retain(|(_, _, event)| event.pallet == name.0); + expected_events.retain(|(_, _, _, event)| event.pallet == name.0); } for expected_event in expected_events { assert_eq!( subscription.next().await.unwrap().unwrap(), - expected_event.2 + expected_event.3 ); } assert!(subscription.next().await.is_none()); @@ -355,4 +403,79 @@ mod tests { } } } + + #[async_std::test] + async fn test_context() { + let mut events = vec![]; + // create all events + for block_hash in [H256::from([0; 32]), H256::from([1; 32])] { + for phase in [ + Phase::Initialization, + Phase::ApplyExtrinsic(0), + Phase::ApplyExtrinsic(1), + Phase::Finalization, + ] { + [named_event("a"), named_event("b")] + .iter() + .enumerate() + .for_each(|(idx, event)| { + events.push(( + phase.clone(), + EventContext { + block_hash, + event_idx: idx, + event: event.clone(), + }, + )); + }); + } + } + + // set variant index so we can uniquely identify the event + events.iter_mut().enumerate().for_each(|(idx, (_, ctx))| { + ctx.event.variant_index = idx as u8; + }); + + let half_len = events.len() / 2; + + let mut subscription: EventSubscription = EventSubscription { + block_reader: BlockReader::Mock(Box::new( + vec![ + ( + events[0].1.block_hash, + Ok(events + .iter() + .take(half_len) + .map(|(phase, ctx)| { + (phase.clone(), ctx.event_idx, ctx.event.clone()) + }) + .collect()), + ), + ( + events[half_len].1.block_hash, + Ok(events + .iter() + .skip(half_len) + .map(|(phase, ctx)| { + (phase.clone(), ctx.event_idx, ctx.event.clone()) + }) + .collect()), + ), + ] + .into_iter(), + )), + block: None, + extrinsic: None, + event: None, + events: Default::default(), + finished: false, + }; + + let expected_events = events.clone(); + + for exp in expected_events { + assert_eq!(subscription.next_context().await.unwrap().unwrap(), exp.1); + } + assert!(subscription.next().await.is_none()); + } } From 7f3f686cefe455e84b0c93d59ee9867be803fd3e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 3 Feb 2022 17:19:27 +0000 Subject: [PATCH 04/10] Update substrate dependencies (#429) * Update substrate dependencies * Update sp-keyring deps --- examples/Cargo.toml | 2 +- macro/Cargo.toml | 2 +- subxt/Cargo.toml | 6 +++--- test-runtime/Cargo.toml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e30ba4d7f0..89bd058d8e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -14,7 +14,7 @@ description = "Subxt example usage" [dev-dependencies] subxt = { path = "../subxt" } async-std = { version = "1.9.0", features = ["attributes", "tokio1"] } -sp-keyring = "4.0.0" +sp-keyring = "5.0.0" env_logger = "0.9.0" futures = "0.3.13" codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full", "bit-vec"] } diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 43b2534841..505647f045 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -33,4 +33,4 @@ subxt-codegen = { path = "../codegen", version = "0.16.0" } pretty_assertions = "1.0.0" subxt = { path = "../subxt", version = "0.16.0" } trybuild = "1.0.38" -sp-keyring = "4.0.0" +sp-keyring = "5.0.0" diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 4f3903908c..2c0400db1c 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -30,8 +30,8 @@ url = "2.2.1" subxt-macro = { version = "0.16.0", path = "../macro" } -sp-core = { version = "4.0.0", default-features = false } -sp-runtime = { version = "4.0.0", default-features = false } +sp-core = { version = "5.0.0", default-features = false } +sp-runtime = { version = "5.0.0", default-features = false } sp-version = "4.0.0" frame-metadata = "14.0.0" @@ -46,4 +46,4 @@ tempdir = "0.3.7" wabt = "0.10.0" which = "4.0.2" test-runtime = { path = "../test-runtime" } -sp-keyring = "4.0.0" +sp-keyring = "5.0.0" diff --git a/test-runtime/Cargo.toml b/test-runtime/Cargo.toml index 8848fdcd7b..032254cecc 100644 --- a/test-runtime/Cargo.toml +++ b/test-runtime/Cargo.toml @@ -5,11 +5,11 @@ edition = "2021" [dependencies] subxt = { path = "../subxt" } -sp-runtime = "4.0.0" +sp-runtime = "5.0.0" codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full", "bit-vec"] } [build-dependencies] subxt = { path = "../subxt", version = "0.16.0" } -sp-core = "4.0.0" +sp-core = "5.0.0" async-std = { version = "1.9.0", features = ["attributes", "tokio1"] } which = "4.2.2" From abd7a4145bb35d436eee49e2e3414ed006fa7ce5 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Fri, 4 Feb 2022 11:35:59 +0100 Subject: [PATCH 05/10] introduce jsonrpsee client abstraction + kill HTTP support. (#341) * PoC async rpc client * add client example should be removed from this repo * fmt * cargo fmt * subxt client tests * cargo fmt * fix some nits * try nightly for all CI jobs * need wasm also for CI * wasm for nightly run too * client: add missing features * update jsonrpsee * hacky update jsonrpsee * use jsonrpsee crates.io release * ci: pin nightly 2021-12-15 * pin nightly to 2021-12-15 * fix build * fmt * compile please * rewrite me * fixes * fixes * pre-generate metadata * fix nit * get rid of needless deps * remove embedded client * Update Cargo.toml * Update subxt/Cargo.toml * Update subxt/Cargo.toml * Update subxt/src/client.rs * Update subxt/src/rpc.rs * Update test-runtime/build.rs * cargo fmt Co-authored-by: James Wilson --- subxt/Cargo.toml | 3 +- subxt/src/client.rs | 2 +- subxt/src/rpc.rs | 212 ++++++++++++++---------------------------- test-runtime/build.rs | 21 +++-- 4 files changed, 88 insertions(+), 150 deletions(-) diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 2c0400db1c..a8ef23d64a 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -20,13 +20,12 @@ chameleon = "0.1.0" scale-info = { version = "1.0.0", features = ["bit-vec"] } futures = "0.3.13" hex = "0.4.3" -jsonrpsee = { version = "0.8.0", features = ["ws-client", "http-client"] } +jsonrpsee = { version = "0.8.0", features = ["async-client", "client-ws-transport"] } log = "0.4.14" num-traits = { version = "0.2.14", default-features = false } serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" thiserror = "1.0.24" -url = "2.2.1" subxt-macro = { version = "0.16.0", path = "../macro" } diff --git a/subxt/src/client.rs b/subxt/src/client.rs index de074214b1..bd1d6298e6 100644 --- a/subxt/src/client.rs +++ b/subxt/src/client.rs @@ -86,7 +86,7 @@ impl ClientBuilder { client } else { let url = self.url.as_deref().unwrap_or("ws://127.0.0.1:9944"); - RpcClient::try_from_url(url).await? + crate::rpc::ws_client(url).await? }; let rpc = Rpc::new(client); let (metadata, genesis_hash, runtime_version, properties) = future::join4( diff --git a/subxt/src/rpc.rs b/subxt/src/rpc.rs index e5e2d20620..0cec6a634b 100644 --- a/subxt/src/rpc.rs +++ b/subxt/src/rpc.rs @@ -46,10 +46,18 @@ use core::{ marker::PhantomData, }; use frame_metadata::RuntimeMetadataPrefixed; -use jsonrpsee::{ +pub use jsonrpsee::{ + client_transport::ws::{ + InvalidUri, + Receiver as WsReceiver, + Sender as WsSender, + Uri, + WsTransportClientBuilder, + }, core::{ client::{ - Client, + Client as RpcClient, + ClientBuilder as RpcClientBuilder, ClientT, Subscription, SubscriptionClientT, @@ -59,11 +67,7 @@ use jsonrpsee::{ Error as RpcError, JsonValue, }, - http_client::{ - HttpClient, - HttpClientBuilder, - }, - ws_client::WsClientBuilder, + rpc_params, }; use serde::{ Deserialize, @@ -193,99 +197,6 @@ pub struct RuntimeVersion { pub other: HashMap, } -/// Rpc client wrapper. -/// This is workaround because adding generic types causes the macros to fail. -#[derive(Clone)] -pub enum RpcClient { - /// JSONRPC client WebSocket transport. - WebSocket(Arc), - /// JSONRPC client HTTP transport. - // NOTE: Arc because `HttpClient` is not clone. - Http(Arc), -} - -impl RpcClient { - /// Create a new [`RpcClient`] from the given URL. - /// - /// Infers the protocol from the URL, supports: - /// - Websockets (`ws://`, `wss://`) - /// - Http (`http://`, `https://`) - pub async fn try_from_url(url: &str) -> Result { - if url.starts_with("ws://") || url.starts_with("wss://") { - let client = WsClientBuilder::default() - .max_notifs_per_subscription(4096) - .build(url) - .await?; - Ok(RpcClient::WebSocket(Arc::new(client))) - } else { - let client = HttpClientBuilder::default().build(&url)?; - Ok(RpcClient::Http(Arc::new(client))) - } - } - - /// Start a JSON-RPC request. - pub async fn request<'a, T: DeserializeOwned + std::fmt::Debug>( - &self, - method: &str, - params: &[JsonValue], - ) -> Result { - let params = Some(params.into()); - log::debug!("request {}: {:?}", method, params); - let data = match self { - RpcClient::WebSocket(inner) => inner.request(method, params).await, - RpcClient::Http(inner) => inner.request(method, params).await, - }; - log::debug!("response: {:?}", data); - data - } - - /// Start a JSON-RPC Subscription. - pub async fn subscribe<'a, T: DeserializeOwned>( - &self, - subscribe_method: &str, - params: &[JsonValue], - unsubscribe_method: &str, - ) -> Result, RpcError> { - let params = Some(params.into()); - match self { - RpcClient::WebSocket(inner) => { - inner - .subscribe(subscribe_method, params, unsubscribe_method) - .await - } - RpcClient::Http(_) => { - Err(RpcError::Custom( - "Subscriptions not supported on HTTP transport".to_owned(), - )) - } - } - } -} - -impl From for RpcClient { - fn from(client: Client) -> Self { - RpcClient::WebSocket(Arc::new(client)) - } -} - -impl From> for RpcClient { - fn from(client: Arc) -> Self { - RpcClient::WebSocket(client) - } -} - -impl From for RpcClient { - fn from(client: HttpClient) -> Self { - RpcClient::Http(Arc::new(client)) - } -} - -impl From> for RpcClient { - fn from(client: Arc) -> Self { - RpcClient::Http(client) - } -} - /// ReadProof struct returned by the RPC /// /// # Note @@ -304,7 +215,7 @@ pub struct ReadProof { /// Client for substrate rpc interfaces pub struct Rpc { /// Rpc client for sending requests. - pub client: RpcClient, + pub client: Arc, marker: PhantomData, } @@ -321,7 +232,7 @@ impl Rpc { /// Create a new [`Rpc`] pub fn new(client: RpcClient) -> Self { Self { - client, + client: Arc::new(client), marker: PhantomData, } } @@ -332,7 +243,7 @@ impl Rpc { key: &StorageKey, hash: Option, ) -> Result, BasicError> { - let params = &[to_json_value(key)?, to_json_value(hash)?]; + let params = rpc_params![key, hash]; let data = self.client.request("state_getStorage", params).await?; Ok(data) } @@ -348,12 +259,7 @@ impl Rpc { hash: Option, ) -> Result, BasicError> { let prefix = prefix.map(|p| p.to_storage_key()); - let params = &[ - to_json_value(prefix)?, - to_json_value(count)?, - to_json_value(start_key)?, - to_json_value(hash)?, - ]; + let params = rpc_params![prefix, count, start_key, hash]; let data = self.client.request("state_getKeysPaged", params).await?; Ok(data) } @@ -365,11 +271,7 @@ impl Rpc { from: T::Hash, to: Option, ) -> Result>, BasicError> { - let params = &[ - to_json_value(keys)?, - to_json_value(from)?, - to_json_value(to)?, - ]; + let params = rpc_params![keys, from, to]; self.client .request("state_queryStorage", params) .await @@ -382,7 +284,7 @@ impl Rpc { keys: &[StorageKey], at: Option, ) -> Result>, BasicError> { - let params = &[to_json_value(keys)?, to_json_value(at)?]; + let params = rpc_params![keys, at]; self.client .request("state_queryStorageAt", params) .await @@ -392,7 +294,7 @@ impl Rpc { /// Fetch the genesis hash pub async fn genesis_hash(&self) -> Result { let block_zero = Some(ListOrValue::Value(NumberOrHex::Number(0))); - let params = &[to_json_value(block_zero)?]; + let params = rpc_params![block_zero]; let list_or_value: ListOrValue> = self.client.request("chain_getBlockHash", params).await?; match list_or_value { @@ -405,7 +307,10 @@ impl Rpc { /// Fetch the metadata pub async fn metadata(&self) -> Result { - let bytes: Bytes = self.client.request("state_getMetadata", &[]).await?; + let bytes: Bytes = self + .client + .request("state_getMetadata", rpc_params![]) + .await?; let meta: RuntimeMetadataPrefixed = Decode::decode(&mut &bytes[..])?; let metadata: Metadata = meta.try_into()?; Ok(metadata) @@ -413,22 +318,25 @@ impl Rpc { /// Fetch system properties pub async fn system_properties(&self) -> Result { - Ok(self.client.request("system_properties", &[]).await?) + Ok(self + .client + .request("system_properties", rpc_params![]) + .await?) } /// Fetch system chain pub async fn system_chain(&self) -> Result { - Ok(self.client.request("system_chain", &[]).await?) + Ok(self.client.request("system_chain", rpc_params![]).await?) } /// Fetch system name pub async fn system_name(&self) -> Result { - Ok(self.client.request("system_name", &[]).await?) + Ok(self.client.request("system_name", rpc_params![]).await?) } /// Fetch system version pub async fn system_version(&self) -> Result { - Ok(self.client.request("system_version", &[]).await?) + Ok(self.client.request("system_version", rpc_params![]).await?) } /// Get a header @@ -436,7 +344,7 @@ impl Rpc { &self, hash: Option, ) -> Result, BasicError> { - let params = &[to_json_value(hash)?]; + let params = rpc_params![hash]; let header = self.client.request("chain_getHeader", params).await?; Ok(header) } @@ -447,7 +355,7 @@ impl Rpc { block_number: Option, ) -> Result, BasicError> { let block_number = block_number.map(ListOrValue::Value); - let params = &[to_json_value(block_number)?]; + let params = rpc_params![block_number]; let list_or_value = self.client.request("chain_getBlockHash", params).await?; match list_or_value { ListOrValue::Value(hash) => Ok(hash), @@ -457,7 +365,10 @@ impl Rpc { /// Get a block hash of the latest finalized block pub async fn finalized_head(&self) -> Result { - let hash = self.client.request("chain_getFinalizedHead", &[]).await?; + let hash = self + .client + .request("chain_getFinalizedHead", rpc_params![]) + .await?; Ok(hash) } @@ -466,7 +377,7 @@ impl Rpc { &self, hash: Option, ) -> Result>, BasicError> { - let params = &[to_json_value(hash)?]; + let params = rpc_params![hash]; let block = self.client.request("chain_getBlock", params).await?; Ok(block) } @@ -477,7 +388,7 @@ impl Rpc { keys: Vec, hash: Option, ) -> Result, BasicError> { - let params = &[to_json_value(keys)?, to_json_value(hash)?]; + let params = rpc_params![keys, hash]; let proof = self.client.request("state_getReadProof", params).await?; Ok(proof) } @@ -487,7 +398,7 @@ impl Rpc { &self, at: Option, ) -> Result { - let params = &[to_json_value(at)?]; + let params = rpc_params![at]; let version = self .client .request("state_getRuntimeVersion", params) @@ -503,7 +414,7 @@ impl Rpc { &self, ) -> Result, BasicError> { let keys = Some(vec![StorageKey::from(SystemEvents::new())]); - let params = &[to_json_value(keys)?]; + let params = rpc_params![keys]; let subscription = self .client @@ -528,7 +439,11 @@ impl Rpc { pub async fn subscribe_blocks(&self) -> Result, BasicError> { let subscription = self .client - .subscribe("chain_subscribeNewHeads", &[], "chain_unsubscribeNewHeads") + .subscribe( + "chain_subscribeNewHeads", + rpc_params![], + "chain_unsubscribeNewHeads", + ) .await?; Ok(subscription) @@ -542,7 +457,7 @@ impl Rpc { .client .subscribe( "chain_subscribeFinalizedHeads", - &[], + rpc_params![], "chain_unsubscribeFinalizedHeads", ) .await?; @@ -555,7 +470,7 @@ impl Rpc { extrinsic: X, ) -> Result { let bytes: Bytes = extrinsic.encode().into(); - let params = &[to_json_value(bytes)?]; + let params = rpc_params![bytes]; let xt_hash = self .client .request("author_submitExtrinsic", params) @@ -570,7 +485,7 @@ impl Rpc { ) -> Result>, BasicError> { let bytes: Bytes = extrinsic.encode().into(); - let params = &[to_json_value(bytes)?]; + let params = rpc_params![bytes]; let subscription = self .client .subscribe( @@ -589,18 +504,17 @@ impl Rpc { suri: String, public: Bytes, ) -> Result<(), BasicError> { - let params = &[ - to_json_value(key_type)?, - to_json_value(suri)?, - to_json_value(public)?, - ]; + let params = rpc_params![key_type, suri, public]; self.client.request("author_insertKey", params).await?; Ok(()) } /// Generate new session keys and returns the corresponding public keys. pub async fn rotate_keys(&self) -> Result { - Ok(self.client.request("author_rotateKeys", &[]).await?) + Ok(self + .client + .request("author_rotateKeys", rpc_params![]) + .await?) } /// Checks if the keystore has private keys for the given session public keys. @@ -612,7 +526,7 @@ impl Rpc { &self, session_keys: Bytes, ) -> Result { - let params = &[to_json_value(session_keys)?]; + let params = rpc_params![session_keys]; Ok(self.client.request("author_hasSessionKeys", params).await?) } @@ -624,11 +538,29 @@ impl Rpc { public_key: Bytes, key_type: String, ) -> Result { - let params = &[to_json_value(public_key)?, to_json_value(key_type)?]; + let params = rpc_params![public_key, key_type]; Ok(self.client.request("author_hasKey", params).await?) } } +/// Build WS RPC client from URL +pub async fn ws_client(url: &str) -> Result { + let (sender, receiver) = ws_transport(url).await?; + Ok(RpcClientBuilder::default() + .max_notifs_per_subscription(4096) + .build(sender, receiver)) +} + +async fn ws_transport(url: &str) -> Result<(WsSender, WsReceiver), RpcError> { + let url: Uri = url + .parse() + .map_err(|e: InvalidUri| RpcError::Transport(e.into()))?; + WsTransportClientBuilder::default() + .build(url) + .await + .map_err(|e| RpcError::Transport(e.into())) +} + #[cfg(test)] mod test { use super::*; diff --git a/test-runtime/build.rs b/test-runtime/build.rs index 71a075a37a..e82f8863ec 100644 --- a/test-runtime/build.rs +++ b/test-runtime/build.rs @@ -31,6 +31,10 @@ use std::{ thread, time, }; +use subxt::rpc::{ + self, + ClientT, +}; static SUBSTRATE_BIN_ENV_VAR: &str = "SUBSTRATE_NODE_PATH"; @@ -50,7 +54,7 @@ async fn run() { let cmd = Command::new(&substrate_bin) .arg("--dev") .arg("--tmp") - .arg(format!("--rpc-port={}", port)) + .arg(format!("--ws-port={}", port)) .spawn(); let mut cmd = match cmd { Ok(cmd) => KillOnDrop(cmd), @@ -63,16 +67,19 @@ async fn run() { let metadata_bytes: sp_core::Bytes = { const MAX_RETRIES: usize = 20; let mut retries = 0; + loop { if retries >= MAX_RETRIES { panic!("Cannot connect to substrate node after {} retries", retries); } - let res = - subxt::RpcClient::try_from_url(&format!("http://localhost:{}", port)) - .await - .expect("should only error if malformed URL for an HTTP connection") - .request("state_getMetadata", &[]) - .await; + + // It might take a while for substrate node that spin up the RPC server. + // Thus, the connection might get rejected a few times. + let res = match rpc::ws_client(&format!("ws://localhost:{}", port)).await { + Ok(c) => c.request("state_getMetadata", None).await, + Err(e) => Err(e), + }; + match res { Ok(res) => { let _ = cmd.kill(); From 868b465e01a839d25449a7fa8de91a448fef826e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 4 Feb 2022 12:46:39 +0200 Subject: [PATCH 06/10] Add more tests for `events.rs/decode_and_consume_type` (#430) * test-runtime: Fix README typo Signed-off-by: Alexandru Vasile * test-runtime: Explicit error handling for missing substrate binary Signed-off-by: Alexandru Vasile * test-runtime: Fix documentation typo Signed-off-by: Alexandru Vasile * events: Test primitive decode_and_consume Signed-off-by: Alexandru Vasile * events: Test tuple decode_and_consume Signed-off-by: Alexandru Vasile * events: Test array decode_and_consume Signed-off-by: Alexandru Vasile * events: Extend array with sequences Signed-off-by: Alexandru Vasile * events: Test variant decode_and_consume Signed-off-by: Alexandru Vasile * events: Test composite decode_and_consume Signed-off-by: Alexandru Vasile * events: Test compact decode_and_consume Signed-off-by: Alexandru Vasile --- subxt/src/events.rs | 188 +++++++++++++++++++++++++++++++++++++++++ test-runtime/README.md | 4 +- test-runtime/build.rs | 6 +- 3 files changed, 195 insertions(+), 3 deletions(-) diff --git a/subxt/src/events.rs b/subxt/src/events.rs index d7f5fb9e93..e637774d9a 100644 --- a/subxt/src/events.rs +++ b/subxt/src/events.rs @@ -373,10 +373,17 @@ pub enum EventsDecodingError { mod tests { use super::*; use crate::{ + error::GenericError::{ + Codec, + EventsDecoding, + Other, + }, + events::EventsDecodingError::UnsupportedPrimitive, Config, DefaultConfig, Phase, }; + use assert_matches::assert_matches; use codec::Encode; use frame_metadata::{ v14::{ @@ -643,4 +650,185 @@ mod tests { bitvec::bitvec![Msb0, u64; 0, 1, 1, 0, 1, 0, 1, 0, 0], ); } + + #[test] + fn decode_primitive() { + decode_and_consume_type_consumes_all_bytes(false); + decode_and_consume_type_consumes_all_bytes(true); + + let dummy_data = vec![0u8]; + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!( + res, + Err(EventsDecoding(UnsupportedPrimitive(TypeDefPrimitive::Char))) + ); + + decode_and_consume_type_consumes_all_bytes("str".to_string()); + + decode_and_consume_type_consumes_all_bytes(1u8); + decode_and_consume_type_consumes_all_bytes(1i8); + + decode_and_consume_type_consumes_all_bytes(1u16); + decode_and_consume_type_consumes_all_bytes(1i16); + + decode_and_consume_type_consumes_all_bytes(1u32); + decode_and_consume_type_consumes_all_bytes(1i32); + + decode_and_consume_type_consumes_all_bytes(1u64); + decode_and_consume_type_consumes_all_bytes(1i64); + + decode_and_consume_type_consumes_all_bytes(1u128); + decode_and_consume_type_consumes_all_bytes(1i128); + } + + #[test] + fn decode_tuple() { + decode_and_consume_type_consumes_all_bytes(()); + + decode_and_consume_type_consumes_all_bytes((true,)); + + decode_and_consume_type_consumes_all_bytes((true, "str")); + + // Incomplete bytes for decoding + let dummy_data = false.encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::<(bool, &'static str)>(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Codec(_))); + + // Incomplete bytes for decoding, with invalid char type + let dummy_data = (false, "str", 0u8).encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::<(bool, &'static str, char)>(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!( + res, + Err(EventsDecoding(UnsupportedPrimitive(TypeDefPrimitive::Char))) + ); + // The last byte (0x0 u8) should not be consumed + assert_eq!(dummy_cursor.len(), 1); + } + + #[test] + fn decode_array_and_seq() { + decode_and_consume_type_consumes_all_bytes([0]); + decode_and_consume_type_consumes_all_bytes([1, 2, 3, 4, 5]); + decode_and_consume_type_consumes_all_bytes([0; 500]); + decode_and_consume_type_consumes_all_bytes(["str", "abc", "cde"]); + + decode_and_consume_type_consumes_all_bytes(vec![0]); + decode_and_consume_type_consumes_all_bytes(vec![1, 2, 3, 4, 5]); + decode_and_consume_type_consumes_all_bytes(vec!["str", "abc", "cde"]); + } + + #[test] + fn decode_variant() { + #[derive(Clone, Encode, TypeInfo)] + enum EnumVar { + A, + B((&'static str, u8)), + C { named: i16 }, + } + const INVALID_TYPE_ID: u32 = 1024; + + decode_and_consume_type_consumes_all_bytes(EnumVar::A); + decode_and_consume_type_consumes_all_bytes(EnumVar::B(("str", 1))); + decode_and_consume_type_consumes_all_bytes(EnumVar::C { named: 1 }); + + // Invalid variant index + let dummy_data = 3u8.encode(); + let dummy_cursor = &mut &*dummy_data; + let (id, reg) = singleton_type_registry::(); + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Other(_))); + + // Valid index, incomplete data + let dummy_data = 2u8.encode(); + let dummy_cursor = &mut &*dummy_data; + let res = decode_and_consume_type(id.id(), ®, dummy_cursor); + assert_matches!(res, Err(Codec(_))); + + let res = decode_and_consume_type(INVALID_TYPE_ID, ®, dummy_cursor); + assert_matches!(res, Err(crate::error::GenericError::Metadata(_))); + } + + #[test] + fn decode_composite() { + #[derive(Clone, Encode, TypeInfo)] + struct Composite {} + decode_and_consume_type_consumes_all_bytes(Composite {}); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV2 { + id: u32, + name: String, + } + decode_and_consume_type_consumes_all_bytes(CompositeV2 { + id: 10, + name: "str".to_string(), + }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV3 { + id: u32, + extra: T, + } + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: vec![0, 1, 2], + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: bitvec::bitvec![Lsb0, u8; 0, 1, 1, 0, 1], + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: ("str", 1), + }); + decode_and_consume_type_consumes_all_bytes(CompositeV3 { + id: 10, + extra: CompositeV2 { + id: 2, + name: "str".to_string(), + }, + }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV4(u32, bool); + decode_and_consume_type_consumes_all_bytes(CompositeV4(1, true)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompositeV5(u32); + decode_and_consume_type_consumes_all_bytes(CompositeV5(1)); + } + + #[test] + fn decode_compact() { + #[derive(Clone, Encode, TypeInfo)] + enum Compact { + A(#[codec(compact)] u32), + } + decode_and_consume_type_consumes_all_bytes(Compact::A(1)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV2(#[codec(compact)] u32); + decode_and_consume_type_consumes_all_bytes(CompactV2(1)); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV3 { + #[codec(compact)] + val: u32, + } + decode_and_consume_type_consumes_all_bytes(CompactV3 { val: 1 }); + + #[derive(Clone, Encode, TypeInfo)] + struct CompactV4 { + #[codec(compact)] + val: T, + } + decode_and_consume_type_consumes_all_bytes(CompactV4 { val: 0u8 }); + decode_and_consume_type_consumes_all_bytes(CompactV4 { val: 1u16 }); + } } diff --git a/test-runtime/README.md b/test-runtime/README.md index 9763412df2..07cc531360 100644 --- a/test-runtime/README.md +++ b/test-runtime/README.md @@ -3,8 +3,8 @@ The logic for this crate exists mainly in the `build.rs` file. At compile time, this crate will: -- Spin up a local `substrate` binary (set the `SUBSTRATE_NODE_PATH` env var to point to a custom binary, otehrwise it'll look for `substrate` on your PATH). +- Spin up a local `substrate` binary (set the `SUBSTRATE_NODE_PATH` env var to point to a custom binary, otherwise it'll look for `substrate` on your PATH). - Obtain metadata from this node. - Export the metadata and a `node_runtime` module which has been annotated using the `subxt` proc macro and is based off the above metadata. -The reason for doing this is that our integration tests (which also spin up a Substrate node) can then use the generated `subxt` types from the exact node being tested against, so that we don't have to worry about metadata getting out of sync with the binary under test. \ No newline at end of file +The reason for doing this is that our integration tests (which also spin up a Substrate node) can then use the generated `subxt` types from the exact node being tested against, so that we don't have to worry about metadata getting out of sync with the binary under test. diff --git a/test-runtime/build.rs b/test-runtime/build.rs index e82f8863ec..300bd82fe9 100644 --- a/test-runtime/build.rs +++ b/test-runtime/build.rs @@ -58,6 +58,10 @@ async fn run() { .spawn(); let mut cmd = match cmd { Ok(cmd) => KillOnDrop(cmd), + Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => { + panic!("A substrate binary should be installed on your path for testing purposes. \ + See https://github.com/paritytech/subxt/tree/master#integration-testing") + } Err(e) => { panic!("Cannot spawn substrate command '{}': {}", substrate_bin, e) } @@ -164,7 +168,7 @@ fn next_open_port() -> Option { } } -/// If the substrate process isn't explicilty killed on drop, +/// If the substrate process isn't explicitly killed on drop, /// it seems that panics that occur while the command is running /// will leave it running and block the build step from ever finishing. /// Wrapping it in this prevents this from happening. From e9be43aaff6fd4a19de81c9a2940764be1ec829c Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 4 Feb 2022 15:44:56 +0200 Subject: [PATCH 07/10] Release preparation for v0.17.0 (#434) * lib: Export `GenericError` to avoid linking to private items Signed-off-by: Alexandru Vasile * Bump version to v0.17.0 Signed-off-by: Alexandru Vasile * doc: Add crates to bump Signed-off-by: Alexandru Vasile * Update changelog Signed-off-by: Alexandru Vasile * changelog: Add new line between title and list Signed-off-by: Alexandru Vasile * releasing: Remove extra closing bracket Signed-off-by: Alexandru Vasile * releasing: Fix cargo install typo for cargo-hack Signed-off-by: Alexandru Vasile * Remove subxt version from macro and test-runtime Signed-off-by: Alexandru Vasile * releasing: Change PR link to sort in descending order Signed-off-by: Alexandru Vasile * changelog: Add missing PR Signed-off-by: Alexandru Vasile --- CHANGELOG.md | 16 ++++++++++++++++ RELEASING.md | 10 +++++----- cli/Cargo.toml | 4 ++-- codegen/Cargo.toml | 2 +- examples/Cargo.toml | 2 +- macro/Cargo.toml | 6 +++--- subxt/Cargo.toml | 4 ++-- subxt/src/lib.rs | 1 + test-runtime/Cargo.toml | 4 ++-- 9 files changed, 33 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a04a13c1..53fb99055a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.17.0] - 2022-02-04 + +### Added + +- introduce jsonrpsee client abstraction + kill HTTP support. ([#341](https://github.com/paritytech/subxt/pull/341)) +- Get event context on EventSubscription ([#423](https://github.com/paritytech/subxt/pull/423)) + +### Changed + +- Add more tests for events.rs/decode_and_consume_type ([#430](https://github.com/paritytech/subxt/pull/430)) +- Update substrate dependencies ([#429](https://github.com/paritytech/subxt/pull/429)) +- export RuntimeError struct ([#427](https://github.com/paritytech/subxt/pull/427)) +- remove unused PalletError struct ([#425](https://github.com/paritytech/subxt/pull/425)) +- Move Subxt crate into a subfolder ([#424](https://github.com/paritytech/subxt/pull/424)) +- Add release checklist ([#418](https://github.com/paritytech/subxt/pull/418)) + ## [0.16.0] - 2022-02-01 *Note*: This is a significant release which introduces support for V14 metadata and macro based codegen, as well as making many breaking changes to the API. diff --git a/RELEASING.md b/RELEASING.md index 53ff0cf34d..3685873b0c 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -26,12 +26,12 @@ We also assume that ongoing work done is being merged directly to the `master` b If there are minor issues with the documentation, they can be fixed in the release branch. -4. Bump the crate version in `Cargo.toml` to whatever was decided in step 2 for `subxt-codegen`, `subxt-macro`, `subxt` and `subxt-cli`. +4. Bump the crate version in `Cargo.toml` to whatever was decided in step 2 for `subxt-cli`, `subxt-codegen`, `subxt-examples`, `subxt-macro` ,`subxt`, `test-runtime`. 5. Update `CHANGELOG.md` to reflect the difference between this release and the last. If you're unsure of what to add, check with the Tools team. See the `CHANGELOG.md` file for details of the format it follows. - Any [closed PRs](https://github.com/paritytech/subxt/pulls?q=is%3Apr+is%3Aclosed) between the last release and + Any [closed PRs](https://github.com/paritytech/subxt/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aclosed) between the last release and this release branch should be noted. 6. Commit any of the above changes to the release branch and open a PR in GitHub with a base of `master`. @@ -46,8 +46,8 @@ We also assume that ongoing work done is being merged directly to the `master` b Additionally, `subxt-macro` has a circular dev dependency on `subxt`, so we use `cargo hack` to remove dev dependencies (and `--allow-dirty` to ignore the git changes as a result) to publish it. - So, first install `cargo hack` with `cargo install cargo hack`. Next, you can run something like the following - command to publish each crate in the required order (allowing a little time inbetween each to let `crates.io` catch up) + So, first install [cargo-hack](https://docs.rs/crate/cargo-hack/latest) with `cargo install cargo-hack`. Next, you can run something like the following + command to publish each crate in the required order (allowing a little time in between each to let `crates.io` catch up with what we've published). ``` @@ -73,4 +73,4 @@ We also assume that ongoing work done is being merged directly to the `master` b Once this is pushed, go along to [the releases page on GitHub](https://github.com/paritytech/subxt/releases) and draft a new release which points to the tag you just pushed to `master` above. Copy the changelog comments - for the current release into the release description. \ No newline at end of file + for the current release into the release description. diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3ad6e99bff..916999e367 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-cli" -version = "0.16.0" +version = "0.17.0" authors = ["Parity Technologies "] edition = "2021" @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] # perform subxt codegen -subxt-codegen = { version = "0.16.0", path = "../codegen" } +subxt-codegen = { version = "0.17.0", path = "../codegen" } # parse command line args structopt = "0.3.25" # make the request to a substrate node to get the metadata diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index ea41458b7b..c2cf3c551d 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-codegen" -version = "0.16.0" +version = "0.17.0" authors = ["Parity Technologies "] edition = "2021" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 89bd058d8e..8d8cbf21b1 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-examples" -version = "0.16.0" +version = "0.17.0" authors = ["Parity Technologies "] edition = "2021" publish = false diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 505647f045..b1267735e4 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt-macro" -version = "0.16.0" +version = "0.17.0" authors = ["Parity Technologies "] edition = "2021" autotests = false @@ -27,10 +27,10 @@ quote = "1.0.8" syn = "1.0.58" scale-info = "1.0.0" -subxt-codegen = { path = "../codegen", version = "0.16.0" } +subxt-codegen = { path = "../codegen", version = "0.17.0" } [dev-dependencies] pretty_assertions = "1.0.0" -subxt = { path = "../subxt", version = "0.16.0" } +subxt = { path = "../subxt" } trybuild = "1.0.38" sp-keyring = "5.0.0" diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index a8ef23d64a..4c01d8e35b 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "subxt" -version = "0.16.0" +version = "0.17.0" authors = ["Parity Technologies "] edition = "2021" @@ -27,7 +27,7 @@ serde = { version = "1.0.124", features = ["derive"] } serde_json = "1.0.64" thiserror = "1.0.24" -subxt-macro = { version = "0.16.0", path = "../macro" } +subxt-macro = { version = "0.17.0", path = "../macro" } sp-core = { version = "5.0.0", default-features = false } sp-runtime = { version = "5.0.0", default-features = false } diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index e4e5668fc6..50aac73692 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -81,6 +81,7 @@ pub use crate::{ error::{ BasicError, Error, + GenericError, RuntimeError, TransactionError, }, diff --git a/test-runtime/Cargo.toml b/test-runtime/Cargo.toml index 032254cecc..fdd63aedc7 100644 --- a/test-runtime/Cargo.toml +++ b/test-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test-runtime" -version = "0.16.0" +version = "0.17.0" edition = "2021" [dependencies] @@ -9,7 +9,7 @@ sp-runtime = "5.0.0" codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full", "bit-vec"] } [build-dependencies] -subxt = { path = "../subxt", version = "0.16.0" } +subxt = { path = "../subxt" } sp-core = "5.0.0" async-std = { version = "1.9.0", features = ["attributes", "tokio1"] } which = "4.2.2" From 19ae2aa9eed8304e5cd12f9a143ea0d94e3c61cf Mon Sep 17 00:00:00 2001 From: James Wilson Date: Fri, 4 Feb 2022 17:45:45 +0000 Subject: [PATCH 08/10] Set "std" feature on sp-runtime to avoid a static assertion error (#438) * apply std feature to runtime to avoid static assertion error * std is a default feature anyway --- subxt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/Cargo.toml b/subxt/Cargo.toml index 4c01d8e35b..dd22638ba8 100644 --- a/subxt/Cargo.toml +++ b/subxt/Cargo.toml @@ -30,7 +30,7 @@ thiserror = "1.0.24" subxt-macro = { version = "0.17.0", path = "../macro" } sp-core = { version = "5.0.0", default-features = false } -sp-runtime = { version = "5.0.0", default-features = false } +sp-runtime = "5.0.0" sp-version = "4.0.0" frame-metadata = "14.0.0" From a7c54f74127b58dd0886b9f42b1f7318dfbc51f4 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Fri, 4 Feb 2022 19:58:35 +0200 Subject: [PATCH 09/10] Update release documentation with dry-run (#435) * releasing: Remove cargo-hack from doc Signed-off-by: Alexandru Vasile * releasing: Add dry-run step Signed-off-by: Alexandru Vasile * releasing: Remove sleep from dry-run step Signed-off-by: Alexandru Vasile --- RELEASING.md | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 3685873b0c..6972ffb341 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -40,28 +40,38 @@ We also assume that ongoing work done is being merged directly to the `master` b 8. Now, we're ready to publish the release to crates.io. - Checkout `master`, ensuring we're looking at that latest merge (`git pull`). + 1. Checkout `master`, ensuring we're looking at that latest merge (`git pull`). - The crates in this repository need publishing in a specific order, since they depend on each other. - Additionally, `subxt-macro` has a circular dev dependency on `subxt`, so we use `cargo hack` to remove - dev dependencies (and `--allow-dirty` to ignore the git changes as a result) to publish it. + ``` + git checkout master && git pull + ``` - So, first install [cargo-hack](https://docs.rs/crate/cargo-hack/latest) with `cargo install cargo-hack`. Next, you can run something like the following - command to publish each crate in the required order (allowing a little time in between each to let `crates.io` catch up - with what we've published). + 2. Perform a dry-run publish to ensure the crates can be correctly published. - ``` - (cd codegen && cargo publish) && \ - sleep 10 && \ - (cd macro && cargo hack publish --no-dev-deps --allow-dirty) && \ - sleep 10 && \ - (cd subxt && cargo publish) && \ - sleep 10 && \ - (cd cli && cargo publish); - ``` + The crates in this repository need publishing in a specific order, since they depend on each other. - If you run into any issues regarding crates not being able to find suitable versions of other `subxt-*` crates, - you may just need to wait a little longer and then run the remaining portion of that command. + ``` + (cd codegen && cargo publish --dry-run) && \ + (cd macro && cargo publish --dry-run) && \ + (cd subxt && cargo publish --dry-run) && \ + (cd cli && cargo publish --dry-run); + ``` + + 3. If the dry-run was successful, run the following command to publish each crate in the required order (allowing + a little time in between each to let crates.io catch up with what we've published). + + ``` + (cd codegen && cargo publish) && \ + sleep 10 && \ + (cd macro && cargo publish) && \ + sleep 10 && \ + (cd subxt && cargo publish) && \ + sleep 10 && \ + (cd cli && cargo publish); + ``` + + If you run into any issues regarding crates not being able to find suitable versions of other `subxt-*` crates, + you may just need to wait a little longer and then run the remaining portion of that command. 9. If the release was successful, tag the commit that we released in the `master` branch with the version that we just released, for example: From 4bed7eb7161ac3cdafe55ac7a186401ea94bba90 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 10 Feb 2022 13:10:27 +0000 Subject: [PATCH 10/10] Fix conversion of `Call` struct names to UpperCamelCase (#441) * Fix conversion of `Call` struct names to UpperCamelCase * Update to latest heck and use ToUpperCamelCase --- codegen/Cargo.toml | 2 +- codegen/src/api/calls.rs | 6 +++--- codegen/src/api/constants.rs | 2 +- codegen/src/api/mod.rs | 4 ++-- codegen/src/api/storage.rs | 2 +- macro/Cargo.toml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index c2cf3c551d..75965e344f 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.49" codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full", "bit-vec"] } darling = "0.13.0" frame-metadata = "14.0" -heck = "0.3.2" +heck = "0.4.0" proc-macro2 = "1.0.24" proc-macro-crate = "0.1.5" proc-macro-error = "1.0.4" diff --git a/codegen/src/api/calls.rs b/codegen/src/api/calls.rs index 96fc12fc9c..f6e1e00d87 100644 --- a/codegen/src/api/calls.rs +++ b/codegen/src/api/calls.rs @@ -23,8 +23,8 @@ use frame_metadata::{ PalletMetadata, }; use heck::{ - CamelCase as _, - SnakeCase as _, + ToSnakeCase as _, + ToUpperCamelCase as _, }; use proc_macro2::TokenStream as TokenStream2; use proc_macro_error::abort_call_site; @@ -43,7 +43,7 @@ pub fn generate_calls( let struct_defs = super::generate_structs_from_variants( type_gen, call.ty.id(), - |name| name.to_camel_case().into(), + |name| name.to_upper_camel_case().into(), "Call", ); let (call_structs, call_fns): (Vec<_>, Vec<_>) = struct_defs diff --git a/codegen/src/api/constants.rs b/codegen/src/api/constants.rs index 7cbb988450..d7786a6b39 100644 --- a/codegen/src/api/constants.rs +++ b/codegen/src/api/constants.rs @@ -16,7 +16,7 @@ use crate::types::TypeGenerator; use frame_metadata::PalletConstantMetadata; -use heck::SnakeCase as _; +use heck::ToSnakeCase as _; use proc_macro2::TokenStream as TokenStream2; use quote::{ format_ident, diff --git a/codegen/src/api/mod.rs b/codegen/src/api/mod.rs index d11071f156..651328261d 100644 --- a/codegen/src/api/mod.rs +++ b/codegen/src/api/mod.rs @@ -54,7 +54,7 @@ use frame_metadata::{ RuntimeMetadataPrefixed, StorageEntryType, }; -use heck::SnakeCase as _; +use heck::ToSnakeCase as _; use proc_macro2::TokenStream as TokenStream2; use proc_macro_error::abort_call_site; use quote::{ @@ -462,7 +462,7 @@ where type_gen, ); CompositeDef::struct_def( - var.name(), + struct_name.as_ref(), Default::default(), fields, Some(parse_quote!(pub)), diff --git a/codegen/src/api/storage.rs b/codegen/src/api/storage.rs index 6e2065c8a8..1a6a8bb5ce 100644 --- a/codegen/src/api/storage.rs +++ b/codegen/src/api/storage.rs @@ -23,7 +23,7 @@ use frame_metadata::{ StorageEntryType, StorageHasher, }; -use heck::SnakeCase as _; +use heck::ToSnakeCase as _; use proc_macro2::TokenStream as TokenStream2; use proc_macro_error::abort_call_site; use quote::{ diff --git a/macro/Cargo.toml b/macro/Cargo.toml index b1267735e4..c8165e2da6 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -19,7 +19,7 @@ async-trait = "0.1.49" codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full"] } darling = "0.13.0" frame-metadata = "14.0" -heck = "0.3.2" +heck = "0.4.0" proc-macro2 = "1.0.24" proc-macro-crate = "0.1.5" proc-macro-error = "1.0.4"