Skip to content
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

[fix] #1801: fix schema generation for HashOf, SignatureOf #1804

Merged
merged 1 commit into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions crypto/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::{
};

use derive_more::{Deref, DerefMut, Display};
use iroha_schema::IntoSchema;
use iroha_schema::prelude::*;
use parity_scale_codec::{Decode, Encode};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
Expand Down Expand Up @@ -157,8 +157,20 @@ impl<T: Encode> HashOf<T> {
}

impl<T> IntoSchema for HashOf<T> {
fn schema(metamap: &mut iroha_schema::MetaMap) {
Hash::schema(metamap)
fn schema(map: &mut MetaMap) {
let type_name = Self::type_name();

Hash::schema(map);
if !map.contains_key(&type_name) {
// Field was just inserted above
#[allow(clippy::expect_used)]
let wrapped_type_metadata = map
.get(&Hash::type_name())
.expect("Wrapped type metadata should have been present in the schemas")
.clone();

map.insert(type_name, wrapped_type_metadata);
}
}
}

Expand Down
18 changes: 15 additions & 3 deletions crypto/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::{fmt, marker::PhantomData};
use std::collections::{btree_map, btree_set};

use derive_more::{Deref, DerefMut};
use iroha_schema::IntoSchema;
use iroha_schema::prelude::*;
use parity_scale_codec::{Decode, Encode};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
Expand Down Expand Up @@ -150,8 +150,20 @@ impl<T> Ord for SignatureOf<T> {
}

impl<T> IntoSchema for SignatureOf<T> {
fn schema(metamap: &mut iroha_schema::MetaMap) {
Signature::schema(metamap)
fn schema(map: &mut MetaMap) {
let type_name = Self::type_name();

Signature::schema(map);
if !map.contains_key(&type_name) {
// Field was just inserted above
#[allow(clippy::expect_used)]
let wrapped_type_metadata = map
.get(&Signature::type_name())
.expect("Wrapped type metadata should have been present in the schemas")
.clone();

map.insert(type_name, wrapped_type_metadata);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions data_model/src/expression.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Expressions to use inside of ISIs.

#![allow(
// Because of `serde(skip)`
// Because of `codec(skip)`
clippy::default_trait_access,
// Because of length on instructions and expressions (can't be 0)
clippy::len_without_is_empty,
Expand Down Expand Up @@ -33,11 +33,11 @@ pub type ExpressionBox = Box<Expression>;

/// Struct for type checking and converting expression results.
#[derive(Debug, Clone, Encode, Decode, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(transparent)]
pub struct EvaluatesTo<V: TryFrom<Value>> {
/// Expression.
#[serde(flatten)]
pub expression: ExpressionBox,
#[serde(skip)]
#[codec(skip)]
_value_type: PhantomData<V>,
}
Expand Down
7 changes: 0 additions & 7 deletions data_model/src/isi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,6 @@ pub struct RemoveKeyValueBox {
pub key: EvaluatesTo<Name>,
}

/// Sized structure for all possible Sets.
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, IntoSchema)]
pub struct SetBox {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two uses total. Here and in Schema. I would ask the library developers if they use it. If they don't I'd get rid of it.

/// Object to set as a value.
pub object: EvaluatesTo<Value>,
}

/// Sized structure for all possible Registers.
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, IntoSchema)]
pub struct RegisterBox {
Expand Down
144 changes: 76 additions & 68 deletions schema/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,23 @@

#![allow(clippy::print_stdout)]

use std::collections::BTreeMap;

use iroha_core::block::stream::prelude::*;
use iroha_schema::prelude::*;

macro_rules! to_json {
($($t:ty),* $(,)?) => {{
let mut out = BTreeMap::new();
$(<$t as IntoSchema>::schema(&mut out);)*
serde_json::to_string_pretty(&out).unwrap()
}};
}

fn main() {
fn build_schemas() -> MetaMap {
use iroha_core::genesis::RawGenesisBlock;
use iroha_data_model::{
expression::*,
isi::{If, *},
prelude::*,
};
use iroha_data_model::prelude::*;

let json = to_json! {
// $ rg '^pub (struct|enum)' | rg -v '(<|Builder|LengthLimits|QueryRequest)' | cut -d' ' -f3 | sed -e 's/[(].*//' -e 's/$/,/' | sort
Add,
And,
BlockPublisherMessage,
BlockSubscriberMessage,
BurnBox,
Contains,
ContainsAll,
ContainsAny,
ContextValue,
Divide,
Equal,
Event,
EventFilter,
EventPublisherMessage,
EventSubscriberMessage,
Expression,
FailBox,
GrantBox,
Greater,
IdBox,
IdentifiableBox,
If,
If,
Instruction,
Less,
MintBox,
Mod,
Multiply,
Not,
Or,
Pair,
Parameter,
Payload,
QueryBox,
QueryResult,
RaiseTo,
RegisterBox,
RemoveKeyValueBox,
SequenceBox,
SetBox,
SetKeyValueBox,
SignedQueryRequest,
Subtract,
TransferBox,
UnregisterBox,
Value,
Where,
macro_rules! schemas {
($($t:ty),* $(,)?) => {{
let mut out = MetaMap::new();
$(<$t as IntoSchema>::schema(&mut out);)*
out
}};
}

// All versioned
schemas! {
// It is sufficient to list top level types only
VersionedBlockPublisherMessage,
VersionedBlockSubscriberMessage,
VersionedEventPublisherMessage,
Expand All @@ -83,7 +28,70 @@ fn main() {
VersionedTransaction,

RawGenesisBlock
};
}
}

// Schemas should always be serializable to JSON
#[allow(clippy::expect_used)]
fn main() {
let schemas = build_schemas();

println!(
"{}",
serde_json::to_string_pretty(&schemas).expect("Unable to serialize schemas")
);
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use super::*;

fn find_missing_schemas(schemas: &MetaMap) -> HashMap<&str, Vec<&str>> {
let mut missing_schemas = HashMap::new();

for (type_name, schema) in schemas {
let types: Vec<&str> = match schema {
Metadata::Enum(EnumMeta { variants }) => variants
.iter()
.map(|v| &v.ty)
.filter_map(Option::as_ref)
.map(String::as_str)
.collect(),
Metadata::Struct(NamedFieldsMeta { declarations }) => {
declarations.iter().map(|d| d.ty.as_str()).collect()
}
Metadata::TupleStruct(UnnamedFieldsMeta { types }) => {
types.iter().map(String::as_str).collect()
}
Metadata::Result(ResultMeta { ok, err }) => vec![ok, err],
Metadata::Map(MapMeta { key, value }) => vec![key, value],
Metadata::Option(ty)
| Metadata::Array(ArrayMeta { ty, .. })
| Metadata::Vec(ty) => {
vec![ty]
}
Metadata::String | Metadata::Bool | Metadata::FixedPoint(_) | Metadata::Int(_) => {
vec![]
}
};

for ty in types {
if !schemas.contains_key(ty) {
missing_schemas
.entry(type_name.as_str())
.or_insert_with(Vec::new)
.push(ty);
}
}
}

missing_schemas
}

println!("{}", json)
#[test]
fn no_missing_schemas() {
assert!(find_missing_schemas(&build_schemas()).is_empty());
}
}
36 changes: 21 additions & 15 deletions schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub trait DecimalPlacesAware {
}

/// Metadata
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub enum Metadata {
/// Structure with named fields
Struct(NamedFieldsMeta),
Expand Down Expand Up @@ -80,22 +80,24 @@ pub enum Metadata {
}

/// Array metadata
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct ArrayMeta {
ty: String,
len: usize,
/// Type
pub ty: String,
/// Length
pub len: usize,
}

/// Named fields
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct NamedFieldsMeta {
/// Fields
pub declarations: Vec<Declaration>,
//todo add collection of properties meta defined in struct
}

/// Field
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct Declaration {
/// Field name
pub name: String,
Expand All @@ -104,22 +106,22 @@ pub struct Declaration {
}

/// Unnamed fileds
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct UnnamedFieldsMeta {
/// Field types
pub types: Vec<String>,
//todo add collection of properties meta defined in struct
}

/// Enum metadata
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct EnumMeta {
/// Enum variants
pub variants: Vec<EnumVariant>,
}

/// Enum variant
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct EnumVariant {
/// Enum variant name
pub name: String,
Expand All @@ -131,7 +133,7 @@ pub struct EnumVariant {
}

/// Result variant
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct ResultMeta {
/// Ok type
pub ok: String,
Expand All @@ -140,7 +142,7 @@ pub struct ResultMeta {
}

/// Map variant
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct MapMeta {
/// Key type
pub key: String,
Expand All @@ -149,7 +151,7 @@ pub struct MapMeta {
}

/// Integer mode
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub enum IntMode {
/// Fixed width
FixedWidth,
Expand All @@ -158,11 +160,11 @@ pub enum IntMode {
}

/// Compact predicate. Just for documentation purposes
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct Compact<T>(T);

/// Fixed metadata
#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
pub struct FixedMeta {
base: String,
decimal_places: usize,
Expand Down Expand Up @@ -319,7 +321,11 @@ impl<V: IntoSchema> IntoSchema for BTreeSet<V> {
format!("BTreeSet<{}>", V::type_name())
}
fn schema(map: &mut MetaMap) {
Vec::<V>::schema(map)
map.entry(Self::type_name())
.or_insert_with(|| Metadata::Vec(V::type_name()));
if !map.contains_key(&V::type_name()) {
Vec::<V>::schema(map)
}
}
}

Expand Down