From d54df245697fe2cf61a7d7783639b9fa383f844b Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 15 Jun 2022 17:53:08 +0300 Subject: [PATCH 1/6] Fix documentation examples Signed-off-by: Alexandru Vasile --- codegen/src/lib.rs | 7 ++++-- docs/subxt.md | 50 ++++++++++++++++++++++++++++++++++------- subxt/src/client.rs | 36 +++++++++++++++++++++-------- subxt/src/events/mod.rs | 44 ++++++++++++++++++++++++++++++------ subxt/src/rpc.rs | 50 ++++++++++++++++++++++++++++++++--------- subxt/src/storage.rs | 46 ++++++++++++++++++++++++++++++++----- subxt/src/updates.rs | 14 +++++++++++- 7 files changed, 204 insertions(+), 43 deletions(-) diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 8f4cd9e023..497269ab15 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -29,13 +29,16 @@ //! //! ## Example //! -//! ```rust +//! ```no_run +//! use std::fs; //! use codec::Decode; //! use frame_metadata::RuntimeMetadataPrefixed; //! use subxt_codegen::DerivesRegistry; //! +//! let encoded = fs::read("../artifacts/polkadot_metadata.scale").unwrap(); +//! //! // Runtime metadata obtained from a node. -//! let metadata = ::decode(encoded)?; +//! let metadata = ::decode(&mut &*encoded).unwrap(); //! // Module under which the API is generated. //! let item_mod = syn::parse_quote!( //! pub mod api {} diff --git a/docs/subxt.md b/docs/subxt.md index 66c825609c..65ccf8a18d 100644 --- a/docs/subxt.md +++ b/docs/subxt.md @@ -14,7 +14,7 @@ Subxt generates a runtime API from downloaded static metadata. The metadata can To generate the runtime API, use the `subxt` attribute which points at downloaded static metadata. -```rust +```ignore #[subxt::subxt(runtime_metadata_path = "metadata.scale")] pub mod node_runtime { } ``` @@ -38,14 +38,21 @@ For more information regarding the `node_runtime` hierarchy, please visit the ### Initializing the API client -```rust +```no_run use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +pub mod polkadot {} + +# #[tokio::main] +# async fn main() { let api = ClientBuilder::new() .set_url("wss://rpc.polkadot.io:443") .build() - .await? - .to_runtime_api::>>(); + .await + .unwrap() + .to_runtime_api::>>(); +# } ``` The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user @@ -116,21 +123,48 @@ call suffered changes. Full metadata validation: -```rust +```no_run +# use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +# #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +# pub mod polkadot {} +# #[tokio::main] +# async fn main() { +# let api = ClientBuilder::new() +# .build() +# .await +# .unwrap() +# .to_runtime_api::>>(); // To make sure that all of our statically generated pallets are compatible with the // runtime node, we can run this check: -api.validate_metadata()?; +api.validate_metadata().unwrap(); +# } ``` Call level validation: -```rust +```ignore +# use sp_keyring::AccountKeyring; +# use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +# #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +# pub mod polkadot {} +# #[tokio::main] +# async fn main() { +# let api = ClientBuilder::new() +# .build() +# .await +# .unwrap() +# .to_runtime_api::>>(); +// Submit the `transfer` extrinsic from Alice's account to Bob's. +let dest = AccountKeyring::Bob.to_account_id().into(); + let extrinsic = api .tx() .balances() // Constructing an extrinsic will fail if the metadata // is not in sync with the generated API. - .transfer(dest, 123_456_789_012_345)?; + .transfer(dest, 123_456_789_012_345) + .unwrap(); +# } ``` ### Runtime Updates diff --git a/subxt/src/client.rs b/subxt/src/client.rs index cf847de601..9ef8591f24 100644 --- a/subxt/src/client.rs +++ b/subxt/src/client.rs @@ -97,17 +97,23 @@ impl ClientBuilder { self } - /// Creates a new Client. + /// Builder for [Client]. /// - /// # Example + /// # Examples /// - /// ```rust + /// ```no_run /// use subxt::{ClientBuilder, DefaultConfig}; /// - /// let client = ClientBuilder::new() - /// .set_url("wss://rpc.polkadot.io:443") - /// .build::() - /// .await?; + /// #[tokio::main] + /// async fn main() { + /// // Build the client. + /// let client = ClientBuilder::new() + /// .set_url("wss://rpc.polkadot.io:443") + /// .build::() + /// .await + /// .unwrap(); + /// // Use the client... + /// } /// ``` pub async fn build(self) -> Result, BasicError> { let client = if let Some(client) = self.client { @@ -208,14 +214,26 @@ impl Client { /// performing runtime updates, while the API is still in use. /// Without performing runtime updates the submitted extrinsics may fail. /// - /// # Example + /// # Examples /// - /// ```rust + /// ```no_run + /// # use subxt::{ClientBuilder, DefaultConfig}; + /// # + /// # #[tokio::main] + /// # async fn main() { + /// # let client = ClientBuilder::new() + /// # .set_url("wss://rpc.polkadot.io:443") + /// # .build::() + /// # .await + /// # .unwrap(); + /// # /// let update_client = client.updates(); + /// // Spawn a new background task to handle runtime updates. /// tokio::spawn(async move { /// let result = update_client.perform_runtime_updates().await; /// println!("Runtime update finished with result={:?}", result); /// }); + /// # } /// ``` pub fn updates(&self) -> UpdateClient { UpdateClient::new( diff --git a/subxt/src/events/mod.rs b/subxt/src/events/mod.rs index c327e51230..260f19dcf0 100644 --- a/subxt/src/events/mod.rs +++ b/subxt/src/events/mod.rs @@ -21,7 +21,7 @@ //! //! This module is wrapped by the generated API in `RuntimeAPI::EventsApi`. //! -//! # Example +//! # Examples //! //! ## Subscribe to all events //! @@ -31,12 +31,25 @@ //! //! To obtain the events from a given block use `at()`. //! -//! ```rust -//! let mut events = api.events().subscribe().await?; +//! ```no_run +//! # use futures::StreamExt; +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! let mut events = api.events().subscribe().await.unwrap(); //! //! while let Some(ev) = events.next().await { //! // Obtain all events from this block. -//! let ev: subxt::Events<_, _> = ev?; +//! let ev: subxt::Events<_, _> = ev.unwrap(); //! // Print block hash. //! println!("Event at block hash {:?}", ev.block_hash()); //! // Iterate over all events. @@ -45,6 +58,7 @@ //! println!("Event details {:?}", event_details); //! } //! } +//! # } //! ``` //! //! ## Filter events @@ -55,16 +69,32 @@ //! returned directly. Otherwise, we'll be given a corresponding tuple of `Option`'s, with exactly //! one variant populated each time. //! -//! ```rust -//! let mut events = api +//! ```no_run +//! # use futures::StreamExt; +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! +//! let mut transfer_events = api //! .events() //! .subscribe() -//! .await? +//! .await +//! .unwrap() //! .filter_events::<(polkadot::balances::events::Transfer,)>(); //! //! while let Some(transfer_event) = transfer_events.next().await { //! println!("Balance transfer event: {transfer_event:?}"); //! } +//! # } //! ``` mod decoding; diff --git a/subxt/src/rpc.rs b/subxt/src/rpc.rs index bd78824f4c..b18e65ae88 100644 --- a/subxt/src/rpc.rs +++ b/subxt/src/rpc.rs @@ -23,12 +23,23 @@ //! //! ## Fetch Storage //! -//! ```rust -//! use subxt::rpc::Rpc; -//! use subxt::storage::StorageKeyPrefix; +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # use subxt::storage::StorageKeyPrefix; +//! # use subxt::rpc::Rpc; //! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); //! // Storage prefix is `twox_128("System") ++ twox_128("ExtrinsicCount")`. -//! let key = StorageKeyPrefix::new::() +//! let key = StorageKeyPrefix::new::() //! .to_storage_key(); //! //! // Obtain the RPC from a generated API @@ -36,27 +47,46 @@ //! .client //! .rpc(); //! -//! let result = rpc.storage(&key, None)?; +//! let result = rpc.storage(&key, None).await.unwrap(); //! println!("Storage result: {:?}", result); +//! # } //! ``` //! //! ## Fetch Keys //! -//! ```rust -//! use subxt::rpc::Rpc; -//! use subxt::storage::StorageKeyPrefix; -//! let key = StorageKeyPrefix::new::(); +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # use subxt::storage::StorageKeyPrefix; +//! # use subxt::rpc::Rpc; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! let key = StorageKeyPrefix::new::() +//! .to_storage_key(); //! //! // Obtain the RPC from a generated API //! let rpc: &Rpc<_> = api //! .client //! .rpc(); +//! //! // Fetch up to 10 keys. //! let keys = rpc -//! .storage_keys_paged(Some(key), 10, None, None); +//! .storage_keys_paged(Some(key), 10, None, None) +//! .await +//! .unwrap(); +//! //! for key in keys.iter() { //! println!("Key: 0x{}", hex::encode(&key)); //! } +//! # } //! ``` // jsonrpsee subscriptions are interminable. diff --git a/subxt/src/storage.rs b/subxt/src/storage.rs index c0682f4aa1..2edbf60d10 100644 --- a/subxt/src/storage.rs +++ b/subxt/src/storage.rs @@ -32,28 +32,62 @@ //! //! ## Fetch Storage Keys //! -//! ```rust +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # use subxt::storage::StorageClient; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! # // Obtain the storage client wrapper from the API. +//! # let storage: StorageClient<_> = api.client.storage(); //! // Fetch just the keys, returning up to 10 keys. //! let keys = storage -//! .fetch_keys::(10, None, None) -//! .await?; +//! .fetch_keys::(10, None, None) +//! .await +//! .unwrap(); //! // Iterate over each key //! for key in keys.iter() { //! println!("Key: 0x{}", hex::encode(&key)); //! } +//! # } //! ``` //! //! ## Iterate over Storage //! -//! ```rust +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # use subxt::storage::StorageClient; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! # // Obtain the storage client wrapper from the API. +//! # let storage: StorageClient<_> = api.client.storage(); //! // Iterate over keys and values. //! let mut iter = storage //! .iter::(None) -//! .await?; -//! while let Some((key, value)) = iter.next().await? { +//! .await +//! .unwrap(); +//! while let Some((key, value)) = iter.next().await.unwrap() { //! println!("Key: 0x{}", hex::encode(&key)); //! println!("Value: {}", value); //! } +//! # } //! ``` use codec::{ diff --git a/subxt/src/updates.rs b/subxt/src/updates.rs index ea606e05fb..8aa212f9f0 100644 --- a/subxt/src/updates.rs +++ b/subxt/src/updates.rs @@ -28,12 +28,24 @@ //! //! Here we use tokio to check for updates in the background, but any runtime can be used. //! -//! ```rust +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig}; +//! # +//! # #[tokio::main] +//! # async fn main() { +//! # let client = ClientBuilder::new() +//! # .set_url("wss://rpc.polkadot.io:443") +//! # .build::() +//! # .await +//! # .unwrap(); +//! # //! let update_client = client.updates(); +//! // Spawn a new background task to handle runtime updates. //! tokio::spawn(async move { //! let result = update_client.perform_runtime_updates().await; //! println!("Runtime update finished with result={:?}", result); //! }); +//! # } //! ``` use crate::{ From d3baa32aaf2ae6e315d7effe6af1950a9baca719 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Wed, 15 Jun 2022 19:29:19 +0300 Subject: [PATCH 2/6] CI: Add `cargo test --doc` Signed-off-by: Alexandru Vasile --- .github/workflows/rust.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index dca7235f4a..d0d5effde7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -99,6 +99,12 @@ jobs: - name: Check internal documentation links run: RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc -vv --workspace --no-deps --document-private-items + - name: Run cargo test on documentatin + uses: actions-rs/cargo@v1.0.3 + with: + command: test + args: --doc + tests: name: Cargo test runs-on: ubuntu-latest From b282f848bee6361314db6cd673972d653eb699c1 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Thu, 16 Jun 2022 11:57:56 +0300 Subject: [PATCH 3/6] Update .github/workflows/rust.yml Co-authored-by: Niklas Adolfsson --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d0d5effde7..a75ab618ed 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -99,7 +99,7 @@ jobs: - name: Check internal documentation links run: RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc -vv --workspace --no-deps --document-private-items - - name: Run cargo test on documentatin + - name: Run cargo test on documentation uses: actions-rs/cargo@v1.0.3 with: command: test From 2587ac1bc483fbe6dcea43a7816d5d712a7a5eb6 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 16 Jun 2022 13:23:34 +0300 Subject: [PATCH 4/6] Remove docs/subxt.md and move documentation to subxt/lib.rs Signed-off-by: Alexandru Vasile --- README.md | 2 +- docs/subxt.md | 178 ---------------------------------------------- subxt/src/lib.rs | 179 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 179 insertions(+), 180 deletions(-) delete mode 100644 docs/subxt.md diff --git a/README.md b/README.md index 1758b1f2dc..22c385e794 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ a different node then the `metadata` command accepts a `--url` argument. ## Subxt Documentation -For more details regarding utilizing subxt, please visit the [documentation](docs/subxt.md). +For more details regarding utilizing subxt, please visit the [documentation](https://docs.rs/subxt/latest/subxt/). ## Integration Testing diff --git a/docs/subxt.md b/docs/subxt.md deleted file mode 100644 index 65ccf8a18d..0000000000 --- a/docs/subxt.md +++ /dev/null @@ -1,178 +0,0 @@ -Subxt is a library to **sub**mit e**xt**rinsics to a [substrate](https://github.com/paritytech/substrate) node via RPC. - -The generated Subxt API exposes the ability to: -- [Submit extrinsics](https://docs.substrate.io/v3/concepts/extrinsics/) (Calls) -- [Query storage](https://docs.substrate.io/v3/runtime/storage/) (Storage) -- [Query constants](https://docs.substrate.io/how-to-guides/v3/basics/configurable-constants/) (Constants) -- [Subscribe to events](https://docs.substrate.io/v3/runtime/events-and-errors/) (Events) - - -### Generate the runtime API - -Subxt generates a runtime API from downloaded static metadata. The metadata can be downloaded using the -[subxt-cli](https://crates.io/crates/subxt-cli) tool. - -To generate the runtime API, use the `subxt` attribute which points at downloaded static metadata. - -```ignore -#[subxt::subxt(runtime_metadata_path = "metadata.scale")] -pub mod node_runtime { } -``` - -The `node_runtime` has the following hierarchy: - -```rust -pub mod node_runtime { - pub mod PalletName { - pub mod calls { } - pub mod storage { } - pub mod constants { } - pub mod events { } - } -} -``` - -For more information regarding the `node_runtime` hierarchy, please visit the -[subxt-codegen](https://docs.rs/subxt-codegen/latest/subxt_codegen/) documentation. - - -### Initializing the API client - -```no_run -use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; - -#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] -pub mod polkadot {} - -# #[tokio::main] -# async fn main() { -let api = ClientBuilder::new() - .set_url("wss://rpc.polkadot.io:443") - .build() - .await - .unwrap() - .to_runtime_api::>>(); -# } -``` - -The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user -supplied implementations for the `Config` and `Extra` types, if the default implementation differs from the target -chain. - -To ensure that extrinsics are properly submitted, during the build phase of the Client the -runtime metadata of the node is downloaded. If the URL is not specified (`set_url`), the local host is used instead. - - -### Submit Extrinsics - -Extrinsics are obtained using the API's `RuntimeApi::tx()` method, followed by `pallet_name()` and then the -`call_item_name()`. - -Submit an extrinsic, returning success once the transaction is validated and accepted into the pool: - -Please visit the [balance_transfer](../examples/examples/balance_transfer.rs) example for more details. - - -### Querying Storage - -The runtime storage is queried via the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and -then the `storage_item_name()`. - -Please visit the [fetch_staking_details](../examples/examples/fetch_staking_details.rs) example for more details. - -### Query Constants - -Constants are embedded into the node's metadata. - -The subxt offers the ability to query constants from the runtime metadata (metadata downloaded when constructing -the client, *not* the one provided for API generation). - -To query constants use the generated `RuntimeApi::constants()` method, followed by the `pallet_name()` and then the -`constant_item_name()`. - -Please visit the [fetch_constants](../examples/examples/fetch_constants.rs) example for more details. - -### Subscribe to Events - -To subscribe to events, use the generated `RuntimeApi::events()` method which exposes: -- `subscribe()` - Subscribe to events emitted from blocks. These blocks haven't necessarily been finalised. -- `subscribe_finalized()` - Subscribe to events from finalized blocks. -- `at()` - Obtain events at a given block hash. - - -*Examples* -- [subscribe_all_events](../examples/examples/subscribe_all_events.rs): Subscribe to events emitted from blocks. -- [subscribe_one_event](../examples/examples/subscribe_one_event.rs): Subscribe and filter by one event. -- [subscribe_some_events](../examples/examples/subscribe_some_events.rs): Subscribe and filter event. - -### Static Metadata Validation - -There are two types of metadata that the subxt is aware of: -- static metadata: Metadata used for generating the API. -- runtime metadata: Metadata downloaded from the target node when a subxt client is created. - -There are cases when the static metadata is different from the runtime metadata of a node. -Such is the case when the node performs a runtime update. - -To ensure that subxt can properly communicate with the target node the static metadata is validated -against the runtime metadata of the node. - -This validation is performed at the Call, Constant, and Storage levels, as well for the entire metadata. -The level of granularity ensures that the users can still submit a given call, even if another -call suffered changes. - -Full metadata validation: - -```no_run -# use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; -# #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] -# pub mod polkadot {} -# #[tokio::main] -# async fn main() { -# let api = ClientBuilder::new() -# .build() -# .await -# .unwrap() -# .to_runtime_api::>>(); -// To make sure that all of our statically generated pallets are compatible with the -// runtime node, we can run this check: -api.validate_metadata().unwrap(); -# } -``` - -Call level validation: - -```ignore -# use sp_keyring::AccountKeyring; -# use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; -# #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] -# pub mod polkadot {} -# #[tokio::main] -# async fn main() { -# let api = ClientBuilder::new() -# .build() -# .await -# .unwrap() -# .to_runtime_api::>>(); -// Submit the `transfer` extrinsic from Alice's account to Bob's. -let dest = AccountKeyring::Bob.to_account_id().into(); - -let extrinsic = api - .tx() - .balances() - // Constructing an extrinsic will fail if the metadata - // is not in sync with the generated API. - .transfer(dest, 123_456_789_012_345) - .unwrap(); -# } -``` - -### Runtime Updates - -There are cases when the node would perform a runtime update, and the runtime node's metadata would be -out of sync with the subxt's metadata. - -The `UpdateClient` API keeps the `RuntimeVersion` and `Metadata` of the client synced with the target node. - - -Please visit the [subscribe_runtime_updates](../examples/examples/subscribe_runtime_updates.rs) example for more details. diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 747a783f31..0703fec752 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -14,7 +14,184 @@ // You should have received a copy of the GNU General Public License // along with subxt. If not, see . -#![doc = include_str!("../../docs/subxt.md")] +//! Subxt is a library to **sub**mit e**xt**rinsics to a [substrate](https://github.com/paritytech/substrate) node via RPC. +//! +//! The generated Subxt API exposes the ability to: +//! - [Submit extrinsics](https://docs.substrate.io/v3/concepts/extrinsics/) (Calls) +//! - [Query storage](https://docs.substrate.io/v3/runtime/storage/) (Storage) +//! - [Query constants](https://docs.substrate.io/how-to-guides/v3/basics/configurable-constants/) (Constants) +//! - [Subscribe to events](https://docs.substrate.io/v3/runtime/events-and-errors/) (Events) +//! +//! +//! ### Generate the runtime API +//! +//! Subxt generates a runtime API from downloaded static metadata. The metadata can be downloaded using the +//! [subxt-cli](https://crates.io/crates/subxt-cli) tool. +//! +//! To generate the runtime API, use the `subxt` attribute which points at downloaded static metadata. +//! +//! ```ignore +//! #[subxt::subxt(runtime_metadata_path = "metadata.scale")] +//! pub mod node_runtime { } +//! ``` +//! +//! The `node_runtime` has the following hierarchy: +//! +//! ```rust +//! pub mod node_runtime { +//! pub mod PalletName { +//! pub mod calls { } +//! pub mod storage { } +//! pub mod constants { } +//! pub mod events { } +//! } +//! } +//! ``` +//! +//! For more information regarding the `node_runtime` hierarchy, please visit the +//! [subxt-codegen](https://docs.rs/subxt-codegen/latest/subxt_codegen/) documentation. +//! +//! +//! ### Initializing the API client +//! +//! ```no_run +//! use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! +//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! pub mod polkadot {} +//! +//! # #[tokio::main] +//! # async fn main() { +//! let api = ClientBuilder::new() +//! .set_url("wss://rpc.polkadot.io:443") +//! .build() +//! .await +//! .unwrap() +//! .to_runtime_api::>>(); +//! # } +//! ``` +//! +//! The `RuntimeApi` type is generated by the `subxt` macro from the supplied metadata. This can be parameterized with user +//! supplied implementations for the `Config` and `Extra` types, if the default implementation differs from the target +//! chain. +//! +//! To ensure that extrinsics are properly submitted, during the build phase of the Client the +//! runtime metadata of the node is downloaded. If the URL is not specified (`set_url`), the local host is used instead. +//! +//! +//! ### Submit Extrinsics +//! +//! Extrinsics are obtained using the API's `RuntimeApi::tx()` method, followed by `pallet_name()` and then the +//! `call_item_name()`. +//! +//! Submit an extrinsic, returning success once the transaction is validated and accepted into the pool: +//! +//! Please visit the [balance_transfer](../examples/examples/balance_transfer.rs) example for more details. +//! +//! +//! ### Querying Storage +//! +//! The runtime storage is queried via the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and +//! then the `storage_item_name()`. +//! +//! Please visit the [fetch_staking_details](../examples/examples/fetch_staking_details.rs) example for more details. +//! +//! ### Query Constants +//! +//! Constants are embedded into the node's metadata. +//! +//! The subxt offers the ability to query constants from the runtime metadata (metadata downloaded when constructing +//! the client, *not* the one provided for API generation). +//! +//! To query constants use the generated `RuntimeApi::constants()` method, followed by the `pallet_name()` and then the +//! `constant_item_name()`. +//! +//! Please visit the [fetch_constants](../examples/examples/fetch_constants.rs) example for more details. +//! +//! ### Subscribe to Events +//! +//! To subscribe to events, use the generated `RuntimeApi::events()` method which exposes: +//! - `subscribe()` - Subscribe to events emitted from blocks. These blocks haven't necessarily been finalised. +//! - `subscribe_finalized()` - Subscribe to events from finalized blocks. +//! - `at()` - Obtain events at a given block hash. +//! +//! +//! *Examples* +//! - [subscribe_all_events](../examples/examples/subscribe_all_events.rs): Subscribe to events emitted from blocks. +//! - [subscribe_one_event](../examples/examples/subscribe_one_event.rs): Subscribe and filter by one event. +//! - [subscribe_some_events](../examples/examples/subscribe_some_events.rs): Subscribe and filter event. +//! +//! ### Static Metadata Validation +//! +//! There are two types of metadata that the subxt is aware of: +//! - static metadata: Metadata used for generating the API. +//! - runtime metadata: Metadata downloaded from the target node when a subxt client is created. +//! +//! There are cases when the static metadata is different from the runtime metadata of a node. +//! Such is the case when the node performs a runtime update. +//! +//! To ensure that subxt can properly communicate with the target node the static metadata is validated +//! against the runtime metadata of the node. +//! +//! This validation is performed at the Call, Constant, and Storage levels, as well for the entire metadata. +//! The level of granularity ensures that the users can still submit a given call, even if another +//! call suffered changes. +//! +//! Full metadata validation: +//! +//! ```no_run +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! # pub mod polkadot {} +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! // To make sure that all of our statically generated pallets are compatible with the +//! // runtime node, we can run this check: +//! api.validate_metadata().unwrap(); +//! # } +//! ``` +//! +//! Call level validation: +//! +//! ```ignore +//! # use sp_keyring::AccountKeyring; +//! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; +//! # #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! # pub mod polkadot {} +//! # #[tokio::main] +//! # async fn main() { +//! # let api = ClientBuilder::new() +//! # .build() +//! # .await +//! # .unwrap() +//! # .to_runtime_api::>>(); +//! // Submit the `transfer` extrinsic from Alice's account to Bob's. +//! let dest = AccountKeyring::Bob.to_account_id().into(); +//! +//! let extrinsic = api +//! .tx() +//! .balances() +//! // Constructing an extrinsic will fail if the metadata +//! // is not in sync with the generated API. +//! .transfer(dest, 123_456_789_012_345) +//! .unwrap(); +//! # } +//! ``` +//! +//! ### Runtime Updates +//! +//! There are cases when the node would perform a runtime update, and the runtime node's metadata would be +//! out of sync with the subxt's metadata. +//! +//! The `UpdateClient` API keeps the `RuntimeVersion` and `Metadata` of the client synced with the target node. +//! +//! Please visit the [subscribe_runtime_updates](../examples/examples/subscribe_runtime_updates.rs) example for more details. + #![deny( bad_style, const_err, From 7d94a8760263bf22565e52bc3dfa5a83cf6946ca Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 16 Jun 2022 14:06:17 +0300 Subject: [PATCH 5/6] Hide polkadot interface for `events/mod.rs` Signed-off-by: Alexandru Vasile --- subxt/src/events/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/subxt/src/events/mod.rs b/subxt/src/events/mod.rs index 260f19dcf0..62680608d7 100644 --- a/subxt/src/events/mod.rs +++ b/subxt/src/events/mod.rs @@ -34,10 +34,8 @@ //! ```no_run //! # use futures::StreamExt; //! # use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; -//! -//! #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] -//! pub mod polkadot {} -//! +//! # #[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata.scale")] +//! # pub mod polkadot {} //! # #[tokio::main] //! # async fn main() { //! # let api = ClientBuilder::new() From ac45e165aa3e756874a83af721201f21b4fb83e7 Mon Sep 17 00:00:00 2001 From: Alexandru Vasile Date: Thu, 16 Jun 2022 14:11:23 +0300 Subject: [PATCH 6/6] docs: Use `#` for headers Signed-off-by: Alexandru Vasile --- subxt/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/subxt/src/lib.rs b/subxt/src/lib.rs index 0703fec752..95f13fc69a 100644 --- a/subxt/src/lib.rs +++ b/subxt/src/lib.rs @@ -23,7 +23,7 @@ //! - [Subscribe to events](https://docs.substrate.io/v3/runtime/events-and-errors/) (Events) //! //! -//! ### Generate the runtime API +//! # Generate the runtime API //! //! Subxt generates a runtime API from downloaded static metadata. The metadata can be downloaded using the //! [subxt-cli](https://crates.io/crates/subxt-cli) tool. @@ -52,7 +52,7 @@ //! [subxt-codegen](https://docs.rs/subxt-codegen/latest/subxt_codegen/) documentation. //! //! -//! ### Initializing the API client +//! # Initializing the API client //! //! ```no_run //! use subxt::{ClientBuilder, DefaultConfig, PolkadotExtrinsicParams}; @@ -79,7 +79,7 @@ //! runtime metadata of the node is downloaded. If the URL is not specified (`set_url`), the local host is used instead. //! //! -//! ### Submit Extrinsics +//! # Submit Extrinsics //! //! Extrinsics are obtained using the API's `RuntimeApi::tx()` method, followed by `pallet_name()` and then the //! `call_item_name()`. @@ -89,14 +89,14 @@ //! Please visit the [balance_transfer](../examples/examples/balance_transfer.rs) example for more details. //! //! -//! ### Querying Storage +//! # Querying Storage //! //! The runtime storage is queried via the generated `RuntimeApi::storage()` method, followed by the `pallet_name()` and //! then the `storage_item_name()`. //! //! Please visit the [fetch_staking_details](../examples/examples/fetch_staking_details.rs) example for more details. //! -//! ### Query Constants +//! # Query Constants //! //! Constants are embedded into the node's metadata. //! @@ -108,7 +108,7 @@ //! //! Please visit the [fetch_constants](../examples/examples/fetch_constants.rs) example for more details. //! -//! ### Subscribe to Events +//! # Subscribe to Events //! //! To subscribe to events, use the generated `RuntimeApi::events()` method which exposes: //! - `subscribe()` - Subscribe to events emitted from blocks. These blocks haven't necessarily been finalised. @@ -121,7 +121,7 @@ //! - [subscribe_one_event](../examples/examples/subscribe_one_event.rs): Subscribe and filter by one event. //! - [subscribe_some_events](../examples/examples/subscribe_some_events.rs): Subscribe and filter event. //! -//! ### Static Metadata Validation +//! # Static Metadata Validation //! //! There are two types of metadata that the subxt is aware of: //! - static metadata: Metadata used for generating the API. @@ -183,7 +183,7 @@ //! # } //! ``` //! -//! ### Runtime Updates +//! # Runtime Updates //! //! There are cases when the node would perform a runtime update, and the runtime node's metadata would be //! out of sync with the subxt's metadata.