mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 23:11:04 +00:00
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:
@@ -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`.",
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: (B−1) × (B−1) + (B−1) + (B−1) = 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]
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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],);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
}],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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, ()>) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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![] }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
{
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
@@ -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());
|
||||
});
|
||||
|
||||
@@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user