mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 06:41:02 +00:00
subxt-core crate (#1466)
* start migrating, broken * first iteration of updating * fmt and clippy * add Composite<u32> decoding via scale value patch * bump scale type gen versions * fix decoding with new scale decode * compiling with changed deps * core utils, condig, client, metadata * core crate compiling * signer crate no once lock * add core to no-std-tests, change imports * broken commit, start pulling everything together in subxt * port more things to subxt * events in core crate, extrinsics sadly much more difficult * almost all examples pass again * dynamic values fix in examples * fix no std issue and fmt * remove unused dependencies * fix lightclient impl * runtime version refactor * formatting and addressing nits * more comments addressed * update wasm example and no-std-signer tests * other nits and error impl on signer errors * fix feature flag * fix runtime version refactor * fix doc links * fix integration tests * fix feature flag gated client state * fix native feature in CI * fix lightclient utils * make imports more lean in subxt-core * integrate changes from subxt-core imports into subxt * other changes in subxt simplify imports more * fix and docs * doc false for cli * fix clippy * remove events block hash in tests * codegen no-std support in generated code * export alloc crate for no-std codegen * fix doc test * implement James comments * remove std traits, use core traits instead * address nits * remove unusued dep in no-std tests * fix Box import in no_std * sp-crypto-hashing instead of sp-core-hashing * bump scale-typegen, add no std codegen tests * fix some things * replace unmaintained derivative with derive_where to remove non-canonical warnings * fmt * remove unused dep * fix deps * update artifacts to fix type ID mismatches * bump to latest scale-typegen --------- Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
@@ -187,8 +187,8 @@ jobs:
|
|||||||
- name: Cargo check subxt-signer
|
- name: Cargo check subxt-signer
|
||||||
run: |
|
run: |
|
||||||
cargo check -p subxt-signer
|
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 sr25519
|
||||||
cargo check -p subxt-signer --no-default-features --features ecdsa,native
|
cargo check -p subxt-signer --no-default-features --features ecdsa
|
||||||
|
|
||||||
# We can't enable web features here, so no cargo hack.
|
# We can't enable web features here, so no cargo hack.
|
||||||
- name: Cargo check subxt-lightclient
|
- name: Cargo check subxt-lightclient
|
||||||
|
|||||||
Generated
+54
-13
@@ -1270,6 +1270,17 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive-where"
|
||||||
|
version = "1.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.53",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.17"
|
version = "0.99.17"
|
||||||
@@ -2816,7 +2827,7 @@ checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcoin_hashes 0.13.0",
|
"bitcoin_hashes 0.13.0",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.6.4",
|
||||||
"serde",
|
"serde",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
@@ -3637,9 +3648,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scale-info"
|
name = "scale-info"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e"
|
checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -3651,9 +3662,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scale-info-derive"
|
name = "scale-info-derive"
|
||||||
version = "2.10.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19"
|
checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -3673,22 +3684,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scale-typegen"
|
name = "scale-typegen"
|
||||||
version = "0.2.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d6108609f017741c78d35967c7afe4aeaa3999b848282581041428e10d23b63"
|
checksum = "0906a872e5733f2633457001962007b644d2e17e08e74340f79820e4951b653f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
"smallvec",
|
||||||
"syn 2.0.53",
|
"syn 2.0.53",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scale-typegen-description"
|
name = "scale-typegen-description"
|
||||||
version = "0.2.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "479f0b8b0d75cce8d284ace5a9b7f5a12c523c94387c710835695e8b194a17bb"
|
checksum = "1601f61a2ec4f278cc6102204860893b90abd938ec7e9d02799748a97169b3c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"peekmore",
|
"peekmore",
|
||||||
@@ -4613,10 +4625,8 @@ version = "0.35.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_matches",
|
"assert_matches",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base58",
|
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake2",
|
"derive-where",
|
||||||
"derivative",
|
|
||||||
"either",
|
"either",
|
||||||
"frame-metadata 16.0.0",
|
"frame-metadata 16.0.0",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -4639,6 +4649,7 @@ dependencies = [
|
|||||||
"sp-crypto-hashing",
|
"sp-crypto-hashing",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
"subxt-core",
|
||||||
"subxt-lightclient",
|
"subxt-lightclient",
|
||||||
"subxt-macro",
|
"subxt-macro",
|
||||||
"subxt-metadata",
|
"subxt-metadata",
|
||||||
@@ -4700,6 +4711,36 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subxt-core"
|
||||||
|
version = "0.35.0"
|
||||||
|
dependencies = [
|
||||||
|
"base58",
|
||||||
|
"bitvec",
|
||||||
|
"blake2",
|
||||||
|
"derive-where",
|
||||||
|
"derive_more",
|
||||||
|
"frame-metadata 16.0.0",
|
||||||
|
"hashbrown 0.14.3",
|
||||||
|
"hex",
|
||||||
|
"impl-serde",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"primitive-types",
|
||||||
|
"scale-bits",
|
||||||
|
"scale-decode",
|
||||||
|
"scale-encode",
|
||||||
|
"scale-info",
|
||||||
|
"scale-value",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sp-core",
|
||||||
|
"sp-crypto-hashing",
|
||||||
|
"sp-keyring",
|
||||||
|
"sp-runtime",
|
||||||
|
"subxt-metadata",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subxt-lightclient"
|
name = "subxt-lightclient"
|
||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
@@ -4773,7 +4814,7 @@ dependencies = [
|
|||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-crypto-hashing",
|
"sp-crypto-hashing",
|
||||||
"sp-keyring",
|
"sp-keyring",
|
||||||
"subxt",
|
"subxt-core",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -2,6 +2,7 @@
|
|||||||
members = [
|
members = [
|
||||||
"cli",
|
"cli",
|
||||||
"codegen",
|
"codegen",
|
||||||
|
"core",
|
||||||
"lightclient",
|
"lightclient",
|
||||||
"testing/substrate-runner",
|
"testing/substrate-runner",
|
||||||
"testing/test-runtime",
|
"testing/test-runtime",
|
||||||
@@ -70,7 +71,7 @@ codec = { package = "parity-scale-codec", version = "3.6.9", default-features =
|
|||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
darling = "0.20.8"
|
darling = "0.20.8"
|
||||||
derivative = "2.2.0"
|
derive-where = "1.2.7"
|
||||||
derive_more = "0.99.17"
|
derive_more = "0.99.17"
|
||||||
either = { version = "1.10.0", default-features = false }
|
either = { version = "1.10.0", default-features = false }
|
||||||
frame-metadata = { version = "16.0.0", default-features = false }
|
frame-metadata = { version = "16.0.0", default-features = false }
|
||||||
@@ -93,6 +94,8 @@ scale-value = { version = "0.14.1", default-features = false }
|
|||||||
scale-bits = { version = "0.5.0", default-features = false }
|
scale-bits = { version = "0.5.0", default-features = false }
|
||||||
scale-decode = { version = "0.11.1", default-features = false }
|
scale-decode = { version = "0.11.1", default-features = false }
|
||||||
scale-encode = { version = "0.6.0", default-features = false }
|
scale-encode = { version = "0.6.0", default-features = false }
|
||||||
|
scale-typegen = "0.4.2"
|
||||||
|
scale-typegen-description = "0.4.2"
|
||||||
serde = { version = "1.0.197", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.197", default-features = false, features = ["derive"] }
|
||||||
serde_json = { version = "1.0.114", default-features = false }
|
serde_json = { version = "1.0.114", default-features = false }
|
||||||
syn = { version = "2.0.15", features = ["full", "extra-traits"] }
|
syn = { version = "2.0.15", features = ["full", "extra-traits"] }
|
||||||
@@ -106,8 +109,6 @@ url = "2.5.0"
|
|||||||
wabt = "0.10.0"
|
wabt = "0.10.0"
|
||||||
wasm-bindgen-test = "0.3.24"
|
wasm-bindgen-test = "0.3.24"
|
||||||
which = "5.0.0"
|
which = "5.0.0"
|
||||||
scale-typegen-description = "0.2.0"
|
|
||||||
scale-typegen = "0.2.0"
|
|
||||||
strip-ansi-escapes = "0.2.0"
|
strip-ansi-escapes = "0.2.0"
|
||||||
|
|
||||||
# Light client support:
|
# Light client support:
|
||||||
@@ -136,6 +137,7 @@ sp-keyring = "34.0.0"
|
|||||||
|
|
||||||
# Subxt workspace crates:
|
# Subxt workspace crates:
|
||||||
subxt = { version = "0.35.0", path = "subxt", default-features = false }
|
subxt = { version = "0.35.0", path = "subxt", default-features = false }
|
||||||
|
subxt-core = { version = "0.35.0", path = "core", default-features = false }
|
||||||
subxt-macro = { version = "0.35.0", path = "macro" }
|
subxt-macro = { version = "0.35.0", path = "macro" }
|
||||||
subxt-metadata = { version = "0.35.0", path = "metadata", default-features = false }
|
subxt-metadata = { version = "0.35.0", path = "metadata", default-features = false }
|
||||||
subxt-codegen = { version = "0.35.0", path = "codegen" }
|
subxt-codegen = { version = "0.35.0", path = "codegen" }
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -46,7 +46,7 @@ pub struct Opts {
|
|||||||
#[clap(long = "substitute-type", value_parser = substitute_type_parser)]
|
#[clap(long = "substitute-type", value_parser = substitute_type_parser)]
|
||||||
substitute_types: Vec<(String, String)>,
|
substitute_types: Vec<(String, String)>,
|
||||||
/// The `subxt` crate access path in the generated code.
|
/// The `subxt` crate access path in the generated code.
|
||||||
/// Defaults to `::subxt`.
|
/// Defaults to `::subxt::ext::subxt_core`.
|
||||||
#[clap(long = "crate")]
|
#[clap(long = "crate")]
|
||||||
crate_path: Option<String>,
|
crate_path: Option<String>,
|
||||||
/// Do not generate documentation for the runtime API code.
|
/// Do not generate documentation for the runtime API code.
|
||||||
|
|||||||
@@ -154,10 +154,7 @@ fn mocked_offline_client(metadata: Metadata) -> OfflineClient<SubstrateConfig> {
|
|||||||
H256::from_str("91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3")
|
H256::from_str("91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3")
|
||||||
.expect("Valid hash; qed");
|
.expect("Valid hash; qed");
|
||||||
|
|
||||||
let runtime_version = subxt::backend::RuntimeVersion {
|
let runtime_version = subxt::client::RuntimeVersion::new(9370, 20);
|
||||||
spec_version: 9370,
|
|
||||||
transaction_version: 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
OfflineClient::<SubstrateConfig>::new(genesis_hash, runtime_version, metadata)
|
OfflineClient::<SubstrateConfig>::new(genesis_hash, runtime_version, metadata)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use super::CodegenError;
|
|||||||
use heck::{ToSnakeCase as _, ToUpperCamelCase as _};
|
use heck::{ToSnakeCase as _, ToUpperCamelCase as _};
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::{typegen::ir::type_ir::CompositeIRKind, TypeGenerator};
|
use scale_typegen::{typegen::ir::type_ir::CompositeIRKind, TypeGenerator};
|
||||||
use subxt_metadata::PalletMetadata;
|
use subxt_metadata::PalletMetadata;
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ use subxt_metadata::PalletMetadata;
|
|||||||
///
|
///
|
||||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||||
/// - `pallet` - Pallet metadata from which the calls are generated.
|
/// - `pallet` - Pallet metadata from which the calls are generated.
|
||||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
/// - `crate_path` - The crate path under which the `subxt-core` crate is located, e.g. `::subxt::ext::subxt_core` when using subxt as a dependency.
|
||||||
pub fn generate_calls(
|
pub fn generate_calls(
|
||||||
type_gen: &TypeGenerator,
|
type_gen: &TypeGenerator,
|
||||||
pallet: &PalletMetadata,
|
pallet: &PalletMetadata,
|
||||||
@@ -41,9 +42,9 @@ pub fn generate_calls(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(name, field)| {
|
.map(|(name, field)| {
|
||||||
// Note: fn_arg_type this is relative the type path of the type alias when prefixed with `types::`, e.g. `set_max_code_size::New`
|
// Note: fn_arg_type this is relative the type path of the type alias when prefixed with `types::`, e.g. `set_max_code_size::New`
|
||||||
let fn_arg_type = &field.type_path;
|
let fn_arg_type = field.type_path.to_token_stream(type_gen.settings());
|
||||||
let call_arg = if field.is_boxed {
|
let call_arg = if field.is_boxed {
|
||||||
quote! { #name: ::std::boxed::Box::new(#name) }
|
quote! { #name: #crate_path::alloc::boxed::Box::new(#name) }
|
||||||
} else {
|
} else {
|
||||||
quote! { #name }
|
quote! { #name }
|
||||||
};
|
};
|
||||||
@@ -71,7 +72,9 @@ pub fn generate_calls(
|
|||||||
let docs = &var.composite.docs;
|
let docs = &var.composite.docs;
|
||||||
|
|
||||||
// this converts the composite into a full struct type. No Type Parameters needed here.
|
// this converts the composite into a full struct type. No Type Parameters needed here.
|
||||||
let struct_def = type_gen.upcast_composite(&var.composite);
|
let struct_def = type_gen
|
||||||
|
.upcast_composite(&var.composite)
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let alias_mod = var.type_alias_mod;
|
let alias_mod = var.type_alias_mod;
|
||||||
// The call structure's documentation was stripped above.
|
// The call structure's documentation was stripped above.
|
||||||
let call_struct = quote! {
|
let call_struct = quote! {
|
||||||
@@ -105,7 +108,9 @@ pub fn generate_calls(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
let call_type = type_gen.resolve_type_path(call_ty)?;
|
let call_type = type_gen
|
||||||
|
.resolve_type_path(call_ty)?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let call_ty = type_gen.resolve_type(call_ty)?;
|
let call_ty = type_gen.resolve_type(call_ty)?;
|
||||||
let docs = type_gen.docs_from_scale_info(&call_ty.docs);
|
let docs = type_gen.docs_from_scale_info(&call_ty.docs);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
use heck::ToSnakeCase as _;
|
use heck::ToSnakeCase as _;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::TypeGenerator;
|
use scale_typegen::TypeGenerator;
|
||||||
use subxt_metadata::PalletMetadata;
|
use subxt_metadata::PalletMetadata;
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ use super::CodegenError;
|
|||||||
///
|
///
|
||||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||||
/// - `pallet` - Pallet metadata from which the constants are generated.
|
/// - `pallet` - Pallet metadata from which the constants are generated.
|
||||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
/// - `crate_path` - The crate path under which the `subxt-core` crate is located, e.g. `::subxt::ext::subxt_core` when using subxt as a dependency.
|
||||||
pub fn generate_constants(
|
pub fn generate_constants(
|
||||||
type_gen: &TypeGenerator,
|
type_gen: &TypeGenerator,
|
||||||
pallet: &PalletMetadata,
|
pallet: &PalletMetadata,
|
||||||
@@ -55,7 +56,9 @@ pub fn generate_constants(
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let return_ty = type_gen.resolve_type_path(constant.ty())?;
|
let return_ty = type_gen
|
||||||
|
.resolve_type_path(constant.ty())?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let docs = constant.docs();
|
let docs = constant.docs();
|
||||||
let docs = type_gen
|
let docs = type_gen
|
||||||
.settings()
|
.settings()
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use heck::ToSnakeCase as _;
|
use heck::ToSnakeCase as _;
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::TypeGenerator;
|
use scale_typegen::TypeGenerator;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use subxt_metadata::{CustomValueMetadata, Metadata};
|
use subxt_metadata::{CustomValueMetadata, Metadata};
|
||||||
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::{quote, ToTokens};
|
use quote::quote;
|
||||||
|
|
||||||
/// Generate the custom values mod, if there are any custom values in the metadata. Else returns None.
|
/// Generate the custom values mod, if there are any custom values in the metadata. Else returns None.
|
||||||
pub fn generate_custom_values(
|
pub fn generate_custom_values(
|
||||||
@@ -60,8 +61,8 @@ fn generate_custom_value_fn(
|
|||||||
let return_ty = type_gen
|
let return_ty = type_gen
|
||||||
.resolve_type_path(custom_value.type_id())
|
.resolve_type_path(custom_value.type_id())
|
||||||
.expect("type is in metadata; qed")
|
.expect("type is in metadata; qed")
|
||||||
.to_token_stream();
|
.to_token_stream(type_gen.settings());
|
||||||
let decodable = quote!(#crate_path::custom_values::Yes);
|
let decodable = quote!(#crate_path::utils::Yes);
|
||||||
(return_ty, decodable)
|
(return_ty, decodable)
|
||||||
} else {
|
} else {
|
||||||
// if type registry does not contain the type, we can just return the Encoded scale bytes.
|
// if type registry does not contain the type, we can just return the Encoded scale bytes.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use scale_typegen::TypeGenerator;
|
|||||||
use subxt_metadata::PalletMetadata;
|
use subxt_metadata::PalletMetadata;
|
||||||
|
|
||||||
use super::CodegenError;
|
use super::CodegenError;
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
|
|
||||||
/// Generate error type alias from the provided pallet metadata.
|
/// Generate error type alias from the provided pallet metadata.
|
||||||
pub fn generate_error_type_alias(
|
pub fn generate_error_type_alias(
|
||||||
@@ -18,7 +19,9 @@ pub fn generate_error_type_alias(
|
|||||||
return Ok(quote!());
|
return Ok(quote!());
|
||||||
};
|
};
|
||||||
|
|
||||||
let error_type = type_gen.resolve_type_path(error_ty)?;
|
let error_type = type_gen
|
||||||
|
.resolve_type_path(error_ty)?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let error_ty = type_gen.resolve_type(error_ty)?;
|
let error_ty = type_gen.resolve_type(error_ty)?;
|
||||||
let docs = &error_ty.docs;
|
let docs = &error_ty.docs;
|
||||||
let docs = type_gen
|
let docs = type_gen
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
use super::CodegenError;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::TypeGenerator;
|
use scale_typegen::TypeGenerator;
|
||||||
use subxt_metadata::PalletMetadata;
|
use subxt_metadata::PalletMetadata;
|
||||||
|
|
||||||
use super::CodegenError;
|
|
||||||
|
|
||||||
/// Generate events from the provided pallet metadata.
|
/// Generate events from the provided pallet metadata.
|
||||||
///
|
///
|
||||||
/// The function creates a new module named `events` under the pallet's module.
|
/// The function creates a new module named `events` under the pallet's module.
|
||||||
@@ -37,7 +37,7 @@ use super::CodegenError;
|
|||||||
///
|
///
|
||||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||||
/// - `pallet` - Pallet metadata from which the events are generated.
|
/// - `pallet` - Pallet metadata from which the events are generated.
|
||||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
/// - `crate_path` - The crate path under which the `subxt-core` crate is located, e.g. `::subxt::ext::subxt_core` when using subxt as a dependency.
|
||||||
pub fn generate_events(
|
pub fn generate_events(
|
||||||
type_gen: &TypeGenerator,
|
type_gen: &TypeGenerator,
|
||||||
pallet: &PalletMetadata,
|
pallet: &PalletMetadata,
|
||||||
@@ -56,7 +56,9 @@ pub fn generate_events(
|
|||||||
let event_struct_name = &var.composite.name;
|
let event_struct_name = &var.composite.name;
|
||||||
let event_name = var.variant_name;
|
let event_name = var.variant_name;
|
||||||
let alias_mod = var.type_alias_mod;
|
let alias_mod = var.type_alias_mod;
|
||||||
let struct_def = type_gen.upcast_composite(&var.composite);
|
let struct_def = type_gen
|
||||||
|
.upcast_composite(&var.composite)
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
quote! {
|
quote! {
|
||||||
#struct_def
|
#struct_def
|
||||||
#alias_mod
|
#alias_mod
|
||||||
@@ -68,7 +70,9 @@ pub fn generate_events(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let event_type = type_gen.resolve_type_path(event_ty)?;
|
let event_type = type_gen
|
||||||
|
.resolve_type_path(event_ty)?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let event_ty = type_gen.resolve_type(event_ty)?;
|
let event_ty = type_gen.resolve_type(event_ty)?;
|
||||||
let docs = &event_ty.docs;
|
let docs = &event_ty.docs;
|
||||||
let docs = type_gen
|
let docs = type_gen
|
||||||
|
|||||||
+18
-7
@@ -13,6 +13,7 @@ mod runtime_apis;
|
|||||||
mod storage;
|
mod storage;
|
||||||
|
|
||||||
use scale_typegen::typegen::ir::type_ir::{CompositeFieldIR, CompositeIR, CompositeIRKind};
|
use scale_typegen::typegen::ir::type_ir::{CompositeFieldIR, CompositeIR, CompositeIRKind};
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::typegen::type_params::TypeParameters;
|
use scale_typegen::typegen::type_params::TypeParameters;
|
||||||
use scale_typegen::typegen::type_path::TypePath;
|
use scale_typegen::typegen::type_path::TypePath;
|
||||||
use scale_typegen::TypeGenerator;
|
use scale_typegen::TypeGenerator;
|
||||||
@@ -44,7 +45,7 @@ impl RuntimeGenerator {
|
|||||||
///
|
///
|
||||||
/// Supported versions: v14 and v15.
|
/// Supported versions: v14 and v15.
|
||||||
pub fn new(mut metadata: Metadata) -> Self {
|
pub fn new(mut metadata: Metadata) -> Self {
|
||||||
metadata.ensure_unique_type_paths();
|
scale_typegen::utils::ensure_unique_type_paths(metadata.types_mut());
|
||||||
RuntimeGenerator { metadata }
|
RuntimeGenerator { metadata }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,9 @@ impl RuntimeGenerator {
|
|||||||
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
||||||
|
|
||||||
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
||||||
let types_mod = type_gen.generate_types_mod()?;
|
let types_mod = type_gen
|
||||||
|
.generate_types_mod()?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let mod_ident = &item_mod_ir.ident;
|
let mod_ident = &item_mod_ir.ident;
|
||||||
let rust_items = item_mod_ir.rust_items();
|
let rust_items = item_mod_ir.rust_items();
|
||||||
|
|
||||||
@@ -121,7 +124,9 @@ impl RuntimeGenerator {
|
|||||||
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
||||||
|
|
||||||
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
||||||
let types_mod = type_gen.generate_types_mod()?;
|
let types_mod = type_gen
|
||||||
|
.generate_types_mod()?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
let types_mod_ident = type_gen.types_mod_ident();
|
let types_mod_ident = type_gen.types_mod_ident();
|
||||||
let pallets_with_mod_names = self
|
let pallets_with_mod_names = self
|
||||||
.metadata
|
.metadata
|
||||||
@@ -214,9 +219,15 @@ impl RuntimeGenerator {
|
|||||||
// Fetch the paths of the outer enums.
|
// Fetch the paths of the outer enums.
|
||||||
// Substrate exposes those under `kitchensink_runtime`, while Polkadot under `polkadot_runtime`.
|
// Substrate exposes those under `kitchensink_runtime`, while Polkadot under `polkadot_runtime`.
|
||||||
|
|
||||||
let call_path = type_gen.resolve_type_path(self.metadata.outer_enums().call_enum_ty())?;
|
let call_path = type_gen
|
||||||
let event_path = type_gen.resolve_type_path(self.metadata.outer_enums().event_enum_ty())?;
|
.resolve_type_path(self.metadata.outer_enums().call_enum_ty())?
|
||||||
let error_path = type_gen.resolve_type_path(self.metadata.outer_enums().error_enum_ty())?;
|
.to_token_stream(type_gen.settings());
|
||||||
|
let event_path = type_gen
|
||||||
|
.resolve_type_path(self.metadata.outer_enums().event_enum_ty())?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
|
let error_path = type_gen
|
||||||
|
.resolve_type_path(self.metadata.outer_enums().error_enum_ty())?
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
|
|
||||||
let custom_values = generate_custom_values(&self.metadata, &type_gen, &crate_path);
|
let custom_values = generate_custom_values(&self.metadata, &type_gen, &crate_path);
|
||||||
|
|
||||||
@@ -399,7 +410,7 @@ pub fn generate_type_alias_mod(
|
|||||||
.expect("composite name in snake_case should be a valid identifier");
|
.expect("composite name in snake_case should be a valid identifier");
|
||||||
|
|
||||||
let mut modify_field_to_be_type_alias = |field: &mut CompositeFieldIR, alias_name: Ident| {
|
let mut modify_field_to_be_type_alias = |field: &mut CompositeFieldIR, alias_name: Ident| {
|
||||||
let type_path = &field.type_path;
|
let type_path = field.type_path.to_token_stream(type_gen.settings());
|
||||||
aliases.push(quote!(pub type #alias_name = #type_path;));
|
aliases.push(quote!(pub type #alias_name = #type_path;));
|
||||||
|
|
||||||
let type_alias_path: syn::Path = parse_quote!(#alias_mod_name::#alias_name);
|
let type_alias_path: syn::Path = parse_quote!(#alias_mod_name::#alias_name);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use std::collections::HashSet;
|
|||||||
use heck::ToSnakeCase as _;
|
use heck::ToSnakeCase as _;
|
||||||
use heck::ToUpperCamelCase as _;
|
use heck::ToUpperCamelCase as _;
|
||||||
|
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
use scale_typegen::TypeGenerator;
|
use scale_typegen::TypeGenerator;
|
||||||
use subxt_metadata::{Metadata, RuntimeApiMetadata};
|
use subxt_metadata::{Metadata, RuntimeApiMetadata};
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ fn generate_runtime_api(
|
|||||||
// Generate alias for runtime type.
|
// Generate alias for runtime type.
|
||||||
let ty = type_gen
|
let ty = type_gen
|
||||||
.resolve_type_path(input.ty)
|
.resolve_type_path(input.ty)
|
||||||
.expect("runtime api input type is in metadata; qed");
|
.expect("runtime api input type is in metadata; qed").to_token_stream(type_gen.settings());
|
||||||
let aliased_param = quote!( pub type #alias_name = #ty; );
|
let aliased_param = quote!( pub type #alias_name = #ty; );
|
||||||
|
|
||||||
// Structures are placed on the same level as the alias module.
|
// Structures are placed on the same level as the alias module.
|
||||||
@@ -96,7 +97,7 @@ fn generate_runtime_api(
|
|||||||
let type_aliases = inputs.iter().map(|(_, _, _, aliased_param)| aliased_param);
|
let type_aliases = inputs.iter().map(|(_, _, _, aliased_param)| aliased_param);
|
||||||
let types_mod_ident = type_gen.types_mod_ident();
|
let types_mod_ident = type_gen.types_mod_ident();
|
||||||
|
|
||||||
let output = type_gen.resolve_type_path(method.output_ty())?;
|
let output = type_gen.resolve_type_path(method.output_ty())?.to_token_stream(type_gen.settings());
|
||||||
let aliased_module = quote!(
|
let aliased_module = quote!(
|
||||||
pub mod #method_name {
|
pub mod #method_name {
|
||||||
use super::#types_mod_ident;
|
use super::#types_mod_ident;
|
||||||
|
|||||||
+17
-10
@@ -13,6 +13,8 @@ use subxt_metadata::{
|
|||||||
|
|
||||||
use super::CodegenError;
|
use super::CodegenError;
|
||||||
|
|
||||||
|
use scale_typegen::typegen::ir::ToTokensWithSettings;
|
||||||
|
|
||||||
/// Generate functions which create storage addresses from the provided pallet's metadata.
|
/// Generate functions which create storage addresses from the provided pallet's metadata.
|
||||||
/// These addresses can be used to access and iterate over storage values.
|
/// These addresses can be used to access and iterate over storage values.
|
||||||
///
|
///
|
||||||
@@ -20,7 +22,7 @@ use super::CodegenError;
|
|||||||
///
|
///
|
||||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||||
/// - `pallet` - Pallet metadata from which the storage items are generated.
|
/// - `pallet` - Pallet metadata from which the storage items are generated.
|
||||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
/// - `crate_path` - The crate path under which the `subxt-core` crate is located, e.g. `::subxt::ext::subxt_core` when using subxt as a dependency.
|
||||||
pub fn generate_storage(
|
pub fn generate_storage(
|
||||||
type_gen: &TypeGenerator,
|
type_gen: &TypeGenerator,
|
||||||
pallet: &PalletMetadata,
|
pallet: &PalletMetadata,
|
||||||
@@ -69,7 +71,8 @@ fn generate_storage_entry_fns(
|
|||||||
let storage_entry_ty = storage_entry.entry_type().value_ty();
|
let storage_entry_ty = storage_entry.entry_type().value_ty();
|
||||||
let storage_entry_value_ty = type_gen
|
let storage_entry_value_ty = type_gen
|
||||||
.resolve_type_path(storage_entry_ty)
|
.resolve_type_path(storage_entry_ty)
|
||||||
.expect("storage type is in metadata; qed");
|
.expect("storage type is in metadata; qed")
|
||||||
|
.to_token_stream(type_gen.settings());
|
||||||
|
|
||||||
let alias_name = format_ident!("{}", storage_entry.name().to_upper_camel_case());
|
let alias_name = format_ident!("{}", storage_entry.name().to_upper_camel_case());
|
||||||
let alias_module_name = format_ident!("{snake_case_name}");
|
let alias_module_name = format_ident!("{snake_case_name}");
|
||||||
@@ -89,7 +92,7 @@ fn generate_storage_entry_fns(
|
|||||||
.expect("type is in metadata; qed");
|
.expect("type is in metadata; qed");
|
||||||
|
|
||||||
let alias_name = format_ident!("Param{}", idx);
|
let alias_name = format_ident!("Param{}", idx);
|
||||||
let alias_type = primitive_type_alias(&ty_path);
|
let alias_type = primitive_type_alias(&ty_path, type_gen.settings());
|
||||||
|
|
||||||
let alias_type_def = quote!( pub type #alias_name = #alias_type; );
|
let alias_type_def = quote!( pub type #alias_name = #alias_type; );
|
||||||
let alias_type_path = quote!( types::#alias_module_name::#alias_name );
|
let alias_type_path = quote!( types::#alias_module_name::#alias_name );
|
||||||
@@ -169,7 +172,7 @@ fn generate_storage_entry_fns(
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let is_defaultable_type = match storage_entry.modifier() {
|
let is_defaultable_type = match storage_entry.modifier() {
|
||||||
StorageEntryModifier::Default => quote!(#crate_path::storage::address::Yes),
|
StorageEntryModifier::Default => quote!(#crate_path::utils::Yes),
|
||||||
StorageEntryModifier::Optional => quote!(()),
|
StorageEntryModifier::Optional => quote!(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,10 +194,10 @@ fn generate_storage_entry_fns(
|
|||||||
(fn_name, false, true)
|
(fn_name, false, true)
|
||||||
};
|
};
|
||||||
let is_fetchable_type = is_fetchable
|
let is_fetchable_type = is_fetchable
|
||||||
.then_some(quote!(#crate_path::storage::address::Yes))
|
.then_some(quote!(#crate_path::utils::Yes))
|
||||||
.unwrap_or(quote!(()));
|
.unwrap_or(quote!(()));
|
||||||
let is_iterable_type = is_iterable
|
let is_iterable_type = is_iterable
|
||||||
.then_some(quote!(#crate_path::storage::address::Yes))
|
.then_some(quote!(#crate_path::utils::Yes))
|
||||||
.unwrap_or(quote!(()));
|
.unwrap_or(quote!(()));
|
||||||
|
|
||||||
let (keys, keys_type) = match keys_slice.len() {
|
let (keys, keys_type) = match keys_slice.len() {
|
||||||
@@ -247,7 +250,7 @@ fn generate_storage_entry_fns(
|
|||||||
arg_name,
|
arg_name,
|
||||||
alias_type_path,
|
alias_type_path,
|
||||||
..
|
..
|
||||||
}| quote!( #arg_name: impl ::std::borrow::Borrow<#alias_type_path> ),
|
}| quote!( #arg_name: impl ::core::borrow::Borrow<#alias_type_path> ),
|
||||||
);
|
);
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
@@ -297,16 +300,20 @@ fn generate_storage_entry_fns(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primitive_type_alias(type_path: &TypePath) -> TokenStream {
|
fn primitive_type_alias(
|
||||||
|
type_path: &TypePath,
|
||||||
|
settings: &scale_typegen::TypeGeneratorSettings,
|
||||||
|
) -> TokenStream {
|
||||||
// Vec<T> is cast to [T]
|
// Vec<T> is cast to [T]
|
||||||
if let Some(ty) = type_path.vec_type_param() {
|
if let Some(ty) = type_path.vec_type_param() {
|
||||||
|
let ty = ty.to_token_stream(settings);
|
||||||
return quote!([#ty]);
|
return quote!([#ty]);
|
||||||
}
|
}
|
||||||
// String is cast to str
|
// String is cast to str
|
||||||
if type_path.is_string() {
|
if type_path.is_string() {
|
||||||
return quote!(::core::primitive::str);
|
return quote!(::core::primitive::str);
|
||||||
}
|
}
|
||||||
quote!(#type_path)
|
type_path.to_token_stream(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -424,7 +431,7 @@ mod tests {
|
|||||||
let expected_storage_constructor = quote!(
|
let expected_storage_constructor = quote!(
|
||||||
fn #name_ident(
|
fn #name_ident(
|
||||||
&self,
|
&self,
|
||||||
_0: impl ::std::borrow::Borrow<types::#name_ident::Param0>,
|
_0: impl ::core::borrow::Borrow<types::#name_ident::Param0>,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
dbg!(&generated_str);
|
dbg!(&generated_str);
|
||||||
|
|||||||
+10
-5
@@ -25,6 +25,7 @@ use getrandom as _;
|
|||||||
|
|
||||||
use api::RuntimeGenerator;
|
use api::RuntimeGenerator;
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use scale_typegen::typegen::settings::AllocCratePath;
|
||||||
use scale_typegen::{
|
use scale_typegen::{
|
||||||
typegen::settings::substitutes::absolute_path, DerivesRegistry, TypeGeneratorSettings,
|
typegen::settings::substitutes::absolute_path, DerivesRegistry, TypeGeneratorSettings,
|
||||||
TypeSubstitutes, TypegenError,
|
TypeSubstitutes, TypegenError,
|
||||||
@@ -77,7 +78,7 @@ pub struct CodegenBuilder {
|
|||||||
impl Default for CodegenBuilder {
|
impl Default for CodegenBuilder {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CodegenBuilder {
|
CodegenBuilder {
|
||||||
crate_path: syn::parse_quote!(::subxt),
|
crate_path: syn::parse_quote!(::subxt::ext::subxt_core),
|
||||||
use_default_derives: true,
|
use_default_derives: true,
|
||||||
use_default_substitutions: true,
|
use_default_substitutions: true,
|
||||||
generate_docs: true,
|
generate_docs: true,
|
||||||
@@ -222,12 +223,12 @@ impl CodegenBuilder {
|
|||||||
self.item_mod = item_mod;
|
self.item_mod = item_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the path to the `subxt` crate. By default, we expect it to be at `::subxt`.
|
/// Set the path to the `subxt` crate. By default, we expect it to be at `::subxt::ext::subxt_core`.
|
||||||
pub fn set_subxt_crate_path(&mut self, crate_path: syn::Path) {
|
pub fn set_subxt_crate_path(&mut self, crate_path: syn::Path) {
|
||||||
self.crate_path = crate_path;
|
self.crate_path = crate_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate an interface, assuming that the default path to the `subxt` crate is `::subxt`.
|
/// Generate an interface, assuming that the default path to the `subxt` crate is `::subxt::ext::subxt_core`.
|
||||||
/// If the `subxt` crate is not available as a top level dependency, use `generate` and provide
|
/// If the `subxt` crate is not available as a top level dependency, use `generate` and provide
|
||||||
/// a valid path to the `subxt¦ crate.
|
/// a valid path to the `subxt¦ crate.
|
||||||
pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
|
pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
|
||||||
@@ -295,7 +296,7 @@ impl CodegenBuilder {
|
|||||||
/// The default [`scale_typegen::TypeGeneratorSettings`], subxt is using for generating code.
|
/// The default [`scale_typegen::TypeGeneratorSettings`], subxt is using for generating code.
|
||||||
/// Useful for emulating subxt's code generation settings from e.g. subxt-explorer.
|
/// Useful for emulating subxt's code generation settings from e.g. subxt-explorer.
|
||||||
pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
|
pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
|
||||||
let crate_path: syn::Path = parse_quote!(::subxt);
|
let crate_path: syn::Path = parse_quote!(::subxt::ext::subxt_core);
|
||||||
let derives = default_derives(&crate_path);
|
let derives = default_derives(&crate_path);
|
||||||
let substitutes = default_substitutes(&crate_path);
|
let substitutes = default_substitutes(&crate_path);
|
||||||
subxt_type_gen_settings(derives, substitutes, &crate_path, true)
|
subxt_type_gen_settings(derives, substitutes, &crate_path, true)
|
||||||
@@ -316,6 +317,7 @@ fn subxt_type_gen_settings(
|
|||||||
compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
|
compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
|
||||||
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
|
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
|
||||||
insert_codec_attributes: true,
|
insert_codec_attributes: true,
|
||||||
|
alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +389,10 @@ fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
|
|||||||
parse_quote!(BTreeMap),
|
parse_quote!(BTreeMap),
|
||||||
parse_quote!(#crate_path::utils::KeyedVec),
|
parse_quote!(#crate_path::utils::KeyedVec),
|
||||||
),
|
),
|
||||||
(parse_quote!(BTreeSet), parse_quote!(::std::vec::Vec)),
|
(
|
||||||
|
parse_quote!(BTreeSet),
|
||||||
|
parse_quote!(#crate_path::alloc::vec::Vec),
|
||||||
|
),
|
||||||
// The `UncheckedExtrinsic(pub Vec<u8>)` is part of the runtime API calls.
|
// The `UncheckedExtrinsic(pub Vec<u8>)` is part of the runtime API calls.
|
||||||
// The inner bytes represent the encoded extrinsic, however when deriving the
|
// The inner bytes represent the encoded extrinsic, however when deriving the
|
||||||
// `EncodeAsType` the bytes would be re-encoded. This leads to the bytes
|
// `EncodeAsType` the bytes would be re-encoded. This leads to the bytes
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
[package]
|
||||||
|
name = "subxt-core"
|
||||||
|
version.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
publish = true
|
||||||
|
|
||||||
|
license.workspace = true
|
||||||
|
readme = "README.md"
|
||||||
|
repository.workspace = true
|
||||||
|
documentation.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
description = "A no-std compatible subset of Subxt's functionality"
|
||||||
|
keywords = ["parity", "subxt", "extrinsic", "no-std"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = [
|
||||||
|
"codec/std",
|
||||||
|
"scale-info/std",
|
||||||
|
"scale-value/std",
|
||||||
|
"scale-bits/std",
|
||||||
|
"scale-decode/std",
|
||||||
|
"scale-encode/std",
|
||||||
|
"frame-metadata/std",
|
||||||
|
"subxt-metadata/std",
|
||||||
|
"hex/std",
|
||||||
|
"serde/std",
|
||||||
|
"serde_json/std",
|
||||||
|
"tracing/std",
|
||||||
|
"impl-serde/std",
|
||||||
|
"primitive-types/std",
|
||||||
|
]
|
||||||
|
substrate-compat = ["sp-core", "sp-runtime"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
codec = { package = "parity-scale-codec", workspace = true, default-features = false, features = ["derive"] }
|
||||||
|
scale-info = { workspace = true, default-features = false, features = ["bit-vec"] }
|
||||||
|
scale-value = { workspace = true, default-features = false }
|
||||||
|
scale-bits = { workspace = true, default-features = false }
|
||||||
|
scale-decode = { workspace = true, default-features = false, features = ["derive", "primitive-types"] }
|
||||||
|
scale-encode = { workspace = true, default-features = false, features = ["derive", "primitive-types", "bits"] }
|
||||||
|
frame-metadata = { workspace = true, default-features = false }
|
||||||
|
subxt-metadata = { workspace = true, default-features = false }
|
||||||
|
derive-where = { workspace = true }
|
||||||
|
derive_more = { workspace = true }
|
||||||
|
hex = { workspace = true, default-features = false, features = ["alloc"] }
|
||||||
|
serde = { workspace = true, default-features = false, features = ["derive"] }
|
||||||
|
serde_json = { workspace = true, default-features = false, features = ["raw_value", "alloc"] }
|
||||||
|
hashbrown = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
# For ss58 encoding AccountId32 to serialize them properly:
|
||||||
|
base58 = { workspace = true }
|
||||||
|
blake2 = { workspace = true }
|
||||||
|
|
||||||
|
# Provides some deserialization, types like U256/H256 and hashing impls like twox/blake256:
|
||||||
|
impl-serde = { workspace = true, default-features = false }
|
||||||
|
primitive-types = { workspace = true, default-features = false, features = ["codec", "serde_no_std", "scale-info"] }
|
||||||
|
sp-crypto-hashing = { workspace = true }
|
||||||
|
|
||||||
|
# Included if the "substrate-compat" feature is enabled.
|
||||||
|
sp-core = { workspace = true, optional = true }
|
||||||
|
sp-runtime = { workspace = true, optional = true }
|
||||||
|
tracing = { workspace = true, default-features = false }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
bitvec = { workspace = true }
|
||||||
|
codec = { workspace = true, features = ["derive", "bit-vec"] }
|
||||||
|
sp-core = { workspace = true }
|
||||||
|
sp-keyring = { workspace = true }
|
||||||
|
sp-runtime = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
defalt-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[package.metadata.playground]
|
||||||
|
defalt-features = true
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Subxt-Core
|
||||||
|
|
||||||
|
This library provides a no-std compatible subset of functionality that `subxt` and `subxt-signer` rely on.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use scale_decode::DecodeAsFields;
|
||||||
|
|
||||||
|
/// Trait to uniquely identify the extrinsic's identity from the runtime metadata.
|
||||||
|
///
|
||||||
|
/// Generated API structures that represent an extrinsic implement this trait.
|
||||||
|
///
|
||||||
|
/// The trait is utilized to decode emitted extrinsics from a block, via obtaining the
|
||||||
|
/// form of the `Extrinsic` from the metadata.
|
||||||
|
pub trait StaticExtrinsic: DecodeAsFields {
|
||||||
|
/// Pallet name.
|
||||||
|
const PALLET: &'static str;
|
||||||
|
/// Call name.
|
||||||
|
const CALL: &'static str;
|
||||||
|
|
||||||
|
/// Returns true if the given pallet and call names match this extrinsic.
|
||||||
|
fn is_extrinsic(pallet: &str, call: &str) -> bool {
|
||||||
|
Self::PALLET == pallet && Self::CALL == call
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
use crate::{config::Config, metadata::Metadata};
|
||||||
|
use derive_where::derive_where;
|
||||||
|
|
||||||
|
/// Each client should be able to provide access to the following fields
|
||||||
|
/// - runtime version
|
||||||
|
/// - genesis hash
|
||||||
|
/// - metadata
|
||||||
|
#[derive_where(Clone, Debug)]
|
||||||
|
pub struct ClientState<C: Config> {
|
||||||
|
genesis_hash: C::Hash,
|
||||||
|
runtime_version: RuntimeVersion,
|
||||||
|
metadata: Metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Config> ClientState<C> {
|
||||||
|
pub fn new(genesis_hash: C::Hash, runtime_version: RuntimeVersion, metadata: Metadata) -> Self {
|
||||||
|
Self {
|
||||||
|
genesis_hash,
|
||||||
|
runtime_version,
|
||||||
|
metadata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn metadata(&self) -> Metadata {
|
||||||
|
self.metadata.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn runtime_version(&self) -> RuntimeVersion {
|
||||||
|
self.runtime_version
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn genesis_hash(&self) -> C::Hash {
|
||||||
|
self.genesis_hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runtime version information needed to submit transactions.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct RuntimeVersion {
|
||||||
|
spec_version: u32,
|
||||||
|
transaction_version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeVersion {
|
||||||
|
pub fn new(spec_version: u32, transaction_version: u32) -> Self {
|
||||||
|
RuntimeVersion {
|
||||||
|
spec_version,
|
||||||
|
transaction_version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Version of the runtime specification. A full-node will not attempt to use its native
|
||||||
|
/// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
|
||||||
|
/// `spec_version` and `authoring_version` are the same between Wasm and native.
|
||||||
|
pub fn spec_version(&self) -> u32 {
|
||||||
|
self.spec_version
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All existing dispatches are fully compatible when this number doesn't change. If this
|
||||||
|
/// number changes, then `spec_version` must change, also.
|
||||||
|
///
|
||||||
|
/// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
|
||||||
|
/// either through an alteration in its user-level semantics, a parameter
|
||||||
|
/// added/removed/changed, a dispatchable being removed, a module being removed, or a
|
||||||
|
/// dispatchable/module changing its index.
|
||||||
|
///
|
||||||
|
/// It need *not* change when a new module is added or when a dispatchable is added.
|
||||||
|
pub fn transaction_version(&self) -> u32 {
|
||||||
|
self.transaction_version
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,46 +7,9 @@
|
|||||||
//! [`crate::config::DefaultExtrinsicParams`] provides a general-purpose
|
//! [`crate::config::DefaultExtrinsicParams`] provides a general-purpose
|
||||||
//! implementation of this that will work in many cases.
|
//! implementation of this that will work in many cases.
|
||||||
|
|
||||||
use crate::{client::OfflineClientT, Config};
|
|
||||||
use core::fmt::Debug;
|
|
||||||
|
|
||||||
use super::refine_params::RefineParams;
|
use super::refine_params::RefineParams;
|
||||||
|
use crate::{client::ClientState, error::ExtrinsicParamsError, Config};
|
||||||
/// An error that can be emitted when trying to construct an instance of [`ExtrinsicParams`],
|
use alloc::vec::Vec;
|
||||||
/// encode data from the instance, or match on signed extensions.
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum ExtrinsicParamsError {
|
|
||||||
/// Cannot find a type id in the metadata. The context provides some additional
|
|
||||||
/// information about the source of the error (eg the signed extension name).
|
|
||||||
#[error("Cannot find type id '{type_id} in the metadata (context: {context})")]
|
|
||||||
MissingTypeId {
|
|
||||||
/// Type ID.
|
|
||||||
type_id: u32,
|
|
||||||
/// Some arbitrary context to help narrow the source of the error.
|
|
||||||
context: &'static str,
|
|
||||||
},
|
|
||||||
/// A signed extension in use on some chain was not provided.
|
|
||||||
#[error("The chain expects a signed extension with the name {0}, but we did not provide one")]
|
|
||||||
UnknownSignedExtension(String),
|
|
||||||
/// Some custom error.
|
|
||||||
#[error("Error constructing extrinsic parameters: {0}")]
|
|
||||||
Custom(CustomExtrinsicParamsError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A custom error.
|
|
||||||
pub type CustomExtrinsicParamsError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
|
||||||
|
|
||||||
impl From<std::convert::Infallible> for ExtrinsicParamsError {
|
|
||||||
fn from(value: std::convert::Infallible) -> Self {
|
|
||||||
match value {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<CustomExtrinsicParamsError> for ExtrinsicParamsError {
|
|
||||||
fn from(value: CustomExtrinsicParamsError) -> Self {
|
|
||||||
ExtrinsicParamsError::Custom(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait allows you to configure the "signed extra" and
|
/// This trait allows you to configure the "signed extra" and
|
||||||
/// "additional" parameters that are a part of the transaction payload
|
/// "additional" parameters that are a part of the transaction payload
|
||||||
@@ -58,10 +21,7 @@ pub trait ExtrinsicParams<T: Config>: ExtrinsicParamsEncoder + Sized + 'static {
|
|||||||
type Params: RefineParams<T>;
|
type Params: RefineParams<T>;
|
||||||
|
|
||||||
/// Construct a new instance of our [`ExtrinsicParams`].
|
/// Construct a new instance of our [`ExtrinsicParams`].
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError>;
|
||||||
client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait is expected to be implemented for any [`ExtrinsicParams`], and
|
/// This trait is expected to be implemented for any [`ExtrinsicParams`], and
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ use scale_encode::EncodeAsType;
|
|||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder};
|
pub use default_extrinsic_params::{DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder};
|
||||||
pub use extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError};
|
pub use extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder};
|
||||||
pub use polkadot::{PolkadotConfig, PolkadotExtrinsicParams, PolkadotExtrinsicParamsBuilder};
|
pub use polkadot::{PolkadotConfig, PolkadotExtrinsicParams, PolkadotExtrinsicParamsBuilder};
|
||||||
pub use refine_params::{RefineParams, RefineParamsData};
|
pub use refine_params::{RefineParams, RefineParamsData};
|
||||||
pub use signed_extensions::SignedExtension;
|
pub use signed_extensions::SignedExtension;
|
||||||
@@ -77,7 +77,7 @@ pub trait BlockHash:
|
|||||||
+ Encode
|
+ Encode
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ Eq
|
+ Eq
|
||||||
+ std::hash::Hash
|
+ core::hash::Hash
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
impl<T> BlockHash for T where
|
impl<T> BlockHash for T where
|
||||||
@@ -92,7 +92,7 @@ impl<T> BlockHash for T where
|
|||||||
+ Encode
|
+ Encode
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ Eq
|
+ Eq
|
||||||
+ std::hash::Hash
|
+ core::hash::Hash
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
use super::{Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder};
|
use super::{Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder};
|
||||||
|
|
||||||
|
use crate::config::SubstrateConfig;
|
||||||
pub use crate::utils::{AccountId32, MultiAddress, MultiSignature};
|
pub use crate::utils::{AccountId32, MultiAddress, MultiSignature};
|
||||||
use crate::SubstrateConfig;
|
|
||||||
pub use primitive_types::{H256, U256};
|
pub use primitive_types::{H256, U256};
|
||||||
|
|
||||||
/// Default set of commonly used types by Polkadot nodes.
|
/// Default set of commonly used types by Polkadot nodes.
|
||||||
@@ -14,7 +14,9 @@ pub struct RefineParamsData<T: Config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> RefineParamsData<T> {
|
impl<T: Config> RefineParamsData<T> {
|
||||||
pub(crate) fn new(account_nonce: u64, block_number: u64, block_hash: T::Hash) -> Self {
|
#[doc(hidden)]
|
||||||
|
/// Creates a new [`RefineParamsData`] instance. Called from `subxt` when refining signed extensions.
|
||||||
|
pub fn new(account_nonce: u64, block_number: u64, block_hash: T::Hash) -> Self {
|
||||||
RefineParamsData {
|
RefineParamsData {
|
||||||
account_nonce,
|
account_nonce,
|
||||||
block_number,
|
block_number,
|
||||||
@@ -7,19 +7,24 @@
|
|||||||
//! [`AnyOf`] to configure the set of signed extensions which are known about
|
//! [`AnyOf`] to configure the set of signed extensions which are known about
|
||||||
//! when interacting with a chain.
|
//! when interacting with a chain.
|
||||||
|
|
||||||
use super::extrinsic_params::{ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError};
|
use super::extrinsic_params::ExtrinsicParams;
|
||||||
use super::refine_params::RefineParamsData;
|
use super::refine_params::RefineParamsData;
|
||||||
use super::RefineParams;
|
use super::RefineParams;
|
||||||
|
use crate::client::ClientState;
|
||||||
|
use crate::config::ExtrinsicParamsEncoder;
|
||||||
|
use crate::error::ExtrinsicParamsError;
|
||||||
use crate::utils::Era;
|
use crate::utils::Era;
|
||||||
use crate::{client::OfflineClientT, Config};
|
use crate::Config;
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::{Compact, Encode};
|
use codec::{Compact, Encode};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
|
use hashbrown::HashMap;
|
||||||
use scale_decode::DecodeAsType;
|
use scale_decode::DecodeAsType;
|
||||||
use scale_info::PortableRegistry;
|
use scale_info::PortableRegistry;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
/// A single [`SignedExtension`] has a unique name, but is otherwise the
|
/// A single [`SignedExtension`] has a unique name, but is otherwise the
|
||||||
/// same as [`ExtrinsicParams`] in describing how to encode the extra and
|
/// same as [`ExtrinsicParams`] in describing how to encode the extra and
|
||||||
/// additional data.
|
/// additional data.
|
||||||
@@ -41,11 +46,8 @@ pub struct CheckSpecVersion(u32);
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CheckSpecVersion {
|
impl<T: Config> ExtrinsicParams<T> for CheckSpecVersion {
|
||||||
type Params = ();
|
type Params = ();
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, _params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
client: Client,
|
Ok(CheckSpecVersion(client.runtime_version().spec_version()))
|
||||||
_params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(CheckSpecVersion(client.runtime_version().spec_version))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,10 +70,7 @@ pub struct CheckNonce(Compact<u64>);
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CheckNonce {
|
impl<T: Config> ExtrinsicParams<T> for CheckNonce {
|
||||||
type Params = CheckNonceParams;
|
type Params = CheckNonceParams;
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(_client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
_client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
// If no nonce is set (nor by user nor refinement), use a nonce of 0.
|
// If no nonce is set (nor by user nor refinement), use a nonce of 0.
|
||||||
let nonce = params.0.unwrap_or(0);
|
let nonce = params.0.unwrap_or(0);
|
||||||
Ok(CheckNonce(Compact(nonce)))
|
Ok(CheckNonce(Compact(nonce)))
|
||||||
@@ -109,11 +108,10 @@ pub struct CheckTxVersion(u32);
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CheckTxVersion {
|
impl<T: Config> ExtrinsicParams<T> for CheckTxVersion {
|
||||||
type Params = ();
|
type Params = ();
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, _params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
client: Client,
|
Ok(CheckTxVersion(
|
||||||
_params: Self::Params,
|
client.runtime_version().transaction_version(),
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
))
|
||||||
Ok(CheckTxVersion(client.runtime_version().transaction_version))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,10 +134,7 @@ pub struct CheckGenesis<T: Config>(T::Hash);
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CheckGenesis<T> {
|
impl<T: Config> ExtrinsicParams<T> for CheckGenesis<T> {
|
||||||
type Params = ();
|
type Params = ();
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, _params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
client: Client,
|
|
||||||
_params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(CheckGenesis(client.genesis_hash()))
|
Ok(CheckGenesis(client.genesis_hash()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,10 +205,7 @@ impl<T: Config> CheckMortalityParams<T> {
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CheckMortality<T> {
|
impl<T: Config> ExtrinsicParams<T> for CheckMortality<T> {
|
||||||
type Params = CheckMortalityParams<T>;
|
type Params = CheckMortalityParams<T>;
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
let check_mortality = if let Some(params) = params.0 {
|
let check_mortality = if let Some(params) = params.0 {
|
||||||
CheckMortality {
|
CheckMortality {
|
||||||
era: params.era,
|
era: params.era,
|
||||||
@@ -246,8 +238,8 @@ impl<T: Config> SignedExtension<T> for CheckMortality<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The [`ChargeAssetTxPayment`] signed extension.
|
/// The [`ChargeAssetTxPayment`] signed extension.
|
||||||
#[derive(Derivative, DecodeAsType)]
|
#[derive(DecodeAsType)]
|
||||||
#[derivative(Clone(bound = "T::AssetId: Clone"), Debug(bound = "T::AssetId: Debug"))]
|
#[derive_where(Clone, Debug; T::AssetId)]
|
||||||
#[decode_as_type(trait_bounds = "T::AssetId: DecodeAsType")]
|
#[decode_as_type(trait_bounds = "T::AssetId: DecodeAsType")]
|
||||||
pub struct ChargeAssetTxPayment<T: Config> {
|
pub struct ChargeAssetTxPayment<T: Config> {
|
||||||
tip: Compact<u128>,
|
tip: Compact<u128>,
|
||||||
@@ -308,10 +300,7 @@ impl<T: Config> ChargeAssetTxPaymentParams<T> {
|
|||||||
impl<T: Config> ExtrinsicParams<T> for ChargeAssetTxPayment<T> {
|
impl<T: Config> ExtrinsicParams<T> for ChargeAssetTxPayment<T> {
|
||||||
type Params = ChargeAssetTxPaymentParams<T>;
|
type Params = ChargeAssetTxPaymentParams<T>;
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(_client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
_client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(ChargeAssetTxPayment {
|
Ok(ChargeAssetTxPayment {
|
||||||
tip: Compact(params.tip),
|
tip: Compact(params.tip),
|
||||||
asset_id: params.asset_id,
|
asset_id: params.asset_id,
|
||||||
@@ -367,10 +356,7 @@ impl ChargeTransactionPaymentParams {
|
|||||||
impl<T: Config> ExtrinsicParams<T> for ChargeTransactionPayment {
|
impl<T: Config> ExtrinsicParams<T> for ChargeTransactionPayment {
|
||||||
type Params = ChargeTransactionPaymentParams;
|
type Params = ChargeTransactionPaymentParams;
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(_client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
_client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(ChargeTransactionPayment {
|
Ok(ChargeTransactionPayment {
|
||||||
tip: Compact(params.tip),
|
tip: Compact(params.tip),
|
||||||
})
|
})
|
||||||
@@ -397,7 +383,7 @@ impl<T: Config> SignedExtension<T> for ChargeTransactionPayment {
|
|||||||
/// is a sensible default, and allows for a single configuration to work across multiple chains.
|
/// is a sensible default, and allows for a single configuration to work across multiple chains.
|
||||||
pub struct AnyOf<T, Params> {
|
pub struct AnyOf<T, Params> {
|
||||||
params: Vec<Box<dyn ExtrinsicParamsEncoder>>,
|
params: Vec<Box<dyn ExtrinsicParamsEncoder>>,
|
||||||
_marker: std::marker::PhantomData<(T, Params)>,
|
_marker: core::marker::PhantomData<(T, Params)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_tuples {
|
macro_rules! impl_tuples {
|
||||||
@@ -412,8 +398,8 @@ macro_rules! impl_tuples {
|
|||||||
{
|
{
|
||||||
type Params = ($($ident::Params,)+);
|
type Params = ($($ident::Params,)+);
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(
|
||||||
client: Client,
|
client: &ClientState<T>,
|
||||||
params: Self::Params,
|
params: Self::Params,
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
) -> Result<Self, ExtrinsicParamsError> {
|
||||||
let metadata = client.metadata();
|
let metadata = client.metadata();
|
||||||
@@ -430,7 +416,7 @@ macro_rules! impl_tuples {
|
|||||||
}
|
}
|
||||||
// Break and record as soon as we find a match:
|
// Break and record as soon as we find a match:
|
||||||
if $ident::matches(e.identifier(), e.extra_ty(), types) {
|
if $ident::matches(e.identifier(), e.extra_ty(), types) {
|
||||||
let ext = $ident::new(client.clone(), params.$index)?;
|
let ext = $ident::new(client, params.$index)?;
|
||||||
let boxed_ext: Box<dyn ExtrinsicParamsEncoder> = Box::new(ext);
|
let boxed_ext: Box<dyn ExtrinsicParamsEncoder> = Box::new(ext);
|
||||||
exts_by_index.insert(idx, boxed_ext);
|
exts_by_index.insert(idx, boxed_ext);
|
||||||
break
|
break
|
||||||
@@ -453,7 +439,7 @@ macro_rules! impl_tuples {
|
|||||||
|
|
||||||
Ok(AnyOf {
|
Ok(AnyOf {
|
||||||
params,
|
params,
|
||||||
_marker: std::marker::PhantomData
|
_marker: core::marker::PhantomData
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
//! Substrate specific configuration
|
//! Substrate specific configuration
|
||||||
|
|
||||||
use super::{Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder, Hasher, Header};
|
use super::{Config, DefaultExtrinsicParams, DefaultExtrinsicParamsBuilder, Hasher, Header};
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -225,12 +227,69 @@ where
|
|||||||
{
|
{
|
||||||
// At the time of writing, Smoldot gives back block numbers in numeric rather
|
// At the time of writing, Smoldot gives back block numbers in numeric rather
|
||||||
// than hex format. So let's support deserializing from both here:
|
// than hex format. So let's support deserializing from both here:
|
||||||
use crate::backend::legacy::rpc_methods::NumberOrHex;
|
|
||||||
let number_or_hex = NumberOrHex::deserialize(d)?;
|
let number_or_hex = NumberOrHex::deserialize(d)?;
|
||||||
let u256 = number_or_hex.into_u256();
|
let u256 = number_or_hex.into_u256();
|
||||||
TryFrom::try_from(u256).map_err(|_| serde::de::Error::custom("Try from failed"))
|
TryFrom::try_from(u256).map_err(|_| serde::de::Error::custom("Try from failed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A number type that can be serialized both as a number or a string that encodes a number in a
|
||||||
|
/// string.
|
||||||
|
///
|
||||||
|
/// We allow two representations of the block number as input. Either we deserialize to the type
|
||||||
|
/// that is specified in the block type or we attempt to parse given hex value.
|
||||||
|
///
|
||||||
|
/// The primary motivation for having this type is to avoid overflows when using big integers in
|
||||||
|
/// JavaScript (which we consider as an important RPC API consumer).
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum NumberOrHex {
|
||||||
|
/// The number represented directly.
|
||||||
|
Number(u64),
|
||||||
|
/// Hex representation of the number.
|
||||||
|
Hex(U256),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NumberOrHex {
|
||||||
|
/// Converts this number into an U256.
|
||||||
|
pub fn into_u256(self) -> U256 {
|
||||||
|
match self {
|
||||||
|
NumberOrHex::Number(n) => n.into(),
|
||||||
|
NumberOrHex::Hex(h) => h,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NumberOrHex> for U256 {
|
||||||
|
fn from(num_or_hex: NumberOrHex) -> U256 {
|
||||||
|
num_or_hex.into_u256()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! into_number_or_hex {
|
||||||
|
($($t: ty)+) => {
|
||||||
|
$(
|
||||||
|
impl From<$t> for NumberOrHex {
|
||||||
|
fn from(x: $t) -> Self {
|
||||||
|
NumberOrHex::Number(x.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
into_number_or_hex!(u8 u16 u32 u64);
|
||||||
|
|
||||||
|
impl From<u128> for NumberOrHex {
|
||||||
|
fn from(n: u128) -> Self {
|
||||||
|
NumberOrHex::Hex(n.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<U256> for NumberOrHex {
|
||||||
|
fn from(n: U256) -> Self {
|
||||||
|
NumberOrHex::Hex(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -2,9 +2,11 @@
|
|||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use crate::{dynamic::DecodedValueThunk, metadata::DecodeWithMetadata};
|
use crate::dynamic::DecodedValueThunk;
|
||||||
use derivative::Derivative;
|
use crate::metadata::DecodeWithMetadata;
|
||||||
use std::borrow::Cow;
|
use alloc::borrow::Cow;
|
||||||
|
use alloc::string::String;
|
||||||
|
use derive_where::derive_where;
|
||||||
|
|
||||||
/// This represents a constant address. Anything implementing this trait
|
/// This represents a constant address. Anything implementing this trait
|
||||||
/// can be used to fetch constants.
|
/// can be used to fetch constants.
|
||||||
@@ -27,26 +29,12 @@ pub trait ConstantAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This represents the address of a constant.
|
/// This represents the address of a constant.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Ord(bound = ""),
|
|
||||||
PartialEq(bound = "")
|
|
||||||
)]
|
|
||||||
pub struct Address<ReturnTy> {
|
pub struct Address<ReturnTy> {
|
||||||
pallet_name: Cow<'static, str>,
|
pallet_name: Cow<'static, str>,
|
||||||
constant_name: Cow<'static, str>,
|
constant_name: Cow<'static, str>,
|
||||||
constant_hash: Option<[u8; 32]>,
|
constant_hash: Option<[u8; 32]>,
|
||||||
_marker: std::marker::PhantomData<ReturnTy>,
|
_marker: core::marker::PhantomData<ReturnTy>,
|
||||||
}
|
|
||||||
|
|
||||||
// Manual implementation to work around https://github.com/mcarton/rust-derivative/issues/115.
|
|
||||||
impl<ReturnTy> PartialOrd for Address<ReturnTy> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of address typically used to return dynamic constant values.
|
/// The type of address typically used to return dynamic constant values.
|
||||||
@@ -59,7 +47,7 @@ impl<ReturnTy> Address<ReturnTy> {
|
|||||||
pallet_name: Cow::Owned(pallet_name.into()),
|
pallet_name: Cow::Owned(pallet_name.into()),
|
||||||
constant_name: Cow::Owned(constant_name.into()),
|
constant_name: Cow::Owned(constant_name.into()),
|
||||||
constant_hash: None,
|
constant_hash: None,
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +63,7 @@ impl<ReturnTy> Address<ReturnTy> {
|
|||||||
pallet_name: Cow::Borrowed(pallet_name),
|
pallet_name: Cow::Borrowed(pallet_name),
|
||||||
constant_name: Cow::Borrowed(constant_name),
|
constant_name: Cow::Borrowed(constant_name),
|
||||||
constant_hash: Some(hash),
|
constant_hash: Some(hash),
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! Types associated with accessing constants.
|
||||||
|
|
||||||
|
mod constant_address;
|
||||||
|
|
||||||
|
pub use constant_address::{dynamic, Address, ConstantAddress, DynamicAddress};
|
||||||
|
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::MetadataError,
|
||||||
|
metadata::{DecodeWithMetadata, MetadataExt},
|
||||||
|
Error, Metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Run validation logic against some constant address you'd like to access. Returns `Ok(())`
|
||||||
|
/// if the address is valid (or if it's not possible to check since the address has no validation hash).
|
||||||
|
/// Return an error if the address was not valid or something went wrong trying to validate it (ie
|
||||||
|
/// the pallet or constant in question do not exist at all).
|
||||||
|
pub fn validate_constant<Address: ConstantAddress>(
|
||||||
|
metadata: &subxt_metadata::Metadata,
|
||||||
|
address: &Address,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(actual_hash) = address.validation_hash() {
|
||||||
|
let expected_hash = metadata
|
||||||
|
.pallet_by_name_err(address.pallet_name())?
|
||||||
|
.constant_hash(address.constant_name())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
MetadataError::ConstantNameNotFound(address.constant_name().to_owned())
|
||||||
|
})?;
|
||||||
|
if actual_hash != expected_hash {
|
||||||
|
return Err(MetadataError::IncompatibleCodegen.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_constant<Address: ConstantAddress>(
|
||||||
|
metadata: &Metadata,
|
||||||
|
address: &Address,
|
||||||
|
) -> Result<Address::Target, Error> {
|
||||||
|
// 1. Validate constant shape if hash given:
|
||||||
|
validate_constant(metadata, address)?;
|
||||||
|
|
||||||
|
// 2. Attempt to decode the constant into the type given:
|
||||||
|
let constant = metadata
|
||||||
|
.pallet_by_name_err(address.pallet_name())?
|
||||||
|
.constant_by_name(address.constant_name())
|
||||||
|
.ok_or_else(|| MetadataError::ConstantNameNotFound(address.constant_name().to_owned()))?;
|
||||||
|
let value = <Address::Target as DecodeWithMetadata>::decode_with_metadata(
|
||||||
|
&mut constant.value(),
|
||||||
|
constant.ty(),
|
||||||
|
metadata,
|
||||||
|
)?;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
+5
-21
@@ -1,8 +1,8 @@
|
|||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use crate::dynamic::DecodedValueThunk;
|
use crate::dynamic::DecodedValueThunk;
|
||||||
use crate::metadata::DecodeWithMetadata;
|
use crate::metadata::DecodeWithMetadata;
|
||||||
|
use crate::utils::Yes;
|
||||||
|
|
||||||
/// This represents the address of a custom value in in the metadata.
|
/// This represents the address of a custom value in in the metadata.
|
||||||
/// Anything, that implements the [CustomValueAddress] trait can be used, to fetch
|
/// Anything, that implements the [CustomValueAddress] trait can be used, to fetch
|
||||||
@@ -33,28 +33,12 @@ impl CustomValueAddress for str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to signal whether a [`CustomValueAddress`] can be decoded.
|
|
||||||
pub struct Yes;
|
|
||||||
|
|
||||||
/// A static address to a custom value.
|
/// A static address to a custom value.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Ord(bound = ""),
|
|
||||||
PartialEq(bound = "")
|
|
||||||
)]
|
|
||||||
pub struct StaticAddress<ReturnTy, IsDecodable> {
|
pub struct StaticAddress<ReturnTy, IsDecodable> {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
hash: Option<[u8; 32]>,
|
hash: Option<[u8; 32]>,
|
||||||
phantom: PhantomData<(ReturnTy, IsDecodable)>,
|
phantom: core::marker::PhantomData<(ReturnTy, IsDecodable)>,
|
||||||
}
|
|
||||||
|
|
||||||
impl<ReturnTy, IsDecodable> PartialOrd for StaticAddress<ReturnTy, IsDecodable> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
||||||
@@ -64,7 +48,7 @@ impl<ReturnTy, IsDecodable> StaticAddress<ReturnTy, IsDecodable> {
|
|||||||
StaticAddress::<ReturnTy, IsDecodable> {
|
StaticAddress::<ReturnTy, IsDecodable> {
|
||||||
name,
|
name,
|
||||||
hash: Some(hash),
|
hash: Some(hash),
|
||||||
phantom: PhantomData,
|
phantom: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! Types associated with accessing custom types
|
||||||
|
|
||||||
|
mod custom_value_address;
|
||||||
|
|
||||||
|
use crate::utils::Yes;
|
||||||
|
pub use custom_value_address::{CustomValueAddress, StaticAddress};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::MetadataError,
|
||||||
|
metadata::{DecodeWithMetadata, MetadataExt},
|
||||||
|
Error, Metadata,
|
||||||
|
};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())`
|
||||||
|
/// if the address is valid (or if it's not possible to check since the address has no validation hash).
|
||||||
|
/// Returns an error if the address was not valid (wrong name, type or raw bytes)
|
||||||
|
pub fn validate_custom_value<Address: CustomValueAddress + ?Sized>(
|
||||||
|
metadata: &Metadata,
|
||||||
|
address: &Address,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(actual_hash) = address.validation_hash() {
|
||||||
|
let custom = metadata.custom();
|
||||||
|
let custom_value = custom
|
||||||
|
.get(address.name())
|
||||||
|
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().into()))?;
|
||||||
|
let expected_hash = custom_value.hash();
|
||||||
|
if actual_hash != expected_hash {
|
||||||
|
return Err(MetadataError::IncompatibleCodegen.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if metadata.custom().get(address.name()).is_none() {
|
||||||
|
return Err(MetadataError::IncompatibleCodegen.into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access a custom value by the address it is registered under. This can be just a [str] to get back a dynamic value,
|
||||||
|
/// or a static address from the generated static interface to get a value of a static type returned.
|
||||||
|
pub fn get_custom_value<Address: CustomValueAddress<IsDecodable = Yes> + ?Sized>(
|
||||||
|
metadata: &Metadata,
|
||||||
|
address: &Address,
|
||||||
|
) -> Result<Address::Target, Error> {
|
||||||
|
// 1. Validate custom value shape if hash given:
|
||||||
|
validate_custom_value(metadata, address)?;
|
||||||
|
|
||||||
|
// 2. Attempt to decode custom value:
|
||||||
|
let custom_value = metadata.custom_value_by_name_err(address.name())?;
|
||||||
|
let value = <Address::Target as DecodeWithMetadata>::decode_with_metadata(
|
||||||
|
&mut custom_value.bytes(),
|
||||||
|
custom_value.type_id(),
|
||||||
|
metadata,
|
||||||
|
)?;
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the bytes of a custom value by the address it is registered under.
|
||||||
|
pub fn get_custom_value_bytes<Address: CustomValueAddress + ?Sized>(
|
||||||
|
metadata: &Metadata,
|
||||||
|
address: &Address,
|
||||||
|
) -> Result<Vec<u8>, Error> {
|
||||||
|
// 1. Validate custom value shape if hash given:
|
||||||
|
validate_custom_value(metadata, address)?;
|
||||||
|
|
||||||
|
// 2. Return the underlying bytes:
|
||||||
|
let custom_value = metadata.custom_value_by_name_err(address.name())?;
|
||||||
|
Ok(custom_value.bytes().to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use codec::Encode;
|
||||||
|
use scale_decode::DecodeAsType;
|
||||||
|
use scale_info::form::PortableForm;
|
||||||
|
use scale_info::TypeInfo;
|
||||||
|
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec;
|
||||||
|
|
||||||
|
use crate::custom_values::get_custom_value;
|
||||||
|
use crate::Metadata;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Encode, TypeInfo, DecodeAsType)]
|
||||||
|
pub struct Person {
|
||||||
|
age: u16,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mock_metadata() -> Metadata {
|
||||||
|
let person_ty = scale_info::MetaType::new::<Person>();
|
||||||
|
let unit = scale_info::MetaType::new::<()>();
|
||||||
|
let mut types = scale_info::Registry::new();
|
||||||
|
let person_ty_id = types.register_type(&person_ty);
|
||||||
|
let unit_id = types.register_type(&unit);
|
||||||
|
let types: scale_info::PortableRegistry = types.into();
|
||||||
|
|
||||||
|
let person = Person {
|
||||||
|
age: 42,
|
||||||
|
name: "Neo".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let person_value_metadata: frame_metadata::v15::CustomValueMetadata<PortableForm> =
|
||||||
|
frame_metadata::v15::CustomValueMetadata {
|
||||||
|
ty: person_ty_id,
|
||||||
|
value: person.encode(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let frame_metadata = frame_metadata::v15::RuntimeMetadataV15 {
|
||||||
|
types,
|
||||||
|
pallets: vec![],
|
||||||
|
extrinsic: frame_metadata::v15::ExtrinsicMetadata {
|
||||||
|
version: 0,
|
||||||
|
address_ty: unit_id,
|
||||||
|
call_ty: unit_id,
|
||||||
|
signature_ty: unit_id,
|
||||||
|
extra_ty: unit_id,
|
||||||
|
signed_extensions: vec![],
|
||||||
|
},
|
||||||
|
ty: unit_id,
|
||||||
|
apis: vec![],
|
||||||
|
outer_enums: frame_metadata::v15::OuterEnums {
|
||||||
|
call_enum_ty: unit_id,
|
||||||
|
event_enum_ty: unit_id,
|
||||||
|
error_enum_ty: unit_id,
|
||||||
|
},
|
||||||
|
custom: frame_metadata::v15::CustomMetadata {
|
||||||
|
map: BTreeMap::from_iter([("Mr. Robot".to_owned(), person_value_metadata)]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let metadata: subxt_metadata::Metadata = frame_metadata.try_into().unwrap();
|
||||||
|
Metadata::new(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decoding() {
|
||||||
|
let metadata = mock_metadata();
|
||||||
|
|
||||||
|
assert!(get_custom_value(&metadata, "Invalid Address").is_err());
|
||||||
|
let person_decoded_value_thunk = get_custom_value(&metadata, "Mr. Robot").unwrap();
|
||||||
|
let person: Person = person_decoded_value_thunk.as_type().unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
person,
|
||||||
|
Person {
|
||||||
|
age: 42,
|
||||||
|
name: "Neo".into()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,12 +5,9 @@
|
|||||||
//! This module provides the entry points to create dynamic
|
//! This module provides the entry points to create dynamic
|
||||||
//! transactions, storage and constant lookups.
|
//! transactions, storage and constant lookups.
|
||||||
|
|
||||||
use crate::{
|
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||||
error::Error,
|
use alloc::vec::Vec;
|
||||||
metadata::{DecodeWithMetadata, Metadata},
|
|
||||||
};
|
|
||||||
use scale_decode::DecodeAsType;
|
use scale_decode::DecodeAsType;
|
||||||
|
|
||||||
pub use scale_value::{At, Value};
|
pub use scale_value::{At, Value};
|
||||||
|
|
||||||
/// A [`scale_value::Value`] type endowed with contextual information
|
/// A [`scale_value::Value`] type endowed with contextual information
|
||||||
@@ -45,7 +42,7 @@ impl DecodeWithMetadata for DecodedValueThunk {
|
|||||||
bytes: &mut &[u8],
|
bytes: &mut &[u8],
|
||||||
type_id: u32,
|
type_id: u32,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, scale_decode::Error> {
|
||||||
let mut v = Vec::with_capacity(bytes.len());
|
let mut v = Vec::with_capacity(bytes.len());
|
||||||
v.extend_from_slice(bytes);
|
v.extend_from_slice(bytes);
|
||||||
*bytes = &[];
|
*bytes = &[];
|
||||||
@@ -67,7 +64,7 @@ impl DecodedValueThunk {
|
|||||||
&self.scale_bytes
|
&self.scale_bytes
|
||||||
}
|
}
|
||||||
/// Decode the SCALE encoded storage entry into a dynamic [`DecodedValue`] type.
|
/// Decode the SCALE encoded storage entry into a dynamic [`DecodedValue`] type.
|
||||||
pub fn to_value(&self) -> Result<DecodedValue, Error> {
|
pub fn to_value(&self) -> Result<DecodedValue, scale_decode::Error> {
|
||||||
let val = scale_value::scale::decode_as_type(
|
let val = scale_value::scale::decode_as_type(
|
||||||
&mut &*self.scale_bytes,
|
&mut &*self.scale_bytes,
|
||||||
&self.type_id,
|
&self.type_id,
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::string::String;
|
||||||
|
use derive_more::{Display, From};
|
||||||
|
use subxt_metadata::StorageHasher;
|
||||||
|
|
||||||
|
#[derive(Debug, Display, From)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Codec error.
|
||||||
|
#[display(fmt = "Scale codec error: {_0}")]
|
||||||
|
Codec(codec::Error),
|
||||||
|
#[display(fmt = "Metadata Error: {_0}")]
|
||||||
|
Metadata(MetadataError),
|
||||||
|
#[display(fmt = "Storage Error: {_0}")]
|
||||||
|
StorageAddress(StorageAddressError),
|
||||||
|
/// Error decoding to a [`crate::dynamic::Value`].
|
||||||
|
#[display(fmt = "Error decoding into dynamic value: {_0}")]
|
||||||
|
Decode(scale_decode::Error),
|
||||||
|
/// Error encoding from a [`crate::dynamic::Value`].
|
||||||
|
#[display(fmt = "Error encoding from dynamic value: {_0}")]
|
||||||
|
Encode(scale_encode::Error),
|
||||||
|
/// Error constructing the appropriate extrinsic params.
|
||||||
|
#[display(fmt = "Extrinsic params error: {_0}")]
|
||||||
|
ExtrinsicParams(ExtrinsicParamsError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<scale_decode::visitor::DecodeError> for Error {
|
||||||
|
fn from(value: scale_decode::visitor::DecodeError) -> Self {
|
||||||
|
Error::Decode(value.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
|
/// Something went wrong trying to access details in the metadata.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Display)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum MetadataError {
|
||||||
|
/// The DispatchError type isn't available in the metadata
|
||||||
|
#[display(fmt = "The DispatchError type isn't available")]
|
||||||
|
DispatchErrorNotFound,
|
||||||
|
/// Type not found in metadata.
|
||||||
|
#[display(fmt = "Type with ID {_0} not found")]
|
||||||
|
TypeNotFound(u32),
|
||||||
|
/// Pallet not found (index).
|
||||||
|
#[display(fmt = "Pallet with index {_0} not found")]
|
||||||
|
PalletIndexNotFound(u8),
|
||||||
|
/// Pallet not found (name).
|
||||||
|
#[display(fmt = "Pallet with name {_0} not found")]
|
||||||
|
PalletNameNotFound(String),
|
||||||
|
/// Variant not found.
|
||||||
|
#[display(fmt = "Variant with index {_0} not found")]
|
||||||
|
VariantIndexNotFound(u8),
|
||||||
|
/// Constant not found.
|
||||||
|
#[display(fmt = "Constant with name {_0} not found")]
|
||||||
|
ConstantNameNotFound(String),
|
||||||
|
/// Call not found.
|
||||||
|
#[display(fmt = "Call with name {_0} not found")]
|
||||||
|
CallNameNotFound(String),
|
||||||
|
/// Runtime trait not found.
|
||||||
|
#[display(fmt = "Runtime trait with name {_0} not found")]
|
||||||
|
RuntimeTraitNotFound(String),
|
||||||
|
/// Runtime method not found.
|
||||||
|
#[display(fmt = "Runtime method with name {_0} not found")]
|
||||||
|
RuntimeMethodNotFound(String),
|
||||||
|
/// Call type not found in metadata.
|
||||||
|
#[display(fmt = "Call type not found in pallet with index {_0}")]
|
||||||
|
CallTypeNotFoundInPallet(u8),
|
||||||
|
/// Event type not found in metadata.
|
||||||
|
#[display(fmt = "Event type not found in pallet with index {_0}")]
|
||||||
|
EventTypeNotFoundInPallet(u8),
|
||||||
|
/// Storage details not found in metadata.
|
||||||
|
#[display(fmt = "Storage details not found in pallet with name {_0}")]
|
||||||
|
StorageNotFoundInPallet(String),
|
||||||
|
/// Storage entry not found.
|
||||||
|
#[display(fmt = "Storage entry {_0} not found")]
|
||||||
|
StorageEntryNotFound(String),
|
||||||
|
/// The generated interface used is not compatible with the node.
|
||||||
|
#[display(fmt = "The generated code is not compatible with the node")]
|
||||||
|
IncompatibleCodegen,
|
||||||
|
/// Custom value not found.
|
||||||
|
#[display(fmt = "Custom value with name {_0} not found")]
|
||||||
|
CustomValueNameNotFound(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for MetadataError {}
|
||||||
|
|
||||||
|
/// Something went wrong trying to encode or decode a storage address.
|
||||||
|
#[derive(Clone, Debug, Display)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum StorageAddressError {
|
||||||
|
/// Storage lookup does not have the expected number of keys.
|
||||||
|
#[display(fmt = "Storage lookup requires {expected} keys but more keys have been provided.")]
|
||||||
|
TooManyKeys {
|
||||||
|
/// The number of keys provided in the storage address.
|
||||||
|
expected: usize,
|
||||||
|
},
|
||||||
|
/// This storage entry in the metadata does not have the correct number of hashers to fields.
|
||||||
|
#[display(
|
||||||
|
fmt = "Storage entry in metadata does not have the correct number of hashers to fields"
|
||||||
|
)]
|
||||||
|
WrongNumberOfHashers {
|
||||||
|
/// The number of hashers in the metadata for this storage entry.
|
||||||
|
hashers: usize,
|
||||||
|
/// The number of fields in the metadata for this storage entry.
|
||||||
|
fields: usize,
|
||||||
|
},
|
||||||
|
/// We weren't given enough bytes to decode the storage address/key.
|
||||||
|
#[display(fmt = "Not enough remaining bytes to decode the storage address/key")]
|
||||||
|
NotEnoughBytes,
|
||||||
|
/// We have leftover bytes after decoding the storage address.
|
||||||
|
#[display(fmt = "We have leftover bytes after decoding the storage address")]
|
||||||
|
TooManyBytes,
|
||||||
|
/// The bytes of a storage address are not the expected address for decoding the storage keys of the address.
|
||||||
|
#[display(
|
||||||
|
fmt = "Storage address bytes are not the expected format. Addresses need to be at least 16 bytes (pallet ++ entry) and follow a structure given by the hashers defined in the metadata"
|
||||||
|
)]
|
||||||
|
UnexpectedAddressBytes,
|
||||||
|
/// An invalid hasher was used to reconstruct a value from a chunk of bytes that is part of a storage address. Hashers where the hash does not contain the original value are invalid for this purpose.
|
||||||
|
#[display(
|
||||||
|
fmt = "An invalid hasher was used to reconstruct a value with type ID {ty_id} from a hash formed by a {hasher:?} hasher. This is only possible for concat-style hashers or the identity hasher"
|
||||||
|
)]
|
||||||
|
HasherCannotReconstructKey {
|
||||||
|
/// Type id of the key's type.
|
||||||
|
ty_id: u32,
|
||||||
|
/// The invalid hasher that caused this error.
|
||||||
|
hasher: StorageHasher,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for StorageAddressError {}
|
||||||
|
|
||||||
|
/// An error that can be emitted when trying to construct an instance of [`crate::config::ExtrinsicParams`],
|
||||||
|
/// encode data from the instance, or match on signed extensions.
|
||||||
|
#[derive(Display, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum ExtrinsicParamsError {
|
||||||
|
/// Cannot find a type id in the metadata. The context provides some additional
|
||||||
|
/// information about the source of the error (eg the signed extension name).
|
||||||
|
#[display(fmt = "Cannot find type id '{type_id} in the metadata (context: {context})")]
|
||||||
|
MissingTypeId {
|
||||||
|
/// Type ID.
|
||||||
|
type_id: u32,
|
||||||
|
/// Some arbitrary context to help narrow the source of the error.
|
||||||
|
context: &'static str,
|
||||||
|
},
|
||||||
|
/// A signed extension in use on some chain was not provided.
|
||||||
|
#[display(
|
||||||
|
fmt = "The chain expects a signed extension with the name {_0}, but we did not provide one"
|
||||||
|
)]
|
||||||
|
UnknownSignedExtension(String),
|
||||||
|
/// Some custom error.
|
||||||
|
#[display(fmt = "Error constructing extrinsic parameters: {_0}")]
|
||||||
|
Custom(Box<dyn CustomError>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Anything implementing this trait can be used in [`ExtrinsicParamsError::Custom`].
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub trait CustomError: std::error::Error + Send + Sync + 'static {}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl<T: std::error::Error + Send + Sync + 'static> CustomError for T {}
|
||||||
|
|
||||||
|
/// Anything implementing this trait can be used in [`ExtrinsicParamsError::Custom`].
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub trait CustomError: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static {}
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
impl<T: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static> CustomError for T {}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for ExtrinsicParamsError {}
|
||||||
|
|
||||||
|
impl From<core::convert::Infallible> for ExtrinsicParamsError {
|
||||||
|
fn from(value: core::convert::Infallible) -> Self {
|
||||||
|
match value {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<dyn CustomError>> for ExtrinsicParamsError {
|
||||||
|
fn from(value: Box<dyn CustomError>) -> Self {
|
||||||
|
ExtrinsicParamsError::Custom(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +1,48 @@
|
|||||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
use alloc::sync::Arc;
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
use alloc::vec::Vec;
|
||||||
// see LICENSE for license details.
|
use codec::{Compact, Decode, Encode};
|
||||||
|
use derive_where::derive_where;
|
||||||
|
use scale_decode::{DecodeAsFields, DecodeAsType};
|
||||||
|
use subxt_metadata::PalletMetadata;
|
||||||
|
|
||||||
//! A representation of a block of events.
|
use crate::{error::MetadataError, Config, Error, Metadata};
|
||||||
|
|
||||||
use super::{Phase, StaticEvent};
|
/// Trait to uniquely identify the events's identity from the runtime metadata.
|
||||||
use crate::{
|
///
|
||||||
client::OnlineClientT,
|
/// Generated API structures that represent an event implement this trait.
|
||||||
error::{Error, MetadataError},
|
///
|
||||||
events::events_client::get_event_bytes,
|
/// The trait is utilized to decode emitted events from a block, via obtaining the
|
||||||
metadata::types::PalletMetadata,
|
/// form of the `Event` from the metadata.
|
||||||
Config, Metadata,
|
pub trait StaticEvent: DecodeAsFields {
|
||||||
};
|
/// Pallet name.
|
||||||
use codec::{Compact, Decode};
|
const PALLET: &'static str;
|
||||||
use derivative::Derivative;
|
/// Event name.
|
||||||
use scale_decode::DecodeAsType;
|
const EVENT: &'static str;
|
||||||
use std::sync::Arc;
|
|
||||||
|
/// Returns true if the given pallet and event names match this event.
|
||||||
|
fn is_event(pallet: &str, event: &str) -> bool {
|
||||||
|
Self::PALLET == pallet && Self::EVENT == event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A collection of events obtained from a block, bundled with the necessary
|
/// A collection of events obtained from a block, bundled with the necessary
|
||||||
/// information needed to decode and iterate over them.
|
/// information needed to decode and iterate over them.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone)]
|
||||||
#[derivative(Clone(bound = ""))]
|
|
||||||
pub struct Events<T: Config> {
|
pub struct Events<T: Config> {
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
block_hash: T::Hash,
|
|
||||||
// Note; raw event bytes are prefixed with a Compact<u32> containing
|
// Note; raw event bytes are prefixed with a Compact<u32> containing
|
||||||
// the number of events to be decoded. The start_idx reflects that, so
|
// the number of events to be decoded. The start_idx reflects that, so
|
||||||
// that we can skip over those bytes when decoding them
|
// that we can skip over those bytes when decoding them
|
||||||
event_bytes: Arc<[u8]>,
|
event_bytes: Arc<[u8]>,
|
||||||
start_idx: usize,
|
start_idx: usize,
|
||||||
num_events: u32,
|
num_events: u32,
|
||||||
|
marker: core::marker::PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the Metadata when debug-logging events; it's big and distracting.
|
// Ignore the Metadata when debug-logging events; it's big and distracting.
|
||||||
impl<T: Config> std::fmt::Debug for Events<T> {
|
impl<T: Config> core::fmt::Debug for Events<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("Events")
|
f.debug_struct("Events")
|
||||||
.field("block_hash", &self.block_hash)
|
|
||||||
.field("event_bytes", &self.event_bytes)
|
.field("event_bytes", &self.event_bytes)
|
||||||
.field("start_idx", &self.start_idx)
|
.field("start_idx", &self.start_idx)
|
||||||
.field("num_events", &self.num_events)
|
.field("num_events", &self.num_events)
|
||||||
@@ -45,7 +51,8 @@ impl<T: Config> std::fmt::Debug for Events<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> Events<T> {
|
impl<T: Config> Events<T> {
|
||||||
pub(crate) fn new(metadata: Metadata, block_hash: T::Hash, event_bytes: Vec<u8>) -> Self {
|
/// Create a new [`Events`] instance from the given bytes.
|
||||||
|
pub fn decode_from(metadata: Metadata, event_bytes: Vec<u8>) -> Self {
|
||||||
// event_bytes is a SCALE encoded vector of events. So, pluck the
|
// event_bytes is a SCALE encoded vector of events. So, pluck the
|
||||||
// compact encoded length from the front, leaving the remaining bytes
|
// compact encoded length from the front, leaving the remaining bytes
|
||||||
// for our iterating to decode.
|
// for our iterating to decode.
|
||||||
@@ -60,34 +67,13 @@ impl<T: Config> Events<T> {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
metadata,
|
metadata,
|
||||||
block_hash,
|
|
||||||
event_bytes: event_bytes.into(),
|
event_bytes: event_bytes.into(),
|
||||||
start_idx,
|
start_idx,
|
||||||
num_events,
|
num_events,
|
||||||
|
marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtain the events from a block hash given custom metadata and a client.
|
|
||||||
///
|
|
||||||
/// # Notes
|
|
||||||
///
|
|
||||||
/// - Prefer to use [`crate::events::EventsClient::at`] to obtain the events.
|
|
||||||
/// - Subxt may fail to decode things that aren't from a runtime using the
|
|
||||||
/// latest metadata version.
|
|
||||||
/// - The client may not be able to obtain the block at the given hash. Only
|
|
||||||
/// archive nodes keep hold of all past block information.
|
|
||||||
pub async fn new_from_client<Client>(
|
|
||||||
metadata: Metadata,
|
|
||||||
block_hash: T::Hash,
|
|
||||||
client: Client,
|
|
||||||
) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
Client: OnlineClientT<T>,
|
|
||||||
{
|
|
||||||
let event_bytes = get_event_bytes(client.backend(), block_hash).await?;
|
|
||||||
Ok(Events::new(metadata, block_hash, event_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The number of events.
|
/// The number of events.
|
||||||
pub fn len(&self) -> u32 {
|
pub fn len(&self) -> u32 {
|
||||||
self.num_events
|
self.num_events
|
||||||
@@ -99,11 +85,6 @@ impl<T: Config> Events<T> {
|
|||||||
self.num_events == 0
|
self.num_events == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the block hash that these events are from.
|
|
||||||
pub fn block_hash(&self) -> T::Hash {
|
|
||||||
self.block_hash
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate over all of the events, using metadata to dynamically
|
/// Iterate over all of the events, using metadata to dynamically
|
||||||
/// decode them as we go, and returning the raw bytes and other associated
|
/// decode them as we go, and returning the raw bytes and other associated
|
||||||
/// details. If an error occurs, all subsequent iterations return `None`.
|
/// details. If an error occurs, all subsequent iterations return `None`.
|
||||||
@@ -119,7 +100,7 @@ impl<T: Config> Events<T> {
|
|||||||
|
|
||||||
let mut pos = self.start_idx;
|
let mut pos = self.start_idx;
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
std::iter::from_fn(move || {
|
core::iter::from_fn(move || {
|
||||||
if event_bytes.len() <= pos || num_events == index {
|
if event_bytes.len() <= pos || num_events == index {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -172,6 +153,17 @@ impl<T: Config> Events<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A phase of a block's execution.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Decode, Encode)]
|
||||||
|
pub enum Phase {
|
||||||
|
/// Applying an extrinsic.
|
||||||
|
ApplyExtrinsic(u32),
|
||||||
|
/// Finalizing the block.
|
||||||
|
Finalization,
|
||||||
|
/// Initializing the block.
|
||||||
|
Initialization,
|
||||||
|
}
|
||||||
|
|
||||||
/// The event details.
|
/// The event details.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EventDetails<T: Config> {
|
pub struct EventDetails<T: Config> {
|
||||||
@@ -194,7 +186,7 @@ pub struct EventDetails<T: Config> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> EventDetails<T> {
|
impl<T: Config> EventDetails<T> {
|
||||||
// Attempt to dynamically decode a single event from our events input.
|
/// Attempt to dynamically decode a single event from our events input.
|
||||||
fn decode_from(
|
fn decode_from(
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
all_bytes: Arc<[u8]>,
|
all_bytes: Arc<[u8]>,
|
||||||
@@ -284,12 +276,12 @@ impl<T: Config> EventDetails<T> {
|
|||||||
|
|
||||||
/// The name of the pallet from whence the Event originated.
|
/// The name of the pallet from whence the Event originated.
|
||||||
pub fn pallet_name(&self) -> &str {
|
pub fn pallet_name(&self) -> &str {
|
||||||
self.event_metadata().pallet.name()
|
self.event_metadata().pallet().name()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of the event (ie the name of the variant that it corresponds to).
|
/// The name of the event (ie the name of the variant that it corresponds to).
|
||||||
pub fn variant_name(&self) -> &str {
|
pub fn variant_name(&self) -> &str {
|
||||||
&self.event_metadata().variant.name
|
&self.event_metadata().variant().name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch details from the metadata for this event.
|
/// Fetch details from the metadata for this event.
|
||||||
@@ -378,15 +370,24 @@ impl<T: Config> EventDetails<T> {
|
|||||||
|
|
||||||
/// Details for the given event plucked from the metadata.
|
/// Details for the given event plucked from the metadata.
|
||||||
pub struct EventMetadataDetails<'a> {
|
pub struct EventMetadataDetails<'a> {
|
||||||
pub pallet: PalletMetadata<'a>,
|
pallet: PalletMetadata<'a>,
|
||||||
pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> EventMetadataDetails<'a> {
|
||||||
|
pub fn pallet(&self) -> PalletMetadata<'a> {
|
||||||
|
self.pallet
|
||||||
|
}
|
||||||
|
pub fn variant(&self) -> &'a scale_info::Variant<scale_info::form::PortableForm> {
|
||||||
|
self.variant
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event related test utilities used outside this module.
|
/// Event related test utilities used outside this module.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test_utils {
|
pub(crate) mod test_utils {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Config, SubstrateConfig};
|
use crate::config::{Config, SubstrateConfig};
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use frame_metadata::{
|
use frame_metadata::{
|
||||||
v15::{
|
v15::{
|
||||||
@@ -531,11 +532,7 @@ pub(crate) mod test_utils {
|
|||||||
// Prepend compact encoded length to event bytes:
|
// Prepend compact encoded length to event bytes:
|
||||||
let mut all_event_bytes = Compact(num_events).encode();
|
let mut all_event_bytes = Compact(num_events).encode();
|
||||||
all_event_bytes.extend(event_bytes);
|
all_event_bytes.extend(event_bytes);
|
||||||
Events::new(
|
Events::decode_from(metadata, all_event_bytes)
|
||||||
metadata,
|
|
||||||
<SubstrateConfig as Config>::Hash::default(),
|
|
||||||
all_event_bytes,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +542,8 @@ mod tests {
|
|||||||
test_utils::{event_record, events, events_raw, AllEvents, EventRecord},
|
test_utils::{event_record, events, events_raw, AllEvents, EventRecord},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
use crate::SubstrateConfig;
|
use crate::config::SubstrateConfig;
|
||||||
|
use crate::events::Phase;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use primitive_types::H256;
|
use primitive_types::H256;
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2019-2024 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! # Subxt-core
|
||||||
|
//!
|
||||||
|
//! `#[no_std]` compatible core crate for subxt.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
pub extern crate alloc;
|
||||||
|
|
||||||
|
pub mod blocks;
|
||||||
|
pub mod client;
|
||||||
|
pub mod config;
|
||||||
|
pub mod constants;
|
||||||
|
pub mod custom_values;
|
||||||
|
pub mod dynamic;
|
||||||
|
pub mod error;
|
||||||
|
pub mod events;
|
||||||
|
pub mod metadata;
|
||||||
|
pub mod runtime_api;
|
||||||
|
pub mod storage;
|
||||||
|
pub mod tx;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
pub use config::Config;
|
||||||
|
pub use error::Error;
|
||||||
|
pub use metadata::Metadata;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
|
||||||
|
pub mod ext {
|
||||||
|
pub use codec;
|
||||||
|
pub use scale_decode;
|
||||||
|
pub use scale_encode;
|
||||||
|
|
||||||
|
cfg_substrate_compat! {
|
||||||
|
pub use sp_runtime;
|
||||||
|
pub use sp_core;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
macro_rules! cfg_feature {
|
||||||
|
($feature:literal, $($item:item)*) => {
|
||||||
|
$(
|
||||||
|
#[cfg(feature = $feature)]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
|
||||||
|
$item
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! cfg_substrate_compat {
|
||||||
|
($($item:item)*) => {
|
||||||
|
crate::macros::cfg_feature!("substrate-compat", $($item)*);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use {cfg_feature, cfg_substrate_compat};
|
||||||
+6
-5
@@ -3,7 +3,8 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use super::Metadata;
|
use super::Metadata;
|
||||||
use crate::error::Error;
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
/// This trait is implemented for all types that also implement [`scale_decode::DecodeAsType`].
|
/// This trait is implemented for all types that also implement [`scale_decode::DecodeAsType`].
|
||||||
pub trait DecodeWithMetadata: Sized {
|
pub trait DecodeWithMetadata: Sized {
|
||||||
@@ -12,7 +13,7 @@ pub trait DecodeWithMetadata: Sized {
|
|||||||
bytes: &mut &[u8],
|
bytes: &mut &[u8],
|
||||||
type_id: u32,
|
type_id: u32,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<Self, Error>;
|
) -> Result<Self, scale_decode::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: scale_decode::DecodeAsType> DecodeWithMetadata for T {
|
impl<T: scale_decode::DecodeAsType> DecodeWithMetadata for T {
|
||||||
@@ -20,7 +21,7 @@ impl<T: scale_decode::DecodeAsType> DecodeWithMetadata for T {
|
|||||||
bytes: &mut &[u8],
|
bytes: &mut &[u8],
|
||||||
type_id: u32,
|
type_id: u32,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
) -> Result<T, Error> {
|
) -> Result<T, scale_decode::Error> {
|
||||||
let val = T::decode_as_type(bytes, &type_id, metadata.types())?;
|
let val = T::decode_as_type(bytes, &type_id, metadata.types())?;
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
@@ -34,7 +35,7 @@ pub trait EncodeWithMetadata {
|
|||||||
type_id: u32,
|
type_id: u32,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
bytes: &mut Vec<u8>,
|
bytes: &mut Vec<u8>,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), scale_encode::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: scale_encode::EncodeAsType> EncodeWithMetadata for T {
|
impl<T: scale_encode::EncodeAsType> EncodeWithMetadata for T {
|
||||||
@@ -44,7 +45,7 @@ impl<T: scale_encode::EncodeAsType> EncodeWithMetadata for T {
|
|||||||
type_id: u32,
|
type_id: u32,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
bytes: &mut Vec<u8>,
|
bytes: &mut Vec<u8>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), scale_encode::Error> {
|
||||||
self.encode_as_type_to(&type_id, metadata.types(), bytes)?;
|
self.encode_as_type_to(&type_id, metadata.types(), bytes)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
use crate::error::MetadataError;
|
||||||
|
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
/// A cheaply clone-able representation of the runtime metadata received from a node.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Metadata {
|
||||||
|
inner: Arc<subxt_metadata::Metadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::Deref for Metadata {
|
||||||
|
type Target = subxt_metadata::Metadata;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metadata {
|
||||||
|
pub fn new(md: subxt_metadata::Metadata) -> Self {
|
||||||
|
Metadata {
|
||||||
|
inner: Arc::new(md),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.pallet_by_name()`, but returns an error if the pallet is not found.
|
||||||
|
pub fn pallet_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
||||||
|
self.pallet_by_name(name)
|
||||||
|
.ok_or_else(|| MetadataError::PalletNameNotFound(name.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.pallet_by_index()`, but returns an error if the pallet is not found.
|
||||||
|
pub fn pallet_by_index_err(
|
||||||
|
&self,
|
||||||
|
index: u8,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
||||||
|
self.pallet_by_index(index)
|
||||||
|
.ok_or(MetadataError::PalletIndexNotFound(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.runtime_api_trait_by_name()`, but returns an error if the trait is not found.
|
||||||
|
pub fn runtime_api_trait_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::RuntimeApiMetadata, MetadataError> {
|
||||||
|
self.runtime_api_trait_by_name(name)
|
||||||
|
.ok_or_else(|| MetadataError::RuntimeTraitNotFound(name.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<subxt_metadata::Metadata> for Metadata {
|
||||||
|
fn from(md: subxt_metadata::Metadata) -> Self {
|
||||||
|
Metadata::new(md)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<frame_metadata::RuntimeMetadataPrefixed> for Metadata {
|
||||||
|
type Error = subxt_metadata::TryFromError;
|
||||||
|
fn try_from(value: frame_metadata::RuntimeMetadataPrefixed) -> Result<Self, Self::Error> {
|
||||||
|
subxt_metadata::Metadata::try_from(value).map(Metadata::from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl codec::Decode for Metadata {
|
||||||
|
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
|
||||||
|
subxt_metadata::Metadata::decode(input).map(Metadata::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Some extension methods on [`subxt_metadata::Metadata`] that return Errors instead of Options.
|
||||||
|
pub trait MetadataExt {
|
||||||
|
fn pallet_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError>;
|
||||||
|
|
||||||
|
fn pallet_by_index_err(
|
||||||
|
&self,
|
||||||
|
index: u8,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError>;
|
||||||
|
|
||||||
|
fn runtime_api_trait_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::RuntimeApiMetadata, MetadataError>;
|
||||||
|
|
||||||
|
fn custom_value_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::CustomValueMetadata, MetadataError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetadataExt for subxt_metadata::Metadata {
|
||||||
|
/// Identical to `metadata.pallet_by_name()`, but returns an error if the pallet is not found.
|
||||||
|
fn pallet_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
||||||
|
self.pallet_by_name(name)
|
||||||
|
.ok_or_else(|| MetadataError::PalletNameNotFound(name.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.pallet_by_index()`, but returns an error if the pallet is not found.
|
||||||
|
fn pallet_by_index_err(
|
||||||
|
&self,
|
||||||
|
index: u8,
|
||||||
|
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
||||||
|
self.pallet_by_index(index)
|
||||||
|
.ok_or(MetadataError::PalletIndexNotFound(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.runtime_api_trait_by_name()`, but returns an error if the trait is not found.
|
||||||
|
fn runtime_api_trait_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::RuntimeApiMetadata, MetadataError> {
|
||||||
|
self.runtime_api_trait_by_name(name)
|
||||||
|
.ok_or_else(|| MetadataError::RuntimeTraitNotFound(name.to_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Identical to `metadata.runtime_api_trait_by_name()`, but returns an error if the trait is not found.
|
||||||
|
fn custom_value_by_name_err(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<subxt_metadata::CustomValueMetadata, MetadataError> {
|
||||||
|
self.custom()
|
||||||
|
.get(name)
|
||||||
|
.ok_or_else(|| MetadataError::CustomValueNameNotFound(name.to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ mod decode_encode_traits;
|
|||||||
mod metadata_type;
|
mod metadata_type;
|
||||||
|
|
||||||
pub use decode_encode_traits::{DecodeWithMetadata, EncodeWithMetadata};
|
pub use decode_encode_traits::{DecodeWithMetadata, EncodeWithMetadata};
|
||||||
pub use metadata_type::Metadata;
|
pub use metadata_type::{Metadata, MetadataExt};
|
||||||
|
|
||||||
// Expose metadata types under a sub module in case somebody needs to reference them:
|
// Expose metadata types under a sub module in case somebody needs to reference them:
|
||||||
pub use subxt_metadata as types;
|
pub use subxt_metadata as types;
|
||||||
@@ -2,15 +2,20 @@
|
|||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
use alloc::borrow::Cow;
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use scale_encode::EncodeAsFields;
|
use scale_encode::EncodeAsFields;
|
||||||
use scale_value::Composite;
|
use scale_value::Composite;
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use crate::dynamic::DecodedValueThunk;
|
use crate::dynamic::DecodedValueThunk;
|
||||||
use crate::error::MetadataError;
|
use crate::error::MetadataError;
|
||||||
use crate::{metadata::DecodeWithMetadata, Error, Metadata};
|
use crate::Error;
|
||||||
|
|
||||||
|
use crate::metadata::{DecodeWithMetadata, Metadata};
|
||||||
|
|
||||||
/// This represents a runtime API payload that can call into the runtime of node.
|
/// This represents a runtime API payload that can call into the runtime of node.
|
||||||
///
|
///
|
||||||
@@ -66,15 +71,7 @@ pub trait RuntimeApiPayload {
|
|||||||
///
|
///
|
||||||
/// This can be created from static values (ie those generated
|
/// This can be created from static values (ie those generated
|
||||||
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; ArgsData)]
|
||||||
#[derivative(
|
|
||||||
Clone(bound = "ArgsData: Clone"),
|
|
||||||
Debug(bound = "ArgsData: std::fmt::Debug"),
|
|
||||||
Eq(bound = "ArgsData: std::cmp::Eq"),
|
|
||||||
Ord(bound = "ArgsData: std::cmp::Ord"),
|
|
||||||
PartialEq(bound = "ArgsData: std::cmp::PartialEq"),
|
|
||||||
PartialOrd(bound = "ArgsData: std::cmp::PartialOrd")
|
|
||||||
)]
|
|
||||||
pub struct Payload<ArgsData, ReturnTy> {
|
pub struct Payload<ArgsData, ReturnTy> {
|
||||||
trait_name: Cow<'static, str>,
|
trait_name: Cow<'static, str>,
|
||||||
method_name: Cow<'static, str>,
|
method_name: Cow<'static, str>,
|
||||||
@@ -150,7 +147,7 @@ impl<ReturnTy, ArgsData> Payload<ArgsData, ReturnTy> {
|
|||||||
method_name: Cow::Borrowed(method_name),
|
method_name: Cow::Borrowed(method_name),
|
||||||
args_data,
|
args_data,
|
||||||
validation_hash: Some(hash),
|
validation_hash: Some(hash),
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! Types associated with accessing and working with storage items.
|
||||||
|
|
||||||
|
mod storage_address;
|
||||||
|
mod storage_key;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Types representing an address which describes where a storage
|
||||||
|
/// entry lives and how to properly decode it.
|
||||||
|
pub mod address {
|
||||||
|
pub use super::storage_address::{dynamic, Address, DynamicAddress, StorageAddress};
|
||||||
|
pub use super::storage_key::{StaticStorageKey, StorageHashers, StorageKey};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use storage_key::StorageKey;
|
||||||
|
|
||||||
|
// For consistency with other modules, also expose
|
||||||
|
// the basic address stuff at the root of the module.
|
||||||
|
pub use storage_address::{dynamic, Address, DynamicAddress, StorageAddress};
|
||||||
@@ -6,10 +6,13 @@ use crate::{
|
|||||||
dynamic::DecodedValueThunk,
|
dynamic::DecodedValueThunk,
|
||||||
error::{Error, MetadataError},
|
error::{Error, MetadataError},
|
||||||
metadata::{DecodeWithMetadata, Metadata},
|
metadata::{DecodeWithMetadata, Metadata},
|
||||||
|
utils::Yes,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use alloc::borrow::{Cow, ToOwned};
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use super::{storage_key::StorageHashers, StorageKey};
|
use super::{storage_key::StorageHashers, StorageKey};
|
||||||
|
|
||||||
@@ -48,27 +51,15 @@ pub trait StorageAddress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to signal whether a [`StorageAddress`] can be iterated,
|
|
||||||
/// fetched and returned with a default value in the type system.
|
|
||||||
pub struct Yes;
|
|
||||||
|
|
||||||
/// A concrete storage address. This can be created from static values (ie those generated
|
/// A concrete storage address. This can be created from static values (ie those generated
|
||||||
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
/// via the `subxt` macro) or dynamic values via [`dynamic`].
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug, Eq, Ord, PartialEq, PartialOrd; Keys)]
|
||||||
#[derivative(
|
|
||||||
Clone(bound = "Keys: Clone"),
|
|
||||||
Debug(bound = "Keys: std::fmt::Debug"),
|
|
||||||
Eq(bound = "Keys: std::cmp::Eq"),
|
|
||||||
Ord(bound = "Keys: std::cmp::Ord"),
|
|
||||||
PartialEq(bound = "Keys: std::cmp::PartialEq"),
|
|
||||||
PartialOrd(bound = "Keys: std::cmp::PartialOrd")
|
|
||||||
)]
|
|
||||||
pub struct Address<Keys: StorageKey, ReturnTy, Fetchable, Defaultable, Iterable> {
|
pub struct Address<Keys: StorageKey, ReturnTy, Fetchable, Defaultable, Iterable> {
|
||||||
pallet_name: Cow<'static, str>,
|
pallet_name: Cow<'static, str>,
|
||||||
entry_name: Cow<'static, str>,
|
entry_name: Cow<'static, str>,
|
||||||
keys: Keys,
|
keys: Keys,
|
||||||
validation_hash: Option<[u8; 32]>,
|
validation_hash: Option<[u8; 32]>,
|
||||||
_marker: std::marker::PhantomData<(ReturnTy, Fetchable, Defaultable, Iterable)>,
|
_marker: core::marker::PhantomData<(ReturnTy, Fetchable, Defaultable, Iterable)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A typical storage address constructed at runtime rather than via the `subxt` macro; this
|
/// A typical storage address constructed at runtime rather than via the `subxt` macro; this
|
||||||
@@ -83,7 +74,7 @@ impl<Keys: StorageKey> DynamicAddress<Keys> {
|
|||||||
entry_name: Cow::Owned(entry_name.into()),
|
entry_name: Cow::Owned(entry_name.into()),
|
||||||
keys,
|
keys,
|
||||||
validation_hash: None,
|
validation_hash: None,
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +99,7 @@ where
|
|||||||
entry_name: Cow::Borrowed(entry_name),
|
entry_name: Cow::Borrowed(entry_name),
|
||||||
keys,
|
keys,
|
||||||
validation_hash: Some(hash),
|
validation_hash: Some(hash),
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,9 +118,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return bytes representing the root of this storage entry (ie a hash of
|
/// Return bytes representing the root of this storage entry (a hash of the pallet and entry name).
|
||||||
/// the pallet and entry name). Use [`crate::storage::StorageClient::address_bytes()`]
|
|
||||||
/// to obtain the bytes representing the entire address.
|
|
||||||
pub fn to_root_bytes(&self) -> Vec<u8> {
|
pub fn to_root_bytes(&self) -> Vec<u8> {
|
||||||
super::utils::storage_address_root_bytes(self)
|
super::utils::storage_address_root_bytes(self)
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
|
use super::utils::hash_bytes;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, MetadataError, StorageAddressError},
|
error::{Error, MetadataError, StorageAddressError},
|
||||||
utils::{Encoded, Static},
|
utils::{Encoded, Static},
|
||||||
};
|
};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use derive_where::derive_where;
|
||||||
use scale_decode::visitor::IgnoreVisitor;
|
use scale_decode::visitor::IgnoreVisitor;
|
||||||
use scale_encode::EncodeAsType;
|
use scale_encode::EncodeAsType;
|
||||||
use scale_info::{PortableRegistry, TypeDef};
|
use scale_info::{PortableRegistry, TypeDef};
|
||||||
use scale_value::Value;
|
use scale_value::Value;
|
||||||
use subxt_metadata::{StorageEntryType, StorageHasher};
|
use subxt_metadata::{StorageEntryType, StorageHasher};
|
||||||
|
|
||||||
use derivative::Derivative;
|
|
||||||
|
|
||||||
use super::utils::hash_bytes;
|
|
||||||
|
|
||||||
/// A collection of storage hashers paired with the type ids of the types they should hash.
|
/// A collection of storage hashers paired with the type ids of the types they should hash.
|
||||||
/// Can be created for each storage entry in the metadata via [`StorageHashers::new()`].
|
/// Can be created for each storage entry in the metadata via [`StorageHashers::new()`].
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct StorageHashers {
|
pub struct StorageHashers {
|
||||||
hashers_and_ty_ids: Vec<(StorageHasher, u32)>,
|
hashers_and_ty_ids: Vec<(StorageHasher, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,11 +162,10 @@ impl StorageKey for () {
|
|||||||
|
|
||||||
/// A storage key for static encoded values.
|
/// A storage key for static encoded values.
|
||||||
/// The original value is only present at construction, but can be decoded from the contained bytes.
|
/// The original value is only present at construction, but can be decoded from the contained bytes.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug, PartialOrd, PartialEq, Eq)]
|
||||||
#[derivative(Clone(bound = ""), Debug(bound = ""))]
|
|
||||||
pub struct StaticStorageKey<K: ?Sized> {
|
pub struct StaticStorageKey<K: ?Sized> {
|
||||||
bytes: Static<Encoded>,
|
bytes: Static<Encoded>,
|
||||||
_marker: std::marker::PhantomData<K>,
|
_marker: core::marker::PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: codec::Encode + ?Sized> StaticStorageKey<K> {
|
impl<K: codec::Encode + ?Sized> StaticStorageKey<K> {
|
||||||
@@ -174,7 +173,7 @@ impl<K: codec::Encode + ?Sized> StaticStorageKey<K> {
|
|||||||
pub fn new(key: &K) -> Self {
|
pub fn new(key: &K) -> Self {
|
||||||
StaticStorageKey {
|
StaticStorageKey {
|
||||||
bytes: Static(Encoded(key.encode())),
|
bytes: Static(Encoded(key.encode())),
|
||||||
_marker: std::marker::PhantomData,
|
_marker: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +226,7 @@ impl<K: ?Sized> StorageKey for StaticStorageKey<K> {
|
|||||||
// Return the key bytes.
|
// Return the key bytes.
|
||||||
let key = StaticStorageKey {
|
let key = StaticStorageKey {
|
||||||
bytes: Static(Encoded(key_bytes.to_vec())),
|
bytes: Static(Encoded(key_bytes.to_vec())),
|
||||||
_marker: std::marker::PhantomData::<K>,
|
_marker: core::marker::PhantomData::<K>,
|
||||||
};
|
};
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
@@ -362,6 +361,10 @@ mod tests {
|
|||||||
|
|
||||||
use crate::utils::Era;
|
use crate::utils::Era;
|
||||||
|
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use super::{StaticStorageKey, StorageKey};
|
use super::{StaticStorageKey, StorageKey};
|
||||||
|
|
||||||
struct KeyBuilder {
|
struct KeyBuilder {
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! these utility methods complement the [`StorageAddress`] trait, but
|
||||||
|
//! aren't things that should ever be overridden, and so don't exist on
|
||||||
|
//! the trait itself.
|
||||||
|
|
||||||
|
use crate::error::MetadataError;
|
||||||
|
use crate::metadata::{DecodeWithMetadata, MetadataExt};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use subxt_metadata::PalletMetadata;
|
||||||
|
use subxt_metadata::{StorageEntryMetadata, StorageHasher};
|
||||||
|
|
||||||
|
use super::StorageAddress;
|
||||||
|
use crate::{error::Error, metadata::Metadata};
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
|
||||||
|
/// Return the root of a given [`StorageAddress`]: hash the pallet name and entry name
|
||||||
|
/// and append those bytes to the output.
|
||||||
|
pub fn write_storage_address_root_bytes<Address: StorageAddress>(
|
||||||
|
addr: &Address,
|
||||||
|
out: &mut Vec<u8>,
|
||||||
|
) {
|
||||||
|
out.extend(sp_crypto_hashing::twox_128(addr.pallet_name().as_bytes()));
|
||||||
|
out.extend(sp_crypto_hashing::twox_128(addr.entry_name().as_bytes()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs the [`storage_address_root_bytes`] as well as any additional bytes that represent
|
||||||
|
/// a lookup in a storage map at that location.
|
||||||
|
pub fn storage_address_bytes<Address: StorageAddress>(
|
||||||
|
addr: &Address,
|
||||||
|
metadata: &Metadata,
|
||||||
|
) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
write_storage_address_root_bytes(addr, &mut bytes);
|
||||||
|
addr.append_entry_bytes(metadata, &mut bytes)?;
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs a vector containing the bytes written by [`write_storage_address_root_bytes`].
|
||||||
|
pub fn storage_address_root_bytes<Address: StorageAddress>(addr: &Address) -> Vec<u8> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
write_storage_address_root_bytes(addr, &mut bytes);
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take some SCALE encoded bytes and a [`StorageHasher`] and hash the bytes accordingly.
|
||||||
|
pub fn hash_bytes(input: &[u8], hasher: StorageHasher, bytes: &mut Vec<u8>) {
|
||||||
|
match hasher {
|
||||||
|
StorageHasher::Identity => bytes.extend(input),
|
||||||
|
StorageHasher::Blake2_128 => bytes.extend(sp_crypto_hashing::blake2_128(input)),
|
||||||
|
StorageHasher::Blake2_128Concat => {
|
||||||
|
bytes.extend(sp_crypto_hashing::blake2_128(input));
|
||||||
|
bytes.extend(input);
|
||||||
|
}
|
||||||
|
StorageHasher::Blake2_256 => bytes.extend(sp_crypto_hashing::blake2_256(input)),
|
||||||
|
StorageHasher::Twox128 => bytes.extend(sp_crypto_hashing::twox_128(input)),
|
||||||
|
StorageHasher::Twox256 => bytes.extend(sp_crypto_hashing::twox_256(input)),
|
||||||
|
StorageHasher::Twox64Concat => {
|
||||||
|
bytes.extend(sp_crypto_hashing::twox_64(input));
|
||||||
|
bytes.extend(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return details about the given storage entry.
|
||||||
|
pub fn lookup_entry_details<'a>(
|
||||||
|
pallet_name: &str,
|
||||||
|
entry_name: &str,
|
||||||
|
metadata: &'a subxt_metadata::Metadata,
|
||||||
|
) -> Result<(PalletMetadata<'a>, &'a StorageEntryMetadata), Error> {
|
||||||
|
let pallet_metadata = metadata.pallet_by_name_err(pallet_name)?;
|
||||||
|
let storage_metadata = pallet_metadata
|
||||||
|
.storage()
|
||||||
|
.ok_or_else(|| MetadataError::StorageNotFoundInPallet(pallet_name.to_owned()))?;
|
||||||
|
let storage_entry = storage_metadata
|
||||||
|
.entry_by_name(entry_name)
|
||||||
|
.ok_or_else(|| MetadataError::StorageEntryNotFound(entry_name.to_owned()))?;
|
||||||
|
Ok((pallet_metadata, storage_entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate a storage address against the metadata.
|
||||||
|
pub fn validate_storage_address<Address: StorageAddress>(
|
||||||
|
address: &Address,
|
||||||
|
pallet: PalletMetadata<'_>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if let Some(hash) = address.validation_hash() {
|
||||||
|
validate_storage(pallet, address.entry_name(), hash)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate a storage entry against the metadata.
|
||||||
|
fn validate_storage(
|
||||||
|
pallet: PalletMetadata<'_>,
|
||||||
|
storage_name: &str,
|
||||||
|
hash: [u8; 32],
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let Some(expected_hash) = pallet.storage_hash(storage_name) else {
|
||||||
|
return Err(MetadataError::IncompatibleCodegen.into());
|
||||||
|
};
|
||||||
|
if expected_hash != hash {
|
||||||
|
return Err(MetadataError::IncompatibleCodegen.into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given some bytes, a pallet and storage name, decode the response.
|
||||||
|
pub fn decode_storage_with_metadata<T: DecodeWithMetadata>(
|
||||||
|
bytes: &mut &[u8],
|
||||||
|
metadata: &Metadata,
|
||||||
|
storage_metadata: &StorageEntryMetadata,
|
||||||
|
) -> Result<T, Error> {
|
||||||
|
let return_ty = storage_metadata.entry_type().value_ty();
|
||||||
|
let val = T::decode_with_metadata(bytes, return_ty, metadata)?;
|
||||||
|
Ok(val)
|
||||||
|
}
|
||||||
@@ -5,16 +5,19 @@
|
|||||||
//! This module contains the trait and types used to represent
|
//! This module contains the trait and types used to represent
|
||||||
//! transactions that can be submitted.
|
//! transactions that can be submitted.
|
||||||
|
|
||||||
use crate::{
|
use crate::error::MetadataError;
|
||||||
dynamic::Value,
|
use crate::metadata::Metadata;
|
||||||
error::{Error, MetadataError},
|
use crate::Error;
|
||||||
metadata::Metadata,
|
use alloc::borrow::{Cow, ToOwned};
|
||||||
};
|
use alloc::string::String;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use derivative::Derivative;
|
|
||||||
use scale_encode::EncodeAsFields;
|
use scale_encode::EncodeAsFields;
|
||||||
use scale_value::{Composite, ValueDef, Variant};
|
use scale_value::{Composite, Value, ValueDef, Variant};
|
||||||
use std::borrow::Cow;
|
|
||||||
|
pub mod signer;
|
||||||
|
pub use signer::Signer;
|
||||||
|
|
||||||
/// This represents a transaction payload that can be submitted
|
/// This represents a transaction payload that can be submitted
|
||||||
/// to a node.
|
/// to a node.
|
||||||
@@ -49,15 +52,7 @@ pub struct ValidationDetails<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A transaction payload containing some generic `CallData`.
|
/// A transaction payload containing some generic `CallData`.
|
||||||
#[derive(Derivative)]
|
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
#[derivative(
|
|
||||||
Clone(bound = "CallData: Clone"),
|
|
||||||
Debug(bound = "CallData: std::fmt::Debug"),
|
|
||||||
Eq(bound = "CallData: std::cmp::Eq"),
|
|
||||||
Ord(bound = "CallData: std::cmp::Ord"),
|
|
||||||
PartialEq(bound = "CallData: std::cmp::PartialEq"),
|
|
||||||
PartialOrd(bound = "CallData: std::cmp::PartialOrd")
|
|
||||||
)]
|
|
||||||
pub struct Payload<CallData> {
|
pub struct Payload<CallData> {
|
||||||
pallet_name: Cow<'static, str>,
|
pallet_name: Cow<'static, str>,
|
||||||
call_name: Cow<'static, str>,
|
call_name: Cow<'static, str>,
|
||||||
@@ -160,7 +155,8 @@ impl<CallData: EncodeAsFields> TxPayload for Payload<CallData> {
|
|||||||
.map(|f| scale_encode::Field::new(&f.ty.id, f.name.as_deref()));
|
.map(|f| scale_encode::Field::new(&f.ty.id, f.name.as_deref()));
|
||||||
|
|
||||||
self.call_data
|
self.call_data
|
||||||
.encode_as_fields_to(&mut fields, metadata.types(), out)?;
|
.encode_as_fields_to(&mut fields, metadata.types(), out)
|
||||||
|
.expect("The fields are valid types from the metadata, qed;");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6,7 +6,12 @@
|
|||||||
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_core::AccountId32`
|
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_core::AccountId32`
|
||||||
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
|
use derive_more::Display;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A 32-byte cryptographic identifier. This is a simplified version of Substrate's
|
/// A 32-byte cryptographic identifier. This is a simplified version of Substrate's
|
||||||
@@ -100,19 +105,22 @@ impl AccountId32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An error obtained from trying to interpret an SS58 encoded string into an AccountId32
|
/// An error obtained from trying to interpret an SS58 encoded string into an AccountId32
|
||||||
#[derive(thiserror::Error, Clone, Copy, Eq, PartialEq, Debug)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Display)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum FromSs58Error {
|
pub enum FromSs58Error {
|
||||||
#[error("Base 58 requirement is violated")]
|
#[display(fmt = "Base 58 requirement is violated")]
|
||||||
BadBase58,
|
BadBase58,
|
||||||
#[error("Length is bad")]
|
#[display(fmt = "Length is bad")]
|
||||||
BadLength,
|
BadLength,
|
||||||
#[error("Invalid checksum")]
|
#[display(fmt = "Invalid checksum")]
|
||||||
InvalidChecksum,
|
InvalidChecksum,
|
||||||
#[error("Invalid SS58 prefix byte.")]
|
#[display(fmt = "Invalid SS58 prefix byte.")]
|
||||||
InvalidPrefix,
|
InvalidPrefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for FromSs58Error {}
|
||||||
|
|
||||||
// We do this just to get a checksum to help verify the validity of the address in to_ss58check
|
// We do this just to get a checksum to help verify the validity of the address in to_ss58check
|
||||||
fn ss58hash(data: &[u8]) -> Vec<u8> {
|
fn ss58hash(data: &[u8]) -> Vec<u8> {
|
||||||
use blake2::{Blake2b512, Digest};
|
use blake2::{Blake2b512, Digest};
|
||||||
@@ -142,13 +150,13 @@ impl<'de> Deserialize<'de> for AccountId32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for AccountId32 {
|
impl core::fmt::Display for AccountId32 {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
write!(f, "{}", self.to_ss58check())
|
write!(f, "{}", self.to_ss58check())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for AccountId32 {
|
impl core::str::FromStr for AccountId32 {
|
||||||
type Err = FromSs58Error;
|
type Err = FromSs58Error;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
AccountId32::from_ss58check(s)
|
AccountId32::from_ss58check(s)
|
||||||
@@ -4,15 +4,16 @@
|
|||||||
|
|
||||||
//! Generic `scale_bits` over `bitvec`-like `BitOrder` and `BitFormat` types.
|
//! Generic `scale_bits` over `bitvec`-like `BitOrder` and `BitFormat` types.
|
||||||
|
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::{Compact, Input};
|
use codec::{Compact, Input};
|
||||||
|
use core::marker::PhantomData;
|
||||||
use scale_bits::{
|
use scale_bits::{
|
||||||
scale::format::{Format, OrderFormat, StoreFormat},
|
scale::format::{Format, OrderFormat, StoreFormat},
|
||||||
Bits,
|
Bits,
|
||||||
};
|
};
|
||||||
use scale_decode::{IntoVisitor, TypeResolver};
|
use scale_decode::{IntoVisitor, TypeResolver};
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
/// Associates `bitvec::store::BitStore` trait with corresponding, type-erased `scale_bits::StoreFormat` enum.
|
/// Associates `bitvec::store::BitStore` trait with corresponding, type-erased `scale_bits::StoreFormat` enum.
|
||||||
///
|
///
|
||||||
/// Used to decode bit sequences by providing `scale_bits::StoreFormat` using
|
/// Used to decode bit sequences by providing `scale_bits::StoreFormat` using
|
||||||
@@ -145,7 +146,7 @@ impl<Store: BitStore, Order: BitOrder> codec::Encode for DecodedBits<Store, Orde
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct DecodedBitsVisitor<S, O, R: TypeResolver>(std::marker::PhantomData<(S, O, R)>);
|
pub struct DecodedBitsVisitor<S, O, R: TypeResolver>(core::marker::PhantomData<(S, O, R)>);
|
||||||
|
|
||||||
impl<Store, Order, R: TypeResolver> scale_decode::Visitor for DecodedBitsVisitor<Store, Order, R> {
|
impl<Store, Order, R: TypeResolver> scale_decode::Visitor for DecodedBitsVisitor<Store, Order, R> {
|
||||||
type Value<'scale, 'info> = DecodedBits<Store, Order>;
|
type Value<'scale, 'info> = DecodedBits<Store, Order>;
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
|
// see LICENSE for license details.
|
||||||
|
|
||||||
|
//! Miscellaneous utility helpers.
|
||||||
|
|
||||||
|
mod account_id;
|
||||||
|
pub mod bits;
|
||||||
|
mod era;
|
||||||
|
mod multi_address;
|
||||||
|
mod multi_signature;
|
||||||
|
mod static_type;
|
||||||
|
mod unchecked_extrinsic;
|
||||||
|
mod wrapper_opaque;
|
||||||
|
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use codec::{Compact, Decode, Encode};
|
||||||
|
use derive_where::derive_where;
|
||||||
|
|
||||||
|
pub use account_id::AccountId32;
|
||||||
|
pub use era::Era;
|
||||||
|
pub use multi_address::MultiAddress;
|
||||||
|
pub use multi_signature::MultiSignature;
|
||||||
|
pub use static_type::Static;
|
||||||
|
pub use unchecked_extrinsic::UncheckedExtrinsic;
|
||||||
|
pub use wrapper_opaque::WrapperKeepOpaque;
|
||||||
|
|
||||||
|
// Used in codegen
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use primitive_types::{H160, H256, H512};
|
||||||
|
|
||||||
|
/// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of
|
||||||
|
/// the transaction payload
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
pub struct Encoded(pub Vec<u8>);
|
||||||
|
|
||||||
|
impl codec::Encode for Encoded {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a compact encoded value from the beginning of the provided bytes,
|
||||||
|
/// returning the value and any remaining bytes.
|
||||||
|
pub fn strip_compact_prefix(bytes: &[u8]) -> Result<(u64, &[u8]), codec::Error> {
|
||||||
|
let cursor = &mut &*bytes;
|
||||||
|
let val = <Compact<u64>>::decode(cursor)?;
|
||||||
|
Ok((val.0, *cursor))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A version of [`core::marker::PhantomData`] that is also Send and Sync (which is fine
|
||||||
|
/// because regardless of the generic param, it is always possible to Send + Sync this
|
||||||
|
/// 0 size type).
|
||||||
|
#[derive(Encode, Decode, scale_info::TypeInfo)]
|
||||||
|
#[derive_where(Clone, PartialEq, Debug, Eq, Default, Hash)]
|
||||||
|
#[scale_info(skip_type_params(T))]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct PhantomDataSendSync<T>(core::marker::PhantomData<T>);
|
||||||
|
|
||||||
|
impl<T> PhantomDataSendSync<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(core::marker::PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Send for PhantomDataSendSync<T> {}
|
||||||
|
unsafe impl<T> Sync for PhantomDataSendSync<T> {}
|
||||||
|
|
||||||
|
/// This represents a key-value collection and is SCALE compatible
|
||||||
|
/// with collections like BTreeMap. This has the same type params
|
||||||
|
/// as `BTreeMap` which allows us to easily swap the two during codegen.
|
||||||
|
pub type KeyedVec<K, V> = Vec<(K, V)>;
|
||||||
|
|
||||||
|
/// A unit marker struct signalling that some property is true
|
||||||
|
pub struct Yes;
|
||||||
|
|
||||||
|
/// A quick helper to encode some bytes to hex.
|
||||||
|
pub fn to_hex(bytes: impl AsRef<[u8]>) -> String {
|
||||||
|
format!("0x{}", hex::encode(bytes.as_ref()))
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_runtime::MultiAddress`
|
//! This doesn't contain much functionality itself, but is easy to convert to/from an `sp_runtime::MultiAddress`
|
||||||
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
//! for instance, to gain functionality without forcing a dependency on Substrate crates here.
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
|
|
||||||
/// A multi-format address wrapper for on-chain accounts. This is a simplified version of Substrate's
|
/// A multi-format address wrapper for on-chain accounts. This is a simplified version of Substrate's
|
||||||
@@ -6,6 +6,8 @@ use codec::{Decode, Encode};
|
|||||||
use scale_decode::{visitor::DecodeAsTypeResult, IntoVisitor, TypeResolver, Visitor};
|
use scale_decode::{visitor::DecodeAsTypeResult, IntoVisitor, TypeResolver, Visitor};
|
||||||
use scale_encode::EncodeAsType;
|
use scale_encode::EncodeAsType;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
/// If the type inside this implements [`Encode`], this will implement [`scale_encode::EncodeAsType`].
|
/// If the type inside this implements [`Encode`], this will implement [`scale_encode::EncodeAsType`].
|
||||||
/// If the type inside this implements [`Decode`], this will implement [`scale_decode::DecodeAsType`].
|
/// If the type inside this implements [`Decode`], this will implement [`scale_decode::DecodeAsType`].
|
||||||
///
|
///
|
||||||
@@ -29,7 +31,7 @@ impl<T: Encode> EncodeAsType for Static<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StaticDecodeAsTypeVisitor<T, R>(std::marker::PhantomData<(T, R)>);
|
pub struct StaticDecodeAsTypeVisitor<T, R>(core::marker::PhantomData<(T, R)>);
|
||||||
|
|
||||||
impl<T: Decode, R: TypeResolver> Visitor for StaticDecodeAsTypeVisitor<T, R> {
|
impl<T: Decode, R: TypeResolver> Visitor for StaticDecodeAsTypeVisitor<T, R> {
|
||||||
type Value<'scale, 'info> = Static<T>;
|
type Value<'scale, 'info> = Static<T>;
|
||||||
@@ -53,7 +55,7 @@ impl<T: Decode, R: TypeResolver> Visitor for StaticDecodeAsTypeVisitor<T, R> {
|
|||||||
impl<T: Decode> IntoVisitor for Static<T> {
|
impl<T: Decode> IntoVisitor for Static<T> {
|
||||||
type AnyVisitor<R: TypeResolver> = StaticDecodeAsTypeVisitor<T, R>;
|
type AnyVisitor<R: TypeResolver> = StaticDecodeAsTypeVisitor<T, R>;
|
||||||
fn into_visitor<R: TypeResolver>() -> StaticDecodeAsTypeVisitor<T, R> {
|
fn into_visitor<R: TypeResolver>() -> StaticDecodeAsTypeVisitor<T, R> {
|
||||||
StaticDecodeAsTypeVisitor(std::marker::PhantomData)
|
StaticDecodeAsTypeVisitor(core::marker::PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,14 +67,14 @@ impl<T> From<T> for Static<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static<T> is just a marker type and should be as transparent as possible:
|
// Static<T> is just a marker type and should be as transparent as possible:
|
||||||
impl<T> std::ops::Deref for Static<T> {
|
impl<T> core::ops::Deref for Static<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::ops::DerefMut for Static<T> {
|
impl<T> core::ops::DerefMut for Static<T> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,13 @@
|
|||||||
//! runtime APIs. Deriving `EncodeAsType` would lead to the inner
|
//! runtime APIs. Deriving `EncodeAsType` would lead to the inner
|
||||||
//! bytes to be re-encoded (length prefixed).
|
//! bytes to be re-encoded (length prefixed).
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use scale_decode::{visitor::DecodeAsTypeResult, DecodeAsType, IntoVisitor, TypeResolver, Visitor};
|
use scale_decode::{visitor::DecodeAsTypeResult, DecodeAsType, IntoVisitor, TypeResolver, Visitor};
|
||||||
|
|
||||||
use super::{Encoded, Static};
|
use super::{Encoded, Static};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
/// The unchecked extrinsic from substrate.
|
/// The unchecked extrinsic from substrate.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Encode)]
|
#[derive(Clone, Debug, Eq, PartialEq, Encode)]
|
||||||
@@ -115,6 +116,8 @@ impl<Address, Call, Signature, Extra> IntoVisitor
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use alloc::vec;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unchecked_extrinsic_encoding() {
|
fn unchecked_extrinsic_encoding() {
|
||||||
// A tx is basically some bytes with a compact length prefix; ie an encoded vec:
|
// A tx is basically some bytes with a compact length prefix; ie an encoded vec:
|
||||||
@@ -4,10 +4,13 @@
|
|||||||
|
|
||||||
use super::PhantomDataSendSync;
|
use super::PhantomDataSendSync;
|
||||||
use codec::{Compact, Decode, DecodeAll, Encode};
|
use codec::{Compact, Decode, DecodeAll, Encode};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use scale_decode::{ext::scale_type_resolver::visitor, IntoVisitor, TypeResolver, Visitor};
|
use scale_decode::{ext::scale_type_resolver::visitor, IntoVisitor, TypeResolver, Visitor};
|
||||||
use scale_encode::EncodeAsType;
|
use scale_encode::EncodeAsType;
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
/// A wrapper for any type `T` which implement encode/decode in a way compatible with `Vec<u8>`.
|
/// A wrapper for any type `T` which implement encode/decode in a way compatible with `Vec<u8>`.
|
||||||
/// [`WrapperKeepOpaque`] stores the type only in its opaque format, aka as a `Vec<u8>`. To
|
/// [`WrapperKeepOpaque`] stores the type only in its opaque format, aka as a `Vec<u8>`. To
|
||||||
/// access the real type `T` [`Self::try_decode`] needs to be used.
|
/// access the real type `T` [`Self::try_decode`] needs to be used.
|
||||||
@@ -18,15 +21,8 @@ use scale_encode::EncodeAsType;
|
|||||||
// - However, the TypeInfo describes the type as a composite with first a compact encoded length and next the type itself.
|
// - However, the TypeInfo describes the type as a composite with first a compact encoded length and next the type itself.
|
||||||
// [`Encode`] and [`Decode`] impls will "just work" to take this into a `Vec<u8>`, but we need a custom [`EncodeAsType`]
|
// [`Encode`] and [`Decode`] impls will "just work" to take this into a `Vec<u8>`, but we need a custom [`EncodeAsType`]
|
||||||
// and [`Visitor`] implementation to encode and decode based on TypeInfo.
|
// and [`Visitor`] implementation to encode and decode based on TypeInfo.
|
||||||
#[derive(Derivative, Encode, Decode)]
|
#[derive(Encode, Decode)]
|
||||||
#[derivative(
|
#[derive_where(Debug, Clone, PartialEq, Eq, Default, Hash)]
|
||||||
Debug(bound = ""),
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Default(bound = ""),
|
|
||||||
Hash(bound = "")
|
|
||||||
)]
|
|
||||||
pub struct WrapperKeepOpaque<T> {
|
pub struct WrapperKeepOpaque<T> {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
_phantom: PhantomDataSendSync<T>,
|
_phantom: PhantomDataSendSync<T>,
|
||||||
@@ -83,7 +79,7 @@ impl<T> EncodeAsType for WrapperKeepOpaque<T> {
|
|||||||
use scale_encode::error::{Error, ErrorKind, Kind};
|
use scale_encode::error::{Error, ErrorKind, Kind};
|
||||||
|
|
||||||
let visitor = visitor::new(out, |_, _| {
|
let visitor = visitor::new(out, |_, _| {
|
||||||
// Check that the target shape lines up: any other shape but the composite is wrong.
|
// Check that the target shape lines up: any other shape but composite is wrong.
|
||||||
Err(Error::new(ErrorKind::WrongShape {
|
Err(Error::new(ErrorKind::WrongShape {
|
||||||
actual: Kind::Struct,
|
actual: Kind::Struct,
|
||||||
expected_id: format!("{:?}", type_id),
|
expected_id: format!("{:?}", type_id),
|
||||||
@@ -100,7 +96,7 @@ impl<T> EncodeAsType for WrapperKeepOpaque<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WrapperKeepOpaqueVisitor<T, R>(std::marker::PhantomData<(T, R)>);
|
pub struct WrapperKeepOpaqueVisitor<T, R>(core::marker::PhantomData<(T, R)>);
|
||||||
impl<T, R: TypeResolver> Visitor for WrapperKeepOpaqueVisitor<T, R> {
|
impl<T, R: TypeResolver> Visitor for WrapperKeepOpaqueVisitor<T, R> {
|
||||||
type Value<'scale, 'info> = WrapperKeepOpaque<T>;
|
type Value<'scale, 'info> = WrapperKeepOpaque<T>;
|
||||||
type Error = scale_decode::Error;
|
type Error = scale_decode::Error;
|
||||||
@@ -143,7 +139,7 @@ impl<T, R: TypeResolver> Visitor for WrapperKeepOpaqueVisitor<T, R> {
|
|||||||
impl<T> IntoVisitor for WrapperKeepOpaque<T> {
|
impl<T> IntoVisitor for WrapperKeepOpaque<T> {
|
||||||
type AnyVisitor<R: TypeResolver> = WrapperKeepOpaqueVisitor<T, R>;
|
type AnyVisitor<R: TypeResolver> = WrapperKeepOpaqueVisitor<T, R>;
|
||||||
fn into_visitor<R: TypeResolver>() -> WrapperKeepOpaqueVisitor<T, R> {
|
fn into_visitor<R: TypeResolver>() -> WrapperKeepOpaqueVisitor<T, R> {
|
||||||
WrapperKeepOpaqueVisitor(std::marker::PhantomData)
|
WrapperKeepOpaqueVisitor(core::marker::PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +147,8 @@ impl<T> IntoVisitor for WrapperKeepOpaque<T> {
|
|||||||
mod test {
|
mod test {
|
||||||
use scale_decode::DecodeAsType;
|
use scale_decode::DecodeAsType;
|
||||||
|
|
||||||
|
use alloc::vec;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Copied from https://github.com/paritytech/substrate/blob/master/frame/support/src/traits/misc.rs
|
// Copied from https://github.com/paritytech/substrate/blob/master/frame/support/src/traits/misc.rs
|
||||||
@@ -188,7 +186,7 @@ mod test {
|
|||||||
+ Encode
|
+ Encode
|
||||||
+ Decode
|
+ Decode
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ std::fmt::Debug
|
+ core::fmt::Debug
|
||||||
+ scale_info::TypeInfo
|
+ scale_info::TypeInfo
|
||||||
+ 'static,
|
+ 'static,
|
||||||
{
|
{
|
||||||
Generated
+26
-2
@@ -2502,8 +2502,6 @@ name = "subxt"
|
|||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base58",
|
|
||||||
"blake2",
|
|
||||||
"derivative",
|
"derivative",
|
||||||
"either",
|
"either",
|
||||||
"frame-metadata 16.0.0",
|
"frame-metadata 16.0.0",
|
||||||
@@ -2551,6 +2549,32 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subxt-core"
|
||||||
|
version = "0.34.0"
|
||||||
|
dependencies = [
|
||||||
|
"base58",
|
||||||
|
"blake2",
|
||||||
|
"derivative",
|
||||||
|
"derive_more",
|
||||||
|
"frame-metadata 16.0.0",
|
||||||
|
"hashbrown 0.14.3",
|
||||||
|
"hex",
|
||||||
|
"impl-serde",
|
||||||
|
"parity-scale-codec",
|
||||||
|
"primitive-types",
|
||||||
|
"scale-bits",
|
||||||
|
"scale-decode",
|
||||||
|
"scale-encode",
|
||||||
|
"scale-info",
|
||||||
|
"scale-value",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sp-core-hashing",
|
||||||
|
"subxt-metadata",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subxt-lightclient"
|
name = "subxt-lightclient"
|
||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ pub async fn extension_signature_for_extrinsic(
|
|||||||
) -> Result<Vec<u8>, anyhow::Error> {
|
) -> Result<Vec<u8>, anyhow::Error> {
|
||||||
let genesis_hash = encode_then_hex(&api.genesis_hash());
|
let genesis_hash = encode_then_hex(&api.genesis_hash());
|
||||||
// These numbers aren't SCALE encoded; their bytes are just converted to hex:
|
// These numbers aren't SCALE encoded; their bytes are just converted to hex:
|
||||||
let spec_version = to_hex(&api.runtime_version().spec_version.to_be_bytes());
|
let spec_version = to_hex(&api.runtime_version().spec_version().to_be_bytes());
|
||||||
let transaction_version = to_hex(&api.runtime_version().transaction_version.to_be_bytes());
|
let transaction_version = to_hex(&api.runtime_version().transaction_version().to_be_bytes());
|
||||||
let nonce = to_hex(&account_nonce.to_be_bytes());
|
let nonce = to_hex(&account_nonce.to_be_bytes());
|
||||||
// If you construct a mortal transaction, then this block hash needs to correspond
|
// If you construct a mortal transaction, then this block hash needs to correspond
|
||||||
// to the block number passed to `Era::mortal()`.
|
// to the block number passed to `Era::mortal()`.
|
||||||
|
|||||||
@@ -171,45 +171,6 @@ impl Metadata {
|
|||||||
&OuterEnumHashes::empty(),
|
&OuterEnumHashes::empty(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that every unique type we'll be generating or referring to also has a
|
|
||||||
/// unique path, so that types with matching paths don't end up overwriting each other
|
|
||||||
/// in the codegen. We ignore any types with generics; Subxt actually endeavours to
|
|
||||||
/// de-duplicate those into single types with a generic.
|
|
||||||
pub fn ensure_unique_type_paths(&mut self) {
|
|
||||||
let mut visited_path_counts = HashMap::<Vec<String>, usize>::new();
|
|
||||||
for ty in self.types.types.iter_mut() {
|
|
||||||
// Ignore types without a path (ie prelude types).
|
|
||||||
if ty.ty.path.namespace().is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let has_valid_type_params = ty.ty.type_params.iter().any(|tp| tp.ty.is_some());
|
|
||||||
|
|
||||||
// Ignore types which have generic params that the type generation will use.
|
|
||||||
// Ordinarily we'd expect that any two types with identical paths must be parameterized
|
|
||||||
// in order to share the path. However scale-info doesn't understand all forms of generics
|
|
||||||
// properly I think (eg generics that have associated types that can differ), and so in
|
|
||||||
// those cases we need to fix the paths for Subxt to generate correct code.
|
|
||||||
if has_valid_type_params {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count how many times we've seen the same path already.
|
|
||||||
let visited_count = visited_path_counts
|
|
||||||
.entry(ty.ty.path.segments.clone())
|
|
||||||
.or_default();
|
|
||||||
*visited_count += 1;
|
|
||||||
|
|
||||||
// alter the type so that if it's been seen more than once, we append a number to
|
|
||||||
// its name to ensure that every unique type has a unique path, too.
|
|
||||||
if *visited_count > 1 {
|
|
||||||
if let Some(name) = ty.ty.path.segments.last_mut() {
|
|
||||||
*name = alloc::format!("{name}{visited_count}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata for a specific pallet.
|
/// Metadata for a specific pallet.
|
||||||
|
|||||||
+6
-7
@@ -15,7 +15,7 @@ description = "Sign extrinsics to be submitted by Subxt"
|
|||||||
keywords = ["parity", "subxt", "extrinsic", "signer"]
|
keywords = ["parity", "subxt", "extrinsic", "signer"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["sr25519", "ecdsa", "subxt", "std", "native"]
|
default = ["sr25519", "ecdsa", "subxt", "std"]
|
||||||
std = ["regex/std", "sp-crypto-hashing/std", "pbkdf2/std", "sha2/std", "hmac/std", "bip39/std", "schnorrkel/std", "secp256k1/std", "sp-core/std"]
|
std = ["regex/std", "sp-crypto-hashing/std", "pbkdf2/std", "sha2/std", "hmac/std", "bip39/std", "schnorrkel/std", "secp256k1/std", "sp-core/std"]
|
||||||
|
|
||||||
# Pick the signer implementation(s) you need by enabling the
|
# Pick the signer implementation(s) you need by enabling the
|
||||||
@@ -27,15 +27,15 @@ ecdsa = ["secp256k1"]
|
|||||||
|
|
||||||
# Make the keypair algorithms here compatible with Subxt's Signer trait,
|
# Make the keypair algorithms here compatible with Subxt's Signer trait,
|
||||||
# so that they can be used to sign transactions for compatible chains.
|
# so that they can be used to sign transactions for compatible chains.
|
||||||
subxt = ["dep:subxt"]
|
subxt = ["dep:subxt-core"]
|
||||||
|
|
||||||
# The getrandom package is used via schnorrkel. We need to enable the JS
|
# The getrandom package is used via schnorrkel. We need to enable the JS
|
||||||
# feature on it if compiling for the web.
|
# feature on it if compiling for the web.
|
||||||
web = ["getrandom/js", "subxt?/web"]
|
web = ["getrandom/js"]
|
||||||
native = ["subxt?/native"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
subxt = { workspace = true, optional = true }
|
subxt-core = { workspace = true, optional = true, default-features = false }
|
||||||
|
secrecy = { workspace = true }
|
||||||
regex = { workspace = true, features = ["unicode"] }
|
regex = { workspace = true, features = ["unicode"] }
|
||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
cfg-if = { workspace = true }
|
cfg-if = { workspace = true }
|
||||||
@@ -49,15 +49,14 @@ zeroize = { workspace = true }
|
|||||||
bip39 = { workspace = true }
|
bip39 = { workspace = true }
|
||||||
schnorrkel = { workspace = true, optional = true }
|
schnorrkel = { workspace = true, optional = true }
|
||||||
secp256k1 = { workspace = true, optional = true, features = ["alloc", "recovery"] }
|
secp256k1 = { workspace = true, optional = true, features = ["alloc", "recovery"] }
|
||||||
secrecy = { workspace = true }
|
|
||||||
|
|
||||||
|
|
||||||
# We only pull this in to enable the JS flag for schnorrkel to use.
|
# We only pull this in to enable the JS flag for schnorrkel to use.
|
||||||
getrandom = { workspace = true, optional = true }
|
getrandom = { workspace = true, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sp-core = { workspace = true }
|
|
||||||
sp-keyring = { workspace = true }
|
sp-keyring = { workspace = true }
|
||||||
|
sp-core = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["getrandom"]
|
ignored = ["getrandom"]
|
||||||
|
|||||||
+3
-3
@@ -272,9 +272,9 @@ pub mod dev {
|
|||||||
mod subxt_compat {
|
mod subxt_compat {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use subxt::config::Config;
|
use subxt_core::config::Config;
|
||||||
use subxt::tx::Signer as SignerT;
|
use subxt_core::tx::Signer as SignerT;
|
||||||
use subxt::utils::{AccountId32, MultiAddress, MultiSignature};
|
use subxt_core::utils::{AccountId32, MultiAddress, MultiSignature};
|
||||||
|
|
||||||
impl From<Signature> for MultiSignature {
|
impl From<Signature> for MultiSignature {
|
||||||
fn from(value: Signature) -> Self {
|
fn from(value: Signature) -> Self {
|
||||||
|
|||||||
@@ -258,9 +258,11 @@ pub mod dev {
|
|||||||
mod subxt_compat {
|
mod subxt_compat {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use subxt::config::Config;
|
use subxt_core::{
|
||||||
use subxt::tx::Signer as SignerT;
|
tx::Signer as SignerT,
|
||||||
use subxt::utils::{AccountId32, MultiAddress, MultiSignature};
|
utils::{AccountId32, MultiAddress, MultiSignature},
|
||||||
|
Config,
|
||||||
|
};
|
||||||
|
|
||||||
impl From<Signature> for MultiSignature {
|
impl From<Signature> for MultiSignature {
|
||||||
fn from(value: Signature) -> Self {
|
fn from(value: Signature) -> Self {
|
||||||
|
|||||||
+3
-10
@@ -53,7 +53,7 @@ jsonrpsee = [
|
|||||||
# Enable this to pull in extra Substrate dependencies which make it possible to
|
# Enable this to pull in extra Substrate dependencies which make it possible to
|
||||||
# use the `sp_core::crypto::Pair` Signer implementation, as well as adding some
|
# use the `sp_core::crypto::Pair` Signer implementation, as well as adding some
|
||||||
# `From` impls for types like `AccountId32`. Cannot be used with "web".
|
# `From` impls for types like `AccountId32`. Cannot be used with "web".
|
||||||
substrate-compat = ["sp-core", "sp-runtime"]
|
substrate-compat = ["subxt-core/substrate-compat"]
|
||||||
|
|
||||||
# Enable this to fetch and utilize the latest unstable metadata from a node.
|
# Enable this to fetch and utilize the latest unstable metadata from a node.
|
||||||
# The unstable metadata is subject to breaking changes and the subxt might
|
# The unstable metadata is subject to breaking changes and the subxt might
|
||||||
@@ -68,6 +68,7 @@ unstable-light-client = ["subxt-lightclient"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive"] }
|
codec = { package = "parity-scale-codec", workspace = true, features = ["derive"] }
|
||||||
|
derive-where = { workspace = true }
|
||||||
scale-info = { workspace = true, features = ["default"] }
|
scale-info = { workspace = true, features = ["default"] }
|
||||||
scale-value = { workspace = true, features = ["default"] }
|
scale-value = { workspace = true, features = ["default"] }
|
||||||
scale-bits = { workspace = true, features = ["default"] }
|
scale-bits = { workspace = true, features = ["default"] }
|
||||||
@@ -80,7 +81,6 @@ serde_json = { workspace = true, features = ["default", "raw_value"] }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
frame-metadata = { workspace = true }
|
frame-metadata = { workspace = true }
|
||||||
derivative = { workspace = true }
|
|
||||||
either = { workspace = true }
|
either = { workspace = true }
|
||||||
instant = { workspace = true }
|
instant = { workspace = true }
|
||||||
|
|
||||||
@@ -89,19 +89,12 @@ impl-serde = { workspace = true }
|
|||||||
primitive-types = { workspace = true, features = ["codec", "scale-info", "serde"] }
|
primitive-types = { workspace = true, features = ["codec", "scale-info", "serde"] }
|
||||||
sp-crypto-hashing = { workspace = true }
|
sp-crypto-hashing = { workspace = true }
|
||||||
|
|
||||||
# For ss58 encoding AccountId32 to serialize them properly:
|
|
||||||
base58 = { workspace = true }
|
|
||||||
blake2 = { workspace = true }
|
|
||||||
|
|
||||||
# Included if the "jsonrpsee" feature is enabled.
|
# Included if the "jsonrpsee" feature is enabled.
|
||||||
jsonrpsee = { workspace = true, optional = true, features = ["jsonrpsee-types"] }
|
jsonrpsee = { workspace = true, optional = true, features = ["jsonrpsee-types"] }
|
||||||
|
|
||||||
# Included if the "substrate-compat" feature is enabled.
|
|
||||||
sp-core = { workspace = true, optional = true }
|
|
||||||
sp-runtime = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
# Other subxt crates we depend on.
|
# Other subxt crates we depend on.
|
||||||
subxt-macro = { workspace = true }
|
subxt-macro = { workspace = true }
|
||||||
|
subxt-core = { workspace = true, features = ["std"] }
|
||||||
subxt-metadata = { workspace = true, features = ["std"] }
|
subxt-metadata = { workspace = true, features = ["std"] }
|
||||||
subxt-lightclient = { workspace = true, optional = true, default-features = false }
|
subxt-lightclient = { workspace = true, optional = true, default-features = false }
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 2. A runtime version (system_version constant on a Substrate node has these):
|
// 2. A runtime version (system_version constant on a Substrate node has these):
|
||||||
let runtime_version = subxt::backend::RuntimeVersion {
|
let runtime_version = subxt::client::RuntimeVersion::new(9370, 20);
|
||||||
spec_version: 9370,
|
|
||||||
transaction_version: 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. Metadata (I'll load it from the downloaded metadata, but you can use
|
// 3. Metadata (I'll load it from the downloaded metadata, but you can use
|
||||||
// `subxt metadata > file.scale` to download it):
|
// `subxt metadata > file.scale` to download it):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use subxt::client::OfflineClientT;
|
use subxt::client::ClientState;
|
||||||
use subxt::config::{
|
use subxt::config::{
|
||||||
Config, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError, RefineParams,
|
Config, ExtrinsicParams, ExtrinsicParamsEncoder, ExtrinsicParamsError, RefineParams,
|
||||||
};
|
};
|
||||||
@@ -60,10 +60,7 @@ impl<T: Config> ExtrinsicParams<T> for CustomExtrinsicParams<T> {
|
|||||||
type Params = CustomExtrinsicParamsBuilder;
|
type Params = CustomExtrinsicParamsBuilder;
|
||||||
|
|
||||||
// Gather together all of the params we will need to encode:
|
// Gather together all of the params we will need to encode:
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(client: &ClientState<T>, params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
client: Client,
|
|
||||||
params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
genesis_hash: client.genesis_hash(),
|
genesis_hash: client.genesis_hash(),
|
||||||
tip: params.tip,
|
tip: params.tip,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use scale_encode::EncodeAsType;
|
use scale_encode::EncodeAsType;
|
||||||
use scale_info::PortableRegistry;
|
use scale_info::PortableRegistry;
|
||||||
use subxt::client::OfflineClientT;
|
use subxt::client::ClientState;
|
||||||
use subxt::config::signed_extensions;
|
use subxt::config::signed_extensions;
|
||||||
use subxt::config::{
|
use subxt::config::{
|
||||||
Config, DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder,
|
Config, DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder,
|
||||||
@@ -60,10 +60,7 @@ impl<T: Config> signed_extensions::SignedExtension<T> for CustomSignedExtension
|
|||||||
impl<T: Config> ExtrinsicParams<T> for CustomSignedExtension {
|
impl<T: Config> ExtrinsicParams<T> for CustomSignedExtension {
|
||||||
type Params = ();
|
type Params = ();
|
||||||
|
|
||||||
fn new<Client: OfflineClientT<T>>(
|
fn new(_client: &ClientState<T>, _params: Self::Params) -> Result<Self, ExtrinsicParamsError> {
|
||||||
_client: Client,
|
|
||||||
_params: Self::Params,
|
|
||||||
) -> Result<Self, ExtrinsicParamsError> {
|
|
||||||
Ok(CustomSignedExtension)
|
Ok(CustomSignedExtension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
use subxt::{OnlineClient, PolkadotConfig};
|
use subxt::{dynamic::Value, OnlineClient, PolkadotConfig};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -8,7 +8,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
// Build a dynamic storage query to iterate account information.
|
// Build a dynamic storage query to iterate account information.
|
||||||
// With a dynamic query, we can just provide an empty vector as the keys to iterate over all entries.
|
// With a dynamic query, we can just provide an empty vector as the keys to iterate over all entries.
|
||||||
let keys: Vec<scale_value::Value> = vec![];
|
let keys: Vec<Value> = vec![];
|
||||||
let storage_query = subxt::dynamic::storage("System", "Account", keys);
|
let storage_query = subxt::dynamic::storage("System", "Account", keys);
|
||||||
|
|
||||||
// Use that query to return an iterator over the results.
|
// Use that query to return an iterator over the results.
|
||||||
|
|||||||
@@ -181,20 +181,16 @@ impl<T: Config + Send + Sync + 'static> Backend<T> for LegacyBackend<T> {
|
|||||||
|
|
||||||
async fn current_runtime_version(&self) -> Result<RuntimeVersion, Error> {
|
async fn current_runtime_version(&self) -> Result<RuntimeVersion, Error> {
|
||||||
let details = self.methods.state_get_runtime_version(None).await?;
|
let details = self.methods.state_get_runtime_version(None).await?;
|
||||||
Ok(RuntimeVersion {
|
Ok(RuntimeVersion::new(
|
||||||
spec_version: details.spec_version,
|
details.spec_version,
|
||||||
transaction_version: details.transaction_version,
|
details.transaction_version,
|
||||||
})
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn stream_runtime_version(&self) -> Result<StreamOfResults<RuntimeVersion>, Error> {
|
async fn stream_runtime_version(&self) -> Result<StreamOfResults<RuntimeVersion>, Error> {
|
||||||
let sub = self.methods.state_subscribe_runtime_version().await?;
|
let sub = self.methods.state_subscribe_runtime_version().await?;
|
||||||
let sub = sub.map(|r| {
|
let sub =
|
||||||
r.map(|v| RuntimeVersion {
|
sub.map(|r| r.map(|v| RuntimeVersion::new(v.spec_version, v.transaction_version)));
|
||||||
spec_version: v.spec_version,
|
|
||||||
transaction_version: v.transaction_version,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
Ok(StreamOf(Box::pin(sub)))
|
Ok(StreamOf(Box::pin(sub)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,14 @@ use crate::backend::rpc::{rpc_params, RpcClient, RpcSubscription};
|
|||||||
use crate::metadata::Metadata;
|
use crate::metadata::Metadata;
|
||||||
use crate::{Config, Error};
|
use crate::{Config, Error};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use primitive_types::U256;
|
use primitive_types::U256;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// An interface to call the legacy RPC methods. This interface is instantiated with
|
/// An interface to call the legacy RPC methods. This interface is instantiated with
|
||||||
/// some `T: Config` trait which determines some of the types that the RPC methods will
|
/// some `T: Config` trait which determines some of the types that the RPC methods will
|
||||||
/// take or hand back.
|
/// take or hand back.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug)]
|
||||||
#[derivative(Clone(bound = ""), Debug(bound = ""))]
|
|
||||||
pub struct LegacyRpcMethods<T> {
|
pub struct LegacyRpcMethods<T> {
|
||||||
client: RpcClient,
|
client: RpcClient,
|
||||||
_marker: std::marker::PhantomData<T>,
|
_marker: std::marker::PhantomData<T>,
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ pub mod legacy;
|
|||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
pub mod unstable;
|
pub mod unstable;
|
||||||
|
|
||||||
|
use subxt_core::client::RuntimeVersion;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::metadata::Metadata;
|
use crate::metadata::Metadata;
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
@@ -277,26 +279,6 @@ impl<T> StreamOf<T> {
|
|||||||
/// A stream of [`Result<Item, Error>`].
|
/// A stream of [`Result<Item, Error>`].
|
||||||
pub type StreamOfResults<T> = StreamOf<Result<T, Error>>;
|
pub type StreamOfResults<T> = StreamOf<Result<T, Error>>;
|
||||||
|
|
||||||
/// Runtime version information needed to submit transactions.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct RuntimeVersion {
|
|
||||||
/// Version of the runtime specification. A full-node will not attempt to use its native
|
|
||||||
/// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
|
|
||||||
/// `spec_version` and `authoring_version` are the same between Wasm and native.
|
|
||||||
pub spec_version: u32,
|
|
||||||
|
|
||||||
/// All existing dispatches are fully compatible when this number doesn't change. If this
|
|
||||||
/// number changes, then `spec_version` must change, also.
|
|
||||||
///
|
|
||||||
/// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
|
|
||||||
/// either through an alteration in its user-level semantics, a parameter
|
|
||||||
/// added/removed/changed, a dispatchable being removed, a module being removed, or a
|
|
||||||
/// dispatchable/module changing its index.
|
|
||||||
///
|
|
||||||
/// It need *not* change when a new module is added or when a dispatchable is added.
|
|
||||||
pub transaction_version: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The status of the transaction.
|
/// The status of the transaction.
|
||||||
///
|
///
|
||||||
/// If the status is [`TransactionStatus::InFinalizedBlock`], [`TransactionStatus::Error`],
|
/// If the status is [`TransactionStatus::InFinalizedBlock`], [`TransactionStatus::Error`],
|
||||||
|
|||||||
@@ -361,7 +361,6 @@ impl<T: Config + Send + Sync + 'static> Backend<T> for UnstableBackend<T> {
|
|||||||
for finalized_block in ev.finalized_block_hashes {
|
for finalized_block in ev.finalized_block_hashes {
|
||||||
runtimes.remove(&finalized_block.hash());
|
runtimes.remove(&finalized_block.hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.finalized_block_runtime
|
ev.finalized_block_runtime
|
||||||
}
|
}
|
||||||
FollowEvent::NewBlock(ev) => {
|
FollowEvent::NewBlock(ev) => {
|
||||||
@@ -417,10 +416,8 @@ impl<T: Config + Send + Sync + 'static> Backend<T> for UnstableBackend<T> {
|
|||||||
RuntimeEvent::Valid(ev) => ev,
|
RuntimeEvent::Valid(ev) => ev,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::future::ready(Some(Ok(RuntimeVersion {
|
let runtime_version = RuntimeVersion::new(runtime_details.spec.spec_version, runtime_details.spec.transaction_version);
|
||||||
spec_version: runtime_details.spec.spec_version,
|
std::future::ready(Some(Ok(runtime_version)))
|
||||||
transaction_version: runtime_details.spec.transaction_version,
|
|
||||||
})))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(StreamOf(Box::pin(runtime_stream)))
|
Ok(StreamOf(Box::pin(runtime_stream)))
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
use crate::backend::rpc::{rpc_params, RpcClient, RpcSubscription};
|
use crate::backend::rpc::{rpc_params, RpcClient, RpcSubscription};
|
||||||
use crate::config::BlockHash;
|
use crate::config::BlockHash;
|
||||||
use crate::{Config, Error};
|
use crate::{Config, Error};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
@@ -18,8 +18,7 @@ use std::task::Poll;
|
|||||||
/// An interface to call the unstable RPC methods. This interface is instantiated with
|
/// An interface to call the unstable RPC methods. This interface is instantiated with
|
||||||
/// some `T: Config` trait which determines some of the types that the RPC methods will
|
/// some `T: Config` trait which determines some of the types that the RPC methods will
|
||||||
/// take or hand back.
|
/// take or hand back.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone, Debug)]
|
||||||
#[derivative(Clone(bound = ""), Debug(bound = ""))]
|
|
||||||
pub struct UnstableRpcMethods<T> {
|
pub struct UnstableRpcMethods<T> {
|
||||||
client: RpcClient,
|
client: RpcClient,
|
||||||
_marker: std::marker::PhantomData<T>,
|
_marker: std::marker::PhantomData<T>,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
error::{BlockError, Error},
|
error::{BlockError, Error},
|
||||||
utils::PhantomDataSendSync,
|
utils::PhantomDataSendSync,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
@@ -18,8 +18,7 @@ type BlockStream<T> = StreamOfResults<T>;
|
|||||||
type BlockStreamRes<T> = Result<BlockStream<T>, Error>;
|
type BlockStreamRes<T> = Result<BlockStream<T>, Error>;
|
||||||
|
|
||||||
/// A client for working with blocks.
|
/// A client for working with blocks.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct BlocksClient<T, Client> {
|
pub struct BlocksClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: PhantomDataSendSync<T>,
|
_marker: PhantomDataSendSync<T>,
|
||||||
|
|||||||
@@ -16,31 +16,14 @@ use crate::config::signed_extensions::{
|
|||||||
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce,
|
ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce,
|
||||||
};
|
};
|
||||||
use crate::config::SignedExtension;
|
use crate::config::SignedExtension;
|
||||||
use crate::dynamic::DecodedValue;
|
use crate::dynamic::Value;
|
||||||
use crate::utils::strip_compact_prefix;
|
use crate::utils::strip_compact_prefix;
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use scale_decode::{DecodeAsFields, DecodeAsType};
|
use scale_decode::DecodeAsType;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
pub use subxt_core::blocks::StaticExtrinsic;
|
||||||
/// Trait to uniquely identify the extrinsic's identity from the runtime metadata.
|
|
||||||
///
|
|
||||||
/// Generated API structures that represent an extrinsic implement this trait.
|
|
||||||
///
|
|
||||||
/// The trait is utilized to decode emitted extrinsics from a block, via obtaining the
|
|
||||||
/// form of the `Extrinsic` from the metadata.
|
|
||||||
pub trait StaticExtrinsic: DecodeAsFields {
|
|
||||||
/// Pallet name.
|
|
||||||
const PALLET: &'static str;
|
|
||||||
/// Call name.
|
|
||||||
const CALL: &'static str;
|
|
||||||
|
|
||||||
/// Returns true if the given pallet and call names match this extrinsic.
|
|
||||||
fn is_extrinsic(pallet: &str, call: &str) -> bool {
|
|
||||||
Self::PALLET == pallet && Self::CALL == call
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The body of a block.
|
/// The body of a block.
|
||||||
pub struct Extrinsics<T: Config, C> {
|
pub struct Extrinsics<T: Config, C> {
|
||||||
@@ -524,8 +507,7 @@ impl ExtrinsicPartTypeIds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The events associated with a given extrinsic.
|
/// The events associated with a given extrinsic.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Debug)]
|
||||||
#[derivative(Debug(bound = ""))]
|
|
||||||
pub struct ExtrinsicEvents<T: Config> {
|
pub struct ExtrinsicEvents<T: Config> {
|
||||||
// The hash of the extrinsic (handy to expose here because
|
// The hash of the extrinsic (handy to expose here because
|
||||||
// this type is returned from TxProgress things in the most
|
// this type is returned from TxProgress things in the most
|
||||||
@@ -547,11 +529,6 @@ impl<T: Config> ExtrinsicEvents<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the hash of the block that the extrinsic is in.
|
|
||||||
pub fn block_hash(&self) -> T::Hash {
|
|
||||||
self.events.block_hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The index of the extrinsic that these events are produced from.
|
/// The index of the extrinsic that these events are produced from.
|
||||||
pub fn extrinsic_index(&self) -> u32 {
|
pub fn extrinsic_index(&self) -> u32 {
|
||||||
self.idx
|
self.idx
|
||||||
@@ -572,11 +549,14 @@ impl<T: Config> ExtrinsicEvents<T> {
|
|||||||
/// This works in the same way that [`events::Events::iter()`] does, with the
|
/// This works in the same way that [`events::Events::iter()`] does, with the
|
||||||
/// exception that it filters out events not related to the submitted extrinsic.
|
/// exception that it filters out events not related to the submitted extrinsic.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = Result<events::EventDetails<T>, Error>> + '_ {
|
pub fn iter(&self) -> impl Iterator<Item = Result<events::EventDetails<T>, Error>> + '_ {
|
||||||
self.events.iter().filter(|ev| {
|
self.events
|
||||||
ev.as_ref()
|
.iter()
|
||||||
.map(|ev| ev.phase() == events::Phase::ApplyExtrinsic(self.idx))
|
.filter(|ev| {
|
||||||
.unwrap_or(true) // Keep any errors.
|
ev.as_ref()
|
||||||
})
|
.map(|ev| ev.phase() == events::Phase::ApplyExtrinsic(self.idx))
|
||||||
|
.unwrap_or(true) // Keep any errors.
|
||||||
|
})
|
||||||
|
.map(|e| e.map_err(Error::from))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find all of the transaction events matching the event type provided as a generic parameter.
|
/// Find all of the transaction events matching the event type provided as a generic parameter.
|
||||||
@@ -742,7 +722,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Signed Extension as a [`scale_value::Value`]
|
/// Signed Extension as a [`scale_value::Value`]
|
||||||
pub fn value(&self) -> Result<DecodedValue, Error> {
|
pub fn value(&self) -> Result<Value<u32>, Error> {
|
||||||
let value = scale_value::scale::decode_as_type(
|
let value = scale_value::scale::decode_as_type(
|
||||||
&mut &self.bytes[..],
|
&mut &self.bytes[..],
|
||||||
&self.ty_id,
|
&self.ty_id,
|
||||||
@@ -770,7 +750,7 @@ impl<'a, T: Config> ExtrinsicSignedExtension<'a, T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{backend::RuntimeVersion, OfflineClient, PolkadotConfig};
|
use crate::{OfflineClient, PolkadotConfig};
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_metadata::v15::{CustomMetadata, OuterEnums};
|
use frame_metadata::v15::{CustomMetadata, OuterEnums};
|
||||||
@@ -781,6 +761,7 @@ mod tests {
|
|||||||
use primitive_types::H256;
|
use primitive_types::H256;
|
||||||
use scale_info::{meta_type, TypeInfo};
|
use scale_info::{meta_type, TypeInfo};
|
||||||
use scale_value::Value;
|
use scale_value::Value;
|
||||||
|
use subxt_core::client::RuntimeVersion;
|
||||||
|
|
||||||
// Extrinsic needs to contain at least the generic type parameter "Call"
|
// Extrinsic needs to contain at least the generic type parameter "Call"
|
||||||
// for the metadata to be valid.
|
// for the metadata to be valid.
|
||||||
@@ -902,10 +883,7 @@ mod tests {
|
|||||||
/// Build an offline client to work with the test metadata.
|
/// Build an offline client to work with the test metadata.
|
||||||
fn client(metadata: Metadata) -> OfflineClient<PolkadotConfig> {
|
fn client(metadata: Metadata) -> OfflineClient<PolkadotConfig> {
|
||||||
// Create the encoded extrinsic bytes.
|
// Create the encoded extrinsic bytes.
|
||||||
let rt_version = RuntimeVersion {
|
let rt_version = RuntimeVersion::new(1, 4);
|
||||||
spec_version: 1,
|
|
||||||
transaction_version: 4,
|
|
||||||
};
|
|
||||||
let block_hash = H256::random();
|
let block_hash = H256::random();
|
||||||
OfflineClient::new(block_hash, rt_version, metadata)
|
OfflineClient::new(block_hash, rt_version, metadata)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ pub use offline_client::{OfflineClient, OfflineClientT};
|
|||||||
pub use online_client::{
|
pub use online_client::{
|
||||||
ClientRuntimeUpdater, OnlineClient, OnlineClientT, RuntimeUpdaterStream, Update, UpgradeError,
|
ClientRuntimeUpdater, OnlineClient, OnlineClientT, RuntimeUpdaterStream, Update, UpgradeError,
|
||||||
};
|
};
|
||||||
|
pub use subxt_core::client::{ClientState, RuntimeVersion};
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
use crate::custom_values::CustomValuesClient;
|
use crate::custom_values::CustomValuesClient;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::RuntimeVersion, blocks::BlocksClient, constants::ConstantsClient,
|
blocks::BlocksClient, constants::ConstantsClient, events::EventsClient,
|
||||||
events::EventsClient, runtime_api::RuntimeApiClient, storage::StorageClient, tx::TxClient,
|
runtime_api::RuntimeApiClient, storage::StorageClient, tx::TxClient, Config, Metadata,
|
||||||
Config, Metadata,
|
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
|
||||||
|
|
||||||
|
use derive_where::derive_where;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use subxt_core::client::{ClientState, RuntimeVersion};
|
||||||
|
|
||||||
/// A trait representing a client that can perform
|
/// A trait representing a client that can perform
|
||||||
/// offline-only actions.
|
/// offline-only actions.
|
||||||
@@ -21,6 +21,10 @@ pub trait OfflineClientT<T: Config>: Clone + Send + Sync + 'static {
|
|||||||
fn genesis_hash(&self) -> T::Hash;
|
fn genesis_hash(&self) -> T::Hash;
|
||||||
/// Return the provided [`RuntimeVersion`].
|
/// Return the provided [`RuntimeVersion`].
|
||||||
fn runtime_version(&self) -> RuntimeVersion;
|
fn runtime_version(&self) -> RuntimeVersion;
|
||||||
|
/// Return the [subxt_core::client::ClientState] (metadata, runtime version and genesis hash).
|
||||||
|
fn client_state(&self) -> ClientState<T> {
|
||||||
|
ClientState::new(self.genesis_hash(), self.runtime_version(), self.metadata())
|
||||||
|
}
|
||||||
|
|
||||||
/// Work with transactions.
|
/// Work with transactions.
|
||||||
fn tx(&self) -> TxClient<T, Self> {
|
fn tx(&self) -> TxClient<T, Self> {
|
||||||
@@ -60,18 +64,9 @@ pub trait OfflineClientT<T: Config>: Clone + Send + Sync + 'static {
|
|||||||
|
|
||||||
/// A client that is capable of performing offline-only operations.
|
/// A client that is capable of performing offline-only operations.
|
||||||
/// Can be constructed as long as you can populate the required fields.
|
/// Can be constructed as long as you can populate the required fields.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Debug, Clone)]
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
|
||||||
pub struct OfflineClient<T: Config> {
|
pub struct OfflineClient<T: Config> {
|
||||||
inner: Arc<Inner<T>>,
|
inner: Arc<ClientState<T>>,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative)]
|
|
||||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
|
||||||
struct Inner<T: Config> {
|
|
||||||
genesis_hash: T::Hash,
|
|
||||||
runtime_version: RuntimeVersion,
|
|
||||||
metadata: Metadata,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> OfflineClient<T> {
|
impl<T: Config> OfflineClient<T> {
|
||||||
@@ -83,27 +78,36 @@ impl<T: Config> OfflineClient<T> {
|
|||||||
metadata: impl Into<Metadata>,
|
metadata: impl Into<Metadata>,
|
||||||
) -> OfflineClient<T> {
|
) -> OfflineClient<T> {
|
||||||
OfflineClient {
|
OfflineClient {
|
||||||
inner: Arc::new(Inner {
|
inner: Arc::new(ClientState::new(
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
runtime_version,
|
runtime_version,
|
||||||
metadata: metadata.into(),
|
metadata.into(),
|
||||||
}),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the genesis hash.
|
/// Return the genesis hash.
|
||||||
pub fn genesis_hash(&self) -> T::Hash {
|
pub fn genesis_hash(&self) -> T::Hash {
|
||||||
self.inner.genesis_hash
|
self.inner.genesis_hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the runtime version.
|
/// Return the runtime version.
|
||||||
pub fn runtime_version(&self) -> RuntimeVersion {
|
pub fn runtime_version(&self) -> RuntimeVersion {
|
||||||
self.inner.runtime_version.clone()
|
self.inner.runtime_version()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`Metadata`] used in this client.
|
/// Return the [`Metadata`] used in this client.
|
||||||
pub fn metadata(&self) -> Metadata {
|
pub fn metadata(&self) -> Metadata {
|
||||||
self.inner.metadata.clone()
|
self.inner.metadata()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [subxt_core::client::ClientState] (metadata, runtime version and genesis hash).
|
||||||
|
pub fn client_state(&self) -> ClientState<T> {
|
||||||
|
ClientState::new(
|
||||||
|
self.inner.genesis_hash(),
|
||||||
|
self.inner.runtime_version(),
|
||||||
|
self.inner.metadata(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just a copy of the most important trait methods so that people
|
// Just a copy of the most important trait methods so that people
|
||||||
@@ -145,6 +149,9 @@ impl<T: Config> OfflineClientT<T> for OfflineClient<T> {
|
|||||||
fn metadata(&self) -> Metadata {
|
fn metadata(&self) -> Metadata {
|
||||||
self.metadata()
|
self.metadata()
|
||||||
}
|
}
|
||||||
|
fn client_state(&self) -> ClientState<T> {
|
||||||
|
self.client_state()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For ergonomics; cloning a client is deliberately fairly cheap (via Arc),
|
// For ergonomics; cloning a client is deliberately fairly cheap (via Arc),
|
||||||
|
|||||||
@@ -5,9 +5,7 @@
|
|||||||
use super::{OfflineClient, OfflineClientT};
|
use super::{OfflineClient, OfflineClientT};
|
||||||
use crate::custom_values::CustomValuesClient;
|
use crate::custom_values::CustomValuesClient;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{legacy::LegacyBackend, rpc::RpcClient, Backend, BackendExt, StreamOfResults},
|
||||||
legacy::LegacyBackend, rpc::RpcClient, Backend, BackendExt, RuntimeVersion, StreamOfResults,
|
|
||||||
},
|
|
||||||
blocks::{BlockRef, BlocksClient},
|
blocks::{BlockRef, BlocksClient},
|
||||||
constants::ConstantsClient,
|
constants::ConstantsClient,
|
||||||
error::Error,
|
error::Error,
|
||||||
@@ -17,9 +15,10 @@ use crate::{
|
|||||||
tx::TxClient,
|
tx::TxClient,
|
||||||
Config, Metadata,
|
Config, Metadata,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use futures::future;
|
use futures::future;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
use subxt_core::client::{ClientState, RuntimeVersion};
|
||||||
|
|
||||||
/// A trait representing a client that can perform
|
/// A trait representing a client that can perform
|
||||||
/// online actions.
|
/// online actions.
|
||||||
@@ -30,15 +29,13 @@ pub trait OnlineClientT<T: Config>: OfflineClientT<T> {
|
|||||||
|
|
||||||
/// A client that can be used to perform API calls (that is, either those
|
/// A client that can be used to perform API calls (that is, either those
|
||||||
/// requiring an [`OfflineClientT`] or those requiring an [`OnlineClientT`]).
|
/// requiring an [`OfflineClientT`] or those requiring an [`OnlineClientT`]).
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone)]
|
||||||
#[derivative(Clone(bound = ""))]
|
|
||||||
pub struct OnlineClient<T: Config> {
|
pub struct OnlineClient<T: Config> {
|
||||||
inner: Arc<RwLock<Inner<T>>>,
|
inner: Arc<RwLock<Inner<T>>>,
|
||||||
backend: Arc<dyn Backend<T>>,
|
backend: Arc<dyn Backend<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive_where(Debug)]
|
||||||
#[derivative(Debug(bound = ""))]
|
|
||||||
struct Inner<T: Config> {
|
struct Inner<T: Config> {
|
||||||
genesis_hash: T::Hash,
|
genesis_hash: T::Hash,
|
||||||
runtime_version: RuntimeVersion,
|
runtime_version: RuntimeVersion,
|
||||||
@@ -231,7 +228,7 @@ impl<T: Config> OnlineClient<T> {
|
|||||||
/// let mut update_stream = updater.runtime_updates().await.unwrap();
|
/// let mut update_stream = updater.runtime_updates().await.unwrap();
|
||||||
///
|
///
|
||||||
/// while let Some(Ok(update)) = update_stream.next().await {
|
/// while let Some(Ok(update)) = update_stream.next().await {
|
||||||
/// let version = update.runtime_version().spec_version;
|
/// let version = update.runtime_version().spec_version();
|
||||||
///
|
///
|
||||||
/// match updater.apply_update(update) {
|
/// match updater.apply_update(update) {
|
||||||
/// Ok(()) => {
|
/// Ok(()) => {
|
||||||
@@ -286,7 +283,17 @@ impl<T: Config> OnlineClient<T> {
|
|||||||
/// Return the runtime version.
|
/// Return the runtime version.
|
||||||
pub fn runtime_version(&self) -> RuntimeVersion {
|
pub fn runtime_version(&self) -> RuntimeVersion {
|
||||||
let inner = self.inner.read().expect("shouldn't be poisoned");
|
let inner = self.inner.read().expect("shouldn't be poisoned");
|
||||||
inner.runtime_version.clone()
|
inner.runtime_version
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [subxt_core::client::ClientState] (metadata, runtime version and genesis hash).
|
||||||
|
pub fn client_state(&self) -> ClientState<T> {
|
||||||
|
let inner = self.inner.read().expect("shouldn't be poisoned");
|
||||||
|
ClientState::new(
|
||||||
|
inner.genesis_hash,
|
||||||
|
inner.runtime_version,
|
||||||
|
inner.metadata.clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the [`RuntimeVersion`] used in this client.
|
/// Change the [`RuntimeVersion`] used in this client.
|
||||||
@@ -310,7 +317,7 @@ impl<T: Config> OnlineClient<T> {
|
|||||||
let inner = self.inner.read().expect("shouldn't be poisoned");
|
let inner = self.inner.read().expect("shouldn't be poisoned");
|
||||||
OfflineClient::new(
|
OfflineClient::new(
|
||||||
inner.genesis_hash,
|
inner.genesis_hash,
|
||||||
inner.runtime_version.clone(),
|
inner.runtime_version,
|
||||||
inner.metadata.clone(),
|
inner.metadata.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -364,6 +371,10 @@ impl<T: Config> OfflineClientT<T> for OnlineClient<T> {
|
|||||||
fn runtime_version(&self) -> RuntimeVersion {
|
fn runtime_version(&self) -> RuntimeVersion {
|
||||||
self.runtime_version()
|
self.runtime_version()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_state(&self) -> ClientState<T> {
|
||||||
|
self.client_state()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Config> OnlineClientT<T> for OnlineClient<T> {
|
impl<T: Config> OnlineClientT<T> for OnlineClient<T> {
|
||||||
@@ -525,7 +536,7 @@ async fn wait_runtime_upgrade_in_finalized_block<T: Config>(
|
|||||||
|
|
||||||
let scale_val = match chunk.to_value() {
|
let scale_val = match chunk.to_value() {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e.into())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(Ok(spec_version)) = scale_val
|
let Some(Ok(spec_version)) = scale_val
|
||||||
@@ -540,7 +551,7 @@ async fn wait_runtime_upgrade_in_finalized_block<T: Config>(
|
|||||||
|
|
||||||
// We are waiting for the chain to have the same spec version
|
// We are waiting for the chain to have the same spec version
|
||||||
// as sent out via the runtime subscription.
|
// as sent out via the runtime subscription.
|
||||||
if spec_version == runtime_version.spec_version {
|
if spec_version == runtime_version.spec_version() {
|
||||||
break block_ref;
|
break block_ref;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,17 +3,11 @@
|
|||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use super::ConstantAddress;
|
use super::ConstantAddress;
|
||||||
use crate::{
|
use crate::{client::OfflineClientT, error::Error, Config};
|
||||||
client::OfflineClientT,
|
use derive_where::derive_where;
|
||||||
error::{Error, MetadataError},
|
|
||||||
metadata::DecodeWithMetadata,
|
|
||||||
Config,
|
|
||||||
};
|
|
||||||
use derivative::Derivative;
|
|
||||||
|
|
||||||
/// A client for accessing constants.
|
/// A client for accessing constants.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct ConstantsClient<T, Client> {
|
pub struct ConstantsClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: std::marker::PhantomData<T>,
|
_marker: std::marker::PhantomData<T>,
|
||||||
@@ -35,20 +29,8 @@ impl<T: Config, Client: OfflineClientT<T>> ConstantsClient<T, Client> {
|
|||||||
/// Return an error if the address was not valid or something went wrong trying to validate it (ie
|
/// Return an error if the address was not valid or something went wrong trying to validate it (ie
|
||||||
/// the pallet or constant in question do not exist at all).
|
/// the pallet or constant in question do not exist at all).
|
||||||
pub fn validate<Address: ConstantAddress>(&self, address: &Address) -> Result<(), Error> {
|
pub fn validate<Address: ConstantAddress>(&self, address: &Address) -> Result<(), Error> {
|
||||||
if let Some(actual_hash) = address.validation_hash() {
|
let metadata = self.client.metadata();
|
||||||
let expected_hash = self
|
subxt_core::constants::validate_constant(&metadata, address).map_err(Error::from)
|
||||||
.client
|
|
||||||
.metadata()
|
|
||||||
.pallet_by_name_err(address.pallet_name())?
|
|
||||||
.constant_hash(address.constant_name())
|
|
||||||
.ok_or_else(|| {
|
|
||||||
MetadataError::ConstantNameNotFound(address.constant_name().to_owned())
|
|
||||||
})?;
|
|
||||||
if actual_hash != expected_hash {
|
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the constant at the address given, returning the type defined by this address.
|
/// Access the constant at the address given, returning the type defined by this address.
|
||||||
@@ -59,22 +41,6 @@ impl<T: Config, Client: OfflineClientT<T>> ConstantsClient<T, Client> {
|
|||||||
address: &Address,
|
address: &Address,
|
||||||
) -> Result<Address::Target, Error> {
|
) -> Result<Address::Target, Error> {
|
||||||
let metadata = self.client.metadata();
|
let metadata = self.client.metadata();
|
||||||
|
subxt_core::constants::get_constant(&metadata, address).map_err(Error::from)
|
||||||
// 1. Validate constant shape if hash given:
|
|
||||||
self.validate(address)?;
|
|
||||||
|
|
||||||
// 2. Attempt to decode the constant into the type given:
|
|
||||||
let constant = metadata
|
|
||||||
.pallet_by_name_err(address.pallet_name())?
|
|
||||||
.constant_by_name(address.constant_name())
|
|
||||||
.ok_or_else(|| {
|
|
||||||
MetadataError::ConstantNameNotFound(address.constant_name().to_owned())
|
|
||||||
})?;
|
|
||||||
let value = <Address::Target as DecodeWithMetadata>::decode_with_metadata(
|
|
||||||
&mut constant.value(),
|
|
||||||
constant.ty(),
|
|
||||||
&metadata,
|
|
||||||
)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
//! Types associated with accessing constants.
|
//! Types associated with accessing constants.
|
||||||
|
|
||||||
mod constant_address;
|
|
||||||
mod constants_client;
|
mod constants_client;
|
||||||
|
|
||||||
pub use constant_address::{dynamic, Address, ConstantAddress, DynamicAddress};
|
|
||||||
pub use constants_client::ConstantsClient;
|
pub use constants_client::ConstantsClient;
|
||||||
|
pub use subxt_core::constants::{dynamic, Address, ConstantAddress, DynamicAddress};
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use crate::client::OfflineClientT;
|
use crate::client::OfflineClientT;
|
||||||
use crate::custom_values::custom_value_address::{CustomValueAddress, Yes};
|
|
||||||
use crate::error::MetadataError;
|
|
||||||
use crate::metadata::DecodeWithMetadata;
|
|
||||||
use crate::{Config, Error};
|
use crate::{Config, Error};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
|
|
||||||
|
use subxt_core::custom_values::{
|
||||||
|
get_custom_value, get_custom_value_bytes, validate_custom_value, CustomValueAddress,
|
||||||
|
};
|
||||||
|
use subxt_core::utils::Yes;
|
||||||
|
|
||||||
/// A client for accessing custom values stored in the metadata.
|
/// A client for accessing custom values stored in the metadata.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct CustomValuesClient<T, Client> {
|
pub struct CustomValuesClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: std::marker::PhantomData<T>,
|
_marker: std::marker::PhantomData<T>,
|
||||||
@@ -30,22 +31,7 @@ impl<T: Config, Client: OfflineClientT<T>> CustomValuesClient<T, Client> {
|
|||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
) -> Result<Address::Target, Error> {
|
) -> Result<Address::Target, Error> {
|
||||||
// 1. Validate custom value shape if hash given:
|
get_custom_value(&self.client.metadata(), address).map_err(Into::into)
|
||||||
self.validate(address)?;
|
|
||||||
|
|
||||||
// 2. Attempt to decode custom value:
|
|
||||||
let metadata = self.client.metadata();
|
|
||||||
let custom = metadata.custom();
|
|
||||||
let custom_value = custom
|
|
||||||
.get(address.name())
|
|
||||||
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().to_string()))?;
|
|
||||||
|
|
||||||
let value = <Address::Target as DecodeWithMetadata>::decode_with_metadata(
|
|
||||||
&mut custom_value.bytes(),
|
|
||||||
custom_value.type_id(),
|
|
||||||
&metadata,
|
|
||||||
)?;
|
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the bytes of a custom value by the address it is registered under.
|
/// Access the bytes of a custom value by the address it is registered under.
|
||||||
@@ -53,17 +39,7 @@ impl<T: Config, Client: OfflineClientT<T>> CustomValuesClient<T, Client> {
|
|||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
// 1. Validate custom value shape if hash given:
|
get_custom_value_bytes(&self.client.metadata(), address).map_err(Into::into)
|
||||||
self.validate(address)?;
|
|
||||||
|
|
||||||
// 2. Return the underlying bytes:
|
|
||||||
let metadata = self.client.metadata();
|
|
||||||
let custom = metadata.custom();
|
|
||||||
let custom_value = custom
|
|
||||||
.get(address.name())
|
|
||||||
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().to_string()))?;
|
|
||||||
|
|
||||||
Ok(custom_value.bytes().to_vec())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())`
|
/// Run the validation logic against some custom value address you'd like to access. Returns `Ok(())`
|
||||||
@@ -73,27 +49,12 @@ impl<T: Config, Client: OfflineClientT<T>> CustomValuesClient<T, Client> {
|
|||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let metadata = self.client.metadata();
|
validate_custom_value(&self.client.metadata(), address).map_err(Into::into)
|
||||||
if let Some(actual_hash) = address.validation_hash() {
|
|
||||||
let custom = metadata.custom();
|
|
||||||
let custom_value = custom
|
|
||||||
.get(address.name())
|
|
||||||
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().into()))?;
|
|
||||||
let expected_hash = custom_value.hash();
|
|
||||||
if actual_hash != expected_hash {
|
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if metadata.custom().get(address.name()).is_none() {
|
|
||||||
return Err(MetadataError::IncompatibleCodegen.into());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::backend::RuntimeVersion;
|
|
||||||
use crate::custom_values::CustomValuesClient;
|
use crate::custom_values::CustomValuesClient;
|
||||||
use crate::{Metadata, OfflineClient, SubstrateConfig};
|
use crate::{Metadata, OfflineClient, SubstrateConfig};
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
@@ -101,6 +62,7 @@ mod tests {
|
|||||||
use scale_info::form::PortableForm;
|
use scale_info::form::PortableForm;
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use subxt_core::client::RuntimeVersion;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Encode, TypeInfo, DecodeAsType)]
|
#[derive(Debug, Clone, PartialEq, Eq, Encode, TypeInfo, DecodeAsType)]
|
||||||
pub struct Person {
|
pub struct Person {
|
||||||
@@ -158,10 +120,7 @@ mod tests {
|
|||||||
fn test_decoding() {
|
fn test_decoding() {
|
||||||
let client = OfflineClient::<SubstrateConfig>::new(
|
let client = OfflineClient::<SubstrateConfig>::new(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
RuntimeVersion {
|
RuntimeVersion::new(0, 0),
|
||||||
spec_version: 0,
|
|
||||||
transaction_version: 0,
|
|
||||||
},
|
|
||||||
mock_metadata(),
|
mock_metadata(),
|
||||||
);
|
);
|
||||||
let custom_value_client = CustomValuesClient::new(client);
|
let custom_value_client = CustomValuesClient::new(client);
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
//! Types associated with accessing custom types
|
//! Types associated with accessing custom types
|
||||||
|
|
||||||
mod custom_value_address;
|
|
||||||
mod custom_values_client;
|
mod custom_values_client;
|
||||||
|
|
||||||
pub use custom_value_address::{CustomValueAddress, StaticAddress, Yes};
|
|
||||||
pub use custom_values_client::CustomValuesClient;
|
pub use custom_values_client::CustomValuesClient;
|
||||||
|
pub use subxt_core::custom_values::{CustomValueAddress, StaticAddress};
|
||||||
|
|||||||
+14
-90
@@ -14,13 +14,12 @@ crate::macros::cfg_unstable_light_client! {
|
|||||||
pub use dispatch_error::{
|
pub use dispatch_error::{
|
||||||
ArithmeticError, DispatchError, ModuleError, TokenError, TransactionalError,
|
ArithmeticError, DispatchError, ModuleError, TokenError, TransactionalError,
|
||||||
};
|
};
|
||||||
use subxt_metadata::StorageHasher;
|
|
||||||
|
|
||||||
// Re-expose the errors we use from other crates here:
|
// Re-expose the errors we use from other crates here:
|
||||||
pub use crate::config::ExtrinsicParamsError;
|
|
||||||
pub use crate::metadata::Metadata;
|
pub use crate::metadata::Metadata;
|
||||||
pub use scale_decode::Error as DecodeError;
|
pub use scale_decode::Error as DecodeError;
|
||||||
pub use scale_encode::Error as EncodeError;
|
pub use scale_encode::Error as EncodeError;
|
||||||
|
pub use subxt_core::error::{ExtrinsicParamsError, MetadataError, StorageAddressError};
|
||||||
pub use subxt_metadata::TryFromError as MetadataTryFromError;
|
pub use subxt_metadata::TryFromError as MetadataTryFromError;
|
||||||
|
|
||||||
/// The underlying error enum, generic over the type held by the `Runtime`
|
/// The underlying error enum, generic over the type held by the `Runtime`
|
||||||
@@ -81,6 +80,19 @@ pub enum Error {
|
|||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<subxt_core::Error> for Error {
|
||||||
|
fn from(value: subxt_core::Error) -> Self {
|
||||||
|
match value {
|
||||||
|
subxt_core::Error::Codec(e) => Error::Codec(e),
|
||||||
|
subxt_core::Error::Metadata(e) => Error::Metadata(e),
|
||||||
|
subxt_core::Error::StorageAddress(e) => Error::StorageAddress(e),
|
||||||
|
subxt_core::Error::Decode(e) => Error::Decode(e),
|
||||||
|
subxt_core::Error::Encode(e) => Error::Encode(e),
|
||||||
|
subxt_core::Error::ExtrinsicParams(e) => Error::ExtrinsicParams(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Error {
|
impl<'a> From<&'a str> for Error {
|
||||||
fn from(error: &'a str) -> Self {
|
fn from(error: &'a str) -> Self {
|
||||||
Error::Other(error.into())
|
Error::Other(error.into())
|
||||||
@@ -189,91 +201,3 @@ pub enum TransactionError {
|
|||||||
#[error("The transaction was dropped: {0}")]
|
#[error("The transaction was dropped: {0}")]
|
||||||
Dropped(String),
|
Dropped(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Something went wrong trying to encode a storage address.
|
|
||||||
#[derive(Clone, Debug, thiserror::Error)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum StorageAddressError {
|
|
||||||
/// Storage lookup does not have the expected number of keys.
|
|
||||||
#[error("Storage lookup requires {expected} keys but more keys have been provided.")]
|
|
||||||
TooManyKeys {
|
|
||||||
/// The number of keys provided in the storage address.
|
|
||||||
expected: usize,
|
|
||||||
},
|
|
||||||
/// This storage entry in the metadata does not have the correct number of hashers to fields.
|
|
||||||
#[error("Storage entry in metadata does not have the correct number of hashers to fields")]
|
|
||||||
WrongNumberOfHashers {
|
|
||||||
/// The number of hashers in the metadata for this storage entry.
|
|
||||||
hashers: usize,
|
|
||||||
/// The number of fields in the metadata for this storage entry.
|
|
||||||
fields: usize,
|
|
||||||
},
|
|
||||||
/// We weren't given enough bytes to decode the storage address/key.
|
|
||||||
#[error("Not enough remaining bytes to decode the storage address/key")]
|
|
||||||
NotEnoughBytes,
|
|
||||||
/// We have leftover bytes after decoding the storage address.
|
|
||||||
#[error("We have leftover bytes after decoding the storage address")]
|
|
||||||
TooManyBytes,
|
|
||||||
/// The bytes of a storage address are not the expected address for decoding the storage keys of the address.
|
|
||||||
#[error("Storage address bytes are not the expected format. Addresses need to be at least 16 bytes (pallet ++ entry) and follow a structure given by the hashers defined in the metadata")]
|
|
||||||
UnexpectedAddressBytes,
|
|
||||||
/// An invalid hasher was used to reconstruct a value from a chunk of bytes that is part of a storage address. Hashers where the hash does not contain the original value are invalid for this purpose.
|
|
||||||
#[error("An invalid hasher was used to reconstruct a value with type ID {ty_id} from a hash formed by a {hasher:?} hasher. This is only possible for concat-style hashers or the identity hasher")]
|
|
||||||
HasherCannotReconstructKey {
|
|
||||||
/// Type id of the key's type.
|
|
||||||
ty_id: u32,
|
|
||||||
/// The invalid hasher that caused this error.
|
|
||||||
hasher: StorageHasher,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Something went wrong trying to access details in the metadata.
|
|
||||||
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum MetadataError {
|
|
||||||
/// The DispatchError type isn't available in the metadata
|
|
||||||
#[error("The DispatchError type isn't available")]
|
|
||||||
DispatchErrorNotFound,
|
|
||||||
/// Type not found in metadata.
|
|
||||||
#[error("Type with ID {0} not found")]
|
|
||||||
TypeNotFound(u32),
|
|
||||||
/// Pallet not found (index).
|
|
||||||
#[error("Pallet with index {0} not found")]
|
|
||||||
PalletIndexNotFound(u8),
|
|
||||||
/// Pallet not found (name).
|
|
||||||
#[error("Pallet with name {0} not found")]
|
|
||||||
PalletNameNotFound(String),
|
|
||||||
/// Variant not found.
|
|
||||||
#[error("Variant with index {0} not found")]
|
|
||||||
VariantIndexNotFound(u8),
|
|
||||||
/// Constant not found.
|
|
||||||
#[error("Constant with name {0} not found")]
|
|
||||||
ConstantNameNotFound(String),
|
|
||||||
/// Call not found.
|
|
||||||
#[error("Call with name {0} not found")]
|
|
||||||
CallNameNotFound(String),
|
|
||||||
/// Runtime trait not found.
|
|
||||||
#[error("Runtime trait with name {0} not found")]
|
|
||||||
RuntimeTraitNotFound(String),
|
|
||||||
/// Runtime method not found.
|
|
||||||
#[error("Runtime method with name {0} not found")]
|
|
||||||
RuntimeMethodNotFound(String),
|
|
||||||
/// Call type not found in metadata.
|
|
||||||
#[error("Call type not found in pallet with index {0}")]
|
|
||||||
CallTypeNotFoundInPallet(u8),
|
|
||||||
/// Event type not found in metadata.
|
|
||||||
#[error("Event type not found in pallet with index {0}")]
|
|
||||||
EventTypeNotFoundInPallet(u8),
|
|
||||||
/// Storage details not found in metadata.
|
|
||||||
#[error("Storage details not found in pallet with name {0}")]
|
|
||||||
StorageNotFoundInPallet(String),
|
|
||||||
/// Storage entry not found.
|
|
||||||
#[error("Storage entry {0} not found")]
|
|
||||||
StorageEntryNotFound(String),
|
|
||||||
/// The generated interface used is not compatible with the node.
|
|
||||||
#[error("The generated code is not compatible with the node")]
|
|
||||||
IncompatibleCodegen,
|
|
||||||
/// Custom value not found.
|
|
||||||
#[error("Custom value with name {0} not found")]
|
|
||||||
CustomValueNameNotFound(String),
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
|
|
||||||
use crate::backend::{Backend, BackendExt, BlockRef};
|
use crate::backend::{Backend, BackendExt, BlockRef};
|
||||||
use crate::{client::OnlineClientT, error::Error, events::Events, Config};
|
use crate::{client::OnlineClientT, error::Error, events::Events, Config};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
/// A client for working with events.
|
/// A client for working with events.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct EventsClient<T, Client> {
|
pub struct EventsClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: std::marker::PhantomData<T>,
|
_marker: std::marker::PhantomData<T>,
|
||||||
@@ -65,11 +64,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let event_bytes = get_event_bytes(client.backend(), block_ref.hash()).await?;
|
let event_bytes = get_event_bytes(client.backend(), block_ref.hash()).await?;
|
||||||
Ok(Events::new(
|
Ok(Events::decode_from(client.metadata(), event_bytes))
|
||||||
client.metadata(),
|
|
||||||
block_ref.hash(),
|
|
||||||
event_bytes,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-32
@@ -5,40 +5,24 @@
|
|||||||
//! This module exposes the types and such necessary for working with events.
|
//! This module exposes the types and such necessary for working with events.
|
||||||
//! The two main entry points into events are [`crate::OnlineClient::events()`]
|
//! The two main entry points into events are [`crate::OnlineClient::events()`]
|
||||||
//! and calls like [crate::tx::TxProgress::wait_for_finalized_success()].
|
//! and calls like [crate::tx::TxProgress::wait_for_finalized_success()].
|
||||||
|
use crate::client::OnlineClientT;
|
||||||
|
use crate::Error;
|
||||||
|
use subxt_core::{Config, Metadata};
|
||||||
|
|
||||||
mod events_client;
|
mod events_client;
|
||||||
mod events_type;
|
|
||||||
|
|
||||||
use codec::{Decode, Encode};
|
|
||||||
pub use events_client::EventsClient;
|
pub use events_client::EventsClient;
|
||||||
pub use events_type::{EventDetails, Events};
|
pub use subxt_core::events::{EventDetails, Events, Phase, StaticEvent};
|
||||||
use scale_decode::DecodeAsFields;
|
|
||||||
|
|
||||||
/// Trait to uniquely identify the events's identity from the runtime metadata.
|
/// Creates a new [`Events`] instance by fetching the corresponding bytes at `block_hash` from the client.
|
||||||
///
|
pub async fn new_events_from_client<T, C>(
|
||||||
/// Generated API structures that represent an event implement this trait.
|
metadata: Metadata,
|
||||||
///
|
block_hash: T::Hash,
|
||||||
/// The trait is utilized to decode emitted events from a block, via obtaining the
|
client: C,
|
||||||
/// form of the `Event` from the metadata.
|
) -> Result<Events<T>, Error>
|
||||||
pub trait StaticEvent: DecodeAsFields {
|
where
|
||||||
/// Pallet name.
|
T: Config,
|
||||||
const PALLET: &'static str;
|
C: OnlineClientT<T>,
|
||||||
/// Event name.
|
{
|
||||||
const EVENT: &'static str;
|
let event_bytes = events_client::get_event_bytes(client.backend(), block_hash).await?;
|
||||||
|
Ok(Events::<T>::decode_from(metadata, event_bytes))
|
||||||
/// Returns true if the given pallet and event names match this event.
|
|
||||||
fn is_event(pallet: &str, event: &str) -> bool {
|
|
||||||
Self::PALLET == pallet && Self::EVENT == event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A phase of a block's execution.
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Decode, Encode)]
|
|
||||||
pub enum Phase {
|
|
||||||
/// Applying an extrinsic.
|
|
||||||
ApplyExtrinsic(u32),
|
|
||||||
/// Finalizing the block.
|
|
||||||
Finalization,
|
|
||||||
/// Initializing the block.
|
|
||||||
Initialization,
|
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-9
@@ -45,18 +45,44 @@ pub use getrandom as _;
|
|||||||
pub mod backend;
|
pub mod backend;
|
||||||
pub mod blocks;
|
pub mod blocks;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod config;
|
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod custom_values;
|
pub mod custom_values;
|
||||||
pub mod dynamic;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod metadata;
|
|
||||||
pub mod runtime_api;
|
pub mod runtime_api;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
pub mod tx;
|
pub mod tx;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// This module provides a [`Config`] type, which is used to define various
|
||||||
|
/// types that are important in order to speak to a particular chain.
|
||||||
|
/// [`SubstrateConfig`] provides a default set of these types suitable for the
|
||||||
|
/// default Substrate node implementation, and [`PolkadotConfig`] for a
|
||||||
|
/// Polkadot node.
|
||||||
|
pub mod config {
|
||||||
|
pub use subxt_core::config::{
|
||||||
|
polkadot, signed_extensions, substrate, BlockHash, Config, DefaultExtrinsicParams,
|
||||||
|
DefaultExtrinsicParamsBuilder, ExtrinsicParams, ExtrinsicParamsEncoder, Hasher, Header,
|
||||||
|
PolkadotConfig, PolkadotExtrinsicParams, RefineParams, RefineParamsData, SignedExtension,
|
||||||
|
SubstrateConfig, SubstrateExtrinsicParams,
|
||||||
|
};
|
||||||
|
pub use subxt_core::error::ExtrinsicParamsError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Types representing the metadata obtained from a node.
|
||||||
|
pub mod metadata {
|
||||||
|
pub use subxt_core::metadata::{DecodeWithMetadata, EncodeWithMetadata, Metadata, MetadataExt};
|
||||||
|
// Expose metadata types under a sub module in case somebody needs to reference them:
|
||||||
|
pub use subxt_metadata as types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit dynamic transactions.
|
||||||
|
pub mod dynamic {
|
||||||
|
pub use subxt_core::dynamic::{
|
||||||
|
constant, runtime_api_call, storage, tx, At, DecodedValue, DecodedValueThunk, Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Internal helper macros
|
// Internal helper macros
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
@@ -84,10 +110,10 @@ pub mod ext {
|
|||||||
pub use scale_decode;
|
pub use scale_decode;
|
||||||
pub use scale_encode;
|
pub use scale_encode;
|
||||||
pub use scale_value;
|
pub use scale_value;
|
||||||
|
pub use subxt_core;
|
||||||
|
|
||||||
cfg_substrate_compat! {
|
cfg_substrate_compat! {
|
||||||
pub use sp_runtime;
|
pub use subxt_core::ext::{sp_runtime, sp_core};
|
||||||
pub use sp_core;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,15 +153,15 @@ pub mod ext {
|
|||||||
///
|
///
|
||||||
/// ## `crate = "..."`
|
/// ## `crate = "..."`
|
||||||
///
|
///
|
||||||
/// Use this attribute to specify a custom path to the `subxt` crate:
|
/// Use this attribute to specify a custom path to the `subxt_core` crate:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # pub extern crate subxt;
|
/// # pub extern crate subxt_core;
|
||||||
/// # pub mod path { pub mod to { pub use subxt; } }
|
/// # pub mod path { pub mod to { pub use subxt_core; } }
|
||||||
/// # fn main() {}
|
/// # fn main() {}
|
||||||
/// #[subxt::subxt(
|
/// #[subxt::subxt(
|
||||||
/// runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale",
|
/// runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale",
|
||||||
/// crate = "crate::path::to::subxt"
|
/// crate = "crate::path::to::subxt_core"
|
||||||
/// )]
|
/// )]
|
||||||
/// mod polkadot {}
|
/// mod polkadot {}
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ macro_rules! cfg_jsonrpsee_web {
|
|||||||
macro_rules! cfg_reconnecting_rpc_client {
|
macro_rules! cfg_reconnecting_rpc_client {
|
||||||
($($item:item)*) => {
|
($($item:item)*) => {
|
||||||
$(
|
$(
|
||||||
#[cfg(all(feature = "unstable-reconnecting-rpc-client"))]
|
#[cfg(feature = "unstable-reconnecting-rpc-client")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-reconnecting-rpc-client")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-reconnecting-rpc-client")))]
|
||||||
$item
|
$item
|
||||||
)*
|
)*
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
||||||
// see LICENSE for license details.
|
|
||||||
|
|
||||||
use crate::error::MetadataError;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// A cheaply clone-able representation of the runtime metadata received from a node.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Metadata {
|
|
||||||
inner: Arc<subxt_metadata::Metadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for Metadata {
|
|
||||||
type Target = subxt_metadata::Metadata;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Metadata {
|
|
||||||
pub(crate) fn new(md: subxt_metadata::Metadata) -> Self {
|
|
||||||
Metadata {
|
|
||||||
inner: Arc::new(md),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.pallet_by_name()`, but returns an error if the pallet is not found.
|
|
||||||
pub fn pallet_by_name_err(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
|
||||||
self.pallet_by_name(name)
|
|
||||||
.ok_or_else(|| MetadataError::PalletNameNotFound(name.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.pallet_by_index()`, but returns an error if the pallet is not found.
|
|
||||||
pub fn pallet_by_index_err(
|
|
||||||
&self,
|
|
||||||
index: u8,
|
|
||||||
) -> Result<subxt_metadata::PalletMetadata, MetadataError> {
|
|
||||||
self.pallet_by_index(index)
|
|
||||||
.ok_or(MetadataError::PalletIndexNotFound(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Identical to `metadata.runtime_api_trait_by_name()`, but returns an error if the trait is not found.
|
|
||||||
pub fn runtime_api_trait_by_name_err(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<subxt_metadata::RuntimeApiMetadata, MetadataError> {
|
|
||||||
self.runtime_api_trait_by_name(name)
|
|
||||||
.ok_or_else(|| MetadataError::RuntimeTraitNotFound(name.to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<subxt_metadata::Metadata> for Metadata {
|
|
||||||
fn from(md: subxt_metadata::Metadata) -> Self {
|
|
||||||
Metadata::new(md)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<frame_metadata::RuntimeMetadataPrefixed> for Metadata {
|
|
||||||
type Error = subxt_metadata::TryFromError;
|
|
||||||
fn try_from(value: frame_metadata::RuntimeMetadataPrefixed) -> Result<Self, Self::Error> {
|
|
||||||
subxt_metadata::Metadata::try_from(value).map(Metadata::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl codec::Decode for Metadata {
|
|
||||||
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
|
|
||||||
subxt_metadata::Metadata::decode(input).map(Metadata::new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,8 @@
|
|||||||
//! Types associated with executing runtime API calls.
|
//! Types associated with executing runtime API calls.
|
||||||
|
|
||||||
mod runtime_client;
|
mod runtime_client;
|
||||||
mod runtime_payload;
|
|
||||||
mod runtime_types;
|
mod runtime_types;
|
||||||
|
|
||||||
pub use runtime_client::RuntimeApiClient;
|
pub use runtime_client::RuntimeApiClient;
|
||||||
pub use runtime_payload::{dynamic, DynamicRuntimeApiPayload, Payload, RuntimeApiPayload};
|
|
||||||
pub use runtime_types::RuntimeApi;
|
pub use runtime_types::RuntimeApi;
|
||||||
|
pub use subxt_core::runtime_api::{dynamic, DynamicRuntimeApiPayload, Payload, RuntimeApiPayload};
|
||||||
|
|||||||
@@ -5,12 +5,11 @@
|
|||||||
use super::runtime_types::RuntimeApi;
|
use super::runtime_types::RuntimeApi;
|
||||||
|
|
||||||
use crate::{backend::BlockRef, client::OnlineClientT, error::Error, Config};
|
use crate::{backend::BlockRef, client::OnlineClientT, error::Error, Config};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
/// Execute runtime API calls.
|
/// Execute runtime API calls.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct RuntimeApiClient<T, Client> {
|
pub struct RuntimeApiClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ use crate::{
|
|||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
use super::RuntimeApiPayload;
|
use super::RuntimeApiPayload;
|
||||||
|
|
||||||
/// Execute runtime API calls.
|
/// Execute runtime API calls.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct RuntimeApi<T: Config, Client> {
|
pub struct RuntimeApi<T: Config, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
block_ref: BlockRef<T::Hash>,
|
block_ref: BlockRef<T::Hash>,
|
||||||
|
|||||||
@@ -4,11 +4,8 @@
|
|||||||
|
|
||||||
//! Types associated with accessing and working with storage items.
|
//! Types associated with accessing and working with storage items.
|
||||||
|
|
||||||
mod storage_address;
|
|
||||||
mod storage_client;
|
mod storage_client;
|
||||||
mod storage_key;
|
|
||||||
mod storage_type;
|
mod storage_type;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
pub use storage_client::StorageClient;
|
pub use storage_client::StorageClient;
|
||||||
|
|
||||||
@@ -17,12 +14,13 @@ pub use storage_type::{Storage, StorageKeyValuePair};
|
|||||||
/// Types representing an address which describes where a storage
|
/// Types representing an address which describes where a storage
|
||||||
/// entry lives and how to properly decode it.
|
/// entry lives and how to properly decode it.
|
||||||
pub mod address {
|
pub mod address {
|
||||||
pub use super::storage_address::{dynamic, Address, DynamicAddress, StorageAddress, Yes};
|
pub use subxt_core::storage::address::{
|
||||||
pub use super::storage_key::{StaticStorageKey, StorageKey};
|
dynamic, Address, DynamicAddress, StaticStorageKey, StorageAddress, StorageKey,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use storage_key::StorageKey;
|
pub use subxt_core::storage::StorageKey;
|
||||||
|
|
||||||
// For consistency with other modules, also expose
|
// For consistency with other modules, also expose
|
||||||
// the basic address stuff at the root of the module.
|
// the basic address stuff at the root of the module.
|
||||||
pub use storage_address::{dynamic, Address, DynamicAddress, StorageAddress};
|
pub use address::{dynamic, Address, DynamicAddress, StorageAddress};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
storage_type::{validate_storage_address, Storage},
|
storage_type::{validate_storage_address, Storage},
|
||||||
utils, StorageAddress,
|
StorageAddress,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::BlockRef,
|
backend::BlockRef,
|
||||||
@@ -12,12 +12,11 @@ use crate::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
/// Query the runtime storage.
|
/// Query the runtime storage.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct StorageClient<T, Client> {
|
pub struct StorageClient<T, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
@@ -51,7 +50,7 @@ where
|
|||||||
/// Convert some storage address into the raw bytes that would be submitted to the node in order
|
/// Convert some storage address into the raw bytes that would be submitted to the node in order
|
||||||
/// to retrieve the entries at the root of the associated address.
|
/// to retrieve the entries at the root of the associated address.
|
||||||
pub fn address_root_bytes<Address: StorageAddress>(&self, address: &Address) -> Vec<u8> {
|
pub fn address_root_bytes<Address: StorageAddress>(&self, address: &Address) -> Vec<u8> {
|
||||||
utils::storage_address_root_bytes(address)
|
subxt_core::storage::utils::storage_address_root_bytes(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert some storage address into the raw bytes that would be submitted to the node in order
|
/// Convert some storage address into the raw bytes that would be submitted to the node in order
|
||||||
@@ -63,7 +62,8 @@ where
|
|||||||
&self,
|
&self,
|
||||||
address: &Address,
|
address: &Address,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
utils::storage_address_bytes(address, &self.client.metadata())
|
subxt_core::storage::utils::storage_address_bytes(address, &self.client.metadata())
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||||
// see LICENSE for license details.
|
// see LICENSE for license details.
|
||||||
|
|
||||||
use super::storage_address::{StorageAddress, Yes};
|
use subxt_core::storage::address::{StorageAddress, StorageHashers, StorageKey};
|
||||||
use super::storage_key::StorageHashers;
|
use subxt_core::utils::Yes;
|
||||||
use super::StorageKey;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{BackendExt, BlockRef},
|
backend::{BackendExt, BlockRef},
|
||||||
@@ -14,7 +13,7 @@ use crate::{
|
|||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
use codec::Decode;
|
use codec::Decode;
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
use std::{future::Future, marker::PhantomData};
|
use std::{future::Future, marker::PhantomData};
|
||||||
@@ -25,8 +24,7 @@ use subxt_metadata::{PalletMetadata, StorageEntryMetadata, StorageEntryType};
|
|||||||
pub use crate::backend::StreamOfResults;
|
pub use crate::backend::StreamOfResults;
|
||||||
|
|
||||||
/// Query the runtime storage.
|
/// Query the runtime storage.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct Storage<T: Config, Client> {
|
pub struct Storage<T: Config, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
block_ref: BlockRef<T::Hash>,
|
block_ref: BlockRef<T::Hash>,
|
||||||
@@ -136,7 +134,8 @@ where
|
|||||||
validate_storage_address(address, pallet)?;
|
validate_storage_address(address, pallet)?;
|
||||||
|
|
||||||
// Look up the return type ID to enable DecodeWithMetadata:
|
// Look up the return type ID to enable DecodeWithMetadata:
|
||||||
let lookup_bytes = super::utils::storage_address_bytes(address, &metadata)?;
|
let lookup_bytes =
|
||||||
|
subxt_core::storage::utils::storage_address_bytes(address, &metadata)?;
|
||||||
if let Some(data) = client.fetch_raw(lookup_bytes).await? {
|
if let Some(data) = client.fetch_raw(lookup_bytes).await? {
|
||||||
let val =
|
let val =
|
||||||
decode_storage_with_metadata::<Address::Target>(&mut &*data, &metadata, entry)?;
|
decode_storage_with_metadata::<Address::Target>(&mut &*data, &metadata, entry)?;
|
||||||
@@ -237,7 +236,8 @@ where
|
|||||||
let hashers = StorageHashers::new(entry, metadata.types())?;
|
let hashers = StorageHashers::new(entry, metadata.types())?;
|
||||||
|
|
||||||
// The address bytes of this entry:
|
// The address bytes of this entry:
|
||||||
let address_bytes = super::utils::storage_address_bytes(&address, &metadata)?;
|
let address_bytes =
|
||||||
|
subxt_core::storage::utils::storage_address_bytes(&address, &metadata)?;
|
||||||
let s = client
|
let s = client
|
||||||
.backend()
|
.backend()
|
||||||
.storage_fetch_descendant_values(address_bytes, block_ref.hash())
|
.storage_fetch_descendant_values(address_bytes, block_ref.hash())
|
||||||
|
|||||||
+4
-3
@@ -11,15 +11,16 @@
|
|||||||
|
|
||||||
use crate::macros::cfg_substrate_compat;
|
use crate::macros::cfg_substrate_compat;
|
||||||
|
|
||||||
mod signer;
|
|
||||||
mod tx_client;
|
mod tx_client;
|
||||||
mod tx_payload;
|
|
||||||
mod tx_progress;
|
mod tx_progress;
|
||||||
|
|
||||||
|
pub use subxt_core::tx as tx_payload;
|
||||||
|
pub use subxt_core::tx::signer;
|
||||||
|
|
||||||
// The PairSigner impl currently relies on Substrate bits and pieces, so make it an optional
|
// The PairSigner impl currently relies on Substrate bits and pieces, so make it an optional
|
||||||
// feature if we want to avoid needing sp_core and sp_runtime.
|
// feature if we want to avoid needing sp_core and sp_runtime.
|
||||||
cfg_substrate_compat! {
|
cfg_substrate_compat! {
|
||||||
pub use self::signer::PairSigner;
|
pub use signer::PairSigner;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
|||||||
@@ -16,12 +16,11 @@ use crate::{
|
|||||||
utils::{Encoded, PhantomDataSendSync},
|
utils::{Encoded, PhantomDataSendSync},
|
||||||
};
|
};
|
||||||
use codec::{Compact, Decode, Encode};
|
use codec::{Compact, Decode, Encode};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use sp_crypto_hashing::blake2_256;
|
use sp_crypto_hashing::blake2_256;
|
||||||
|
|
||||||
/// A client for working with transactions.
|
/// A client for working with transactions.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Clone; Client)]
|
||||||
#[derivative(Clone(bound = "Client: Clone"))]
|
|
||||||
pub struct TxClient<T: Config, Client> {
|
pub struct TxClient<T: Config, Client> {
|
||||||
client: Client,
|
client: Client,
|
||||||
_marker: PhantomDataSendSync<T>,
|
_marker: PhantomDataSendSync<T>,
|
||||||
@@ -126,7 +125,7 @@ impl<T: Config, C: OfflineClientT<T>> TxClient<T, C> {
|
|||||||
|
|
||||||
// 3. Construct our custom additional/extra params.
|
// 3. Construct our custom additional/extra params.
|
||||||
let additional_and_extra_params =
|
let additional_and_extra_params =
|
||||||
<T::ExtrinsicParams as ExtrinsicParams<T>>::new(self.client.clone(), params)?;
|
<T::ExtrinsicParams as ExtrinsicParams<T>>::new(&self.client.client_state(), params)?;
|
||||||
|
|
||||||
// Return these details, ready to construct a signed extrinsic from.
|
// Return these details, ready to construct a signed extrinsic from.
|
||||||
Ok(PartialExtrinsic {
|
Ok(PartialExtrinsic {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
use crate::utils::strip_compact_prefix;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{BlockRef, StreamOfResults, TransactionStatus as BackendTxStatus},
|
backend::{BlockRef, StreamOfResults, TransactionStatus as BackendTxStatus},
|
||||||
client::OnlineClientT,
|
client::OnlineClientT,
|
||||||
@@ -14,8 +13,9 @@ use crate::{
|
|||||||
events::EventsClient,
|
events::EventsClient,
|
||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derive_where::derive_where;
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
|
use subxt_core::utils::strip_compact_prefix;
|
||||||
|
|
||||||
/// This struct represents a subscription to the progress of some transaction.
|
/// This struct represents a subscription to the progress of some transaction.
|
||||||
pub struct TxProgress<T: Config, C> {
|
pub struct TxProgress<T: Config, C> {
|
||||||
@@ -167,8 +167,7 @@ impl<T: Config, C: Clone> Stream for TxProgress<T, C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Possible transaction statuses returned from our [`TxProgress::next()`] call.
|
/// Possible transaction statuses returned from our [`TxProgress::next()`] call.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Debug; C)]
|
||||||
#[derivative(Debug(bound = "C: std::fmt::Debug"))]
|
|
||||||
pub enum TxStatus<T: Config, C> {
|
pub enum TxStatus<T: Config, C> {
|
||||||
/// Transaction is part of the future queue.
|
/// Transaction is part of the future queue.
|
||||||
Validated,
|
Validated,
|
||||||
@@ -221,8 +220,7 @@ impl<T: Config, C> TxStatus<T, C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This struct represents a transaction that has made it into a block.
|
/// This struct represents a transaction that has made it into a block.
|
||||||
#[derive(Derivative)]
|
#[derive_where(Debug; C)]
|
||||||
#[derivative(Debug(bound = "C: std::fmt::Debug"))]
|
|
||||||
pub struct TxInBlock<T: Config, C> {
|
pub struct TxInBlock<T: Config, C> {
|
||||||
block_ref: BlockRef<T::Hash>,
|
block_ref: BlockRef<T::Hash>,
|
||||||
ext_hash: T::Hash,
|
ext_hash: T::Hash,
|
||||||
@@ -321,6 +319,8 @@ impl<T: Config, C: OnlineClientT<T>> TxInBlock<T, C> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use subxt_core::client::RuntimeVersion;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{StreamOfResults, TransactionStatus},
|
backend::{StreamOfResults, TransactionStatus},
|
||||||
client::{OfflineClientT, OnlineClientT},
|
client::{OfflineClientT, OnlineClientT},
|
||||||
@@ -345,7 +345,11 @@ mod test {
|
|||||||
unimplemented!("just a mock impl to satisfy trait bounds")
|
unimplemented!("just a mock impl to satisfy trait bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime_version(&self) -> crate::backend::RuntimeVersion {
|
fn runtime_version(&self) -> RuntimeVersion {
|
||||||
|
unimplemented!("just a mock impl to satisfy trait bounds")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_state(&self) -> subxt_core::client::ClientState<SubstrateConfig> {
|
||||||
unimplemented!("just a mock impl to satisfy trait bounds")
|
unimplemented!("just a mock impl to satisfy trait bounds")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-73
@@ -4,58 +4,21 @@
|
|||||||
|
|
||||||
//! Miscellaneous utility helpers.
|
//! Miscellaneous utility helpers.
|
||||||
|
|
||||||
mod account_id;
|
|
||||||
pub mod bits;
|
|
||||||
mod era;
|
|
||||||
mod multi_address;
|
|
||||||
mod multi_signature;
|
|
||||||
mod static_type;
|
|
||||||
mod unchecked_extrinsic;
|
|
||||||
mod wrapper_opaque;
|
|
||||||
|
|
||||||
use crate::error::RpcError;
|
|
||||||
use crate::macros::cfg_jsonrpsee;
|
use crate::macros::cfg_jsonrpsee;
|
||||||
use crate::Error;
|
use crate::{error::RpcError, Error};
|
||||||
use codec::{Compact, Decode, Encode};
|
|
||||||
use derivative::Derivative;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub use account_id::AccountId32;
|
pub use subxt_core::utils::{
|
||||||
pub use era::Era;
|
bits, strip_compact_prefix, to_hex, AccountId32, Encoded, Era, KeyedVec, MultiAddress,
|
||||||
pub use multi_address::MultiAddress;
|
MultiSignature, PhantomDataSendSync, Static, UncheckedExtrinsic, WrapperKeepOpaque, Yes, H160,
|
||||||
pub use multi_signature::MultiSignature;
|
H256, H512,
|
||||||
pub use static_type::Static;
|
};
|
||||||
pub use unchecked_extrinsic::UncheckedExtrinsic;
|
|
||||||
pub use wrapper_opaque::WrapperKeepOpaque;
|
|
||||||
|
|
||||||
cfg_jsonrpsee! {
|
cfg_jsonrpsee! {
|
||||||
mod fetch_chain_spec;
|
mod fetch_chain_spec;
|
||||||
pub use fetch_chain_spec::{fetch_chainspec_from_rpc_node, FetchChainspecError};
|
pub use fetch_chain_spec::{fetch_chainspec_from_rpc_node, FetchChainspecError};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in codegen
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub use primitive_types::{H160, H256, H512};
|
|
||||||
|
|
||||||
/// Wraps an already encoded byte vector, prevents being encoded as a raw byte vector as part of
|
|
||||||
/// the transaction payload
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub struct Encoded(pub Vec<u8>);
|
|
||||||
|
|
||||||
impl codec::Encode for Encoded {
|
|
||||||
fn encode(&self) -> Vec<u8> {
|
|
||||||
self.0.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decodes a compact encoded value from the beginning of the provided bytes,
|
|
||||||
/// returning the value and any remaining bytes.
|
|
||||||
pub(crate) fn strip_compact_prefix(bytes: &[u8]) -> Result<(u64, &[u8]), codec::Error> {
|
|
||||||
let cursor = &mut &*bytes;
|
|
||||||
let val = <Compact<u64>>::decode(cursor)?;
|
|
||||||
Ok((val.0, *cursor))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A URL is considered secure if it uses a secure scheme ("https" or "wss") or is referring to localhost.
|
/// A URL is considered secure if it uses a secure scheme ("https" or "wss") or is referring to localhost.
|
||||||
///
|
///
|
||||||
/// Returns an error if the the string could not be parsed into a URL.
|
/// Returns an error if the the string could not be parsed into a URL.
|
||||||
@@ -80,33 +43,3 @@ pub fn validate_url_is_secure(url: &str) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A version of [`std::marker::PhantomData`] that is also Send and Sync (which is fine
|
|
||||||
/// because regardless of the generic param, it is always possible to Send + Sync this
|
|
||||||
/// 0 size type).
|
|
||||||
#[derive(Derivative, Encode, Decode, scale_info::TypeInfo)]
|
|
||||||
#[derivative(
|
|
||||||
Clone(bound = ""),
|
|
||||||
PartialEq(bound = ""),
|
|
||||||
Debug(bound = ""),
|
|
||||||
Eq(bound = ""),
|
|
||||||
Default(bound = ""),
|
|
||||||
Hash(bound = "")
|
|
||||||
)]
|
|
||||||
#[scale_info(skip_type_params(T))]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct PhantomDataSendSync<T>(core::marker::PhantomData<T>);
|
|
||||||
|
|
||||||
impl<T> PhantomDataSendSync<T> {
|
|
||||||
pub(crate) fn new() -> Self {
|
|
||||||
Self(core::marker::PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T> Send for PhantomDataSendSync<T> {}
|
|
||||||
unsafe impl<T> Sync for PhantomDataSendSync<T> {}
|
|
||||||
|
|
||||||
/// This represents a key-value collection and is SCALE compatible
|
|
||||||
/// with collections like BTreeMap. This has the same type params
|
|
||||||
/// as `BTreeMap` which allows us to easily swap the two during codegen.
|
|
||||||
pub type KeyedVec<K, V> = Vec<(K, V)>;
|
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ async fn chainhead_unstable_follow() {
|
|||||||
FollowEvent::Initialized(init) => {
|
FollowEvent::Initialized(init) => {
|
||||||
assert_eq!(init.finalized_block_hashes, vec![finalized_block_hash]);
|
assert_eq!(init.finalized_block_hashes, vec![finalized_block_hash]);
|
||||||
if let Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec })) = init.finalized_block_runtime {
|
if let Some(RuntimeEvent::Valid(RuntimeVersionEvent { spec })) = init.finalized_block_runtime {
|
||||||
assert_eq!(spec.spec_version, runtime_version.spec_version);
|
assert_eq!(spec.spec_version, runtime_version.spec_version());
|
||||||
assert_eq!(spec.transaction_version, runtime_version.transaction_version);
|
assert_eq!(spec.transaction_version, runtime_version.transaction_version());
|
||||||
} else {
|
} else {
|
||||||
panic!("runtime details not provided with init event, got {:?}", init.finalized_block_runtime);
|
panic!("runtime details not provided with init event, got {:?}", init.finalized_block_runtime);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user