Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
@@ -16,21 +16,25 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait,
fold_fn_decl_for_client_side, extract_parameter_names_types_and_borrows,
generate_native_call_generator_fn_name, return_type_extract_type,
generate_method_runtime_api_impl_name, generate_call_api_at_fn_name, prefix_function_with_trait,
replace_wild_card_parameter_names, AllowSelfRefInParameters,
extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side,
generate_call_api_at_fn_name, generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, generate_native_call_generator_fn_name,
generate_runtime_mod_name_for_trait, prefix_function_with_trait,
replace_wild_card_parameter_names, return_type_extract_type, AllowSelfRefInParameters,
};
use proc_macro2::{TokenStream, Span};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, ReturnType,
fold::{self, Fold}, parse_quote, ItemTrait, Generics, GenericParam, Attribute, FnArg, Type,
visit::{Visit, self}, TraitBound, Meta, NestedMeta, Lit, TraitItem, Ident, TraitItemMethod,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
visit::{self, Visit},
Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, Lit, Meta, NestedMeta, ReturnType,
TraitBound, TraitItem, TraitItemMethod, Type,
};
use std::collections::HashMap;
@@ -59,9 +63,8 @@ const CHANGED_IN_ATTRIBUTE: &str = "changed_in";
/// Is used when a trait method was renamed.
const RENAMED_ATTRIBUTE: &str = "renamed";
/// All attributes that we support in the declaration of a runtime api trait.
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[
CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE,
];
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] =
&[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE];
/// The structure used for parsing the runtime api declarations.
struct RuntimeApiDecls {
@@ -94,14 +97,12 @@ fn extend_generics_with_block(generics: &mut Generics) {
/// attribute body as `TokenStream`.
fn remove_supported_attributes(attrs: &mut Vec<Attribute>) -> HashMap<&'static str, Attribute> {
let mut result = HashMap::new();
attrs.retain(|v| {
match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path.is_ident(a)) {
Some(attribute) => {
result.insert(*attribute, v.clone());
false
},
None => true,
}
attrs.retain(|v| match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path.is_ident(a)) {
Some(attribute) => {
result.insert(*attribute, v.clone());
false
},
None => true,
});
result
@@ -226,16 +227,17 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result<TokenStream> {
)
)
} else {
quote!( Ok(res) )
quote!(Ok(res))
};
let input_names = params.iter().map(|v| &v.0);
// If the type is using the block generic type, we will encode/decode it to make it
// compatible. To ensure that we forward it by ref/value, we use the value given by the
// the user. Otherwise if it is not using the block, we don't need to add anything.
let input_borrows = params
.iter()
.map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { None });
let input_borrows =
params
.iter()
.map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { None });
// Replace all `Block` with `NodeBlock`, add `'a` lifetime to references and collect
// all the function inputs.
@@ -304,28 +306,23 @@ fn parse_renamed_attribute(renamed: &Attribute) -> Result<(String, u32)> {
);
match meta {
Meta::List(list) => {
Meta::List(list) =>
if list.nested.len() > 2 && list.nested.is_empty() {
err
} else {
let mut itr = list.nested.iter();
let old_name = match itr.next() {
Some(NestedMeta::Lit(Lit::Str(i))) => {
i.value()
},
Some(NestedMeta::Lit(Lit::Str(i))) => i.value(),
_ => return err,
};
let version = match itr.next() {
Some(NestedMeta::Lit(Lit::Int(i))) => {
i.base10_parse()?
},
Some(NestedMeta::Lit(Lit::Int(i))) => i.base10_parse()?,
_ => return err,
};
Ok((old_name, version))
}
},
},
_ => err,
}
}
@@ -353,23 +350,19 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
fn_.span(),
format!(
"`{}` and `{}` are not supported at once.",
RENAMED_ATTRIBUTE,
CHANGED_IN_ATTRIBUTE
)
));
RENAMED_ATTRIBUTE, CHANGED_IN_ATTRIBUTE
),
))
}
// We do not need to generate this function for a method that signature was changed.
if attrs.contains_key(CHANGED_IN_ATTRIBUTE) {
continue;
continue
}
// Parse the renamed attributes.
let mut renames = Vec::new();
if let Some((_, a)) = attrs
.iter()
.find(|a| a.0 == &RENAMED_ATTRIBUTE)
{
if let Some((_, a)) = attrs.iter().find(|a| a.0 == &RENAMED_ATTRIBUTE) {
let (old_name, version) = parse_renamed_attribute(a)?;
renames.push((version, prefix_function_with_trait(&trait_name, &old_name)));
}
@@ -381,7 +374,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
versions.push(version);
old_names.push(old_name);
(versions, old_names)
}
},
);
// Generate the generator function
@@ -456,27 +449,32 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result<TokenStream> {
extend_generics_with_block(&mut decl.generics);
let mod_name = generate_runtime_mod_name_for_trait(&decl.ident);
let found_attributes = remove_supported_attributes(&mut decl.attrs);
let api_version = get_api_version(&found_attributes).map(|v| {
generate_runtime_api_version(v as u32)
})?;
let api_version =
get_api_version(&found_attributes).map(|v| generate_runtime_api_version(v as u32))?;
let id = generate_runtime_api_id(&decl.ident.to_string());
let call_api_at_calls = generate_call_api_at_calls(&decl)?;
// Remove methods that have the `changed_in` attribute as they are not required for the
// runtime anymore.
decl.items = decl.items.iter_mut().filter_map(|i| match i {
TraitItem::Method(ref mut method) => {
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
None
} else {
// Make sure we replace all the wild card parameter names.
replace_wild_card_parameter_names(&mut method.sig);
Some(TraitItem::Method(method.clone()))
}
}
r => Some(r.clone()),
}).collect();
decl.items = decl
.items
.iter_mut()
.filter_map(|i| match i {
TraitItem::Method(ref mut method) => {
if remove_supported_attributes(&mut method.attrs)
.contains_key(CHANGED_IN_ATTRIBUTE)
{
None
} else {
// Make sure we replace all the wild card parameter names.
replace_wild_card_parameter_names(&mut method.sig);
Some(TraitItem::Method(method.clone()))
}
},
r => Some(r.clone()),
})
.collect();
let native_call_generators = generate_native_call_generators(&decl)?;
@@ -533,8 +531,10 @@ impl<'a> ToClientSideDecl<'a> {
result
}
fn fold_trait_item_method(&mut self, method: TraitItemMethod)
-> (TraitItemMethod, Option<TraitItemMethod>, TraitItemMethod) {
fn fold_trait_item_method(
&mut self,
method: TraitItemMethod,
) -> (TraitItemMethod, Option<TraitItemMethod>, TraitItemMethod) {
let crate_ = self.crate_;
let context = quote!( #crate_::ExecutionContext::OffchainCall(None) );
let fn_impl = self.create_method_runtime_api_impl(method.clone());
@@ -547,8 +547,9 @@ impl<'a> ToClientSideDecl<'a> {
fn create_method_decl_with_context(&mut self, method: TraitItemMethod) -> TraitItemMethod {
let crate_ = self.crate_;
let context_arg: syn::FnArg = parse_quote!( context: #crate_::ExecutionContext );
let mut fn_decl_ctx = self.create_method_decl(method, quote!( context ));
fn_decl_ctx.sig.ident = Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site());
let mut fn_decl_ctx = self.create_method_decl(method, quote!(context));
fn_decl_ctx.sig.ident =
Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site());
fn_decl_ctx.sig.inputs.insert(2, context_arg);
fn_decl_ctx
@@ -556,9 +557,12 @@ impl<'a> ToClientSideDecl<'a> {
/// Takes the given method and creates a `method_runtime_api_impl` method that will be
/// implemented in the runtime for the client side.
fn create_method_runtime_api_impl(&mut self, mut method: TraitItemMethod) -> Option<TraitItemMethod> {
fn create_method_runtime_api_impl(
&mut self,
mut method: TraitItemMethod,
) -> Option<TraitItemMethod> {
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
return None;
return None
}
let fn_sig = &method.sig;
@@ -566,36 +570,35 @@ impl<'a> ToClientSideDecl<'a> {
// Get types and if the value is borrowed from all parameters.
// If there is an error, we push it as the block to the user.
let param_types = match extract_parameter_names_types_and_borrows(
fn_sig,
AllowSelfRefInParameters::No,
) {
Ok(res) => res.into_iter().map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
}).collect::<Vec<_>>(),
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
}
};
let param_types =
match extract_parameter_names_types_and_borrows(fn_sig, AllowSelfRefInParameters::No) {
Ok(res) => res
.into_iter()
.map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
})
.collect::<Vec<_>>(),
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
},
};
let name = generate_method_runtime_api_impl_name(&self.trait_, &method.sig.ident);
let block_id = self.block_id;
let crate_ = self.crate_;
Some(
parse_quote!{
#[doc(hidden)]
fn #name(
&self,
at: &#block_id,
context: #crate_::ExecutionContext,
params: Option<( #( #param_types ),* )>,
params_encoded: Vec<u8>,
) -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError>;
}
)
Some(parse_quote! {
#[doc(hidden)]
fn #name(
&self,
at: &#block_id,
context: #crate_::ExecutionContext,
params: Option<( #( #param_types ),* )>,
params_encoded: Vec<u8>,
) -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError>;
})
}
/// Takes the method declared by the user and creates the declaration we require for the runtime
@@ -614,7 +617,7 @@ impl<'a> ToClientSideDecl<'a> {
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
}
},
};
let params2 = params.clone();
let ret_type = return_type_extract_type(&method.sig.output);
@@ -635,7 +638,8 @@ impl<'a> ToClientSideDecl<'a> {
Error::new(
method.span(),
"`changed_in` version can not be greater than the `api_version`",
).to_compile_error()
)
.to_compile_error(),
);
}
@@ -646,49 +650,48 @@ impl<'a> ToClientSideDecl<'a> {
method.sig.ident = ident;
method.attrs.push(parse_quote!( #[deprecated] ));
let panic = format!("Calling `{}` should not return a native value!", method.sig.ident);
(quote!( panic!(#panic) ), quote!( None ))
let panic =
format!("Calling `{}` should not return a native value!", method.sig.ident);
(quote!(panic!(#panic)), quote!(None))
},
Ok(None) => (quote!( Ok(n) ), quote!( Some(( #( #params2 ),* )) )),
Ok(None) => (quote!(Ok(n)), quote!( Some(( #( #params2 ),* )) )),
Err(e) => {
self.errors.push(e.to_compile_error());
(quote!( unimplemented!() ), quote!( None ))
}
(quote!(unimplemented!()), quote!(None))
},
};
let function_name = method.sig.ident.to_string();
// Generate the default implementation that calls the `method_runtime_api_impl` method.
method.default = Some(
parse_quote! {
{
let runtime_api_impl_params_encoded =
#crate_::Encode::encode(&( #( &#params ),* ));
method.default = Some(parse_quote! {
{
let runtime_api_impl_params_encoded =
#crate_::Encode::encode(&( #( &#params ),* ));
self.#name_impl(
__runtime_api_at_param__,
#context,
#param_tuple,
runtime_api_impl_params_encoded,
).and_then(|r|
match r {
#crate_::NativeOrEncoded::Native(n) => {
#native_handling
},
#crate_::NativeOrEncoded::Encoded(r) => {
<#ret_type as #crate_::Decode>::decode(&mut &r[..])
.map_err(|err|
#crate_::ApiError::FailedToDecodeReturnValue {
function: #function_name,
error: err,
}
)
}
self.#name_impl(
__runtime_api_at_param__,
#context,
#param_tuple,
runtime_api_impl_params_encoded,
).and_then(|r|
match r {
#crate_::NativeOrEncoded::Native(n) => {
#native_handling
},
#crate_::NativeOrEncoded::Encoded(r) => {
<#ret_type as #crate_::Decode>::decode(&mut &r[..])
.map_err(|err|
#crate_::ApiError::FailedToDecodeReturnValue {
function: #function_name,
error: err,
}
)
}
)
}
}
)
}
);
});
method
}
@@ -705,11 +708,7 @@ impl<'a> Fold for ToClientSideDecl<'a> {
if is_core_trait {
// Add all the supertraits we want to have for `Core`.
input.supertraits = parse_quote!(
'static
+ Send
+ Sync
);
input.supertraits = parse_quote!('static + Send + Sync);
} else {
// Add the `Core` runtime api as super trait.
let crate_ = &self.crate_;
@@ -729,24 +728,22 @@ fn parse_runtime_api_version(version: &Attribute) -> Result<u64> {
let meta = version.parse_meta()?;
let err = Err(Error::new(
meta.span(),
&format!(
"Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`",
api_version = API_VERSION_ATTRIBUTE
)
)
);
meta.span(),
&format!(
"Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`",
api_version = API_VERSION_ATTRIBUTE
),
));
match meta {
Meta::List(list) => {
Meta::List(list) =>
if list.nested.len() != 1 {
err
} else if let Some(NestedMeta::Lit(Lit::Int(i))) = list.nested.first() {
i.base10_parse()
} else {
err
}
},
},
_ => err,
}
}
@@ -798,14 +795,18 @@ fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream {
/// Get changed in version from the user given attribute or `Ok(None)`, if no attribute was given.
fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result<Option<u64>> {
found_attributes.get(&CHANGED_IN_ATTRIBUTE)
found_attributes
.get(&CHANGED_IN_ATTRIBUTE)
.map(|v| parse_runtime_api_version(v).map(Some))
.unwrap_or(Ok(None))
}
/// Get the api version from the user given attribute or `Ok(1)`, if no attribute was given.
fn get_api_version(found_attributes: &HashMap<&'static str, Attribute>) -> Result<u64> {
found_attributes.get(&API_VERSION_ATTRIBUTE).map(parse_runtime_api_version).unwrap_or(Ok(1))
found_attributes
.get(&API_VERSION_ATTRIBUTE)
.map(parse_runtime_api_version)
.unwrap_or(Ok(1))
}
/// Generate the declaration of the trait for the client side.
@@ -863,7 +864,10 @@ impl CheckTraitDecl {
/// Check that the given method declarations are correct.
///
/// Any error is stored in `self.errors`.
fn check_method_declarations<'a>(&mut self, methods: impl Iterator<Item = &'a TraitItemMethod>) {
fn check_method_declarations<'a>(
&mut self,
methods: impl Iterator<Item = &'a TraitItemMethod>,
) {
let mut method_to_signature_changed = HashMap::<Ident, Vec<Option<u64>>>::new();
methods.into_iter().for_each(|method| {
@@ -871,7 +875,10 @@ impl CheckTraitDecl {
let changed_in = match get_changed_in(&attributes) {
Ok(r) => r,
Err(e) => { self.errors.push(e); return; },
Err(e) => {
self.errors.push(e);
return
},
};
method_to_signature_changed
@@ -912,16 +919,13 @@ impl<'ast> Visit<'ast> for CheckTraitDecl {
fn visit_generic_param(&mut self, input: &'ast GenericParam) {
match input {
GenericParam::Type(ty) if ty.ident == BLOCK_GENERIC_IDENT => {
self.errors.push(
Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro!"
)
)
},
_ => {}
GenericParam::Type(ty) if ty.ident == BLOCK_GENERIC_IDENT =>
self.errors.push(Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro!",
)),
_ => {},
}
visit::visit_generic_param(self, input);
@@ -930,14 +934,12 @@ impl<'ast> Visit<'ast> for CheckTraitDecl {
fn visit_trait_bound(&mut self, input: &'ast TraitBound) {
if let Some(last_ident) = input.path.segments.last().map(|v| &v.ident) {
if last_ident == "BlockT" || last_ident == BLOCK_GENERIC_IDENT {
self.errors.push(
Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
self.errors.push(Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro! If you try to use a different trait than the \
substrate `Block` trait, please rename it locally."
)
)
substrate `Block` trait, please rename it locally.",
))
}
}
@@ -965,7 +967,9 @@ pub fn decl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
// Parse all trait declarations
let RuntimeApiDecls { decls: api_decls } = parse_macro_input!(input as RuntimeApiDecls);
decl_runtime_apis_impl_inner(&api_decls).unwrap_or_else(|e| e.to_compile_error()).into()
decl_runtime_apis_impl_inner(&api_decls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result<TokenStream> {
@@ -975,13 +979,11 @@ fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result<TokenStream>
let runtime_decls = generate_runtime_decls(api_decls)?;
let client_side_decls = generate_client_side_decls(api_decls)?;
Ok(
quote!(
#hidden_includes
Ok(quote!(
#hidden_includes
#runtime_decls
#runtime_decls
#client_side_decls
)
)
#client_side_decls
))
}
@@ -16,12 +16,12 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes,
generate_runtime_mod_name_for_trait, generate_method_runtime_api_impl_name,
extract_parameter_names_types_and_borrows, generate_native_call_generator_fn_name,
return_type_extract_type, generate_call_api_at_fn_name, prefix_function_with_trait,
extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait,
AllowSelfRefInParameters, RequireQualifiedTraitPath,
extract_parameter_names_types_and_borrows, generate_call_api_at_fn_name, generate_crate_access,
generate_hidden_includes, generate_method_runtime_api_impl_name,
generate_native_call_generator_fn_name, generate_runtime_mod_name_for_trait,
prefix_function_with_trait, return_type_extract_type, AllowSelfRefInParameters,
RequireQualifiedTraitPath,
};
use proc_macro2::{Span, TokenStream};
@@ -29,9 +29,12 @@ use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, Path, Signature, Attribute,
ImplItem, parse::{Parse, ParseStream, Result, Error}, PathArguments, GenericArgument, TypePath,
fold::{self, Fold}, parse_quote,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
Attribute, GenericArgument, Ident, ImplItem, ItemImpl, Path, PathArguments, Signature, Type,
TypePath,
};
use std::collections::HashSet;
@@ -66,9 +69,10 @@ fn generate_impl_call(
signature: &Signature,
runtime: &Type,
input: &Ident,
impl_trait: &Path
impl_trait: &Path,
) -> Result<TokenStream> {
let params = extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
let params =
extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let fn_name = &signature.ident;
@@ -78,27 +82,25 @@ fn generate_impl_call(
let ptypes = params.iter().map(|v| &v.1);
let pborrow = params.iter().map(|v| &v.2);
Ok(
quote!(
let (#( #pnames ),*) : ( #( #ptypes ),* ) =
match #c::DecodeLimit::decode_all_with_depth_limit(
#c::MAX_EXTRINSIC_DEPTH,
&#input,
) {
Ok(res) => res,
Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
};
Ok(quote!(
let (#( #pnames ),*) : ( #( #ptypes ),* ) =
match #c::DecodeLimit::decode_all_with_depth_limit(
#c::MAX_EXTRINSIC_DEPTH,
&#input,
) {
Ok(res) => res,
Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
};
#[allow(deprecated)]
<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*)
)
)
#[allow(deprecated)]
<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*)
))
}
/// Generate all the implementation calls for the given functions.
fn generate_impl_calls(
impls: &[ItemImpl],
input: &Ident
input: &Ident,
) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
let mut impl_calls = Vec::new();
@@ -113,12 +115,8 @@ fn generate_impl_calls(
for item in &impl_.items {
if let ImplItem::Method(method) = item {
let impl_call = generate_impl_call(
&method.sig,
&impl_.self_ty,
input,
&impl_trait
)?;
let impl_call =
generate_impl_call(&method.sig, &impl_.self_ty, input, &impl_trait)?;
impl_calls.push((
impl_trait_ident.clone(),
@@ -137,15 +135,16 @@ fn generate_impl_calls(
fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
let data = Ident::new("__sp_api__input_data", Span::call_site());
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let impl_calls = generate_impl_calls(impls, &data)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let name = prefix_function_with_trait(&trait_, &fn_name);
quote!(
#( #attrs )*
#name => Some(#c::Encode::encode(&{ #impl_ })),
)
});
let impl_calls =
generate_impl_calls(impls, &data)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let name = prefix_function_with_trait(&trait_, &fn_name);
quote!(
#( #attrs )*
#name => Some(#c::Encode::encode(&{ #impl_ })),
)
});
Ok(quote!(
#[cfg(feature = "std")]
@@ -163,34 +162,33 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
let input = Ident::new("input", Span::call_site());
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let impl_calls = generate_impl_calls(impls, &input)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let fn_name = Ident::new(
&prefix_function_with_trait(&trait_, &fn_name),
Span::call_site()
);
let impl_calls =
generate_impl_calls(impls, &input)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let fn_name =
Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
quote!(
#( #attrs )*
#[cfg(not(feature = "std"))]
#[no_mangle]
pub unsafe fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
let mut #input = if input_len == 0 {
&[0u8; 0]
} else {
unsafe {
#c::slice::from_raw_parts(input_data, input_len)
}
};
quote!(
#( #attrs )*
#[cfg(not(feature = "std"))]
#[no_mangle]
pub unsafe fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
let mut #input = if input_len == 0 {
&[0u8; 0]
} else {
unsafe {
#c::slice::from_raw_parts(input_data, input_len)
}
};
#c::init_runtime_logger();
#c::init_runtime_logger();
let output = (move || { #impl_ })();
#c::to_substrate_wasm_fn_return_value(&output)
}
)
});
let output = (move || { #impl_ })();
#c::to_substrate_wasm_fn_return_value(&output)
}
)
});
Ok(quote!( #( #impl_calls )* ))
}
@@ -414,7 +412,6 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
Ok(quote!( #( #impls_prepared )* ))
}
/// Auxiliary data structure that is used to convert `impl Api for Runtime` to
/// `impl Api for RuntimeApi`.
/// This requires us to replace the runtime `Block` with the node `Block`,
@@ -430,11 +427,8 @@ struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
fn fold_type_path(&mut self, input: TypePath) -> TypePath {
let new_ty_path = if input == *self.runtime_block {
parse_quote!( __SR_API_BLOCK__ )
} else {
input
};
let new_ty_path =
if input == *self.runtime_block { parse_quote!(__SR_API_BLOCK__) } else { input };
fold::fold_type_path(self, new_ty_path)
}
@@ -451,12 +445,18 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
// Generate the access to the native parameters
let param_tuple_access = if input.sig.inputs.len() == 1 {
vec![ quote!( p ) ]
vec![quote!(p)]
} else {
input.sig.inputs.iter().enumerate().map(|(i, _)| {
let i = syn::Index::from(i);
quote!( p.#i )
}).collect::<Vec<_>>()
input
.sig
.inputs
.iter()
.enumerate()
.map(|(i, _)| {
let i = syn::Index::from(i);
quote!( p.#i )
})
.collect::<Vec<_>>()
};
let (param_types, error) = match extract_parameter_names_types_and_borrows(
@@ -464,12 +464,14 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
AllowSelfRefInParameters::No,
) {
Ok(res) => (
res.into_iter().map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
}).collect::<Vec<_>>(),
None
res.into_iter()
.map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
})
.collect::<Vec<_>>(),
None,
),
Err(e) => (Vec::new(), Some(e.to_compile_error())),
};
@@ -483,10 +485,8 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
params_encoded: Vec<u8>,
};
input.sig.ident = generate_method_runtime_api_impl_name(
&self.impl_trait,
&input.sig.ident,
);
input.sig.ident =
generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident);
let ret_type = return_type_extract_type(&input.sig.output);
// Generate the correct return type.
@@ -544,43 +544,34 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
// Implement the trait for the `RuntimeApiImpl`
input.self_ty = Box::new(
parse_quote!( RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall> )
);
input.self_ty =
Box::new(parse_quote!( RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall> ));
input.generics.params.push(parse_quote!(
__SR_API_BLOCK__: #crate_::BlockT + std::panic::UnwindSafe +
std::panic::RefUnwindSafe
));
input.generics.params.push(
parse_quote!(
__SR_API_BLOCK__: #crate_::BlockT + std::panic::UnwindSafe +
std::panic::RefUnwindSafe
)
);
input.generics.params.push(
parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SR_API_BLOCK__> + 'static )
parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SR_API_BLOCK__> + 'static ),
);
let where_clause = input.generics.make_where_clause();
where_clause.predicates.push(
parse_quote! {
RuntimeApiImplCall::StateBackend:
#crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>>
}
);
where_clause.predicates.push(parse_quote! {
RuntimeApiImplCall::StateBackend:
#crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>>
});
// Require that all types used in the function signatures are unwind safe.
extract_all_signature_types(&input.items).iter().for_each(|i| {
where_clause.predicates.push(
parse_quote! {
#i: std::panic::UnwindSafe + std::panic::RefUnwindSafe
}
);
where_clause.predicates.push(parse_quote! {
#i: std::panic::UnwindSafe + std::panic::RefUnwindSafe
});
});
where_clause.predicates.push(
parse_quote! {
__SR_API_BLOCK__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe
}
);
where_clause.predicates.push(parse_quote! {
__SR_API_BLOCK__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe
});
input.attrs = filter_cfg_attrs(&input.attrs);
@@ -650,14 +641,12 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
let span = trait_.span();
if !processed_traits.insert(trait_) {
return Err(
Error::new(
span,
"Two traits with the same name detected! \
return Err(Error::new(
span,
"Two traits with the same name detected! \
The trait name is used to generate its ID. \
Please rename one trait at the declaration!"
)
)
Please rename one trait at the declaration!",
))
}
let id: Path = parse_quote!( #path ID );
@@ -692,7 +681,9 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
// Parse all impl blocks
let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
impl_runtime_apis_impl_inner(&api_impls).unwrap_or_else(|e| e.to_compile_error()).into()
impl_runtime_apis_impl_inner(&api_impls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
@@ -704,27 +695,25 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
let wasm_interface = generate_wasm_interface(api_impls)?;
let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
Ok(
quote!(
#hidden_includes
Ok(quote!(
#hidden_includes
#base_runtime_api
#base_runtime_api
#api_impls_for_runtime
#api_impls_for_runtime
#api_impls_for_runtime_api
#api_impls_for_runtime_api
#runtime_api_versions
#runtime_api_versions
pub mod api {
use super::*;
pub mod api {
use super::*;
#dispatch_impl
#dispatch_impl
#wasm_interface
}
)
)
#wasm_interface
}
))
}
// Filters all attributes except the cfg ones.
@@ -21,9 +21,9 @@
use proc_macro::TokenStream;
mod decl_runtime_apis;
mod impl_runtime_apis;
mod mock_impl_runtime_apis;
mod decl_runtime_apis;
mod utils;
#[proc_macro]
@@ -16,10 +16,10 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, extract_parameter_names_types_and_borrows,
return_type_extract_type, extract_block_type_from_trait_path, extract_impl_trait,
AllowSelfRefInParameters, RequireQualifiedTraitPath,
extract_block_type_from_trait_path, extract_impl_trait,
extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, return_type_extract_type, AllowSelfRefInParameters,
RequireQualifiedTraitPath,
};
use proc_macro2::{Span, TokenStream};
@@ -27,8 +27,11 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::{
spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, TypePath, parse_quote,
parse::{Parse, ParseStream, Result, Error}, fold::{self, Fold}, Attribute, Pat,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
Attribute, Ident, ItemImpl, Pat, Type, TypePath,
};
/// Unique identifier used to make the hidden includes unique for this macro.
@@ -62,10 +65,7 @@ impl Parse for RuntimeApiImpls {
}
/// Implement the `ApiExt` trait and the `Core` runtime api.
fn implement_common_api_traits(
block_type: TypePath,
self_ty: Type,
) -> Result<TokenStream> {
fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<TokenStream> {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
Ok(quote!(
@@ -168,11 +168,13 @@ fn implement_common_api_traits(
/// If the attribute was found, it will be automatically removed from the vec.
fn has_advanced_attribute(attributes: &mut Vec<Attribute>) -> bool {
let mut found = false;
attributes.retain(|attr| if attr.path.is_ident(ADVANCED_ATTRIBUTE) {
found = true;
false
} else {
true
attributes.retain(|attr| {
if attr.path.is_ident(ADVANCED_ATTRIBUTE) {
found = true;
false
} else {
true
}
});
found
@@ -214,7 +216,7 @@ fn get_at_param_name(
let name = param_names.remove(0);
Ok((quote!( #name ), ptype_and_borrows.0))
} else {
Ok((quote!( _ ), default_block_id_type.clone()))
Ok((quote!(_), default_block_id_type.clone()))
}
}
@@ -235,24 +237,27 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
let is_advanced = has_advanced_attribute(&mut input.attrs);
let mut errors = Vec::new();
let (mut param_names, mut param_types_and_borrows) = match extract_parameter_names_types_and_borrows(
&input.sig,
AllowSelfRefInParameters::YesButIgnore,
) {
Ok(res) => (
res.iter().map(|v| v.0.clone()).collect::<Vec<_>>(),
res.iter().map(|v| {
let ty = &v.1;
let borrow = &v.2;
(quote_spanned!(ty.span() => #borrow #ty ), v.2.is_some())
}).collect::<Vec<_>>(),
),
Err(e) => {
errors.push(e.to_compile_error());
let (mut param_names, mut param_types_and_borrows) =
match extract_parameter_names_types_and_borrows(
&input.sig,
AllowSelfRefInParameters::YesButIgnore,
) {
Ok(res) => (
res.iter().map(|v| v.0.clone()).collect::<Vec<_>>(),
res.iter()
.map(|v| {
let ty = &v.1;
let borrow = &v.2;
(quote_spanned!(ty.span() => #borrow #ty ), v.2.is_some())
})
.collect::<Vec<_>>(),
),
Err(e) => {
errors.push(e.to_compile_error());
(Default::default(), Default::default())
}
};
(Default::default(), Default::default())
},
};
let block_type = &self.block_type;
let block_id_type = quote!( &#crate_::BlockId<#block_type> );
@@ -267,8 +272,8 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
Ok(res) => res,
Err(e) => {
errors.push(e.to_compile_error());
(quote!( _ ), block_id_type)
}
(quote!(_), block_id_type)
},
};
let param_types = param_types_and_borrows.iter().map(|v| &v.0);
@@ -281,10 +286,8 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
_: Vec<u8>,
};
input.sig.ident = generate_method_runtime_api_impl_name(
&self.impl_trait,
&input.sig.ident,
);
input.sig.ident =
generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident);
// When using advanced, the user needs to declare the correct return type on its own,
// otherwise do it for the user.
@@ -360,28 +363,24 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result<GeneratedRuntimeApiI
let block_type = extract_block_type_from_trait_path(impl_trait_path)?;
self_ty = match self_ty.take() {
Some(self_ty) => {
Some(self_ty) =>
if self_ty == impl_.self_ty {
Some(self_ty)
} else {
let mut error =Error::new(
let mut error = Error::new(
impl_.self_ty.span(),
"Self type should not change between runtime apis",
);
error.combine(Error::new(
self_ty.span(),
"First self type found here",
));
error.combine(Error::new(self_ty.span(), "First self type found here"));
return Err(error)
}
},
},
None => Some(impl_.self_ty.clone()),
};
global_block_type = match global_block_type.take() {
Some(global_block_type) => {
Some(global_block_type) =>
if global_block_type == *block_type {
Some(global_block_type)
} else {
@@ -396,15 +395,11 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result<GeneratedRuntimeApiI
));
return Err(error)
}
},
},
None => Some(block_type.clone()),
};
let mut visitor = FoldRuntimeApiImpl {
block_type,
impl_trait: &impl_trait.ident,
};
let mut visitor = FoldRuntimeApiImpl { block_type, impl_trait: &impl_trait.ident };
result.push(visitor.fold_item_impl(impl_.clone()));
}
@@ -421,7 +416,9 @@ pub fn mock_impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro
// Parse all impl blocks
let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
mock_impl_runtime_apis_impl_inner(&api_impls).unwrap_or_else(|e| e.to_compile_error()).into()
mock_impl_runtime_apis_impl_inner(&api_impls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn mock_impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
@@ -15,11 +15,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use proc_macro2::{TokenStream, Span};
use proc_macro2::{Span, TokenStream};
use syn::{
Result, Ident, Signature, parse_quote, Type, Pat, spanned::Spanned, FnArg, Error, token::And,
ImplItem, ReturnType, PathArguments, Path, GenericArgument, TypePath, ItemImpl,
parse_quote, spanned::Spanned, token::And, Error, FnArg, GenericArgument, Ident, ImplItem,
ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath,
};
use quote::quote;
@@ -49,18 +49,19 @@ pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream {
Err(e) => {
let err = Error::new(Span::call_site(), e).to_compile_error();
quote!( #err )
}
},
}
}
/// Generates the access to the `sc_client` crate.
pub fn generate_crate_access(unique_id: &'static str) -> TokenStream {
if env::var("CARGO_PKG_NAME").unwrap() == "sp-api" {
quote!( sp_api )
quote!(sp_api)
} else {
let mod_name = generate_hidden_includes_mod_name(unique_id);
quote!( self::#mod_name::sp_api )
}.into()
}
.into()
}
/// Generates the name of the module that contains the trait declaration for the runtime.
@@ -76,7 +77,7 @@ pub fn generate_method_runtime_api_impl_name(trait_: &Ident, method: &Ident) ->
/// Get the type of a `syn::ReturnType`.
pub fn return_type_extract_type(rt: &ReturnType) -> Type {
match rt {
ReturnType::Default => parse_quote!( () ),
ReturnType::Default => parse_quote!(()),
ReturnType::Type(_, ref ty) => *ty.clone(),
}
}
@@ -84,10 +85,13 @@ pub fn return_type_extract_type(rt: &ReturnType) -> Type {
/// Replace the `_` (wild card) parameter names in the given signature with unique identifiers.
pub fn replace_wild_card_parameter_names(input: &mut Signature) {
let mut generated_pattern_counter = 0;
input.inputs.iter_mut().for_each(|arg| if let FnArg::Typed(arg) = arg {
arg.pat = Box::new(
generate_unique_pattern((*arg.pat).clone(), &mut generated_pattern_counter),
);
input.inputs.iter_mut().for_each(|arg| {
if let FnArg::Typed(arg) = arg {
arg.pat = Box::new(generate_unique_pattern(
(*arg.pat).clone(),
&mut generated_pattern_counter,
));
}
});
}
@@ -101,7 +105,7 @@ pub fn fold_fn_decl_for_client_side(
// Add `&self, at:& BlockId` as parameters to each function at the beginning.
input.inputs.insert(0, parse_quote!( __runtime_api_at_param__: &#block_id ));
input.inputs.insert(0, parse_quote!( &self ));
input.inputs.insert(0, parse_quote!(&self));
// Wrap the output in a `Result`
input.output = {
@@ -114,10 +118,8 @@ pub fn fold_fn_decl_for_client_side(
pub fn generate_unique_pattern(pat: Pat, counter: &mut u32) -> Pat {
match pat {
Pat::Wild(_) => {
let generated_name = Ident::new(
&format!("__runtime_api_generated_name_{}__", counter),
pat.span(),
);
let generated_name =
Ident::new(&format!("__runtime_api_generated_name_{}__", counter), pat.span());
*counter += 1;
parse_quote!( #generated_name )
@@ -145,26 +147,20 @@ pub fn extract_parameter_names_types_and_borrows(
match input {
FnArg::Typed(arg) => {
let (ty, borrow) = match &*arg.ty {
Type::Reference(t) => {
((*t.elem).clone(), Some(t.and_token))
},
t => { (t.clone(), None) },
Type::Reference(t) => ((*t.elem).clone(), Some(t.and_token)),
t => (t.clone(), None),
};
let name = generate_unique_pattern(
(*arg.pat).clone(),
&mut generated_pattern_counter,
);
let name =
generate_unique_pattern((*arg.pat).clone(), &mut generated_pattern_counter);
result.push((name, ty, borrow));
},
FnArg::Receiver(_) if matches!(allow_self, AllowSelfRefInParameters::No) => {
return Err(Error::new(input.span(), "`self` parameter not supported!"))
},
FnArg::Receiver(recv) => {
FnArg::Receiver(_) if matches!(allow_self, AllowSelfRefInParameters::No) =>
return Err(Error::new(input.span(), "`self` parameter not supported!")),
FnArg::Receiver(recv) =>
if recv.mutability.is_some() || recv.reference.is_none() {
return Err(Error::new(recv.span(), "Only `&self` is supported!"))
}
},
},
}
}
@@ -190,7 +186,8 @@ pub fn prefix_function_with_trait<F: ToString>(trait_: &Ident, function: &F) ->
///
/// If a type is a reference, the inner type is extracted (without the reference).
pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec<Type> {
items.iter()
items
.iter()
.filter_map(|i| match i {
ImplItem::Method(method) => Some(&method.sig),
_ => None,
@@ -201,13 +198,17 @@ pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec<Type> {
ReturnType::Type(_, ty) => Some((**ty).clone()),
};
sig.inputs.iter().filter_map(|i| match i {
FnArg::Typed(arg) => Some(&arg.ty),
_ => None,
}).map(|ty| match &**ty {
Type::Reference(t) => (*t.elem).clone(),
_ => (**ty).clone(),
}).chain(ret_ty)
sig.inputs
.iter()
.filter_map(|i| match i {
FnArg::Typed(arg) => Some(&arg.ty),
_ => None,
})
.map(|ty| match &**ty {
Type::Reference(t) => (*t.elem).clone(),
_ => (**ty).clone(),
})
.chain(ret_ty)
})
.collect()
}
@@ -223,19 +224,20 @@ pub fn extract_block_type_from_trait_path(trait_: &Path) -> Result<&TypePath> {
.ok_or_else(|| Error::new(span, "Empty path not supported"))?;
match &generics.arguments {
PathArguments::AngleBracketed(ref args) => {
args.args.first().and_then(|v| match v {
PathArguments::AngleBracketed(ref args) => args
.args
.first()
.and_then(|v| match v {
GenericArgument::Type(Type::Path(ref block)) => Some(block),
_ => None
}).ok_or_else(|| Error::new(args.span(), "Missing `Block` generic parameter."))
},
_ => None,
})
.ok_or_else(|| Error::new(args.span(), "Missing `Block` generic parameter.")),
PathArguments::None => {
let span = trait_.segments.last().as_ref().unwrap().span();
Err(Error::new(span, "Missing `Block` generic parameter."))
},
PathArguments::Parenthesized(_) => {
Err(Error::new(generics.arguments.span(), "Unexpected parentheses in path!"))
},
PathArguments::Parenthesized(_) =>
Err(Error::new(generics.arguments.span(), "Unexpected parentheses in path!")),
}
}
@@ -252,19 +254,20 @@ pub fn extract_impl_trait<'a>(
impl_: &'a ItemImpl,
require: RequireQualifiedTraitPath,
) -> Result<&'a Path> {
impl_.trait_.as_ref().map(|v| &v.1).ok_or_else(
|| Error::new(impl_.span(), "Only implementation of traits are supported!")
).and_then(|p| {
if p.segments.len() > 1 || matches!(require, RequireQualifiedTraitPath::No) {
Ok(p)
} else {
Err(
Error::new(
impl_
.trait_
.as_ref()
.map(|v| &v.1)
.ok_or_else(|| Error::new(impl_.span(), "Only implementation of traits are supported!"))
.and_then(|p| {
if p.segments.len() > 1 || matches!(require, RequireQualifiedTraitPath::No) {
Ok(p)
} else {
Err(Error::new(
p.span(),
"The implemented trait has to be referenced with a path, \
e.g. `impl client::Core for Runtime`."
)
)
}
})
e.g. `impl client::Core for Runtime`.",
))
}
})
}
+47 -48
View File
@@ -70,13 +70,7 @@
extern crate self as sp_api;
#[doc(hidden)]
#[cfg(feature = "std")]
pub use sp_state_machine::{
OverlayedChanges, StorageProof, Backend as StateBackend, ChangesTrieState, InMemoryBackend,
};
#[doc(hidden)]
#[cfg(feature = "std")]
pub use sp_core::NativeOrEncoded;
pub use codec::{self, Decode, DecodeLimit, Encode};
#[doc(hidden)]
#[cfg(feature = "std")]
pub use hash_db::Hasher;
@@ -84,27 +78,34 @@ pub use hash_db::Hasher;
#[cfg(not(feature = "std"))]
pub use sp_core::to_substrate_wasm_fn_return_value;
#[doc(hidden)]
pub use sp_runtime::{
traits::{
Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, HashFor, NumberFor,
Header as HeaderT, Hash as HashT,
},
generic::BlockId, transaction_validity::TransactionValidity, RuntimeString, TransactionOutcome,
};
#[cfg(feature = "std")]
pub use sp_core::NativeOrEncoded;
use sp_core::OpaqueMetadata;
#[doc(hidden)]
pub use sp_core::{offchain, ExecutionContext};
#[doc(hidden)]
pub use sp_version::{ApiId, RuntimeVersion, ApisVec, create_apis_vec};
pub use sp_runtime::{
generic::BlockId,
traits::{
Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, Hash as HashT, HashFor,
Header as HeaderT, NumberFor,
},
transaction_validity::TransactionValidity,
RuntimeString, TransactionOutcome,
};
#[doc(hidden)]
pub use sp_std::{slice, mem};
#[cfg(feature = "std")]
pub use sp_state_machine::{
Backend as StateBackend, ChangesTrieState, InMemoryBackend, OverlayedChanges, StorageProof,
};
#[cfg(feature = "std")]
use sp_std::result;
#[doc(hidden)]
pub use codec::{Encode, Decode, DecodeLimit, self};
use sp_core::OpaqueMetadata;
pub use sp_std::{mem, slice};
#[doc(hidden)]
pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion};
#[cfg(feature = "std")]
use std::{panic::UnwindSafe, cell::RefCell};
use std::{cell::RefCell, panic::UnwindSafe};
/// Maximum nesting level for extrinsics.
pub const MAX_EXTRINSIC_DEPTH: u32 = 256;
@@ -386,18 +387,18 @@ pub type ProofRecorder<B> = sp_state_machine::ProofRecorder<<B as BlockT>::Hash>
/// A type that is used as cache for the storage transactions.
#[cfg(feature = "std")]
pub type StorageTransactionCache<Block, Backend> =
sp_state_machine::StorageTransactionCache<
<Backend as StateBackend<HashFor<Block>>>::Transaction, HashFor<Block>, NumberFor<Block>
>;
pub type StorageTransactionCache<Block, Backend> = sp_state_machine::StorageTransactionCache<
<Backend as StateBackend<HashFor<Block>>>::Transaction,
HashFor<Block>,
NumberFor<Block>,
>;
#[cfg(feature = "std")]
pub type StorageChanges<SBackend, Block> =
sp_state_machine::StorageChanges<
<SBackend as StateBackend<HashFor<Block>>>::Transaction,
HashFor<Block>,
NumberFor<Block>
>;
pub type StorageChanges<SBackend, Block> = sp_state_machine::StorageChanges<
<SBackend as StateBackend<HashFor<Block>>>::Transaction,
HashFor<Block>,
NumberFor<Block>,
>;
/// Extract the state backend type for a type that implements `ProvideRuntimeApi`.
#[cfg(feature = "std")]
@@ -463,29 +464,31 @@ pub trait ApiExt<Block: BlockT> {
/// Depending on the outcome of the closure, the transaction is committed or rolled-back.
///
/// The internal result of the closure is returned afterwards.
fn execute_in_transaction<F: FnOnce(&Self) -> TransactionOutcome<R>, R>(
&self,
call: F,
) -> R where Self: Sized;
fn execute_in_transaction<F: FnOnce(&Self) -> TransactionOutcome<R>, R>(&self, call: F) -> R
where
Self: Sized;
/// Checks if the given api is implemented and versions match.
fn has_api<A: RuntimeApiInfo + ?Sized>(
&self,
at: &BlockId<Block>,
) -> Result<bool, ApiError> where Self: Sized;
fn has_api<A: RuntimeApiInfo + ?Sized>(&self, at: &BlockId<Block>) -> Result<bool, ApiError>
where
Self: Sized;
/// Check if the given api is implemented and the version passes a predicate.
fn has_api_with<A: RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
&self,
at: &BlockId<Block>,
pred: P,
) -> Result<bool, ApiError> where Self: Sized;
) -> Result<bool, ApiError>
where
Self: Sized;
/// Returns the version of the given api.
fn api_version<A: RuntimeApiInfo + ?Sized>(
&self,
at: &BlockId<Block>,
) -> Result<Option<u32>, ApiError> where Self: Sized;
) -> Result<Option<u32>, ApiError>
where
Self: Sized;
/// Start recording all accessed trie nodes for generating proofs.
fn record_proof(&mut self);
@@ -509,10 +512,9 @@ pub trait ApiExt<Block: BlockT> {
backend: &Self::StateBackend,
changes_trie_state: Option<&ChangesTrieState<HashFor<Block>, NumberFor<Block>>>,
parent_hash: Block::Hash,
) -> Result<
StorageChanges<Self::StateBackend, Block>,
String
> where Self: Sized;
) -> Result<StorageChanges<Self::StateBackend, Block>, String>
where
Self: Sized;
}
/// Parameters for [`CallApiAt::call_api_at`].
@@ -557,10 +559,7 @@ pub trait CallApiAt<Block: BlockT> {
) -> Result<NativeOrEncoded<R>, ApiError>;
/// Returns the runtime version at the given block.
fn runtime_version_at(
&self,
at: &BlockId<Block>,
) -> Result<RuntimeVersion, ApiError>;
fn runtime_version_at(&self, at: &BlockId<Block>) -> Result<RuntimeVersion, ApiError>;
}
/// Auxiliary wrapper that holds an api instance and binds it to the given lifetime.
+11 -8
View File
@@ -15,14 +15,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use criterion::{Criterion, criterion_group, criterion_main};
use substrate_test_runtime_client::{
DefaultTestClientBuilderExt, TestClientBuilder,
TestClientBuilderExt, runtime::TestAPI,
};
use criterion::{criterion_group, criterion_main, Criterion};
use sp_api::ProvideRuntimeApi;
use sp_runtime::generic::BlockId;
use sp_state_machine::ExecutionStrategy;
use sp_api::ProvideRuntimeApi;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
fn sp_api_benchmark(c: &mut Criterion) {
c.bench_function("add one with same runtime api", |b| {
@@ -58,13 +57,17 @@ fn sp_api_benchmark(c: &mut Criterion) {
});
c.bench_function("calling function by function pointer in wasm", |b| {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();
let block_id = BlockId::Number(client.chain_info().best_number);
b.iter(|| client.runtime_api().benchmark_indirect_call(&block_id).unwrap())
});
c.bench_function("calling function in wasm", |b| {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();
let block_id = BlockId::Number(client.chain_info().best_number);
b.iter(|| client.runtime_api().benchmark_direct_call(&block_id).unwrap())
});
@@ -16,12 +16,13 @@
// limitations under the License.
use sp_api::{
RuntimeApiInfo, decl_runtime_apis, impl_runtime_apis, mock_impl_runtime_apis,
ApiError,
ApiExt,
decl_runtime_apis, impl_runtime_apis, mock_impl_runtime_apis, ApiError, ApiExt, RuntimeApiInfo,
};
use sp_runtime::{traits::{GetNodeBlockType, Block as BlockT}, generic::BlockId};
use sp_core::NativeOrEncoded;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, GetNodeBlockType},
};
use substrate_test_runtime_client::runtime::Block;
/// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType`
@@ -142,16 +143,22 @@ type TestClient = substrate_test_runtime_client::client::Client<
#[test]
fn test_client_side_function_signature() {
let _test: fn(&RuntimeApiImpl<Block, TestClient>, &BlockId<Block>, u64) -> Result<(), ApiError> =
RuntimeApiImpl::<Block, TestClient>::test;
let _something_with_block:
fn(&RuntimeApiImpl<Block, TestClient>, &BlockId<Block>, Block) -> Result<Block, ApiError> =
RuntimeApiImpl::<Block, TestClient>::something_with_block;
let _test: fn(
&RuntimeApiImpl<Block, TestClient>,
&BlockId<Block>,
u64,
) -> Result<(), ApiError> = RuntimeApiImpl::<Block, TestClient>::test;
let _something_with_block: fn(
&RuntimeApiImpl<Block, TestClient>,
&BlockId<Block>,
Block,
) -> Result<Block, ApiError> = RuntimeApiImpl::<Block, TestClient>::something_with_block;
#[allow(deprecated)]
let _same_name_before_version_2:
fn(&RuntimeApiImpl<Block, TestClient>, &BlockId<Block>) -> Result<String, ApiError> =
RuntimeApiImpl::<Block, TestClient>::same_name_before_version_2;
let _same_name_before_version_2: fn(
&RuntimeApiImpl<Block, TestClient>,
&BlockId<Block>,
) -> Result<String, ApiError> = RuntimeApiImpl::<Block, TestClient>::same_name_before_version_2;
}
#[test]
@@ -186,9 +193,7 @@ fn check_runtime_api_versions() {
fn mock_runtime_api_has_api() {
let mock = MockApi { block: None };
assert!(
mock.has_api::<dyn ApiWithCustomVersion<Block>>(&BlockId::Number(0)).unwrap(),
);
assert!(mock.has_api::<dyn ApiWithCustomVersion<Block>>(&BlockId::Number(0)).unwrap(),);
assert!(mock.has_api::<dyn Api<Block>>(&BlockId::Number(0)).unwrap());
}
@@ -15,21 +15,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use sp_api::{ProvideRuntimeApi, Core};
use sp_api::{Core, ProvideRuntimeApi};
use sp_runtime::{
generic::BlockId,
traits::{HashFor, Header as HeaderT},
};
use sp_state_machine::{
create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionStrategy,
};
use substrate_test_runtime_client::{
prelude::*,
runtime::{Block, DecodeFails, Header, TestAPI, Transfer},
DefaultTestClientBuilderExt, TestClientBuilder,
runtime::{TestAPI, DecodeFails, Transfer, Block, Header},
};
use sp_runtime::{generic::BlockId, traits::{Header as HeaderT, HashFor}};
use sp_state_machine::{
ExecutionStrategy, create_proof_check_backend,
execution_proof_check_on_trie_backend,
};
use sp_consensus::SelectChain;
use codec::Encode;
use sc_block_builder::BlockBuilderProvider;
use sp_consensus::SelectChain;
fn calling_function_with_strat(strat: ExecutionStrategy) {
let client = TestClientBuilder::new().set_execution_strategy(strat).build();
@@ -52,7 +54,9 @@ fn calling_wasm_runtime_function() {
#[test]
#[should_panic(expected = "FailedToConvertParameter { function: \"fail_convert_parameter\"")]
fn calling_native_runtime_function_with_non_decodable_parameter() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::NativeWhenPossible)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
runtime_api.fail_convert_parameter(&block_id, DecodeFails::new()).unwrap();
@@ -61,7 +65,9 @@ fn calling_native_runtime_function_with_non_decodable_parameter() {
#[test]
#[should_panic(expected = "FailedToConvertReturnValue { function: \"fail_convert_return_value\"")]
fn calling_native_runtime_function_with_non_decodable_return_value() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::NativeWhenPossible)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
runtime_api.fail_convert_return_value(&block_id).unwrap();
@@ -69,7 +75,9 @@ fn calling_native_runtime_function_with_non_decodable_return_value() {
#[test]
fn calling_native_runtime_signature_changed_function() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeWhenPossible).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::NativeWhenPossible)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
@@ -78,7 +86,9 @@ fn calling_native_runtime_signature_changed_function() {
#[test]
fn calling_wasm_runtime_signature_changed_old_function() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
@@ -103,10 +113,11 @@ fn calling_with_both_strategy_and_fail_on_native_should_work() {
assert_eq!(runtime_api.fail_on_native(&block_id).unwrap(), 1);
}
#[test]
fn calling_with_native_else_wasm_and_fail_on_wasm_should_work() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeElseWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::NativeElseWasm)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
assert_eq!(runtime_api.fail_on_wasm(&block_id).unwrap(), 1);
@@ -114,7 +125,9 @@ fn calling_with_native_else_wasm_and_fail_on_wasm_should_work() {
#[test]
fn calling_with_native_else_wasm_and_fail_on_native_should_work() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::NativeElseWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::NativeElseWasm)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
assert_eq!(runtime_api.fail_on_native(&block_id).unwrap(), 1);
@@ -122,7 +135,9 @@ fn calling_with_native_else_wasm_and_fail_on_native_should_work() {
#[test]
fn use_trie_function() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm).build();
let client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
assert_eq!(runtime_api.use_trie(&block_id).unwrap(), 2);
@@ -133,10 +148,18 @@ fn initialize_block_works() {
let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build();
let runtime_api = client.runtime_api();
let block_id = BlockId::Number(client.chain_info().best_number);
runtime_api.initialize_block(
&block_id,
&Header::new(1, Default::default(), Default::default(), Default::default(), Default::default()),
).unwrap();
runtime_api
.initialize_block(
&block_id,
&Header::new(
1,
Default::default(),
Default::default(),
Default::default(),
Default::default(),
),
)
.unwrap();
assert_eq!(runtime_api.get_block_number(&block_id).unwrap(), 1);
}
@@ -165,7 +188,8 @@ fn record_proof_works() {
nonce: 0,
from: AccountKeyring::Alice.into(),
to: Default::default(),
}.into_signed_tx();
}
.into_signed_tx();
// Build the block and record proof
let mut builder = client
@@ -177,15 +201,12 @@ fn record_proof_works() {
let backend = create_proof_check_backend::<HashFor<Block>>(
storage_root,
proof.expect("Proof was generated"),
).expect("Creates proof backend.");
)
.expect("Creates proof backend.");
// Use the proof backend to execute `execute_block`.
let mut overlay = Default::default();
let executor = NativeExecutor::<LocalExecutor>::new(
WasmExecutionMethod::Interpreted,
None,
8,
);
let executor = NativeExecutor::<LocalExecutor>::new(WasmExecutionMethod::Interpreted, None, 8);
execution_proof_check_on_trie_backend::<_, u64, _, _>(
&backend,
&mut overlay,
@@ -194,7 +215,8 @@ fn record_proof_works() {
"Core_execute_block",
&block.encode(),
&runtime_code,
).expect("Executes block while using the proof backend");
)
.expect("Executes block while using the proof backend");
}
#[test]
@@ -203,7 +225,8 @@ fn call_runtime_api_with_multiple_arguments() {
let data = vec![1, 2, 4, 5, 6, 7, 8, 8, 10, 12];
let block_id = BlockId::Number(client.chain_info().best_number);
client.runtime_api()
client
.runtime_api()
.test_multiple_arguments(&block_id, data.clone(), data.clone(), data.len() as u32)
.unwrap();
}
@@ -213,8 +236,8 @@ fn disable_logging_works() {
if std::env::var("RUN_TEST").is_ok() {
sp_tracing::try_init_simple();
let mut builder = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm);
let mut builder =
TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::AlwaysWasm);
builder.genesis_init_mut().set_wasm_code(
substrate_test_runtime_client::runtime::wasm_binary_logging_disabled_unwrap().to_vec(),
);
@@ -17,7 +17,7 @@
//! Ecdsa crypto types.
use crate::{RuntimePublic, KeyTypeId};
use crate::{KeyTypeId, RuntimePublic};
use sp_std::vec::Vec;
@@ -33,9 +33,9 @@ mod app {
}
}
pub use app::{Public as AppPublic, Signature as AppSignature};
#[cfg(feature = "full_crypto")]
pub use app::Pair as AppPair;
pub use app::{Public as AppPublic, Signature as AppSignature};
impl RuntimePublic for Public {
type Signature = Signature;
@@ -17,7 +17,7 @@
//! Ed25519 crypto types.
use crate::{RuntimePublic, KeyTypeId};
use crate::{KeyTypeId, RuntimePublic};
use sp_std::vec::Vec;
@@ -33,9 +33,9 @@ mod app {
}
}
pub use app::{Public as AppPublic, Signature as AppSignature};
#[cfg(feature = "full_crypto")]
pub use app::Pair as AppPair;
pub use app::{Public as AppPublic, Signature as AppSignature};
impl RuntimePublic for Public {
type Signature = Signature;
@@ -18,15 +18,18 @@
//! Traits and macros for constructing application specific strongly typed crypto wrappers.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#[doc(hidden)]
pub use sp_core::{self, crypto::{CryptoType, CryptoTypePublicPair, Public, Derive, IsWrappedBy, Wraps}, RuntimeDebug};
pub use sp_core::crypto::{key_types, CryptoTypeId, KeyTypeId};
#[doc(hidden)]
#[cfg(feature = "full_crypto")]
pub use sp_core::crypto::{SecretStringError, DeriveJunction, Ss58Codec, Pair};
pub use sp_core::crypto::{KeyTypeId, CryptoTypeId, key_types};
pub use sp_core::crypto::{DeriveJunction, Pair, SecretStringError, Ss58Codec};
#[doc(hidden)]
pub use sp_core::{
self,
crypto::{CryptoType, CryptoTypePublicPair, Derive, IsWrappedBy, Public, Wraps},
RuntimeDebug,
};
#[doc(hidden)]
pub use codec;
@@ -34,15 +37,11 @@ pub use codec;
#[cfg(feature = "std")]
pub use serde;
#[doc(hidden)]
pub use sp_std::{
convert::TryFrom,
ops::Deref,
vec::Vec,
};
pub use sp_std::{convert::TryFrom, ops::Deref, vec::Vec};
pub mod ecdsa;
pub mod ed25519;
pub mod sr25519;
pub mod ecdsa;
mod traits;
pub use traits::*;
@@ -51,7 +50,7 @@ pub use traits::*;
/// Application-specific types whose identifier is `$key_type`.
///
/// ```rust
///# use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId};
/// # use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId};
/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId`
/// // of value `b"fuba"`.
/// app_crypto!(ed25519, KeyTypeId(*b"_uba"));
@@ -61,8 +60,17 @@ pub use traits::*;
macro_rules! app_crypto {
($module:ident, $key_type:expr) => {
$crate::app_crypto_public_full_crypto!($module::Public, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_public_common!($module::Public, $module::Signature, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_signature_full_crypto!($module::Signature, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_public_common!(
$module::Public,
$module::Signature,
$key_type,
$module::CRYPTO_ID
);
$crate::app_crypto_signature_full_crypto!(
$module::Signature,
$key_type,
$module::CRYPTO_ID
);
$crate::app_crypto_signature_common!($module::Signature, $key_type);
$crate::app_crypto_pair!($module::Pair, $key_type, $module::CRYPTO_ID);
};
@@ -72,7 +80,7 @@ macro_rules! app_crypto {
/// Application-specific types whose identifier is `$key_type`.
///
/// ```rust
///# use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId};
/// # use sp_application_crypto::{app_crypto, wrap, ed25519, KeyTypeId};
/// // Declare a new set of crypto types using Ed25519 logic that identifies as `KeyTypeId`
/// // of value `b"fuba"`.
/// app_crypto!(ed25519, KeyTypeId(*b"_uba"));
@@ -82,8 +90,17 @@ macro_rules! app_crypto {
macro_rules! app_crypto {
($module:ident, $key_type:expr) => {
$crate::app_crypto_public_not_full_crypto!($module::Public, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_public_common!($module::Public, $module::Signature, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_signature_not_full_crypto!($module::Signature, $key_type, $module::CRYPTO_ID);
$crate::app_crypto_public_common!(
$module::Public,
$module::Signature,
$key_type,
$module::CRYPTO_ID
);
$crate::app_crypto_signature_not_full_crypto!(
$module::Signature,
$key_type,
$module::CRYPTO_ID
);
$crate::app_crypto_signature_common!($module::Signature, $key_type);
};
}
@@ -93,7 +110,7 @@ macro_rules! app_crypto {
#[macro_export]
macro_rules! app_crypto_pair {
($pair:ty, $key_type:expr, $crypto_type:expr) => {
$crate::wrap!{
$crate::wrap! {
/// A generic `AppPublic` wrapper type over $pair crypto; this has no specific App.
#[derive(Clone)]
pub struct Pair($pair);
@@ -111,12 +128,16 @@ macro_rules! app_crypto_pair {
$crate::app_crypto_pair_functions_if_std!($pair);
fn derive<
Iter: Iterator<Item=$crate::DeriveJunction>
>(&self, path: Iter, seed: Option<Self::Seed>) -> Result<(Self, Option<Self::Seed>), Self::DeriveError> {
fn derive<Iter: Iterator<Item = $crate::DeriveJunction>>(
&self,
path: Iter,
seed: Option<Self::Seed>,
) -> Result<(Self, Option<Self::Seed>), Self::DeriveError> {
self.0.derive(path, seed).map(|x| (Self(x.0), x.1))
}
fn from_seed(seed: &Self::Seed) -> Self { Self(<$pair>::from_seed(seed)) }
fn from_seed(seed: &Self::Seed) -> Self {
Self(<$pair>::from_seed(seed))
}
fn from_seed_slice(seed: &[u8]) -> Result<Self, $crate::SecretStringError> {
<$pair>::from_seed_slice(seed).map(Self)
}
@@ -137,8 +158,12 @@ macro_rules! app_crypto_pair {
) -> bool {
<$pair>::verify_weak(sig, message, pubkey)
}
fn public(&self) -> Self::Public { Public(self.0.public()) }
fn to_raw_vec(&self) -> $crate::Vec<u8> { self.0.to_raw_vec() }
fn public(&self) -> Self::Public {
Public(self.0.public())
}
fn to_raw_vec(&self) -> $crate::Vec<u8> {
self.0.to_raw_vec()
}
}
impl $crate::AppKey for Pair {
@@ -167,22 +192,22 @@ macro_rules! app_crypto_pair_functions_if_std {
(Self(r.0), r.1, r.2)
}
fn from_phrase(phrase: &str, password: Option<&str>)
-> Result<(Self, Self::Seed), $crate::SecretStringError>
{
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, Self::Seed), $crate::SecretStringError> {
<$pair>::from_phrase(phrase, password).map(|r| (Self(r.0), r.1))
}
}
};
}
#[doc(hidden)]
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! app_crypto_pair_functions_if_std {
($pair:ty) => {}
($pair:ty) => {};
}
/// Declares Public type which is functionally equivalent to `$public`, but is new
/// Application-specific type whose identifier is `$key_type`.
/// can only be used together with `full_crypto` feature
@@ -191,7 +216,7 @@ macro_rules! app_crypto_pair_functions_if_std {
#[macro_export]
macro_rules! app_crypto_public_full_crypto {
($public:ty, $key_type:expr, $crypto_type:expr) => {
$crate::wrap!{
$crate::wrap! {
/// A generic `AppPublic` wrapper type over $public crypto; this has no specific App.
#[derive(
Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord,
@@ -216,7 +241,7 @@ macro_rules! app_crypto_public_full_crypto {
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
}
}
};
}
/// Declares Public type which is functionally equivalent to `$public`, but is new
@@ -227,7 +252,7 @@ macro_rules! app_crypto_public_full_crypto {
#[macro_export]
macro_rules! app_crypto_public_not_full_crypto {
($public:ty, $key_type:expr, $crypto_type:expr) => {
$crate::wrap!{
$crate::wrap! {
/// A generic `AppPublic` wrapper type over $public crypto; this has no specific App.
#[derive(
Clone, Default, Eq, PartialEq, Ord, PartialOrd,
@@ -247,7 +272,7 @@ macro_rules! app_crypto_public_not_full_crypto {
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
}
}
};
}
/// Declares Public type which is functionally equivalent to `$public`, but is new
@@ -260,15 +285,21 @@ macro_rules! app_crypto_public_common {
$crate::app_crypto_public_common_if_std!();
impl AsRef<[u8]> for Public {
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl AsMut<[u8]> for Public {
fn as_mut(&mut self) -> &mut [u8] { self.0.as_mut() }
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}
impl $crate::Public for Public {
fn from_slice(x: &[u8]) -> Self { Self(<$public>::from_slice(x)) }
fn from_slice(x: &[u8]) -> Self {
Self(<$public>::from_slice(x))
}
fn to_public_crypto_pair(&self) -> $crate::CryptoTypePublicPair {
$crate::CryptoTypePublicPair($crypto_type, self.to_raw_vec())
@@ -279,14 +310,20 @@ macro_rules! app_crypto_public_common {
type Generic = $public;
}
impl $crate::RuntimeAppPublic for Public where $public: $crate::RuntimePublic<Signature=$sig> {
impl $crate::RuntimeAppPublic for Public
where
$public: $crate::RuntimePublic<Signature = $sig>,
{
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
type Signature = Signature;
fn all() -> $crate::Vec<Self> {
<$public as $crate::RuntimePublic>::all($key_type).into_iter().map(Self).collect()
<$public as $crate::RuntimePublic>::all($key_type)
.into_iter()
.map(Self)
.collect()
}
fn generate_pair(seed: Option<$crate::Vec<u8>>) -> Self {
@@ -294,11 +331,8 @@ macro_rules! app_crypto_public_common {
}
fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature> {
<$public as $crate::RuntimePublic>::sign(
self.as_ref(),
$key_type,
msg,
).map(Signature)
<$public as $crate::RuntimePublic>::sign(self.as_ref(), $key_type, msg)
.map(Signature)
}
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
@@ -318,10 +352,7 @@ macro_rules! app_crypto_public_common {
impl From<&Public> for $crate::CryptoTypePublicPair {
fn from(key: &Public) -> Self {
$crate::CryptoTypePublicPair(
$crypto_type,
$crate::Public::to_raw_vec(key),
)
$crate::CryptoTypePublicPair($crypto_type, $crate::Public::to_raw_vec(key))
}
}
@@ -332,7 +363,7 @@ macro_rules! app_crypto_public_common {
<$public>::try_from(data).map(Into::into)
}
}
}
};
}
/// Implements traits for the public key type if `feature = "std"` is enabled.
@@ -342,8 +373,9 @@ macro_rules! app_crypto_public_common {
macro_rules! app_crypto_public_common_if_std {
() => {
impl $crate::Derive for Public {
fn derive<Iter: Iterator<Item=$crate::DeriveJunction>>(&self,
path: Iter
fn derive<Iter: Iterator<Item = $crate::DeriveJunction>>(
&self,
path: Iter,
) -> Option<Self> {
self.0.derive(path).map(Self)
}
@@ -357,8 +389,9 @@ macro_rules! app_crypto_public_common_if_std {
}
impl $crate::serde::Serialize for Public {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where
S: $crate::serde::Serializer
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer,
{
use $crate::Ss58Codec;
serializer.serialize_str(&self.to_ss58check())
@@ -366,15 +399,16 @@ macro_rules! app_crypto_public_common_if_std {
}
impl<'de> $crate::serde::Deserialize<'de> for Public {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> where
D: $crate::serde::Deserializer<'de>
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: $crate::serde::Deserializer<'de>,
{
use $crate::Ss58Codec;
Public::from_ss58check(&String::deserialize(deserializer)?)
.map_err(|e| $crate::serde::de::Error::custom(format!("{:?}", e)))
}
}
}
};
}
#[cfg(not(feature = "std"))]
@@ -383,10 +417,9 @@ macro_rules! app_crypto_public_common_if_std {
macro_rules! app_crypto_public_common_if_std {
() => {
impl $crate::Derive for Public {}
}
};
}
/// Declares Signature type which is functionally equivalent to `$sig`, but is new
/// Application-specific type whose identifier is `$key_type`.
/// can only be used together with `full_crypto` feature
@@ -418,7 +451,7 @@ macro_rules! app_crypto_signature_full_crypto {
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
}
}
};
}
/// Declares Signature type which is functionally equivalent to `$sig`, but is new
@@ -448,7 +481,7 @@ macro_rules! app_crypto_signature_not_full_crypto {
const ID: $crate::KeyTypeId = $key_type;
const CRYPTO_ID: $crate::CryptoTypeId = $crypto_type;
}
}
};
}
/// Declares Signature type which is functionally equivalent to `$sig`, but is new
@@ -461,11 +494,15 @@ macro_rules! app_crypto_signature_common {
impl $crate::Deref for Signature {
type Target = [u8];
fn deref(&self) -> &Self::Target { self.0.as_ref() }
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] { self.0.as_ref() }
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl $crate::AppSignature for Signature {
@@ -479,7 +516,7 @@ macro_rules! app_crypto_signature_common {
Ok(<$sig>::try_from(data.as_slice())?.into())
}
}
}
};
}
/// Implement bidirectional `From` and on-way `AsRef`/`AsMut` for two types, `$inner` and `$outer`.
@@ -547,10 +584,9 @@ macro_rules! with_pair {
}
}
#[doc(hidden)]
#[macro_export]
#[cfg(all(not(feature = "std"), not(feature = "full_crypto")))]
macro_rules! with_pair {
( $( $def:tt )* ) => {}
( $( $def:tt )* ) => {};
}
@@ -17,7 +17,7 @@
//! Sr25519 crypto types.
use crate::{RuntimePublic, KeyTypeId};
use crate::{KeyTypeId, RuntimePublic};
use sp_std::vec::Vec;
@@ -33,9 +33,9 @@ mod app {
}
}
pub use app::{Public as AppPublic, Signature as AppSignature};
#[cfg(feature = "full_crypto")]
pub use app::Pair as AppPair;
pub use app::{Public as AppPublic, Signature as AppSignature};
impl RuntimePublic for Public {
type Signature = Signature;
@@ -19,7 +19,7 @@
use sp_core::crypto::Pair;
use codec::Codec;
use sp_core::crypto::{KeyTypeId, CryptoType, CryptoTypeId, IsWrappedBy, Public};
use sp_core::crypto::{CryptoType, CryptoTypeId, IsWrappedBy, KeyTypeId, Public};
use sp_std::{fmt::Debug, vec::Vec};
/// An application-specific key.
@@ -57,7 +57,7 @@ impl<T> MaybeHash for T {}
/// Type which implements Debug and Hash in std, not when no-std (no-std variant with crypto).
#[cfg(all(not(feature = "std"), feature = "full_crypto"))]
pub trait MaybeDebugHash: sp_std::hash::Hash {}
pub trait MaybeDebugHash: sp_std::hash::Hash {}
#[cfg(all(not(feature = "std"), feature = "full_crypto"))]
impl<T: sp_std::hash::Hash> MaybeDebugHash for T {}
@@ -66,15 +66,23 @@ pub trait AppPublic:
AppKey + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec
{
/// The wrapped type which is just a plain instance of `Public`.
type Generic:
IsWrappedBy<Self> + Public + Ord + PartialOrd + Eq + PartialEq + Debug + MaybeHash + codec::Codec;
type Generic: IsWrappedBy<Self>
+ Public
+ Ord
+ PartialOrd
+ Eq
+ PartialEq
+ Debug
+ MaybeHash
+ codec::Codec;
}
/// A application's key pair.
#[cfg(feature = "full_crypto")]
pub trait AppPair: AppKey + Pair<Public=<Self as AppKey>::Public> {
pub trait AppPair: AppKey + Pair<Public = <Self as AppKey>::Public> {
/// The wrapped type which is just a plain instance of `Pair`.
type Generic: IsWrappedBy<Self> + Pair<Public = <<Self as AppKey>::Public as AppPublic>::Generic>;
type Generic: IsWrappedBy<Self>
+ Pair<Public = <<Self as AppKey>::Public as AppPublic>::Generic>;
}
/// A application's signature.
@@ -16,28 +16,22 @@
// limitations under the License.
//! Integration tests for ecdsa
use std::sync::Arc;
use sp_runtime::generic::BlockId;
use sp_core::{
crypto::Pair,
testing::ECDSA,
};
use sp_keystore::{
SyncCryptoStore,
testing::KeyStore,
};
use substrate_test_runtime_client::{
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
runtime::TestAPI,
};
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ecdsa::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ECDSA};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_runtime::generic::BlockId;
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
#[test]
fn ecdsa_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client.runtime_api()
let (signature, public) = test_client
.runtime_api()
.test_ecdsa_crypto(&BlockId::Number(0))
.expect("Tests `ecdsa` crypto.");
@@ -17,28 +17,22 @@
//! Integration tests for ed25519
use std::sync::Arc;
use sp_runtime::generic::BlockId;
use sp_core::{
crypto::Pair,
testing::ED25519,
};
use sp_keystore::{
SyncCryptoStore,
testing::KeyStore,
};
use substrate_test_runtime_client::{
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
runtime::TestAPI,
};
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::ed25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::ED25519};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_runtime::generic::BlockId;
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
#[test]
fn ed25519_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client.runtime_api()
let (signature, public) = test_client
.runtime_api()
.test_ed25519_crypto(&BlockId::Number(0))
.expect("Tests `ed25519` crypto.");
@@ -17,9 +17,9 @@
//! Integration tests for application crypto
#[cfg(test)]
mod ecdsa;
#[cfg(test)]
mod ed25519;
#[cfg(test)]
mod sr25519;
#[cfg(test)]
mod ecdsa;
@@ -17,28 +17,22 @@
//! Integration tests for sr25519
use std::sync::Arc;
use sp_runtime::generic::BlockId;
use sp_core::{
crypto::Pair,
testing::SR25519,
};
use sp_keystore::{
SyncCryptoStore,
testing::KeyStore,
};
use substrate_test_runtime_client::{
TestClientBuilder, DefaultTestClientBuilderExt, TestClientBuilderExt,
runtime::TestAPI,
};
use sp_api::ProvideRuntimeApi;
use sp_application_crypto::sr25519::{AppPair, AppPublic};
use sp_core::{crypto::Pair, testing::SR25519};
use sp_keystore::{testing::KeyStore, SyncCryptoStore};
use sp_runtime::generic::BlockId;
use std::sync::Arc;
use substrate_test_runtime_client::{
runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
};
#[test]
fn sr25519_works_in_runtime() {
let keystore = Arc::new(KeyStore::new());
let test_client = TestClientBuilder::new().set_keystore(keystore.clone()).build();
let (signature, public) = test_client.runtime_api()
let (signature, public) = test_client
.runtime_api()
.test_sr25519_crypto(&BlockId::Number(0))
.expect("Tests `sr25519` crypto.");
@@ -15,9 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use criterion::{Criterion, Throughput, BenchmarkId, criterion_group, criterion_main};
use sp_arithmetic::biguint::{BigUint, Single};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use rand::Rng;
use sp_arithmetic::biguint::{BigUint, Single};
fn random_big_uint(size: usize) -> BigUint {
let mut rng = rand::thread_rng();
@@ -73,7 +73,7 @@ fn bench_division(c: &mut Criterion) {
}
}
criterion_group!{
criterion_group! {
name = benches;
config = Criterion::default();
targets = bench_addition, bench_subtraction, bench_multiplication, bench_division
@@ -60,8 +60,13 @@ fn main() {
let expected = ue.unwrap() + ve.unwrap();
let t = u.clone().add(&v);
assert_eq!(
u128::try_from(t.clone()).unwrap(), expected,
"{:?} + {:?} ===> {:?} != {:?}", u, v, t, expected,
u128::try_from(t.clone()).unwrap(),
expected,
"{:?} + {:?} ===> {:?} != {:?}",
u,
v,
t,
expected,
);
}
@@ -74,8 +79,13 @@ fn main() {
let t = t.unwrap();
let expected = expected.unwrap();
assert_eq!(
u128::try_from(t.clone()).unwrap(), expected,
"{:?} - {:?} ===> {:?} != {:?}", u, v, t, expected,
u128::try_from(t.clone()).unwrap(),
expected,
"{:?} - {:?} ===> {:?} != {:?}",
u,
v,
t,
expected,
);
}
}
@@ -84,31 +94,51 @@ fn main() {
let expected = ue.unwrap() * ve.unwrap();
let t = u.clone().mul(&v);
assert_eq!(
u128::try_from(t.clone()).unwrap(), expected,
"{:?} * {:?} ===> {:?} != {:?}", u, v, t, expected,
u128::try_from(t.clone()).unwrap(),
expected,
"{:?} * {:?} ===> {:?} != {:?}",
u,
v,
t,
expected,
);
}
if check_digit_lengths(&u, &v, 4) {
let (ue, ve) = (ue.unwrap(), ve.unwrap());
if ve == 0 {
return;
return
}
let (q, r) = (ue / ve, ue % ve);
if let Some((qq, rr)) = u.clone().div(&v, true) {
assert_eq!(
u128::try_from(qq.clone()).unwrap(), q,
"{:?} / {:?} ===> {:?} != {:?}", u, v, qq, q,
u128::try_from(qq.clone()).unwrap(),
q,
"{:?} / {:?} ===> {:?} != {:?}",
u,
v,
qq,
q,
);
assert_eq!(
u128::try_from(rr.clone()).unwrap(), r,
"{:?} % {:?} ===> {:?} != {:?}", u, v, rr, r,
u128::try_from(rr.clone()).unwrap(),
r,
"{:?} % {:?} ===> {:?} != {:?}",
u,
v,
rr,
r,
);
} else if v.len() == 1 {
let qq = u.clone().div_unit(ve as Single);
assert_eq!(
u128::try_from(qq.clone()).unwrap(), q,
"[single] {:?} / {:?} ===> {:?} != {:?}", u, v, qq, q,
u128::try_from(qq.clone()).unwrap(),
q,
"[single] {:?} / {:?} ===> {:?} != {:?}",
u,
v,
qq,
q,
);
} else if v.msb() != 0 && u.msb() != 0 && u.len() > v.len() {
panic!("div returned none for an unexpected reason");
@@ -175,7 +205,7 @@ fn assert_biguints_eq(a: &BigUint, b: &num_bigint::BigUint) {
// `num_bigint::BigUint` doesn't expose it's internals, so we need to convert into that to
// compare.
let limbs = (0 .. a.len()).map(|i| a.get(i)).collect();
let limbs = (0..a.len()).map(|i| a.get(i)).collect();
let num_a = num_bigint::BigUint::new(limbs);
assert!(&num_a == b, "\narithmetic: {:?}\nnum-bigint: {:?}", a, b);
@@ -28,7 +28,7 @@
//! [here](https://docs.rs/honggfuzz/).
use honggfuzz::fuzz;
use sp_arithmetic::{FixedPointNumber, FixedI64, traits::Saturating};
use sp_arithmetic::{traits::Saturating, FixedI64, FixedPointNumber};
fn main() {
loop {
@@ -38,7 +38,8 @@ fn main() {
// Check `from_rational` and division are consistent.
if y != 0 {
let f1 = FixedI64::saturating_from_integer(x) / FixedI64::saturating_from_integer(y);
let f1 =
FixedI64::saturating_from_integer(x) / FixedI64::saturating_from_integer(y);
let f2 = FixedI64::saturating_from_rational(x, y);
assert_eq!(f1.into_inner(), f2.into_inner());
}
@@ -75,7 +76,8 @@ fn main() {
let a = FixedI64::saturating_from_rational(2, 5);
let b = a.saturating_mul_acc_int(x);
let xx = FixedI64::saturating_from_integer(x);
let d = a.saturating_mul(xx).saturating_add(xx).into_inner() as i128 / FixedI64::accuracy() as i128;
let d = a.saturating_mul(xx).saturating_add(xx).into_inner() as i128 /
FixedI64::accuracy() as i128;
assert_eq!(b, d);
});
}
@@ -60,7 +60,7 @@ fn main() {
fn mul_div(a: u128, b: u128, c: u128) -> u128 {
use primitive_types::U256;
if a.is_zero() {
return Zero::zero();
return Zero::zero()
}
let c = c.max(1);
@@ -15,7 +15,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! # Running
//! Running this fuzzer can be done with `cargo hfuzz run normalize`. `honggfuzz` CLI options can
//! be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
@@ -37,7 +36,9 @@ fn main() {
loop {
fuzz!(|data: (Vec<Ty>, Ty)| {
let (data, norm) = data;
if data.len() == 0 { return; }
if data.len() == 0 {
return
}
let pre_sum: u128 = data.iter().map(|x| *x as u128).sum();
let normalized = data.normalize(norm);
@@ -50,13 +51,7 @@ fn main() {
let sum: u128 = normalized.iter().map(|x| *x as u128).sum();
// if this function returns Ok(), then it will ALWAYS be accurate.
assert_eq!(
sum,
norm as u128,
"sums don't match {:?}, {}",
normalized,
norm,
);
assert_eq!(sum, norm as u128, "sums don't match {:?}, {}", normalized, norm,);
} else {
panic!("Should have returned Ok for input = {:?}, target = {:?}", data, norm);
}
@@ -24,16 +24,11 @@
//! `cargo hfuzz run-debug per_thing_rational hfuzz_workspace/per_thing_rational/*.fuzz`.
use honggfuzz::fuzz;
use sp_arithmetic::{
PerThing, PerU16, Percent, Perbill, Perquintill, traits::SaturatedConversion,
};
use sp_arithmetic::{traits::SaturatedConversion, PerThing, PerU16, Perbill, Percent, Perquintill};
fn main() {
loop {
fuzz!(|
data: ((u16, u16), (u32, u32), (u64, u64))
| {
fuzz!(|data: ((u16, u16), (u32, u32), (u64, u64))| {
let (u16_pair, u32_pair, u64_pair) = data;
// peru16
@@ -109,7 +104,6 @@ fn main() {
Perquintill::from_float(smaller as f64 / bigger.max(1) as f64),
1000,
);
})
}
}
+44 -52
View File
@@ -7,7 +7,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,9 +17,9 @@
//! Infinite precision unsigned integer for substrate runtime.
use num_traits::{Zero, One};
use sp_std::{cmp::Ordering, ops, prelude::*, vec, cell::RefCell, convert::TryFrom};
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use num_traits::{One, Zero};
use sp_std::{cell::RefCell, cmp::Ordering, convert::TryFrom, ops, prelude::*, vec};
// A sensible value for this would be half of the dword size of the host machine. Since the
// runtime is compiled to 32bit webassembly, using 32 and 64 for single and double respectively
@@ -105,7 +105,9 @@ impl BigUint {
}
/// Number of limbs.
pub fn len(&self) -> usize { self.digits.len() }
pub fn len(&self) -> usize {
self.digits.len()
}
/// A naive getter for limb at `index`. Note that the order is lsb -> msb.
///
@@ -156,7 +158,9 @@ impl BigUint {
// by definition, a big-int number should never have leading zero limbs. This function
// has the ability to cause this. There is nothing to do if the number already has 1
// limb only. call it a day and return.
if self.len().is_zero() { return; }
if self.len().is_zero() {
return
}
let index = self.digits.iter().position(|&elem| elem != 0).unwrap_or(self.len() - 1);
if index > 0 {
@@ -168,7 +172,9 @@ impl BigUint {
/// is already bigger than `size` limbs.
pub fn lpad(&mut self, size: usize) {
let n = self.len();
if n >= size { return; }
if n >= size {
return
}
let pad = size - n;
let mut new_digits = (0..pad).map(|_| 0).collect::<Vec<Single>>();
new_digits.extend(self.digits.iter());
@@ -260,15 +266,15 @@ impl BigUint {
if self.get(j) == 0 {
// Note: `with_capacity` allocates with 0. Explicitly set j + m to zero if
// otherwise.
continue;
continue
}
let mut k = 0;
for i in 0..m {
// PROOF: (B1) × (B1) + (B1) + (B1) = B^2 1 < B^2. addition is safe.
let t = mul_single(self.get(j), other.get(i))
+ Double::from(w.get(i + j))
+ Double::from(k);
let t = mul_single(self.get(j), other.get(i)) +
Double::from(w.get(i + j)) +
Double::from(k);
w.set(i + j, (t % B) as Single);
// PROOF: (B^2 - 1) / B < B. conversion is safe.
k = (t / B) as Single;
@@ -288,9 +294,9 @@ impl BigUint {
let mut out = Self::with_capacity(n);
let mut r: Single = 0;
// PROOF: (B-1) * B + (B-1) still fits in double
let with_r = |x: Single, r: Single| { Double::from(r) * B + Double::from(x) };
let with_r = |x: Single, r: Single| Double::from(r) * B + Double::from(x);
for d in (0..n).rev() {
let (q, rr) = div_single(with_r(self.get(d), r), other) ;
let (q, rr) = div_single(with_r(self.get(d), r), other);
out.set(d, q as Single);
r = rr;
}
@@ -311,11 +317,7 @@ impl BigUint {
///
/// Taken from "The Art of Computer Programming" by D.E. Knuth, vol 2, chapter 4.
pub fn div(self, other: &Self, rem: bool) -> Option<(Self, Self)> {
if other.len() <= 1
|| other.msb() == 0
|| self.msb() == 0
|| self.len() <= other.len()
{
if other.len() <= 1 || other.msb() == 0 || self.msb() == 0 || self.len() <= other.len() {
return None
}
let n = other.len();
@@ -344,9 +346,7 @@ impl BigUint {
// PROOF: this always fits into `Double`. In the context of Single = u8, and
// Double = u16, think of 255 * 256 + 255 which is just u16::MAX.
let dividend =
Double::from(self_norm.get(j + n))
* B
+ Double::from(self_norm.get(j + n - 1));
Double::from(self_norm.get(j + n)) * B + Double::from(self_norm.get(j + n - 1));
let divisor = other_norm.get(n - 1);
div_single(dividend, divisor)
};
@@ -377,23 +377,30 @@ impl BigUint {
test();
while (*rhat.borrow() as Double) < B {
if !test() { break; }
if !test() {
break
}
}
let qhat = qhat.into_inner();
// we don't need rhat anymore. just let it go out of scope when it does.
// step D4
let lhs = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() };
let lhs = Self { digits: (j..=j + n).rev().map(|d| self_norm.get(d)).collect() };
let rhs = other_norm.clone().mul(&Self::from(qhat));
let maybe_sub = lhs.sub(&rhs);
let mut negative = false;
let sub = match maybe_sub {
Ok(t) => t,
Err(t) => { negative = true; t }
Err(t) => {
negative = true;
t
},
};
(j..=j+n).for_each(|d| { self_norm.set(d, sub.get(d - j)); });
(j..=j + n).for_each(|d| {
self_norm.set(d, sub.get(d - j));
});
// step D5
// PROOF: the `test()` specifically decreases qhat until it is below `B`. conversion
@@ -403,9 +410,11 @@ impl BigUint {
// step D6: add back if negative happened.
if negative {
q.set(j, q.get(j) - 1);
let u = Self { digits: (j..=j+n).rev().map(|d| self_norm.get(d)).collect() };
let u = Self { digits: (j..=j + n).rev().map(|d| self_norm.get(d)).collect() };
let r = other_norm.clone().add(&u);
(j..=j+n).rev().for_each(|d| { self_norm.set(d, r.get(d - j)); })
(j..=j + n).rev().for_each(|d| {
self_norm.set(d, r.get(d - j));
})
}
}
@@ -415,9 +424,8 @@ impl BigUint {
if normalizer_bits > 0 {
let s = SHIFT as u32;
let nb = normalizer_bits;
for d in 0..n-1 {
let v = self_norm.get(d) >> nb
| self_norm.get(d + 1).overflowing_shl(s - nb).0;
for d in 0..n - 1 {
let v = self_norm.get(d) >> nb | self_norm.get(d + 1).overflowing_shl(s - nb).0;
r.set(d, v);
}
r.set(n - 1, self_norm.get(n - 1) >> normalizer_bits);
@@ -445,7 +453,6 @@ impl sp_std::fmt::Debug for BigUint {
fn fmt(&self, _: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
Ok(())
}
}
impl PartialEq for BigUint {
@@ -475,7 +482,7 @@ impl Ord for BigUint {
Ordering::Equal => lhs.cmp(rhs),
_ => len_cmp,
}
}
},
}
}
}
@@ -632,18 +639,9 @@ pub mod tests {
#[test]
fn equality_works() {
assert_eq!(
BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] },
true,
);
assert_eq!(
BigUint { digits: vec![3, 2, 3] } == BigUint { digits: vec![1, 2, 3] },
false,
);
assert_eq!(
BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] },
true,
);
assert_eq!(BigUint { digits: vec![1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, true,);
assert_eq!(BigUint { digits: vec![3, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, false,);
assert_eq!(BigUint { digits: vec![0, 1, 2, 3] } == BigUint { digits: vec![1, 2, 3] }, true,);
}
#[test]
@@ -669,14 +667,8 @@ pub mod tests {
use sp_std::convert::TryFrom;
assert_eq!(u64::try_from(with_limbs(1)).unwrap(), 1);
assert_eq!(u64::try_from(with_limbs(2)).unwrap(), u32::MAX as u64 + 2);
assert_eq!(
u64::try_from(with_limbs(3)).unwrap_err(),
"cannot fit a number into u64",
);
assert_eq!(
u128::try_from(with_limbs(3)).unwrap(),
u32::MAX as u128 + u64::MAX as u128 + 3
);
assert_eq!(u64::try_from(with_limbs(3)).unwrap_err(), "cannot fit a number into u64",);
assert_eq!(u128::try_from(with_limbs(3)).unwrap(), u32::MAX as u128 + u64::MAX as u128 + 3);
}
#[test]
+228 -106
View File
@@ -17,22 +17,38 @@
//! Decimal Fixed Point implementations for Substrate runtime.
use sp_std::{ops::{self, Add, Sub, Mul, Div}, fmt::Debug, prelude::*, convert::{TryInto, TryFrom}};
use codec::{Encode, Decode, CompactAs};
use crate::{
helpers_128bit::multiply_by_rational, PerThing,
helpers_128bit::multiply_by_rational,
traits::{
SaturatedConversion, CheckedSub, CheckedAdd, CheckedMul, CheckedDiv, CheckedNeg,
Bounded, Saturating, UniqueSaturatedInto, Zero, One
Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedSub, One,
SaturatedConversion, Saturating, UniqueSaturatedInto, Zero,
},
PerThing,
};
use codec::{CompactAs, Decode, Encode};
use sp_std::{
convert::{TryFrom, TryInto},
fmt::Debug,
ops::{self, Add, Div, Mul, Sub},
prelude::*,
};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
/// Integer types that can be used to interact with `FixedPointNumber` implementations.
pub trait FixedPointOperand: Copy + Clone + Bounded + Zero + Saturating
+ PartialOrd + UniqueSaturatedInto<u128> + TryFrom<u128> + CheckedNeg {}
pub trait FixedPointOperand:
Copy
+ Clone
+ Bounded
+ Zero
+ Saturating
+ PartialOrd
+ UniqueSaturatedInto<u128>
+ TryFrom<u128>
+ CheckedNeg
{
}
impl FixedPointOperand for i128 {}
impl FixedPointOperand for u128 {}
@@ -53,11 +69,26 @@ impl FixedPointOperand for u8 {}
/// to `Self::Inner::max_value() / Self::DIV`.
/// This is also referred to as the _accuracy_ of the type in the documentation.
pub trait FixedPointNumber:
Sized + Copy + Default + Debug
+ Saturating + Bounded
+ Eq + PartialEq + Ord + PartialOrd
+ CheckedSub + CheckedAdd + CheckedMul + CheckedDiv
+ Add + Sub + Div + Mul + Zero + One
Sized
+ Copy
+ Default
+ Debug
+ Saturating
+ Bounded
+ Eq
+ PartialEq
+ Ord
+ PartialOrd
+ CheckedSub
+ CheckedAdd
+ CheckedMul
+ CheckedDiv
+ Add
+ Sub
+ Div
+ Mul
+ Zero
+ One
{
/// The underlying data type used for this fixed point number.
type Inner: Debug + One + CheckedMul + CheckedDiv + FixedPointOperand;
@@ -108,7 +139,10 @@ pub trait FixedPointNumber:
/// Creates `self` from a rational number. Equal to `n / d`.
///
/// Returns `None` if `d == 0` or `n / d` exceeds accuracy.
fn checked_from_rational<N: FixedPointOperand, D: FixedPointOperand>(n: N, d: D) -> Option<Self> {
fn checked_from_rational<N: FixedPointOperand, D: FixedPointOperand>(
n: N,
d: D,
) -> Option<Self> {
if d == D::zero() {
return None
}
@@ -117,7 +151,8 @@ pub trait FixedPointNumber:
let d: I129 = d.into();
let negative = n.negative != d.negative;
multiply_by_rational(n.value, Self::DIV.unique_saturated_into(), d.value).ok()
multiply_by_rational(n.value, Self::DIV.unique_saturated_into(), d.value)
.ok()
.and_then(|value| from_i129(I129 { value, negative }))
.map(Self::from_inner)
}
@@ -130,7 +165,8 @@ pub trait FixedPointNumber:
let rhs: I129 = n.into();
let negative = lhs.negative != rhs.negative;
multiply_by_rational(lhs.value, rhs.value, Self::DIV.unique_saturated_into()).ok()
multiply_by_rational(lhs.value, rhs.value, Self::DIV.unique_saturated_into())
.ok()
.and_then(|value| from_i129(I129 { value, negative }))
}
@@ -149,7 +185,8 @@ pub trait FixedPointNumber:
let rhs: I129 = d.into();
let negative = lhs.negative != rhs.negative;
lhs.value.checked_div(rhs.value)
lhs.value
.checked_div(rhs.value)
.and_then(|n| n.checked_div(Self::DIV.unique_saturated_into()))
.and_then(|value| from_i129(I129 { value, negative }))
}
@@ -212,7 +249,8 @@ pub trait FixedPointNumber:
/// Returns the integer part.
fn trunc(self) -> Self {
self.into_inner().checked_div(&Self::DIV)
self.into_inner()
.checked_div(&Self::DIV)
.expect("panics only if DIV is zero, DIV is not zero; qed")
.checked_mul(&Self::DIV)
.map(Self::from_inner)
@@ -281,7 +319,8 @@ struct I129 {
impl<N: FixedPointOperand> From<N> for I129 {
fn from(n: N) -> I129 {
if n < N::zero() {
let value: u128 = n.checked_neg()
let value: u128 = n
.checked_neg()
.map(|n| n.unique_saturated_into())
.unwrap_or_else(|| N::max_value().unique_saturated_into().saturating_add(1));
I129 { value, negative: true }
@@ -322,9 +361,10 @@ macro_rules! implement_fixed {
$title:expr $(,)?
) => {
/// A fixed point number representation in the range.
///
#[doc = $title]
#[derive(Encode, Decode, CompactAs, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(
Encode, Decode, CompactAs, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord,
)]
pub struct $name($inner_type);
impl From<$inner_type> for $name {
@@ -386,7 +426,7 @@ macro_rules! implement_fixed {
fn saturating_pow(self, exp: usize) -> Self {
if exp == 0 {
return Self::saturating_from_integer(1);
return Self::saturating_from_integer(1)
}
let exp = exp as u32;
@@ -471,7 +511,8 @@ macro_rules! implement_fixed {
let rhs: I129 = other.0.into();
let negative = lhs.negative != rhs.negative;
multiply_by_rational(lhs.value, Self::DIV as u128, rhs.value).ok()
multiply_by_rational(lhs.value, Self::DIV as u128, rhs.value)
.ok()
.and_then(|value| from_i129(I129 { value, negative }))
.map(Self)
}
@@ -483,7 +524,8 @@ macro_rules! implement_fixed {
let rhs: I129 = other.0.into();
let negative = lhs.negative != rhs.negative;
multiply_by_rational(lhs.value, rhs.value, Self::DIV as u128).ok()
multiply_by_rational(lhs.value, rhs.value, Self::DIV as u128)
.ok()
.and_then(|value| from_i129(I129 { value, negative }))
.map(Self)
}
@@ -524,7 +566,11 @@ macro_rules! implement_fixed {
format!("{}{}", signum_for_zero, int)
};
let precision = (Self::accuracy() as f64).log10() as usize;
let fractional = format!("{:0>weight$}", ((self.0 % Self::accuracy()) as i128).abs(), weight=precision);
let fractional = format!(
"{:0>weight$}",
((self.0 % Self::accuracy()) as i128).abs(),
weight = precision
);
write!(f, "{}({}.{})", stringify!($name), integral, fractional)
}
@@ -534,7 +580,10 @@ macro_rules! implement_fixed {
}
}
impl<P: PerThing> From<P> for $name where P::Inner: FixedPointOperand {
impl<P: PerThing> From<P> for $name
where
P::Inner: FixedPointOperand,
{
fn from(p: P) -> Self {
let accuracy = P::ACCURACY;
let value = p.deconstruct();
@@ -554,8 +603,8 @@ macro_rules! implement_fixed {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let inner: <Self as FixedPointNumber>::Inner = s.parse()
.map_err(|_| "invalid string input for fixed point number")?;
let inner: <Self as FixedPointNumber>::Inner =
s.parse().map_err(|_| "invalid string input for fixed point number")?;
Ok(Self::from_inner(inner))
}
}
@@ -610,50 +659,32 @@ macro_rules! implement_fixed {
#[test]
fn from_i129_works() {
let a = I129 {
value: 1,
negative: true,
};
let a = I129 { value: 1, negative: true };
// Can't convert negative number to unsigned.
assert_eq!(from_i129::<u128>(a), None);
let a = I129 {
value: u128::MAX - 1,
negative: false,
};
let a = I129 { value: u128::MAX - 1, negative: false };
// Max - 1 value fits.
assert_eq!(from_i129::<u128>(a), Some(u128::MAX - 1));
let a = I129 {
value: u128::MAX,
negative: false,
};
let a = I129 { value: u128::MAX, negative: false };
// Max value fits.
assert_eq!(from_i129::<u128>(a), Some(u128::MAX));
let a = I129 {
value: i128::MAX as u128 + 1,
negative: true,
};
let a = I129 { value: i128::MAX as u128 + 1, negative: true };
// Min value fits.
assert_eq!(from_i129::<i128>(a), Some(i128::MIN));
let a = I129 {
value: i128::MAX as u128 + 1,
negative: false,
};
let a = I129 { value: i128::MAX as u128 + 1, negative: false };
// Max + 1 does not fit.
assert_eq!(from_i129::<i128>(a), None);
let a = I129 {
value: i128::MAX as u128,
negative: false,
};
let a = I129 { value: i128::MAX as u128, negative: false };
// Max value fits.
assert_eq!(from_i129::<i128>(a), Some(i128::MAX));
@@ -724,7 +755,6 @@ macro_rules! implement_fixed {
// Min.
assert_eq!($name::max_value(), b);
}
}
@@ -849,8 +879,7 @@ macro_rules! implement_fixed {
let accuracy = $name::accuracy();
// Case where integer fits.
let a = $name::checked_from_integer(42)
.expect("42 * accuracy <= inner_max; qed");
let a = $name::checked_from_integer(42).expect("42 * accuracy <= inner_max; qed");
assert_eq!(a.into_inner(), 42 * accuracy);
// Max integer that fit.
@@ -928,7 +957,7 @@ macro_rules! implement_fixed {
if $name::SIGNED {
// Negative case: -2.5
let a = $name::saturating_from_rational(-5, 2);
assert_eq!(a.into_inner(), 0 - 25 * accuracy / 10);
assert_eq!(a.into_inner(), 0 - 25 * accuracy / 10);
// Other negative case: -2.5
let a = $name::saturating_from_rational(5, -2);
@@ -1048,7 +1077,10 @@ macro_rules! implement_fixed {
if $name::SIGNED {
// Min - 1 => Underflow => None.
let a = $name::checked_from_rational(inner_max as u128 + 2, 0.saturating_sub(accuracy));
let a = $name::checked_from_rational(
inner_max as u128 + 2,
0.saturating_sub(accuracy),
);
assert_eq!(a, None);
let a = $name::checked_from_rational(inner_max, 0 - 3 * accuracy).unwrap();
@@ -1163,15 +1195,15 @@ macro_rules! implement_fixed {
// Max - 1.
let b = $name::from_inner(inner_max - 1);
assert_eq!(a.checked_mul(&(b/2.into())), Some(b));
assert_eq!(a.checked_mul(&(b / 2.into())), Some(b));
// Max.
let c = $name::from_inner(inner_max);
assert_eq!(a.checked_mul(&(c/2.into())), Some(b));
assert_eq!(a.checked_mul(&(c / 2.into())), Some(b));
// Max + 1 => None.
let e = $name::from_inner(1);
assert_eq!(a.checked_mul(&(c/2.into()+e)), None);
assert_eq!(a.checked_mul(&(c / 2.into() + e)), None);
if $name::SIGNED {
// Min + 1.
@@ -1192,8 +1224,14 @@ macro_rules! implement_fixed {
let b = $name::saturating_from_rational(1, -2);
assert_eq!(b.checked_mul(&42.into()), Some(0.saturating_sub(21).into()));
assert_eq!(b.checked_mul(&$name::max_value()), $name::max_value().checked_div(&0.saturating_sub(2).into()));
assert_eq!(b.checked_mul(&$name::min_value()), $name::min_value().checked_div(&0.saturating_sub(2).into()));
assert_eq!(
b.checked_mul(&$name::max_value()),
$name::max_value().checked_div(&0.saturating_sub(2).into())
);
assert_eq!(
b.checked_mul(&$name::min_value()),
$name::min_value().checked_div(&0.saturating_sub(2).into())
);
assert_eq!(c.checked_mul(&$name::min_value()), None);
}
@@ -1203,8 +1241,14 @@ macro_rules! implement_fixed {
assert_eq!(a.checked_mul(&42.into()), Some(21.into()));
assert_eq!(c.checked_mul(&2.into()), Some(510.into()));
assert_eq!(c.checked_mul(&$name::max_value()), None);
assert_eq!(a.checked_mul(&$name::max_value()), $name::max_value().checked_div(&2.into()));
assert_eq!(a.checked_mul(&$name::min_value()), $name::min_value().checked_div(&2.into()));
assert_eq!(
a.checked_mul(&$name::max_value()),
$name::max_value().checked_div(&2.into())
);
assert_eq!(
a.checked_mul(&$name::min_value()),
$name::min_value().checked_div(&2.into())
);
}
#[test]
@@ -1230,13 +1274,25 @@ macro_rules! implement_fixed {
if b < c {
// Not executed by unsigned inners.
assert_eq!(a.checked_div_int(0.saturating_sub(2)), Some(0.saturating_sub(inner_max / (2 * accuracy))));
assert_eq!(a.checked_div_int(0.saturating_sub(inner_max / accuracy)), Some(0.saturating_sub(1)));
assert_eq!(
a.checked_div_int(0.saturating_sub(2)),
Some(0.saturating_sub(inner_max / (2 * accuracy)))
);
assert_eq!(
a.checked_div_int(0.saturating_sub(inner_max / accuracy)),
Some(0.saturating_sub(1))
);
assert_eq!(b.checked_div_int(i128::MIN), Some(0));
assert_eq!(b.checked_div_int(inner_min / accuracy), Some(1));
assert_eq!(b.checked_div_int(1i8), None);
assert_eq!(b.checked_div_int(0.saturating_sub(2)), Some(0.saturating_sub(inner_min / (2 * accuracy))));
assert_eq!(b.checked_div_int(0.saturating_sub(inner_min / accuracy)), Some(0.saturating_sub(1)));
assert_eq!(
b.checked_div_int(0.saturating_sub(2)),
Some(0.saturating_sub(inner_min / (2 * accuracy)))
);
assert_eq!(
b.checked_div_int(0.saturating_sub(inner_min / accuracy)),
Some(0.saturating_sub(1))
);
assert_eq!(c.checked_div_int(i128::MIN), Some(0));
assert_eq!(d.checked_div_int(i32::MIN), Some(0));
}
@@ -1294,7 +1350,10 @@ macro_rules! implement_fixed {
if $name::SIGNED {
assert_eq!($name::from_inner(inner_min).saturating_abs(), $name::max_value());
assert_eq!($name::saturating_from_rational(-1, 2).saturating_abs(), (1, 2).into());
assert_eq!(
$name::saturating_from_rational(-1, 2).saturating_abs(),
(1, 2).into()
);
}
}
@@ -1319,31 +1378,72 @@ macro_rules! implement_fixed {
#[test]
fn saturating_pow_should_work() {
assert_eq!($name::saturating_from_integer(2).saturating_pow(0), $name::saturating_from_integer(1));
assert_eq!($name::saturating_from_integer(2).saturating_pow(1), $name::saturating_from_integer(2));
assert_eq!($name::saturating_from_integer(2).saturating_pow(2), $name::saturating_from_integer(4));
assert_eq!($name::saturating_from_integer(2).saturating_pow(3), $name::saturating_from_integer(8));
assert_eq!($name::saturating_from_integer(2).saturating_pow(50),
$name::saturating_from_integer(1125899906842624i64));
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(0),
$name::saturating_from_integer(1)
);
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(1),
$name::saturating_from_integer(2)
);
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(2),
$name::saturating_from_integer(4)
);
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(3),
$name::saturating_from_integer(8)
);
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(50),
$name::saturating_from_integer(1125899906842624i64)
);
assert_eq!($name::saturating_from_integer(1).saturating_pow(1000), (1).into());
assert_eq!($name::saturating_from_integer(1).saturating_pow(usize::MAX), (1).into());
assert_eq!(
$name::saturating_from_integer(1).saturating_pow(usize::MAX),
(1).into()
);
if $name::SIGNED {
// Saturating.
assert_eq!($name::saturating_from_integer(2).saturating_pow(68), $name::max_value());
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(68),
$name::max_value()
);
assert_eq!($name::saturating_from_integer(-1).saturating_pow(1000), (1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(1001), 0.saturating_sub(1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(usize::MAX), 0.saturating_sub(1).into());
assert_eq!($name::saturating_from_integer(-1).saturating_pow(usize::MAX - 1), (1).into());
assert_eq!(
$name::saturating_from_integer(-1).saturating_pow(1001),
0.saturating_sub(1).into()
);
assert_eq!(
$name::saturating_from_integer(-1).saturating_pow(usize::MAX),
0.saturating_sub(1).into()
);
assert_eq!(
$name::saturating_from_integer(-1).saturating_pow(usize::MAX - 1),
(1).into()
);
}
assert_eq!($name::saturating_from_integer(114209).saturating_pow(5), $name::max_value());
assert_eq!(
$name::saturating_from_integer(114209).saturating_pow(5),
$name::max_value()
);
assert_eq!($name::saturating_from_integer(1).saturating_pow(usize::MAX), (1).into());
assert_eq!($name::saturating_from_integer(0).saturating_pow(usize::MAX), (0).into());
assert_eq!($name::saturating_from_integer(2).saturating_pow(usize::MAX), $name::max_value());
assert_eq!(
$name::saturating_from_integer(1).saturating_pow(usize::MAX),
(1).into()
);
assert_eq!(
$name::saturating_from_integer(0).saturating_pow(usize::MAX),
(0).into()
);
assert_eq!(
$name::saturating_from_integer(2).saturating_pow(usize::MAX),
$name::max_value()
);
}
#[test]
@@ -1368,9 +1468,18 @@ macro_rules! implement_fixed {
if b < c {
// Not executed by unsigned inners.
assert_eq!(a.checked_div(&0.saturating_sub(2).into()), Some($name::from_inner(0.saturating_sub(inner_max / 2))));
assert_eq!(a.checked_div(&-$name::max_value()), Some(0.saturating_sub(1).into()));
assert_eq!(b.checked_div(&0.saturating_sub(2).into()), Some($name::from_inner(0.saturating_sub(inner_min / 2))));
assert_eq!(
a.checked_div(&0.saturating_sub(2).into()),
Some($name::from_inner(0.saturating_sub(inner_max / 2)))
);
assert_eq!(
a.checked_div(&-$name::max_value()),
Some(0.saturating_sub(1).into())
);
assert_eq!(
b.checked_div(&0.saturating_sub(2).into()),
Some($name::from_inner(0.saturating_sub(inner_min / 2)))
);
assert_eq!(c.checked_div(&$name::max_value()), Some(0.into()));
assert_eq!(b.checked_div(&b), Some($name::one()));
}
@@ -1427,14 +1536,10 @@ macro_rules! implement_fixed {
assert_eq!(n, i + f);
let n = $name::saturating_from_rational(5, 2)
.frac()
.saturating_mul(10.into());
let n = $name::saturating_from_rational(5, 2).frac().saturating_mul(10.into());
assert_eq!(n, 5.into());
let n = $name::saturating_from_rational(1, 2)
.frac()
.saturating_mul(10.into());
let n = $name::saturating_from_rational(1, 2).frac().saturating_mul(10.into());
assert_eq!(n, 5.into());
if $name::SIGNED {
@@ -1444,14 +1549,10 @@ macro_rules! implement_fixed {
assert_eq!(n, i - f);
// The sign is attached to the integer part unless it is zero.
let n = $name::saturating_from_rational(-5, 2)
.frac()
.saturating_mul(10.into());
let n = $name::saturating_from_rational(-5, 2).frac().saturating_mul(10.into());
assert_eq!(n, 5.into());
let n = $name::saturating_from_rational(-1, 2)
.frac()
.saturating_mul(10.into());
let n = $name::saturating_from_rational(-1, 2).frac().saturating_mul(10.into());
assert_eq!(n, 0.saturating_sub(5).into());
}
}
@@ -1564,30 +1665,51 @@ macro_rules! implement_fixed {
#[test]
fn fmt_should_work() {
let zero = $name::zero();
assert_eq!(format!("{:?}", zero), format!("{}(0.{:0>weight$})", stringify!($name), 0, weight=precision()));
assert_eq!(
format!("{:?}", zero),
format!("{}(0.{:0>weight$})", stringify!($name), 0, weight = precision())
);
let one = $name::one();
assert_eq!(format!("{:?}", one), format!("{}(1.{:0>weight$})", stringify!($name), 0, weight=precision()));
assert_eq!(
format!("{:?}", one),
format!("{}(1.{:0>weight$})", stringify!($name), 0, weight = precision())
);
let frac = $name::saturating_from_rational(1, 2);
assert_eq!(format!("{:?}", frac), format!("{}(0.{:0<weight$})", stringify!($name), 5, weight=precision()));
assert_eq!(
format!("{:?}", frac),
format!("{}(0.{:0<weight$})", stringify!($name), 5, weight = precision())
);
let frac = $name::saturating_from_rational(5, 2);
assert_eq!(format!("{:?}", frac), format!("{}(2.{:0<weight$})", stringify!($name), 5, weight=precision()));
assert_eq!(
format!("{:?}", frac),
format!("{}(2.{:0<weight$})", stringify!($name), 5, weight = precision())
);
let frac = $name::saturating_from_rational(314, 100);
assert_eq!(format!("{:?}", frac), format!("{}(3.{:0<weight$})", stringify!($name), 14, weight=precision()));
assert_eq!(
format!("{:?}", frac),
format!("{}(3.{:0<weight$})", stringify!($name), 14, weight = precision())
);
if $name::SIGNED {
let neg = -$name::one();
assert_eq!(format!("{:?}", neg), format!("{}(-1.{:0>weight$})", stringify!($name), 0, weight=precision()));
assert_eq!(
format!("{:?}", neg),
format!("{}(-1.{:0>weight$})", stringify!($name), 0, weight = precision())
);
let frac = $name::saturating_from_rational(-314, 100);
assert_eq!(format!("{:?}", frac), format!("{}(-3.{:0<weight$})", stringify!($name), 14, weight=precision()));
assert_eq!(
format!("{:?}", frac),
format!("{}(-3.{:0<weight$})", stringify!($name), 14, weight = precision())
);
}
}
}
}
};
}
implement_fixed!(
@@ -22,7 +22,11 @@
use crate::biguint;
use num_traits::Zero;
use sp_std::{cmp::{min, max}, convert::TryInto, mem};
use sp_std::{
cmp::{max, min},
convert::TryInto,
mem,
};
/// Helper gcd function used in Rational128 implementation.
pub fn gcd(a: u128, b: u128) -> u128 {
@@ -63,7 +67,9 @@ pub fn to_big_uint(x: u128) -> biguint::BigUint {
///
/// Invariant: c must be greater than or equal to 1.
pub fn multiply_by_rational(mut a: u128, mut b: u128, mut c: u128) -> Result<u128, &'static str> {
if a.is_zero() || b.is_zero() { return Ok(Zero::zero()); }
if a.is_zero() || b.is_zero() {
return Ok(Zero::zero())
}
c = c.max(1);
// a and b are interchangeable by definition in this function. It always helps to assume the
@@ -102,9 +108,10 @@ pub fn multiply_by_rational(mut a: u128, mut b: u128, mut c: u128) -> Result<u12
// bigger than c. In this case, returning zero is defensive-only and div should
// always return Some.
let (mut q, r) = ab.div(&c_num, true).unwrap_or((Zero::zero(), Zero::zero()));
let r: u128 = r.try_into()
.expect("reminder of div by c is always less than c; qed");
if r > (c / 2) { q = q.add(&to_big_uint(1)); }
let r: u128 = r.try_into().expect("reminder of div by c is always less than c; qed");
if r > (c / 2) {
q = q.add(&to_big_uint(1));
}
q
};
q.lstrip();
+48 -102
View File
@@ -34,18 +34,18 @@ macro_rules! assert_eq_error_rate {
}
pub mod biguint;
pub mod helpers_128bit;
pub mod traits;
pub mod per_things;
pub mod fixed_point;
pub mod helpers_128bit;
pub mod per_things;
pub mod rational;
pub mod traits;
pub use fixed_point::{FixedPointNumber, FixedPointOperand, FixedI64, FixedI128, FixedU128};
pub use per_things::{PerThing, InnerOf, UpperOf, Percent, PerU16, Permill, Perbill, Perquintill};
pub use fixed_point::{FixedI128, FixedI64, FixedPointNumber, FixedPointOperand, FixedU128};
pub use per_things::{InnerOf, PerThing, PerU16, Perbill, Percent, Permill, Perquintill, UpperOf};
pub use rational::{Rational128, RationalInfinite};
use sp_std::{prelude::*, cmp::Ordering, fmt::Debug, convert::TryInto};
use traits::{BaseArithmetic, One, Zero, SaturatedConversion, Unsigned};
use sp_std::{cmp::Ordering, convert::TryInto, fmt::Debug, prelude::*};
use traits::{BaseArithmetic, One, SaturatedConversion, Unsigned, Zero};
/// Trait for comparing two numbers with an threshold.
///
@@ -82,7 +82,6 @@ where
_ => Ordering::Equal,
}
}
}
}
@@ -114,8 +113,10 @@ impl_normalize_for_numeric!(u8, u16, u32, u64, u128);
impl<P: PerThing> Normalizable<P> for Vec<P> {
fn normalize(&self, targeted_sum: P) -> Result<Vec<P>, &'static str> {
let uppers =
self.iter().map(|p| <UpperOf<P>>::from(p.clone().deconstruct())).collect::<Vec<_>>();
let uppers = self
.iter()
.map(|p| <UpperOf<P>>::from(p.clone().deconstruct()))
.collect::<Vec<_>>();
let normalized =
normalize(uppers.as_ref(), <UpperOf<P>>::from(targeted_sum.deconstruct()))?;
@@ -157,7 +158,8 @@ impl<P: PerThing> Normalizable<P> for Vec<P> {
///
/// * This proof is used in the implementation as well.
pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str>
where T: Clone + Copy + Ord + BaseArithmetic + Unsigned + Debug,
where
T: Clone + Copy + Ord + BaseArithmetic + Unsigned + Debug,
{
// compute sum and return error if failed.
let mut sum = T::zero();
@@ -171,12 +173,12 @@ pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str
// Nothing to do here.
if count.is_zero() {
return Ok(Vec::<T>::new());
return Ok(Vec::<T>::new())
}
let diff = targeted_sum.max(sum) - targeted_sum.min(sum);
if diff.is_zero() {
return Ok(input.to_vec());
return Ok(input.to_vec())
}
let needs_bump = targeted_sum > sum;
@@ -198,7 +200,8 @@ pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str
if !per_round.is_zero() {
for _ in 0..count {
output_with_idx[min_index].1 = output_with_idx[min_index].1
output_with_idx[min_index].1 = output_with_idx[min_index]
.1
.checked_add(&per_round)
.expect("Proof provided in the module doc; qed.");
if output_with_idx[min_index].1 >= threshold {
@@ -210,7 +213,8 @@ pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str
// continue with the previous min_index
while !leftover.is_zero() {
output_with_idx[min_index].1 = output_with_idx[min_index].1
output_with_idx[min_index].1 = output_with_idx[min_index]
.1
.checked_add(&T::one())
.expect("Proof provided in the module doc; qed.");
if output_with_idx[min_index].1 >= threshold {
@@ -232,9 +236,8 @@ pub fn normalize<T>(input: &[T], targeted_sum: T) -> Result<Vec<T>, &'static str
if !per_round.is_zero() {
for _ in 0..count {
output_with_idx[max_index].1 = output_with_idx[max_index].1
.checked_sub(&per_round)
.unwrap_or_else(|| {
output_with_idx[max_index].1 =
output_with_idx[max_index].1.checked_sub(&per_round).unwrap_or_else(|| {
let remainder = per_round - output_with_idx[max_index].1;
leftover += remainder;
output_with_idx[max_index].1.saturating_sub(per_round)
@@ -284,7 +287,7 @@ mod normalize_tests {
normalize(vec![8 as $type, 9, 7, 10].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
}
};
}
// it should work for all types as long as the length of vector can be converted to T.
test_for!(u128);
@@ -297,22 +300,13 @@ mod normalize_tests {
#[test]
fn fails_on_if_input_sum_large() {
assert!(normalize(vec![1u8; 255].as_ref(), 10).is_ok());
assert_eq!(
normalize(vec![1u8; 256].as_ref(), 10),
Err("sum of input cannot fit in `T`"),
);
assert_eq!(normalize(vec![1u8; 256].as_ref(), 10), Err("sum of input cannot fit in `T`"),);
}
#[test]
fn does_not_fail_on_subtraction_overflow() {
assert_eq!(
normalize(vec![1u8, 100, 100].as_ref(), 10).unwrap(),
vec![1, 9, 0],
);
assert_eq!(
normalize(vec![1u8, 8, 9].as_ref(), 1).unwrap(),
vec![0, 1, 0],
);
assert_eq!(normalize(vec![1u8, 100, 100].as_ref(), 10).unwrap(), vec![1, 9, 0],);
assert_eq!(normalize(vec![1u8, 8, 9].as_ref(), 1).unwrap(), vec![0, 1, 0],);
}
#[test]
@@ -323,11 +317,9 @@ mod normalize_tests {
#[test]
fn works_for_per_thing() {
assert_eq!(
vec![
Perbill::from_percent(33),
Perbill::from_percent(33),
Perbill::from_percent(33)
].normalize(Perbill::one()).unwrap(),
vec![Perbill::from_percent(33), Perbill::from_percent(33), Perbill::from_percent(33)]
.normalize(Perbill::one())
.unwrap(),
vec![
Perbill::from_parts(333333334),
Perbill::from_parts(333333333),
@@ -336,11 +328,9 @@ mod normalize_tests {
);
assert_eq!(
vec![
Perbill::from_percent(20),
Perbill::from_percent(15),
Perbill::from_percent(30)
].normalize(Perbill::one()).unwrap(),
vec![Perbill::from_percent(20), Perbill::from_percent(15), Perbill::from_percent(30)]
.normalize(Perbill::one())
.unwrap(),
vec![
Perbill::from_parts(316666668),
Perbill::from_parts(383333332),
@@ -355,11 +345,9 @@ mod normalize_tests {
// could have a situation where the sum cannot be calculated in the inner type. Calculating
// using the upper type of the per_thing should assure this to be okay.
assert_eq!(
vec![
PerU16::from_percent(40),
PerU16::from_percent(40),
PerU16::from_percent(40),
].normalize(PerU16::one()).unwrap(),
vec![PerU16::from_percent(40), PerU16::from_percent(40), PerU16::from_percent(40),]
.normalize(PerU16::one())
.unwrap(),
vec![
PerU16::from_parts(21845), // 33%
PerU16::from_parts(21845), // 33%
@@ -370,82 +358,40 @@ mod normalize_tests {
#[test]
fn normalize_works_all_le() {
assert_eq!(
normalize(vec![8u32, 9, 7, 10].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(normalize(vec![8u32, 9, 7, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(
normalize(vec![7u32, 7, 7, 7].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(normalize(vec![7u32, 7, 7, 7].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(
normalize(vec![7u32, 7, 7, 10].as_ref(), 40).unwrap(),
vec![11, 11, 8, 10],
);
assert_eq!(normalize(vec![7u32, 7, 7, 10].as_ref(), 40).unwrap(), vec![11, 11, 8, 10],);
assert_eq!(
normalize(vec![7u32, 8, 7, 10].as_ref(), 40).unwrap(),
vec![11, 8, 11, 10],
);
assert_eq!(normalize(vec![7u32, 8, 7, 10].as_ref(), 40).unwrap(), vec![11, 8, 11, 10],);
assert_eq!(
normalize(vec![7u32, 7, 8, 10].as_ref(), 40).unwrap(),
vec![11, 11, 8, 10],
);
assert_eq!(normalize(vec![7u32, 7, 8, 10].as_ref(), 40).unwrap(), vec![11, 11, 8, 10],);
}
#[test]
fn normalize_works_some_ge() {
assert_eq!(
normalize(vec![8u32, 11, 9, 10].as_ref(), 40).unwrap(),
vec![10, 11, 9, 10],
);
assert_eq!(normalize(vec![8u32, 11, 9, 10].as_ref(), 40).unwrap(), vec![10, 11, 9, 10],);
}
#[test]
fn always_inc_min() {
assert_eq!(
normalize(vec![10u32, 7, 10, 10].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(
normalize(vec![10u32, 10, 7, 10].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(
normalize(vec![10u32, 10, 10, 7].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(normalize(vec![10u32, 7, 10, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(normalize(vec![10u32, 10, 7, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(normalize(vec![10u32, 10, 10, 7].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
}
#[test]
fn normalize_works_all_ge() {
assert_eq!(
normalize(vec![12u32, 11, 13, 10].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(normalize(vec![12u32, 11, 13, 10].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(
normalize(vec![13u32, 13, 13, 13].as_ref(), 40).unwrap(),
vec![10, 10, 10, 10],
);
assert_eq!(normalize(vec![13u32, 13, 13, 13].as_ref(), 40).unwrap(), vec![10, 10, 10, 10],);
assert_eq!(
normalize(vec![13u32, 13, 13, 10].as_ref(), 40).unwrap(),
vec![12, 9, 9, 10],
);
assert_eq!(normalize(vec![13u32, 13, 13, 10].as_ref(), 40).unwrap(), vec![12, 9, 9, 10],);
assert_eq!(
normalize(vec![13u32, 12, 13, 10].as_ref(), 40).unwrap(),
vec![9, 12, 9, 10],
);
assert_eq!(normalize(vec![13u32, 12, 13, 10].as_ref(), 40).unwrap(), vec![9, 12, 9, 10],);
assert_eq!(
normalize(vec![13u32, 13, 12, 10].as_ref(), 40).unwrap(),
vec![9, 9, 12, 10],
);
assert_eq!(normalize(vec![13u32, 13, 12, 10].as_ref(), 40).unwrap(), vec![9, 9, 12, 10],);
}
}
+132 -70
View File
@@ -16,16 +16,20 @@
// limitations under the License.
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use sp_std::{ops, fmt, prelude::*, convert::{TryFrom, TryInto}};
use codec::{Encode, CompactAs};
use num_traits::Pow;
use crate::traits::{
SaturatedConversion, UniqueSaturatedInto, Saturating, BaseArithmetic, Bounded, Zero, Unsigned,
One,
BaseArithmetic, Bounded, One, SaturatedConversion, Saturating, UniqueSaturatedInto, Unsigned,
Zero,
};
use codec::{CompactAs, Encode};
use num_traits::Pow;
use sp_debug_derive::RuntimeDebug;
use sp_std::{
convert::{TryFrom, TryInto},
fmt, ops,
prelude::*,
};
/// Get the inner type of a `PerThing`.
pub type InnerOf<P> = <P as PerThing>::Inner;
@@ -36,8 +40,19 @@ pub type UpperOf<P> = <P as PerThing>::Upper;
/// Something that implements a fixed point ration with an arbitrary granularity `X`, as _parts per
/// `X`_.
pub trait PerThing:
Sized + Saturating + Copy + Default + Eq + PartialEq + Ord + PartialOrd + Bounded + fmt::Debug
+ ops::Div<Output=Self> + ops::Mul<Output=Self> + Pow<usize, Output=Self>
Sized
+ Saturating
+ Copy
+ Default
+ Eq
+ PartialEq
+ Ord
+ PartialOrd
+ Bounded
+ fmt::Debug
+ ops::Div<Output = Self>
+ ops::Mul<Output = Self>
+ Pow<usize, Output = Self>
{
/// The data type used to build this per-thingy.
type Inner: BaseArithmetic + Unsigned + Copy + Into<u128> + fmt::Debug;
@@ -56,16 +71,24 @@ pub trait PerThing:
const ACCURACY: Self::Inner;
/// Equivalent to `Self::from_parts(0)`.
fn zero() -> Self { Self::from_parts(Self::Inner::zero()) }
fn zero() -> Self {
Self::from_parts(Self::Inner::zero())
}
/// Return `true` if this is nothing.
fn is_zero(&self) -> bool { self.deconstruct() == Self::Inner::zero() }
fn is_zero(&self) -> bool {
self.deconstruct() == Self::Inner::zero()
}
/// Equivalent to `Self::from_parts(Self::ACCURACY)`.
fn one() -> Self { Self::from_parts(Self::ACCURACY) }
fn one() -> Self {
Self::from_parts(Self::ACCURACY)
}
/// Return `true` if this is one.
fn is_one(&self) -> bool { self.deconstruct() == Self::ACCURACY }
fn is_one(&self) -> bool {
self.deconstruct() == Self::ACCURACY
}
/// Build this type from a percent. Equivalent to `Self::from_parts(x * Self::ACCURACY / 100)`
/// but more accurate and can cope with potential type overflows.
@@ -104,8 +127,13 @@ pub trait PerThing:
/// ```
fn mul_floor<N>(self, b: N) -> N
where
N: Clone + UniqueSaturatedInto<Self::Inner> + ops::Rem<N, Output=N> +
ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N> + Unsigned,
N: Clone
+ UniqueSaturatedInto<Self::Inner>
+ ops::Rem<N, Output = N>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ Unsigned,
Self::Inner: Into<N>,
{
overflow_prune_mul::<N, Self>(b, self.deconstruct(), Rounding::Down)
@@ -128,9 +156,14 @@ pub trait PerThing:
/// ```
fn mul_ceil<N>(self, b: N) -> N
where
N: Clone + UniqueSaturatedInto<Self::Inner> + ops::Rem<N, Output=N> +
ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N> + Unsigned,
Self::Inner: Into<N>
N: Clone
+ UniqueSaturatedInto<Self::Inner>
+ ops::Rem<N, Output = N>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ Unsigned,
Self::Inner: Into<N>,
{
overflow_prune_mul::<N, Self>(b, self.deconstruct(), Rounding::Up)
}
@@ -146,9 +179,14 @@ pub trait PerThing:
/// ```
fn saturating_reciprocal_mul<N>(self, b: N) -> N
where
N: Clone + UniqueSaturatedInto<Self::Inner> + ops::Rem<N, Output=N> +
ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N> + Saturating +
Unsigned,
N: Clone
+ UniqueSaturatedInto<Self::Inner>
+ ops::Rem<N, Output = N>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ Saturating
+ Unsigned,
Self::Inner: Into<N>,
{
saturating_reciprocal_mul::<N, Self>(b, self.deconstruct(), Rounding::Nearest)
@@ -168,9 +206,14 @@ pub trait PerThing:
/// ```
fn saturating_reciprocal_mul_floor<N>(self, b: N) -> N
where
N: Clone + UniqueSaturatedInto<Self::Inner> + ops::Rem<N, Output=N> +
ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N> + Saturating +
Unsigned,
N: Clone
+ UniqueSaturatedInto<Self::Inner>
+ ops::Rem<N, Output = N>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ Saturating
+ Unsigned,
Self::Inner: Into<N>,
{
saturating_reciprocal_mul::<N, Self>(b, self.deconstruct(), Rounding::Down)
@@ -190,9 +233,14 @@ pub trait PerThing:
/// ```
fn saturating_reciprocal_mul_ceil<N>(self, b: N) -> N
where
N: Clone + UniqueSaturatedInto<Self::Inner> + ops::Rem<N, Output=N> +
ops::Div<N, Output=N> + ops::Mul<N, Output=N> + ops::Add<N, Output=N> + Saturating +
Unsigned,
N: Clone
+ UniqueSaturatedInto<Self::Inner>
+ ops::Rem<N, Output = N>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ Saturating
+ Unsigned,
Self::Inner: Into<N>,
{
saturating_reciprocal_mul::<N, Self>(b, self.deconstruct(), Rounding::Up)
@@ -211,7 +259,9 @@ pub trait PerThing:
/// Same as `Self::from_float`.
#[deprecated = "Use from_float instead"]
#[cfg(feature = "std")]
fn from_fraction(x: f64) -> Self { Self::from_float(x) }
fn from_fraction(x: f64) -> Self {
Self::from_float(x)
}
/// Approximate the fraction `p/q` into a per-thing fraction. This will never overflow.
///
@@ -233,18 +283,31 @@ pub trait PerThing:
/// ```
fn from_rational<N>(p: N, q: N) -> Self
where
N: Clone + Ord + TryInto<Self::Inner> + TryInto<Self::Upper> +
ops::Div<N, Output=N> + ops::Rem<N, Output=N> + ops::Add<N, Output=N> + Unsigned,
N: Clone
+ Ord
+ TryInto<Self::Inner>
+ TryInto<Self::Upper>
+ ops::Div<N, Output = N>
+ ops::Rem<N, Output = N>
+ ops::Add<N, Output = N>
+ Unsigned,
Self::Inner: Into<N>;
/// Same as `Self::from_rational`.
#[deprecated = "Use from_rational instead"]
fn from_rational_approximation<N>(p: N, q: N) -> Self
where
N: Clone + Ord + TryInto<Self::Inner> + TryInto<Self::Upper>
+ ops::Div<N, Output=N> + ops::Rem<N, Output=N> + ops::Add<N, Output=N> + Unsigned
+ Zero + One,
Self::Inner: Into<N>,
where
N: Clone
+ Ord
+ TryInto<Self::Inner>
+ TryInto<Self::Upper>
+ ops::Div<N, Output = N>
+ ops::Rem<N, Output = N>
+ ops::Add<N, Output = N>
+ Unsigned
+ Zero
+ One,
Self::Inner: Into<N>,
{
Self::from_rational(p, q)
}
@@ -264,37 +327,38 @@ enum Rounding {
/// bounds instead of overflowing.
fn saturating_reciprocal_mul<N, P>(x: N, part: P::Inner, rounding: Rounding) -> N
where
N: Clone + UniqueSaturatedInto<P::Inner> + ops::Div<N, Output=N> + ops::Mul<N,
Output=N> + ops::Add<N, Output=N> + ops::Rem<N, Output=N> + Saturating + Unsigned,
N: Clone
+ UniqueSaturatedInto<P::Inner>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ ops::Rem<N, Output = N>
+ Saturating
+ Unsigned,
P: PerThing,
P::Inner: Into<N>,
{
let maximum: N = P::ACCURACY.into();
let c = rational_mul_correction::<N, P>(
x.clone(),
P::ACCURACY,
part,
rounding,
);
let c = rational_mul_correction::<N, P>(x.clone(), P::ACCURACY, part, rounding);
(x / part.into()).saturating_mul(maximum).saturating_add(c)
}
/// Overflow-prune multiplication. Accurately multiply a value by `self` without overflowing.
fn overflow_prune_mul<N, P>(x: N, part: P::Inner, rounding: Rounding) -> N
where
N: Clone + UniqueSaturatedInto<P::Inner> + ops::Div<N, Output=N> + ops::Mul<N,
Output=N> + ops::Add<N, Output=N> + ops::Rem<N, Output=N> + Unsigned,
N: Clone
+ UniqueSaturatedInto<P::Inner>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ ops::Rem<N, Output = N>
+ Unsigned,
P: PerThing,
P::Inner: Into<N>,
{
let maximum: N = P::ACCURACY.into();
let part_n: N = part.into();
let c = rational_mul_correction::<N, P>(
x.clone(),
part,
P::ACCURACY,
rounding,
);
let c = rational_mul_correction::<N, P>(x.clone(), part, P::ACCURACY, rounding);
(x / maximum) * part_n + c
}
@@ -304,10 +368,14 @@ where
/// to `x / denom * numer` for an accurate result.
fn rational_mul_correction<N, P>(x: N, numer: P::Inner, denom: P::Inner, rounding: Rounding) -> N
where
N: UniqueSaturatedInto<P::Inner> + ops::Div<N, Output=N> + ops::Mul<N,
Output=N> + ops::Add<N, Output=N> + ops::Rem<N, Output=N> + Unsigned,
N: UniqueSaturatedInto<P::Inner>
+ ops::Div<N, Output = N>
+ ops::Mul<N, Output = N>
+ ops::Add<N, Output = N>
+ ops::Rem<N, Output = N>
+ Unsigned,
P: PerThing,
P::Inner: Into<N>
P::Inner: Into<N>,
{
let numer_upper = P::Upper::from(numer);
let denom_n: N = denom.into();
@@ -324,16 +392,18 @@ where
// Already rounded down
Rounding::Down => {},
// Round up if the fractional part of the result is non-zero.
Rounding::Up => if rem_mul_upper % denom_upper > 0.into() {
// `rem * numer / denom` is less than `numer`, so this will not overflow.
rem_mul_div_inner += 1.into();
},
Rounding::Up =>
if rem_mul_upper % denom_upper > 0.into() {
// `rem * numer / denom` is less than `numer`, so this will not overflow.
rem_mul_div_inner += 1.into();
},
// Round up if the fractional part of the result is greater than a half. An exact half is
// rounded down.
Rounding::Nearest => if rem_mul_upper % denom_upper > denom_upper / 2.into() {
// `rem * numer / denom` is less than `numer`, so this will not overflow.
rem_mul_div_inner += 1.into();
},
Rounding::Nearest =>
if rem_mul_upper % denom_upper > denom_upper / 2.into() {
// `rem * numer / denom` is less than `numer`, so this will not overflow.
rem_mul_div_inner += 1.into();
},
}
rem_mul_div_inner.into()
}
@@ -1331,15 +1401,7 @@ macro_rules! implement_per_thing_with_perthousand {
}
}
implement_per_thing!(
Percent,
test_per_cent,
[u32, u64, u128],
100u8,
u8,
u16,
"_Percent_",
);
implement_per_thing!(Percent, test_per_cent, [u32, u64, u128], 100u8, u8, u16, "_Percent_",);
implement_per_thing_with_perthousand!(
PerU16,
test_peru16,
+39 -57
View File
@@ -15,10 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{biguint::BigUint, helpers_128bit};
use num_traits::{Bounded, One, Zero};
use sp_std::{cmp::Ordering, prelude::*};
use crate::helpers_128bit;
use num_traits::{Zero, One, Bounded};
use crate::biguint::BigUint;
/// A wrapper for any rational number with infinitely large numerator and denominator.
///
@@ -160,9 +159,11 @@ impl Rational128 {
/// accurately calculated.
pub fn lcm(&self, other: &Self) -> Result<u128, &'static str> {
// this should be tested better: two large numbers that are almost the same.
if self.1 == other.1 { return Ok(self.1) }
if self.1 == other.1 {
return Ok(self.1)
}
let g = helpers_128bit::gcd(self.1, other.1);
helpers_128bit::multiply_by_rational(self.1 , other.1, g)
helpers_128bit::multiply_by_rational(self.1, other.1, g)
}
/// A saturating add that assumes `self` and `other` have the same denominator.
@@ -170,7 +171,7 @@ impl Rational128 {
if other.is_zero() {
self
} else {
Self(self.0.saturating_add(other.0) ,self.1)
Self(self.0.saturating_add(other.0), self.1)
}
}
@@ -179,7 +180,7 @@ impl Rational128 {
if other.is_zero() {
self
} else {
Self(self.0.saturating_sub(other.0) ,self.1)
Self(self.0.saturating_sub(other.0), self.1)
}
}
@@ -190,7 +191,9 @@ impl Rational128 {
let lcm = self.lcm(&other).map_err(|_| "failed to scale to denominator")?;
let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?;
let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?;
let n = self_scaled.0.checked_add(other_scaled.0)
let n = self_scaled
.0
.checked_add(other_scaled.0)
.ok_or("overflow while adding numerators")?;
Ok(Self(n, self_scaled.1))
}
@@ -203,7 +206,9 @@ impl Rational128 {
let self_scaled = self.to_den(lcm).map_err(|_| "failed to scale to denominator")?;
let other_scaled = other.to_den(lcm).map_err(|_| "failed to scale to denominator")?;
let n = self_scaled.0.checked_sub(other_scaled.0)
let n = self_scaled
.0
.checked_sub(other_scaled.0)
.ok_or("overflow while subtracting numerators")?;
Ok(Self(n, self_scaled.1))
}
@@ -243,7 +248,8 @@ impl Ord for Rational128 {
} else {
// Don't even compute gcd.
let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1);
let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1);
let other_n =
helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1);
self_n.cmp(&other_n)
}
}
@@ -256,7 +262,8 @@ impl PartialEq for Rational128 {
self.0.eq(&other.0)
} else {
let self_n = helpers_128bit::to_big_uint(self.0) * helpers_128bit::to_big_uint(other.1);
let other_n = helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1);
let other_n =
helpers_128bit::to_big_uint(other.0) * helpers_128bit::to_big_uint(self.1);
self_n.eq(&other_n)
}
}
@@ -264,8 +271,7 @@ impl PartialEq for Rational128 {
#[cfg(test)]
mod tests {
use super::*;
use super::helpers_128bit::*;
use super::{helpers_128bit::*, *};
const MAX128: u128 = u128::MAX;
const MAX64: u128 = u64::MAX as u128;
@@ -277,7 +283,9 @@ mod tests {
fn mul_div(a: u128, b: u128, c: u128) -> u128 {
use primitive_types::U256;
if a.is_zero() { return Zero::zero(); }
if a.is_zero() {
return Zero::zero()
}
let c = c.max(1);
// e for extended
@@ -295,14 +303,8 @@ mod tests {
#[test]
fn truth_value_function_works() {
assert_eq!(
mul_div(2u128.pow(100), 8, 4),
2u128.pow(101)
);
assert_eq!(
mul_div(2u128.pow(100), 4, 8),
2u128.pow(99)
);
assert_eq!(mul_div(2u128.pow(100), 8, 4), 2u128.pow(101));
assert_eq!(mul_div(2u128.pow(100), 4, 8), 2u128.pow(99));
// and it returns a if result cannot fit
assert_eq!(mul_div(MAX128 - 10, 2, 1), MAX128 - 10);
@@ -319,13 +321,10 @@ mod tests {
assert_eq!(r(MAX128 / 2, MAX128).to_den(10), Ok(r(5, 10)));
// large to perbill. This is very well needed for npos-elections.
assert_eq!(
r(MAX128 / 2, MAX128).to_den(1000_000_000),
Ok(r(500_000_000, 1000_000_000))
);
assert_eq!(r(MAX128 / 2, MAX128).to_den(1000_000_000), Ok(r(500_000_000, 1000_000_000)));
// large to large
assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128/2), Ok(r(MAX128/4, MAX128/2)));
assert_eq!(r(MAX128 / 2, MAX128).to_den(MAX128 / 2), Ok(r(MAX128 / 4, MAX128 / 2)));
}
#[test]
@@ -343,11 +342,11 @@ mod tests {
// large numbers
assert_eq!(
r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128-1)),
r(1_000_000_000, MAX128).lcm(&r(7_000_000_000, MAX128 - 1)),
Err("result cannot fit in u128"),
);
assert_eq!(
r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64-1)),
r(1_000_000_000, MAX64).lcm(&r(7_000_000_000, MAX64 - 1)),
Ok(340282366920938463408034375210639556610),
);
assert!(340282366920938463408034375210639556610 < MAX128);
@@ -362,7 +361,7 @@ mod tests {
// errors
assert_eq!(
r(1, MAX128).checked_add(r(1, MAX128-1)),
r(1, MAX128).checked_add(r(1, MAX128 - 1)),
Err("failed to scale to denominator"),
);
assert_eq!(
@@ -383,17 +382,14 @@ mod tests {
// errors
assert_eq!(
r(2, MAX128).checked_sub(r(1, MAX128-1)),
r(2, MAX128).checked_sub(r(1, MAX128 - 1)),
Err("failed to scale to denominator"),
);
assert_eq!(
r(7, MAX128).checked_sub(r(MAX128, MAX128)),
Err("overflow while subtracting numerators"),
);
assert_eq!(
r(1, 10).checked_sub(r(2,10)),
Err("overflow while subtracting numerators"),
);
assert_eq!(r(1, 10).checked_sub(r(2, 10)), Err("overflow while subtracting numerators"),);
}
#[test]
@@ -428,7 +424,7 @@ mod tests {
);
assert_eq!(
// MAX128 % 7 == 3
multiply_by_rational(MAX128, 11 , 13).unwrap(),
multiply_by_rational(MAX128, 11, 13).unwrap(),
(MAX128 / 13 * 11) + (8 * 11 / 13),
);
assert_eq!(
@@ -437,14 +433,8 @@ mod tests {
(MAX128 / 1000 * 555) + (455 * 555 / 1000),
);
assert_eq!(
multiply_by_rational(2 * MAX64 - 1, MAX64, MAX64).unwrap(),
2 * MAX64 - 1,
);
assert_eq!(
multiply_by_rational(2 * MAX64 - 1, MAX64 - 1, MAX64).unwrap(),
2 * MAX64 - 3,
);
assert_eq!(multiply_by_rational(2 * MAX64 - 1, MAX64, MAX64).unwrap(), 2 * MAX64 - 1,);
assert_eq!(multiply_by_rational(2 * MAX64 - 1, MAX64 - 1, MAX64).unwrap(), 2 * MAX64 - 3,);
assert_eq!(
multiply_by_rational(MAX64 + 100, MAX64_2, MAX64_2 / 2).unwrap(),
@@ -459,31 +449,23 @@ mod tests {
multiply_by_rational(2u128.pow(66) - 1, 2u128.pow(65) - 1, 2u128.pow(65)).unwrap(),
73786976294838206461,
);
assert_eq!(
multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(),
250000000,
);
assert_eq!(multiply_by_rational(1_000_000_000, MAX128 / 8, MAX128 / 2).unwrap(), 250000000,);
assert_eq!(
multiply_by_rational(
29459999999999999988000u128,
1000000000000000000u128,
10000000000000000000u128
).unwrap(),
)
.unwrap(),
2945999999999999998800u128
);
}
#[test]
fn multiply_by_rational_a_b_are_interchangeable() {
assert_eq!(
multiply_by_rational(10, MAX128, MAX128 / 2),
Ok(20),
);
assert_eq!(
multiply_by_rational(MAX128, 10, MAX128 / 2),
Ok(20),
);
assert_eq!(multiply_by_rational(10, MAX128, MAX128 / 2), Ok(20),);
assert_eq!(multiply_by_rational(MAX128, 10, MAX128 / 2), Ok(20),);
}
#[test]
+155 -66
View File
@@ -17,58 +17,129 @@
//! Primitive traits for the runtime arithmetic.
use sp_std::{self, convert::{TryFrom, TryInto}};
use codec::HasCompact;
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{
Zero, One, Bounded, CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedNeg,
CheckedShl, CheckedShr, checked_pow, Signed, Unsigned,
checked_pow, Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedShl, CheckedShr,
CheckedSub, One, Signed, Unsigned, Zero,
};
use sp_std::ops::{
Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign,
RemAssign, Shl, Shr
use sp_std::{
self,
convert::{TryFrom, TryInto},
ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, Shr, Sub, SubAssign,
},
};
/// A meta trait for arithmetic type operations, regardless of any limitation on size.
pub trait BaseArithmetic:
From<u8> +
Zero + One + IntegerSquareRoot +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
Shl<u32, Output = Self> + Shr<u32, Output = Self> +
CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + Saturating +
PartialOrd<Self> + Ord + Bounded + HasCompact + Sized +
TryFrom<u8> + TryInto<u8> + TryFrom<u16> + TryInto<u16> + TryFrom<u32> + TryInto<u32> +
TryFrom<u64> + TryInto<u64> + TryFrom<u128> + TryInto<u128> + TryFrom<usize> + TryInto<usize> +
UniqueSaturatedFrom<u8> + UniqueSaturatedInto<u8> +
UniqueSaturatedFrom<u16> + UniqueSaturatedInto<u16> +
UniqueSaturatedFrom<u32> + UniqueSaturatedInto<u32> +
UniqueSaturatedFrom<u64> + UniqueSaturatedInto<u64> +
UniqueSaturatedFrom<u128> + UniqueSaturatedInto<u128>
{}
From<u8>
+ Zero
+ One
+ IntegerSquareRoot
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ Rem<Self, Output = Self>
+ RemAssign<Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ CheckedShl
+ CheckedShr
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ Saturating
+ PartialOrd<Self>
+ Ord
+ Bounded
+ HasCompact
+ Sized
+ TryFrom<u8>
+ TryInto<u8>
+ TryFrom<u16>
+ TryInto<u16>
+ TryFrom<u32>
+ TryInto<u32>
+ TryFrom<u64>
+ TryInto<u64>
+ TryFrom<u128>
+ TryInto<u128>
+ TryFrom<usize>
+ TryInto<usize>
+ UniqueSaturatedFrom<u8>
+ UniqueSaturatedInto<u8>
+ UniqueSaturatedFrom<u16>
+ UniqueSaturatedInto<u16>
+ UniqueSaturatedFrom<u32>
+ UniqueSaturatedInto<u32>
+ UniqueSaturatedFrom<u64>
+ UniqueSaturatedInto<u64>
+ UniqueSaturatedFrom<u128>
+ UniqueSaturatedInto<u128>
{
}
impl<T:
From<u8> +
Zero + One + IntegerSquareRoot +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
Shl<u32, Output = Self> + Shr<u32, Output = Self> +
CheckedShl + CheckedShr + CheckedAdd + CheckedSub + CheckedMul + CheckedDiv + Saturating +
PartialOrd<Self> + Ord + Bounded + HasCompact + Sized +
TryFrom<u8> + TryInto<u8> + TryFrom<u16> + TryInto<u16> + TryFrom<u32> + TryInto<u32> +
TryFrom<u64> + TryInto<u64> + TryFrom<u128> + TryInto<u128> + TryFrom<usize> + TryInto<usize> +
UniqueSaturatedFrom<u8> + UniqueSaturatedInto<u8> +
UniqueSaturatedFrom<u16> + UniqueSaturatedInto<u16> +
UniqueSaturatedFrom<u32> + UniqueSaturatedInto<u32> +
UniqueSaturatedFrom<u64> + UniqueSaturatedInto<u64> +
UniqueSaturatedFrom<u128> + UniqueSaturatedInto<u128>
> BaseArithmetic for T {}
impl<
T: From<u8>
+ Zero
+ One
+ IntegerSquareRoot
+ Add<Self, Output = Self>
+ AddAssign<Self>
+ Sub<Self, Output = Self>
+ SubAssign<Self>
+ Mul<Self, Output = Self>
+ MulAssign<Self>
+ Div<Self, Output = Self>
+ DivAssign<Self>
+ Rem<Self, Output = Self>
+ RemAssign<Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ CheckedShl
+ CheckedShr
+ CheckedAdd
+ CheckedSub
+ CheckedMul
+ CheckedDiv
+ Saturating
+ PartialOrd<Self>
+ Ord
+ Bounded
+ HasCompact
+ Sized
+ TryFrom<u8>
+ TryInto<u8>
+ TryFrom<u16>
+ TryInto<u16>
+ TryFrom<u32>
+ TryInto<u32>
+ TryFrom<u64>
+ TryInto<u64>
+ TryFrom<u128>
+ TryInto<u128>
+ TryFrom<usize>
+ TryInto<usize>
+ UniqueSaturatedFrom<u8>
+ UniqueSaturatedInto<u8>
+ UniqueSaturatedFrom<u16>
+ UniqueSaturatedInto<u16>
+ UniqueSaturatedFrom<u32>
+ UniqueSaturatedInto<u32>
+ UniqueSaturatedFrom<u64>
+ UniqueSaturatedInto<u64>
+ UniqueSaturatedFrom<u128>
+ UniqueSaturatedInto<u128>,
> BaseArithmetic for T
{
}
/// A meta trait for arithmetic.
///
@@ -129,35 +200,49 @@ pub trait Saturating {
fn saturating_pow(self, exp: usize) -> Self;
/// Increment self by one, saturating.
fn saturating_inc(&mut self) where Self: One {
fn saturating_inc(&mut self)
where
Self: One,
{
let mut o = Self::one();
sp_std::mem::swap(&mut o, self);
*self = o.saturating_add(One::one());
}
/// Decrement self by one, saturating at zero.
fn saturating_dec(&mut self) where Self: One {
fn saturating_dec(&mut self)
where
Self: One,
{
let mut o = Self::one();
sp_std::mem::swap(&mut o, self);
*self = o.saturating_sub(One::one());
}
/// Increment self by some `amount`, saturating.
fn saturating_accrue(&mut self, amount: Self) where Self: One {
fn saturating_accrue(&mut self, amount: Self)
where
Self: One,
{
let mut o = Self::one();
sp_std::mem::swap(&mut o, self);
*self = o.saturating_add(amount);
}
/// Decrement self by some `amount`, saturating at zero.
fn saturating_reduce(&mut self, amount: Self) where Self: One {
fn saturating_reduce(&mut self, amount: Self)
where
Self: One,
{
let mut o = Self::one();
sp_std::mem::swap(&mut o, self);
*self = o.saturating_sub(amount);
}
}
impl<T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating> Saturating for T {
impl<T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Saturating> Saturating
for T
{
fn saturating_add(self, o: Self) -> Self {
<Self as num_traits::Saturating>::saturating_add(self, o)
}
@@ -167,26 +252,24 @@ impl<T: Clone + Zero + One + PartialOrd + CheckedMul + Bounded + num_traits::Sat
}
fn saturating_mul(self, o: Self) -> Self {
self.checked_mul(&o)
.unwrap_or_else(||
if (self < T::zero()) != (o < T::zero()) {
Bounded::min_value()
} else {
Bounded::max_value()
}
)
self.checked_mul(&o).unwrap_or_else(|| {
if (self < T::zero()) != (o < T::zero()) {
Bounded::min_value()
} else {
Bounded::max_value()
}
})
}
fn saturating_pow(self, exp: usize) -> Self {
let neg = self < T::zero() && exp % 2 != 0;
checked_pow(self, exp)
.unwrap_or_else(||
if neg {
Bounded::min_value()
} else {
Bounded::max_value()
}
)
checked_pow(self, exp).unwrap_or_else(|| {
if neg {
Bounded::min_value()
} else {
Bounded::max_value()
}
})
}
}
@@ -199,7 +282,10 @@ pub trait SaturatedConversion {
/// This just uses `UniqueSaturatedFrom` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_from<T>(t: T) -> Self where Self: UniqueSaturatedFrom<T> {
fn saturated_from<T>(t: T) -> Self
where
Self: UniqueSaturatedFrom<T>,
{
<Self as UniqueSaturatedFrom<T>>::unique_saturated_from(t)
}
@@ -208,7 +294,10 @@ pub trait SaturatedConversion {
/// This just uses `UniqueSaturatedInto` internally but with this
/// variant you can provide the destination type using turbofish syntax
/// in case Rust happens not to assume the correct type.
fn saturated_into<T>(self) -> T where Self: UniqueSaturatedInto<T> {
fn saturated_into<T>(self) -> T
where
Self: UniqueSaturatedInto<T>,
{
<Self as UniqueSaturatedInto<T>>::unique_saturated_into(self)
}
}
@@ -22,11 +22,7 @@
use sp_std::vec::Vec;
mod app {
use sp_application_crypto::{
key_types::AUTHORITY_DISCOVERY,
app_crypto,
sr25519,
};
use sp_application_crypto::{app_crypto, key_types::AUTHORITY_DISCOVERY, sr25519};
app_crypto!(sr25519, AUTHORITY_DISCOVERY);
}
+4 -4
View File
@@ -19,11 +19,11 @@
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::{result::Result, prelude::*};
use sp_std::{prelude::*, result::Result};
use codec::{Encode, Decode};
use sp_inherents::{Error, InherentIdentifier, InherentData, IsFatalError};
use sp_runtime::{RuntimeString, traits::Header as HeaderT};
use codec::{Decode, Encode};
use sp_inherents::{Error, InherentData, InherentIdentifier, IsFatalError};
use sp_runtime::{traits::Header as HeaderT, RuntimeString};
/// The identifier for the `uncles` inherent.
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"uncles00";
+37 -31
View File
@@ -19,11 +19,13 @@
use std::sync::Arc;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use sp_runtime::generic::BlockId;
use sp_runtime::Justifications;
use log::warn;
use parking_lot::RwLock;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, Header as HeaderT, NumberFor},
Justifications,
};
use crate::header_metadata::HeaderMetadata;
@@ -38,7 +40,10 @@ pub trait HeaderBackend<Block: BlockT>: Send + Sync {
/// Get block status.
fn status(&self, id: BlockId<Block>) -> Result<BlockStatus>;
/// Get block number by hash. Returns `None` if the header is not in the chain.
fn number(&self, hash: Block::Hash) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>;
fn number(
&self,
hash: Block::Hash,
) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>;
/// Get block hash by number. Returns `None` if the header is not in the chain.
fn hash(&self, number: NumberFor<Block>) -> Result<Option<Block::Hash>>;
@@ -60,28 +65,29 @@ pub trait HeaderBackend<Block: BlockT>: Send + Sync {
/// Get block header. Returns `UnknownBlock` error if block is not found.
fn expect_header(&self, id: BlockId<Block>) -> Result<Block::Header> {
self.header(id)?.ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", id)))
self.header(id)?
.ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", id)))
}
/// Convert an arbitrary block ID into a block number. Returns `UnknownBlock` error if block is not found.
fn expect_block_number_from_id(&self, id: &BlockId<Block>) -> Result<NumberFor<Block>> {
self.block_number_from_id(id)
.and_then(|n| n.ok_or_else(||
Error::UnknownBlock(format!("Expect block number from id: {}", id))
))
self.block_number_from_id(id).and_then(|n| {
n.ok_or_else(|| Error::UnknownBlock(format!("Expect block number from id: {}", id)))
})
}
/// Convert an arbitrary block ID into a block hash. Returns `UnknownBlock` error if block is not found.
fn expect_block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Block::Hash> {
self.block_hash_from_id(id)
.and_then(|n| n.ok_or_else(||
Error::UnknownBlock(format!("Expect block hash from id: {}", id))
))
self.block_hash_from_id(id).and_then(|n| {
n.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id)))
})
}
}
/// Blockchain database backend. Does not perform any validation.
pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, Error=Error> {
pub trait Backend<Block: BlockT>:
HeaderBackend<Block> + HeaderMetadata<Block, Error = Error>
{
/// Get block body. Returns `None` if block is not found.
fn body(&self, id: BlockId<Block>) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
/// Get block justifications. Returns `None` if no justification exists.
@@ -120,14 +126,14 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
match self.header(BlockId::Hash(target_hash))? {
Some(x) => x,
// target not in blockchain
None => { return Ok(None); },
None => return Ok(None),
}
};
if let Some(max_number) = maybe_max_number {
// target outside search range
if target_header.number() > &max_number {
return Ok(None);
return Ok(None)
}
}
@@ -148,12 +154,12 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
// provided, we continue to search from all leaves below.
if let Some(max_number) = maybe_max_number {
if let Some(header) = self.hash(max_number)? {
return Ok(Some(header));
return Ok(Some(header))
}
}
} else if info.finalized_number >= *target_header.number() {
// header is on a dead fork.
return Ok(None);
return Ok(None)
}
self.leaves()?
@@ -171,12 +177,13 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
// waiting until we are <= max_number
if let Some(max_number) = maybe_max_number {
loop {
let current_header = self.header(BlockId::Hash(current_hash.clone()))?
let current_header = self
.header(BlockId::Hash(current_hash.clone()))?
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
if current_header.number() <= &max_number {
best_hash = current_header.hash();
break;
break
}
current_hash = *current_header.parent_hash();
@@ -187,15 +194,16 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
loop {
// until we find target
if current_hash == target_hash {
return Ok(Some(best_hash));
return Ok(Some(best_hash))
}
let current_header = self.header(BlockId::Hash(current_hash.clone()))?
let current_header = self
.header(BlockId::Hash(current_hash.clone()))?
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
// stop search in this chain once we go below the target's block number
if current_header.number() < target_header.number() {
break;
break
}
current_hash = *current_header.parent_hash();
@@ -209,8 +217,7 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
warn!(
"Block {:?} exists in chain but not found when following all \
leaves backwards. Number limit = {:?}",
target_hash,
maybe_max_number,
target_hash, maybe_max_number,
);
Ok(None)
@@ -218,10 +225,7 @@ pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, E
/// Get single indexed transaction by content hash. Note that this will only fetch transactions
/// that are indexed by the runtime with `storage_index_transaction`.
fn indexed_transaction(
&self,
hash: &Block::Hash,
) -> Result<Option<Vec<u8>>>;
fn indexed_transaction(&self, hash: &Block::Hash) -> Result<Option<Vec<u8>>>;
/// Check if indexed transaction exists.
fn has_indexed_transaction(&self, hash: &Block::Hash) -> Result<bool> {
@@ -253,7 +257,9 @@ pub trait Cache<Block: BlockT>: Send + Sync {
&self,
key: &well_known_cache_keys::Id,
block: &BlockId<Block>,
) -> Result<Option<((NumberFor<Block>, Block::Hash), Option<(NumberFor<Block>, Block::Hash)>, Vec<u8>)>>;
) -> Result<
Option<((NumberFor<Block>, Block::Hash), Option<(NumberFor<Block>, Block::Hash)>, Vec<u8>)>,
>;
}
/// Blockchain info
@@ -272,7 +278,7 @@ pub struct Info<Block: BlockT> {
/// Last finalized state.
pub finalized_state: Option<(Block::Hash, <<Block as BlockT>::Header as HeaderT>::Number)>,
/// Number of concurrent leave forks.
pub number_leaves: usize
pub number_leaves: usize,
}
/// Block status.
+8 -5
View File
@@ -17,12 +17,12 @@
//! Substrate client possible errors.
use std::{self, result};
use sp_state_machine;
use sp_runtime::transaction_validity::TransactionValidityError;
use sp_consensus;
use codec::Error as CodecError;
use sp_api::ApiError;
use sp_consensus;
use sp_runtime::transaction_validity::TransactionValidityError;
use sp_state_machine;
use std::{self, result};
/// Client Result type alias
pub type Result<T> = result::Result<T, Error>;
@@ -205,7 +205,10 @@ impl Error {
/// Construct from a state db error.
// Can not be done directly, since that would make cargo run out of stack if
// `sc-state-db` is lib is added as dependency.
pub fn from_state_db<E>(e: E) -> Self where E: std::fmt::Debug {
pub fn from_state_db<E>(e: E) -> Self
where
E: std::fmt::Debug,
{
Error::StateDatabase(format!("{:?}", e))
}
}
@@ -18,9 +18,9 @@
//! Implements tree backend, cached header metadata and algorithms
//! to compute routes efficiently over the tree of headers.
use sp_runtime::traits::{Block as BlockT, NumberFor, Header};
use parking_lot::RwLock;
use lru::LruCache;
use parking_lot::RwLock;
use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
/// Set to the expected max difference between `best` and `finalized` blocks at sync.
const LRU_CACHE_SIZE: usize = 5_000;
@@ -86,10 +86,7 @@ pub fn lowest_common_ancestor<Block: BlockT, T: HeaderMetadata<Block> + ?Sized>(
backend.insert_header_metadata(orig_header_two.hash, orig_header_two);
}
Ok(HashAndNumber {
hash: header_one.hash,
number: header_one.number,
})
Ok(HashAndNumber { hash: header_one.hash, number: header_one.number })
}
/// Compute a tree-route between two blocks. See tree-route docs for more details.
@@ -105,51 +102,33 @@ pub fn tree_route<Block: BlockT, T: HeaderMetadata<Block>>(
let mut to_branch = Vec::new();
while to.number > from.number {
to_branch.push(HashAndNumber {
number: to.number,
hash: to.hash,
});
to_branch.push(HashAndNumber { number: to.number, hash: to.hash });
to = backend.header_metadata(to.parent)?;
}
while from.number > to.number {
from_branch.push(HashAndNumber {
number: from.number,
hash: from.hash,
});
from_branch.push(HashAndNumber { number: from.number, hash: from.hash });
from = backend.header_metadata(from.parent)?;
}
// numbers are equal now. walk backwards until the block is the same
while to.hash != from.hash {
to_branch.push(HashAndNumber {
number: to.number,
hash: to.hash,
});
to_branch.push(HashAndNumber { number: to.number, hash: to.hash });
to = backend.header_metadata(to.parent)?;
from_branch.push(HashAndNumber {
number: from.number,
hash: from.hash,
});
from_branch.push(HashAndNumber { number: from.number, hash: from.hash });
from = backend.header_metadata(from.parent)?;
}
// add the pivot block. and append the reversed to-branch
// (note that it's reverse order originals)
let pivot = from_branch.len();
from_branch.push(HashAndNumber {
number: to.number,
hash: to.hash,
});
from_branch.push(HashAndNumber { number: to.number, hash: to.hash });
from_branch.extend(to_branch.into_iter().rev());
Ok(TreeRoute {
route: from_branch,
pivot,
})
Ok(TreeRoute { route: from_branch, pivot })
}
/// Hash and number of a block.
@@ -204,14 +183,16 @@ impl<Block: BlockT> TreeRoute<Block> {
/// Get the common ancestor block. This might be one of the two blocks of the
/// route.
pub fn common_block(&self) -> &HashAndNumber<Block> {
self.route.get(self.pivot).expect("tree-routes are computed between blocks; \
self.route.get(self.pivot).expect(
"tree-routes are computed between blocks; \
which are included in the route; \
thus it is never empty; qed")
thus it is never empty; qed",
)
}
/// Get a slice of enacted blocks (descendents of the common ancestor)
pub fn enacted(&self) -> &[HashAndNumber<Block>] {
&self.route[self.pivot + 1 ..]
&self.route[self.pivot + 1..]
}
}
@@ -240,17 +221,13 @@ pub struct HeaderMetadataCache<Block: BlockT> {
impl<Block: BlockT> HeaderMetadataCache<Block> {
/// Creates a new LRU header metadata cache with `capacity`.
pub fn new(capacity: usize) -> Self {
HeaderMetadataCache {
cache: RwLock::new(LruCache::new(capacity)),
}
HeaderMetadataCache { cache: RwLock::new(LruCache::new(capacity)) }
}
}
impl<Block: BlockT> Default for HeaderMetadataCache<Block> {
fn default() -> Self {
HeaderMetadataCache {
cache: RwLock::new(LruCache::new(LRU_CACHE_SIZE)),
}
HeaderMetadataCache { cache: RwLock::new(LruCache::new(LRU_CACHE_SIZE)) }
}
}
+2 -2
View File
@@ -18,9 +18,9 @@
//! Substrate blockchain traits and primitives.
mod backend;
mod header_metadata;
mod error;
mod header_metadata;
pub use error::*;
pub use backend::*;
pub use error::*;
pub use header_metadata::*;
@@ -22,9 +22,9 @@
//! `CompatibleDigestItem` trait to appear in public interfaces.
use crate::AURA_ENGINE_ID;
use sp_runtime::generic::DigestItem;
use codec::{Codec, Encode};
use sp_consensus_slots::Slot;
use codec::{Encode, Codec};
use sp_runtime::generic::DigestItem;
use sp_std::fmt::Debug;
/// A digest item which is usable with aura consensus.
@@ -42,9 +42,10 @@ pub trait CompatibleDigestItem<Signature>: Sized {
fn as_aura_pre_digest(&self) -> Option<Slot>;
}
impl<Signature, Hash> CompatibleDigestItem<Signature> for DigestItem<Hash> where
impl<Signature, Hash> CompatibleDigestItem<Signature> for DigestItem<Hash>
where
Signature: Codec,
Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static
Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static,
{
fn aura_seal(signature: Signature) -> Self {
DigestItem::Seal(AURA_ENGINE_ID, signature.encode())
@@ -16,8 +16,7 @@
// limitations under the License.
/// Contains the inherents for the AURA module
use sp_inherents::{InherentIdentifier, InherentData, Error};
use sp_inherents::{Error, InherentData, InherentIdentifier};
/// The Aura inherent identifier.
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"auraslot";
@@ -28,13 +27,13 @@ pub type InherentType = sp_consensus_slots::Slot;
/// Auxiliary trait to extract Aura inherent data.
pub trait AuraInherentData {
/// Get aura inherent data.
fn aura_inherent_data(&self) ->Result<Option<InherentType>, Error>;
fn aura_inherent_data(&self) -> Result<Option<InherentType>, Error>;
/// Replace aura inherent data.
fn aura_replace_inherent_data(&mut self, new: InherentType);
}
impl AuraInherentData for InherentData {
fn aura_inherent_data(&self) ->Result<Option<InherentType>, Error> {
fn aura_inherent_data(&self) -> Result<Option<InherentType>, Error> {
self.get_data(&INHERENT_IDENTIFIER)
}
@@ -54,9 +53,7 @@ pub struct InherentDataProvider {
impl InherentDataProvider {
/// Create a new instance with the given slot.
pub fn new(slot: InherentType) -> Self {
Self {
slot,
}
Self { slot }
}
/// Creates the inherent data provider by calculating the slot from the given
@@ -65,13 +62,10 @@ impl InherentDataProvider {
timestamp: sp_timestamp::Timestamp,
duration: std::time::Duration,
) -> Self {
let slot = InherentType::from(
(timestamp.as_duration().as_millis() / duration.as_millis()) as u64
);
let slot =
InherentType::from((timestamp.as_duration().as_millis() / duration.as_millis()) as u64);
Self {
slot,
}
Self { slot }
}
}
@@ -87,10 +81,7 @@ impl sp_std::ops::Deref for InherentDataProvider {
#[cfg(feature = "std")]
#[async_trait::async_trait]
impl sp_inherents::InherentDataProvider for InherentDataProvider {
fn provide_inherent_data(
&self,
inherent_data: &mut InherentData,
) ->Result<(), Error> {
fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> {
inherent_data.put_data(INHERENT_IDENTIFIER, &self.slot)
}
@@ -19,9 +19,9 @@
#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Encode, Decode, Codec};
use sp_std::vec::Vec;
use codec::{Codec, Decode, Encode};
use sp_runtime::ConsensusEngineId;
use sp_std::vec::Vec;
pub mod digests;
pub mod inherents;
@@ -46,7 +46,7 @@ pub mod sr25519 {
pub mod ed25519 {
mod app_ed25519 {
use sp_application_crypto::{app_crypto, key_types::AURA, ed25519};
use sp_application_crypto::{app_crypto, ed25519, key_types::AURA};
app_crypto!(ed25519, AURA);
}
@@ -22,8 +22,8 @@ use super::{
BabeEpochConfiguration, Slot, BABE_ENGINE_ID,
};
use codec::{Codec, Decode, Encode};
use sp_std::vec::Vec;
use sp_runtime::{DigestItem, RuntimeDebug};
use sp_std::vec::Vec;
use sp_consensus_vrf::schnorrkel::{Randomness, VRFOutput, VRFProof};
@@ -143,14 +143,13 @@ pub enum NextConfigDescriptor {
c: (u64, u64),
/// Value of `allowed_slots` in `BabeEpochConfiguration`.
allowed_slots: AllowedSlots,
}
},
}
impl From<NextConfigDescriptor> for BabeEpochConfiguration {
fn from(desc: NextConfigDescriptor) -> Self {
match desc {
NextConfigDescriptor::V1 { c, allowed_slots } =>
Self { c, allowed_slots },
NextConfigDescriptor::V1 { c, allowed_slots } => Self { c, allowed_slots },
}
}
}
@@ -176,8 +175,9 @@ pub trait CompatibleDigestItem: Sized {
fn as_next_config_descriptor(&self) -> Option<NextConfigDescriptor>;
}
impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
Hash: Send + Sync + Eq + Clone + Codec + 'static
impl<Hash> CompatibleDigestItem for DigestItem<Hash>
where
Hash: Send + Sync + Eq + Clone + Codec + 'static,
{
fn babe_pre_digest(digest: PreDigest) -> Self {
DigestItem::PreRuntime(BABE_ENGINE_ID, digest.encode())
@@ -17,7 +17,7 @@
//! Inherents for BABE
use sp_inherents::{InherentData, InherentIdentifier, Error};
use sp_inherents::{Error, InherentData, InherentIdentifier};
use sp_std::result::Result;
@@ -64,13 +64,10 @@ impl InherentDataProvider {
timestamp: sp_timestamp::Timestamp,
duration: std::time::Duration,
) -> Self {
let slot = InherentType::from(
(timestamp.as_duration().as_millis() / duration.as_millis()) as u64
);
let slot =
InherentType::from((timestamp.as_duration().as_millis() / duration.as_millis()) as u64);
Self {
slot,
}
Self { slot }
}
/// Returns the `slot` of this inherent data provider.
+10 -23
View File
@@ -30,7 +30,7 @@ pub use sp_consensus_vrf::schnorrkel::{
use codec::{Decode, Encode};
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use sp_keystore::vrf::{VRFTranscriptData, VRFTranscriptValue};
use sp_runtime::{traits::Header, ConsensusEngineId, RuntimeDebug};
@@ -96,11 +96,7 @@ pub type BabeAuthorityWeight = u64;
pub type BabeBlockWeight = u32;
/// Make a VRF transcript from given randomness, slot number and epoch.
pub fn make_transcript(
randomness: &Randomness,
slot: Slot,
epoch: u64,
) -> Transcript {
pub fn make_transcript(randomness: &Randomness, slot: Slot, epoch: u64) -> Transcript {
let mut transcript = Transcript::new(&BABE_ENGINE_ID);
transcript.append_u64(b"slot number", *slot);
transcript.append_u64(b"current epoch", epoch);
@@ -110,18 +106,14 @@ pub fn make_transcript(
/// Make a VRF transcript data container
#[cfg(feature = "std")]
pub fn make_transcript_data(
randomness: &Randomness,
slot: Slot,
epoch: u64,
) -> VRFTranscriptData {
pub fn make_transcript_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VRFTranscriptData {
VRFTranscriptData {
label: &BABE_ENGINE_ID,
items: vec![
("slot number", VRFTranscriptValue::U64(*slot)),
("current epoch", VRFTranscriptValue::U64(epoch)),
("chain randomness", VRFTranscriptValue::Bytes(randomness.to_vec())),
]
],
}
}
@@ -280,20 +272,15 @@ where
use digests::*;
use sp_application_crypto::RuntimeAppPublic;
let find_pre_digest = |header: &H| {
header
.digest()
.logs()
.iter()
.find_map(|log| log.as_babe_pre_digest())
};
let find_pre_digest =
|header: &H| header.digest().logs().iter().find_map(|log| log.as_babe_pre_digest());
let verify_seal_signature = |mut header: H, offender: &AuthorityId| {
let seal = header.digest_mut().pop()?.as_babe_seal()?;
let pre_hash = header.hash();
if !offender.verify(&pre_hash.as_ref(), &seal) {
return None;
return None
}
Some(())
@@ -302,7 +289,7 @@ where
let verify_proof = || {
// we must have different headers for the equivocation to be valid
if proof.first_header.hash() == proof.second_header.hash() {
return None;
return None
}
let first_pre_digest = find_pre_digest(&proof.first_header)?;
@@ -313,12 +300,12 @@ where
if proof.slot != first_pre_digest.slot() ||
first_pre_digest.slot() != second_pre_digest.slot()
{
return None;
return None
}
// both headers must have been authored by the same authority
if first_pre_digest.authority_index() != second_pre_digest.authority_index() {
return None;
return None
}
// we finally verify that the expected authority has signed both headers and
@@ -17,16 +17,14 @@
//! Block import helpers.
use sp_runtime::traits::{Block as BlockT, DigestItemFor, Header as HeaderT, NumberFor, HashFor};
use sp_runtime::{Justification, Justifications};
use serde::{Serialize, Deserialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;
use std::any::Any;
use serde::{Deserialize, Serialize};
use sp_runtime::{
traits::{Block as BlockT, DigestItemFor, HashFor, Header as HeaderT, NumberFor},
Justification, Justifications,
};
use std::{any::Any, borrow::Cow, collections::HashMap, sync::Arc};
use crate::Error;
use crate::import_queue::CacheKeyId;
use crate::{import_queue::CacheKeyId, Error};
/// Block import result.
#[derive(Debug, PartialEq, Eq)]
@@ -88,8 +86,8 @@ impl ImportResult {
if aux.needs_justification {
justification_sync_link.request_justification(hash, number);
}
}
_ => {}
},
_ => {},
}
}
}
@@ -154,9 +152,7 @@ pub struct ImportedState<B: BlockT> {
impl<B: BlockT> std::fmt::Debug for ImportedState<B> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct("ImportedState")
.field("block", &self.block)
.finish()
fmt.debug_struct("ImportedState").field("block", &self.block).finish()
}
}
@@ -226,12 +222,10 @@ pub struct BlockImportParams<Block: BlockT, Transaction> {
impl<Block: BlockT, Transaction> BlockImportParams<Block, Transaction> {
/// Create a new block import params.
pub fn new(
origin: BlockOrigin,
header: Block::Header,
) -> Self {
pub fn new(origin: BlockOrigin, header: Block::Header) -> Self {
Self {
origin, header,
origin,
header,
justifications: None,
post_digests: Vec::new(),
body: None,
@@ -273,7 +267,9 @@ impl<Block: BlockT, Transaction> BlockImportParams<Block, Transaction> {
///
/// Actually this just sets `StorageChanges::Changes` to `None` and makes rustc think that `Self` now
/// uses a different transaction type.
pub fn clear_storage_changes_and_mutate<Transaction2>(self) -> BlockImportParams<Block, Transaction2> {
pub fn clear_storage_changes_and_mutate<Transaction2>(
self,
) -> BlockImportParams<Block, Transaction2> {
// Preserve imported state.
let state_action = match self.state_action {
StateAction::ApplyChanges(StorageChanges::Import(state)) =>
@@ -305,14 +301,15 @@ impl<Block: BlockT, Transaction> BlockImportParams<Block, Transaction> {
let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?;
v.downcast::<T>().or_else(|v| {
self.intermediates.insert(k, v);
Err(Error::InvalidIntermediate)
self.intermediates.insert(k, v);
Err(Error::InvalidIntermediate)
})
}
/// Get a reference to a given intermediate.
pub fn intermediate<T: 'static>(&self, key: &[u8]) -> Result<&T, Error> {
self.intermediates.get(key)
self.intermediates
.get(key)
.ok_or(Error::NoIntermediate)?
.downcast_ref::<T>()
.ok_or(Error::InvalidIntermediate)
@@ -320,7 +317,8 @@ impl<Block: BlockT, Transaction> BlockImportParams<Block, Transaction> {
/// Get a mutable reference to a given intermediate.
pub fn intermediate_mut<T: 'static>(&mut self, key: &[u8]) -> Result<&mut T, Error> {
self.intermediates.get_mut(key)
self.intermediates
.get_mut(key)
.ok_or(Error::NoIntermediate)?
.downcast_mut::<T>()
.ok_or(Error::InvalidIntermediate)
@@ -353,8 +351,8 @@ pub trait BlockImport<B: BlockT> {
#[async_trait::async_trait]
impl<B: BlockT, Transaction> BlockImport<B> for crate::import_queue::BoxBlockImport<B, Transaction>
where
Transaction: Send + 'static,
where
Transaction: Send + 'static,
{
type Error = crate::error::Error;
type Transaction = Transaction;
@@ -381,10 +379,10 @@ impl<B: BlockT, Transaction> BlockImport<B> for crate::import_queue::BoxBlockImp
#[async_trait::async_trait]
impl<B: BlockT, T, E: std::error::Error + Send + 'static, Transaction> BlockImport<B> for Arc<T>
where
for<'r> &'r T: BlockImport<B, Error = E, Transaction = Transaction>,
T: Send + Sync,
Transaction: Send + 'static,
where
for<'r> &'r T: BlockImport<B, Error = E, Transaction = Transaction>,
T: Send + Sync,
Transaction: Send + 'static,
{
type Error = E;
type Transaction = Transaction;
@@ -18,9 +18,9 @@
//! Block announcement validation.
use crate::BlockStatus;
use futures::FutureExt as _;
use sp_runtime::{generic::BlockId, traits::Block};
use std::{error::Error, future::Future, pin::Pin, sync::Arc};
use futures::FutureExt as _;
/// A type which provides access to chain information.
pub trait Chain<B: Block> {
@@ -92,6 +92,7 @@ impl<B: Block> BlockAnnounceValidator<B> for DefaultBlockAnnounceValidator {
} else {
Ok(Validation::Success { is_new_best: false })
}
}.boxed()
}
.boxed()
}
}
@@ -16,8 +16,8 @@
// limitations under the License.
//! Error types in Consensus
use sp_version::RuntimeVersion;
use sp_core::ed25519::Public;
use sp_version::RuntimeVersion;
use std::error;
/// Result type alias.
@@ -58,8 +58,10 @@ pub enum Error {
#[error("Message sender {0:?} is not a valid authority")]
InvalidAuthority(Public),
/// Authoring interface does not match the runtime.
#[error("Authoring for current \
runtime is not supported. Native ({native}) cannot author for on-chain ({on_chain}).")]
#[error(
"Authoring for current \
runtime is not supported. Native ({native}) cannot author for on-chain ({on_chain})."
)]
IncompatibleAuthoringRuntime { native: RuntimeVersion, on_chain: RuntimeVersion },
/// Authoring interface does not match the runtime.
#[error("Authoring for current runtime is not supported since it has no version.")]
@@ -81,7 +83,7 @@ pub enum Error {
ChainLookup(String),
/// Signing failed
#[error("Failed to sign using key: {0:?}. Reason: {1}")]
CannotSign(Vec<u8>, String)
CannotSign(Vec<u8>, String),
}
impl core::convert::From<Public> for Error {
@@ -18,7 +18,7 @@
//! Block evaluation and evaluation errors.
use codec::Encode;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT, One, CheckedConversion};
use sp_runtime::traits::{Block as BlockT, CheckedConversion, Header as HeaderT, One};
// This is just a best effort to encode the number. None indicated that it's too big to encode
// in a u128.
@@ -48,15 +48,13 @@ pub fn evaluate_initial<Block: BlockT>(
parent_hash: &<Block as BlockT>::Hash,
parent_number: <<Block as BlockT>::Header as HeaderT>::Number,
) -> Result<()> {
let encoded = Encode::encode(proposal);
let proposal = Block::decode(&mut &encoded[..])
.map_err(|e| Error::BadProposalFormat(e))?;
let proposal = Block::decode(&mut &encoded[..]).map_err(|e| Error::BadProposalFormat(e))?;
if *parent_hash != *proposal.header().parent_hash() {
return Err(Error::WrongParentHash {
expected: format!("{:?}", *parent_hash),
got: format!("{:?}", proposal.header().parent_hash())
got: format!("{:?}", proposal.header().parent_hash()),
})
}
@@ -28,14 +28,17 @@
use std::collections::HashMap;
use sp_runtime::{Justifications, traits::{Block as BlockT, Header as _, NumberFor}};
use sp_runtime::{
traits::{Block as BlockT, Header as _, NumberFor},
Justifications,
};
use crate::{
error::Error as ConsensusError,
block_import::{
BlockImport, BlockOrigin, BlockImportParams, ImportedAux, JustificationImport, ImportResult,
BlockCheckParams, ImportedState, StateAction,
BlockCheckParams, BlockImport, BlockImportParams, BlockOrigin, ImportResult, ImportedAux,
ImportedState, JustificationImport, StateAction,
},
error::Error as ConsensusError,
metrics::Metrics,
};
pub use basic_queue::BasicQueue;
@@ -43,18 +46,19 @@ pub use basic_queue::BasicQueue;
/// A commonly-used Import Queue type.
///
/// This defines the transaction type of the `BasicQueue` to be the transaction type for a client.
pub type DefaultImportQueue<Block, Client> = BasicQueue<Block, sp_api::TransactionFor<Client, Block>>;
pub type DefaultImportQueue<Block, Client> =
BasicQueue<Block, sp_api::TransactionFor<Client, Block>>;
mod basic_queue;
pub mod buffered_link;
/// Shared block import struct used by the queue.
pub type BoxBlockImport<B, Transaction> = Box<
dyn BlockImport<B, Error = ConsensusError, Transaction = Transaction> + Send + Sync
>;
pub type BoxBlockImport<B, Transaction> =
Box<dyn BlockImport<B, Error = ConsensusError, Transaction = Transaction> + Send + Sync>;
/// Shared justification import struct used by the queue.
pub type BoxJustificationImport<B> = Box<dyn JustificationImport<B, Error=ConsensusError> + Send + Sync>;
pub type BoxJustificationImport<B> =
Box<dyn JustificationImport<B, Error = ConsensusError> + Send + Sync>;
/// Maps to the Origin used by the network.
pub type Origin = libp2p::PeerId;
@@ -115,7 +119,7 @@ pub trait ImportQueue<B: BlockT>: Send {
who: Origin,
hash: B::Hash,
number: NumberFor<B>,
justifications: Justifications
justifications: Justifications,
);
/// Polls for actions to perform on the network.
///
@@ -133,10 +137,18 @@ pub trait Link<B: BlockT>: Send {
&mut self,
_imported: usize,
_count: usize,
_results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
) {}
_results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
}
/// Justification import result.
fn justification_imported(&mut self, _who: Origin, _hash: &B::Hash, _number: NumberFor<B>, _success: bool) {}
fn justification_imported(
&mut self,
_who: Origin,
_hash: &B::Hash,
_number: NumberFor<B>,
_success: bool,
) {
}
/// Request a justification for the given block.
fn request_justification(&mut self, _hash: &B::Hash, _number: NumberFor<B>) {}
}
@@ -180,7 +192,11 @@ pub async fn import_single_block<B: BlockT, V: Verifier<B>, Transaction: Send +
}
/// Single block import function with metering.
pub(crate) async fn import_single_block_metered<B: BlockT, V: Verifier<B>, Transaction: Send + 'static>(
pub(crate) async fn import_single_block_metered<
B: BlockT,
V: Verifier<B>,
Transaction: Send + 'static,
>(
import_handle: &mut impl BlockImport<B, Transaction = Transaction, Error = ConsensusError>,
block_origin: BlockOrigin,
block: IncomingBlock<B>,
@@ -207,60 +223,61 @@ pub(crate) async fn import_single_block_metered<B: BlockT, V: Verifier<B>, Trans
let hash = header.hash();
let parent_hash = header.parent_hash().clone();
let import_handler = |import| {
match import {
Ok(ImportResult::AlreadyInChain) => {
trace!(target: "sync", "Block already in chain {}: {:?}", number, hash);
Ok(BlockImportResult::ImportedKnown(number, peer.clone()))
},
Ok(ImportResult::Imported(aux)) => Ok(BlockImportResult::ImportedUnknown(number, aux, peer.clone())),
Ok(ImportResult::MissingState) => {
debug!(target: "sync", "Parent state is missing for {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::MissingState)
},
Ok(ImportResult::UnknownParent) => {
debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::UnknownParent)
},
Ok(ImportResult::KnownBad) => {
debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash);
Err(BlockImportError::BadBlock(peer.clone()))
},
Err(e) => {
debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e);
Err(BlockImportError::Other(e))
}
}
let import_handler = |import| match import {
Ok(ImportResult::AlreadyInChain) => {
trace!(target: "sync", "Block already in chain {}: {:?}", number, hash);
Ok(BlockImportResult::ImportedKnown(number, peer.clone()))
},
Ok(ImportResult::Imported(aux)) =>
Ok(BlockImportResult::ImportedUnknown(number, aux, peer.clone())),
Ok(ImportResult::MissingState) => {
debug!(target: "sync", "Parent state is missing for {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::MissingState)
},
Ok(ImportResult::UnknownParent) => {
debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent_hash);
Err(BlockImportError::UnknownParent)
},
Ok(ImportResult::KnownBad) => {
debug!(target: "sync", "Peer gave us a bad block {}: {:?}", number, hash);
Err(BlockImportError::BadBlock(peer.clone()))
},
Err(e) => {
debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e);
Err(BlockImportError::Other(e))
},
};
match import_handler(import_handle.check_block(BlockCheckParams {
hash,
number,
parent_hash,
allow_missing_state: block.allow_missing_state,
import_existing: block.import_existing,
}).await)? {
match import_handler(
import_handle
.check_block(BlockCheckParams {
hash,
number,
parent_hash,
allow_missing_state: block.allow_missing_state,
import_existing: block.import_existing,
})
.await,
)? {
BlockImportResult::ImportedUnknown { .. } => (),
r => return Ok(r), // Any other successful result means that the block is already imported.
}
let started = wasm_timer::Instant::now();
let (mut import_block, maybe_keys) = verifier.verify(
block_origin,
header,
justifications,
block.body
).await.map_err(|msg| {
if let Some(ref peer) = peer {
trace!(target: "sync", "Verifying {}({}) from {} failed: {}", number, hash, peer, msg);
} else {
trace!(target: "sync", "Verifying {}({}) failed: {}", number, hash, msg);
}
if let Some(metrics) = metrics.as_ref() {
metrics.report_verification(false, started.elapsed());
}
BlockImportError::VerificationFailed(peer.clone(), msg)
})?;
let (mut import_block, maybe_keys) = verifier
.verify(block_origin, header, justifications, block.body)
.await
.map_err(|msg| {
if let Some(ref peer) = peer {
trace!(target: "sync", "Verifying {}({}) from {} failed: {}", number, hash, peer, msg);
} else {
trace!(target: "sync", "Verifying {}({}) failed: {}", number, hash, msg);
}
if let Some(metrics) = metrics.as_ref() {
metrics.report_verification(false, started.elapsed());
}
BlockImportError::VerificationFailed(peer.clone(), msg)
})?;
if let Some(metrics) = metrics.as_ref() {
metrics.report_verification(true, started.elapsed());
@@ -15,20 +15,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{pin::Pin, time::Duration, marker::PhantomData};
use futures::{prelude::*, task::Context, task::Poll};
use futures::{
prelude::*,
task::{Context, Poll},
};
use futures_timer::Delay;
use sp_runtime::{Justification, Justifications, traits::{Block as BlockT, Header as HeaderT, NumberFor}};
use sp_utils::mpsc::{TracingUnboundedSender, tracing_unbounded, TracingUnboundedReceiver};
use prometheus_endpoint::Registry;
use sp_runtime::{
traits::{Block as BlockT, Header as HeaderT, NumberFor},
Justification, Justifications,
};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use std::{marker::PhantomData, pin::Pin, time::Duration};
use crate::{
block_import::BlockOrigin,
import_queue::{
BlockImportResult, BlockImportError, Verifier, BoxBlockImport,
BoxJustificationImport, ImportQueue, Link, Origin,
IncomingBlock, import_single_block_metered,
buffered_link::{self, BufferedLinkSender, BufferedLinkReceiver},
buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender},
import_single_block_metered, BlockImportError, BlockImportResult, BoxBlockImport,
BoxJustificationImport, ImportQueue, IncomingBlock, Link, Origin, Verifier,
},
metrics::Metrics,
};
@@ -85,24 +90,20 @@ impl<B: BlockT, Transaction: Send + 'static> BasicQueue<B, Transaction> {
spawner.spawn_essential_blocking("basic-block-import-worker", future.boxed());
Self {
justification_sender,
block_import_sender,
result_port,
_phantom: PhantomData,
}
Self { justification_sender, block_import_sender, result_port, _phantom: PhantomData }
}
}
impl<B: BlockT, Transaction: Send> ImportQueue<B> for BasicQueue<B, Transaction> {
fn import_blocks(&mut self, origin: BlockOrigin, blocks: Vec<IncomingBlock<B>>) {
if blocks.is_empty() {
return;
return
}
trace!(target: "sync", "Scheduling {} blocks for import", blocks.len());
let res =
self.block_import_sender.unbounded_send(worker_messages::ImportBlocks(origin, blocks));
let res = self
.block_import_sender
.unbounded_send(worker_messages::ImportBlocks(origin, blocks));
if res.is_err() {
log::error!(
@@ -145,7 +146,12 @@ mod worker_messages {
use super::*;
pub struct ImportBlocks<B: BlockT>(pub BlockOrigin, pub Vec<IncomingBlock<B>>);
pub struct ImportJustification<B: BlockT>(pub Origin, pub B::Hash, pub NumberFor<B>, pub Justification);
pub struct ImportJustification<B: BlockT>(
pub Origin,
pub B::Hash,
pub NumberFor<B>,
pub Justification,
);
}
/// The process of importing blocks.
@@ -164,7 +170,8 @@ async fn block_import_process<B: BlockT, Transaction: Send + 'static>(
delay_between_blocks: Duration,
) {
loop {
let worker_messages::ImportBlocks(origin, blocks) = match block_import_receiver.next().await {
let worker_messages::ImportBlocks(origin, blocks) = match block_import_receiver.next().await
{
Some(blocks) => blocks,
None => {
log::debug!(
@@ -182,7 +189,8 @@ async fn block_import_process<B: BlockT, Transaction: Send + 'static>(
&mut verifier,
delay_between_blocks,
metrics.clone(),
).await;
)
.await;
result_sender.blocks_processed(res.imported, res.block_count, res.results);
}
@@ -214,11 +222,7 @@ impl<B: BlockT> BlockImportWorker<B> {
let (block_import_sender, block_import_port) =
tracing_unbounded("mpsc_import_queue_worker_blocks");
let mut worker = BlockImportWorker {
result_sender,
justification_import,
metrics,
};
let mut worker = BlockImportWorker { result_sender, justification_import, metrics };
let delay_between_blocks = Duration::default();
@@ -248,29 +252,26 @@ impl<B: BlockT> BlockImportWorker<B> {
target: "block-import",
"Stopping block import because result channel was closed!",
);
return;
return
}
// Make sure to first process all justifications
while let Poll::Ready(justification) = futures::poll!(justification_port.next()) {
match justification {
Some(ImportJustification(who, hash, number, justification)) => {
worker
.import_justification(who, hash, number, justification)
.await
}
Some(ImportJustification(who, hash, number, justification)) =>
worker.import_justification(who, hash, number, justification).await,
None => {
log::debug!(
target: "block-import",
"Stopping block import because justification channel was closed!",
);
return;
}
return
},
}
}
if let Poll::Ready(()) = futures::poll!(&mut block_import_process) {
return;
return
}
// All futures that we polled are now pending.
@@ -310,13 +311,10 @@ impl<B: BlockT> BlockImportWorker<B> {
};
if let Some(metrics) = self.metrics.as_ref() {
metrics
.justification_import_time
.observe(started.elapsed().as_secs_f64());
metrics.justification_import_time.observe(started.elapsed().as_secs_f64());
}
self.result_sender
.justification_imported(who, &hash, number, success);
self.result_sender.justification_imported(who, &hash, number, success);
}
}
@@ -382,7 +380,8 @@ async fn import_many_blocks<B: BlockT, V: Verifier<B>, Transaction: Send + 'stat
block,
verifier,
metrics.clone(),
).await
)
.await
};
if let Some(metrics) = metrics.as_ref() {
@@ -604,7 +603,7 @@ mod tests {
block_on(futures::future::poll_fn(|cx| {
while link.events.len() < 9 {
match Future::poll(Pin::new(&mut worker), cx) {
Poll::Pending => {}
Poll::Pending => {},
Poll::Ready(()) => panic!("import queue worker should not conclude."),
}
@@ -36,13 +36,15 @@
//! std::task::Poll::Pending::<()>
//! });
//! ```
//!
use crate::import_queue::{BlockImportError, BlockImportResult, Link, Origin};
use futures::prelude::*;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use sp_utils::mpsc::{TracingUnboundedSender, TracingUnboundedReceiver, tracing_unbounded};
use std::{pin::Pin, task::Context, task::Poll};
use crate::import_queue::{Origin, Link, BlockImportResult, BlockImportError};
use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender};
use std::{
pin::Pin,
task::{Context, Poll},
};
/// Wraps around an unbounded channel from the `futures` crate. The sender implements `Link` and
/// can be used to buffer commands, and the receiver can be used to poll said commands and transfer
@@ -70,15 +72,17 @@ impl<B: BlockT> BufferedLinkSender<B> {
impl<B: BlockT> Clone for BufferedLinkSender<B> {
fn clone(&self) -> Self {
BufferedLinkSender {
tx: self.tx.clone(),
}
BufferedLinkSender { tx: self.tx.clone() }
}
}
/// Internal buffered message.
enum BlockImportWorkerMsg<B: BlockT> {
BlocksProcessed(usize, usize, Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>),
BlocksProcessed(
usize,
usize,
Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
),
JustificationImported(Origin, B::Hash, NumberFor<B>, bool),
RequestJustification(B::Hash, NumberFor<B>),
}
@@ -88,9 +92,11 @@ impl<B: BlockT> Link<B> for BufferedLinkSender<B> {
&mut self,
imported: usize,
count: usize,
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>
results: Vec<(Result<BlockImportResult<NumberFor<B>>, BlockImportError>, B::Hash)>,
) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(imported, count, results));
let _ = self
.tx
.unbounded_send(BlockImportWorkerMsg::BlocksProcessed(imported, count, results));
}
fn justification_imported(
@@ -98,14 +104,16 @@ impl<B: BlockT> Link<B> for BufferedLinkSender<B> {
who: Origin,
hash: &B::Hash,
number: NumberFor<B>,
success: bool
success: bool,
) {
let msg = BlockImportWorkerMsg::JustificationImported(who, hash.clone(), number, success);
let _ = self.tx.unbounded_send(msg);
}
fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
let _ = self.tx.unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number));
let _ = self
.tx
.unbounded_send(BlockImportWorkerMsg::RequestJustification(hash.clone(), number));
}
}
@@ -23,28 +23,28 @@
// This provides "unused" building blocks to other crates
#![allow(dead_code)]
// our error-chain could potentially blow up otherwise
#![recursion_limit="128"]
#![recursion_limit = "128"]
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
use std::sync::Arc;
use std::time::Duration;
use std::{sync::Arc, time::Duration};
use sp_runtime::{
generic::BlockId, traits::{Block as BlockT, DigestFor, NumberFor, HashFor},
};
use futures::prelude::*;
use sp_runtime::{
generic::BlockId,
traits::{Block as BlockT, DigestFor, HashFor, NumberFor},
};
use sp_state_machine::StorageProof;
pub mod block_import;
pub mod block_validation;
pub mod error;
pub mod block_import;
mod select_chain;
pub mod import_queue;
pub mod evaluation;
pub mod import_queue;
mod metrics;
mod select_chain;
pub use self::error::Error;
pub use block_import::{
@@ -52,10 +52,10 @@ pub use block_import::{
ImportResult, ImportedAux, ImportedState, JustificationImport, JustificationSyncLink,
StateAction, StorageChanges,
};
pub use select_chain::SelectChain;
pub use sp_state_machine::Backend as StateBackend;
pub use import_queue::DefaultImportQueue;
pub use select_chain::SelectChain;
pub use sp_inherents::InherentData;
pub use sp_state_machine::Backend as StateBackend;
/// Block status.
#[derive(Debug, PartialEq, Eq)]
@@ -80,7 +80,9 @@ pub trait Environment<B: BlockT> {
type Proposer: Proposer<B> + Send + 'static;
/// A future that resolves to the proposer.
type CreateProposer: Future<Output = Result<Self::Proposer, Self::Error>>
+ Send + Unpin + 'static;
+ Send
+ Unpin
+ 'static;
/// Error which can occur upon creation.
type Error: From<Error> + std::fmt::Debug + 'static;
@@ -96,7 +98,8 @@ pub struct Proposal<Block: BlockT, Transaction, Proof> {
/// Proof that was recorded while building the block.
pub proof: Proof,
/// The storage changes while building this block.
pub storage_changes: sp_state_machine::StorageChanges<Transaction, HashFor<Block>, NumberFor<Block>>,
pub storage_changes:
sp_state_machine::StorageChanges<Transaction, HashFor<Block>, NumberFor<Block>>,
}
/// Error that is returned when [`ProofRecording`] requested to record a proof,
@@ -179,8 +182,7 @@ pub trait Proposer<B: BlockT> {
/// The transaction type used by the backend.
type Transaction: Default + Send + 'static;
/// Future that resolves to a committed proposal with an optional proof.
type Proposal:
Future<Output = Result<Proposal<B, Self::Transaction, Self::Proof>, Self::Error>>
type Proposal: Future<Output = Result<Proposal<B, Self::Transaction, Self::Proof>, Self::Error>>
+ Send
+ Unpin
+ 'static;
@@ -233,11 +235,19 @@ pub trait SyncOracle {
pub struct NoNetwork;
impl SyncOracle for NoNetwork {
fn is_major_syncing(&mut self) -> bool { false }
fn is_offline(&mut self) -> bool { false }
fn is_major_syncing(&mut self) -> bool {
false
}
fn is_offline(&mut self) -> bool {
false
}
}
impl<T> SyncOracle for Arc<T> where T: ?Sized, for<'r> &'r T: SyncOracle {
impl<T> SyncOracle for Arc<T>
where
T: ?Sized,
for<'r> &'r T: SyncOracle,
{
fn is_major_syncing(&mut self) -> bool {
<&T>::is_major_syncing(&mut &**self)
}
@@ -277,13 +287,10 @@ impl<T: sp_version::GetRuntimeVersion<Block>, Block: BlockT> CanAuthorWith<Block
fn can_author_with(&self, at: &BlockId<Block>) -> Result<(), String> {
match self.0.runtime_version(at) {
Ok(version) => self.0.native_version().can_author_with(&version),
Err(e) => {
Err(format!(
"Failed to get runtime version at `{}` and will disable authoring. Error: {}",
at,
e,
))
}
Err(e) => Err(format!(
"Failed to get runtime version at `{}` and will disable authoring. Error: {}",
at, e,
)),
}
}
}
@@ -18,12 +18,13 @@
//! Metering tools for consensus
use prometheus_endpoint::{
register, U64, Registry, PrometheusError, Opts, CounterVec, Histogram, HistogramVec, HistogramOpts
register, CounterVec, Histogram, HistogramOpts, HistogramVec, Opts, PrometheusError, Registry,
U64,
};
use sp_runtime::traits::{Block as BlockT, NumberFor};
use crate::import_queue::{BlockImportResult, BlockImportError};
use crate::import_queue::{BlockImportError, BlockImportResult};
/// Generic Prometheus metrics for common consensus functionality.
#[derive(Clone)]
@@ -40,36 +41,29 @@ impl Metrics {
import_queue_processed: register(
CounterVec::new(
Opts::new("import_queue_processed_total", "Blocks processed by import queue"),
&["result"] // 'success or failure
&["result"], // 'success or failure
)?,
registry,
)?,
block_verification_time: register(
HistogramVec::new(
HistogramOpts::new(
"block_verification_time",
"Time taken to verify blocks",
),
HistogramOpts::new("block_verification_time", "Time taken to verify blocks"),
&["result"],
)?,
registry,
)?,
block_verification_and_import_time: register(
Histogram::with_opts(
HistogramOpts::new(
"block_verification_and_import_time",
"Time taken to verify and import blocks",
),
)?,
Histogram::with_opts(HistogramOpts::new(
"block_verification_and_import_time",
"Time taken to verify and import blocks",
))?,
registry,
)?,
justification_import_time: register(
Histogram::with_opts(
HistogramOpts::new(
"justification_import_time",
"Time taken to import justifications",
),
)?,
Histogram::with_opts(HistogramOpts::new(
"justification_import_time",
"Time taken to import justifications",
))?,
registry,
)?,
})
@@ -82,7 +76,7 @@ impl Metrics {
let label = match result {
Ok(_) => "success",
Err(BlockImportError::IncompleteHeader(_)) => "incomplete_header",
Err(BlockImportError::VerificationFailed(_,_)) => "verification_failed",
Err(BlockImportError::VerificationFailed(_, _)) => "verification_failed",
Err(BlockImportError::BadBlock(_)) => "bad_block",
Err(BlockImportError::MissingState) => "missing_state",
Err(BlockImportError::UnknownParent) => "unknown_parent",
@@ -90,15 +84,13 @@ impl Metrics {
Err(BlockImportError::Other(_)) => "failed",
};
self.import_queue_processed.with_label_values(
&[label]
).inc();
self.import_queue_processed.with_label_values(&[label]).inc();
}
pub fn report_verification(&self, success: bool, time: std::time::Duration) {
self.block_verification_time.with_label_values(
&[if success { "success" } else { "verification_failed" }]
).observe(time.as_secs_f64());
self.block_verification_time
.with_label_values(&[if success { "success" } else { "verification_failed" }])
.observe(time.as_secs_f64());
}
pub fn report_verification_and_import(&self, time: std::time::Duration) {
@@ -18,7 +18,6 @@
use crate::error::Error;
use sp_runtime::traits::{Block as BlockT, NumberFor};
/// The SelectChain trait defines the strategy upon which the head is chosen
/// if multiple forks are present for an opaque definition of "best" in the
/// specific chain build.
@@ -19,9 +19,9 @@
#![cfg_attr(not(feature = "std"), no_std)]
use sp_std::vec::Vec;
use sp_runtime::ConsensusEngineId;
use codec::Decode;
use sp_runtime::ConsensusEngineId;
use sp_std::vec::Vec;
/// The `ConsensusEngineId` of PoW.
pub const POW_ENGINE_ID: ConsensusEngineId = [b'p', b'o', b'w', b'_'];
@@ -17,13 +17,19 @@
//! Schnorrkel-based VRF.
use codec::{Encode, Decode, EncodeLike};
use sp_std::{convert::TryFrom, prelude::*};
use sp_core::U512;
use sp_std::ops::{Deref, DerefMut};
use codec::{Decode, Encode, EncodeLike};
use schnorrkel::errors::MultiSignatureStage;
use sp_core::U512;
use sp_std::{
convert::TryFrom,
ops::{Deref, DerefMut},
prelude::*,
};
pub use schnorrkel::{SignatureError, PublicKey, vrf::{VRF_PROOF_LENGTH, VRF_OUTPUT_LENGTH}};
pub use schnorrkel::{
vrf::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH},
PublicKey, SignatureError,
};
/// The length of the Randomness.
pub const RANDOMNESS_LENGTH: usize = VRF_OUTPUT_LENGTH;
@@ -34,11 +40,15 @@ pub struct VRFOutput(pub schnorrkel::vrf::VRFOutput);
impl Deref for VRFOutput {
type Target = schnorrkel::vrf::VRFOutput;
fn deref(&self) -> &Self::Target { &self.0 }
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for VRFOutput {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Encode for VRFOutput {
@@ -47,7 +57,7 @@ impl Encode for VRFOutput {
}
}
impl EncodeLike for VRFOutput { }
impl EncodeLike for VRFOutput {}
impl Decode for VRFOutput {
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
@@ -82,11 +92,15 @@ impl Ord for VRFProof {
impl Deref for VRFProof {
type Target = schnorrkel::vrf::VRFProof;
fn deref(&self) -> &Self::Target { &self.0 }
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for VRFProof {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Encode for VRFProof {
@@ -95,7 +109,7 @@ impl Encode for VRFProof {
}
}
impl EncodeLike for VRFProof { }
impl EncodeLike for VRFProof {}
impl Decode for VRFProof {
fn decode<R: codec::Input>(i: &mut R) -> Result<Self, codec::Error> {
@@ -113,8 +127,8 @@ impl TryFrom<[u8; VRF_PROOF_LENGTH]> for VRFProof {
}
fn convert_error(e: SignatureError) -> codec::Error {
use SignatureError::*;
use MultiSignatureStage::*;
use SignatureError::*;
match e {
EquationFalse => "Signature error: `EquationFalse`".into(),
PointDecompressionError => "Signature error: `PointDecompressionError`".into(),
+31 -50
View File
@@ -15,22 +15,21 @@
#[macro_use]
extern crate criterion;
use criterion::{Criterion, black_box, Bencher, BenchmarkId};
use sp_core::crypto::Pair as _;
use sp_core::hashing::{twox_128, blake2_128};
use criterion::{black_box, Bencher, BenchmarkId, Criterion};
use sp_core::{
crypto::Pair as _,
hashing::{blake2_128, twox_128},
};
const MAX_KEY_SIZE: u32 = 32;
fn get_key(key_size: u32) -> Vec<u8> {
use rand::SeedableRng;
use rand::Rng;
use rand::{Rng, SeedableRng};
let rnd: [u8; 32] = rand::rngs::StdRng::seed_from_u64(12).gen();
let mut rnd = rnd.iter().cycle();
(0..key_size)
.map(|_| *rnd.next().unwrap())
.collect()
(0..key_size).map(|_| *rnd.next().unwrap()).collect()
}
fn bench_blake2_128(b: &mut Bencher, key: &Vec<u8>) {
@@ -81,27 +80,21 @@ fn bench_ed25519(c: &mut Criterion) {
let mut group = c.benchmark_group("ed25519");
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::ed25519::Pair::generate().0;
group.bench_function(
BenchmarkId::new("signing", format!("{}", msg_size)),
|b| b.iter(|| key.sign(&msg)),
);
group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| {
b.iter(|| key.sign(&msg))
});
}
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::ed25519::Pair::generate().0;
let sig = key.sign(&msg);
let public = key.public();
group.bench_function(
BenchmarkId::new("verifying", format!("{}", msg_size)),
|b| b.iter(|| sp_core::ed25519::Pair::verify(&sig, &msg, &public)),
);
group.bench_function(BenchmarkId::new("verifying", format!("{}", msg_size)), |b| {
b.iter(|| sp_core::ed25519::Pair::verify(&sig, &msg, &public))
});
}
group.finish();
@@ -111,27 +104,21 @@ fn bench_sr25519(c: &mut Criterion) {
let mut group = c.benchmark_group("sr25519");
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::sr25519::Pair::generate().0;
group.bench_function(
BenchmarkId::new("signing", format!("{}", msg_size)),
|b| b.iter(|| key.sign(&msg)),
);
group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| {
b.iter(|| key.sign(&msg))
});
}
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::sr25519::Pair::generate().0;
let sig = key.sign(&msg);
let public = key.public();
group.bench_function(
BenchmarkId::new("verifying", format!("{}", msg_size)),
|b| b.iter(|| sp_core::sr25519::Pair::verify(&sig, &msg, &public)),
);
group.bench_function(BenchmarkId::new("verifying", format!("{}", msg_size)), |b| {
b.iter(|| sp_core::sr25519::Pair::verify(&sig, &msg, &public))
});
}
group.finish();
@@ -141,27 +128,21 @@ fn bench_ecdsa(c: &mut Criterion) {
let mut group = c.benchmark_group("ecdsa");
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::ecdsa::Pair::generate().0;
group.bench_function(
BenchmarkId::new("signing", format!("{}", msg_size)),
|b| b.iter(|| key.sign(&msg)),
);
group.bench_function(BenchmarkId::new("signing", format!("{}", msg_size)), |b| {
b.iter(|| key.sign(&msg))
});
}
for msg_size in vec![32, 1024, 1024 * 1024] {
let msg = (0..msg_size)
.map(|_| rand::random::<u8>())
.collect::<Vec<_>>();
let msg = (0..msg_size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
let key = sp_core::ecdsa::Pair::generate().0;
let sig = key.sign(&msg);
let public = key.public();
group.bench_function(
BenchmarkId::new("verifying", format!("{}", msg_size)),
|b| b.iter(|| sp_core::ecdsa::Pair::verify(&sig, &msg, &public)),
);
group.bench_function(BenchmarkId::new("verifying", format!("{}", msg_size)), |b| {
b.iter(|| sp_core::ecdsa::Pair::verify(&sig, &msg, &public))
});
}
group.finish();
+69 -54
View File
@@ -17,13 +17,16 @@
//! Substrate changes trie configuration.
#[cfg(any(feature = "std", test))]
use serde::{Serialize, Deserialize};
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use num_traits::Zero;
#[cfg(any(feature = "std", test))]
use serde::{Deserialize, Serialize};
/// Substrate changes trie configuration.
#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf))]
#[cfg_attr(
any(feature = "std", test),
derive(Serialize, Deserialize, parity_util_mem::MallocSizeOf)
)]
#[derive(Debug, Clone, PartialEq, Eq, Default, Encode, Decode)]
pub struct ChangesTrieConfiguration {
/// Interval (in blocks) at which level1-digests are created. Digests are not
@@ -62,32 +65,31 @@ impl ChangesTrieConfiguration {
}
/// Do we need to build digest at given block?
pub fn is_digest_build_required_at_block<Number>(
&self,
zero: Number,
block: Number,
) -> bool
where
Number: From<u32> + PartialEq +
::sp_std::ops::Rem<Output=Number> + ::sp_std::ops::Sub<Output=Number> +
::sp_std::cmp::PartialOrd + Zero,
pub fn is_digest_build_required_at_block<Number>(&self, zero: Number, block: Number) -> bool
where
Number: From<u32>
+ PartialEq
+ ::sp_std::ops::Rem<Output = Number>
+ ::sp_std::ops::Sub<Output = Number>
+ ::sp_std::cmp::PartialOrd
+ Zero,
{
block > zero
&& self.is_digest_build_enabled()
&& ((block - zero) % self.digest_interval.into()).is_zero()
block > zero &&
self.is_digest_build_enabled() &&
((block - zero) % self.digest_interval.into()).is_zero()
}
/// Returns max digest interval. One if digests are not created at all.
pub fn max_digest_interval(&self) -> u32 {
if !self.is_digest_build_enabled() {
return 1;
return 1
}
// we'll get >1 loop iteration only when bad configuration parameters are selected
let mut current_level = self.digest_levels;
loop {
if let Some(max_digest_interval) = self.digest_interval.checked_pow(current_level) {
return max_digest_interval;
return max_digest_interval
}
current_level -= 1;
@@ -97,25 +99,28 @@ impl ChangesTrieConfiguration {
/// Returns max level digest block number that has been created at block <= passed block number.
///
/// Returns None if digests are not created at all.
pub fn prev_max_level_digest_block<Number>(
&self,
zero: Number,
block: Number,
) -> Option<Number>
where
Number: Clone + From<u32> + PartialOrd + PartialEq +
::sp_std::ops::Add<Output=Number> + ::sp_std::ops::Sub<Output=Number> +
::sp_std::ops::Div<Output=Number> + ::sp_std::ops::Mul<Output=Number> + Zero,
pub fn prev_max_level_digest_block<Number>(&self, zero: Number, block: Number) -> Option<Number>
where
Number: Clone
+ From<u32>
+ PartialOrd
+ PartialEq
+ ::sp_std::ops::Add<Output = Number>
+ ::sp_std::ops::Sub<Output = Number>
+ ::sp_std::ops::Div<Output = Number>
+ ::sp_std::ops::Mul<Output = Number>
+ Zero,
{
if block <= zero {
return None;
return None
}
let (next_begin, next_end) = self.next_max_level_digest_range(zero.clone(), block.clone())?;
let (next_begin, next_end) =
self.next_max_level_digest_range(zero.clone(), block.clone())?;
// if 'next' digest includes our block, then it is a also a previous digest
if next_end == block {
return Some(block);
return Some(block)
}
// if previous digest ends at zero block, then there are no previous digest
@@ -136,13 +141,18 @@ impl ChangesTrieConfiguration {
zero: Number,
mut block: Number,
) -> Option<(Number, Number)>
where
Number: Clone + From<u32> + PartialOrd + PartialEq +
::sp_std::ops::Add<Output=Number> + ::sp_std::ops::Sub<Output=Number> +
::sp_std::ops::Div<Output=Number> + ::sp_std::ops::Mul<Output=Number>,
where
Number: Clone
+ From<u32>
+ PartialOrd
+ PartialEq
+ ::sp_std::ops::Add<Output = Number>
+ ::sp_std::ops::Sub<Output = Number>
+ ::sp_std::ops::Div<Output = Number>
+ ::sp_std::ops::Mul<Output = Number>,
{
if !self.is_digest_build_enabled() {
return None;
return None
}
if block <= zero {
@@ -152,7 +162,7 @@ impl ChangesTrieConfiguration {
let max_digest_interval: Number = self.max_digest_interval().into();
let max_digests_since_zero = (block.clone() - zero.clone()) / max_digest_interval.clone();
if max_digests_since_zero == 0.into() {
return Some((zero.clone() + 1.into(), zero + max_digest_interval));
return Some((zero.clone() + 1.into(), zero + max_digest_interval))
}
let last_max_digest_block = zero + max_digests_since_zero * max_digest_interval.clone();
Some(if block == last_max_digest_block {
@@ -169,14 +179,22 @@ impl ChangesTrieConfiguration {
/// digest interval (in blocks)
/// step between blocks we're interested in when digest is built
/// )
pub fn digest_level_at_block<Number>(&self, zero: Number, block: Number) -> Option<(u32, u32, u32)>
where
Number: Clone + From<u32> + PartialEq +
::sp_std::ops::Rem<Output=Number> + ::sp_std::ops::Sub<Output=Number> +
::sp_std::cmp::PartialOrd + Zero,
pub fn digest_level_at_block<Number>(
&self,
zero: Number,
block: Number,
) -> Option<(u32, u32, u32)>
where
Number: Clone
+ From<u32>
+ PartialEq
+ ::sp_std::ops::Rem<Output = Number>
+ ::sp_std::ops::Sub<Output = Number>
+ ::sp_std::cmp::PartialOrd
+ Zero,
{
if !self.is_digest_build_required_at_block(zero.clone(), block.clone()) {
return None;
return None
}
let relative_block = block - zero;
@@ -185,8 +203,9 @@ impl ChangesTrieConfiguration {
let mut digest_step = 1u32;
while current_level < self.digest_levels {
let new_digest_interval = match digest_interval.checked_mul(self.digest_interval) {
Some(new_digest_interval) if (relative_block.clone() % new_digest_interval.into()).is_zero()
=> new_digest_interval,
Some(new_digest_interval)
if (relative_block.clone() % new_digest_interval.into()).is_zero() =>
new_digest_interval,
_ => break,
};
@@ -195,11 +214,7 @@ impl ChangesTrieConfiguration {
current_level += 1;
}
Some((
current_level,
digest_interval,
digest_step,
))
Some((current_level, digest_interval, digest_step))
}
}
@@ -208,10 +223,7 @@ mod tests {
use super::ChangesTrieConfiguration;
fn config(interval: u32, levels: u32) -> ChangesTrieConfiguration {
ChangesTrieConfiguration {
digest_interval: interval,
digest_levels: levels,
}
ChangesTrieConfiguration { digest_interval: interval, digest_levels: levels }
}
#[test]
@@ -255,7 +267,10 @@ mod tests {
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 8u64), Some((1, 8, 1)));
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 64u64), Some((2, 64, 8)));
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 512u64), Some((3, 512, 64)));
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 4096u64), Some((4, 4096, 512)));
assert_eq!(
config(8, 4).digest_level_at_block(zero, zero + 4096u64),
Some((4, 4096, 512))
);
assert_eq!(config(8, 4).digest_level_at_block(zero, zero + 4112u64), Some((1, 8, 1)));
}
+293 -159
View File
@@ -19,37 +19,35 @@
//! Cryptographic utilities.
// end::description[]
use crate::{sr25519, ed25519};
use sp_std::hash::Hash;
use sp_std::vec::Vec;
use sp_std::str;
#[cfg(feature = "std")]
use sp_std::convert::TryInto;
use sp_std::convert::TryFrom;
use crate::hexdisplay::HexDisplay;
use crate::{ed25519, sr25519};
#[cfg(feature = "std")]
use base58::{FromBase58, ToBase58};
use codec::{Decode, Encode, MaxEncodedLen};
#[cfg(feature = "std")]
use parking_lot::Mutex;
#[cfg(feature = "std")]
use rand::{RngCore, rngs::OsRng};
use codec::{Encode, Decode, MaxEncodedLen};
use rand::{rngs::OsRng, RngCore};
#[cfg(feature = "std")]
use regex::Regex;
#[cfg(feature = "std")]
use base58::{FromBase58, ToBase58};
#[cfg(feature = "std")]
use crate::hexdisplay::HexDisplay;
#[doc(hidden)]
pub use sp_std::ops::Deref;
use sp_runtime_interface::pass_by::PassByInner;
/// Trait to zeroize a memory buffer.
pub use zeroize::Zeroize;
/// Trait for accessing reference to `SecretString`.
pub use secrecy::ExposeSecret;
/// A store for sensitive data.
#[cfg(feature = "std")]
pub use secrecy::SecretString;
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "std")]
use sp_std::convert::TryInto;
#[doc(hidden)]
pub use sp_std::ops::Deref;
use sp_std::{convert::TryFrom, hash::Hash, str, vec::Vec};
/// Trait to zeroize a memory buffer.
pub use zeroize::Zeroize;
/// The root phrase for our publicly known keys.
pub const DEV_PHRASE: &str = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
pub const DEV_PHRASE: &str =
"bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// The address of the associated root phrase for our publicly known keys.
pub const DEV_ADDRESS: &str = "5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV";
@@ -118,22 +116,28 @@ pub enum DeriveJunction {
#[cfg(feature = "full_crypto")]
impl DeriveJunction {
/// Consume self to return a soft derive junction with the same chain code.
pub fn soften(self) -> Self { DeriveJunction::Soft(self.unwrap_inner()) }
pub fn soften(self) -> Self {
DeriveJunction::Soft(self.unwrap_inner())
}
/// Consume self to return a hard derive junction with the same chain code.
pub fn harden(self) -> Self { DeriveJunction::Hard(self.unwrap_inner()) }
pub fn harden(self) -> Self {
DeriveJunction::Hard(self.unwrap_inner())
}
/// Create a new soft (vanilla) DeriveJunction from a given, encodable, value.
///
/// If you need a hard junction, use `hard()`.
pub fn soft<T: Encode>(index: T) -> Self {
let mut cc: [u8; JUNCTION_ID_LEN] = Default::default();
index.using_encoded(|data| if data.len() > JUNCTION_ID_LEN {
let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data);
let hash = hash_result.as_bytes();
cc.copy_from_slice(hash);
} else {
cc[0..data.len()].copy_from_slice(data);
index.using_encoded(|data| {
if data.len() > JUNCTION_ID_LEN {
let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data);
let hash = hash_result.as_bytes();
cc.copy_from_slice(hash);
} else {
cc[0..data.len()].copy_from_slice(data);
}
});
DeriveJunction::Soft(cc)
}
@@ -174,11 +178,8 @@ impl DeriveJunction {
impl<T: AsRef<str>> From<T> for DeriveJunction {
fn from(j: T) -> DeriveJunction {
let j = j.as_ref();
let (code, hard) = if let Some(stripped) = j.strip_prefix('/') {
(stripped, true)
} else {
(j, false)
};
let (code, hard) =
if let Some(stripped) = j.strip_prefix('/') { (stripped, true) } else { (j, false) };
let res = if let Ok(n) = str::parse::<u64>(code) {
// number
@@ -231,12 +232,11 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
/// Some if the string is a properly encoded SS58Check address.
#[cfg(feature = "std")]
fn from_ss58check(s: &str) -> Result<Self, PublicError> {
Self::from_ss58check_with_version(s)
.and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
Self::from_ss58check_with_version(s).and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
}
/// Some if the string is a properly encoded SS58Check address.
@@ -249,7 +249,9 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
let body_len = res.as_mut().len();
let data = s.from_base58().map_err(|_| PublicError::BadBase58)?;
if data.len() < 2 { return Err(PublicError::BadLength); }
if data.len() < 2 {
return Err(PublicError::BadLength)
}
let (prefix_len, ident) = match data[0] {
0..=63 => (1, data[0] as u16),
64..=127 => {
@@ -261,18 +263,22 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
let lower = (data[0] << 2) | (data[1] >> 6);
let upper = data[1] & 0b00111111;
(2, (lower as u16) | ((upper as u16) << 8))
}
},
_ => return Err(PublicError::UnknownVersion),
};
if data.len() != prefix_len + body_len + CHECKSUM_LEN { return Err(PublicError::BadLength) }
if data.len() != prefix_len + body_len + CHECKSUM_LEN {
return Err(PublicError::BadLength)
}
let format = ident.try_into().map_err(|_: ()| PublicError::UnknownVersion)?;
if !Self::format_is_allowed(format) { return Err(PublicError::FormatNotAllowed) }
if !Self::format_is_allowed(format) {
return Err(PublicError::FormatNotAllowed)
}
let hash = ss58hash(&data[0..body_len + prefix_len]);
let checksum = &hash.as_bytes()[0..CHECKSUM_LEN];
if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum {
// Invalid checksum.
return Err(PublicError::InvalidChecksum);
return Err(PublicError::InvalidChecksum)
}
res.as_mut().copy_from_slice(&data[prefix_len..body_len + prefix_len]);
Ok((res, format))
@@ -282,12 +288,11 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
/// a derivation path following.
#[cfg(feature = "std")]
fn from_string(s: &str) -> Result<Self, PublicError> {
Self::from_string_with_version(s)
.and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
Self::from_string_with_version(s).and_then(|(r, v)| match v {
v if !v.is_custom() => Ok(r),
v if v == *DEFAULT_VERSION.lock() => Ok(r),
_ => Err(PublicError::UnknownVersion),
})
}
/// Return the ss58-check string for this key.
@@ -304,7 +309,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
// lower bits of the upper byte in the low pos
let second = ((ident >> 8) as u8) | ((ident & 0b0000_0000_0000_0011) as u8) << 6;
vec![first | 0b01000000, second]
}
},
_ => unreachable!("masked out the upper two bits; qed"),
};
v.extend(self.as_ref());
@@ -315,7 +320,9 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + Default {
/// Return the ss58-check string for this key.
#[cfg(feature = "std")]
fn to_ss58check(&self) -> String { self.to_ss58check_with_version(*DEFAULT_VERSION.lock()) }
fn to_ss58check(&self) -> String {
self.to_ss58check_with_version(*DEFAULT_VERSION.lock())
}
/// Some if the string is a properly encoded SS58Check address, optionally with
/// a derivation path following.
@@ -331,7 +338,7 @@ pub trait Derive: Sized {
///
/// Will be `None` for public keys if there are any hard junctions in there.
#[cfg(feature = "std")]
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
fn derive<Iter: Iterator<Item = DeriveJunction>>(&self, _path: Iter) -> Option<Self> {
None
}
}
@@ -629,9 +636,7 @@ lazy_static::lazy_static! {
impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
fn from_string(s: &str) -> Result<Self, PublicError> {
let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?;
let s = cap.name("ss58")
.map(|r| r.as_str())
.unwrap_or(DEV_ADDRESS);
let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS);
let addr = if let Some(stripped) = s.strip_prefix("0x") {
let d = hex::decode(stripped).map_err(|_| PublicError::InvalidFormat)?;
let mut r = Self::default();
@@ -647,28 +652,23 @@ impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Default + Derive> Ss58Codec for T {
if cap["path"].is_empty() {
Ok(addr)
} else {
let path = JUNCTION_REGEX.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]));
addr.derive(path)
.ok_or(PublicError::InvalidPath)
let path =
JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
addr.derive(path).ok_or(PublicError::InvalidPath)
}
}
fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?;
let (addr, v) = Self::from_ss58check_with_version(
cap.name("ss58")
.map(|r| r.as_str())
.unwrap_or(DEV_ADDRESS)
cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS),
)?;
if cap["path"].is_empty() {
Ok((addr, v))
} else {
let path = JUNCTION_REGEX.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]));
addr.derive(path)
.ok_or(PublicError::InvalidPath)
.map(|a| (a, v))
let path =
JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
addr.derive(path).ok_or(PublicError::InvalidPath).map(|a| (a, v))
}
}
}
@@ -694,10 +694,14 @@ pub trait Public:
fn from_slice(data: &[u8]) -> Self;
/// Return a `Vec<u8>` filled with raw data.
fn to_raw_vec(&self) -> Vec<u8> { self.as_slice().to_vec() }
fn to_raw_vec(&self) -> Vec<u8> {
self.as_slice().to_vec()
}
/// Return a slice filled with raw data.
fn as_slice(&self) -> &[u8] { self.as_ref() }
fn as_slice(&self) -> &[u8] {
self.as_ref()
}
/// Return `CryptoTypePublicPair` from public key.
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair;
}
@@ -809,14 +813,20 @@ impl sp_std::fmt::Debug for AccountId32 {
#[cfg(feature = "std")]
impl serde::Serialize for AccountId32 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_ss58check())
}
}
#[cfg(feature = "std")]
impl<'de> serde::Deserialize<'de> for AccountId32 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ss58Codec::from_ss58check(&String::deserialize(deserializer)?)
.map_err(|e| serde::de::Error::custom(format!("{:?}", e)))
}
@@ -851,11 +861,13 @@ mod dummy {
pub struct Dummy;
impl AsRef<[u8]> for Dummy {
fn as_ref(&self) -> &[u8] { &b""[..] }
fn as_ref(&self) -> &[u8] {
&b""[..]
}
}
impl AsMut<[u8]> for Dummy {
fn as_mut(&mut self) -> &mut[u8] {
fn as_mut(&mut self) -> &mut [u8] {
unsafe {
#[allow(mutable_transmutes)]
sp_std::mem::transmute::<_, &'static mut [u8]>(&b""[..])
@@ -878,14 +890,18 @@ mod dummy {
impl Derive for Dummy {}
impl Public for Dummy {
fn from_slice(_: &[u8]) -> Self { Self }
fn from_slice(_: &[u8]) -> Self {
Self
}
#[cfg(feature = "std")]
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
fn as_slice(&self) -> &[u8] { b"" }
fn to_raw_vec(&self) -> Vec<u8> {
vec![]
}
fn as_slice(&self) -> &[u8] {
b""
}
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(
CryptoTypeId(*b"dumm"), Public::to_raw_vec(self)
)
CryptoTypePublicPair(CryptoTypeId(*b"dumm"), Public::to_raw_vec(self))
}
}
@@ -895,23 +911,41 @@ mod dummy {
type Signature = Dummy;
type DeriveError = ();
#[cfg(feature = "std")]
fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) { Default::default() }
fn generate_with_phrase(_: Option<&str>) -> (Self, String, Self::Seed) {
Default::default()
}
#[cfg(feature = "std")]
fn from_phrase(_: &str, _: Option<&str>)
-> Result<(Self, Self::Seed), SecretStringError>
{
fn from_phrase(_: &str, _: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError> {
Ok(Default::default())
}
fn derive<
Iter: Iterator<Item=DeriveJunction>,
>(&self, _: Iter, _: Option<Dummy>) -> Result<(Self, Option<Dummy>), Self::DeriveError> { Ok((Self, None)) }
fn from_seed(_: &Self::Seed) -> Self { Self }
fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> { Ok(Self) }
fn sign(&self, _: &[u8]) -> Self::Signature { Self }
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool { true }
fn public(&self) -> Self::Public { Self }
fn to_raw_vec(&self) -> Vec<u8> { vec![] }
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
_: Iter,
_: Option<Dummy>,
) -> Result<(Self, Option<Dummy>), Self::DeriveError> {
Ok((Self, None))
}
fn from_seed(_: &Self::Seed) -> Self {
Self
}
fn from_seed_slice(_: &[u8]) -> Result<Self, SecretStringError> {
Ok(Self)
}
fn sign(&self, _: &[u8]) -> Self::Signature {
Self
}
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
true
}
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(_: &[u8], _: M, _: P) -> bool {
true
}
fn public(&self) -> Self::Public {
Self
}
fn to_raw_vec(&self) -> Vec<u8> {
vec![]
}
}
}
@@ -956,10 +990,14 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
/// Returns the KeyPair from the English BIP39 seed `phrase`, or `None` if it's invalid.
#[cfg(feature = "std")]
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Self, Self::Seed), SecretStringError>;
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, Self::Seed), SecretStringError>;
/// Derive a child key from a series of given junctions.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
seed: Option<Self::Seed>,
) -> Result<(Self, Option<Self::Seed>), Self::DeriveError>;
@@ -1018,19 +1056,20 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
///
/// `None` is returned if no matches are found.
#[cfg(feature = "std")]
fn from_string_with_seed(s: &str, password_override: Option<&str>)
-> Result<(Self, Option<Self::Seed>), SecretStringError>
{
fn from_string_with_seed(
s: &str,
password_override: Option<&str>,
) -> Result<(Self, Option<Self::Seed>), SecretStringError> {
let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?;
let path = JUNCTION_REGEX.captures_iter(&cap["path"])
.map(|f| DeriveJunction::from(&f[1]));
let path = JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
let password = password_override.or_else(|| cap.name("password").map(|m| m.as_str()));
let (root, seed) = if let Some(stripped) = phrase.strip_prefix("0x") {
hex::decode(stripped).ok()
hex::decode(stripped)
.ok()
.and_then(|seed_vec| {
let mut seed = Self::Seed::default();
if seed.as_ref().len() == seed_vec.len() {
@@ -1042,8 +1081,7 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static {
})
.ok_or(SecretStringError::InvalidSeed)?
} else {
Self::from_phrase(phrase, password)
.map_err(|_| SecretStringError::InvalidPhrase)?
Self::from_phrase(phrase, password).map_err(|_| SecretStringError::InvalidPhrase)?
};
root.derive(path, Some(seed)).map_err(|_| SecretStringError::InvalidPath)
}
@@ -1074,19 +1112,25 @@ pub trait Wraps: Sized {
type Inner: IsWrappedBy<Self>;
}
impl<T, Outer> IsWrappedBy<Outer> for T where
impl<T, Outer> IsWrappedBy<Outer> for T
where
Outer: AsRef<Self> + AsMut<Self> + From<Self>,
T: From<Outer>,
{
/// Get a reference to the inner from the outer.
fn from_ref(outer: &Outer) -> &Self { outer.as_ref() }
fn from_ref(outer: &Outer) -> &Self {
outer.as_ref()
}
/// Get a mutable reference to the inner from the outer.
fn from_mut(outer: &mut Outer) -> &mut Self { outer.as_mut() }
fn from_mut(outer: &mut Outer) -> &mut Self {
outer.as_mut()
}
}
impl<Inner, Outer, T> UncheckedFrom<T> for Outer where
Outer: Wraps<Inner=Inner>,
impl<Inner, Outer, T> UncheckedFrom<T> for Outer
where
Outer: Wraps<Inner = Inner>,
Inner: IsWrappedBy<Outer> + UncheckedFrom<T>,
{
fn unchecked_from(t: T) -> Self {
@@ -1110,8 +1154,18 @@ pub trait CryptoType {
/// Values whose first character is `_` are reserved for private use and won't conflict with any
/// public modules.
#[derive(
Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode, PassByInner,
crate::RuntimeDebug
Copy,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Encode,
Decode,
PassByInner,
crate::RuntimeDebug,
)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct KeyTypeId(pub [u8; 4]);
@@ -1134,7 +1188,7 @@ impl<'a> TryFrom<&'a str> for KeyTypeId {
fn try_from(x: &'a str) -> Result<Self, ()> {
let b = x.as_bytes();
if b.len() != 4 {
return Err(());
return Err(())
}
let mut res = KeyTypeId::default();
res.0.copy_from_slice(&b[0..4]);
@@ -1159,7 +1213,7 @@ impl sp_std::fmt::Display for CryptoTypePublicPair {
Ok(id) => id.to_string(),
Err(_) => {
format!("{:#?}", self.0)
}
},
};
write!(f, "{}-{}", id, HexDisplay::from(&self.1))
}
@@ -1195,16 +1249,16 @@ pub mod key_types {
#[cfg(test)]
mod tests {
use super::*;
use crate::DeriveJunction;
use hex_literal::hex;
use super::*;
#[derive(Clone, Eq, PartialEq, Debug)]
enum TestPair {
Generated,
GeneratedWithPhrase,
GeneratedFromPhrase{phrase: String, password: Option<String>},
Standard{phrase: String, password: Option<String>, path: Vec<DeriveJunction>},
GeneratedFromPhrase { phrase: String, password: Option<String> },
Standard { phrase: String, password: Option<String>, path: Vec<DeriveJunction> },
Seed(Vec<u8>),
}
impl Default for TestPair {
@@ -1250,9 +1304,7 @@ mod tests {
vec![]
}
fn to_public_crypto_pair(&self) -> CryptoTypePublicPair {
CryptoTypePublicPair(
CryptoTypeId(*b"dumm"), self.to_raw_vec(),
)
CryptoTypePublicPair(CryptoTypeId(*b"dumm"), self.to_raw_vec())
}
}
impl Pair for TestPair {
@@ -1261,41 +1313,68 @@ mod tests {
type Signature = [u8; 0];
type DeriveError = ();
fn generate() -> (Self, <Self as Pair>::Seed) { (TestPair::Generated, [0u8; 8]) }
fn generate() -> (Self, <Self as Pair>::Seed) {
(TestPair::Generated, [0u8; 8])
}
fn generate_with_phrase(_password: Option<&str>) -> (Self, String, <Self as Pair>::Seed) {
(TestPair::GeneratedWithPhrase, "".into(), [0u8; 8])
}
fn from_phrase(phrase: &str, password: Option<&str>)
-> Result<(Self, <Self as Pair>::Seed), SecretStringError>
{
Ok((TestPair::GeneratedFromPhrase {
phrase: phrase.to_owned(),
password: password.map(Into::into)
}, [0u8; 8]))
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Self, <Self as Pair>::Seed), SecretStringError> {
Ok((
TestPair::GeneratedFromPhrase {
phrase: phrase.to_owned(),
password: password.map(Into::into),
},
[0u8; 8],
))
}
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path_iter: Iter, _: Option<[u8; 8]>)
-> Result<(Self, Option<[u8; 8]>), Self::DeriveError>
{
Ok((match self.clone() {
TestPair::Standard {phrase, password, path} =>
TestPair::Standard { phrase, password, path: path.into_iter().chain(path_iter).collect() },
TestPair::GeneratedFromPhrase {phrase, password} =>
TestPair::Standard { phrase, password, path: path_iter.collect() },
x => if path_iter.count() == 0 { x } else { return Err(()) },
}, None))
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path_iter: Iter,
_: Option<[u8; 8]>,
) -> Result<(Self, Option<[u8; 8]>), Self::DeriveError> {
Ok((
match self.clone() {
TestPair::Standard { phrase, password, path } => TestPair::Standard {
phrase,
password,
path: path.into_iter().chain(path_iter).collect(),
},
TestPair::GeneratedFromPhrase { phrase, password } =>
TestPair::Standard { phrase, password, path: path_iter.collect() },
x =>
if path_iter.count() == 0 {
x
} else {
return Err(())
},
},
None,
))
}
fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self {
TestPair::Seed(_seed.as_ref().to_owned())
}
fn sign(&self, _message: &[u8]) -> Self::Signature {
[]
}
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool {
true
}
fn from_seed(_seed: &<TestPair as Pair>::Seed) -> Self { TestPair::Seed(_seed.as_ref().to_owned()) }
fn sign(&self, _message: &[u8]) -> Self::Signature { [] }
fn verify<M: AsRef<[u8]>>(_: &Self::Signature, _: M, _: &Self::Public) -> bool { true }
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(
_sig: &[u8],
_message: M,
_pubkey: P
) -> bool { true }
fn public(&self) -> Self::Public { TestPublic }
fn from_seed_slice(seed: &[u8])
-> Result<Self, SecretStringError>
{
_pubkey: P,
) -> bool {
true
}
fn public(&self) -> Self::Public {
TestPublic
}
fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError> {
Ok(TestPair::Seed(seed.to_owned()))
}
fn to_raw_vec(&self) -> Vec<u8> {
@@ -1327,43 +1406,83 @@ mod tests {
fn interpret_std_secret_string_should_work() {
assert_eq!(
TestPair::from_string("hello world", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![]
})
);
assert_eq!(
TestPair::from_string("hello world/1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft(1)]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::soft(1)]
})
);
assert_eq!(
TestPair::from_string("hello world/DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::soft("DOT")]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::soft("DOT")]
})
);
assert_eq!(
TestPair::from_string("hello world//1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1)]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::hard(1)]
})
);
assert_eq!(
TestPair::from_string("hello world//DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT")]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::hard("DOT")]
})
);
assert_eq!(
TestPair::from_string("hello world//1/DOT", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
})
);
assert_eq!(
TestPair::from_string("hello world//DOT/1", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: None, path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: None,
path: vec![DeriveJunction::hard("DOT"), DeriveJunction::soft(1)]
})
);
assert_eq!(
TestPair::from_string("hello world///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: Some("password".to_owned()),
path: vec![]
})
);
assert_eq!(
TestPair::from_string("hello world//1/DOT///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: Some("password".to_owned()),
path: vec![DeriveJunction::hard(1), DeriveJunction::soft("DOT")]
})
);
assert_eq!(
TestPair::from_string("hello world/1//DOT///password", None),
Ok(TestPair::Standard{phrase: "hello world".to_owned(), password: Some("password".to_owned()), path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]})
Ok(TestPair::Standard {
phrase: "hello world".to_owned(),
password: Some("password".to_owned()),
path: vec![DeriveJunction::soft(1), DeriveJunction::hard("DOT")]
})
);
}
@@ -1371,25 +1490,40 @@ mod tests {
fn accountid_32_from_str_works() {
use std::str::FromStr;
assert!(AccountId32::from_str("5G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").is_ok());
assert!(AccountId32::from_str("5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").is_ok());
assert!(AccountId32::from_str("0x5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").is_ok());
assert!(AccountId32::from_str(
"5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
)
.is_ok());
assert!(AccountId32::from_str(
"0x5c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
)
.is_ok());
assert_eq!(
AccountId32::from_str("99G9VdMwXvzza9pS8qE8ZHJk3CheHW9uucBn9ngW4C1gmmzpv").unwrap_err(),
"invalid ss58 address.",
);
assert_eq!(
AccountId32::from_str("gc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
AccountId32::from_str(
"gc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
)
.unwrap_err(),
"invalid hex address.",
);
assert_eq!(
AccountId32::from_str("0xgc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
AccountId32::from_str(
"0xgc55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
)
.unwrap_err(),
"invalid hex address.",
);
// valid hex but invalid length will be treated as ss58.
assert_eq!(
AccountId32::from_str("55c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d").unwrap_err(),
AccountId32::from_str(
"55c55177d67b064bb5d189a3e1ddad9bc6646e02e64d6e308f5acbb1533ac430d"
)
.unwrap_err(),
"invalid ss58 address.",
);
}
+92 -54
View File
@@ -22,25 +22,30 @@
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
use sp_std::cmp::Ordering;
use codec::{Encode, Decode, MaxEncodedLen};
#[cfg(feature = "full_crypto")]
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
#[cfg(feature = "std")]
use bip39::{Mnemonic, Language, MnemonicType};
#[cfg(feature = "full_crypto")]
use crate::{hashing::blake2_256, crypto::{Pair as TraitPair, DeriveJunction, SecretStringError}};
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use crate::{
crypto::{DeriveJunction, Pair as TraitPair, SecretStringError},
hashing::blake2_256,
};
#[cfg(feature = "std")]
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
use crate::crypto::{Public as TraitPublic, CryptoTypePublicPair, UncheckedFrom, CryptoType, Derive, CryptoTypeId};
use sp_runtime_interface::pass_by::PassByInner;
use bip39::{Language, Mnemonic, MnemonicType};
#[cfg(feature = "full_crypto")]
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "full_crypto")]
use secp256k1::{PublicKey, SecretKey};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
/// An identifier used to match public keys against ecdsa keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds");
@@ -165,7 +170,6 @@ impl sp_std::convert::TryFrom<&[u8]> for Public {
if data.len() == 33 {
Ok(Self::from_slice(data))
} else {
Err(())
}
}
@@ -206,14 +210,20 @@ impl sp_std::fmt::Debug for Public {
#[cfg(feature = "std")]
impl Serialize for Public {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_ss58check())
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Public {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Public::from_ss58check(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))
}
@@ -246,14 +256,20 @@ impl sp_std::convert::TryFrom<&[u8]> for Signature {
#[cfg(feature = "std")]
impl Serialize for Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(self))
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let signature_hex = hex::decode(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
Signature::try_from(signature_hex.as_ref())
@@ -359,7 +375,7 @@ impl Signature {
#[cfg(feature = "full_crypto")]
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
let message = secp256k1::Message::parse(message);
let sig: (_, _) = self.try_into().ok()?;
secp256k1::recover(&message, &sig.0, &sig.1)
@@ -381,7 +397,9 @@ impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature {
#[cfg(feature = "full_crypto")]
impl<'a> TryFrom<&'a Signature> for (secp256k1::Signature, secp256k1::RecoveryId) {
type Error = ();
fn try_from(x: &'a Signature) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> {
fn try_from(
x: &'a Signature,
) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> {
Ok((
secp256k1::Signature::parse_slice(&x.0[0..64]).expect("hardcoded to 64 bytes; qed"),
secp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?,
@@ -430,21 +448,22 @@ impl TraitPair for Pair {
let phrase = mnemonic.phrase();
let (pair, seed) = Self::from_phrase(phrase, password)
.expect("All phrases generated by Mnemonic are valid; qed");
(
pair,
phrase.to_owned(),
seed,
)
(pair, phrase.to_owned(), seed)
}
/// Generate key pair from given recovery phrase and password.
#[cfg(feature = "std")]
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Pair, Seed), SecretStringError> {
let big_seed = seed_from_entropy(
Mnemonic::from_phrase(phrase, Language::English)
.map_err(|_| SecretStringError::InvalidPhrase)?.entropy(),
.map_err(|_| SecretStringError::InvalidPhrase)?
.entropy(),
password.unwrap_or(""),
).map_err(|_| SecretStringError::InvalidSeed)?;
)
.map_err(|_| SecretStringError::InvalidSeed)?;
let mut seed = Seed::default();
seed.copy_from_slice(&big_seed[0..32]);
Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed))
@@ -462,16 +481,17 @@ impl TraitPair for Pair {
///
/// You should never need to use this; generate(), generate_with_phrase
fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> {
let secret = SecretKey::parse_slice(seed_slice)
.map_err(|_| SecretStringError::InvalidSeedLength)?;
let secret =
SecretKey::parse_slice(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?;
let public = PublicKey::from_secret_key(&secret);
Ok(Pair{ public, secret })
Ok(Pair { public, secret })
}
/// Derive a child key from a series of given junctions.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
_seed: Option<Seed>
_seed: Option<Seed>,
) -> Result<(Pair, Option<Seed>), DeriveError> {
let mut acc = self.secret.serialize();
for j in path {
@@ -497,7 +517,10 @@ impl TraitPair for Pair {
/// Verify a signature on a message. Returns true if the signature is good.
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
let sig: (_, _) = match sig.try_into() { Ok(x) => x, _ => return false };
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
_ => false,
@@ -510,9 +533,17 @@ impl TraitPair for Pair {
/// size. Use it only if you're coming from byte buffers and need the speed.
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
if sig.len() != 65 { return false }
let ri = match secp256k1::RecoveryId::parse(sig[64]) { Ok(x) => x, _ => return false };
let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) { Ok(x) => x, _ => return false };
if sig.len() != 65 {
return false
}
let ri = match secp256k1::RecoveryId::parse(sig[64]) {
Ok(x) => x,
_ => return false,
};
let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig, &ri) {
Ok(actual) => pubkey.as_ref() == &actual.serialize()[1..],
_ => false,
@@ -554,30 +585,30 @@ impl Pair {
/// and thus matches the given `public` key.
pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool {
let message = secp256k1::Message::parse(message);
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => public.0[..] == actual.serialize_compressed()[..],
_ => false,
}
}
}
}
impl CryptoType for Public {
#[cfg(feature="full_crypto")]
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
impl CryptoType for Signature {
#[cfg(feature="full_crypto")]
#[cfg(feature = "full_crypto")]
type Pair = Pair;
}
#[cfg(feature="full_crypto")]
#[cfg(feature = "full_crypto")]
impl CryptoType for Pair {
type Pair = Pair;
}
@@ -585,16 +616,20 @@ impl CryptoType for Pair {
#[cfg(test)]
mod test {
use super::*;
use crate::{
crypto::{set_default_ss58_version, PublicError, DEV_PHRASE},
keccak_256,
};
use hex_literal::hex;
use crate::{crypto::{DEV_PHRASE, set_default_ss58_version}, keccak_256};
use serde_json;
use crate::crypto::PublicError;
#[test]
fn default_phrase_should_be_used() {
assert_eq!(
Pair::from_string("//Alice///password", None).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password"))
.unwrap()
.public(),
);
}
@@ -613,9 +648,9 @@ mod test {
#[test]
fn test_vector_should_work() {
let pair = Pair::from_seed(
&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
);
let pair = Pair::from_seed(&hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let public = pair.public();
assert_eq!(
public,
@@ -634,8 +669,9 @@ mod test {
fn test_vector_by_string_should_work() {
let pair = Pair::from_string(
"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
None
).unwrap();
None,
)
.unwrap();
let public = pair.public();
assert_eq!(
public,
@@ -803,7 +839,8 @@ mod test {
// `msg` shouldn't be mangled
let msg = [0u8; 32];
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature = secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
let sig2: Signature =
secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
assert_eq!(sig1, sig2);
@@ -815,15 +852,16 @@ mod test {
// using pre-hashed `msg` works
let msg = keccak_256(b"this should be hashed");
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature = secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
let sig2: Signature =
secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
assert_eq!(sig1, sig2);
assert_eq!(sig1, sig2);
}
#[test]
fn verify_prehashed_works() {
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
// `msg` and `sig` match
let msg = keccak_256(b"this should be hashed");
let sig = pair.sign_prehashed(&msg);
+72 -45
View File
@@ -22,26 +22,28 @@
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use crate::{hash::H256, hash::H512};
use codec::{Encode, Decode, MaxEncodedLen};
use crate::hash::{H256, H512};
use codec::{Decode, Encode, MaxEncodedLen};
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
use crate::crypto::{
CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom,
};
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError};
#[cfg(feature = "std")]
use bip39::{Language, Mnemonic, MnemonicType};
#[cfg(feature = "full_crypto")]
use core::convert::TryFrom;
#[cfg(feature = "full_crypto")]
use ed25519_dalek::{Signer as _, Verifier as _};
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
#[cfg(feature = "std")]
use bip39::{Mnemonic, Language, MnemonicType};
#[cfg(feature = "full_crypto")]
use crate::crypto::{Pair as TraitPair, DeriveJunction, SecretStringError};
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
#[cfg(feature = "std")]
use serde::{de, Serializer, Serialize, Deserializer, Deserialize};
use crate::crypto::{Public as TraitPublic, CryptoTypePublicPair, UncheckedFrom, CryptoType, Derive, CryptoTypeId};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime_interface::pass_by::PassByInner;
use sp_std::ops::Deref;
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
/// An identifier used to match public keys against ed25519 keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ed25");
@@ -55,8 +57,7 @@ type Seed = [u8; 32];
/// A public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner,
MaxEncodedLen,
PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner, MaxEncodedLen,
)]
pub struct Public(pub [u8; 32]);
@@ -70,7 +71,7 @@ impl Clone for Pair {
Pair(ed25519_dalek::Keypair {
public: self.0.public,
secret: ed25519_dalek::SecretKey::from_bytes(self.0.secret.as_bytes())
.expect("key is always the correct size; qed")
.expect("key is always the correct size; qed"),
})
}
}
@@ -177,14 +178,20 @@ impl sp_std::fmt::Debug for Public {
#[cfg(feature = "std")]
impl Serialize for Public {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_ss58check())
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Public {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Public::from_ss58check(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))
}
@@ -210,14 +217,20 @@ impl sp_std::convert::TryFrom<&[u8]> for Signature {
#[cfg(feature = "std")]
impl Serialize for Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(self))
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let signature_hex = hex::decode(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
Signature::try_from(signature_hex.as_ref())
@@ -438,21 +451,22 @@ impl TraitPair for Pair {
let phrase = mnemonic.phrase();
let (pair, seed) = Self::from_phrase(phrase, password)
.expect("All phrases generated by Mnemonic are valid; qed");
(
pair,
phrase.to_owned(),
seed,
)
(pair, phrase.to_owned(), seed)
}
/// Generate key pair from given recovery phrase and password.
#[cfg(feature = "std")]
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Pair, Seed), SecretStringError> {
let big_seed = seed_from_entropy(
Mnemonic::from_phrase(phrase, Language::English)
.map_err(|_| SecretStringError::InvalidPhrase)?.entropy(),
.map_err(|_| SecretStringError::InvalidPhrase)?
.entropy(),
password.unwrap_or(""),
).map_err(|_| SecretStringError::InvalidSeed)?;
)
.map_err(|_| SecretStringError::InvalidSeed)?;
let mut seed = Seed::default();
seed.copy_from_slice(&big_seed[0..32]);
Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed))
@@ -477,7 +491,8 @@ impl TraitPair for Pair {
}
/// Derive a child key from a series of given junctions.
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
_seed: Option<Seed>,
) -> Result<(Pair, Option<Seed>), DeriveError> {
@@ -522,7 +537,7 @@ impl TraitPair for Pair {
let sig = match ed25519_dalek::Signature::try_from(sig) {
Ok(s) => s,
Err(_) => return false
Err(_) => return false,
};
public_key.verify(message.as_ref(), &sig).is_ok()
@@ -572,15 +587,17 @@ impl CryptoType for Pair {
#[cfg(test)]
mod test {
use super::*;
use hex_literal::hex;
use crate::crypto::DEV_PHRASE;
use hex_literal::hex;
use serde_json;
#[test]
fn default_phrase_should_be_used() {
assert_eq!(
Pair::from_string("//Alice///password", None).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password"))
.unwrap()
.public(),
);
}
@@ -599,13 +616,16 @@ mod test {
#[test]
fn test_vector_should_work() {
let pair = Pair::from_seed(
&hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60")
);
let public = pair.public();
assert_eq!(public, Public::from_raw(
hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
let pair = Pair::from_seed(&hex!(
"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
));
let public = pair.public();
assert_eq!(
public,
Public::from_raw(hex!(
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"
))
);
let message = b"";
let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
let signature = Signature::from_raw(signature);
@@ -617,12 +637,16 @@ mod test {
fn test_vector_by_string_should_work() {
let pair = Pair::from_string(
"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
None
).unwrap();
None,
)
.unwrap();
let public = pair.public();
assert_eq!(public, Public::from_raw(
hex!("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a")
));
assert_eq!(
public,
Public::from_raw(hex!(
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"
))
);
let message = b"";
let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b");
let signature = Signature::from_raw(signature);
@@ -644,9 +668,12 @@ mod test {
fn seeded_pair_should_work() {
let pair = Pair::from_seed(b"12345678901234567890123456789012");
let public = pair.public();
assert_eq!(public, Public::from_raw(
hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee")
));
assert_eq!(
public,
Public::from_raw(hex!(
"2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee"
))
);
let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000");
let signature = pair.sign(&message[..]);
println!("Correct signature: {:?}", signature);
+43 -10
View File
@@ -55,13 +55,34 @@ mod tests {
#[test]
fn test_h256() {
let tests = vec![
(Default::default(), "0x0000000000000000000000000000000000000000000000000000000000000000"),
(H256::from_low_u64_be(2), "0x0000000000000000000000000000000000000000000000000000000000000002"),
(H256::from_low_u64_be(15), "0x000000000000000000000000000000000000000000000000000000000000000f"),
(H256::from_low_u64_be(16), "0x0000000000000000000000000000000000000000000000000000000000000010"),
(H256::from_low_u64_be(1_000), "0x00000000000000000000000000000000000000000000000000000000000003e8"),
(H256::from_low_u64_be(100_000), "0x00000000000000000000000000000000000000000000000000000000000186a0"),
(H256::from_low_u64_be(u64::MAX), "0x000000000000000000000000000000000000000000000000ffffffffffffffff"),
(
Default::default(),
"0x0000000000000000000000000000000000000000000000000000000000000000",
),
(
H256::from_low_u64_be(2),
"0x0000000000000000000000000000000000000000000000000000000000000002",
),
(
H256::from_low_u64_be(15),
"0x000000000000000000000000000000000000000000000000000000000000000f",
),
(
H256::from_low_u64_be(16),
"0x0000000000000000000000000000000000000000000000000000000000000010",
),
(
H256::from_low_u64_be(1_000),
"0x00000000000000000000000000000000000000000000000000000000000003e8",
),
(
H256::from_low_u64_be(100_000),
"0x00000000000000000000000000000000000000000000000000000000000186a0",
),
(
H256::from_low_u64_be(u64::MAX),
"0x000000000000000000000000000000000000000000000000ffffffffffffffff",
),
];
for (number, expected) in tests {
@@ -72,9 +93,21 @@ mod tests {
#[test]
fn test_invalid() {
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000g\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0x00000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>(
"\"0x000000000000000000000000000000000000000000000000000000000000000\""
)
.unwrap_err()
.is_data());
assert!(ser::from_str::<H256>(
"\"0x000000000000000000000000000000000000000000000000000000000000000g\""
)
.unwrap_err()
.is_data());
assert!(ser::from_str::<H256>(
"\"0x00000000000000000000000000000000000000000000000000000000000000000\""
)
.unwrap_err()
.is_data());
assert!(ser::from_str::<H256>("\"\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"10\"").unwrap_err().is_data());
+4 -4
View File
@@ -18,9 +18,9 @@
//! Substrate Blake2b Hasher implementation
pub mod blake2 {
use hash_db::Hasher;
use hash256_std_hasher::Hash256StdHasher;
use crate::hash::H256;
use hash256_std_hasher::Hash256StdHasher;
use hash_db::Hasher;
/// Concrete implementation of Hasher using Blake2b 256-bit hashes
#[derive(Debug)]
@@ -38,9 +38,9 @@ pub mod blake2 {
}
pub mod keccak {
use hash_db::Hasher;
use hash256_std_hasher::Hash256StdHasher;
use crate::hash::H256;
use hash256_std_hasher::Hash256StdHasher;
use hash_db::Hasher;
/// Concrete implementation of Hasher using Keccak 256-bit hashes
#[derive(Debug)]
+18 -8
View File
@@ -22,7 +22,9 @@ pub struct HexDisplay<'a>(&'a [u8]);
impl<'a> HexDisplay<'a> {
/// Create new instance that will display `d` as a hex string when displayed.
pub fn from<R: AsBytesRef>(d: &'a R) -> Self { HexDisplay(d.as_bytes_ref()) }
pub fn from<R: AsBytesRef>(d: &'a R) -> Self {
HexDisplay(d.as_bytes_ref())
}
}
impl<'a> sp_std::fmt::Display for HexDisplay<'a> {
@@ -60,15 +62,21 @@ pub trait AsBytesRef {
}
impl AsBytesRef for &[u8] {
fn as_bytes_ref(&self) -> &[u8] { self }
fn as_bytes_ref(&self) -> &[u8] {
self
}
}
impl AsBytesRef for [u8] {
fn as_bytes_ref(&self) -> &[u8] { &self }
fn as_bytes_ref(&self) -> &[u8] {
&self
}
}
impl AsBytesRef for sp_std::vec::Vec<u8> {
fn as_bytes_ref(&self) -> &[u8] { &self }
fn as_bytes_ref(&self) -> &[u8] {
&self
}
}
impl AsBytesRef for sp_storage::StorageKey {
@@ -85,9 +93,11 @@ macro_rules! impl_non_endians {
)* }
}
impl_non_endians!([u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8],
[u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40],
[u8; 48], [u8; 56], [u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128]);
impl_non_endians!(
[u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], [u8; 10], [u8; 12],
[u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], [u8; 48], [u8; 56],
[u8; 64], [u8; 65], [u8; 80], [u8; 96], [u8; 112], [u8; 128]
);
/// Format into ASCII + # + hex, suitable for storage key preimages.
#[cfg(feature = "std")]
@@ -103,7 +113,7 @@ pub fn ascii_format(asciish: &[u8]) -> String {
latch = true;
}
r.push_str(&format!("{:02x}", *c));
}
},
}
}
r
+37 -29
View File
@@ -18,7 +18,6 @@
//! Shareable Substrate types.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
/// Initialize a key-value collection from array.
@@ -32,17 +31,16 @@ macro_rules! map {
);
}
use sp_runtime_interface::pass_by::{PassByEnum, PassByInner};
use sp_std::prelude::*;
use sp_std::ops::Deref;
#[cfg(feature = "std")]
use std::borrow::Cow;
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
#[doc(hidden)]
pub use codec::{Decode, Encode};
#[cfg(feature = "std")]
pub use serde;
#[doc(hidden)]
pub use codec::{Encode, Decode};
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use sp_runtime_interface::pass_by::{PassByEnum, PassByInner};
use sp_std::{ops::Deref, prelude::*};
#[cfg(feature = "std")]
use std::borrow::Cow;
pub use sp_debug_derive::RuntimeDebug;
@@ -53,37 +51,39 @@ pub use impl_serde::serialize as bytes;
pub mod hashing;
#[cfg(feature = "full_crypto")]
pub use hashing::{blake2_128, blake2_256, twox_64, twox_128, twox_256, keccak_256};
pub mod hexdisplay;
pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64};
pub mod crypto;
pub mod hexdisplay;
pub mod u32_trait;
pub mod ed25519;
pub mod sr25519;
mod changes_trie;
pub mod ecdsa;
pub mod ed25519;
pub mod hash;
#[cfg(feature = "std")]
mod hasher;
pub mod offchain;
pub mod sandbox;
pub mod uint;
mod changes_trie;
pub mod sr25519;
pub mod testing;
#[cfg(feature = "std")]
pub mod traits;
pub mod testing;
pub mod uint;
pub use self::hash::{H160, H256, H512, convert_hash};
pub use self::uint::{U256, U512};
pub use self::{
hash::{convert_hash, H160, H256, H512},
uint::{U256, U512},
};
pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange};
#[cfg(feature = "full_crypto")]
pub use crypto::{DeriveJunction, Pair, Public};
pub use hash_db::Hasher;
#[cfg(feature = "std")]
pub use self::hasher::blake2::Blake2Hasher;
#[cfg(feature = "std")]
pub use self::hasher::keccak::KeccakHasher;
pub use hash_db::Hasher;
pub use sp_storage as storage;
@@ -117,14 +117,14 @@ impl ExecutionContext {
use ExecutionContext::*;
match self {
Importing | Syncing | BlockConstruction =>
offchain::Capabilities::none(),
Importing | Syncing | BlockConstruction => offchain::Capabilities::none(),
// Enable keystore, transaction pool and Offchain DB reads by default for offchain calls.
OffchainCall(None) => [
offchain::Capability::Keystore,
offchain::Capability::OffchainDbRead,
offchain::Capability::TransactionPool,
][..].into(),
][..]
.into(),
OffchainCall(Some((_, capabilities))) => *capabilities,
}
}
@@ -133,19 +133,25 @@ impl ExecutionContext {
/// Hex-serialized shim for `Vec<u8>`.
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, PartialOrd, Ord))]
pub struct Bytes(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
pub struct Bytes(#[cfg_attr(feature = "std", serde(with = "bytes"))] pub Vec<u8>);
impl From<Vec<u8>> for Bytes {
fn from(s: Vec<u8>) -> Self { Bytes(s) }
fn from(s: Vec<u8>) -> Self {
Bytes(s)
}
}
impl From<OpaqueMetadata> for Bytes {
fn from(s: OpaqueMetadata) -> Self { Bytes(s.0) }
fn from(s: OpaqueMetadata) -> Self {
Bytes(s.0)
}
}
impl Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &[u8] { &self.0[..] }
fn deref(&self) -> &[u8] {
&self.0[..]
}
}
impl codec::WrapperTypeEncode for Bytes {}
@@ -183,7 +189,9 @@ impl sp_std::ops::Deref for OpaqueMetadata {
}
/// Simple blob to hold a `PeerId` without committing to its format.
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, PassByInner)]
#[derive(
Default, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, PassByInner,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct OpaquePeerId(pub Vec<u8>);
@@ -200,7 +208,7 @@ pub enum NativeOrEncoded<R> {
/// The native representation.
Native(R),
/// The encoded representation.
Encoded(Vec<u8>)
Encoded(Vec<u8>),
}
#[cfg(feature = "std")]
+67 -43
View File
@@ -17,10 +17,13 @@
//! Offchain workers types
use codec::{Encode, Decode};
use sp_std::{prelude::{Vec, Box}, convert::TryFrom};
use crate::{OpaquePeerId, RuntimeDebug};
use sp_runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum};
use codec::{Decode, Encode};
use sp_runtime_interface::pass_by::{PassByCodec, PassByEnum, PassByInner};
use sp_std::{
convert::TryFrom,
prelude::{Box, Vec},
};
pub use crate::crypto::KeyTypeId;
@@ -30,7 +33,7 @@ pub mod storage;
pub mod testing;
/// Persistent storage prefix used by the Offchain Worker API when creating a DB key.
pub const STORAGE_PREFIX : &[u8] = b"storage";
pub const STORAGE_PREFIX: &[u8] = b"storage";
/// Offchain DB persistent (non-fork-aware) storage.
pub trait OffchainStorage: Clone + Send + Sync {
@@ -93,7 +96,9 @@ impl From<StorageKind> for u32 {
}
/// Opaque type for offchain http requests.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, PassByInner)]
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, Encode, Decode, PassByInner,
)]
#[cfg_attr(feature = "std", derive(Hash))]
pub struct HttpRequestId(pub u16);
@@ -123,7 +128,7 @@ impl TryFrom<u32> for HttpError {
e if e == HttpError::DeadlineReached as u8 as u32 => Ok(HttpError::DeadlineReached),
e if e == HttpError::IoError as u8 as u32 => Ok(HttpError::IoError),
e if e == HttpError::Invalid as u8 as u32 => Ok(HttpError::Invalid),
_ => Err(())
_ => Err(()),
}
}
}
@@ -202,11 +207,15 @@ impl OpaqueMultiaddr {
}
/// Opaque timestamp type
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
#[derive(
Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode,
)]
pub struct Timestamp(u64);
/// Duration type
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode)]
#[derive(
Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Default, RuntimeDebug, PassByInner, Encode, Decode,
)]
pub struct Duration(u64);
impl Duration {
@@ -290,11 +299,7 @@ impl Capabilities {
/// Those calls should be allowed to sign and submit transactions
/// and access offchain workers database (but read only!).
pub fn rich_offchain_call() -> Self {
[
Capability::TransactionPool,
Capability::Keystore,
Capability::OffchainDbRead,
][..].into()
[Capability::TransactionPool, Capability::Keystore, Capability::OffchainDbRead][..].into()
}
/// Check if particular capability is enabled.
@@ -345,12 +350,11 @@ pub trait Externalities: Send {
/// Returns an error if:
/// - No new request identifier could be allocated.
/// - The method or URI contain invalid characters.
///
fn http_request_start(
&mut self,
method: &str,
uri: &str,
meta: &[u8]
meta: &[u8],
) -> Result<HttpRequestId, ()>;
/// Append header to the request.
@@ -365,12 +369,11 @@ pub trait Externalities: Send {
///
/// An error doesn't poison the request, and you can continue as if the call had never been
/// made.
///
fn http_request_add_header(
&mut self,
request_id: HttpRequestId,
name: &str,
value: &str
value: &str,
) -> Result<(), ()>;
/// Write a chunk of request body.
@@ -387,12 +390,11 @@ pub trait Externalities: Send {
/// - The deadline is reached.
/// - An I/O error has happened, for example the remote has closed our
/// request. The request is then considered invalid.
///
fn http_request_write_body(
&mut self,
request_id: HttpRequestId,
chunk: &[u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<(), HttpError>;
/// Block and wait for the responses for given requests.
@@ -408,7 +410,7 @@ pub trait Externalities: Send {
fn http_response_wait(
&mut self,
ids: &[HttpRequestId],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Vec<HttpRequestStatus>;
/// Read all response headers.
@@ -420,10 +422,7 @@ pub trait Externalities: Send {
///
/// Returns an empty list if the identifier is unknown/invalid, hasn't
/// received a response, or has finished.
fn http_response_headers(
&mut self,
request_id: HttpRequestId
) -> Vec<(Vec<u8>, Vec<u8>)>;
fn http_response_headers(&mut self, request_id: HttpRequestId) -> Vec<(Vec<u8>, Vec<u8>)>;
/// Read a chunk of body response to given buffer.
///
@@ -443,12 +442,11 @@ pub trait Externalities: Send {
/// - The deadline is reached.
/// - An I/O error has happened, for example the remote has closed our
/// request. The request is then considered invalid.
///
fn http_response_read_body(
&mut self,
request_id: HttpRequestId,
buffer: &mut [u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<usize, HttpError>;
/// Set the authorized nodes from runtime.
@@ -466,11 +464,11 @@ pub trait Externalities: Send {
impl<T: Externalities + ?Sized> Externalities for Box<T> {
fn is_validator(&self) -> bool {
(& **self).is_validator()
(&**self).is_validator()
}
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
(& **self).network_state()
(&**self).network_state()
}
fn timestamp(&mut self) -> Timestamp {
@@ -485,11 +483,21 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
(&mut **self).random_seed()
}
fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
fn http_request_start(
&mut self,
method: &str,
uri: &str,
meta: &[u8],
) -> Result<HttpRequestId, ()> {
(&mut **self).http_request_start(method, uri, meta)
}
fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
fn http_request_add_header(
&mut self,
request_id: HttpRequestId,
name: &str,
value: &str,
) -> Result<(), ()> {
(&mut **self).http_request_add_header(request_id, name, value)
}
@@ -497,12 +505,16 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
&mut self,
request_id: HttpRequestId,
chunk: &[u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<(), HttpError> {
(&mut **self).http_request_write_body(request_id, chunk, deadline)
}
fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
fn http_response_wait(
&mut self,
ids: &[HttpRequestId],
deadline: Option<Timestamp>,
) -> Vec<HttpRequestStatus> {
(&mut **self).http_response_wait(ids, deadline)
}
@@ -514,7 +526,7 @@ impl<T: Externalities + ?Sized> Externalities for Box<T> {
&mut self,
request_id: HttpRequestId,
buffer: &mut [u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<usize, HttpError> {
(&mut **self).http_response_read_body(request_id, buffer, deadline)
}
@@ -533,10 +545,7 @@ pub struct LimitedExternalities<T> {
impl<T> LimitedExternalities<T> {
/// Create new externalities limited to given `capabilities`.
pub fn new(capabilities: Capabilities, externalities: T) -> Self {
Self {
capabilities,
externalities,
}
Self { capabilities, externalities }
}
/// Check if given capability is allowed.
@@ -575,12 +584,22 @@ impl<T: Externalities> Externalities for LimitedExternalities<T> {
self.externalities.random_seed()
}
fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<HttpRequestId, ()> {
fn http_request_start(
&mut self,
method: &str,
uri: &str,
meta: &[u8],
) -> Result<HttpRequestId, ()> {
self.check(Capability::Http, "http_request_start");
self.externalities.http_request_start(method, uri, meta)
}
fn http_request_add_header(&mut self, request_id: HttpRequestId, name: &str, value: &str) -> Result<(), ()> {
fn http_request_add_header(
&mut self,
request_id: HttpRequestId,
name: &str,
value: &str,
) -> Result<(), ()> {
self.check(Capability::Http, "http_request_add_header");
self.externalities.http_request_add_header(request_id, name, value)
}
@@ -589,13 +608,17 @@ impl<T: Externalities> Externalities for LimitedExternalities<T> {
&mut self,
request_id: HttpRequestId,
chunk: &[u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<(), HttpError> {
self.check(Capability::Http, "http_request_write_body");
self.externalities.http_request_write_body(request_id, chunk, deadline)
}
fn http_response_wait(&mut self, ids: &[HttpRequestId], deadline: Option<Timestamp>) -> Vec<HttpRequestStatus> {
fn http_response_wait(
&mut self,
ids: &[HttpRequestId],
deadline: Option<Timestamp>,
) -> Vec<HttpRequestStatus> {
self.check(Capability::Http, "http_response_wait");
self.externalities.http_response_wait(ids, deadline)
}
@@ -609,7 +632,7 @@ impl<T: Externalities> Externalities for LimitedExternalities<T> {
&mut self,
request_id: HttpRequestId,
buffer: &mut [u8],
deadline: Option<Timestamp>
deadline: Option<Timestamp>,
) -> Result<usize, HttpError> {
self.check(Capability::Http, "http_response_read_body");
self.externalities.http_response_read_body(request_id, buffer, deadline)
@@ -717,7 +740,8 @@ impl<T: DbExternalities> DbExternalities for LimitedExternalities<T> {
new_value: &[u8],
) -> bool {
self.check(Capability::OffchainDbWrite, "local_storage_compare_and_set");
self.externalities.local_storage_compare_and_set(kind, key, old_value, new_value)
self.externalities
.local_storage_compare_and_set(kind, key, old_value, new_value)
}
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
@@ -17,9 +17,11 @@
//! In-memory implementation of offchain workers database.
use std::collections::hash_map::{HashMap, Entry};
use crate::offchain::OffchainStorage;
use std::iter::Iterator;
use std::{
collections::hash_map::{Entry, HashMap},
iter::Iterator,
};
/// In-memory storage for offchain workers.
#[derive(Debug, Clone, Default)]
@@ -29,12 +31,12 @@ pub struct InMemOffchainStorage {
impl InMemOffchainStorage {
/// Consume the offchain storage and iterate over all key value pairs.
pub fn into_iter(self) -> impl Iterator<Item=(Vec<u8>,Vec<u8>)> {
pub fn into_iter(self) -> impl Iterator<Item = (Vec<u8>, Vec<u8>)> {
self.storage.into_iter()
}
/// Iterate over all key value pairs by reference.
pub fn iter(&self) -> impl Iterator<Item=(&Vec<u8>,&Vec<u8>)> {
pub fn iter(&self) -> impl Iterator<Item = (&Vec<u8>, &Vec<u8>)> {
self.storage.iter()
}
@@ -71,10 +73,13 @@ impl OffchainStorage for InMemOffchainStorage {
let key = prefix.iter().chain(key).cloned().collect();
match self.storage.entry(key) {
Entry::Vacant(entry) => if old_value.is_none() {
entry.insert(new_value.to_vec());
true
} else { false },
Entry::Vacant(entry) =>
if old_value.is_none() {
entry.insert(new_value.to_vec());
true
} else {
false
},
Entry::Occupied(ref mut entry) if Some(entry.get().as_slice()) == old_value => {
entry.insert(new_value.to_vec());
true
@@ -20,24 +20,18 @@
//! Namely all ExecutionExtensions that allow mocking
//! the extra APIs.
use crate::{
offchain::{
self, storage::InMemOffchainStorage, HttpError, HttpRequestId as RequestId,
HttpRequestStatus as RequestStatus, OffchainOverlayedChange, OffchainStorage,
OpaqueNetworkState, StorageKind, Timestamp, TransactionPool,
},
OpaquePeerId,
};
use std::{
collections::{BTreeMap, VecDeque},
sync::Arc,
};
use crate::OpaquePeerId;
use crate::offchain::{
self,
OffchainOverlayedChange,
storage::InMemOffchainStorage,
HttpError,
HttpRequestId as RequestId,
HttpRequestStatus as RequestStatus,
Timestamp,
StorageKind,
OpaqueNetworkState,
TransactionPool,
OffchainStorage,
};
use parking_lot::RwLock;
@@ -75,9 +69,7 @@ impl TestPersistentOffchainDB {
/// Create a new and empty offchain storage db for persistent items
pub fn new() -> Self {
Self {
persistent: Arc::new(RwLock::new(InMemOffchainStorage::default()))
}
Self { persistent: Arc::new(RwLock::new(InMemOffchainStorage::default())) }
}
/// Apply a set of off-chain changes directly to the test backend
@@ -88,7 +80,8 @@ impl TestPersistentOffchainDB {
let mut me = self.persistent.write();
for ((_prefix, key), value_operation) in changes {
match value_operation {
OffchainOverlayedChange::SetValue(val) => me.set(Self::PREFIX, key.as_slice(), val.as_slice()),
OffchainOverlayedChange::SetValue(val) =>
me.set(Self::PREFIX, key.as_slice(), val.as_slice()),
OffchainOverlayedChange::Remove => me.remove(Self::PREFIX, key.as_slice()),
}
}
@@ -124,7 +117,6 @@ impl OffchainStorage for TestPersistentOffchainDB {
}
}
/// Internal state of the externalities.
///
/// This can be used in tests to respond or assert stuff about interactions.
@@ -151,20 +143,17 @@ impl OffchainState {
id: u16,
expected: PendingRequest,
response: impl Into<Vec<u8>>,
response_headers: impl IntoIterator<Item=(String, String)>,
response_headers: impl IntoIterator<Item = (String, String)>,
) {
match self.requests.get_mut(&RequestId(id)) {
None => {
panic!("Missing pending request: {:?}.\n\nAll: {:?}", id, self.requests);
}
},
Some(req) => {
assert_eq!(
*req,
expected,
);
assert_eq!(*req, expected,);
req.response = Some(response.into());
req.response_headers = response_headers.into_iter().collect();
}
},
}
}
@@ -213,7 +202,9 @@ impl TestOffchainExt {
}
/// Create new `TestOffchainExt` and a reference to the internal state.
pub fn with_offchain_db(offchain_db: TestPersistentOffchainDB) -> (Self, Arc<RwLock<OffchainState>>) {
pub fn with_offchain_db(
offchain_db: TestPersistentOffchainDB,
) -> (Self, Arc<RwLock<OffchainState>>) {
let (ext, state) = Self::new();
ext.0.write().persistent_storage = offchain_db;
(ext, state)
@@ -226,10 +217,7 @@ impl offchain::Externalities for TestOffchainExt {
}
fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
Ok(OpaqueNetworkState {
peer_id: Default::default(),
external_addresses: vec![],
})
Ok(OpaqueNetworkState { peer_id: Default::default(), external_addresses: vec![] })
}
fn timestamp(&mut self) -> Timestamp {
@@ -244,15 +232,23 @@ impl offchain::Externalities for TestOffchainExt {
self.0.read().seed
}
fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<RequestId, ()> {
fn http_request_start(
&mut self,
method: &str,
uri: &str,
meta: &[u8],
) -> Result<RequestId, ()> {
let mut state = self.0.write();
let id = RequestId(state.requests.len() as u16);
state.requests.insert(id, PendingRequest {
method: method.into(),
uri: uri.into(),
meta: meta.into(),
..Default::default()
});
state.requests.insert(
id,
PendingRequest {
method: method.into(),
uri: uri.into(),
meta: meta.into(),
..Default::default()
},
);
Ok(id)
}
@@ -275,7 +271,7 @@ impl offchain::Externalities for TestOffchainExt {
&mut self,
request_id: RequestId,
chunk: &[u8],
_deadline: Option<Timestamp>
_deadline: Option<Timestamp>,
) -> Result<(), HttpError> {
let mut state = self.0.write();
@@ -302,12 +298,14 @@ impl offchain::Externalities for TestOffchainExt {
) -> Vec<RequestStatus> {
let state = self.0.read();
ids.iter().map(|id| match state.requests.get(id) {
Some(req) if req.response.is_none() =>
panic!("No `response` provided for request with id: {:?}", id),
None => RequestStatus::Invalid,
_ => RequestStatus::Finished(200),
}).collect()
ids.iter()
.map(|id| match state.requests.get(id) {
Some(req) if req.response.is_none() =>
panic!("No `response` provided for request with id: {:?}", id),
None => RequestStatus::Invalid,
_ => RequestStatus::Finished(200),
})
.collect()
}
fn http_response_headers(&mut self, request_id: RequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
@@ -327,11 +325,12 @@ impl offchain::Externalities for TestOffchainExt {
&mut self,
request_id: RequestId,
buffer: &mut [u8],
_deadline: Option<Timestamp>
_deadline: Option<Timestamp>,
) -> Result<usize, HttpError> {
let mut state = self.0.write();
if let Some(req) = state.requests.get_mut(&request_id) {
let response = req.response
let response = req
.response
.as_mut()
.unwrap_or_else(|| panic!("No response provided for request: {:?}", request_id));
@@ -377,14 +376,14 @@ impl offchain::DbExternalities for TestOffchainExt {
kind: StorageKind,
key: &[u8],
old_value: Option<&[u8]>,
new_value: &[u8]
new_value: &[u8],
) -> bool {
let mut state = self.0.write();
match kind {
StorageKind::LOCAL => state.local_storage
.compare_and_set(b"", key, old_value, new_value),
StorageKind::PERSISTENT => state.persistent_storage
.compare_and_set(b"", key, old_value, new_value),
StorageKind::LOCAL =>
state.local_storage.compare_and_set(b"", key, old_value, new_value),
StorageKind::PERSISTENT =>
state.persistent_storage.compare_and_set(b"", key, old_value, new_value),
}
}
+18 -28
View File
@@ -17,17 +17,15 @@
//! Definition of a sandbox environment.
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use sp_std::vec::Vec;
/// Error error that can be returned from host function.
#[derive(Encode, Decode)]
#[derive(crate::RuntimeDebug)]
#[derive(Encode, Decode, crate::RuntimeDebug)]
pub struct HostError;
/// Describes an entity to define or import into the environment.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[derive(crate::RuntimeDebug)]
#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)]
pub enum ExternEntity {
/// Function that is specified by an index in a default table of
/// a module that creates the sandbox.
@@ -44,8 +42,7 @@ pub enum ExternEntity {
///
/// Each entry has a two-level name and description of an entity
/// being defined.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[derive(crate::RuntimeDebug)]
#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)]
pub struct Entry {
/// Module name of which corresponding entity being defined.
pub module_name: Vec<u8>,
@@ -56,8 +53,7 @@ pub struct Entry {
}
/// Definition of runtime that could be used by sandboxed code.
#[derive(Clone, PartialEq, Eq, Encode, Decode)]
#[derive(crate::RuntimeDebug)]
#[derive(Clone, PartialEq, Eq, Encode, Decode, crate::RuntimeDebug)]
pub struct EnvironmentDefinition {
/// Vector of all entries in the environment definition.
pub entries: Vec<Entry>,
@@ -91,8 +87,8 @@ pub const ERR_EXECUTION: u32 = -3i32 as u32;
#[cfg(test)]
mod tests {
use super::*;
use std::fmt;
use codec::Codec;
use std::fmt;
fn roundtrip<S: Codec + PartialEq + fmt::Debug>(s: S) {
let encoded = s.encode();
@@ -101,28 +97,22 @@ mod tests {
#[test]
fn env_def_roundtrip() {
roundtrip(EnvironmentDefinition { entries: vec![] });
roundtrip(EnvironmentDefinition {
entries: vec![],
entries: vec![Entry {
module_name: b"kernel"[..].into(),
field_name: b"memory"[..].into(),
entity: ExternEntity::Memory(1337),
}],
});
roundtrip(EnvironmentDefinition {
entries: vec![
Entry {
module_name: b"kernel"[..].into(),
field_name: b"memory"[..].into(),
entity: ExternEntity::Memory(1337),
},
],
});
roundtrip(EnvironmentDefinition {
entries: vec![
Entry {
module_name: b"env"[..].into(),
field_name: b"abort"[..].into(),
entity: ExternEntity::Function(228),
},
],
entries: vec![Entry {
module_name: b"env"[..].into(),
field_name: b"abort"[..].into(),
entity: ExternEntity::Function(228),
}],
});
}
}
+92 -75
View File
@@ -21,34 +21,38 @@
//! Note: `CHAIN_CODE_LENGTH` must be equal to `crate::crypto::JUNCTION_ID_LEN`
//! for this to work.
// end::description[]
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
#[cfg(feature = "full_crypto")]
use crate::crypto::{DeriveJunction, Infallible, Pair as TraitPair, SecretStringError};
#[cfg(feature = "std")]
use bip39::{Language, Mnemonic, MnemonicType};
#[cfg(feature = "full_crypto")]
use schnorrkel::{
derive::{ChainCode, Derivation, CHAIN_CODE_LENGTH},
signing_context, ExpansionMode, Keypair, MiniSecretKey, PublicKey, SecretKey,
};
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
#[cfg(feature = "full_crypto")]
use schnorrkel::{signing_context, ExpansionMode, Keypair, SecretKey, MiniSecretKey, PublicKey,
derive::{Derivation, ChainCode, CHAIN_CODE_LENGTH}
};
#[cfg(feature = "std")]
use std::convert::TryFrom;
#[cfg(feature = "std")]
use substrate_bip39::mini_secret_from_entropy;
#[cfg(feature = "std")]
use bip39::{Mnemonic, Language, MnemonicType};
#[cfg(feature = "full_crypto")]
use crate::crypto::{
Pair as TraitPair, DeriveJunction, Infallible, SecretStringError
};
#[cfg(feature = "std")]
use crate::crypto::Ss58Codec;
use crate::crypto::{Public as TraitPublic, CryptoTypePublicPair, UncheckedFrom, CryptoType, Derive, CryptoTypeId};
use crate::hash::{H256, H512};
use codec::{Encode, Decode, MaxEncodedLen};
use crate::{
crypto::{
CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic,
UncheckedFrom,
},
hash::{H256, H512},
};
use codec::{Decode, Encode, MaxEncodedLen};
use sp_std::ops::Deref;
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "full_crypto")]
use schnorrkel::keys::{MINI_SECRET_KEY_LENGTH, SECRET_KEY_LENGTH};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime_interface::pass_by::PassByInner;
// signing context
@@ -61,8 +65,7 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25");
/// An Schnorrkel/Ristretto x25519 ("sr25519") public key.
#[cfg_attr(feature = "full_crypto", derive(Hash))]
#[derive(
PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner,
MaxEncodedLen,
PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner, MaxEncodedLen,
)]
pub struct Public(pub [u8; 32]);
@@ -76,7 +79,7 @@ impl Clone for Pair {
Pair(schnorrkel::Keypair {
public: self.0.public,
secret: schnorrkel::SecretKey::from_bytes(&self.0.secret.to_bytes()[..])
.expect("key is always the correct size; qed")
.expect("key is always the correct size; qed"),
})
}
}
@@ -176,14 +179,20 @@ impl sp_std::fmt::Debug for Public {
#[cfg(feature = "std")]
impl Serialize for Public {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_ss58check())
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Public {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Public::from_ss58check(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))
}
@@ -211,14 +220,20 @@ impl sp_std::convert::TryFrom<&[u8]> for Signature {
#[cfg(feature = "std")]
impl Serialize for Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(self))
}
}
#[cfg(feature = "std")]
impl<'de> Deserialize<'de> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let signature_hex = hex::decode(&String::deserialize(deserializer)?)
.map_err(|e| de::Error::custom(format!("{:?}", e)))?;
Signature::try_from(signature_hex.as_ref())
@@ -350,7 +365,7 @@ impl Derive for Public {
///
/// `None` if there are any hard junctions in there.
#[cfg(feature = "std")]
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Option<Public> {
fn derive<Iter: Iterator<Item = DeriveJunction>>(&self, path: Iter) -> Option<Public> {
let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?;
for j in path {
match j {
@@ -471,8 +486,7 @@ impl TraitPair for Pair {
///
/// A MiniSecretKey is literally what Ed25519 calls a SecretKey, which is just 32 random bytes.
fn from_seed(seed: &Seed) -> Pair {
Self::from_seed_slice(&seed[..])
.expect("32 bytes can always build a key; qed")
Self::from_seed_slice(&seed[..]).expect("32 bytes can always build a key; qed")
}
/// Get the public key.
@@ -488,21 +502,17 @@ impl TraitPair for Pair {
/// You should never need to use this; generate(), generate_with_phrase(), from_phrase()
fn from_seed_slice(seed: &[u8]) -> Result<Pair, SecretStringError> {
match seed.len() {
MINI_SECRET_KEY_LENGTH => {
Ok(Pair(
MiniSecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.expand_to_keypair(ExpansionMode::Ed25519)
))
}
SECRET_KEY_LENGTH => {
Ok(Pair(
SecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.to_keypair()
))
}
_ => Err(SecretStringError::InvalidSeedLength)
MINI_SECRET_KEY_LENGTH => Ok(Pair(
MiniSecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.expand_to_keypair(ExpansionMode::Ed25519),
)),
SECRET_KEY_LENGTH => Ok(Pair(
SecretKey::from_bytes(seed)
.map_err(|_| SecretStringError::InvalidSeed)?
.to_keypair(),
)),
_ => Err(SecretStringError::InvalidSeedLength),
}
}
#[cfg(feature = "std")]
@@ -511,20 +521,20 @@ impl TraitPair for Pair {
let phrase = mnemonic.phrase();
let (pair, seed) = Self::from_phrase(phrase, password)
.expect("All phrases generated by Mnemonic are valid; qed");
(
pair,
phrase.to_owned(),
seed,
)
(pair, phrase.to_owned(), seed)
}
#[cfg(feature = "std")]
fn from_phrase(phrase: &str, password: Option<&str>) -> Result<(Pair, Seed), SecretStringError> {
fn from_phrase(
phrase: &str,
password: Option<&str>,
) -> Result<(Pair, Seed), SecretStringError> {
Mnemonic::from_phrase(phrase, Language::English)
.map_err(|_| SecretStringError::InvalidPhrase)
.map(|m| Self::from_entropy(m.entropy(), password))
}
fn derive<Iter: Iterator<Item=DeriveJunction>>(&self,
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
seed: Option<Seed>,
) -> Result<(Pair, Option<Seed>), Self::DeriveError> {
@@ -532,17 +542,22 @@ impl TraitPair for Pair {
if let Ok(msk) = MiniSecretKey::from_bytes(&s) {
if msk.expand(ExpansionMode::Ed25519) == self.0.secret {
Some(msk)
} else { None }
} else { None }
} else { None };
} else {
None
}
} else {
None
}
} else {
None
};
let init = self.0.secret.clone();
let (result, seed) = path.fold((init, seed), |(acc, acc_seed), j| match (j, acc_seed) {
(DeriveJunction::Soft(cc), _) =>
(acc.derived_key_simple(ChainCode(cc), &[]).0, None),
(DeriveJunction::Soft(cc), _) => (acc.derived_key_simple(ChainCode(cc), &[]).0, None),
(DeriveJunction::Hard(cc), maybe_seed) => {
let seed = derive_hard_junction(&acc, &cc);
(seed.expand(ExpansionMode::Ed25519), maybe_seed.map(|_| seed))
}
},
});
Ok((Self(result.into()), seed.map(|s| MiniSecretKey::to_bytes(&s))))
}
@@ -596,9 +611,9 @@ impl Pair {
// Match both schnorrkel 0.1.1 and 0.8.0+ signatures, supporting both wallets
// that have not been upgraded and those that have.
match PublicKey::from_bytes(pubkey.as_ref()) {
Ok(pk) => pk.verify_simple_preaudit_deprecated(
SIGNING_CTX, message.as_ref(), &sig.0[..],
).is_ok(),
Ok(pk) => pk
.verify_simple_preaudit_deprecated(SIGNING_CTX, message.as_ref(), &sig.0[..])
.is_ok(),
Err(_) => false,
}
}
@@ -642,20 +657,16 @@ pub fn verify_batch(
for signature in signatures {
match schnorrkel::Signature::from_bytes(signature.as_ref()) {
Ok(s) => sr_signatures.push(s),
Err(_) => return false
Err(_) => return false,
};
}
let mut messages: Vec<merlin::Transcript> = messages.into_iter().map(
|msg| signing_context(SIGNING_CTX).bytes(msg)
).collect();
let mut messages: Vec<merlin::Transcript> = messages
.into_iter()
.map(|msg| signing_context(SIGNING_CTX).bytes(msg))
.collect();
schnorrkel::verify_batch(
&mut messages,
&sr_signatures,
&sr_pub_keys,
true,
).is_ok()
schnorrkel::verify_batch(&mut messages, &sr_signatures, &sr_pub_keys, true).is_ok()
}
#[cfg(test)]
@@ -685,7 +696,9 @@ mod compatibility_test {
#[test]
fn verify_known_old_message_should_work() {
let public = Public::from_raw(hex!("b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918"));
let public = Public::from_raw(hex!(
"b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918"
));
// signature generated by the 1.1 version with the same ^^ public key.
let signature = Signature::from_raw(hex!(
"5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202"
@@ -699,7 +712,7 @@ mod compatibility_test {
#[cfg(test)]
mod test {
use super::*;
use crate::crypto::{Ss58Codec, DEV_PHRASE, DEV_ADDRESS};
use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE};
use hex_literal::hex;
use serde_json;
@@ -707,10 +720,14 @@ mod test {
fn default_phrase_should_be_used() {
assert_eq!(
Pair::from_string("//Alice///password", None).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")).unwrap().public(),
Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password"))
.unwrap()
.public(),
);
assert_eq!(
Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).as_ref().map(Pair::public),
Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None)
.as_ref()
.map(Pair::public),
Pair::from_string("/Alice", None).as_ref().map(Pair::public)
);
}
@@ -856,9 +873,9 @@ mod test {
// The values in this test case are compared to the output of `node-test.js` in schnorrkel-js.
//
// This is to make sure that the wasm library is compatible.
let pk = Pair::from_seed(
&hex!("0000000000000000000000000000000000000000000000000000000000000000")
);
let pk = Pair::from_seed(&hex!(
"0000000000000000000000000000000000000000000000000000000000000000"
));
let public = pk.public();
let js_signature = Signature::from_raw(hex!(
"28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00"
+5 -1
View File
@@ -162,7 +162,11 @@ impl crate::traits::SpawnNamed for TaskExecutor {
#[cfg(feature = "std")]
impl crate::traits::SpawnEssentialNamed for TaskExecutor {
fn spawn_essential_blocking(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
fn spawn_essential_blocking(
&self,
_: &'static str,
future: futures::future::BoxFuture<'static, ()>,
) {
self.0.spawn_ok(future);
}
fn spawn_essential(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
+11 -7
View File
@@ -99,11 +99,7 @@ impl<'a> RuntimeCode<'a> {
///
/// This is only useful for tests that don't want to execute any code.
pub fn empty() -> Self {
Self {
code_fetcher: &NoneFetchRuntimeCode,
hash: Vec::new(),
heap_pages: None,
}
Self { code_fetcher: &NoneFetchRuntimeCode, hash: Vec::new(), heap_pages: None }
}
}
@@ -225,7 +221,11 @@ pub trait SpawnEssentialNamed: Clone + Send + Sync {
/// Spawn the given blocking future.
///
/// The given `name` is used to identify the future in tracing.
fn spawn_essential_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>);
fn spawn_essential_blocking(
&self,
name: &'static str,
future: futures::future::BoxFuture<'static, ()>,
);
/// Spawn the given non-blocking future.
///
/// The given `name` is used to identify the future in tracing.
@@ -233,7 +233,11 @@ pub trait SpawnEssentialNamed: Clone + Send + Sync {
}
impl SpawnEssentialNamed for Box<dyn SpawnEssentialNamed> {
fn spawn_essential_blocking(&self, name: &'static str, future: futures::future::BoxFuture<'static, ()>) {
fn spawn_essential_blocking(
&self,
name: &'static str,
future: futures::future::BoxFuture<'static, ()>,
) {
(**self).spawn_essential_blocking(name, future)
}
+436 -110
View File
@@ -24,221 +24,547 @@ pub trait Value {
}
/// Type representing the value 0 for the `Value` trait.
pub struct _0; impl Value for _0 { const VALUE: u32 = 0; }
pub struct _0;
impl Value for _0 {
const VALUE: u32 = 0;
}
/// Type representing the value 1 for the `Value` trait.
pub struct _1; impl Value for _1 { const VALUE: u32 = 1; }
pub struct _1;
impl Value for _1 {
const VALUE: u32 = 1;
}
/// Type representing the value 2 for the `Value` trait.
pub struct _2; impl Value for _2 { const VALUE: u32 = 2; }
pub struct _2;
impl Value for _2 {
const VALUE: u32 = 2;
}
/// Type representing the value 3 for the `Value` trait.
pub struct _3; impl Value for _3 { const VALUE: u32 = 3; }
pub struct _3;
impl Value for _3 {
const VALUE: u32 = 3;
}
/// Type representing the value 4 for the `Value` trait.
pub struct _4; impl Value for _4 { const VALUE: u32 = 4; }
pub struct _4;
impl Value for _4 {
const VALUE: u32 = 4;
}
/// Type representing the value 5 for the `Value` trait.
pub struct _5; impl Value for _5 { const VALUE: u32 = 5; }
pub struct _5;
impl Value for _5 {
const VALUE: u32 = 5;
}
/// Type representing the value 6 for the `Value` trait.
pub struct _6; impl Value for _6 { const VALUE: u32 = 6; }
pub struct _6;
impl Value for _6 {
const VALUE: u32 = 6;
}
/// Type representing the value 7 for the `Value` trait.
pub struct _7; impl Value for _7 { const VALUE: u32 = 7; }
pub struct _7;
impl Value for _7 {
const VALUE: u32 = 7;
}
/// Type representing the value 8 for the `Value` trait.
pub struct _8; impl Value for _8 { const VALUE: u32 = 8; }
pub struct _8;
impl Value for _8 {
const VALUE: u32 = 8;
}
/// Type representing the value 9 for the `Value` trait.
pub struct _9; impl Value for _9 { const VALUE: u32 = 9; }
pub struct _9;
impl Value for _9 {
const VALUE: u32 = 9;
}
/// Type representing the value 10 for the `Value` trait.
pub struct _10; impl Value for _10 { const VALUE: u32 = 10; }
pub struct _10;
impl Value for _10 {
const VALUE: u32 = 10;
}
/// Type representing the value 11 for the `Value` trait.
pub struct _11; impl Value for _11 { const VALUE: u32 = 11; }
pub struct _11;
impl Value for _11 {
const VALUE: u32 = 11;
}
/// Type representing the value 12 for the `Value` trait.
pub struct _12; impl Value for _12 { const VALUE: u32 = 12; }
pub struct _12;
impl Value for _12 {
const VALUE: u32 = 12;
}
/// Type representing the value 13 for the `Value` trait.
pub struct _13; impl Value for _13 { const VALUE: u32 = 13; }
pub struct _13;
impl Value for _13 {
const VALUE: u32 = 13;
}
/// Type representing the value 14 for the `Value` trait.
pub struct _14; impl Value for _14 { const VALUE: u32 = 14; }
pub struct _14;
impl Value for _14 {
const VALUE: u32 = 14;
}
/// Type representing the value 15 for the `Value` trait.
pub struct _15; impl Value for _15 { const VALUE: u32 = 15; }
pub struct _15;
impl Value for _15 {
const VALUE: u32 = 15;
}
/// Type representing the value 16 for the `Value` trait.
pub struct _16; impl Value for _16 { const VALUE: u32 = 16; }
pub struct _16;
impl Value for _16 {
const VALUE: u32 = 16;
}
/// Type representing the value 17 for the `Value` trait.
pub struct _17; impl Value for _17 { const VALUE: u32 = 17; }
pub struct _17;
impl Value for _17 {
const VALUE: u32 = 17;
}
/// Type representing the value 18 for the `Value` trait.
pub struct _18; impl Value for _18 { const VALUE: u32 = 18; }
pub struct _18;
impl Value for _18 {
const VALUE: u32 = 18;
}
/// Type representing the value 19 for the `Value` trait.
pub struct _19; impl Value for _19 { const VALUE: u32 = 19; }
pub struct _19;
impl Value for _19 {
const VALUE: u32 = 19;
}
/// Type representing the value 20 for the `Value` trait.
pub struct _20; impl Value for _20 { const VALUE: u32 = 20; }
pub struct _20;
impl Value for _20 {
const VALUE: u32 = 20;
}
/// Type representing the value 21 for the `Value` trait.
pub struct _21; impl Value for _21 { const VALUE: u32 = 21; }
pub struct _21;
impl Value for _21 {
const VALUE: u32 = 21;
}
/// Type representing the value 22 for the `Value` trait.
pub struct _22; impl Value for _22 { const VALUE: u32 = 22; }
pub struct _22;
impl Value for _22 {
const VALUE: u32 = 22;
}
/// Type representing the value 23 for the `Value` trait.
pub struct _23; impl Value for _23 { const VALUE: u32 = 23; }
pub struct _23;
impl Value for _23 {
const VALUE: u32 = 23;
}
/// Type representing the value 24 for the `Value` trait.
pub struct _24; impl Value for _24 { const VALUE: u32 = 24; }
pub struct _24;
impl Value for _24 {
const VALUE: u32 = 24;
}
/// Type representing the value 25 for the `Value` trait.
pub struct _25; impl Value for _25 { const VALUE: u32 = 25; }
pub struct _25;
impl Value for _25 {
const VALUE: u32 = 25;
}
/// Type representing the value 26 for the `Value` trait.
pub struct _26; impl Value for _26 { const VALUE: u32 = 26; }
pub struct _26;
impl Value for _26 {
const VALUE: u32 = 26;
}
/// Type representing the value 27 for the `Value` trait.
pub struct _27; impl Value for _27 { const VALUE: u32 = 27; }
pub struct _27;
impl Value for _27 {
const VALUE: u32 = 27;
}
/// Type representing the value 28 for the `Value` trait.
pub struct _28; impl Value for _28 { const VALUE: u32 = 28; }
pub struct _28;
impl Value for _28 {
const VALUE: u32 = 28;
}
/// Type representing the value 29 for the `Value` trait.
pub struct _29; impl Value for _29 { const VALUE: u32 = 29; }
pub struct _29;
impl Value for _29 {
const VALUE: u32 = 29;
}
/// Type representing the value 30 for the `Value` trait.
pub struct _30; impl Value for _30 { const VALUE: u32 = 30; }
pub struct _30;
impl Value for _30 {
const VALUE: u32 = 30;
}
/// Type representing the value 31 for the `Value` trait.
pub struct _31; impl Value for _31 { const VALUE: u32 = 31; }
pub struct _31;
impl Value for _31 {
const VALUE: u32 = 31;
}
/// Type representing the value 32 for the `Value` trait.
pub struct _32; impl Value for _32 { const VALUE: u32 = 32; }
pub struct _32;
impl Value for _32 {
const VALUE: u32 = 32;
}
/// Type representing the value 33 for the `Value` trait.
pub struct _33; impl Value for _33 { const VALUE: u32 = 33; }
pub struct _33;
impl Value for _33 {
const VALUE: u32 = 33;
}
/// Type representing the value 34 for the `Value` trait.
pub struct _34; impl Value for _34 { const VALUE: u32 = 34; }
pub struct _34;
impl Value for _34 {
const VALUE: u32 = 34;
}
/// Type representing the value 35 for the `Value` trait.
pub struct _35; impl Value for _35 { const VALUE: u32 = 35; }
pub struct _35;
impl Value for _35 {
const VALUE: u32 = 35;
}
/// Type representing the value 36 for the `Value` trait.
pub struct _36; impl Value for _36 { const VALUE: u32 = 36; }
pub struct _36;
impl Value for _36 {
const VALUE: u32 = 36;
}
/// Type representing the value 37 for the `Value` trait.
pub struct _37; impl Value for _37 { const VALUE: u32 = 37; }
pub struct _37;
impl Value for _37 {
const VALUE: u32 = 37;
}
/// Type representing the value 38 for the `Value` trait.
pub struct _38; impl Value for _38 { const VALUE: u32 = 38; }
pub struct _38;
impl Value for _38 {
const VALUE: u32 = 38;
}
/// Type representing the value 39 for the `Value` trait.
pub struct _39; impl Value for _39 { const VALUE: u32 = 39; }
pub struct _39;
impl Value for _39 {
const VALUE: u32 = 39;
}
/// Type representing the value 40 for the `Value` trait.
pub struct _40; impl Value for _40 { const VALUE: u32 = 40; }
pub struct _40;
impl Value for _40 {
const VALUE: u32 = 40;
}
/// Type representing the value 41 for the `Value` trait.
pub struct _41; impl Value for _41 { const VALUE: u32 = 41; }
pub struct _41;
impl Value for _41 {
const VALUE: u32 = 41;
}
/// Type representing the value 42 for the `Value` trait.
pub struct _42; impl Value for _42 { const VALUE: u32 = 42; }
pub struct _42;
impl Value for _42 {
const VALUE: u32 = 42;
}
/// Type representing the value 43 for the `Value` trait.
pub struct _43; impl Value for _43 { const VALUE: u32 = 43; }
pub struct _43;
impl Value for _43 {
const VALUE: u32 = 43;
}
/// Type representing the value 44 for the `Value` trait.
pub struct _44; impl Value for _44 { const VALUE: u32 = 44; }
pub struct _44;
impl Value for _44 {
const VALUE: u32 = 44;
}
/// Type representing the value 45 for the `Value` trait.
pub struct _45; impl Value for _45 { const VALUE: u32 = 45; }
pub struct _45;
impl Value for _45 {
const VALUE: u32 = 45;
}
/// Type representing the value 46 for the `Value` trait.
pub struct _46; impl Value for _46 { const VALUE: u32 = 46; }
pub struct _46;
impl Value for _46 {
const VALUE: u32 = 46;
}
/// Type representing the value 47 for the `Value` trait.
pub struct _47; impl Value for _47 { const VALUE: u32 = 47; }
pub struct _47;
impl Value for _47 {
const VALUE: u32 = 47;
}
/// Type representing the value 48 for the `Value` trait.
pub struct _48; impl Value for _48 { const VALUE: u32 = 48; }
pub struct _48;
impl Value for _48 {
const VALUE: u32 = 48;
}
/// Type representing the value 49 for the `Value` trait.
pub struct _49; impl Value for _49 { const VALUE: u32 = 49; }
pub struct _49;
impl Value for _49 {
const VALUE: u32 = 49;
}
/// Type representing the value 50 for the `Value` trait.
pub struct _50; impl Value for _50 { const VALUE: u32 = 50; }
pub struct _50;
impl Value for _50 {
const VALUE: u32 = 50;
}
/// Type representing the value 51 for the `Value` trait.
pub struct _51; impl Value for _51 { const VALUE: u32 = 51; }
pub struct _51;
impl Value for _51 {
const VALUE: u32 = 51;
}
/// Type representing the value 52 for the `Value` trait.
pub struct _52; impl Value for _52 { const VALUE: u32 = 52; }
pub struct _52;
impl Value for _52 {
const VALUE: u32 = 52;
}
/// Type representing the value 53 for the `Value` trait.
pub struct _53; impl Value for _53 { const VALUE: u32 = 53; }
pub struct _53;
impl Value for _53 {
const VALUE: u32 = 53;
}
/// Type representing the value 54 for the `Value` trait.
pub struct _54; impl Value for _54 { const VALUE: u32 = 54; }
pub struct _54;
impl Value for _54 {
const VALUE: u32 = 54;
}
/// Type representing the value 55 for the `Value` trait.
pub struct _55; impl Value for _55 { const VALUE: u32 = 55; }
pub struct _55;
impl Value for _55 {
const VALUE: u32 = 55;
}
/// Type representing the value 56 for the `Value` trait.
pub struct _56; impl Value for _56 { const VALUE: u32 = 56; }
pub struct _56;
impl Value for _56 {
const VALUE: u32 = 56;
}
/// Type representing the value 57 for the `Value` trait.
pub struct _57; impl Value for _57 { const VALUE: u32 = 57; }
pub struct _57;
impl Value for _57 {
const VALUE: u32 = 57;
}
/// Type representing the value 58 for the `Value` trait.
pub struct _58; impl Value for _58 { const VALUE: u32 = 58; }
pub struct _58;
impl Value for _58 {
const VALUE: u32 = 58;
}
/// Type representing the value 59 for the `Value` trait.
pub struct _59; impl Value for _59 { const VALUE: u32 = 59; }
pub struct _59;
impl Value for _59 {
const VALUE: u32 = 59;
}
/// Type representing the value 60 for the `Value` trait.
pub struct _60; impl Value for _60 { const VALUE: u32 = 60; }
pub struct _60;
impl Value for _60 {
const VALUE: u32 = 60;
}
/// Type representing the value 61 for the `Value` trait.
pub struct _61; impl Value for _61 { const VALUE: u32 = 61; }
pub struct _61;
impl Value for _61 {
const VALUE: u32 = 61;
}
/// Type representing the value 62 for the `Value` trait.
pub struct _62; impl Value for _62 { const VALUE: u32 = 62; }
pub struct _62;
impl Value for _62 {
const VALUE: u32 = 62;
}
/// Type representing the value 63 for the `Value` trait.
pub struct _63; impl Value for _63 { const VALUE: u32 = 63; }
pub struct _63;
impl Value for _63 {
const VALUE: u32 = 63;
}
/// Type representing the value 64 for the `Value` trait.
pub struct _64; impl Value for _64 { const VALUE: u32 = 64; }
pub struct _64;
impl Value for _64 {
const VALUE: u32 = 64;
}
/// Type representing the value 65 for the `Value` trait.
pub struct _65; impl Value for _65 { const VALUE: u32 = 65; }
pub struct _65;
impl Value for _65 {
const VALUE: u32 = 65;
}
/// Type representing the value 66 for the `Value` trait.
pub struct _66; impl Value for _66 { const VALUE: u32 = 66; }
pub struct _66;
impl Value for _66 {
const VALUE: u32 = 66;
}
/// Type representing the value 67 for the `Value` trait.
pub struct _67; impl Value for _67 { const VALUE: u32 = 67; }
pub struct _67;
impl Value for _67 {
const VALUE: u32 = 67;
}
/// Type representing the value 68 for the `Value` trait.
pub struct _68; impl Value for _68 { const VALUE: u32 = 68; }
pub struct _68;
impl Value for _68 {
const VALUE: u32 = 68;
}
/// Type representing the value 69 for the `Value` trait.
pub struct _69; impl Value for _69 { const VALUE: u32 = 69; }
pub struct _69;
impl Value for _69 {
const VALUE: u32 = 69;
}
/// Type representing the value 70 for the `Value` trait.
pub struct _70; impl Value for _70 { const VALUE: u32 = 70; }
pub struct _70;
impl Value for _70 {
const VALUE: u32 = 70;
}
/// Type representing the value 71 for the `Value` trait.
pub struct _71; impl Value for _71 { const VALUE: u32 = 71; }
pub struct _71;
impl Value for _71 {
const VALUE: u32 = 71;
}
/// Type representing the value 72 for the `Value` trait.
pub struct _72; impl Value for _72 { const VALUE: u32 = 72; }
pub struct _72;
impl Value for _72 {
const VALUE: u32 = 72;
}
/// Type representing the value 73 for the `Value` trait.
pub struct _73; impl Value for _73 { const VALUE: u32 = 73; }
pub struct _73;
impl Value for _73 {
const VALUE: u32 = 73;
}
/// Type representing the value 74 for the `Value` trait.
pub struct _74; impl Value for _74 { const VALUE: u32 = 74; }
pub struct _74;
impl Value for _74 {
const VALUE: u32 = 74;
}
/// Type representing the value 75 for the `Value` trait.
pub struct _75; impl Value for _75 { const VALUE: u32 = 75; }
pub struct _75;
impl Value for _75 {
const VALUE: u32 = 75;
}
/// Type representing the value 76 for the `Value` trait.
pub struct _76; impl Value for _76 { const VALUE: u32 = 76; }
pub struct _76;
impl Value for _76 {
const VALUE: u32 = 76;
}
/// Type representing the value 77 for the `Value` trait.
pub struct _77; impl Value for _77 { const VALUE: u32 = 77; }
pub struct _77;
impl Value for _77 {
const VALUE: u32 = 77;
}
/// Type representing the value 78 for the `Value` trait.
pub struct _78; impl Value for _78 { const VALUE: u32 = 78; }
pub struct _78;
impl Value for _78 {
const VALUE: u32 = 78;
}
/// Type representing the value 79 for the `Value` trait.
pub struct _79; impl Value for _79 { const VALUE: u32 = 79; }
pub struct _79;
impl Value for _79 {
const VALUE: u32 = 79;
}
/// Type representing the value 80 for the `Value` trait.
pub struct _80; impl Value for _80 { const VALUE: u32 = 80; }
pub struct _80;
impl Value for _80 {
const VALUE: u32 = 80;
}
/// Type representing the value 81 for the `Value` trait.
pub struct _81; impl Value for _81 { const VALUE: u32 = 81; }
pub struct _81;
impl Value for _81 {
const VALUE: u32 = 81;
}
/// Type representing the value 82 for the `Value` trait.
pub struct _82; impl Value for _82 { const VALUE: u32 = 82; }
pub struct _82;
impl Value for _82 {
const VALUE: u32 = 82;
}
/// Type representing the value 83 for the `Value` trait.
pub struct _83; impl Value for _83 { const VALUE: u32 = 83; }
pub struct _83;
impl Value for _83 {
const VALUE: u32 = 83;
}
/// Type representing the value 84 for the `Value` trait.
pub struct _84; impl Value for _84 { const VALUE: u32 = 84; }
pub struct _84;
impl Value for _84 {
const VALUE: u32 = 84;
}
/// Type representing the value 85 for the `Value` trait.
pub struct _85; impl Value for _85 { const VALUE: u32 = 85; }
pub struct _85;
impl Value for _85 {
const VALUE: u32 = 85;
}
/// Type representing the value 86 for the `Value` trait.
pub struct _86; impl Value for _86 { const VALUE: u32 = 86; }
pub struct _86;
impl Value for _86 {
const VALUE: u32 = 86;
}
/// Type representing the value 87 for the `Value` trait.
pub struct _87; impl Value for _87 { const VALUE: u32 = 87; }
pub struct _87;
impl Value for _87 {
const VALUE: u32 = 87;
}
/// Type representing the value 88 for the `Value` trait.
pub struct _88; impl Value for _88 { const VALUE: u32 = 88; }
pub struct _88;
impl Value for _88 {
const VALUE: u32 = 88;
}
/// Type representing the value 89 for the `Value` trait.
pub struct _89; impl Value for _89 { const VALUE: u32 = 89; }
pub struct _89;
impl Value for _89 {
const VALUE: u32 = 89;
}
/// Type representing the value 90 for the `Value` trait.
pub struct _90; impl Value for _90 { const VALUE: u32 = 90; }
pub struct _90;
impl Value for _90 {
const VALUE: u32 = 90;
}
/// Type representing the value 91 for the `Value` trait.
pub struct _91; impl Value for _91 { const VALUE: u32 = 91; }
pub struct _91;
impl Value for _91 {
const VALUE: u32 = 91;
}
/// Type representing the value 92 for the `Value` trait.
pub struct _92; impl Value for _92 { const VALUE: u32 = 92; }
pub struct _92;
impl Value for _92 {
const VALUE: u32 = 92;
}
/// Type representing the value 93 for the `Value` trait.
pub struct _93; impl Value for _93 { const VALUE: u32 = 93; }
pub struct _93;
impl Value for _93 {
const VALUE: u32 = 93;
}
/// Type representing the value 94 for the `Value` trait.
pub struct _94; impl Value for _94 { const VALUE: u32 = 94; }
pub struct _94;
impl Value for _94 {
const VALUE: u32 = 94;
}
/// Type representing the value 95 for the `Value` trait.
pub struct _95; impl Value for _95 { const VALUE: u32 = 95; }
pub struct _95;
impl Value for _95 {
const VALUE: u32 = 95;
}
/// Type representing the value 96 for the `Value` trait.
pub struct _96; impl Value for _96 { const VALUE: u32 = 96; }
pub struct _96;
impl Value for _96 {
const VALUE: u32 = 96;
}
/// Type representing the value 97 for the `Value` trait.
pub struct _97; impl Value for _97 { const VALUE: u32 = 97; }
pub struct _97;
impl Value for _97 {
const VALUE: u32 = 97;
}
/// Type representing the value 98 for the `Value` trait.
pub struct _98; impl Value for _98 { const VALUE: u32 = 98; }
pub struct _98;
impl Value for _98 {
const VALUE: u32 = 98;
}
/// Type representing the value 99 for the `Value` trait.
pub struct _99; impl Value for _99 { const VALUE: u32 = 99; }
pub struct _99;
impl Value for _99 {
const VALUE: u32 = 99;
}
/// Type representing the value 100 for the `Value` trait.
pub struct _100; impl Value for _100 { const VALUE: u32 = 100; }
pub struct _100;
impl Value for _100 {
const VALUE: u32 = 100;
}
/// Type representing the value 112 for the `Value` trait.
pub struct _112; impl Value for _112 { const VALUE: u32 = 112; }
pub struct _112;
impl Value for _112 {
const VALUE: u32 = 112;
}
/// Type representing the value 128 for the `Value` trait.
pub struct _128; impl Value for _128 { const VALUE: u32 = 128; }
pub struct _128;
impl Value for _128 {
const VALUE: u32 = 128;
}
/// Type representing the value 160 for the `Value` trait.
pub struct _160; impl Value for _160 { const VALUE: u32 = 160; }
pub struct _160;
impl Value for _160 {
const VALUE: u32 = 160;
}
/// Type representing the value 192 for the `Value` trait.
pub struct _192; impl Value for _192 { const VALUE: u32 = 192; }
pub struct _192;
impl Value for _192 {
const VALUE: u32 = 192;
}
/// Type representing the value 224 for the `Value` trait.
pub struct _224; impl Value for _224 { const VALUE: u32 = 224; }
pub struct _224;
impl Value for _224 {
const VALUE: u32 = 224;
}
/// Type representing the value 256 for the `Value` trait.
pub struct _256; impl Value for _256 { const VALUE: u32 = 256; }
pub struct _256;
impl Value for _256 {
const VALUE: u32 = 256;
}
/// Type representing the value 384 for the `Value` trait.
pub struct _384; impl Value for _384 { const VALUE: u32 = 384; }
pub struct _384;
impl Value for _384 {
const VALUE: u32 = 384;
}
/// Type representing the value 512 for the `Value` trait.
pub struct _512; impl Value for _512 { const VALUE: u32 = 512; }
pub struct _512;
impl Value for _512 {
const VALUE: u32 = 512;
}
+20 -27
View File
@@ -22,7 +22,7 @@ pub use primitive_types::{U256, U512};
#[cfg(test)]
mod tests {
use super::*;
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use sp_serializer as ser;
macro_rules! test {
@@ -55,34 +55,27 @@ mod tests {
assert!(ser::from_str::<$name>("\"10\"").unwrap_err().is_data());
assert!(ser::from_str::<$name>("\"0\"").unwrap_err().is_data());
}
}
};
}
test!(U256, test_u256);
#[test]
fn test_u256_codec() {
let res1 = vec![120, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0];
let res2 = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
let res1 = vec![
120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
let res2 = vec![
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
];
assert_eq!(
U256::from(120).encode(),
res1);
assert_eq!(
U256::max_value().encode(),
res2);
assert_eq!(
U256::decode(&mut &res1[..]),
Ok(U256::from(120)));
assert_eq!(
U256::decode(&mut &res2[..]),
Ok(U256::max_value()));
assert_eq!(U256::from(120).encode(), res1);
assert_eq!(U256::max_value().encode(), res2);
assert_eq!(U256::decode(&mut &res1[..]), Ok(U256::from(120)));
assert_eq!(U256::decode(&mut &res2[..]), Ok(U256::max_value()));
}
#[test]
@@ -91,10 +84,10 @@ mod tests {
ser::to_string_pretty(&!U256::zero()),
"\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
);
assert!(
ser::from_str::<U256>("\"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"")
.unwrap_err()
.is_data()
);
assert!(ser::from_str::<U256>(
"\"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
)
.unwrap_err()
.is_data());
}
}
+31 -28
View File
@@ -16,30 +16,31 @@
// limitations under the License.
/// A wrapper around `kvdb::Database` that implements `sp_database::Database` trait
use ::kvdb::{DBTransaction, KeyValueDB};
use crate::{Database, Change, ColumnId, Transaction, error};
use crate::{error, Change, ColumnId, Database, Transaction};
struct DbAdapter<D: KeyValueDB + 'static>(D);
fn handle_err<T>(result: std::io::Result<T>) -> T {
match result {
Ok(r) => r,
Err(e) => {
Err(e) => {
panic!("Critical database error: {:?}", e);
}
},
}
}
/// Wrap RocksDb database into a trait object that implements `sp_database::Database`
pub fn as_database<D, H>(db: D) -> std::sync::Arc<dyn Database<H>>
where D: KeyValueDB + 'static, H: Clone + AsRef<[u8]>
where
D: KeyValueDB + 'static,
H: Clone + AsRef<[u8]>,
{
std::sync::Arc::new(DbAdapter(db))
}
impl <D: KeyValueDB> DbAdapter<D> {
impl<D: KeyValueDB> DbAdapter<D> {
// Returns counter key and counter value if it exists.
fn read_counter(&self, col: ColumnId, key: &[u8]) -> error::Result<(Vec<u8>, Option<u32>)> {
// Add a key suffix for the counter
@@ -49,16 +50,16 @@ impl <D: KeyValueDB> DbAdapter<D> {
Some(data) => {
let mut counter_data = [0; 4];
if data.len() != 4 {
return Err(error::DatabaseError(Box::new(
std::io::Error::new(std::io::ErrorKind::Other,
format!("Unexpected counter len {}", data.len())))
))
return Err(error::DatabaseError(Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Unexpected counter len {}", data.len()),
))))
}
counter_data.copy_from_slice(&data);
let counter = u32::from_le_bytes(counter_data);
(counter_key, Some(counter))
},
None => (counter_key, None)
None => (counter_key, None),
})
}
}
@@ -70,27 +71,29 @@ impl<D: KeyValueDB, H: Clone + AsRef<[u8]>> Database<H> for DbAdapter<D> {
match change {
Change::Set(col, key, value) => tx.put_vec(col, &key, value),
Change::Remove(col, key) => tx.delete(col, &key),
Change::Store(col, key, value) => {
match self.read_counter(col, key.as_ref())? {
(counter_key, Some(mut counter)) => {
counter += 1;
tx.put(col, &counter_key, &counter.to_le_bytes());
},
(counter_key, None) => {
let d = 1u32.to_le_bytes();
tx.put(col, &counter_key, &d);
tx.put_vec(col, key.as_ref(), value);
},
}
}
Change::Store(col, key, value) => match self.read_counter(col, key.as_ref())? {
(counter_key, Some(mut counter)) => {
counter += 1;
tx.put(col, &counter_key, &counter.to_le_bytes());
},
(counter_key, None) => {
let d = 1u32.to_le_bytes();
tx.put(col, &counter_key, &d);
tx.put_vec(col, key.as_ref(), value);
},
},
Change::Reference(col, key) => {
if let (counter_key, Some(mut counter)) = self.read_counter(col, key.as_ref())? {
if let (counter_key, Some(mut counter)) =
self.read_counter(col, key.as_ref())?
{
counter += 1;
tx.put(col, &counter_key, &counter.to_le_bytes());
}
}
},
Change::Release(col, key) => {
if let (counter_key, Some(mut counter)) = self.read_counter(col, key.as_ref())? {
if let (counter_key, Some(mut counter)) =
self.read_counter(col, key.as_ref())?
{
counter -= 1;
if counter == 0 {
tx.delete(col, &counter_key);
@@ -99,7 +102,7 @@ impl<D: KeyValueDB, H: Clone + AsRef<[u8]>> Database<H> for DbAdapter<D> {
tx.put(col, &counter_key, &counter.to_le_bytes());
}
}
}
},
}
}
self.0.write(tx).map_err(|e| error::DatabaseError(Box::new(e)))
+7 -4
View File
@@ -18,11 +18,11 @@
//! The main database trait, allowing Substrate to store data persistently.
pub mod error;
mod mem;
mod kvdb;
mod mem;
pub use mem::MemDb;
pub use crate::kvdb::as_database;
pub use mem::MemDb;
/// An identifier for a column.
pub type ColumnId = u32;
@@ -118,10 +118,13 @@ impl<H> std::fmt::Debug for dyn Database<H> {
pub fn with_get<R, H: Clone + AsRef<[u8]>>(
db: &dyn Database<H>,
col: ColumnId,
key: &[u8], mut f: impl FnMut(&[u8]) -> R
key: &[u8],
mut f: impl FnMut(&[u8]) -> R,
) -> Option<R> {
let mut result: Option<R> = None;
let mut adapter = |k: &_| { result = Some(f(k)); };
let mut adapter = |k: &_| {
result = Some(f(k));
};
db.with_get(col, key, &mut adapter);
result
}
+21 -11
View File
@@ -17,41 +17,52 @@
//! In-memory implementation of `Database`
use std::collections::{HashMap, hash_map::Entry};
use crate::{Database, Change, ColumnId, Transaction, error};
use crate::{error, Change, ColumnId, Database, Transaction};
use parking_lot::RwLock;
use std::collections::{hash_map::Entry, HashMap};
#[derive(Default)]
/// This implements `Database` as an in-memory hash map. `commit` is not atomic.
pub struct MemDb(RwLock<HashMap<ColumnId, HashMap<Vec<u8>, (u32, Vec<u8>)>>>);
impl<H> Database<H> for MemDb
where H: Clone + AsRef<[u8]>
where
H: Clone + AsRef<[u8]>,
{
fn commit(&self, transaction: Transaction<H>) -> error::Result<()> {
let mut s = self.0.write();
for change in transaction.0.into_iter() {
match change {
Change::Set(col, key, value) => { s.entry(col).or_default().insert(key, (1, value)); },
Change::Remove(col, key) => { s.entry(col).or_default().remove(&key); },
Change::Set(col, key, value) => {
s.entry(col).or_default().insert(key, (1, value));
},
Change::Remove(col, key) => {
s.entry(col).or_default().remove(&key);
},
Change::Store(col, hash, value) => {
s.entry(col).or_default().entry(hash.as_ref().to_vec())
s.entry(col)
.or_default()
.entry(hash.as_ref().to_vec())
.and_modify(|(c, _)| *c += 1)
.or_insert_with(|| (1, value));
},
Change::Reference(col, hash) => {
if let Entry::Occupied(mut entry) = s.entry(col).or_default().entry(hash.as_ref().to_vec()) {
if let Entry::Occupied(mut entry) =
s.entry(col).or_default().entry(hash.as_ref().to_vec())
{
entry.get_mut().0 += 1;
}
}
},
Change::Release(col, hash) => {
if let Entry::Occupied(mut entry) = s.entry(col).or_default().entry(hash.as_ref().to_vec()) {
if let Entry::Occupied(mut entry) =
s.entry(col).or_default().entry(hash.as_ref().to_vec())
{
entry.get_mut().0 -= 1;
if entry.get().0 == 0 {
entry.remove();
}
}
}
},
}
}
@@ -76,4 +87,3 @@ impl MemDb {
s.get(&col).map(|c| c.len()).unwrap_or(0)
}
}
+48 -78
View File
@@ -15,9 +15,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use quote::quote;
use proc_macro2::TokenStream;
use syn::{Data, DeriveInput, parse_quote};
use quote::quote;
use syn::{parse_quote, Data, DeriveInput};
pub fn debug_derive(ast: DeriveInput) -> proc_macro::TokenStream {
let name_str = ast.ident.to_string();
@@ -28,11 +28,11 @@ pub fn debug_derive(ast: DeriveInput) -> proc_macro::TokenStream {
let wh = generics.make_where_clause();
for t in ast.generics.type_params() {
let name = &t.ident;
wh.predicates.push(parse_quote!{ #name : core::fmt::Debug });
wh.predicates.push(parse_quote! { #name : core::fmt::Debug });
}
generics.split_for_impl()
};
let gen = quote!{
let gen = quote! {
impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause {
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
#implementation
@@ -62,32 +62,26 @@ mod implementation {
mod implementation {
use super::*;
use proc_macro2::Span;
use syn::{Ident, Index, token::SelfValue};
use syn::{token::SelfValue, Ident, Index};
/// Derive the inner implementation of `Debug::fmt` function.
pub fn derive(name_str: &str, data: &Data) -> TokenStream {
match *data {
Data::Struct(ref s) => derive_struct(&name_str, &s.fields),
Data::Union(ref u) => derive_fields(&name_str, Fields::new(u.fields.named.iter(), None)),
Data::Union(ref u) =>
derive_fields(&name_str, Fields::new(u.fields.named.iter(), None)),
Data::Enum(ref e) => derive_enum(&name_str, &e),
}
}
enum Fields {
Indexed {
indices: Vec<Index>,
},
Unnamed {
vars: Vec<Ident>,
},
Named {
names: Vec<Ident>,
this: Option<SelfValue>,
},
Indexed { indices: Vec<Index> },
Unnamed { vars: Vec<Ident> },
Named { names: Vec<Ident>, this: Option<SelfValue> },
}
impl Fields {
fn new<'a>(fields: impl Iterator<Item=&'a syn::Field>, this: Option<SelfValue>) -> Self {
fn new<'a>(fields: impl Iterator<Item = &'a syn::Field>, this: Option<SelfValue>) -> Self {
let mut indices = vec![];
let mut names = vec![];
@@ -100,27 +94,17 @@ mod implementation {
}
if names.is_empty() {
Self::Indexed {
indices,
}
Self::Indexed { indices }
} else {
Self::Named {
names,
this,
}
Self::Named { names, this }
}
}
}
fn derive_fields<'a>(
name_str: &str,
fields: Fields,
) -> TokenStream {
fn derive_fields<'a>(name_str: &str, fields: Fields) -> TokenStream {
match fields {
Fields::Named { names, this } => {
let names_str: Vec<_> = names.iter()
.map(|x| x.to_string())
.collect();
let names_str: Vec<_> = names.iter().map(|x| x.to_string()).collect();
let fields = match this {
None => quote! { #( .field(#names_str, #names) )* },
@@ -132,16 +116,15 @@ mod implementation {
#fields
.finish()
}
},
Fields::Indexed { indices } => {
Fields::Indexed { indices } => {
quote! {
fmt.debug_tuple(#name_str)
#( .field(&self.#indices) )*
.finish()
}
},
Fields::Unnamed { vars } => {
Fields::Unnamed { vars } => {
quote! {
fmt.debug_tuple(#name_str)
#( .field(#vars) )*
@@ -151,38 +134,33 @@ mod implementation {
}
}
fn derive_enum(
name: &str,
e: &syn::DataEnum,
) -> TokenStream {
let v = e.variants
.iter()
.map(|v| {
let name = format!("{}::{}", name, v.ident);
let ident = &v.ident;
match v.fields {
syn::Fields::Named(ref f) => {
let names: Vec<_> = f.named.iter().flat_map(|f| f.ident.clone()).collect();
let fields_impl = derive_fields(&name, Fields::Named {
names: names.clone(),
this: None,
});
(ident, (quote!{ { #( ref #names ),* } }, fields_impl))
},
syn::Fields::Unnamed(ref f) => {
let names = f.unnamed.iter()
.enumerate()
.map(|(id, _)| Ident::new(&format!("a{}", id), Span::call_site()))
.collect::<Vec<_>>();
let fields_impl = derive_fields(&name, Fields::Unnamed { vars: names.clone() });
(ident, (quote! { ( #( ref #names ),* ) }, fields_impl))
},
syn::Fields::Unit => {
let fields_impl = derive_fields(&name, Fields::Indexed { indices: vec![] });
(ident, (quote! { }, fields_impl))
},
}
});
fn derive_enum(name: &str, e: &syn::DataEnum) -> TokenStream {
let v = e.variants.iter().map(|v| {
let name = format!("{}::{}", name, v.ident);
let ident = &v.ident;
match v.fields {
syn::Fields::Named(ref f) => {
let names: Vec<_> = f.named.iter().flat_map(|f| f.ident.clone()).collect();
let fields_impl =
derive_fields(&name, Fields::Named { names: names.clone(), this: None });
(ident, (quote! { { #( ref #names ),* } }, fields_impl))
},
syn::Fields::Unnamed(ref f) => {
let names = f
.unnamed
.iter()
.enumerate()
.map(|(id, _)| Ident::new(&format!("a{}", id), Span::call_site()))
.collect::<Vec<_>>();
let fields_impl = derive_fields(&name, Fields::Unnamed { vars: names.clone() });
(ident, (quote! { ( #( ref #names ),* ) }, fields_impl))
},
syn::Fields::Unit => {
let fields_impl = derive_fields(&name, Fields::Indexed { indices: vec![] });
(ident, (quote! {}, fields_impl))
},
}
});
type Vecs<A, B> = (Vec<A>, Vec<B>);
let (variants, others): Vecs<_, _> = v.unzip();
@@ -196,23 +174,15 @@ mod implementation {
}
}
fn derive_struct(
name_str: &str,
fields: &syn::Fields,
) -> TokenStream {
fn derive_struct(name_str: &str, fields: &syn::Fields) -> TokenStream {
match *fields {
syn::Fields::Named(ref f) => derive_fields(
name_str,
Fields::new(f.named.iter(), Some(syn::Token!(self)(Span::call_site()))),
),
syn::Fields::Unnamed(ref f) => derive_fields(
name_str,
Fields::new(f.unnamed.iter(), None),
),
syn::Fields::Unit => derive_fields(
name_str,
Fields::Indexed { indices: vec![] },
),
syn::Fields::Unnamed(ref f) =>
derive_fields(name_str, Fields::new(f.unnamed.iter(), None)),
syn::Fields::Unit => derive_fields(name_str, Fields::Indexed { indices: vec![] }),
}
}
}
+1 -2
View File
@@ -38,6 +38,5 @@ use proc_macro::TokenStream;
#[proc_macro_derive(RuntimeDebug)]
pub fn debug_derive(input: TokenStream) -> TokenStream {
impls::debug_derive(syn::parse_macro_input!(input))
impls::debug_derive(syn::parse_macro_input!(input))
}
@@ -30,33 +30,17 @@ struct Named {
enum EnumLongName<A> {
A,
B(A, String),
VariantLongName {
a: A,
b: String,
},
VariantLongName { a: A, b: String },
}
#[test]
fn should_display_proper_debug() {
use self::EnumLongName as Enum;
assert_eq!(
format!("{:?}", Unnamed(1, "abc".into())),
"Unnamed(1, \"abc\")"
);
assert_eq!(
format!("{:?}", Named { a: 1, b: "abc".into() }),
"Named { a: 1, b: \"abc\" }"
);
assert_eq!(
format!("{:?}", Enum::<u64>::A),
"EnumLongName::A"
);
assert_eq!(
format!("{:?}", Enum::B(1, "abc".into())),
"EnumLongName::B(1, \"abc\")"
);
assert_eq!(format!("{:?}", Unnamed(1, "abc".into())), "Unnamed(1, \"abc\")");
assert_eq!(format!("{:?}", Named { a: 1, b: "abc".into() }), "Named { a: 1, b: \"abc\" }");
assert_eq!(format!("{:?}", Enum::<u64>::A), "EnumLongName::A");
assert_eq!(format!("{:?}", Enum::B(1, "abc".into())), "EnumLongName::B(1, \"abc\")");
assert_eq!(
format!("{:?}", Enum::VariantLongName { a: 1, b: "abc".into() }),
"EnumLongName::VariantLongName { a: 1, b: \"abc\" }"
@@ -22,10 +22,13 @@
//!
//! It is required that each extension implements the [`Extension`] trait.
use sp_std::{
collections::btree_map::{BTreeMap, Entry}, any::{Any, TypeId}, ops::DerefMut, boxed::Box,
};
use crate::Error;
use sp_std::{
any::{Any, TypeId},
boxed::Box,
collections::btree_map::{BTreeMap, Entry},
ops::DerefMut,
};
/// Marker trait for types that should be registered as [`Externalities`](crate::Externalities) extension.
///
@@ -101,7 +104,11 @@ pub trait ExtensionStore {
/// Register extension `extension` with specified `type_id`.
///
/// It should return error if extension is already registered.
fn register_extension_with_type_id(&mut self, type_id: TypeId, extension: Box<dyn Extension>) -> Result<(), Error>;
fn register_extension_with_type_id(
&mut self,
type_id: TypeId,
extension: Box<dyn Extension>,
) -> Result<(), Error>;
/// Deregister extension with speicifed 'type_id' and drop it.
///
@@ -129,10 +136,7 @@ impl Extensions {
}
/// Register the given extension.
pub fn register<E: Extension>(
&mut self,
ext: E,
) {
pub fn register<E: Extension>(&mut self, ext: E) {
let type_id = ext.type_id();
self.extensions.insert(type_id, Box::new(ext));
}
@@ -154,7 +158,10 @@ impl Extensions {
/// Return a mutable reference to the requested extension.
pub fn get_mut(&mut self, ext_type_id: TypeId) -> Option<&mut dyn Any> {
self.extensions.get_mut(&ext_type_id).map(DerefMut::deref_mut).map(Extension::as_mut_any)
self.extensions
.get_mut(&ext_type_id)
.map(DerefMut::deref_mut)
.map(Extension::as_mut_any)
}
/// Deregister extension for the given `type_id`.
@@ -165,7 +172,9 @@ impl Extensions {
}
/// Returns a mutable iterator over all extensions.
pub fn iter_mut<'a>(&'a mut self) -> impl Iterator<Item = (&'a TypeId, &'a mut Box<dyn Extension>)> {
pub fn iter_mut<'a>(
&'a mut self,
) -> impl Iterator<Item = (&'a TypeId, &'a mut Box<dyn Extension>)> {
self.extensions.iter_mut()
}
}
+15 -48
View File
@@ -25,12 +25,16 @@
//!
//! This crate exposes the main [`Externalities`] trait.
use sp_std::{any::{Any, TypeId}, vec::Vec, boxed::Box};
use sp_std::{
any::{Any, TypeId},
boxed::Box,
vec::Vec,
};
use sp_storage::{ChildInfo, TrackedStorageKey};
pub use extensions::{Extension, ExtensionStore, Extensions};
pub use scope_limited::{set_and_run_with_externalities, with_externalities};
pub use extensions::{Extension, Extensions, ExtensionStore};
mod extensions;
mod scope_limited;
@@ -68,20 +72,12 @@ pub trait Externalities: ExtensionStore {
/// This may be optimized for large values.
///
/// Returns an `Option` that holds the SCALE encoded hash.
fn child_storage_hash(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>>;
fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
/// Read child runtime storage.
///
/// Returns an `Option` that holds the SCALE encoded hash.
fn child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>>;
fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
/// Set storage entry `key` of current contract being called (effective immediately).
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
@@ -89,12 +85,7 @@ pub trait Externalities: ExtensionStore {
}
/// Set child storage entry `key` of current contract being called (effective immediately).
fn set_child_storage(
&mut self,
child_info: &ChildInfo,
key: Vec<u8>,
value: Vec<u8>,
) {
fn set_child_storage(&mut self, child_info: &ChildInfo, key: Vec<u8>, value: Vec<u8>) {
self.place_child_storage(child_info, key, Some(value))
}
@@ -104,11 +95,7 @@ pub trait Externalities: ExtensionStore {
}
/// Clear a child storage entry (`key`) of current contract being called (effective immediately).
fn clear_child_storage(
&mut self,
child_info: &ChildInfo,
key: &[u8],
) {
fn clear_child_storage(&mut self, child_info: &ChildInfo, key: &[u8]) {
self.place_child_storage(child_info, key.to_vec(), None)
}
@@ -118,11 +105,7 @@ pub trait Externalities: ExtensionStore {
}
/// Whether a child storage entry exists.
fn exists_child_storage(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> bool {
fn exists_child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> bool {
self.child_storage(child_info, key).is_some()
}
@@ -130,11 +113,7 @@ pub trait Externalities: ExtensionStore {
fn next_storage_key(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Returns the key immediately following the given key, if it exists, in child storage.
fn next_child_storage_key(
&self,
child_info: &ChildInfo,
key: &[u8],
) -> Option<Vec<u8>>;
fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option<Vec<u8>>;
/// Clear an entire child storage.
///
@@ -169,12 +148,7 @@ pub trait Externalities: ExtensionStore {
fn place_storage(&mut self, key: Vec<u8>, value: Option<Vec<u8>>);
/// Set or clear a child storage entry.
fn place_child_storage(
&mut self,
child_info: &ChildInfo,
key: Vec<u8>,
value: Option<Vec<u8>>,
);
fn place_child_storage(&mut self, child_info: &ChildInfo, key: Vec<u8>, value: Option<Vec<u8>>);
/// Get the trie root of the current storage map.
///
@@ -189,19 +163,12 @@ pub trait Externalities: ExtensionStore {
///
/// If the storage root equals the default hash as defined by the trie, the key in the top-level
/// storage map will be removed.
fn child_storage_root(
&mut self,
child_info: &ChildInfo,
) -> Vec<u8>;
fn child_storage_root(&mut self, child_info: &ChildInfo) -> Vec<u8>;
/// Append storage item.
///
/// This assumes specific format of the storage item. Also there is no way to undo this operation.
fn storage_append(
&mut self,
key: Vec<u8>,
value: Vec<u8>,
);
fn storage_append(&mut self, key: Vec<u8>, value: Vec<u8>);
/// Get the changes trie root of the current storage overlay at a block with given `parent`.
///
@@ -25,7 +25,8 @@ environmental::environmental!(ext: trait Externalities);
/// while executing the given closure [`with_externalities`] grants access to them. The externalities
/// are only set for the same thread this function was called from.
pub fn set_and_run_with_externalities<F, R>(ext: &mut dyn Externalities, f: F) -> R
where F: FnOnce() -> R
where
F: FnOnce() -> R,
{
ext::using(ext, f)
}
@@ -25,12 +25,11 @@ extern crate alloc;
#[cfg(feature = "std")]
use serde::Serialize;
use codec::{Encode, Decode, Input, Codec};
use sp_runtime::{ConsensusEngineId, RuntimeDebug, traits::NumberFor};
use sp_std::borrow::Cow;
use sp_std::vec::Vec;
use codec::{Codec, Decode, Encode, Input};
#[cfg(feature = "std")]
use sp_keystore::{SyncCryptoStorePtr, SyncCryptoStore};
use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::{traits::NumberFor, ConsensusEngineId, RuntimeDebug};
use sp_std::{borrow::Cow, vec::Vec};
#[cfg(feature = "std")]
use log::debug;
@@ -39,7 +38,7 @@ use log::debug;
pub const KEY_TYPE: sp_core::crypto::KeyTypeId = sp_application_crypto::key_types::GRANDPA;
mod app {
use sp_application_crypto::{app_crypto, key_types::GRANDPA, ed25519};
use sp_application_crypto::{app_crypto, ed25519, key_types::GRANDPA};
app_crypto!(ed25519, GRANDPA);
}
@@ -181,10 +180,7 @@ impl<H, N> EquivocationProof<H, N> {
/// Create a new `EquivocationProof` for the given set id and using the
/// given equivocation as proof.
pub fn new(set_id: SetId, equivocation: Equivocation<H, N>) -> Self {
EquivocationProof {
set_id,
equivocation,
}
EquivocationProof { set_id, equivocation }
}
/// Returns the set id at which the equivocation occurred.
@@ -277,7 +273,7 @@ where
if $equivocation.first.0.target_hash == $equivocation.second.0.target_hash &&
$equivocation.first.0.target_number == $equivocation.second.0.target_number
{
return false;
return false
}
// check signatures on both votes are valid
@@ -297,17 +293,17 @@ where
report.set_id,
);
return valid_first && valid_second;
return valid_first && valid_second
};
}
match report.equivocation {
Equivocation::Prevote(equivocation) => {
check!(equivocation, grandpa::Message::Prevote);
}
},
Equivocation::Precommit(equivocation) => {
check!(equivocation, grandpa::Message::Precommit);
}
},
}
}
@@ -390,8 +386,8 @@ where
H: Encode,
N: Encode,
{
use sp_core::crypto::Public;
use sp_application_crypto::AppKey;
use sp_core::crypto::Public;
use sp_std::convert::TryInto;
let encoded = localized_payload(round, set_id, &message);
@@ -400,13 +396,13 @@ where
AuthorityId::ID,
&public.to_public_crypto_pair(),
&encoded[..],
).ok().flatten()?.try_into().ok()?;
)
.ok()
.flatten()?
.try_into()
.ok()?;
Some(grandpa::SignedMessage {
message,
signature,
id: public,
})
Some(grandpa::SignedMessage { message, signature, id: public })
}
/// WASM function call to check for pending changes.
@@ -457,7 +453,7 @@ impl<'a> Decode for VersionedAuthorityList<'a> {
fn decode<I: Input>(value: &mut I) -> Result<Self, codec::Error> {
let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?;
if version != AUTHORITIES_VERSION {
return Err("unknown Grandpa authorities version".into());
return Err("unknown Grandpa authorities version".into())
}
Ok(authorities.into())
}
@@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{InherentData, Error, InherentIdentifier};
use crate::{Error, InherentData, InherentIdentifier};
use sp_runtime::traits::Block as BlockT;
/// Something that can create inherent data providers.
@@ -44,7 +44,9 @@ impl<F, Block, IDP, ExtraArgs, Fut> CreateInherentDataProviders<Block, ExtraArgs
where
Block: BlockT,
F: Fn(Block::Hash, ExtraArgs) -> Fut + Sync + Send,
Fut: std::future::Future<Output = Result<IDP, Box<dyn std::error::Error + Send + Sync>>> + Send + 'static,
Fut: std::future::Future<Output = Result<IDP, Box<dyn std::error::Error + Send + Sync>>>
+ Send
+ 'static,
IDP: InherentDataProvider + 'static,
ExtraArgs: Send + 'static,
{
+18 -29
View File
@@ -140,7 +140,7 @@
//! let block_production = if is_validator {
//! // For block production we want to provide our inherent data provider
//! cool_consensus_block_production(|_parent, ()| async {
//! Ok(InherentDataProvider)
//! Ok(InherentDataProvider)
//! }).boxed()
//! } else {
//! futures::future::pending().boxed()
@@ -162,9 +162,12 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
use codec::{Encode, Decode};
use codec::{Decode, Encode};
use sp_std::{collections::btree_map::{BTreeMap, IntoIter, Entry}, vec::Vec};
use sp_std::{
collections::btree_map::{BTreeMap, Entry, IntoIter},
vec::Vec,
};
#[cfg(feature = "std")]
mod client_side;
@@ -204,7 +207,7 @@ pub type InherentIdentifier = [u8; 8];
#[derive(Clone, Default, Encode, Decode)]
pub struct InherentData {
/// All inherent data encoded with parity-scale-codec and an identifier.
data: BTreeMap<InherentIdentifier, Vec<u8>>
data: BTreeMap<InherentIdentifier, Vec<u8>>,
}
impl InherentData {
@@ -231,20 +234,14 @@ impl InherentData {
entry.insert(inherent.encode());
Ok(())
},
Entry::Occupied(_) => {
Err(Error::InherentDataExists(identifier))
}
Entry::Occupied(_) => Err(Error::InherentDataExists(identifier)),
}
}
/// Replace the data for an inherent.
///
/// If it does not exist, the data is just inserted.
pub fn replace_data<I: codec::Encode>(
&mut self,
identifier: InherentIdentifier,
inherent: &I,
) {
pub fn replace_data<I: codec::Encode>(&mut self, identifier: InherentIdentifier, inherent: &I) {
self.data.insert(identifier, inherent.encode());
}
@@ -260,11 +257,10 @@ impl InherentData {
identifier: &InherentIdentifier,
) -> Result<Option<I>, Error> {
match self.data.get(identifier) {
Some(inherent) =>
I::decode(&mut &inherent[..])
.map_err(|e| Error::DecodingFailed(e, *identifier))
.map(Some),
None => Ok(None)
Some(inherent) => I::decode(&mut &inherent[..])
.map_err(|e| Error::DecodingFailed(e, *identifier))
.map(Some),
None => Ok(None),
}
}
@@ -292,11 +288,7 @@ pub struct CheckInherentsResult {
impl Default for CheckInherentsResult {
fn default() -> Self {
Self {
okay: true,
errors: InherentData::new(),
fatal_error: false,
}
Self { okay: true, errors: InherentData::new(), fatal_error: false }
}
}
@@ -370,8 +362,8 @@ impl CheckInherentsResult {
impl PartialEq for CheckInherentsResult {
fn eq(&self, other: &Self) -> bool {
self.fatal_error == other.fatal_error &&
self.okay == other.okay &&
self.errors.data == other.errors.data
self.okay == other.okay &&
self.errors.data == other.errors.data
}
}
@@ -407,7 +399,7 @@ impl<E: codec::Encode> IsFatalError for MakeFatalError<E> {
#[cfg(test)]
mod tests {
use super::*;
use codec::{Encode, Decode};
use codec::{Decode, Encode};
const TEST_INHERENT_0: InherentIdentifier = *b"testinh0";
const TEST_INHERENT_1: InherentIdentifier = *b"testinh1";
@@ -470,10 +462,7 @@ mod tests {
let inherent_data = provider.create_inherent_data().unwrap();
assert_eq!(
inherent_data.get_data::<u32>(&TEST_INHERENT_0).unwrap().unwrap(),
42u32,
);
assert_eq!(inherent_data.get_data::<u32>(&TEST_INHERENT_0).unwrap().unwrap(), 42u32,);
}
#[test]
+22 -12
View File
@@ -17,9 +17,12 @@
//! Batch/parallel verification.
use sp_core::{ed25519, sr25519, ecdsa, crypto::Pair, traits::SpawnNamed};
use std::sync::{Arc, atomic::{AtomicBool, Ordering as AtomicOrdering}};
use futures::{future::FutureExt, channel::oneshot};
use futures::{channel::oneshot, future::FutureExt};
use sp_core::{crypto::Pair, ecdsa, ed25519, sr25519, traits::SpawnNamed};
use std::sync::{
atomic::{AtomicBool, Ordering as AtomicOrdering},
Arc,
};
#[derive(Debug, Clone)]
struct Sr25519BatchItem {
@@ -61,7 +64,9 @@ impl BatchVerifier {
name: &'static str,
) -> bool {
// there is already invalid transaction encountered
if self.invalid.load(AtomicOrdering::Relaxed) { return false; }
if self.invalid.load(AtomicOrdering::Relaxed) {
return false
}
let invalid_clone = self.invalid.clone();
let (sender, receiver) = oneshot::channel();
@@ -78,7 +83,8 @@ impl BatchVerifier {
log::warn!("Verification halted while result was pending");
invalid_clone.store(true, AtomicOrdering::Relaxed);
}
}.boxed(),
}
.boxed(),
);
true
@@ -110,7 +116,9 @@ impl BatchVerifier {
pub_key: sr25519::Public,
message: Vec<u8>,
) -> bool {
if self.invalid.load(AtomicOrdering::Relaxed) { return false; }
if self.invalid.load(AtomicOrdering::Relaxed) {
return false
}
self.sr25519_items.push(Sr25519BatchItem { signature, pub_key, message });
if self.sr25519_items.len() >= 128 {
@@ -163,7 +171,7 @@ impl BatchVerifier {
);
if !Self::verify_sr25519_batch(std::mem::take(&mut self.sr25519_items)) {
return false;
return false
}
if pending.len() > 0 {
@@ -172,10 +180,12 @@ impl BatchVerifier {
"substrate_batch_verify_join",
async move {
futures::future::join_all(pending).await;
sender.send(())
.expect("Channel never panics if receiver is live. \
Receiver is always live until received this data; qed. ");
}.boxed(),
sender.send(()).expect(
"Channel never panics if receiver is live. \
Receiver is always live until received this data; qed. ",
);
}
.boxed(),
);
if receiver.recv().is_err() {
@@ -184,7 +194,7 @@ impl BatchVerifier {
"Haven't received async result from verification task. Returning false.",
);
return false;
return false
}
}
+163 -194
View File
@@ -18,14 +18,16 @@
//! I/O host interface for substrate runtime.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc_error_handler))]
#![cfg_attr(feature = "std",
doc = "Substrate runtime standard library as compiled when linked with Rust's standard library.")]
#![cfg_attr(not(feature = "std"),
doc = "Substrate's runtime standard library as compiled without Rust's standard library.")]
#![cfg_attr(
feature = "std",
doc = "Substrate runtime standard library as compiled when linked with Rust's standard library."
)]
#![cfg_attr(
not(feature = "std"),
doc = "Substrate's runtime standard library as compiled without Rust's standard library."
)]
use sp_std::vec::Vec;
@@ -35,31 +37,35 @@ use tracing;
#[cfg(feature = "std")]
use sp_core::{
crypto::Pair,
traits::{TaskExecutorExt, RuntimeSpawnExt},
offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
hexdisplay::HexDisplay,
offchain::{OffchainDbExt, OffchainWorkerExt, TransactionPoolExt},
storage::ChildInfo,
traits::{RuntimeSpawnExt, TaskExecutorExt},
};
#[cfg(feature = "std")]
use sp_keystore::{KeystoreExt, SyncCryptoStore};
use sp_core::{
OpaquePeerId, crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, LogLevelFilter,
crypto::KeyTypeId,
ecdsa, ed25519,
offchain::{
Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState,
HttpError, HttpRequestId, HttpRequestStatus, OpaqueNetworkState, StorageKind, Timestamp,
},
sr25519, LogLevel, LogLevelFilter, OpaquePeerId, H256,
};
#[cfg(feature = "std")]
use sp_trie::{TrieConfiguration, trie_types::Layout};
use sp_trie::{trie_types::Layout, TrieConfiguration};
use sp_runtime_interface::{runtime_interface, Pointer};
use sp_runtime_interface::pass_by::{PassBy, PassByCodec};
use sp_runtime_interface::{
pass_by::{PassBy, PassByCodec},
runtime_interface, Pointer,
};
use codec::{Encode, Decode};
use codec::{Decode, Encode};
#[cfg(feature = "std")]
use sp_externalities::{ExternalitiesExt, Externalities};
use sp_externalities::{Externalities, ExternalitiesExt};
#[cfg(feature = "std")]
mod batch_verifier;
@@ -167,7 +173,6 @@ pub trait Storage {
}
}
/// Append the encoded `value` to the storage item at `key`.
///
/// The storage item needs to implement [`EncodeAppend`](codec::EncodeAppend).
@@ -255,11 +260,7 @@ pub trait DefaultChildStorage {
///
/// Parameter `storage_key` is the unprefixed location of the root of the child trie in the parent trie.
/// Result is `None` if the value for `key` in the child storage can not be found.
fn get(
&self,
storage_key: &[u8],
key: &[u8],
) -> Option<Vec<u8>> {
fn get(&self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
let child_info = ChildInfo::new_default(storage_key);
self.child_storage(&child_info, key).map(|s| s.to_vec())
}
@@ -279,25 +280,19 @@ pub trait DefaultChildStorage {
value_offset: u32,
) -> Option<u32> {
let child_info = ChildInfo::new_default(storage_key);
self.child_storage(&child_info, key)
.map(|value| {
let value_offset = value_offset as usize;
let data = &value[value_offset.min(value.len())..];
let written = std::cmp::min(data.len(), value_out.len());
value_out[..written].copy_from_slice(&data[..written]);
data.len() as u32
})
self.child_storage(&child_info, key).map(|value| {
let value_offset = value_offset as usize;
let data = &value[value_offset.min(value.len())..];
let written = std::cmp::min(data.len(), value_out.len());
value_out[..written].copy_from_slice(&data[..written]);
data.len() as u32
})
}
/// Set a child storage value.
///
/// Set `key` to `value` in the child storage denoted by `storage_key`.
fn set(
&mut self,
storage_key: &[u8],
key: &[u8],
value: &[u8],
) {
fn set(&mut self, storage_key: &[u8], key: &[u8], value: &[u8]) {
let child_info = ChildInfo::new_default(storage_key);
self.set_child_storage(&child_info, key.to_vec(), value.to_vec());
}
@@ -305,11 +300,7 @@ pub trait DefaultChildStorage {
/// Clear a child storage key.
///
/// For the default child storage at `storage_key`, clear value at `key`.
fn clear(
&mut self,
storage_key: &[u8],
key: &[u8],
) {
fn clear(&mut self, storage_key: &[u8], key: &[u8]) {
let child_info = ChildInfo::new_default(storage_key);
self.clear_child_storage(&child_info, key);
}
@@ -318,10 +309,7 @@ pub trait DefaultChildStorage {
///
/// If it exists, the child storage for `storage_key`
/// is removed.
fn storage_kill(
&mut self,
storage_key: &[u8],
) {
fn storage_kill(&mut self, storage_key: &[u8]) {
let child_info = ChildInfo::new_default(storage_key);
self.kill_child_storage(&child_info, None);
}
@@ -352,11 +340,7 @@ pub trait DefaultChildStorage {
/// Check a child storage key.
///
/// Check whether the given `key` exists in default child defined at `storage_key`.
fn exists(
&self,
storage_key: &[u8],
key: &[u8],
) -> bool {
fn exists(&self, storage_key: &[u8], key: &[u8]) -> bool {
let child_info = ChildInfo::new_default(storage_key);
self.exists_child_storage(&child_info, key)
}
@@ -364,11 +348,7 @@ pub trait DefaultChildStorage {
/// Clear child default key by prefix.
///
/// Clear the child storage of each key-value pair where the key starts with the given `prefix`.
fn clear_prefix(
&mut self,
storage_key: &[u8],
prefix: &[u8],
) {
fn clear_prefix(&mut self, storage_key: &[u8], prefix: &[u8]) {
let child_info = ChildInfo::new_default(storage_key);
let _ = self.clear_child_prefix(&child_info, prefix, None);
}
@@ -397,10 +377,7 @@ pub trait DefaultChildStorage {
/// The hashing algorithm is defined by the `Block`.
///
/// Returns a `Vec<u8>` that holds the SCALE encoded hash.
fn root(
&mut self,
storage_key: &[u8],
) -> Vec<u8> {
fn root(&mut self, storage_key: &[u8]) -> Vec<u8> {
let child_info = ChildInfo::new_default(storage_key);
self.child_storage_root(&child_info)
}
@@ -408,11 +385,7 @@ pub trait DefaultChildStorage {
/// Child storage key iteration.
///
/// Get the next key in storage after the given one in lexicographic order in child storage.
fn next_key(
&mut self,
storage_key: &[u8],
key: &[u8],
) -> Option<Vec<u8>> {
fn next_key(&mut self, storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
let child_info = ChildInfo::new_default(storage_key);
self.next_child_storage_key(&child_info, key)
}
@@ -447,7 +420,8 @@ pub trait Trie {
&root,
proof,
&[(key, Some(value))],
).is_ok()
)
.is_ok()
}
/// Verify trie proof
@@ -456,7 +430,8 @@ pub trait Trie {
&root,
proof,
&[(key, Some(value))],
).is_ok()
)
.is_ok()
}
}
@@ -516,7 +491,7 @@ pub trait Misc {
err,
);
None
}
},
}
}
}
@@ -526,7 +501,8 @@ pub trait Misc {
pub trait Crypto {
/// Returns all `ed25519` public keys for the given key id from the keystore.
fn ed25519_public_keys(&mut self, id: KeyTypeId) -> Vec<ed25519::Public> {
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ed25519_public_keys(keystore, id)
}
@@ -539,7 +515,8 @@ pub trait Crypto {
/// Returns the public key.
fn ed25519_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> ed25519::Public {
let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!"));
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ed25519_generate_new(keystore, id, seed)
.expect("`ed25519_generate` failed")
@@ -555,7 +532,8 @@ pub trait Crypto {
pub_key: &ed25519::Public,
msg: &[u8],
) -> Option<ed25519::Signature> {
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
@@ -566,11 +544,7 @@ pub trait Crypto {
/// Verify `ed25519` signature.
///
/// Returns `true` when the verification was successful.
fn ed25519_verify(
sig: &ed25519::Signature,
msg: &[u8],
pub_key: &ed25519::Public,
) -> bool {
fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pub_key: &ed25519::Public) -> bool {
ed25519::Pair::verify(sig, msg, pub_key)
}
@@ -588,20 +562,16 @@ pub trait Crypto {
msg: &[u8],
pub_key: &ed25519::Public,
) -> bool {
self.extension::<VerificationExt>().map(
|extension| extension.push_ed25519(sig.clone(), pub_key.clone(), msg.to_vec())
).unwrap_or_else(|| ed25519_verify(sig, msg, pub_key))
self.extension::<VerificationExt>()
.map(|extension| extension.push_ed25519(sig.clone(), pub_key.clone(), msg.to_vec()))
.unwrap_or_else(|| ed25519_verify(sig, msg, pub_key))
}
/// Verify `sr25519` signature.
///
/// Returns `true` when the verification was successful.
#[version(2)]
fn sr25519_verify(
sig: &sr25519::Signature,
msg: &[u8],
pub_key: &sr25519::Public,
) -> bool {
fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pub_key: &sr25519::Public) -> bool {
sr25519::Pair::verify(sig, msg, pub_key)
}
@@ -619,14 +589,15 @@ pub trait Crypto {
msg: &[u8],
pub_key: &sr25519::Public,
) -> bool {
self.extension::<VerificationExt>().map(
|extension| extension.push_sr25519(sig.clone(), pub_key.clone(), msg.to_vec())
).unwrap_or_else(|| sr25519_verify(sig, msg, pub_key))
self.extension::<VerificationExt>()
.map(|extension| extension.push_sr25519(sig.clone(), pub_key.clone(), msg.to_vec()))
.unwrap_or_else(|| sr25519_verify(sig, msg, pub_key))
}
/// Start verification extension.
fn start_batch_verify(&mut self) {
let scheduler = self.extension::<TaskExecutorExt>()
let scheduler = self
.extension::<TaskExecutorExt>()
.expect("No task executor associated with the current context!")
.clone();
@@ -641,7 +612,8 @@ pub trait Crypto {
///
/// Will panic if no `VerificationExt` is registered (`start_batch_verify` was not called).
fn finish_batch_verify(&mut self) -> bool {
let result = self.extension::<VerificationExt>()
let result = self
.extension::<VerificationExt>()
.expect("`finish_batch_verify` should only be called after `start_batch_verify`")
.verify_and_clear();
@@ -653,7 +625,8 @@ pub trait Crypto {
/// Returns all `sr25519` public keys for the given key id from the keystore.
fn sr25519_public_keys(&mut self, id: KeyTypeId) -> Vec<sr25519::Public> {
let keystore = &*** self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sr25519_public_keys(keystore, id)
}
@@ -666,7 +639,8 @@ pub trait Crypto {
/// Returns the public key.
fn sr25519_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> sr25519::Public {
let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!"));
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sr25519_generate_new(keystore, id, seed)
.expect("`sr25519_generate` failed")
@@ -682,7 +656,8 @@ pub trait Crypto {
pub_key: &sr25519::Public,
msg: &[u8],
) -> Option<sr25519::Signature> {
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
@@ -700,7 +675,8 @@ pub trait Crypto {
/// Returns all `ecdsa` public keys for the given key id from the keystore.
fn ecdsa_public_keys(&mut self, id: KeyTypeId) -> Vec<ecdsa::Public> {
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ecdsa_public_keys(keystore, id)
}
@@ -713,10 +689,10 @@ pub trait Crypto {
/// Returns the public key.
fn ecdsa_generate(&mut self, id: KeyTypeId, seed: Option<Vec<u8>>) -> ecdsa::Public {
let seed = seed.as_ref().map(|s| std::str::from_utf8(&s).expect("Seed is valid utf8!"));
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::ecdsa_generate_new(keystore, id, seed)
.expect("`ecdsa_generate` failed")
SyncCryptoStore::ecdsa_generate_new(keystore, id, seed).expect("`ecdsa_generate` failed")
}
/// Sign the given `msg` with the `ecdsa` key that corresponds to the given public key and
@@ -729,7 +705,8 @@ pub trait Crypto {
pub_key: &ecdsa::Public,
msg: &[u8],
) -> Option<ecdsa::Signature> {
let keystore = &***self.extension::<KeystoreExt>()
let keystore = &***self
.extension::<KeystoreExt>()
.expect("No `keystore` associated for the current context!");
SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg)
.ok()
@@ -740,11 +717,7 @@ pub trait Crypto {
/// Verify `ecdsa` signature.
///
/// Returns `true` when the verification was successful.
fn ecdsa_verify(
sig: &ecdsa::Signature,
msg: &[u8],
pub_key: &ecdsa::Public,
) -> bool {
fn ecdsa_verify(sig: &ecdsa::Signature, msg: &[u8], pub_key: &ecdsa::Public) -> bool {
ecdsa::Pair::verify(sig, msg, pub_key)
}
@@ -762,9 +735,9 @@ pub trait Crypto {
msg: &[u8],
pub_key: &ecdsa::Public,
) -> bool {
self.extension::<VerificationExt>().map(
|extension| extension.push_ecdsa(sig.clone(), pub_key.clone(), msg.to_vec())
).unwrap_or_else(|| ecdsa_verify(sig, msg, pub_key))
self.extension::<VerificationExt>()
.map(|extension| extension.push_ecdsa(sig.clone(), pub_key.clone(), msg.to_vec()))
.unwrap_or_else(|| ecdsa_verify(sig, msg, pub_key))
}
/// Verify and recover a SECP256k1 ECDSA signature.
@@ -778,10 +751,11 @@ pub trait Crypto {
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 64], EcdsaVerifyError> {
let rs = secp256k1::Signature::parse_slice(&sig[0..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8)
.map_err(|_| EcdsaVerifyError::BadV)?;
let rs =
secp256k1::Signature::parse_slice(&sig[0..64]).map_err(|_| EcdsaVerifyError::BadRS)?;
let v =
secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = secp256k1::recover(&secp256k1::Message::parse(msg), &rs, &v)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
let mut res = [0u8; 64];
@@ -799,10 +773,11 @@ pub trait Crypto {
sig: &[u8; 65],
msg: &[u8; 32],
) -> Result<[u8; 33], EcdsaVerifyError> {
let rs = secp256k1::Signature::parse_slice(&sig[0..64])
.map_err(|_| EcdsaVerifyError::BadRS)?;
let v = secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8)
.map_err(|_| EcdsaVerifyError::BadV)?;
let rs =
secp256k1::Signature::parse_slice(&sig[0..64]).map_err(|_| EcdsaVerifyError::BadRS)?;
let v =
secp256k1::RecoveryId::parse(if sig[64] > 26 { sig[64] - 27 } else { sig[64] } as u8)
.map_err(|_| EcdsaVerifyError::BadV)?;
let pubkey = secp256k1::recover(&secp256k1::Message::parse(msg), &rs, &v)
.map_err(|_| EcdsaVerifyError::BadSignature)?;
Ok(pubkey.serialize_compressed())
@@ -907,8 +882,10 @@ pub trait Offchain {
/// The transaction will end up in the pool.
fn submit_transaction(&mut self, data: Vec<u8>) -> Result<(), ()> {
self.extension::<TransactionPoolExt>()
.expect("submit_transaction can be called only in the offchain call context with
TransactionPool capabilities enabled")
.expect(
"submit_transaction can be called only in the offchain call context with
TransactionPool capabilities enabled",
)
.submit_transaction(data)
}
@@ -949,8 +926,10 @@ pub trait Offchain {
/// offchain worker tasks running on the same machine. It IS persisted between runs.
fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
self.extension::<OffchainDbExt>()
.expect("local_storage_set can be called only in the offchain call context with
OffchainDb extension")
.expect(
"local_storage_set can be called only in the offchain call context with
OffchainDb extension",
)
.local_storage_set(kind, key, value)
}
@@ -960,8 +939,10 @@ pub trait Offchain {
/// offchain worker tasks running on the same machine. It IS persisted between runs.
fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
self.extension::<OffchainDbExt>()
.expect("local_storage_clear can be called only in the offchain call context with
OffchainDb extension")
.expect(
"local_storage_clear can be called only in the offchain call context with
OffchainDb extension",
)
.local_storage_clear(kind, key)
}
@@ -982,14 +963,11 @@ pub trait Offchain {
new_value: &[u8],
) -> bool {
self.extension::<OffchainDbExt>()
.expect("local_storage_compare_and_set can be called only in the offchain call context
with OffchainDb extension")
.local_storage_compare_and_set(
kind,
key,
old_value.as_deref(),
new_value,
.expect(
"local_storage_compare_and_set can be called only in the offchain call context
with OffchainDb extension",
)
.local_storage_compare_and_set(kind, key, old_value.as_deref(), new_value)
}
/// Gets a value from the local storage.
@@ -999,8 +977,10 @@ pub trait Offchain {
/// offchain worker tasks running on the same machine. It IS persisted between runs.
fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
self.extension::<OffchainDbExt>()
.expect("local_storage_get can be called only in the offchain call context with
OffchainDb extension")
.expect(
"local_storage_get can be called only in the offchain call context with
OffchainDb extension",
)
.local_storage_get(kind, key)
}
@@ -1128,12 +1108,7 @@ pub trait Logging {
/// Instead of using directly, prefer setting up `RuntimeLogger` and using `log` macros.
fn log(level: LogLevel, target: &str, message: &[u8]) {
if let Ok(message) = std::str::from_utf8(message) {
log::log!(
target: target,
log::Level::from(level),
"{}",
message,
)
log::log!(target: target, log::Level::from(level), "{}", message,)
}
}
@@ -1153,7 +1128,6 @@ impl<T: Encode + Decode> PassBy for Crossing<T> {
}
impl<T: Encode + Decode> Crossing<T> {
/// Convert into the inner type
pub fn into_inner(self) -> T {
self.0
@@ -1162,12 +1136,12 @@ impl<T: Encode + Decode> Crossing<T> {
// useful for testing
impl<T> core::default::Default for Crossing<T>
where T: core::default::Default + Encode + Decode
where
T: core::default::Default + Encode + Decode,
{
fn default() -> Self {
Self(Default::default())
}
}
/// Interface to provide tracing facilities for wasm. Modelled after tokios `tracing`-crate
@@ -1184,9 +1158,7 @@ pub trait WasmTracing {
/// chose to cache the result for the execution of the entire block.
fn enabled(&mut self, metadata: Crossing<sp_tracing::WasmMetadata>) -> bool {
let metadata: &tracing_core::metadata::Metadata<'static> = (&metadata.into_inner()).into();
tracing::dispatcher::get_default(|d| {
d.enabled(metadata)
})
tracing::dispatcher::get_default(|d| d.enabled(metadata))
}
/// Open a new span with the given attributes. Return the u64 Id of the span.
@@ -1205,9 +1177,7 @@ pub trait WasmTracing {
d.enter(&final_id);
final_id.into_u64()
}),
_ => {
0
}
_ => 0,
}
}
@@ -1226,19 +1196,18 @@ pub trait WasmTracing {
}
}
#[cfg(all(not(feature="std"), feature="with-tracing"))]
#[cfg(all(not(feature = "std"), feature = "with-tracing"))]
mod tracing_setup {
use super::{wasm_tracing, Crossing};
use core::sync::atomic::{AtomicBool, Ordering};
use tracing_core::{
dispatcher::{Dispatch, set_global_default},
span::{Id, Record, Attributes},
Metadata, Event,
dispatcher::{set_global_default, Dispatch},
span::{Attributes, Id, Record},
Event, Metadata,
};
use super::{wasm_tracing, Crossing};
static TRACING_SET: AtomicBool = AtomicBool::new(false);
/// The PassingTracingSubscriber implements `tracing_core::Subscriber`
/// and pushes the information across the runtime interface to the host
struct PassingTracingSubsciber;
@@ -1256,12 +1225,12 @@ mod tracing_setup {
/// Not implemented! We do not support recording values later
/// Will panic when used.
fn record(&self, span: &Id, values: &Record<'_>) {
unimplemented!{} // this usage is not supported
unimplemented! {} // this usage is not supported
}
/// Not implemented! We do not support recording values later
/// Will panic when used.
fn record_follows_from(&self, span: &Id, follows: &Id) {
unimplemented!{ } // this usage is not supported
unimplemented! {} // this usage is not supported
}
fn event(&self, event: &Event<'_>) {
wasm_tracing::event(Crossing(event.into()))
@@ -1271,7 +1240,6 @@ mod tracing_setup {
}
}
/// Initialize tracing of sp_tracing on wasm with `with-tracing` enabled.
/// Can be called multiple times from within the same process and will only
/// set the global bridging subscriber once.
@@ -1284,11 +1252,11 @@ mod tracing_setup {
}
}
#[cfg(not(all(not(feature="std"), feature="with-tracing")))]
#[cfg(not(all(not(feature = "std"), feature = "with-tracing")))]
mod tracing_setup {
/// Initialize tracing of sp_tracing not necessary noop. To enable build
/// without std and with the `with-tracing`-feature.
pub fn init_tracing() { }
pub fn init_tracing() {}
}
pub use tracing_setup::init_tracing;
@@ -1319,14 +1287,16 @@ pub trait Sandbox {
return_val_len: u32,
state_ptr: Pointer<u8>,
) -> u32 {
self.sandbox().invoke(
instance_idx,
&function,
&args,
return_val_ptr,
return_val_len,
state_ptr.into(),
).expect("Failed to invoke function with sandbox")
self.sandbox()
.invoke(
instance_idx,
&function,
&args,
return_val_ptr,
return_val_len,
state_ptr.into(),
)
.expect("Failed to invoke function with sandbox")
}
/// Create a new memory instance with the given `initial` and `maximum` size.
@@ -1364,20 +1334,30 @@ pub trait Sandbox {
/// Teardown the memory instance with the given `memory_idx`.
fn memory_teardown(&mut self, memory_idx: u32) {
self.sandbox().memory_teardown(memory_idx).expect("Failed to teardown memory with sandbox")
self.sandbox()
.memory_teardown(memory_idx)
.expect("Failed to teardown memory with sandbox")
}
/// Teardown the sandbox instance with the given `instance_idx`.
fn instance_teardown(&mut self, instance_idx: u32) {
self.sandbox().instance_teardown(instance_idx).expect("Failed to teardown sandbox instance")
self.sandbox()
.instance_teardown(instance_idx)
.expect("Failed to teardown sandbox instance")
}
/// Get the value from a global with the given `name`. The sandbox is determined by the given
/// `instance_idx`.
///
/// Returns `Some(_)` when the requested global variable could be found.
fn get_global_val(&mut self, instance_idx: u32, name: &str) -> Option<sp_wasm_interface::Value> {
self.sandbox().get_global_val(instance_idx, name).expect("Failed to get global from sandbox")
fn get_global_val(
&mut self,
instance_idx: u32,
name: &str,
) -> Option<sp_wasm_interface::Value> {
self.sandbox()
.get_global_val(instance_idx, name)
.expect("Failed to get global from sandbox")
}
}
@@ -1390,11 +1370,13 @@ pub trait RuntimeTasks {
///
/// This should not be used directly. Use `sp_tasks::spawn` instead.
fn spawn(dispatcher_ref: u32, entry: u32, payload: Vec<u8>) -> u64 {
sp_externalities::with_externalities(|mut ext|{
let runtime_spawn = ext.extension::<RuntimeSpawnExt>()
sp_externalities::with_externalities(|mut ext| {
let runtime_spawn = ext
.extension::<RuntimeSpawnExt>()
.expect("Cannot spawn without dynamic runtime dispatcher (RuntimeSpawnExt)");
runtime_spawn.spawn_call(dispatcher_ref, entry, payload)
}).expect("`RuntimeTasks::spawn`: called outside of externalities context")
})
.expect("`RuntimeTasks::spawn`: called outside of externalities context")
}
/// Wasm host function for joining a task.
@@ -1402,12 +1384,14 @@ pub trait RuntimeTasks {
/// This should not be used directly. Use `join` of `sp_tasks::spawn` result instead.
fn join(handle: u64) -> Vec<u8> {
sp_externalities::with_externalities(|mut ext| {
let runtime_spawn = ext.extension::<RuntimeSpawnExt>()
let runtime_spawn = ext
.extension::<RuntimeSpawnExt>()
.expect("Cannot join without dynamic runtime dispatcher (RuntimeSpawnExt)");
runtime_spawn.join(handle)
}).expect("`RuntimeTasks::join`: called outside of externalities context")
})
.expect("`RuntimeTasks::join`: called outside of externalities context")
}
}
}
/// Allocator used by Substrate when executing the Wasm runtime.
#[cfg(not(feature = "std"))]
@@ -1483,10 +1467,8 @@ pub type SubstrateHostFunctions = (
#[cfg(test)]
mod tests {
use super::*;
use sp_core::{map, storage::Storage, testing::TaskExecutor, traits::TaskExecutorExt};
use sp_state_machine::BasicExternalities;
use sp_core::{
storage::Storage, map, traits::TaskExecutorExt, testing::TaskExecutor,
};
use std::any::TypeId;
#[test]
@@ -1542,7 +1524,10 @@ mod tests {
});
t.execute_with(|| {
assert!(matches!(storage::clear_prefix(b":abc", None), KillStorageResult::AllRemoved(2)));
assert!(matches!(
storage::clear_prefix(b":abc", None),
KillStorageResult::AllRemoved(2)
));
assert!(storage::get(b":a").is_some());
assert!(storage::get(b":abdd").is_some());
@@ -1583,11 +1568,7 @@ mod tests {
}
// push invlaid
crypto::sr25519_batch_verify(
&Default::default(),
&Vec::new(),
&Default::default(),
);
crypto::sr25519_batch_verify(&Default::default(), &Vec::new(), &Default::default());
assert!(!crypto::finish_batch_verify());
crypto::start_batch_verify();
@@ -1607,11 +1588,7 @@ mod tests {
ext.execute_with(|| {
// invalid ed25519 signature
crypto::start_batch_verify();
crypto::ed25519_batch_verify(
&Default::default(),
&Vec::new(),
&Default::default(),
);
crypto::ed25519_batch_verify(&Default::default(), &Vec::new(), &Default::default());
assert!(!crypto::finish_batch_verify());
// 2 valid ed25519 signatures
@@ -1637,11 +1614,7 @@ mod tests {
let signature = pair.sign(msg);
crypto::ed25519_batch_verify(&signature, msg, &pair.public());
crypto::ed25519_batch_verify(
&Default::default(),
&Vec::new(),
&Default::default(),
);
crypto::ed25519_batch_verify(&Default::default(), &Vec::new(), &Default::default());
assert!(!crypto::finish_batch_verify());
@@ -1673,11 +1646,7 @@ mod tests {
let signature = pair.sign(msg);
crypto::sr25519_batch_verify(&signature, msg, &pair.public());
crypto::sr25519_batch_verify(
&Default::default(),
&Vec::new(),
&Default::default(),
);
crypto::sr25519_batch_verify(&Default::default(), &Vec::new(), &Default::default());
assert!(!crypto::finish_batch_verify());
});
+25 -31
View File
@@ -17,11 +17,14 @@
//! Support code for the runtime. A set of test accounts.
use std::{collections::HashMap, ops::Deref};
use lazy_static::lazy_static;
use sp_core::{ed25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
pub use sp_core::ed25519;
use sp_core::{
ed25519::{Pair, Public, Signature},
Pair as PairT, Public as PublicT, H256,
};
use sp_runtime::AccountId32;
use std::{collections::HashMap, ops::Deref};
/// Set of test accounts.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)]
@@ -79,7 +82,7 @@ impl Keyring {
}
/// Returns an iterator over all test accounts.
pub fn iter() -> impl Iterator<Item=Keyring> {
pub fn iter() -> impl Iterator<Item = Keyring> {
<Self as strum::IntoEnumIterator>::iter()
}
@@ -114,13 +117,10 @@ impl From<Keyring> for sp_runtime::MultiSigner {
}
lazy_static! {
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> = {
Keyring::iter().map(|i| (i, i.pair())).collect()
};
static ref PUBLIC_KEYS: HashMap<Keyring, Public> = {
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect()
};
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> =
Keyring::iter().map(|i| (i, i.pair())).collect();
static ref PUBLIC_KEYS: HashMap<Keyring, Public> =
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect();
}
impl From<Keyring> for Public {
@@ -185,26 +185,20 @@ mod tests {
#[test]
fn should_work() {
assert!(
Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Alice.public(),
)
);
assert!(
!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Bob!",
&Keyring::Alice.public(),
)
);
assert!(
!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Bob.public(),
)
);
assert!(Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Alice.public(),
));
assert!(!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Bob!",
&Keyring::Alice.public(),
));
assert!(!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Bob.public(),
));
}
}
+26 -33
View File
@@ -17,12 +17,14 @@
//! Support code for the runtime. A set of test accounts.
use std::collections::HashMap;
use std::ops::Deref;
use lazy_static::lazy_static;
use sp_core::{sr25519::{Pair, Public, Signature}, Pair as PairT, Public as PublicT, H256};
pub use sp_core::sr25519;
use sp_core::{
sr25519::{Pair, Public, Signature},
Pair as PairT, Public as PublicT, H256,
};
use sp_runtime::AccountId32;
use std::{collections::HashMap, ops::Deref};
/// Set of test accounts.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)]
@@ -80,7 +82,7 @@ impl Keyring {
}
/// Returns an iterator over all test accounts.
pub fn iter() -> impl Iterator<Item=Keyring> {
pub fn iter() -> impl Iterator<Item = Keyring> {
<Self as strum::IntoEnumIterator>::iter()
}
@@ -135,19 +137,16 @@ impl std::str::FromStr for Keyring {
"ferdie" => Ok(Keyring::Ferdie),
"one" => Ok(Keyring::One),
"two" => Ok(Keyring::Two),
_ => Err(ParseKeyringError)
_ => Err(ParseKeyringError),
}
}
}
lazy_static! {
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> = {
Keyring::iter().map(|i| (i, i.pair())).collect()
};
static ref PUBLIC_KEYS: HashMap<Keyring, Public> = {
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect()
};
static ref PRIVATE_KEYS: HashMap<Keyring, Pair> =
Keyring::iter().map(|i| (i, i.pair())).collect();
static ref PUBLIC_KEYS: HashMap<Keyring, Public> =
PRIVATE_KEYS.iter().map(|(&name, pair)| (name, pair.public())).collect();
}
impl From<Keyring> for AccountId32 {
@@ -212,26 +211,20 @@ mod tests {
#[test]
fn should_work() {
assert!(
Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Alice.public(),
)
);
assert!(
!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Bob!",
&Keyring::Alice.public(),
)
);
assert!(
!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Bob.public(),
)
);
assert!(Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Alice.public(),
));
assert!(!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Bob!",
&Keyring::Alice.public(),
));
assert!(!Pair::verify(
&Keyring::Alice.sign(b"I am Alice!"),
b"I am Alice!",
&Keyring::Bob.public(),
));
}
}
+25 -34
View File
@@ -19,30 +19,30 @@
pub mod testing;
pub mod vrf;
use std::sync::Arc;
use crate::vrf::{VRFSignature, VRFTranscriptData};
use async_trait::async_trait;
use futures::{executor::block_on, future::join_all};
use sp_core::{
crypto::{KeyTypeId, CryptoTypePublicPair},
ed25519, sr25519, ecdsa,
crypto::{CryptoTypePublicPair, KeyTypeId},
ecdsa, ed25519, sr25519,
};
use crate::vrf::{VRFTranscriptData, VRFSignature};
use std::sync::Arc;
/// CryptoStore error
#[derive(Debug, derive_more::Display)]
pub enum Error {
/// Public key type is not supported
#[display(fmt="Key not supported: {:?}", _0)]
#[display(fmt = "Key not supported: {:?}", _0)]
KeyNotSupported(KeyTypeId),
/// Validation error
#[display(fmt="Validation error: {}", _0)]
#[display(fmt = "Validation error: {}", _0)]
ValidationError(String),
/// Keystore unavailable
#[display(fmt="Keystore unavailable")]
#[display(fmt = "Keystore unavailable")]
Unavailable,
/// Programming errors
#[display(fmt="An unknown keystore error occurred: {}", _0)]
Other(String)
#[display(fmt = "An unknown keystore error occurred: {}", _0)]
Other(String),
}
/// Something that generates, stores and provides access to keys.
@@ -91,12 +91,7 @@ pub trait CryptoStore: Send + Sync {
/// Places it into the file system store.
///
/// `Err` if there's some sort of weird filesystem error, but should generally be `Ok`.
async fn insert_unknown(
&self,
id: KeyTypeId,
suri: &str,
public: &[u8]
) -> Result<(), ()>;
async fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()>;
/// Find intersection between provided keys and supported keys
///
@@ -105,7 +100,7 @@ pub trait CryptoStore: Send + Sync {
async fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>
keys: Vec<CryptoTypePublicPair>,
) -> Result<Vec<CryptoTypePublicPair>, Error>;
/// List all supported keys
///
@@ -142,14 +137,14 @@ pub trait CryptoStore: Send + Sync {
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8]
msg: &[u8],
) -> Result<Option<(CryptoTypePublicPair, Vec<u8>)>, Error> {
if keys.len() == 1 {
return Ok(self.sign_with(id, &keys[0], msg).await?.map(|s| (keys[0].clone(), s)));
return Ok(self.sign_with(id, &keys[0], msg).await?.map(|s| (keys[0].clone(), s)))
} else {
for k in self.supported_keys(id, keys).await? {
if let Ok(Some(sign)) = self.sign_with(id, &k, msg).await {
return Ok(Some((k, sign)));
return Ok(Some((k, sign)))
}
}
}
@@ -170,8 +165,7 @@ pub trait CryptoStore: Send + Sync {
keys: Vec<CryptoTypePublicPair>,
msg: &[u8],
) -> Result<Vec<Result<Option<Vec<u8>>, Error>>, ()> {
let futs = keys.iter()
.map(|k| self.sign_with(id, k, msg));
let futs = keys.iter().map(|k| self.sign_with(id, k, msg));
Ok(join_all(futs).await)
}
@@ -202,8 +196,8 @@ pub trait CryptoStore: Send + Sync {
/// in turn, used for signing the provided pre-hashed message.
///
/// The `msg` argument provided should be a hashed message for which an
/// ECDSA signature should be generated.
///
/// ECDSA signature should be generated.
///
/// Returns an [`ecdsa::Signature`] or `None` in case the given `id` and
/// `public` combination doesn't exist in the keystore. An `Err` will be
/// returned if generating the signature itself failed.
@@ -260,11 +254,8 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
/// If the given seed is `Some(_)`, the key pair will only be stored in memory.
///
/// Returns the public key of the generated key pair.
fn ecdsa_generate_new(
&self,
id: KeyTypeId,
seed: Option<&str>,
) -> Result<ecdsa::Public, Error>;
fn ecdsa_generate_new(&self, id: KeyTypeId, seed: Option<&str>)
-> Result<ecdsa::Public, Error>;
/// Insert a new key. This doesn't require any known of the crypto; but a public key must be
/// manually provided.
@@ -281,7 +272,7 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
fn supported_keys(
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>
keys: Vec<CryptoTypePublicPair>,
) -> Result<Vec<CryptoTypePublicPair>, Error>;
/// List all supported keys
@@ -321,16 +312,16 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
&self,
id: KeyTypeId,
keys: Vec<CryptoTypePublicPair>,
msg: &[u8]
msg: &[u8],
) -> Result<Option<(CryptoTypePublicPair, Vec<u8>)>, Error> {
if keys.len() == 1 {
return Ok(
SyncCryptoStore::sign_with(self, id, &keys[0], msg)?.map(|s| (keys[0].clone(), s)),
SyncCryptoStore::sign_with(self, id, &keys[0], msg)?.map(|s| (keys[0].clone(), s))
)
} else {
for k in SyncCryptoStore::supported_keys(self, id, keys)? {
if let Ok(Some(sign)) = SyncCryptoStore::sign_with(self, id, &k, msg) {
return Ok(Some((k, sign)));
return Ok(Some((k, sign)))
}
}
}
@@ -380,8 +371,8 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync {
/// in turn, used for signing the provided pre-hashed message.
///
/// The `msg` argument provided should be a hashed message for which an
/// ECDSA signature should be generated.
///
/// ECDSA signature should be generated.
///
/// Returns an [`ecdsa::Signature`] or `None` in case the given `id` and
/// `public` combination doesn't exist in the keystore. An `Err` will be
/// returned if generating the signature itself failed.
+138 -105
View File
@@ -17,19 +17,21 @@
//! Types that should only be used for testing!
use sp_core::crypto::KeyTypeId;
use sp_core::{
crypto::{Pair, Public, CryptoTypePublicPair},
ed25519, sr25519, ecdsa,
crypto::{CryptoTypePublicPair, KeyTypeId, Pair, Public},
ecdsa, ed25519, sr25519,
};
use crate::{
{CryptoStore, SyncCryptoStorePtr, Error, SyncCryptoStore},
vrf::{VRFTranscriptData, VRFSignature, make_transcript},
vrf::{make_transcript, VRFSignature, VRFTranscriptData},
CryptoStore, Error, SyncCryptoStore, SyncCryptoStorePtr,
};
use std::{collections::{HashMap, HashSet}, sync::Arc};
use parking_lot::RwLock;
use async_trait::async_trait;
use parking_lot::RwLock;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
/// A keystore implementation usable in tests.
#[derive(Default)]
@@ -45,29 +47,28 @@ impl KeyStore {
}
fn sr25519_key_pair(&self, id: KeyTypeId, pub_key: &sr25519::Public) -> Option<sr25519::Pair> {
self.keys.read().get(&id)
.and_then(|inner|
inner.get(pub_key.as_slice())
.map(|s| sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid"))
)
self.keys.read().get(&id).and_then(|inner| {
inner.get(pub_key.as_slice()).map(|s| {
sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid")
})
})
}
fn ed25519_key_pair(&self, id: KeyTypeId, pub_key: &ed25519::Public) -> Option<ed25519::Pair> {
self.keys.read().get(&id)
.and_then(|inner|
inner.get(pub_key.as_slice())
.map(|s| ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid"))
)
self.keys.read().get(&id).and_then(|inner| {
inner.get(pub_key.as_slice()).map(|s| {
ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid")
})
})
}
fn ecdsa_key_pair(&self, id: KeyTypeId, pub_key: &ecdsa::Public) -> Option<ecdsa::Pair> {
self.keys.read().get(&id)
.and_then(|inner|
inner.get(pub_key.as_slice())
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
)
self.keys.read().get(&id).and_then(|inner| {
inner
.get(pub_key.as_slice())
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
})
}
}
#[async_trait]
@@ -158,28 +159,32 @@ impl CryptoStore for KeyStore {
impl SyncCryptoStore for KeyStore {
fn keys(&self, id: KeyTypeId) -> Result<Vec<CryptoTypePublicPair>, Error> {
self.keys.read()
self.keys
.read()
.get(&id)
.map(|map| {
Ok(map.keys()
.fold(Vec::new(), |mut v, k| {
v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone()));
v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone()));
v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k.clone()));
v
}))
Ok(map.keys().fold(Vec::new(), |mut v, k| {
v.push(CryptoTypePublicPair(sr25519::CRYPTO_ID, k.clone()));
v.push(CryptoTypePublicPair(ed25519::CRYPTO_ID, k.clone()));
v.push(CryptoTypePublicPair(ecdsa::CRYPTO_ID, k.clone()));
v
}))
})
.unwrap_or_else(|| Ok(vec![]))
}
fn sr25519_public_keys(&self, id: KeyTypeId) -> Vec<sr25519::Public> {
self.keys.read().get(&id)
.map(|keys|
self.keys
.read()
.get(&id)
.map(|keys| {
keys.values()
.map(|s| sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid"))
.map(|s| {
sr25519::Pair::from_string(s, None).expect("`sr25519` seed slice is valid")
})
.map(|p| p.public())
.collect()
)
})
.unwrap_or_default()
}
@@ -190,27 +195,40 @@ impl SyncCryptoStore for KeyStore {
) -> Result<sr25519::Public, Error> {
match seed {
Some(seed) => {
let pair = sr25519::Pair::from_string(seed, None)
.map_err(|_| Error::ValidationError("Generates an `sr25519` pair.".to_owned()))?;
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
let pair = sr25519::Pair::from_string(seed, None).map_err(|_| {
Error::ValidationError("Generates an `sr25519` pair.".to_owned())
})?;
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
},
None => {
let (pair, phrase, _) = sr25519::Pair::generate_with_phrase(None);
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
}
},
}
}
fn ed25519_public_keys(&self, id: KeyTypeId) -> Vec<ed25519::Public> {
self.keys.read().get(&id)
.map(|keys|
self.keys
.read()
.get(&id)
.map(|keys| {
keys.values()
.map(|s| ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid"))
.map(|s| {
ed25519::Pair::from_string(s, None).expect("`ed25519` seed slice is valid")
})
.map(|p| p.public())
.collect()
)
})
.unwrap_or_default()
}
@@ -221,27 +239,40 @@ impl SyncCryptoStore for KeyStore {
) -> Result<ed25519::Public, Error> {
match seed {
Some(seed) => {
let pair = ed25519::Pair::from_string(seed, None)
.map_err(|_| Error::ValidationError("Generates an `ed25519` pair.".to_owned()))?;
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
let pair = ed25519::Pair::from_string(seed, None).map_err(|_| {
Error::ValidationError("Generates an `ed25519` pair.".to_owned())
})?;
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
},
None => {
let (pair, phrase, _) = ed25519::Pair::generate_with_phrase(None);
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
}
},
}
}
fn ecdsa_public_keys(&self, id: KeyTypeId) -> Vec<ecdsa::Public> {
self.keys.read().get(&id)
.map(|keys|
self.keys
.read()
.get(&id)
.map(|keys| {
keys.values()
.map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid"))
.map(|s| {
ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid")
})
.map(|p| p.public())
.collect()
)
})
.unwrap_or_default()
}
@@ -254,24 +285,38 @@ impl SyncCryptoStore for KeyStore {
Some(seed) => {
let pair = ecdsa::Pair::from_string(seed, None)
.map_err(|_| Error::ValidationError("Generates an `ecdsa` pair.".to_owned()))?;
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), seed.into());
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), seed.into());
Ok(pair.public())
},
None => {
let (pair, phrase, _) = ecdsa::Pair::generate_with_phrase(None);
self.keys.write().entry(id).or_default().insert(pair.public().to_raw_vec(), phrase);
self.keys
.write()
.entry(id)
.or_default()
.insert(pair.public().to_raw_vec(), phrase);
Ok(pair.public())
}
},
}
}
fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> {
self.keys.write().entry(id).or_default().insert(public.to_owned(), suri.to_string());
self.keys
.write()
.entry(id)
.or_default()
.insert(public.to_owned(), suri.to_string());
Ok(())
}
fn has_keys(&self, public_keys: &[(Vec<u8>, KeyTypeId)]) -> bool {
public_keys.iter().all(|(k, t)| self.keys.read().get(&t).and_then(|s| s.get(k)).is_some())
public_keys
.iter()
.all(|(k, t)| self.keys.read().get(&t).and_then(|s| s.get(k)).is_some())
}
fn supported_keys(
@@ -295,24 +340,24 @@ impl SyncCryptoStore for KeyStore {
match key.0 {
ed25519::CRYPTO_ID => {
let key_pair = self
.ed25519_key_pair(id, &ed25519::Public::from_slice(key.1.as_slice()));
let key_pair =
self.ed25519_key_pair(id, &ed25519::Public::from_slice(key.1.as_slice()));
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
}
},
sr25519::CRYPTO_ID => {
let key_pair = self
.sr25519_key_pair(id, &sr25519::Public::from_slice(key.1.as_slice()));
let key_pair =
self.sr25519_key_pair(id, &sr25519::Public::from_slice(key.1.as_slice()));
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
}
},
ecdsa::CRYPTO_ID => {
let key_pair = self
.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice()));
let key_pair =
self.ecdsa_key_pair(id, &ecdsa::Public::from_slice(key.1.as_slice()));
key_pair.map(|k| k.sign(msg).encode()).map(Ok).transpose()
}
_ => Err(Error::KeyNotSupported(id))
},
_ => Err(Error::KeyNotSupported(id)),
}
}
@@ -323,17 +368,11 @@ impl SyncCryptoStore for KeyStore {
transcript_data: VRFTranscriptData,
) -> Result<Option<VRFSignature>, Error> {
let transcript = make_transcript(transcript_data);
let pair = if let Some(k) = self.sr25519_key_pair(key_type, public) {
k
} else {
return Ok(None)
};
let pair =
if let Some(k) = self.sr25519_key_pair(key_type, public) { k } else { return Ok(None) };
let (inout, proof, _) = pair.as_ref().vrf_sign(transcript);
Ok(Some(VRFSignature {
output: inout.to_output(),
proof,
}))
Ok(Some(VRFSignature { output: inout.to_output(), proof }))
}
fn ecdsa_sign_prehashed(
@@ -362,15 +401,18 @@ impl Into<Arc<dyn CryptoStore>> for KeyStore {
#[cfg(test)]
mod tests {
use super::*;
use sp_core::{sr25519, testing::{ED25519, SR25519, ECDSA}};
use crate::{SyncCryptoStore, vrf::VRFTranscriptValue};
use crate::{vrf::VRFTranscriptValue, SyncCryptoStore};
use sp_core::{
sr25519,
testing::{ECDSA, ED25519, SR25519},
};
#[test]
fn store_key_and_extract() {
let store = KeyStore::new();
let public = SyncCryptoStore::ed25519_generate_new(&store, ED25519, None)
.expect("Generates key");
let public =
SyncCryptoStore::ed25519_generate_new(&store, ED25519, None).expect("Generates key");
let public_keys = SyncCryptoStore::keys(&store, ED25519).unwrap();
@@ -384,12 +426,8 @@ mod tests {
let secret_uri = "//Alice";
let key_pair = sr25519::Pair::from_string(secret_uri, None).expect("Generates key pair");
SyncCryptoStore::insert_unknown(
&store,
SR25519,
secret_uri,
key_pair.public().as_ref(),
).expect("Inserts unknown key");
SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let public_keys = SyncCryptoStore::keys(&store, SR25519).unwrap();
@@ -409,7 +447,7 @@ mod tests {
("one", VRFTranscriptValue::U64(1)),
("two", VRFTranscriptValue::U64(2)),
("three", VRFTranscriptValue::Bytes("test".as_bytes().to_vec())),
]
],
};
let result = SyncCryptoStore::sr25519_vrf_sign(
@@ -420,19 +458,11 @@ mod tests {
);
assert!(result.unwrap().is_none());
SyncCryptoStore::insert_unknown(
&store,
SR25519,
secret_uri,
key_pair.public().as_ref(),
).expect("Inserts unknown key");
SyncCryptoStore::insert_unknown(&store, SR25519, secret_uri, key_pair.public().as_ref())
.expect("Inserts unknown key");
let result = SyncCryptoStore::sr25519_vrf_sign(
&store,
SR25519,
&key_pair.public(),
transcript_data,
);
let result =
SyncCryptoStore::sr25519_vrf_sign(&store, SR25519, &key_pair.public(), transcript_data);
assert!(result.unwrap().is_some());
}
@@ -445,16 +475,19 @@ mod tests {
let pair = ecdsa::Pair::from_string(suri, None).unwrap();
let msg = sp_core::keccak_256(b"this should be a hashed message");
// no key in key store
let res = SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
let res =
SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
assert!(res.is_none());
// insert key, sign again
let res = SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap();
let res =
SyncCryptoStore::insert_unknown(&store, ECDSA, suri, pair.public().as_ref()).unwrap();
assert_eq!((), res);
let res = SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
assert!(res.is_some());
let res =
SyncCryptoStore::ecdsa_sign_prehashed(&store, ECDSA, &pair.public(), &msg).unwrap();
assert!(res.is_some());
}
}
+3 -9
View File
@@ -59,21 +59,17 @@ pub fn make_transcript(data: VRFTranscriptData) -> Transcript {
},
VRFTranscriptValue::U64(val) => {
transcript.append_u64(label.as_bytes(), val);
}
},
}
}
transcript
}
#[cfg(test)]
mod tests {
use super::*;
use rand::RngCore;
use rand_chacha::{
rand_core::SeedableRng,
ChaChaRng,
};
use rand_chacha::{rand_core::SeedableRng, ChaChaRng};
#[test]
fn transcript_creation_matches() {
@@ -90,9 +86,7 @@ mod tests {
});
let test = |t: Transcript| -> [u8; 16] {
let mut b = [0u8; 16];
t.build_rng()
.finalize(&mut ChaChaRng::from_seed([0u8;32]))
.fill_bytes(&mut b);
t.build_rng().finalize(&mut ChaChaRng::from_seed([0u8; 32])).fill_bytes(&mut b);
b
};
debug_assert!(test(orig_transcript) == test(new_transcript));
@@ -18,8 +18,7 @@
//! Handling of blobs that may be compressed, based on an 8-byte magic identifier
//! at the head.
use std::borrow::Cow;
use std::io::Read;
use std::{borrow::Cow, io::Read};
// An arbitrary prefix, that indicates a blob beginning with should be decompressed with
// Zstd compression.
@@ -52,7 +51,7 @@ impl std::fmt::Display for Error {
}
}
impl std::error::Error for Error { }
impl std::error::Error for Error {}
fn read_from_decoder(
decoder: impl Read,
@@ -81,8 +80,8 @@ fn decompress_zstd(blob: &[u8], bomb_limit: usize) -> Result<Vec<u8>, Error> {
#[cfg(target_os = "unknown")]
fn decompress_zstd(mut blob: &[u8], bomb_limit: usize) -> Result<Vec<u8>, Error> {
let blob_len = blob.len();
let decoder = ruzstd::streaming_decoder::StreamingDecoder::new(&mut blob)
.map_err(|_| Error::Invalid)?;
let decoder =
ruzstd::streaming_decoder::StreamingDecoder::new(&mut blob).map_err(|_| Error::Invalid)?;
read_from_decoder(decoder, blob_len, bomb_limit)
}
@@ -105,7 +104,7 @@ pub fn compress(blob: &[u8], bomb_limit: usize) -> Option<Vec<u8>> {
use std::io::Write;
if blob.len() > bomb_limit {
return None;
return None
}
let mut buf = ZSTD_PREFIX.to_vec();
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Benchmarks of the phragmen election algorithm.
//! Note that execution times will not be accurate in an absolute scale, since
//! - Everything is executed in the context of `TestExternalities`
@@ -27,13 +26,12 @@ use test::Bencher;
use rand::{self, Rng};
use sp_npos_elections::{ElectionResult, VoteWeight};
use std::collections::BTreeMap;
use sp_runtime::{Perbill, PerThing, traits::Zero};
use sp_npos_elections::{
balance_solution, assignment_ratio_to_staked, to_support_map, to_without_backing, VoteWeight,
ExtendedBalance, Assignment, StakedAssignment, IdentifierT, assignment_ratio_to_staked,
seq_phragmen,
assignment_ratio_to_staked, balance_solution, seq_phragmen, to_support_map, to_without_backing,
Assignment, ExtendedBalance, IdentifierT, StakedAssignment, VoteWeight,
};
use sp_runtime::{traits::Zero, PerThing, Perbill};
use std::collections::BTreeMap;
// default params. Each will be scaled by the benchmarks individually.
const VALIDATORS: u64 = 100;
@@ -69,15 +67,13 @@ mod bench_closure_and_slice {
ratio
.into_iter()
.zip(stakes.into_iter().map(|x| *x as ExtendedBalance))
.map(|(a, stake)| {
a.into_staked(stake.into(), true)
})
.map(|(a, stake)| a.into_staked(stake.into(), true))
.collect()
}
#[bench]
fn closure(b: &mut Bencher) {
let assignments = (0..1000).map(|_| random_assignment()).collect::<Vec<Assignment<_ ,_>>>();
let assignments = (0..1000).map(|_| random_assignment()).collect::<Vec<Assignment<_, _>>>();
let stake_of = |x: &u32| -> VoteWeight { (x * 2 + 100).into() };
// each have one clone of assignments
@@ -86,7 +82,7 @@ mod bench_closure_and_slice {
#[bench]
fn slice(b: &mut Bencher) {
let assignments = (0..1000).map(|_| random_assignment()).collect::<Vec<Assignment<_ ,_>>>();
let assignments = (0..1000).map(|_| random_assignment()).collect::<Vec<Assignment<_, _>>>();
let stake_of = |x: &u32| -> VoteWeight { (x * 2 + 100).into() };
b.iter(|| {
@@ -112,20 +108,19 @@ fn do_phragmen(
let mut candidates = Vec::with_capacity(num_validators as usize);
let mut stake_of_tree: BTreeMap<AccountId, VoteWeight> = BTreeMap::new();
(1 ..= num_validators).for_each(|acc| {
(1..=num_validators).for_each(|acc| {
candidates.push(acc);
stake_of_tree.insert(acc, STAKE + rr(10, 1000));
});
let mut voters = Vec::with_capacity(num_nominators as usize);
(PREFIX ..= (PREFIX + num_nominators)).for_each(|acc| {
(PREFIX..=(PREFIX + num_nominators)).for_each(|acc| {
// all possible targets
let mut all_targets = candidates.clone();
// we remove and pop into `targets` `edge_per_voter` times.
let targets = (0 .. edge_per_voter).map(|_| {
all_targets.remove(rr(0, all_targets.len()) as usize)
})
.collect::<Vec<AccountId>>();
let targets = (0..edge_per_voter)
.map(|_| all_targets.remove(rr(0, all_targets.len()) as usize))
.collect::<Vec<AccountId>>();
let stake = STAKE + rr(10, 1000);
stake_of_tree.insert(acc, stake);
@@ -138,20 +133,16 @@ fn do_phragmen(
Zero::zero(),
candidates.clone(),
voters.clone(),
).unwrap();
)
.unwrap();
let stake_of = |who: &AccountId| -> VoteWeight {
*stake_of_tree.get(who).unwrap()
};
let stake_of = |who: &AccountId| -> VoteWeight { *stake_of_tree.get(who).unwrap() };
// Do the benchmarking with balancing.
if eq_iters > 0 {
let staked = assignment_ratio_to_staked(assignments, &stake_of);
let winners = to_without_backing(winners);
let mut support = to_support_map(
winners.as_ref(),
staked.as_ref(),
).unwrap();
let mut support = to_support_map(winners.as_ref(), staked.as_ref()).unwrap();
balance_solution(
staked.into_iter().map(|a| (a.clone(), stake_of(&a.who))).collect(),
@@ -46,25 +46,29 @@ pub(crate) fn from_impl(count: usize) -> TokenStream2 {
),)
};
let from_impl_rest = (3..=count).map(|c| {
let inner = (0..c-1).map(|i|
quote!((index_of_target(&distribution[#i].0).or_invalid_index()?, distribution[#i].1),)
).collect::<TokenStream2>();
let field_name = field_name_for(c);
let last_index = c - 1;
let last = quote!(index_of_target(&distribution[#last_index].0).or_invalid_index()?);
quote!(
#c => compact.#field_name.push(
(
index_of_voter(&who).or_invalid_index()?,
[#inner],
#last,
let from_impl_rest = (3..=count)
.map(|c| {
let inner = (0..c - 1)
.map(
|i| quote!((index_of_target(&distribution[#i].0).or_invalid_index()?, distribution[#i].1),),
)
),
)
}).collect::<TokenStream2>();
.collect::<TokenStream2>();
let field_name = field_name_for(c);
let last_index = c - 1;
let last = quote!(index_of_target(&distribution[#last_index].0).or_invalid_index()?);
quote!(
#c => compact.#field_name.push(
(
index_of_voter(&who).or_invalid_index()?,
[#inner],
#last,
)
),
)
})
.collect::<TokenStream2>();
quote!(
#from_impl_single
@@ -113,39 +117,41 @@ pub(crate) fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 {
)
};
let into_impl_rest = (3..=count).map(|c| {
let name = field_name_for(c);
quote!(
for (voter_index, inners, t_last_idx) in self.#name {
let mut sum = #per_thing::zero();
let mut inners_parsed = inners
.iter()
.map(|(ref t_idx, p)| {
sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p);
let target = target_at(*t_idx).or_invalid_index()?;
Ok((target, *p))
})
.collect::<Result<_npos::sp_std::prelude::Vec<(A, #per_thing)>, _npos::Error>>()?;
let into_impl_rest = (3..=count)
.map(|c| {
let name = field_name_for(c);
quote!(
for (voter_index, inners, t_last_idx) in self.#name {
let mut sum = #per_thing::zero();
let mut inners_parsed = inners
.iter()
.map(|(ref t_idx, p)| {
sum = _npos::sp_arithmetic::traits::Saturating::saturating_add(sum, *p);
let target = target_at(*t_idx).or_invalid_index()?;
Ok((target, *p))
})
.collect::<Result<_npos::sp_std::prelude::Vec<(A, #per_thing)>, _npos::Error>>()?;
if sum >= #per_thing::one() {
return Err(_npos::Error::CompactStakeOverflow);
if sum >= #per_thing::one() {
return Err(_npos::Error::CompactStakeOverflow);
}
// defensive only. Since Percent doesn't have `Sub`.
let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub(
#per_thing::one(),
sum,
);
inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last));
assignments.push(_npos::Assignment {
who: voter_at(voter_index).or_invalid_index()?,
distribution: inners_parsed,
});
}
// defensive only. Since Percent doesn't have `Sub`.
let p_last = _npos::sp_arithmetic::traits::Saturating::saturating_sub(
#per_thing::one(),
sum,
);
inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last));
assignments.push(_npos::Assignment {
who: voter_at(voter_index).or_invalid_index()?,
distribution: inners_parsed,
});
}
)
}).collect::<TokenStream2>();
)
})
.collect::<TokenStream2>();
quote!(
#into_impl_single
@@ -80,39 +80,42 @@ fn decode_impl(
}
};
let decode_impl_rest = (3..=count).map(|c| {
let name = field_name_for(c);
let decode_impl_rest = (3..=count)
.map(|c| {
let name = field_name_for(c);
let inner_impl = (0..c-1).map(|i|
quote! { ( (inner[#i].0).0, (inner[#i].1).0 ), }
).collect::<TokenStream2>();
let inner_impl = (0..c - 1)
.map(|i| quote! { ( (inner[#i].0).0, (inner[#i].1).0 ), })
.collect::<TokenStream2>();
quote! {
let #name =
<
_npos::sp_std::prelude::Vec<(
_npos::codec::Compact<#voter_type>,
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
_npos::codec::Compact<#target_type>,
)>
as _npos::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, inner, t_last)| (
v.0,
[ #inner_impl ],
t_last.0,
))
.collect::<_npos::sp_std::prelude::Vec<_>>();
}
}).collect::<TokenStream2>();
quote! {
let #name =
<
_npos::sp_std::prelude::Vec<(
_npos::codec::Compact<#voter_type>,
[(_npos::codec::Compact<#target_type>, _npos::codec::Compact<#weight_type>); #c-1],
_npos::codec::Compact<#target_type>,
)>
as _npos::codec::Decode
>::decode(value)?;
let #name = #name
.into_iter()
.map(|(v, inner, t_last)| (
v.0,
[ #inner_impl ],
t_last.0,
))
.collect::<_npos::sp_std::prelude::Vec<_>>();
}
})
.collect::<TokenStream2>();
let all_field_names = (1..=count).map(|c| {
let name = field_name_for(c);
quote! { #name, }
}).collect::<TokenStream2>();
let all_field_names = (1..=count)
.map(|c| {
let name = field_name_for(c);
quote! { #name, }
})
.collect::<TokenStream2>();
quote!(
impl _npos::codec::Decode for #ident {
@@ -165,29 +168,33 @@ fn encode_impl(ident: syn::Ident, count: usize) -> TokenStream2 {
}
};
let encode_impl_rest = (3..=count).map(|c| {
let name = field_name_for(c);
let encode_impl_rest = (3..=count)
.map(|c| {
let name = field_name_for(c);
// we use the knowledge of the length to avoid copy_from_slice.
let inners_compact_array = (0..c-1).map(|i|
quote!{(
_npos::codec::Compact(inner[#i].0.clone()),
_npos::codec::Compact(inner[#i].1.clone()),
),}
).collect::<TokenStream2>();
// we use the knowledge of the length to avoid copy_from_slice.
let inners_compact_array = (0..c - 1)
.map(|i| {
quote! {(
_npos::codec::Compact(inner[#i].0.clone()),
_npos::codec::Compact(inner[#i].1.clone()),
),}
})
.collect::<TokenStream2>();
quote! {
let #name = self.#name
.iter()
.map(|(v, inner, t_last)| (
_npos::codec::Compact(v.clone()),
[ #inners_compact_array ],
_npos::codec::Compact(t_last.clone()),
))
.collect::<_npos::sp_std::prelude::Vec<_>>();
#name.encode_to(&mut r);
}
}).collect::<TokenStream2>();
quote! {
let #name = self.#name
.iter()
.map(|(v, inner, t_last)| (
_npos::codec::Compact(v.clone()),
[ #inners_compact_array ],
_npos::codec::Compact(t_last.clone()),
))
.collect::<_npos::sp_std::prelude::Vec<_>>();
#name.encode_to(&mut r);
}
})
.collect::<TokenStream2>();
quote!(
impl _npos::codec::Encode for #ident {
@@ -65,7 +65,7 @@ pub(crate) fn from_impl(count: usize) -> TokenStream2 {
)
),
)
})
})
.collect::<TokenStream2>();
quote!(
@@ -18,7 +18,7 @@
//! Proc macro for a npos compact assignment.
use proc_macro::TokenStream;
use proc_macro2::{TokenStream as TokenStream2, Span, Ident};
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use proc_macro_crate::{crate_name, FoundCrate};
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
@@ -82,15 +82,8 @@ pub(crate) fn syn_err(message: &'static str) -> syn::Error {
/// ```
#[proc_macro]
pub fn generate_solution_type(item: TokenStream) -> TokenStream {
let SolutionDef {
vis,
ident,
count,
voter_type,
target_type,
weight_type,
compact_encoding,
} = syn::parse_macro_input!(item as SolutionDef);
let SolutionDef { vis, ident, count, voter_type, target_type, weight_type, compact_encoding } =
syn::parse_macro_input!(item as SolutionDef);
let imports = imports().unwrap_or_else(|e| e.to_compile_error());
@@ -102,7 +95,8 @@ pub fn generate_solution_type(item: TokenStream) -> TokenStream {
target_type.clone(),
weight_type.clone(),
compact_encoding,
).unwrap_or_else(|e| e.to_compile_error());
)
.unwrap_or_else(|e| e.to_compile_error());
quote!(
#imports
@@ -167,7 +161,7 @@ fn struct_def(
weight_type.clone(),
count,
);
quote!{
quote! {
#compact_impl
#[derive(Default, PartialEq, Eq, Clone, Debug, PartialOrd, Ord)]
}
@@ -321,23 +315,27 @@ fn remove_voter_impl(count: usize) -> TokenStream2 {
}
fn len_impl(count: usize) -> TokenStream2 {
(1..=count).map(|c| {
let field_name = field_name_for(c);
quote!(
all_len = all_len.saturating_add(self.#field_name.len());
)
}).collect::<TokenStream2>()
(1..=count)
.map(|c| {
let field_name = field_name_for(c);
quote!(
all_len = all_len.saturating_add(self.#field_name.len());
)
})
.collect::<TokenStream2>()
}
fn edge_count_impl(count: usize) -> TokenStream2 {
(1..=count).map(|c| {
let field_name = field_name_for(c);
quote!(
all_edges = all_edges.saturating_add(
self.#field_name.len().saturating_mul(#c as usize)
);
)
}).collect::<TokenStream2>()
(1..=count)
.map(|c| {
let field_name = field_name_for(c);
quote!(
all_edges = all_edges.saturating_add(
self.#field_name.len().saturating_mul(#c as usize)
);
)
})
.collect::<TokenStream2>()
}
fn unique_targets_impl(count: usize) -> TokenStream2 {
@@ -360,17 +358,19 @@ fn unique_targets_impl(count: usize) -> TokenStream2 {
}
};
let unique_targets_impl_rest = (3..=count).map(|c| {
let field_name = field_name_for(c);
quote! {
self.#field_name.iter().for_each(|(_, inners, t_last)| {
inners.iter().for_each(|(t, _)| {
maybe_insert_target(*t);
let unique_targets_impl_rest = (3..=count)
.map(|c| {
let field_name = field_name_for(c);
quote! {
self.#field_name.iter().for_each(|(_, inners, t_last)| {
inners.iter().for_each(|(t, _)| {
maybe_insert_target(*t);
});
maybe_insert_target(*t_last);
});
maybe_insert_target(*t_last);
});
}
}).collect::<TokenStream2>();
}
})
.collect::<TokenStream2>();
quote! {
#unique_targets_impl_single
@@ -440,23 +440,29 @@ impl Parse for SolutionDef {
let expected_types = ["VoterIndex", "TargetIndex", "Accuracy"];
let mut types: Vec<syn::Type> = generics.args.iter().zip(expected_types.iter()).map(|(t, expected)|
match t {
let mut types: Vec<syn::Type> = generics
.args
.iter()
.zip(expected_types.iter())
.map(|(t, expected)| match t {
syn::GenericArgument::Type(ty) => {
// this is now an error
Err(syn::Error::new_spanned(ty, format!("Expected binding: `{} = ...`", expected)))
Err(syn::Error::new_spanned(
ty,
format!("Expected binding: `{} = ...`", expected),
))
},
syn::GenericArgument::Binding(syn::Binding{ident, ty, ..}) => {
syn::GenericArgument::Binding(syn::Binding { ident, ty, .. }) => {
// check that we have the right keyword for this position in the argument list
if ident == expected {
Ok(ty.clone())
} else {
Err(syn::Error::new_spanned(ident, format!("Expected `{}`", expected)))
}
}
},
_ => Err(syn_err("Wrong type of generic provided. Must be a `type`.")),
}
).collect::<Result<_>>()?;
})
.collect::<Result<_>>()?;
let weight_type = types.pop().expect("Vector of length 3 can be popped; qed");
let target_type = types.pop().expect("Vector of length 2 can be popped; qed");
@@ -467,15 +473,15 @@ impl Parse for SolutionDef {
let expr = count_expr.expr;
let expr_lit = match *expr {
syn::Expr::Lit(count_lit) => count_lit.lit,
_ => return Err(syn_err("Count must be literal."))
_ => return Err(syn_err("Count must be literal.")),
};
let int_lit = match expr_lit {
syn::Lit::Int(int_lit) => int_lit,
_ => return Err(syn_err("Count must be int literal."))
_ => return Err(syn_err("Count must be int literal.")),
};
let count = int_lit.base10_parse::<usize>()?;
Ok(Self { vis, ident, voter_type, target_type, weight_type, count, compact_encoding } )
Ok(Self { vis, ident, voter_type, target_type, weight_type, count, compact_encoding })
}
}
@@ -62,11 +62,7 @@ pub fn generate_random_npos_inputs(
candidate_count: usize,
voter_count: usize,
mut rng: impl Rng,
) -> (
usize,
Vec<AccountId>,
Vec<(AccountId, VoteWeight, Vec<AccountId>)>,
) {
) -> (usize, Vec<AccountId>, Vec<(AccountId, VoteWeight, Vec<AccountId>)>) {
// cache for fast generation of unique candidate and voter ids
let mut used_ids = HashSet::with_capacity(candidate_count + voter_count);
@@ -1,6 +1,5 @@
use honggfuzz::fuzz;
use sp_npos_elections::generate_solution_type;
use sp_npos_elections::sp_arithmetic::Percent;
use sp_npos_elections::{generate_solution_type, sp_arithmetic::Percent};
use sp_runtime::codec::{Encode, Error};
fn main() {
@@ -26,9 +25,8 @@ fn main() {
// The reencoded value should definitely be decodable (if unwrap() fails that is a valid
// panic/finding for the fuzzer):
let decoded2: InnerTestSolutionCompact =
<InnerTestSolutionCompact as codec::Decode>::decode(
&mut reencoded.as_slice(),
).unwrap();
<InnerTestSolutionCompact as codec::Decode>::decode(&mut reencoded.as_slice())
.unwrap();
// And it should be equal to the original decoded object (resulting from directly
// decoding fuzzer_data):
assert_eq!(decoded, decoded2);

Some files were not shown because too many files have changed in this diff Show More