Correctly serialize code in chain spec as hex (#4025)

* Correctly serialize code in chain spec as hex.

Due to a bug, the runtime code was previously serialized as a JSON
array of numbers, pretty printed one byte per line.

* Remove panic in macro and whitelist attribute types for storage
genesis config lines.

* Use syn::Error to enforce whitelisted attributes on genesis config.

* Blacklist genesis extra config line attributes instead of whitelist.
This commit is contained in:
Jim Posen
2019-11-07 18:40:04 +01:00
committed by Bastian Köcher
parent cca9ab436c
commit d9c2ac5fd7
2 changed files with 34 additions and 21 deletions
@@ -18,14 +18,14 @@
use srml_support_procedural_tools::syn_ext as ext; use srml_support_procedural_tools::syn_ext as ext;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use syn::parse_quote; use syn::{spanned::Spanned, parse_quote};
use quote::quote; use quote::quote;
use super::super::{DeclStorageDefExt, StorageLineTypeDef}; use super::super::{DeclStorageDefExt, StorageLineTypeDef};
pub struct GenesisConfigFieldDef { pub struct GenesisConfigFieldDef {
pub doc: Vec<syn::Meta>,
pub name: syn::Ident, pub name: syn::Ident,
pub typ: syn::Type, pub typ: syn::Type,
pub attrs: Vec<syn::Meta>,
pub default: TokenStream, pub default: TokenStream,
} }
@@ -43,8 +43,8 @@ pub struct GenesisConfigDef {
} }
impl GenesisConfigDef { impl GenesisConfigDef {
pub fn from_def(def: &DeclStorageDefExt) -> Self { pub fn from_def(def: &DeclStorageDefExt) -> syn::Result<Self> {
let fields = Self::get_genesis_config_field_defs(def); let fields = Self::get_genesis_config_field_defs(def)?;
let is_generic = fields.iter() let is_generic = fields.iter()
.any(|field| ext::type_contains_ident(&field.typ, &def.module_runtime_generic)); .any(|field| ext::type_contains_ident(&field.typ, &def.module_runtime_generic));
@@ -71,17 +71,19 @@ impl GenesisConfigDef {
(quote!(), quote!(), quote!(), None) (quote!(), quote!(), quote!(), None)
}; };
Self { Ok(Self {
is_generic, is_generic,
fields, fields,
genesis_struct_decl, genesis_struct_decl,
genesis_struct, genesis_struct,
genesis_impl, genesis_impl,
genesis_where_clause, genesis_where_clause,
} })
} }
fn get_genesis_config_field_defs(def: &DeclStorageDefExt) -> Vec<GenesisConfigFieldDef> { fn get_genesis_config_field_defs(def: &DeclStorageDefExt)
-> syn::Result<Vec<GenesisConfigFieldDef>>
{
let mut config_field_defs = Vec::new(); let mut config_field_defs = Vec::new();
for (config_field, line) in def.storage_lines.iter() for (config_field, line) in def.storage_lines.iter()
@@ -114,31 +116,39 @@ impl GenesisConfigDef {
.unwrap_or_else(|| quote!( Default::default() )); .unwrap_or_else(|| quote!( Default::default() ));
config_field_defs.push(GenesisConfigFieldDef { config_field_defs.push(GenesisConfigFieldDef {
doc: line.doc_attrs.clone(),
name: config_field, name: config_field,
typ, typ,
attrs: line.doc_attrs.clone(),
default, default,
}); });
} }
for line in &def.extra_genesis_config_lines { for line in &def.extra_genesis_config_lines {
let doc = line.attrs.iter() let attrs = line.attrs.iter()
.filter_map(|a| a.parse_meta().ok()) .map(|attr| {
.filter(|m| m.path().is_ident("doc")) let meta = attr.parse_meta()?;
.collect(); if meta.path().is_ident("cfg") {
return Err(syn::Error::new(
meta.span(),
"extra genesis config items do not support `cfg` attribute"
));
}
Ok(meta)
})
.collect::<syn::Result<_>>()?;
let default = line.default.as_ref().map(|e| quote!( #e )) let default = line.default.as_ref().map(|e| quote!( #e ))
.unwrap_or_else(|| quote!( Default::default() )); .unwrap_or_else(|| quote!( Default::default() ));
config_field_defs.push(GenesisConfigFieldDef { config_field_defs.push(GenesisConfigFieldDef {
doc,
name: line.name.clone(), name: line.name.clone(),
typ: line.typ.clone(), typ: line.typ.clone(),
attrs,
default, default,
}); });
} }
config_field_defs Ok(config_field_defs)
} }
} }
@@ -33,13 +33,13 @@ fn decl_genesis_config_and_impl_default(
genesis_config: &GenesisConfigDef, genesis_config: &GenesisConfigDef,
) -> TokenStream { ) -> TokenStream {
let config_fields = genesis_config.fields.iter().map(|field| { let config_fields = genesis_config.fields.iter().map(|field| {
let (name, typ, doc) = (&field.name, &field.typ, &field.doc); let (name, typ, attrs) = (&field.name, &field.typ, &field.attrs);
quote!( #( #[ #doc] )* pub #name: #typ, ) quote!( #( #[ #attrs] )* pub #name: #typ, )
}); });
let config_field_defaults = genesis_config.fields.iter().map(|field| { let config_field_defaults = genesis_config.fields.iter().map(|field| {
let (name, default, doc) = (&field.name, &field.default, &field.doc); let (name, default) = (&field.name, &field.default);
quote!( #( #[ #doc] )* #name: #default, ) quote!( #name: #default, )
}); });
let serde_bug_bound = if !genesis_config.fields.is_empty() { let serde_bug_bound = if !genesis_config.fields.is_empty() {
@@ -188,10 +188,13 @@ pub fn genesis_config_and_build_storage(
) -> TokenStream { ) -> TokenStream {
let builders = BuilderDef::from_def(scrate, def); let builders = BuilderDef::from_def(scrate, def);
if !builders.blocks.is_empty() { if !builders.blocks.is_empty() {
let genesis_config = &GenesisConfigDef::from_def(def); let genesis_config = match GenesisConfigDef::from_def(def) {
Ok(genesis_config) => genesis_config,
Err(err) => return err.to_compile_error(),
};
let decl_genesis_config_and_impl_default = let decl_genesis_config_and_impl_default =
decl_genesis_config_and_impl_default(scrate, genesis_config); decl_genesis_config_and_impl_default(scrate, &genesis_config);
let impl_build_storage = impl_build_storage(scrate, def, genesis_config, &builders); let impl_build_storage = impl_build_storage(scrate, def, &genesis_config, &builders);
quote!{ quote!{
#decl_genesis_config_and_impl_default #decl_genesis_config_and_impl_default