-
Notifications
You must be signed in to change notification settings - Fork 257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add proper test Custom values #1147
Add proper test Custom values #1147
Conversation
@@ -1,15 +1,14 @@ | |||
// Copyright 2019-2023 Parity Technologies (UK) Ltd. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think we could keep the copyright here (everywhere else)
fn main() { | ||
let metadata_prefixed = generate_custom_metadata::metadata_custom_values_foo(); | ||
let bytes = metadata_prefixed.encode(); | ||
std::fs::write("./artifacts/metadata_with_custom_values.scale", bytes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a call to this to /scripts/artifacts.sh
(ie cargo run --bin generate-custom-metadata > artifacts/metadata_with_custom_values.scale
), so that running that script updates all of our artifacts :)
(also, let's either allow the caller to decide where to write the file to, or just write the file to stdout, so that the file location can be specified in artifacts.sh
so it's clear from that script what is being generated)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, that is a great idea!
@@ -48,7 +54,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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below, we add some CustomMetadata
with a valid Foo value inside it (sorry; I can't comment on the exact line).
Could we also add a custom value with a random type ID that isn't in use (eg u32::MAX
); people might opt to do this too and we want to be sure that we can still access the bytes and that nothing will panic (just Err) if we try decoding them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case we just test if the bytes are returned from the dynamic interface right? E.g. we do not generate any static custom value address. Or should we generate a static address that has a return type of Vec<u8>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we've decided that you can't call .at()
on a value with an invalid type ID, perhaps we can test that such an attempt fails with a compile error (via trybuild), but that .at_bytes()
works, sicne that's what we've decided to allow.
Looks good; just a couple of small comments! I'm not super keen on the dispatch error types being exported from the new generate-custom-values crate (it's a bit of a random place for them), but I'm not too bothered for now (I think ultimately a |
codegen/src/types/mod.rs
Outdated
pub fn types(&self) -> &PortableRegistry { | ||
self.type_registry | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Instead of exposing this in this TypeGenerator, let's just pass the PortableRegistry
into the function instead (it's accessible as something like self.metadata.types()
in the parent function). Not a big deal though!
metadata/src/utils/validation.rs
Outdated
&hash(custom_value.bytes()), | ||
) | ||
let name_hash = hash(custom_value.name.as_bytes()); | ||
let bytes_hash =hash(custom_value.bytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let bytes_hash =hash(custom_value.bytes()); | |
let bytes_hash = hash(custom_value.bytes()); |
metadata/src/utils/validation.rs
Outdated
&hash(custom_value.bytes()), | ||
) | ||
let name_hash = hash(custom_value.name.as_bytes()); | ||
let bytes_hash =hash(custom_value.bytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal of this validation stuff is to make sure that the code generated from some metadata is still compatible with some node (and the node metadata) so that it can still be used without issue.
With that in mind, we don't actually need to check that custom_value.bytes()
is identical; it doesn't matter if the bytes are different so long as they still decode OK into the generated type that the codegen is expecting. So let's remove the hashing of bytes. Otherwise looks good offhand (though this stuff always needs some thought and I obv missed this last time :))
@@ -10,6 +10,9 @@ use crate::metadata::DecodeWithMetadata; | |||
pub trait CustomValueAddress { | |||
/// The type of the custom value. | |||
type Target: DecodeWithMetadata; | |||
/// Should be set to `Yes` for Dynamic values and static values that have a valid type. | |||
/// Should be `()` for custom values, that have an invalid type id. | |||
type Decodable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! For consistency with storage, how about IsDecodable
?
@@ -26,7 +26,7 @@ impl<T, Client> CustomValuesClient<T, Client> { | |||
impl<T: Config, Client: OfflineClientT<T>> CustomValuesClient<T, Client> { | |||
/// 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 at<Address: CustomValueAddress + ?Sized>( | |||
pub fn at<Address: CustomValueAddress<Decodable =Yes> + ?Sized>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn at<Address: CustomValueAddress<Decodable =Yes> + ?Sized>( | |
pub fn at<Address: CustomValueAddress<Decodable = Yes> + ?Sized>( |
.ok_or_else(|| MetadataError::CustomValueNameNotFound(address.name().to_string()))?; | ||
|
||
Ok(custom_value.bytes().to_vec()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Shame about needing to to_vec()
, but I can see it's because the metadata is cloned and not referenced; maybe something we can address elsewhere at some point :)
testing/ui-tests/Cargo.toml
Outdated
scale-info = { workspace = true, features = ["bit-vec"] } | ||
frame-metadata ={ workspace = true } | ||
codec = { package = "parity-scale-codec", workspace = true, features = ["derive", "bit-vec"] } | ||
subxt = { workspace = true, features = ["native", "jsonrpsee"] } | ||
subxt = { workspace = true, features = ["native", "jsonrpsee", "substrate-compat"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is substrate-compat
needed? Offhand I can't see any use for it but I'm likely to be missing something :)
Looking good, and I like the new I left a few comments which are mostly just little things, but with these small bits looked at I'd be happy to see this merge:
|
You are right, it is not necessary, I changed an import to |
Co-authored-by: James Wilson <james@jsdw.me>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look great to me; nice one!
scripts/artifacts.sh
Outdated
cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets "" > artifacts/polkadot_metadata_tiny.scale | ||
# generate a metadata file that only contains some custom metadata | ||
cargo run --bin generate-custom-metadata > artifacts/metadata_with_custom_values.scale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Could use an extra line at the end of the script
testing/ui-tests/Cargo.toml
Outdated
scale-info = { workspace = true, features = ["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" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: extra line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Nice one!
cargo run --bin subxt metadata --file artifacts/polkadot_metadata_full.scale --pallets "" > artifacts/polkadot_metadata_tiny.scale | ||
# generate a metadata file that only contains some custom metadata | ||
cargo run --bin generate-custom-metadata > artifacts/metadata_with_custom_values.scale |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not related to this PR, just to not forget about it, would be a good practice to exit on failures:
set -e
such we don't move forward if some prior step fails
fixes #1134.
I added a test that uses some generated metadata to get custom values via an
OfflineClient
: