From 9683112a5f94551803bedef441435610c5464970 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 11 Jan 2024 16:27:25 +0100 Subject: [PATCH 01/10] asset hub example and book adjustment --- subxt/examples/setup_config_assethub.rs | 57 +++++++++++++++++++++++++ subxt/src/book/setup/config.rs | 12 ++++++ 2 files changed, 69 insertions(+) create mode 100644 subxt/examples/setup_config_assethub.rs diff --git a/subxt/examples/setup_config_assethub.rs b/subxt/examples/setup_config_assethub.rs new file mode 100644 index 0000000000..ca515726fc --- /dev/null +++ b/subxt/examples/setup_config_assethub.rs @@ -0,0 +1,57 @@ +#![allow(missing_docs)] +use subxt::config::{ + Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder, PolkadotConfig, SubstrateConfig, +}; +use subxt_signer::sr25519::dev; + +#[subxt::subxt( + runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale", + derive_for_type(path = "xcm::v2::multilocation::MultiLocation", derive = "Clone"), + derive_for_type(path = "xcm::v2::multilocation::Junctions", derive = "Clone"), + derive_for_type(path = "xcm::v2::junction::Junction", derive = "Clone"), + derive_for_type(path = "xcm::v2::NetworkId", derive = "Clone"), + derive_for_type(path = "xcm::v2::BodyId", derive = "Clone"), + derive_for_type(path = "xcm::v2::BodyPart", derive = "Clone"), + derive_for_type( + path = "bounded_collections::weak_bounded_vec::WeakBoundedVec", + derive = "Clone" + ) +)] +pub mod runtime {} +use runtime::runtime_types::xcm::v2::multilocation::{MultiLocation, Junctions}; + +// We don't need to construct this at runtime, so an empty enum is appropriate. +pub enum AssetHubConfig {} + +impl Config for AssetHubConfig { + type Hash = ::Hash; + type AccountId = ::AccountId; + type Address = ::Address; + type Signature = ::Signature; + type Hasher = ::Hasher; + type Header = ::Header; + type ExtrinsicParams = DefaultExtrinsicParams; + // Here we use the MultiLocation from the metadata as a part of the config: + // The `ChargeAssetTxPayment` signed extension that is part of the ExtrinsicParams above, now uses the type: + type AssetId = MultiLocation; +} + +#[tokio::main] +async fn main() { + // With the config defined, we can create an extrinsic with subxt: + let client = subxt::OnlineClient::::new().await.unwrap(); + let tx_payload = runtime::tx().system().remark(b"Hello".to_vec()); + + // Build extrinsic params using an asset at this location as a tip: + let location: MultiLocation = MultiLocation { + parents: 3, + interior: Junctions::Here, + }; + let tx_config = DefaultExtrinsicParamsBuilder::::new().tip_of(1234, location).build(); + + // And provide the extrinsic params including the tip when submitting a transaction: + let _ = client + .tx() + .sign_and_submit_then_watch(&tx_payload, &dev::alice(), tx_config) + .await; +} diff --git a/subxt/src/book/setup/config.rs b/subxt/src/book/setup/config.rs index dba7654d7b..0ad06938fb 100644 --- a/subxt/src/book/setup/config.rs +++ b/subxt/src/book/setup/config.rs @@ -152,3 +152,15 @@ //! ```rust,ignore #![doc = include_str ! ("../../../examples/setup_config_custom.rs")] //! ``` +//! +//! ### Using a type from the metadata as a config parameter +//! +//! You can also use types that are generated from chain metadata as type parameters of the Config trait. +//! Just make sure all trait bounds are satisfied. This can often be achieved by using custom derives with the subxt macro. +//! For example, the AssetHub Parachain, expects tips to include a `MultiLocation`, which is a type we can draw from the metadata. +//! +//! This example shows, what using the `MultiLocation` struct as part of your config would look like in subxt: +//! +//! ```rust,ignore +#![doc = include_str ! ("../../../examples/setup_config_assethub.rs")] +//! ``` From 71e21ff9e1f1ee30b913dcf7953652cdef5c8af2 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 11 Jan 2024 16:29:47 +0100 Subject: [PATCH 02/10] formatting --- subxt/examples/setup_config_assethub.rs | 6 ++++-- subxt/src/book/setup/config.rs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/subxt/examples/setup_config_assethub.rs b/subxt/examples/setup_config_assethub.rs index ca515726fc..39ef25ddda 100644 --- a/subxt/examples/setup_config_assethub.rs +++ b/subxt/examples/setup_config_assethub.rs @@ -18,7 +18,7 @@ use subxt_signer::sr25519::dev; ) )] pub mod runtime {} -use runtime::runtime_types::xcm::v2::multilocation::{MultiLocation, Junctions}; +use runtime::runtime_types::xcm::v2::multilocation::{Junctions, MultiLocation}; // We don't need to construct this at runtime, so an empty enum is appropriate. pub enum AssetHubConfig {} @@ -47,7 +47,9 @@ async fn main() { parents: 3, interior: Junctions::Here, }; - let tx_config = DefaultExtrinsicParamsBuilder::::new().tip_of(1234, location).build(); + let tx_config = DefaultExtrinsicParamsBuilder::::new() + .tip_of(1234, location) + .build(); // And provide the extrinsic params including the tip when submitting a transaction: let _ = client diff --git a/subxt/src/book/setup/config.rs b/subxt/src/book/setup/config.rs index 0ad06938fb..57c922a677 100644 --- a/subxt/src/book/setup/config.rs +++ b/subxt/src/book/setup/config.rs @@ -158,9 +158,9 @@ //! You can also use types that are generated from chain metadata as type parameters of the Config trait. //! Just make sure all trait bounds are satisfied. This can often be achieved by using custom derives with the subxt macro. //! For example, the AssetHub Parachain, expects tips to include a `MultiLocation`, which is a type we can draw from the metadata. -//! +//! //! This example shows, what using the `MultiLocation` struct as part of your config would look like in subxt: -//! +//! //! ```rust,ignore #![doc = include_str ! ("../../../examples/setup_config_assethub.rs")] //! ``` From 6861c6c24ba92b2052612d8bf4662a38f18c49cd Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Thu, 11 Jan 2024 16:45:56 +0100 Subject: [PATCH 03/10] recursive derives --- subxt/examples/setup_config_assethub.rs | 11 +++-------- subxt/examples/setup_config_custom.rs | 12 ++---------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/subxt/examples/setup_config_assethub.rs b/subxt/examples/setup_config_assethub.rs index 39ef25ddda..99750898ef 100644 --- a/subxt/examples/setup_config_assethub.rs +++ b/subxt/examples/setup_config_assethub.rs @@ -6,15 +6,10 @@ use subxt_signer::sr25519::dev; #[subxt::subxt( runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale", - derive_for_type(path = "xcm::v2::multilocation::MultiLocation", derive = "Clone"), - derive_for_type(path = "xcm::v2::multilocation::Junctions", derive = "Clone"), - derive_for_type(path = "xcm::v2::junction::Junction", derive = "Clone"), - derive_for_type(path = "xcm::v2::NetworkId", derive = "Clone"), - derive_for_type(path = "xcm::v2::BodyId", derive = "Clone"), - derive_for_type(path = "xcm::v2::BodyPart", derive = "Clone"), derive_for_type( - path = "bounded_collections::weak_bounded_vec::WeakBoundedVec", - derive = "Clone" + path = "xcm::v2::multilocation::MultiLocation", + derive = "Clone", + recursive ) )] pub mod runtime {} diff --git a/subxt/examples/setup_config_custom.rs b/subxt/examples/setup_config_custom.rs index c884324fc0..4748202e1f 100644 --- a/subxt/examples/setup_config_custom.rs +++ b/subxt/examples/setup_config_custom.rs @@ -4,16 +4,8 @@ use subxt::client::OfflineClientT; use subxt::config::{Config, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError}; use subxt_signer::sr25519::dev; -#[subxt::subxt( - runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale", - derive_for_type( - path = "xcm::v2::multilocation::MultiLocation", - derive = "Clone", - recursive - ) -)] +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale")] pub mod runtime {} -use runtime::runtime_types::xcm::v2::multilocation::MultiLocation; // We don't need to construct this at runtime, // so an empty enum is appropriate: @@ -27,7 +19,7 @@ impl Config for CustomConfig { type Hasher = subxt::config::substrate::BlakeTwo256; type Header = subxt::config::substrate::SubstrateHeader; type ExtrinsicParams = CustomExtrinsicParams; - type AssetId = MultiLocation; + type AssetId = u32; } // This represents some arbitrary (and nonsensical) custom parameters that From 4e217acaa10ed18d99c0b88143b347792c6beef5 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 12 Jan 2024 17:06:26 +0100 Subject: [PATCH 04/10] polkadot monitor example and book adjustments --- subxt/examples/blocks_subscribing.rs | 5 ++- subxt/examples/polkadot_monitor.rs | 63 ++++++++++++++++++++++++++++ subxt/src/book/usage/blocks.rs | 54 ++++++++++++++++++++++-- subxt/src/utils/multi_address.rs | 7 ++++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 subxt/examples/polkadot_monitor.rs diff --git a/subxt/examples/blocks_subscribing.rs b/subxt/examples/blocks_subscribing.rs index 5511df990d..7ac15bd44c 100644 --- a/subxt/examples/blocks_subscribing.rs +++ b/subxt/examples/blocks_subscribing.rs @@ -37,8 +37,8 @@ async fn main() -> Result<(), Box> { println!(" Extrinsic #{idx}:"); println!(" Bytes: {bytes_hex}"); println!(" Decoded: {decoded_ext:?}"); - println!(" Events:"); + println!(" Events:"); for evt in events.iter() { let evt = evt?; let pallet_name = evt.pallet_name(); @@ -58,6 +58,9 @@ async fn main() -> Result<(), Box> { println!(" {name}: {value}"); } } + + // // We could also decode the + // let decoded_as_remark = ext.as_root_extrinsic::(); } } diff --git a/subxt/examples/polkadot_monitor.rs b/subxt/examples/polkadot_monitor.rs new file mode 100644 index 0000000000..934dc7e6ec --- /dev/null +++ b/subxt/examples/polkadot_monitor.rs @@ -0,0 +1,63 @@ +#![allow(missing_docs)] +use subxt::{ + utils::{AccountId32, MultiAddress}, + OnlineClient, PolkadotConfig, +}; + +use codec::Decode; + +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] +pub mod polkadot {} + +use polkadot::balances::calls::types::TransferKeepAlive; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create a client that subscribes to blocks of the live Polkadot network. + let api = OnlineClient::::from_url("wss://rpc.polkadot.io:443").await?; + + // Subscribe to all finalized blocks: + let mut blocks_sub = api.blocks().subscribe_finalized().await?; + + // For each block, print details about the `TransferKeepAlive` transactions we are interested in. + while let Some(block) = blocks_sub.next().await { + let block = block?; + let block_number = block.header().number; + let block_hash = block.hash(); + println!("Block #{block_number} ({block_hash}):"); + + let extrinsics = block.extrinsics().await?; + for ext in extrinsics.iter() { + let ext = ext?; + if let Ok(Some(transfer)) = ext.as_extrinsic::() { + if let Some(extensions) = ext.signed_extensions() { + ext.address_bytes().unwrap(); + let addr_bytes = ext.address_bytes().expect("TransferKeepAlive should be signed"); + let sender = MultiAddress::::decode(&mut &addr_bytes[..]) + .expect("Decoding should work"); + let sender = display_address(&sender); + let receiver = display_address(&transfer.dest); + let value = transfer.value; + let tip = extensions.tip().expect("Should have tip"); + let nonce = extensions.nonce().expect("Should have nonce"); + + println!( + " Transfer of {value} DOT:\n {sender} (Tip: {tip}, Nonce: {nonce}) ---> {receiver}", + ); + } else { + panic!("TransferKeepAlive should be signed") + } + } + } + } + + Ok(()) +} + +fn display_address(addr: &MultiAddress) -> String { + if let MultiAddress::Id(id32) = addr { + format!("{id32}") + } else { + "MultiAddress::...".into() + } +} diff --git a/subxt/src/book/usage/blocks.rs b/subxt/src/book/usage/blocks.rs index c98e0298ca..5edde879e2 100644 --- a/subxt/src/book/usage/blocks.rs +++ b/subxt/src/book/usage/blocks.rs @@ -27,13 +27,59 @@ //! Aside from these links to other Subxt APIs, the main thing that we can do here is iterate over and //! decode the extrinsics in a block body. //! -//! ## Example +//! ## Decoding Extrinsics //! -//! Given a block, you can [download the block body](crate::blocks::Block::extrinsics()) and iterate over -//! the extrinsics stored within it. From there, you can decode the extrinsics and access various details, -//! including the associated events: +//! Given a block, you can [download the block body](crate::blocks::Block::extrinsics()) and [iterate over +//! the extrinsics](crate::blocks::Extrinsics::iter()) stored within it. The extrinsics yielded, are of type +//! [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), which is just a blob of bytes that also stores which +//! pallet and call in that pallet it belongs to. It also contains information about signed extensions that +//! have been used for submitting this extrinsic. +//! +//! To use the extrinsic, you probably want to decode it into a concrete Rust type. These Rust types representing +//! extrinsics from different pallets can be generated from metadata using the subxt macro or the CLI tool. +//! +//! When decoding the extrinsic into a static type you have two options: +//! +//! ### Statically decode the extrinsics into [the root extrinsic type](crate::blocks::ExtrinsicDetails::as_root_extrinsic()) +//! +//! The root extrinsic type generated by subxt is a Rust enum with one variant for each pallet. Each of these +//! variants has a field that is another enum whose variants cover all calls of the respective pallet. +//! If the extrinsic bytes are valid and your metadata matches the chains metadata, decoding the bytes of an extrinsic into +//! this root extrinsic type should always succeed. +//! This example shows how to subscribe to blocks, and decode the extrinsics in each block into the root extrinsic type. +//! Once decoded, we can access details about the extrinsic, including the associated events and signed extensions. //! //! ```rust,ignore #![doc = include_str!("../../../examples/blocks_subscribing.rs")] //! ``` //! +//! ### Statically decode the extrinsic into [a specific pallet call](crate::blocks::ExtrinsicDetails::as_extrinsic()) +//! +//! . This is +//! useful if you are expecting a specific extrinsic to be part of some block. If the extrinsic you try to decode +//! is a different extrinsic, an `Ok(None)` value is returned from [`as_extrinsic::()`](crate::blocks::ExtrinsicDetails::as_extrinsic()); +//! +//! If you are only interested in a specific kind of extrinsic in a block you can also [iterate over all of them](crate::blocks::Extrinsics::find), +//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last) +//! given some the [Extrinsics](crate::blocks::Extrinsics) from a blocks body. +//! +//! The following example monitors `TransferKeepAlive` extrinsics on the polkadot network. +//! We statically decode them and also make use of signed +//! +//! ```rust,ignore +#![doc = include_str!("../../../examples/polkadot_monitor.rs")] +//! ``` +//! +//! ### Decoding signed extensions +//! +//! Extrinsics can contain signed extensions. The signed extensions can be different across chains. +//! Which signed extensions you expect are specified in the [Config](crate::Config) implementation for your chain. +//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), +//! you can try to [get its signed extensions](crate::blocks::ExtrinsicDetails::signed_extensions()). In general +//! these are only available on extrinsics that have been signed. You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find), +//! in the returned [signed extensions](crate::blocks::ExtrinsicSignedExtensions). +//! +//! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and the +//! [account nonce](crate::blocks::ExtrinsicSignedExtensions::tip()) associated with an extrinsic, given its signed extensions. +//! +//! diff --git a/subxt/src/utils/multi_address.rs b/subxt/src/utils/multi_address.rs index 9b1e556fa9..4619ad1e02 100644 --- a/subxt/src/utils/multi_address.rs +++ b/subxt/src/utils/multi_address.rs @@ -37,6 +37,13 @@ pub enum MultiAddress { Address20([u8; 20]), } +impl MultiAddress { + ///sasda sa dsa + pub fn foo(&self) { + println!("lol") + } +} + impl From for MultiAddress { fn from(a: AccountId) -> Self { Self::Id(a) From 171667e5b3231388c565e65f2aeef508251c5280 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Fri, 12 Jan 2024 17:08:40 +0100 Subject: [PATCH 05/10] formatting --- subxt/examples/polkadot_monitor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/subxt/examples/polkadot_monitor.rs b/subxt/examples/polkadot_monitor.rs index 934dc7e6ec..5b4067e56e 100644 --- a/subxt/examples/polkadot_monitor.rs +++ b/subxt/examples/polkadot_monitor.rs @@ -32,7 +32,9 @@ async fn main() -> Result<(), Box> { if let Ok(Some(transfer)) = ext.as_extrinsic::() { if let Some(extensions) = ext.signed_extensions() { ext.address_bytes().unwrap(); - let addr_bytes = ext.address_bytes().expect("TransferKeepAlive should be signed"); + let addr_bytes = ext + .address_bytes() + .expect("TransferKeepAlive should be signed"); let sender = MultiAddress::::decode(&mut &addr_bytes[..]) .expect("Decoding should work"); let sender = display_address(&sender); From f2bd3a66de192b8f8a5dbc7649685d76a9a71f08 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Mon, 15 Jan 2024 15:15:27 +0100 Subject: [PATCH 06/10] adjust docs and examples, add dynamic example --- subxt/examples/block_decoding_dynamic.rs | 46 ++++++++++++++++++ ...ot_monitor.rs => block_decoding_static.rs} | 38 +++++++-------- subxt/examples/blocks_subscribing.rs | 3 -- subxt/src/book/setup/config.rs | 4 +- subxt/src/book/usage/blocks.rs | 48 ++++++++++++------- subxt/src/utils/multi_address.rs | 7 --- 6 files changed, 97 insertions(+), 49 deletions(-) create mode 100644 subxt/examples/block_decoding_dynamic.rs rename subxt/examples/{polkadot_monitor.rs => block_decoding_static.rs} (57%) diff --git a/subxt/examples/block_decoding_dynamic.rs b/subxt/examples/block_decoding_dynamic.rs new file mode 100644 index 0000000000..8bd54d4afb --- /dev/null +++ b/subxt/examples/block_decoding_dynamic.rs @@ -0,0 +1,46 @@ +#![allow(missing_docs)] +use subxt::{OnlineClient, PolkadotConfig}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Create a client that subscribes to blocks of the Polkadot network. + let api = OnlineClient::::from_url("wss://rpc.polkadot.io:443").await?; + + // Subscribe to all finalized blocks: + let mut blocks_sub = api.blocks().subscribe_finalized().await?; + while let Some(block) = blocks_sub.next().await { + let block = block?; + let block_number = block.header().number; + let block_hash = block.hash(); + println!("Block #{block_number} ({block_hash})"); + + // Decode each signed extrinsic in the block dynamically + let extrinsics = block.extrinsics().await?; + for ext in extrinsics.iter() { + let ext = ext?; + + let Some(signed_extensions) = ext.signed_extensions() else { + continue; // we do not look at inherents in this example + }; + + let meta = ext.extrinsic_metadata()?; + let fields = ext.field_values()?; + + println!(" {}/{}", meta.pallet.name(), meta.variant.name); + println!(" Signed Extensions:"); + for signed_ext in signed_extensions.iter() { + let signed_ext = signed_ext?; + // We only want to take a look at these 3 signed extensions, because the others all just have unit fields. + if ["CheckMortality", "CheckNonce", "ChargeTransactionPayment"] + .contains(&signed_ext.name()) + { + println!(" {}: {}", signed_ext.name(), signed_ext.value()?); + } + } + println!(" Fields:"); + println!(" {}\n", fields); + } + } + + Ok(()) +} diff --git a/subxt/examples/polkadot_monitor.rs b/subxt/examples/block_decoding_static.rs similarity index 57% rename from subxt/examples/polkadot_monitor.rs rename to subxt/examples/block_decoding_static.rs index 5b4067e56e..42eccc9c24 100644 --- a/subxt/examples/polkadot_monitor.rs +++ b/subxt/examples/block_decoding_static.rs @@ -13,7 +13,7 @@ use polkadot::balances::calls::types::TransferKeepAlive; #[tokio::main] async fn main() -> Result<(), Box> { - // Create a client that subscribes to blocks of the live Polkadot network. + // Create a client that subscribes to blocks of the Polkadot network. let api = OnlineClient::::from_url("wss://rpc.polkadot.io:443").await?; // Subscribe to all finalized blocks: @@ -30,25 +30,25 @@ async fn main() -> Result<(), Box> { for ext in extrinsics.iter() { let ext = ext?; if let Ok(Some(transfer)) = ext.as_extrinsic::() { - if let Some(extensions) = ext.signed_extensions() { - ext.address_bytes().unwrap(); - let addr_bytes = ext - .address_bytes() - .expect("TransferKeepAlive should be signed"); - let sender = MultiAddress::::decode(&mut &addr_bytes[..]) - .expect("Decoding should work"); - let sender = display_address(&sender); - let receiver = display_address(&transfer.dest); - let value = transfer.value; - let tip = extensions.tip().expect("Should have tip"); - let nonce = extensions.nonce().expect("Should have nonce"); - - println!( - " Transfer of {value} DOT:\n {sender} (Tip: {tip}, Nonce: {nonce}) ---> {receiver}", - ); - } else { + let Some(extensions) = ext.signed_extensions() else { panic!("TransferKeepAlive should be signed") - } + }; + + ext.address_bytes().unwrap(); + let addr_bytes = ext + .address_bytes() + .expect("TransferKeepAlive should be signed"); + let sender = MultiAddress::::decode(&mut &addr_bytes[..]) + .expect("Decoding should work"); + let sender = display_address(&sender); + let receiver = display_address(&transfer.dest); + let value = transfer.value; + let tip = extensions.tip().expect("Should have tip"); + let nonce = extensions.nonce().expect("Should have nonce"); + + println!( + " Transfer of {value} DOT:\n {sender} (Tip: {tip}, Nonce: {nonce}) ---> {receiver}", + ); } } } diff --git a/subxt/examples/blocks_subscribing.rs b/subxt/examples/blocks_subscribing.rs index 7ac15bd44c..3402a08827 100644 --- a/subxt/examples/blocks_subscribing.rs +++ b/subxt/examples/blocks_subscribing.rs @@ -58,9 +58,6 @@ async fn main() -> Result<(), Box> { println!(" {name}: {value}"); } } - - // // We could also decode the - // let decoded_as_remark = ext.as_root_extrinsic::(); } } diff --git a/subxt/src/book/setup/config.rs b/subxt/src/book/setup/config.rs index 57c922a677..6e6e811a55 100644 --- a/subxt/src/book/setup/config.rs +++ b/subxt/src/book/setup/config.rs @@ -157,9 +157,9 @@ //! //! You can also use types that are generated from chain metadata as type parameters of the Config trait. //! Just make sure all trait bounds are satisfied. This can often be achieved by using custom derives with the subxt macro. -//! For example, the AssetHub Parachain, expects tips to include a `MultiLocation`, which is a type we can draw from the metadata. +//! For example, the AssetHub Parachain expects tips to include a `MultiLocation`, which is a type we can draw from the metadata. //! -//! This example shows, what using the `MultiLocation` struct as part of your config would look like in subxt: +//! This example shows what using the `MultiLocation` struct as part of your config would look like in subxt: //! //! ```rust,ignore #![doc = include_str ! ("../../../examples/setup_config_assethub.rs")] diff --git a/subxt/src/book/usage/blocks.rs b/subxt/src/book/usage/blocks.rs index 5edde879e2..8f5ea7f64f 100644 --- a/subxt/src/book/usage/blocks.rs +++ b/subxt/src/book/usage/blocks.rs @@ -30,7 +30,7 @@ //! ## Decoding Extrinsics //! //! Given a block, you can [download the block body](crate::blocks::Block::extrinsics()) and [iterate over -//! the extrinsics](crate::blocks::Extrinsics::iter()) stored within it. The extrinsics yielded, are of type +//! the extrinsics](crate::blocks::Extrinsics::iter()) stored within it. The extrinsics yielded are of type //! [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), which is just a blob of bytes that also stores which //! pallet and call in that pallet it belongs to. It also contains information about signed extensions that //! have been used for submitting this extrinsic. @@ -44,10 +44,11 @@ //! //! The root extrinsic type generated by subxt is a Rust enum with one variant for each pallet. Each of these //! variants has a field that is another enum whose variants cover all calls of the respective pallet. -//! If the extrinsic bytes are valid and your metadata matches the chains metadata, decoding the bytes of an extrinsic into +//! If the extrinsic bytes are valid and your metadata matches the chain's metadata, decoding the bytes of an extrinsic into //! this root extrinsic type should always succeed. -//! This example shows how to subscribe to blocks, and decode the extrinsics in each block into the root extrinsic type. -//! Once decoded, we can access details about the extrinsic, including the associated events and signed extensions. +//! This example shows how to subscribe to blocks and decode the extrinsics in each block into the root extrinsic type. +//! Once we get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), we can decode it statically or dynamically. +//! We can also access details about the extrinsic, including the associated events and signed extensions. //! //! ```rust,ignore #![doc = include_str!("../../../examples/blocks_subscribing.rs")] @@ -55,31 +56,42 @@ //! //! ### Statically decode the extrinsic into [a specific pallet call](crate::blocks::ExtrinsicDetails::as_extrinsic()) //! -//! . This is -//! useful if you are expecting a specific extrinsic to be part of some block. If the extrinsic you try to decode +//! This is useful if you are expecting a specific extrinsic to be part of some block. If the extrinsic you try to decode //! is a different extrinsic, an `Ok(None)` value is returned from [`as_extrinsic::()`](crate::blocks::ExtrinsicDetails::as_extrinsic()); //! -//! If you are only interested in a specific kind of extrinsic in a block you can also [iterate over all of them](crate::blocks::Extrinsics::find), -//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last) -//! given some the [Extrinsics](crate::blocks::Extrinsics) from a blocks body. +//! If you are only interested in finding specific extrinsics in a block, you can also [iterate over all of them](crate::blocks::Extrinsics::find), +//! get only [the first one](crate::blocks::Extrinsics::find_first), or [the last one](crate::blocks::Extrinsics::find_last). //! -//! The following example monitors `TransferKeepAlive` extrinsics on the polkadot network. -//! We statically decode them and also make use of signed +//! The following example monitors `TransferKeepAlive` extrinsics on the Polkadot network. +//! We statically decode them and access the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and [account nonce](crate::blocks::ExtrinsicSignedExtensions::nonce()) signed extensions. //! //! ```rust,ignore -#![doc = include_str!("../../../examples/polkadot_monitor.rs")] +#![doc = include_str!("../../../examples/block_decoding_static.rs")] //! ``` //! -//! ### Decoding signed extensions +//! ### Dynamically decode the extrinsic +//! +//! Sometimes you might use subxt with metadata that is not known at compile time. In this case, you do not have access to a statically generated +//! interface module that contains the relevant Rust types. You can [decode ExtrinsicDetails dynamically](crate::blocks::ExtrinsicDetails::field_values()), +//! which gives you access to it's fields as a [scale value composite](scale_value::Composite). +//! The following example looks for signed extrinsics on the Polkadot network and retrieves their pallet name, variant name, data fields and signed extensions dynamically. +//! Notice how we do not need to use code generation via the subxt macro. The only fixed component we provide is the [PolkadotConfig](crate::config::PolkadotConfig). +//! Other than that it works in a chain-agnostic way: +//! +//! ```rust,ignore +#![doc = include_str!("../../../examples/block_decoding_dynamic.rs")] +//! ``` +//! +//! ## Decoding signed extensions //! //! Extrinsics can contain signed extensions. The signed extensions can be different across chains. -//! Which signed extensions you expect are specified in the [Config](crate::Config) implementation for your chain. -//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), -//! you can try to [get its signed extensions](crate::blocks::ExtrinsicDetails::signed_extensions()). In general -//! these are only available on extrinsics that have been signed. You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find), +//! The [Config](crate::Config) implementation for your chain defines which signed extensions you expect. +//! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in, +//! you can try to [get its signed extensions](crate::blocks::ExtrinsicDetails::signed_extensions()). +//! In general these are only available on signed extrinsics (not inherents). You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find), //! in the returned [signed extensions](crate::blocks::ExtrinsicSignedExtensions). //! //! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and the //! [account nonce](crate::blocks::ExtrinsicSignedExtensions::tip()) associated with an extrinsic, given its signed extensions. -//! +//! If you prefer to do things dynamically you can get the data of the signed extension as a [scale value](crate::blocks::ExtrinsicSignedExtension::value()). //! diff --git a/subxt/src/utils/multi_address.rs b/subxt/src/utils/multi_address.rs index 4619ad1e02..9b1e556fa9 100644 --- a/subxt/src/utils/multi_address.rs +++ b/subxt/src/utils/multi_address.rs @@ -37,13 +37,6 @@ pub enum MultiAddress { Address20([u8; 20]), } -impl MultiAddress { - ///sasda sa dsa - pub fn foo(&self) { - println!("lol") - } -} - impl From for MultiAddress { fn from(a: AccountId) -> Self { Self::Id(a) From 0fd2c596269b8d8b6d4bf9b64e1c18b7eae54922 Mon Sep 17 00:00:00 2001 From: Tadeo hepperle Date: Tue, 16 Jan 2024 19:00:13 +0100 Subject: [PATCH 07/10] james suggestions --- subxt/src/book/usage/blocks.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subxt/src/book/usage/blocks.rs b/subxt/src/book/usage/blocks.rs index 8f5ea7f64f..2fea83020a 100644 --- a/subxt/src/book/usage/blocks.rs +++ b/subxt/src/book/usage/blocks.rs @@ -46,6 +46,7 @@ //! variants has a field that is another enum whose variants cover all calls of the respective pallet. //! If the extrinsic bytes are valid and your metadata matches the chain's metadata, decoding the bytes of an extrinsic into //! this root extrinsic type should always succeed. +//! //! This example shows how to subscribe to blocks and decode the extrinsics in each block into the root extrinsic type. //! Once we get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), we can decode it statically or dynamically. //! We can also access details about the extrinsic, including the associated events and signed extensions. @@ -88,7 +89,7 @@ //! The [Config](crate::Config) implementation for your chain defines which signed extensions you expect. //! Once you get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails) for an extrinsic you are interested in, //! you can try to [get its signed extensions](crate::blocks::ExtrinsicDetails::signed_extensions()). -//! In general these are only available on signed extrinsics (not inherents). You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find), +//! These are only available on signed extrinsics. You can try to [find a specific signed extension](crate::blocks::ExtrinsicSignedExtensions::find), //! in the returned [signed extensions](crate::blocks::ExtrinsicSignedExtensions). //! //! Subxt also provides utility functions to get the [tip](crate::blocks::ExtrinsicSignedExtensions::tip()) and the From 31ee174edc989fc4068235947ac06fa1884035d3 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 17 Jan 2024 10:21:23 +0000 Subject: [PATCH 08/10] fmt --- subxt/src/book/usage/blocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subxt/src/book/usage/blocks.rs b/subxt/src/book/usage/blocks.rs index 2fea83020a..95befa6818 100644 --- a/subxt/src/book/usage/blocks.rs +++ b/subxt/src/book/usage/blocks.rs @@ -46,7 +46,7 @@ //! variants has a field that is another enum whose variants cover all calls of the respective pallet. //! If the extrinsic bytes are valid and your metadata matches the chain's metadata, decoding the bytes of an extrinsic into //! this root extrinsic type should always succeed. -//! +//! //! This example shows how to subscribe to blocks and decode the extrinsics in each block into the root extrinsic type. //! Once we get hold of the [ExtrinsicDetails](crate::blocks::ExtrinsicDetails), we can decode it statically or dynamically. //! We can also access details about the extrinsic, including the associated events and signed extensions. From b7aacd9d3e245504c5d7029e19e30c3324b833d5 Mon Sep 17 00:00:00 2001 From: Pan chao <152830401+Pan-chao@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:13:26 +0100 Subject: [PATCH 09/10] chore(subxt/src): typo fix (#1370) * rpcmethods * followstr * mod and else --- subxt/src/backend/mod.rs | 2 +- subxt/src/backend/unstable/follow_stream_driver.rs | 2 +- subxt/src/backend/unstable/follow_stream_unpin.rs | 4 ++-- subxt/src/backend/unstable/rpc_methods.rs | 2 +- subxt/src/config/default_extrinsic_params.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/subxt/src/backend/mod.rs b/subxt/src/backend/mod.rs index 3fb9782c53..3db06818b3 100644 --- a/subxt/src/backend/mod.rs +++ b/subxt/src/backend/mod.rs @@ -310,7 +310,7 @@ pub enum TransactionStatus { /// Number of peers it's been broadcast to. num_peers: u32, }, - /// Transaciton is no longer in a best block. + /// Transaction is no longer in a best block. NoLongerInBestBlock, /// Transaction has been included in block with given hash. InBestBlock { diff --git a/subxt/src/backend/unstable/follow_stream_driver.rs b/subxt/src/backend/unstable/follow_stream_driver.rs index fdca29723a..482bfd2543 100644 --- a/subxt/src/backend/unstable/follow_stream_driver.rs +++ b/subxt/src/backend/unstable/follow_stream_driver.rs @@ -240,7 +240,7 @@ impl Shared { } } - // Keep our buffer of ready/block events uptodate: + // Keep our buffer of ready/block events up-to-date: match item { FollowStreamMsg::Ready(sub_id) => { // Set new subscription ID when it comes in. diff --git a/subxt/src/backend/unstable/follow_stream_unpin.rs b/subxt/src/backend/unstable/follow_stream_unpin.rs index 3f055f9f4d..fe064f0707 100644 --- a/subxt/src/backend/unstable/follow_stream_unpin.rs +++ b/subxt/src/backend/unstable/follow_stream_unpin.rs @@ -206,7 +206,7 @@ impl Stream for FollowStreamUnpin { FollowStreamMsg::Event(FollowEvent::Stop) } - // These events aren't intresting; we just forward them on: + // These events aren't interesting; we just forward them on: FollowStreamMsg::Event(FollowEvent::OperationBodyDone(details)) => { FollowStreamMsg::Event(FollowEvent::OperationBodyDone(details)) } @@ -364,7 +364,7 @@ impl FollowStreamUnpin { // Any new futures pushed above need polling to start. We could // just wait for the next stream event, but let's wake the task to - // have it polled sooner, just incase it's slow to receive things. + // have it polled sooner, just in case it's slow to receive things. waker.wake_by_ref(); } } diff --git a/subxt/src/backend/unstable/rpc_methods.rs b/subxt/src/backend/unstable/rpc_methods.rs index ca1a38691b..331cb5459b 100644 --- a/subxt/src/backend/unstable/rpc_methods.rs +++ b/subxt/src/backend/unstable/rpc_methods.rs @@ -542,7 +542,7 @@ pub enum StorageResultType { ClosestDescendantMerkleValue(Bytes), } -/// The method respose of `chainHead_body`, `chainHead_call` and `chainHead_storage`. +/// The method response of `chainHead_body`, `chainHead_call` and `chainHead_storage`. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(tag = "result")] diff --git a/subxt/src/config/default_extrinsic_params.rs b/subxt/src/config/default_extrinsic_params.rs index 880591e7f0..dce83853bf 100644 --- a/subxt/src/config/default_extrinsic_params.rs +++ b/subxt/src/config/default_extrinsic_params.rs @@ -100,7 +100,7 @@ impl DefaultExtrinsicParamsBuilder { self } - /// Provide a tip to the block auther using the token denominated by the `asset_id` provided. This + /// Provide a tip to the block author using the token denominated by the `asset_id` provided. This /// is not applicable on chains which don't use the `ChargeAssetTxPayment` signed extension; in this /// case, no tip will be given. pub fn tip_of(mut self, tip: u128, asset_id: T::AssetId) -> Self { From 319272de661446fe9f47b4dd289eba0ac0924339 Mon Sep 17 00:00:00 2001 From: Tadeo Hepperle <62739623+tadeohepperle@users.noreply.github.com> Date: Wed, 17 Jan 2024 12:28:58 +0100 Subject: [PATCH 10/10] Weekly Cronjob fetching artifacts and generating polkadot.rs file. (#1352) * github CI action cronjob * add commit message * fix the CI yml files * binary crate for CI script with substrate-runner * update the CI script * correct the artifacts script * remove bash script --- .editorconfig | 3 + .github/workflows/build-substrate.yml | 2 +- .github/workflows/nightly.yml | 1 - .github/workflows/rust.yml | 682 ++++++++++++------------- .github/workflows/update-artifacts.yml | 56 ++ Cargo.lock | 7 + Cargo.toml | 1 + scripts/artifacts.sh | 26 - scripts/artifacts/.gitignore | 1 + scripts/artifacts/Cargo.lock | 14 + scripts/artifacts/Cargo.toml | 14 + scripts/artifacts/src/main.rs | 89 ++++ 12 files changed, 527 insertions(+), 369 deletions(-) create mode 100644 .github/workflows/update-artifacts.yml delete mode 100755 scripts/artifacts.sh create mode 100644 scripts/artifacts/.gitignore create mode 100644 scripts/artifacts/Cargo.lock create mode 100644 scripts/artifacts/Cargo.toml create mode 100644 scripts/artifacts/src/main.rs diff --git a/.editorconfig b/.editorconfig index 9fb23ce694..f0735cedfb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,6 @@ trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 + +[*.yml] +indent_size = 2 diff --git a/.github/workflows/build-substrate.yml b/.github/workflows/build-substrate.yml index 4ab008fb85..4cadcc7200 100644 --- a/.github/workflows/build-substrate.yml +++ b/.github/workflows/build-substrate.yml @@ -41,4 +41,4 @@ jobs: name: nightly-substrate-binary path: target/release/substrate-node retention-days: 2 - if-no-files-found: error \ No newline at end of file + if-no-files-found: error diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 640c2716fe..2add781112 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -5,7 +5,6 @@ on: # Run at 8am every day, well after the new binary is built - cron: "0 8 * * *" - env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 225b5e8158..ed5d8fe04b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,350 +1,350 @@ name: Rust on: - push: - # Run jobs when commits are pushed to - # master or release-like branches: - branches: - - master - pull_request: - # Run jobs for any external PR that wants - # to merge to master, too: - branches: - - master + push: + # Run jobs when commits are pushed to + # master or release-like branches: + branches: + - master + pull_request: + # Run jobs for any external PR that wants + # to merge to master, too: + branches: + - master concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true env: - CARGO_TERM_COLOR: always - # Increase wasm test timeout from 20 seconds (default) to 1 minute. - WASM_BINDGEN_TEST_TIMEOUT: 60 + CARGO_TERM_COLOR: always + # Increase wasm test timeout from 20 seconds (default) to 1 minute. + WASM_BINDGEN_TEST_TIMEOUT: 60 jobs: - check: - name: Cargo check - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Install cargo-hack - uses: baptiste0928/cargo-install@v2 - with: - crate: cargo-hack - version: 0.5 - - # A basic check over all targets together. This may lead to features being combined etc, - # and doesn't test combinations of different features. - - name: Cargo check all targets. - run: cargo check --all-targets - - # Next, check subxt features. - # - `native` feature must always be enabled - # - `web` feature is always ignored. - # - This means, don't check --no-default-features and don't try enabling --all-features; both will fail - - name: Cargo hack; check each subxt feature - run: cargo hack -p subxt --each-feature check --exclude-no-default-features --exclude-all-features --exclude-features web --features native - - # Subxt-signer has the "subxt" features enabled in the "check all targets" test. Run it on its own to - # check it without. We can't enable subxt or web features here, so no cargo hack. - - name: Cargo check subxt-signer - run: | - cargo check -p subxt-signer - cargo check -p subxt-signer --no-default-features --features sr25519,native - cargo check -p subxt-signer --no-default-features --features ecdsa,native - - # We can't enable web features here, so no cargo hack. - - name: Cargo check subxt-lightclient - run: cargo check -p subxt-lightclient - - # Next, check each other package in isolation. - - name: Cargo hack; check each feature/crate on its own - run: cargo hack --exclude subxt --exclude subxt-signer --exclude subxt-lightclient --exclude-all-features --each-feature check --workspace - - # Check the parachain-example code, which isn't a part of the workspace so is otherwise ignored. - - name: Cargo check parachain-example - run: cargo check --manifest-path examples/parachain-example/Cargo.toml - - wasm_check: - name: Cargo check (WASM) - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: wasm32-unknown-unknown - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - # Check WASM examples, which aren't a part of the workspace and so are otherwise missed: - - name: Cargo check WASM examples - run: | - cargo check --manifest-path examples/wasm-example/Cargo.toml --target wasm32-unknown-unknown - - fmt: - name: Cargo fmt - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Install Rust nightly toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: rustfmt - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Cargo fmt - uses: actions-rs/cargo@v1.0.3 - with: - command: fmt - args: --all -- --check - - docs: - name: Check documentation and run doc tests - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - 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 documentation - uses: actions-rs/cargo@v1.0.3 - with: - command: test - args: --doc - - tests: - name: "Test (Native)" - runs-on: ubuntu-latest-16-cores - timeout-minutes: 30 - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Install cargo-nextest - run: cargo install cargo-nextest - - - name: Run tests - uses: actions-rs/cargo@v1.0.3 - with: - command: nextest - args: run --workspace - - unstable_backend_tests: - name: "Test (Unstable Backend)" - runs-on: ubuntu-latest-16-cores - timeout-minutes: 30 - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Install cargo-nextest - run: cargo install cargo-nextest - - - name: Run tests - uses: actions-rs/cargo@v1.0.3 - with: - command: nextest - args: run --workspace --features unstable-backend-client - - light_client_tests: - name: "Test (Light Client)" - runs-on: ubuntu-latest-16-cores - timeout-minutes: 30 - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Run tests - uses: actions-rs/cargo@v1.0.3 - with: - command: test - args: --release --package integration-tests --features unstable-light-client - - wasm_tests: - name: Test (WASM) - runs-on: ubuntu-latest - timeout-minutes: 30 - env: - # Set timeout for wasm tests to be much bigger than the default 20 secs. - WASM_BINDGEN_TEST_TIMEOUT: 300 - - steps: - - uses: actions/checkout@v4 - - - name: Install wasm-pack - run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - - name: Install firefox - uses: browser-actions/setup-firefox@latest - - - name: Install chrome - uses: browser-actions/setup-chrome@latest - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Run subxt WASM tests - run: | - # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. - # `node-key` provides a deterministic p2p address. - substrate-node --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & - wasm-pack test --headless --firefox - wasm-pack test --headless --chrome - pkill substrate-node - working-directory: testing/wasm-rpc-tests - - - name: Run subxt-lightclient WASM tests - run: | - # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. - # `node-key` provides a deterministic p2p address. - substrate-node --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & - wasm-pack test --headless --firefox - wasm-pack test --headless --chrome - pkill substrate-node - working-directory: testing/wasm-lightclient-tests - - - name: Run subxt-signer WASM tests - run: | - wasm-pack test --headless --firefox - wasm-pack test --headless --chrome - working-directory: signer/wasm-tests - - clippy: - name: Cargo clippy - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - components: clippy - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Run clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets -- -D warnings - machete: - name: "Check unused dependencies" - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Use substrate-node binary - uses: ./.github/workflows/actions/use-substrate - - - name: Install Rust stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 - - - name: Install cargo-machete - run: cargo install cargo-machete - - - name: Check unused dependencies - uses: actions-rs/cargo@v1.0.3 - with: - command: machete + check: + name: Cargo check + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Install cargo-hack + uses: baptiste0928/cargo-install@v2 + with: + crate: cargo-hack + version: 0.5 + + # A basic check over all targets together. This may lead to features being combined etc, + # and doesn't test combinations of different features. + - name: Cargo check all targets. + run: cargo check --all-targets + + # Next, check subxt features. + # - `native` feature must always be enabled + # - `web` feature is always ignored. + # - This means, don't check --no-default-features and don't try enabling --all-features; both will fail + - name: Cargo hack; check each subxt feature + run: cargo hack -p subxt --each-feature check --exclude-no-default-features --exclude-all-features --exclude-features web --features native + + # Subxt-signer has the "subxt" features enabled in the "check all targets" test. Run it on its own to + # check it without. We can't enable subxt or web features here, so no cargo hack. + - name: Cargo check subxt-signer + run: | + cargo check -p subxt-signer + cargo check -p subxt-signer --no-default-features --features sr25519,native + cargo check -p subxt-signer --no-default-features --features ecdsa,native + + # We can't enable web features here, so no cargo hack. + - name: Cargo check subxt-lightclient + run: cargo check -p subxt-lightclient + + # Next, check each other package in isolation. + - name: Cargo hack; check each feature/crate on its own + run: cargo hack --exclude subxt --exclude subxt-signer --exclude subxt-lightclient --exclude-all-features --each-feature check --workspace + + # Check the parachain-example code, which isn't a part of the workspace so is otherwise ignored. + - name: Cargo check parachain-example + run: cargo check --manifest-path examples/parachain-example/Cargo.toml + + wasm_check: + name: Cargo check (WASM) + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + target: wasm32-unknown-unknown + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + # Check WASM examples, which aren't a part of the workspace and so are otherwise missed: + - name: Cargo check WASM examples + run: | + cargo check --manifest-path examples/wasm-example/Cargo.toml --target wasm32-unknown-unknown + + fmt: + name: Cargo fmt + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Install Rust nightly toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Cargo fmt + uses: actions-rs/cargo@v1.0.3 + with: + command: fmt + args: --all -- --check + + docs: + name: Check documentation and run doc tests + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - 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 documentation + uses: actions-rs/cargo@v1.0.3 + with: + command: test + args: --doc + + tests: + name: "Test (Native)" + runs-on: ubuntu-latest-16-cores + timeout-minutes: 30 + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Install cargo-nextest + run: cargo install cargo-nextest + + - name: Run tests + uses: actions-rs/cargo@v1.0.3 + with: + command: nextest + args: run --workspace + + unstable_backend_tests: + name: "Test (Unstable Backend)" + runs-on: ubuntu-latest-16-cores + timeout-minutes: 30 + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Install cargo-nextest + run: cargo install cargo-nextest + + - name: Run tests + uses: actions-rs/cargo@v1.0.3 + with: + command: nextest + args: run --workspace --features unstable-backend-client + + light_client_tests: + name: "Test (Light Client)" + runs-on: ubuntu-latest-16-cores + timeout-minutes: 30 + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Run tests + uses: actions-rs/cargo@v1.0.3 + with: + command: test + args: --release --package integration-tests --features unstable-light-client + + wasm_tests: + name: Test (WASM) + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + # Set timeout for wasm tests to be much bigger than the default 20 secs. + WASM_BINDGEN_TEST_TIMEOUT: 300 + + steps: + - uses: actions/checkout@v4 + + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Install firefox + uses: browser-actions/setup-firefox@latest + + - name: Install chrome + uses: browser-actions/setup-chrome@latest + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Run subxt WASM tests + run: | + # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. + # `node-key` provides a deterministic p2p address. + substrate-node --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & + wasm-pack test --headless --firefox + wasm-pack test --headless --chrome + pkill substrate-node + working-directory: testing/wasm-rpc-tests + + - name: Run subxt-lightclient WASM tests + run: | + # `listen-addr` is used to configure p2p to accept websocket connections instead of TCP. + # `node-key` provides a deterministic p2p address. + substrate-node --dev --node-key 0000000000000000000000000000000000000000000000000000000000000001 --listen-addr /ip4/0.0.0.0/tcp/30333/ws > /dev/null 2>&1 & + wasm-pack test --headless --firefox + wasm-pack test --headless --chrome + pkill substrate-node + working-directory: testing/wasm-lightclient-tests + + - name: Run subxt-signer WASM tests + run: | + wasm-pack test --headless --firefox + wasm-pack test --headless --chrome + working-directory: signer/wasm-tests + + clippy: + name: Cargo clippy + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: clippy + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Run clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-targets -- -D warnings + machete: + name: "Check unused dependencies" + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + + - name: Install cargo-machete + run: cargo install cargo-machete + + - name: Check unused dependencies + uses: actions-rs/cargo@v1.0.3 + with: + command: machete diff --git a/.github/workflows/update-artifacts.yml b/.github/workflows/update-artifacts.yml new file mode 100644 index 0000000000..fefed66a3d --- /dev/null +++ b/.github/workflows/update-artifacts.yml @@ -0,0 +1,56 @@ +name: Update Artifacts + +on: + workflow_dispatch: # Allows manual triggering + schedule: + - cron: "0 0 * * 1" # weekly on Monday at 00:00 UTC + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + name: Renew Artifacts + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + + # We run this (up-to-date) node locally to fetch metadata from it for the artifacts + - name: Use substrate-node binary + uses: ./.github/workflows/actions/use-substrate + + - name: Install Rust stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - name: Rust Cache + uses: Swatinem/rust-cache@3cf7f8cc28d1b4e7d01e3783be10a97d55d483c8 # v2.7.1 + + # This starts a substrate node and runs a few subxt cli child processes to fetch metadata from it and generate code. + # In particular it generates: + # - 4 metadata (*.scale) files in the `artifacts` directory + # - a polkadot.rs file from the full metadata that is checked in integration tests + # - a polkadot.json in the `artifacts/demo_chain_specs` directory + - name: Fetch Artifacts + run: cargo build --bin artifacts + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + base: master + branch: update-artifacts + commit-message: Update Artifacts (auto-generated) + branch-suffix: timestamp + title: Update Artifacts (auto-generated) + body: | + This PR updates the artifacts by fetching fresh metadata from a substrate node. + It also recreates the polkadot.rs file used in the integration tests. + It was created automatically by a Weekly GitHub Action Cronjob. diff --git a/Cargo.lock b/Cargo.lock index cf7d806a4a..c0c7edece2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,6 +331,13 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "artifacts" +version = "0.33.0" +dependencies = [ + "substrate-runner", +] + [[package]] name = "assert_matches" version = "1.5.0" diff --git a/Cargo.toml b/Cargo.toml index 8bd8eb21a2..d52a1126e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "metadata", "signer", "subxt", + "scripts/artifacts" ] # We exclude any crates that would depend on non mutually diff --git a/scripts/artifacts.sh b/scripts/artifacts.sh deleted file mode 100755 index f201e7cf81..0000000000 --- a/scripts/artifacts.sh +++ /dev/null @@ -1,26 +0,0 @@ -# # Generates the 3 metadata files in `/artifacts` and the polkadot.rs file for integration tests -# -# This script is to be run from the root of the repository: `scripts/artifacts.sh` -# -# It expects a local polkadot node to be running a JSON-RPC HTTP server at 127.0.0.1:9933 -# A local polkadot node can be run via: -# ``` -# git clone https://github.com/paritytech/polkadot.git -# cd polkadot -# cargo build --release -# ./target/release/polkadot --dev --tmp -# ``` - -# get the full metadata -cargo run --bin subxt metadata --version 15 > artifacts/polkadot_metadata_full.scale -# use it to generate polkadot.rs -cargo run --bin subxt codegen --file artifacts/polkadot_metadata_full.scale | rustfmt > testing/integration-tests/src/full_client/codegen/polkadot.rs -# generate a metadata file that only contains a few pallets that we need for our examples. -cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets "Balances,Staking,System,Multisig,Timestamp,ParaInherent" > artifacts/polkadot_metadata_small.scale -# generate a metadata file that contains no pallets -cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets "" > artifacts/polkadot_metadata_tiny.scale -# generate a metadata file that only contains some custom metadata -cargo run --bin generate-custom-metadata > artifacts/metadata_with_custom_values.scale - -# Generate the polkadot chain spec. -cargo run --features chain-spec-pruning --bin subxt chain-spec --url wss://rpc.polkadot.io:443 --output-file artifacts/demo_chain_specs/polkadot.json --state-root-hash --remove-substitutes diff --git a/scripts/artifacts/.gitignore b/scripts/artifacts/.gitignore new file mode 100644 index 0000000000..c41cc9e35e --- /dev/null +++ b/scripts/artifacts/.gitignore @@ -0,0 +1 @@ +/target \ No newline at end of file diff --git a/scripts/artifacts/Cargo.lock b/scripts/artifacts/Cargo.lock new file mode 100644 index 0000000000..d1fb446b78 --- /dev/null +++ b/scripts/artifacts/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "artifacts" +version = "0.1.0" +dependencies = [ + "substrate-runner", +] + +[[package]] +name = "substrate-runner" +version = "0.33.0" diff --git a/scripts/artifacts/Cargo.toml b/scripts/artifacts/Cargo.toml new file mode 100644 index 0000000000..b06ea9da56 --- /dev/null +++ b/scripts/artifacts/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "artifacts" +authors.workspace = true +edition.workspace = true +version.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +documentation.workspace = true +homepage.workspace = true +description = "Internal tool to regenerate artifacts" + +[dependencies] +substrate-runner = { workspace = true } diff --git a/scripts/artifacts/src/main.rs b/scripts/artifacts/src/main.rs new file mode 100644 index 0000000000..fa3ecb4315 --- /dev/null +++ b/scripts/artifacts/src/main.rs @@ -0,0 +1,89 @@ +use std::{ + fs::File, + process::{Command, Stdio}, +}; + +use substrate_runner::SubstrateNode; + +/// A Script to generate artifacts that are used in the integration tests. +/// +/// Run with `cargo run --bin artifacts` from the root of the repository. +fn main() { + let mut node_builder = SubstrateNode::builder(); + node_builder.binary_paths(["substrate-node", "substrate"]); + + // Spawn the node and retrieve a ws URL to it: + let proc = node_builder + .spawn() + .map_err(|e| e.to_string()) + .expect("Could not spawn node"); + let node_url = format!("ws://127.0.0.1:{}", proc.ws_port()); + + // Get the full metadata from the spawned substrate node + Command::make(&format!( + "cargo run --bin subxt metadata --version 15 --url {node_url}" + )) + .out("artifacts/polkadot_metadata_full.scale"); + + // Use it to generate polkadot.rs + Command::make("cargo run --bin subxt codegen --file artifacts/polkadot_metadata_full.scale") + .pipe("rustfmt") + .out("testing/integration-tests/src/full_client/codegen/polkadot.rs"); + + // Generate a metadata file that only contains a few pallets that we need for our examples. + Command::make(r#"cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets "Balances,Staking,System,Multisig,Timestamp,ParaInherent""#) + .out("artifacts/polkadot_metadata_small.scale"); + + // Generate a metadata file that contains no pallets + Command::make(r#"cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets """#) + .out("artifacts/polkadot_metadata_tiny.scale"); + + // Generate a metadata file that only contains some custom metadata + Command::make("cargo run --bin generate-custom-metadata") + .out("artifacts/metadata_with_custom_values.scale"); + + // Generate the polkadot chain spec. + Command::make("cargo run --features chain-spec-pruning --bin subxt chain-spec --url wss://rpc.polkadot.io:443 --output-file artifacts/demo_chain_specs/polkadot.json --state-root-hash --remove-substitutes").spawn().unwrap().wait().unwrap(); +} + +trait CommandT { + /// Creates a new command, parsing the arg_string provided. + fn make(arg_string: &str) -> Self; + + /// Pipes the output of the current command to the next command. + fn pipe(self, arg_string: &str) -> Self; + + /// Writes bytes from stdout to a new file at path. + fn out(self, path: &str); +} + +impl CommandT for Command { + fn make(arg_string: &str) -> Self { + // Note: simple space splitting, no fancy parsing of e.g. quotes surrounding whitespace. + let mut parts = arg_string.split(' '); + let program = parts.next().expect("no program in command string"); + let mut command = Command::new(program); + for e in parts { + command.arg(e); + } + command + } + + fn pipe(mut self, arg_string: &str) -> Self { + // execute self + let old_cmd = self.stdout(Stdio::piped()).spawn().unwrap(); + let mut next_cmd = Self::make(arg_string); + next_cmd.stdin(Stdio::from(old_cmd.stdout.unwrap())); + next_cmd + } + + fn out(mut self, path: &str) { + dbg!(path); + let file = File::create(path).unwrap(); + self.stdout(Stdio::from(file)) + .spawn() + .unwrap() + .wait() + .unwrap(); + } +}