Add proper test Custom values (#1147)

* add proper tests for custom values

* remove try operators

* use sustrate compat for import of hash

* add license and hex

* add script to artifacts.sh

* custom values with ids not in metadata can be accessed in static interface

* fmt and clippy

* access bytes of custom values directly, even if type id wrong

* final fixes

* removing substrate-compat flag from ui tests

* Update subxt/src/custom_values/custom_values_client.rs

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

* remove types access in type generator

* 2 extra lines

---------

Co-authored-by: James Wilson <james@jsdw.me>
This commit is contained in:
Tadeo Hepperle
2023-09-12 15:46:12 +02:00
committed by GitHub
parent 022d709d02
commit c8462defab
22 changed files with 208 additions and 44 deletions
@@ -0,0 +1,18 @@
[package]
name = "generate-custom-metadata"
authors.workspace = true
edition.workspace = true
version.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
documentation.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
subxt = { workspace = true, features = ["native"] }
scale-info = { workspace = true, features = ["bit-vec"] }
frame-metadata = { workspace = true }
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "bit-vec"] }
@@ -0,0 +1,5 @@
# generate-custom-metadata
A small crate with a binary that creates scale encoded metadata with custom values and writes it to stdout (as raw bytes).
It also provides dispatch error types that are used in `../ui_tests`.
@@ -5,11 +5,14 @@
use codec::Encode;
use frame_metadata::v15::{CustomMetadata, ExtrinsicMetadata, OuterEnums, RuntimeMetadataV15};
use frame_metadata::RuntimeMetadataPrefixed;
use scale_info::form::PortableForm;
use scale_info::TypeInfo;
use scale_info::{meta_type, IntoPortable};
use std::collections::BTreeMap;
pub mod dispatch_error;
/// Generate metadata which contains a `Foo { a: u8, b: &str }` custom value.
pub fn metadata_custom_values_foo() -> RuntimeMetadataPrefixed {
let mut registry = scale_info::Registry::new();
@@ -23,7 +26,10 @@ pub fn metadata_custom_values_foo() -> RuntimeMetadataPrefixed {
}
let foo_value_metadata: frame_metadata::v15::CustomValueMetadata<PortableForm> = {
let value = Foo { a: 0, b: "Hello" };
let value = Foo {
a: 42,
b: "Have a great day!",
};
let foo_ty = scale_info::MetaType::new::<Foo>();
let foo_ty_id = registry.register_type(&foo_ty);
frame_metadata::v15::CustomValueMetadata {
@@ -32,6 +38,13 @@ pub fn metadata_custom_values_foo() -> RuntimeMetadataPrefixed {
}
};
let invalid_type_id_metadata: frame_metadata::v15::CustomValueMetadata<PortableForm> = {
frame_metadata::v15::CustomValueMetadata {
ty: u32::MAX.into(),
value: vec![0, 1, 2, 3],
}
};
// We don't care about the extrinsic type.
let extrinsic = ExtrinsicMetadata {
version: 0,
@@ -48,7 +61,7 @@ pub fn metadata_custom_values_foo() -> RuntimeMetadataPrefixed {
let unit_ty = registry.register_type(&meta_type::<()>());
// Metadata needs to contain this DispatchError, since codegen looks for it.
registry.register_type(&meta_type::<crate::utils::dispatch_error::ArrayDispatchError>());
registry.register_type(&meta_type::<dispatch_error::ArrayDispatchError>());
let metadata = RuntimeMetadataV15 {
types: registry.into(),
@@ -68,6 +81,7 @@ pub fn metadata_custom_values_foo() -> RuntimeMetadataPrefixed {
("foo".into(), foo_value_metadata.clone()),
("12".into(), foo_value_metadata.clone()),
("&Hello".into(), foo_value_metadata),
("InvalidTypeId".into(), invalid_type_id_metadata),
]),
},
};
@@ -0,0 +1,17 @@
// 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 codec::Encode;
use std::io::{self, Write};
/// Creates some scale encoded metadata with custom values and writes it out to stdout (as raw bytes)
///
/// Can be called from the root of the project with: `cargo run --bin generate-custom-metadata > output.scale`.
fn main() -> io::Result<()> {
let metadata_prefixed = generate_custom_metadata::metadata_custom_values_foo();
let stdout = io::stdout();
let mut handle = stdout.lock();
handle.write_all(&metadata_prefixed.encode())?;
Ok(())
}
+7 -2
View File
@@ -10,8 +10,13 @@ publish = false
[dev-dependencies]
trybuild = { workspace = true }
hex = { workspace = true }
scale-info = { workspace = true, features = ["bit-vec"] }
frame-metadata ={ workspace = true }
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "bit-vec"] }
frame-metadata = { workspace = true }
codec = { package = "parity-scale-codec", workspace = true, features = [
"derive",
"bit-vec",
] }
subxt = { workspace = true, features = ["native", "jsonrpsee"] }
subxt-metadata = { workspace = true }
generate-custom-metadata = { path = "../generate-custom-metadata" }
@@ -0,0 +1,47 @@
use codec::{Decode};
use subxt::{config::substrate::H256, OfflineClient, PolkadotConfig};
use subxt_metadata::Metadata;
#[subxt::subxt(runtime_metadata_path = "../../../../artifacts/metadata_with_custom_values.scale", derive_for_all_types = "Eq, PartialEq")]
pub mod node {}
use node::runtime_types::generate_custom_metadata::Foo;
fn main() {
let api = construct_offline_client();
let expected_foo = Foo {
a: 42,
b: "Have a great day!".into(),
};
// static query:
let foo_address = node::custom().foo();
let foo = api.custom_values().at(&foo_address).unwrap();
assert_eq!(foo, expected_foo);
// dynamic query:
let foo_value = api.custom_values().at("Foo").unwrap();
let foo: Foo = foo_value.as_type().unwrap();
assert_eq!(foo, expected_foo);
// static query for some custom value that has an invalid type id: (we can still access the bytes)
let custom_bytes = api.custom_values().bytes_at("InvalidTypeId").unwrap();
assert_eq!(vec![0,1,2,3], custom_bytes);
}
fn construct_offline_client() -> OfflineClient<PolkadotConfig> {
let genesis_hash = {
let h = "91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3";
let bytes = hex::decode(h).unwrap();
H256::from_slice(&bytes)
};
let runtime_version = subxt::backend::RuntimeVersion {
spec_version: 9370,
transaction_version: 20,
};
let metadata = {
let bytes = std::fs::read("../../../../artifacts/metadata_with_custom_values.scale").unwrap();
Metadata::decode(&mut &*bytes).unwrap()
};
OfflineClient::<PolkadotConfig>::new(genesis_hash, runtime_version, metadata)
}
+5 -3
View File
@@ -2,10 +2,12 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::utils::{
dispatch_error::{ArrayDispatchError, LegacyDispatchError, NamedFieldDispatchError},
generate_metadata_from_pallets_custom_dispatch_error,
use crate::utils::generate_metadata_from_pallets_custom_dispatch_error;
use generate_custom_metadata::dispatch_error::{
ArrayDispatchError, LegacyDispatchError, NamedFieldDispatchError,
};
use frame_metadata::RuntimeMetadataPrefixed;
pub fn metadata_array_dispatch_error() -> RuntimeMetadataPrefixed {
+1 -8
View File
@@ -11,7 +11,6 @@
//! Use with `TRYBUILD=overwrite` after updating codebase (see `trybuild` docs for more details on that)
//! to automatically regenerate `stderr` files, but don't forget to check that new files make sense.
mod custom_values;
mod dispatch_errors;
mod storage;
mod utils;
@@ -21,13 +20,13 @@ use crate::utils::MetadataTestRunner;
// Each of these tests leads to some rust code being compiled and
// executed to test that compilation is successful (or errors in the
// way that we'd expect).
#[test]
fn ui_tests() {
let mut m = MetadataTestRunner::default();
let t = trybuild::TestCases::new();
t.pass("src/correct/*.rs");
// Check that storage maps with no keys are handled properly.
t.pass(
m.new_test_case()
@@ -52,12 +51,6 @@ fn ui_tests() {
.build(dispatch_errors::metadata_array_dispatch_error()),
);
t.pass(
m.new_test_case()
.name("custom_values_foo")
.build(custom_values::metadata_custom_values_foo()),
);
// Test retaining only specific pallets and ensure that works.
for pallet in ["Babe", "Claims", "Grandpa", "Balances"] {
let mut metadata = MetadataTestRunner::load_metadata();
+2 -4
View File
@@ -2,7 +2,6 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
pub mod dispatch_error;
mod metadata_test_runner;
use frame_metadata::{
@@ -12,6 +11,7 @@ use frame_metadata::{
},
RuntimeMetadataPrefixed,
};
use generate_custom_metadata::dispatch_error::ArrayDispatchError;
use scale_info::{meta_type, IntoPortable, TypeInfo};
pub use metadata_test_runner::MetadataTestRunner;
@@ -78,9 +78,7 @@ pub fn generate_metadata_from_pallets_custom_dispatch_error<DispatchError: TypeI
/// We default to a useless extrinsic type, and register a fake `DispatchError`
/// type so that codegen is happy with the metadata generated.
pub fn generate_metadata_from_pallets(pallets: Vec<PalletMetadata>) -> RuntimeMetadataPrefixed {
generate_metadata_from_pallets_custom_dispatch_error::<dispatch_error::ArrayDispatchError>(
pallets,
)
generate_metadata_from_pallets_custom_dispatch_error::<ArrayDispatchError>(pallets)
}
/// Given some storage entries, generate a [`RuntimeMetadataPrefixed`] struct.