Reorganising the repository - external renames and moves (#4074)

* Adding first rough ouline of the repository structure

* Remove old CI stuff

* add title

* formatting fixes

* move node-exits job's script to scripts dir

* Move docs into subdir

* move to bin

* move maintainence scripts, configs and helpers into its own dir

* add .local to ignore

* move core->client

* start up 'test' area

* move test client

* move test runtime

* make test move compile

* Add dependencies rule enforcement.

* Fix indexing.

* Update docs to reflect latest changes

* Moving /srml->/paint

* update docs

* move client/sr-* -> primitives/

* clean old readme

* remove old broken code in rhd

* update lock

* Step 1.

* starting to untangle client

* Fix after merge.

* start splitting out client interfaces

* move children and blockchain interfaces

* Move trie and state-machine to primitives.

* Fix WASM builds.

* fixing broken imports

* more interface moves

* move backend and light to interfaces

* move CallExecutor

* move cli off client

* moving around more interfaces

* re-add consensus crates into the mix

* fix subkey path

* relieve client from executor

* starting to pull out client from grandpa

* move is_decendent_of out of client

* grandpa still depends on client directly

* lemme tests pass

* rename srml->paint

* Make it compile.

* rename interfaces->client-api

* Move keyring to primitives.

* fixup libp2p dep

* fix broken use

* allow dependency enforcement to fail

* move fork-tree

* Moving wasm-builder

* make env

* move build-script-utils

* fixup broken crate depdencies and names

* fix imports for authority discovery

* fix typo

* update cargo.lock

* fixing imports

* Fix paths and add missing crates

* re-add missing crates
This commit is contained in:
Benjamin Kampmann
2019-11-14 21:51:17 +01:00
committed by Bastian Köcher
parent becc3b0a4f
commit 60e5011c72
809 changed files with 7801 additions and 6464 deletions
@@ -0,0 +1,166 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Provides some utilities to define a piecewise linear function.
use crate::{Perbill, traits::{SimpleArithmetic, SaturatedConversion}};
use core::ops::Sub;
/// Piecewise Linear function in [0, 1] -> [0, 1].
#[derive(PartialEq, Eq, primitives::RuntimeDebug)]
pub struct PiecewiseLinear<'a> {
/// Array of points. Must be in order from the lowest abscissas to the highest.
pub points: &'a [(Perbill, Perbill)],
/// The maximum value that can be returned.
pub maximum: Perbill,
}
fn abs_sub<N: Ord + Sub<Output=N> + Clone>(a: N, b: N) -> N where {
a.clone().max(b.clone()) - a.min(b)
}
impl<'a> PiecewiseLinear<'a> {
/// Compute `f(n/d)*d` with `n <= d`. This is useful to avoid loss of precision.
pub fn calculate_for_fraction_times_denominator<N>(&self, n: N, d: N) -> N where
N: SimpleArithmetic + Clone
{
let n = n.min(d.clone());
if self.points.len() == 0 {
return N::zero()
}
let next_point_index = self.points.iter()
.position(|p| n < p.0 * d.clone());
let (prev, next) = if let Some(next_point_index) = next_point_index {
if let Some(previous_point_index) = next_point_index.checked_sub(1) {
(self.points[previous_point_index], self.points[next_point_index])
} else {
// There is no previous points, take first point ordinate
return self.points.first().map(|p| p.1).unwrap_or_else(Perbill::zero) * d
}
} else {
// There is no next points, take last point ordinate
return self.points.last().map(|p| p.1).unwrap_or_else(Perbill::zero) * d
};
let delta_y = multiply_by_rational_saturating(
abs_sub(n.clone(), prev.0 * d.clone()),
abs_sub(next.1.deconstruct(), prev.1.deconstruct()),
// Must not saturate as prev abscissa > next abscissa
next.0.deconstruct().saturating_sub(prev.0.deconstruct()),
);
// If both substration are same sign then result is positive
if (n > prev.0 * d.clone()) == (next.1.deconstruct() > prev.1.deconstruct()) {
(prev.1 * d).saturating_add(delta_y)
// Otherwise result is negative
} else {
(prev.1 * d).saturating_sub(delta_y)
}
}
}
// Compute value * p / q.
// This is guaranteed not to overflow on whatever values nor lose precision.
// `q` must be superior to zero.
fn multiply_by_rational_saturating<N>(value: N, p: u32, q: u32) -> N
where N: SimpleArithmetic + Clone
{
let q = q.max(1);
// Mul can saturate if p > q
let result_divisor_part = (value.clone() / q.into()).saturating_mul(p.into());
let result_remainder_part = {
let rem = value % q.into();
// Fits into u32 because q is u32 and remainder < q
let rem_u32 = rem.saturated_into::<u32>();
// Multiplication fits into u64 as both term are u32
let rem_part = rem_u32 as u64 * p as u64 / q as u64;
// Can saturate if p > q
rem_part.saturated_into::<N>()
};
// Can saturate if p > q
result_divisor_part.saturating_add(result_remainder_part)
}
#[test]
fn test_multiply_by_rational_saturating() {
use std::convert::TryInto;
let div = 100u32;
for value in 0..=div {
for p in 0..=div {
for q in 1..=div {
let value: u64 = (value as u128 * u64::max_value() as u128 / div as u128)
.try_into().unwrap();
let p = (p as u64 * u32::max_value() as u64 / div as u64)
.try_into().unwrap();
let q = (q as u64 * u32::max_value() as u64 / div as u64)
.try_into().unwrap();
assert_eq!(
multiply_by_rational_saturating(value, p, q),
(value as u128 * p as u128 / q as u128)
.try_into().unwrap_or(u64::max_value())
);
}
}
}
}
#[test]
fn test_calculate_for_fraction_times_denominator() {
use std::convert::TryInto;
let curve = PiecewiseLinear {
points: &[
(Perbill::from_parts(0_000_000_000), Perbill::from_parts(0_500_000_000)),
(Perbill::from_parts(0_500_000_000), Perbill::from_parts(1_000_000_000)),
(Perbill::from_parts(1_000_000_000), Perbill::from_parts(0_000_000_000)),
],
maximum: Perbill::from_parts(1_000_000_000),
};
pub fn formal_calculate_for_fraction_times_denominator(n: u64, d: u64) -> u64 {
if n <= Perbill::from_parts(0_500_000_000) * d.clone() {
n + d / 2
} else {
(d as u128 * 2 - n as u128 * 2).try_into().unwrap()
}
}
let div = 100u32;
for d in 0..=div {
for n in 0..=d {
let d: u64 = (d as u128 * u64::max_value() as u128 / div as u128)
.try_into().unwrap();
let n: u64 = (n as u128 * u64::max_value() as u128 / div as u128)
.try_into().unwrap();
let res = curve.calculate_for_fraction_times_denominator(n, d);
let expected = formal_calculate_for_fraction_times_denominator(n, d);
assert!(abs_sub(res, expected) <= 1);
}
}
}
@@ -0,0 +1,112 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of a block and associated items.
#[cfg(feature = "std")]
use std::fmt;
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use rstd::prelude::*;
use primitives::RuntimeDebug;
use crate::codec::{Codec, Encode, Decode};
use crate::traits::{self, Member, Block as BlockT, Header as HeaderT, MaybeSerialize};
use crate::Justification;
/// Something to identify a block.
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub enum BlockId<Block: BlockT> {
/// Identify by block header hash.
Hash(<<Block as BlockT>::Header as HeaderT>::Hash),
/// Identify by block number.
Number(<<Block as BlockT>::Header as HeaderT>::Number),
}
impl<Block: BlockT> BlockId<Block> {
/// Create a block ID from a hash.
pub fn hash(hash: Block::Hash) -> Self {
BlockId::Hash(hash)
}
/// Create a block ID from a number.
pub fn number(number: <Block::Header as HeaderT>::Number) -> Self {
BlockId::Number(number)
}
}
impl<Block: BlockT> Copy for BlockId<Block> {}
#[cfg(feature = "std")]
impl<Block: BlockT> fmt::Display for BlockId<Block> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
/// Abstraction over a substrate block.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Block<Header, Extrinsic: MaybeSerialize> {
/// The block header.
pub header: Header,
/// The accompanying extrinsics.
pub extrinsics: Vec<Extrinsic>,
}
impl<Header, Extrinsic: MaybeSerialize> traits::Block for Block<Header, Extrinsic>
where
Header: HeaderT,
Extrinsic: Member + Codec + traits::Extrinsic,
{
type Extrinsic = Extrinsic;
type Header = Header;
type Hash = <Self::Header as traits::Header>::Hash;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.extrinsics[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.extrinsics)
}
fn new(header: Self::Header, extrinsics: Vec<Self::Extrinsic>) -> Self {
Block { header, extrinsics }
}
fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec<u8> {
(header, extrinsics).encode()
}
}
/// Abstraction over a substrate block and justification.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct SignedBlock<Block> {
/// Full block.
pub block: Block,
/// Block justification.
pub justification: Option<Justification>,
}
@@ -0,0 +1,98 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of an extrinsic that has passed the verification
//! stage.
use crate::traits::{
self, Member, MaybeDisplay, SignedExtension, Dispatchable,
};
#[allow(deprecated)]
use crate::traits::ValidateUnsigned;
use crate::weights::{GetDispatchInfo, DispatchInfo};
use crate::transaction_validity::TransactionValidity;
/// Definition of something that the external world might want to say; its
/// existence implies that it has been checked and is good, particularly with
/// regards to the signature.
#[derive(PartialEq, Eq, Clone, primitives::RuntimeDebug)]
pub struct CheckedExtrinsic<AccountId, Call, Extra> {
/// Who this purports to be from and the number of extrinsics have come before
/// from the same signer, if anyone (note this is not a signature).
pub signed: Option<(AccountId, Extra)>,
/// The function that should be called.
pub function: Call,
}
impl<AccountId, Call, Extra, Origin> traits::Applyable for
CheckedExtrinsic<AccountId, Call, Extra>
where
AccountId: Member + MaybeDisplay,
Call: Member + Dispatchable<Origin=Origin>,
Extra: SignedExtension<AccountId=AccountId, Call=Call>,
Origin: From<Option<AccountId>>,
{
type AccountId = AccountId;
type Call = Call;
fn sender(&self) -> Option<&Self::AccountId> {
self.signed.as_ref().map(|x| &x.0)
}
#[allow(deprecated)] // Allow ValidateUnsigned
fn validate<U: ValidateUnsigned<Call = Self::Call>>(
&self,
info: DispatchInfo,
len: usize,
) -> TransactionValidity {
if let Some((ref id, ref extra)) = self.signed {
Extra::validate(extra, id, &self.function, info, len)
} else {
let valid = Extra::validate_unsigned(&self.function, info, len)?;
let unsigned_validation = U::validate_unsigned(&self.function)?;
Ok(valid.combine_with(unsigned_validation))
}
}
#[allow(deprecated)] // Allow ValidateUnsigned
fn apply<U: ValidateUnsigned<Call=Self::Call>>(
self,
info: DispatchInfo,
len: usize,
) -> crate::ApplyResult {
let (maybe_who, pre) = if let Some((id, extra)) = self.signed {
let pre = Extra::pre_dispatch(extra, &id, &self.function, info, len)?;
(Some(id), pre)
} else {
let pre = Extra::pre_dispatch_unsigned(&self.function, info, len)?;
U::pre_dispatch(&self.function)?;
(None, pre)
};
let res = self.function.dispatch(Origin::from(maybe_who));
Extra::post_dispatch(pre, info, len);
Ok(res.map_err(Into::into))
}
}
impl<AccountId, Call, Extra> GetDispatchInfo for CheckedExtrinsic<AccountId, Call, Extra>
where
Call: GetDispatchInfo,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
@@ -0,0 +1,376 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of a digest.
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use rstd::prelude::*;
use crate::ConsensusEngineId;
use crate::codec::{Decode, Encode, Input, Error};
use primitives::RuntimeDebug;
/// Generic header digest.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Digest<Hash: Encode + Decode> {
/// A list of logs in the digest.
pub logs: Vec<DigestItem<Hash>>,
}
impl<Item: Encode + Decode> Default for Digest<Item> {
fn default() -> Self {
Digest { logs: Vec::new(), }
}
}
impl<Hash: Encode + Decode> Digest<Hash> {
/// Get reference to all digest items.
pub fn logs(&self) -> &[DigestItem<Hash>] {
&self.logs
}
/// Push new digest item.
pub fn push(&mut self, item: DigestItem<Hash>) {
self.logs.push(item);
}
/// Pop a digest item.
pub fn pop(&mut self) -> Option<DigestItem<Hash>> {
self.logs.pop()
}
/// Get reference to the first digest item that matches the passed predicate.
pub fn log<T: ?Sized, F: Fn(&DigestItem<Hash>) -> Option<&T>>(&self, predicate: F) -> Option<&T> {
self.logs().iter()
.filter_map(predicate)
.next()
}
/// Get a conversion of the first digest item that successfully converts using the function.
pub fn convert_first<T, F: Fn(&DigestItem<Hash>) -> Option<T>>(&self, predicate: F) -> Option<T> {
self.logs().iter()
.filter_map(predicate)
.next()
}
}
/// Digest item that is able to encode/decode 'system' digest items and
/// provide opaque access to other items.
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
pub enum DigestItem<Hash> {
/// System digest item that contains the root of changes trie at given
/// block. It is created for every block iff runtime supports changes
/// trie creation.
ChangesTrieRoot(Hash),
/// A pre-runtime digest.
///
/// These are messages from the consensus engine to the runtime, although
/// the consensus engine can (and should) read them itself to avoid
/// code and state duplication. It is erroneous for a runtime to produce
/// these, but this is not (yet) checked.
PreRuntime(ConsensusEngineId, Vec<u8>),
/// A message from the runtime to the consensus engine. This should *never*
/// be generated by the native code of any consensus engine, but this is not
/// checked (yet).
Consensus(ConsensusEngineId, Vec<u8>),
/// Put a Seal on it. This is only used by native code, and is never seen
/// by runtimes.
Seal(ConsensusEngineId, Vec<u8>),
/// Some other thing. Unsupported and experimental.
Other(Vec<u8>),
}
#[cfg(feature = "std")]
impl<Hash: Encode> serde::Serialize for DigestItem<Hash> {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
self.using_encoded(|bytes| {
primitives::bytes::serialize(bytes, seq)
})
}
}
#[cfg(feature = "std")]
impl<'a, Hash: Decode> serde::Deserialize<'a> for DigestItem<Hash> {
fn deserialize<D>(de: D) -> Result<Self, D::Error> where
D: serde::Deserializer<'a>,
{
let r = primitives::bytes::deserialize(de)?;
Decode::decode(&mut &r[..])
.map_err(|e| serde::de::Error::custom(format!("Decode error: {}", e)))
}
}
/// A 'referencing view' for digest item. Does not own its contents. Used by
/// final runtime implementations for encoding/decoding its log items.
#[derive(PartialEq, Eq, Clone, RuntimeDebug)]
pub enum DigestItemRef<'a, Hash: 'a> {
/// Reference to `DigestItem::ChangesTrieRoot`.
ChangesTrieRoot(&'a Hash),
/// A pre-runtime digest.
///
/// These are messages from the consensus engine to the runtime, although
/// the consensus engine can (and should) read them itself to avoid
/// code and state duplication. It is erroneous for a runtime to produce
/// these, but this is not (yet) checked.
PreRuntime(&'a ConsensusEngineId, &'a Vec<u8>),
/// A message from the runtime to the consensus engine. This should *never*
/// be generated by the native code of any consensus engine, but this is not
/// checked (yet).
Consensus(&'a ConsensusEngineId, &'a Vec<u8>),
/// Put a Seal on it. This is only used by native code, and is never seen
/// by runtimes.
Seal(&'a ConsensusEngineId, &'a Vec<u8>),
/// Any 'non-system' digest item, opaque to the native code.
Other(&'a Vec<u8>),
}
/// Type of the digest item. Used to gain explicit control over `DigestItem` encoding
/// process. We need an explicit control, because final runtimes are encoding their own
/// digest items using `DigestItemRef` type and we can't auto-derive `Decode`
/// trait for `DigestItemRef`.
#[repr(u32)]
#[derive(Encode, Decode)]
pub enum DigestItemType {
ChangesTrieRoot = 2,
PreRuntime = 6,
Consensus = 4,
Seal = 5,
Other = 0,
}
/// Type of a digest item that contains raw data; this also names the consensus engine ID where
/// applicable. Used to identify one or more digest items of interest.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum OpaqueDigestItemId<'a> {
/// Type corresponding to DigestItem::PreRuntime.
PreRuntime(&'a ConsensusEngineId),
/// Type corresponding to DigestItem::Consensus.
Consensus(&'a ConsensusEngineId),
/// Type corresponding to DigestItem::Seal.
Seal(&'a ConsensusEngineId),
/// Some other (non-prescribed) type.
Other,
}
impl<Hash> DigestItem<Hash> {
/// Returns a 'referencing view' for this digest item.
pub fn dref<'a>(&'a self) -> DigestItemRef<'a, Hash> {
match *self {
DigestItem::ChangesTrieRoot(ref v) => DigestItemRef::ChangesTrieRoot(v),
DigestItem::PreRuntime(ref v, ref s) => DigestItemRef::PreRuntime(v, s),
DigestItem::Consensus(ref v, ref s) => DigestItemRef::Consensus(v, s),
DigestItem::Seal(ref v, ref s) => DigestItemRef::Seal(v, s),
DigestItem::Other(ref v) => DigestItemRef::Other(v),
}
}
/// Returns `Some` if the entry is the `ChangesTrieRoot` entry.
pub fn as_changes_trie_root(&self) -> Option<&Hash> {
self.dref().as_changes_trie_root()
}
/// Returns `Some` if this entry is the `PreRuntime` entry.
pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &[u8])> {
self.dref().as_pre_runtime()
}
/// Returns `Some` if this entry is the `Consensus` entry.
pub fn as_consensus(&self) -> Option<(ConsensusEngineId, &[u8])> {
self.dref().as_consensus()
}
/// Returns `Some` if this entry is the `Seal` entry.
pub fn as_seal(&self) -> Option<(ConsensusEngineId, &[u8])> {
self.dref().as_seal()
}
/// Returns Some if `self` is a `DigestItem::Other`.
pub fn as_other(&self) -> Option<&[u8]> {
match *self {
DigestItem::Other(ref v) => Some(&v[..]),
_ => None,
}
}
/// Returns the opaque data contained in the item if `Some` if this entry has the id given.
pub fn try_as_raw(&self, id: OpaqueDigestItemId) -> Option<&[u8]> {
self.dref().try_as_raw(id)
}
/// Returns the data contained in the item if `Some` if this entry has the id given, decoded
/// to the type provided `T`.
pub fn try_to<T: Decode>(&self, id: OpaqueDigestItemId) -> Option<T> {
self.dref().try_to::<T>(id)
}
}
impl<Hash: Encode> Encode for DigestItem<Hash> {
fn encode(&self) -> Vec<u8> {
self.dref().encode()
}
}
impl<Hash: Encode> codec::EncodeLike for DigestItem<Hash> {}
impl<Hash: Decode> Decode for DigestItem<Hash> {
#[allow(deprecated)]
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
let item_type: DigestItemType = Decode::decode(input)?;
match item_type {
DigestItemType::ChangesTrieRoot => Ok(DigestItem::ChangesTrieRoot(
Decode::decode(input)?,
)),
DigestItemType::PreRuntime => {
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
Ok(DigestItem::PreRuntime(vals.0, vals.1))
},
DigestItemType::Consensus => {
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
Ok(DigestItem::Consensus(vals.0, vals.1))
}
DigestItemType::Seal => {
let vals: (ConsensusEngineId, Vec<u8>) = Decode::decode(input)?;
Ok(DigestItem::Seal(vals.0, vals.1))
},
DigestItemType::Other => Ok(DigestItem::Other(
Decode::decode(input)?,
)),
}
}
}
impl<'a, Hash> DigestItemRef<'a, Hash> {
/// Cast this digest item into `ChangesTrieRoot`.
pub fn as_changes_trie_root(&self) -> Option<&'a Hash> {
match *self {
DigestItemRef::ChangesTrieRoot(ref changes_trie_root) => Some(changes_trie_root),
_ => None,
}
}
/// Cast this digest item into `PreRuntime`
pub fn as_pre_runtime(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
match *self {
DigestItemRef::PreRuntime(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
_ => None,
}
}
/// Cast this digest item into `Consensus`
pub fn as_consensus(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
match *self {
DigestItemRef::Consensus(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
_ => None,
}
}
/// Cast this digest item into `Seal`
pub fn as_seal(&self) -> Option<(ConsensusEngineId, &'a [u8])> {
match *self {
DigestItemRef::Seal(consensus_engine_id, ref data) => Some((*consensus_engine_id, data)),
_ => None,
}
}
/// Cast this digest item into `PreRuntime`
pub fn as_other(&self) -> Option<&'a [u8]> {
match *self {
DigestItemRef::Other(ref data) => Some(data),
_ => None,
}
}
/// Try to match this digest item to the given opaque item identifier; if it matches, then
/// return the opaque data it contains.
pub fn try_as_raw(&self, id: OpaqueDigestItemId) -> Option<&'a [u8]> {
match (id, self) {
(OpaqueDigestItemId::Consensus(w), &DigestItemRef::Consensus(v, s)) |
(OpaqueDigestItemId::Seal(w), &DigestItemRef::Seal(v, s)) |
(OpaqueDigestItemId::PreRuntime(w), &DigestItemRef::PreRuntime(v, s))
if v == w => Some(&s[..]),
(OpaqueDigestItemId::Other, &DigestItemRef::Other(s)) => Some(&s[..]),
_ => None,
}
}
/// Try to match this digest item to the given opaque item identifier; if it matches, then
/// try to cast to the given datatype; if that works, return it.
pub fn try_to<T: Decode>(&self, id: OpaqueDigestItemId) -> Option<T> {
self.try_as_raw(id).and_then(|mut x| Decode::decode(&mut x).ok())
}
}
impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> {
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
match *self {
DigestItemRef::ChangesTrieRoot(changes_trie_root) => {
DigestItemType::ChangesTrieRoot.encode_to(&mut v);
changes_trie_root.encode_to(&mut v);
},
DigestItemRef::Consensus(val, data) => {
DigestItemType::Consensus.encode_to(&mut v);
(val, data).encode_to(&mut v);
},
DigestItemRef::Seal(val, sig) => {
DigestItemType::Seal.encode_to(&mut v);
(val, sig).encode_to(&mut v);
},
DigestItemRef::PreRuntime(val, data) => {
DigestItemType::PreRuntime.encode_to(&mut v);
(val, data).encode_to(&mut v);
},
DigestItemRef::Other(val) => {
DigestItemType::Other.encode_to(&mut v);
val.encode_to(&mut v);
},
}
v
}
}
impl<'a, Hash: Encode> codec::EncodeLike for DigestItemRef<'a, Hash> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_serialize_digest() {
let digest = Digest {
logs: vec![
DigestItem::ChangesTrieRoot(4),
DigestItem::Other(vec![1, 2, 3]),
DigestItem::Seal(*b"test", vec![1, 2, 3])
],
};
assert_eq!(
::serde_json::to_string(&digest).unwrap(),
r#"{"logs":["0x0204000000","0x000c010203","0x05746573740c010203"]}"#
);
}
}
@@ -0,0 +1,206 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of an unchecked (pre-verification) extrinsic.
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use crate::codec::{Decode, Encode, Input, Output, Error};
/// Era period
pub type Period = u64;
/// Era phase
pub type Phase = u64;
/// An era to describe the longevity of a transaction.
#[derive(PartialEq, Eq, Clone, Copy, primitives::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Era {
/// The transaction is valid forever. The genesis hash must be present in the signed content.
Immortal,
/// Period and phase are encoded:
/// - The period of validity from the block hash found in the signing material.
/// - The phase in the period that this transaction's lifetime begins (and, importantly,
/// implies which block hash is included in the signature material). If the `period` is
/// greater than 1 << 12, then it will be a factor of the times greater than 1<<12 that
/// `period` is.
Mortal(Period, Phase),
}
/*
E.g. with period == 4:
0 10 20 30 40
0123456789012345678901234567890123456789012
|...|
authored -/ \- expiry
phase = 1
n = Q(current - phase, period) + phase
*/
impl Era {
/// Create a new era based on a period (which should be a power of two between 4 and 65536 inclusive)
/// and a block number on which it should start (or, for long periods, be shortly after the start).
pub fn mortal(period: u64, current: u64) -> Self {
let period = period.checked_next_power_of_two()
.unwrap_or(1 << 16)
.max(4)
.min(1 << 16);
let phase = current % period;
let quantize_factor = (period >> 12).max(1);
let quantized_phase = phase / quantize_factor * quantize_factor;
Era::Mortal(period, quantized_phase)
}
/// Create an "immortal" transaction.
pub fn immortal() -> Self {
Era::Immortal
}
/// `true` if this is an immortal transaction.
pub fn is_immortal(&self) -> bool {
match self {
Era::Immortal => true,
_ => false,
}
}
/// Get the block number of the start of the era whose properties this object
/// describes that `current` belongs to.
pub fn birth(self, current: u64) -> u64 {
match self {
Era::Immortal => 0,
Era::Mortal(period, phase) => (current.max(phase) - phase) / period * period + phase,
}
}
/// Get the block number of the first block at which the era has ended.
pub fn death(self, current: u64) -> u64 {
match self {
Era::Immortal => u64::max_value(),
Era::Mortal(period, _) => self.birth(current) + period,
}
}
}
impl Encode for Era {
fn encode_to<T: Output>(&self, output: &mut T) {
match self {
Era::Immortal => output.push_byte(0),
Era::Mortal(period, phase) => {
let quantize_factor = (*period as u64 >> 12).max(1);
let encoded = (period.trailing_zeros() - 1).max(1).min(15) as u16 | ((phase / quantize_factor) << 4) as u16;
output.push(&encoded);
}
}
}
}
impl codec::EncodeLike for Era {}
impl Decode for Era {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
let first = input.read_byte()?;
if first == 0 {
Ok(Era::Immortal)
} else {
let encoded = first as u64 + ((input.read_byte()? as u64) << 8);
let period = 2 << (encoded % (1 << 4));
let quantize_factor = (period >> 12).max(1);
let phase = (encoded >> 4) * quantize_factor;
if period >= 4 && phase < period {
Ok(Era::Mortal(period, phase))
} else {
Err("Invalid period and phase".into())
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn immortal_works() {
let e = Era::immortal();
assert_eq!(e.birth(0), 0);
assert_eq!(e.death(0), u64::max_value());
assert_eq!(e.birth(1), 0);
assert_eq!(e.death(1), u64::max_value());
assert_eq!(e.birth(u64::max_value()), 0);
assert_eq!(e.death(u64::max_value()), u64::max_value());
assert!(e.is_immortal());
assert_eq!(e.encode(), vec![0u8]);
assert_eq!(e, Era::decode(&mut&[0u8][..]).unwrap());
}
#[test]
fn mortal_codec_works() {
let e = Era::mortal(64, 42);
assert!(!e.is_immortal());
let expected = vec![5 + 42 % 16 * 16, 42 / 16];
assert_eq!(e.encode(), expected);
assert_eq!(e, Era::decode(&mut&expected[..]).unwrap());
}
#[test]
fn long_period_mortal_codec_works() {
let e = Era::mortal(32768, 20000);
let expected = vec![(14 + 2500 % 16 * 16) as u8, (2500 / 16) as u8];
assert_eq!(e.encode(), expected);
assert_eq!(e, Era::decode(&mut&expected[..]).unwrap());
}
#[test]
fn era_initialization_works() {
assert_eq!(Era::mortal(64, 42), Era::Mortal(64, 42));
assert_eq!(Era::mortal(32768, 20000), Era::Mortal(32768, 20000));
assert_eq!(Era::mortal(200, 513), Era::Mortal(256, 1));
assert_eq!(Era::mortal(2, 1), Era::Mortal(4, 1));
assert_eq!(Era::mortal(4, 5), Era::Mortal(4, 1));
}
#[test]
fn quantized_clamped_era_initialization_works() {
// clamp 1000000 to 65536, quantize 1000001 % 65536 to the nearest 4
assert_eq!(Era::mortal(1000000, 1000001), Era::Mortal(65536, 1000001 % 65536 / 4 * 4));
}
#[test]
fn mortal_birth_death_works() {
let e = Era::mortal(4, 6);
for i in 6..10 {
assert_eq!(e.birth(i), 6);
assert_eq!(e.death(i), 10);
}
// wrong because it's outside of the (current...current + period) range
assert_ne!(e.birth(10), 6);
assert_ne!(e.birth(5), 6);
}
#[test]
fn current_less_than_phase() {
// should not panic
Era::mortal(4, 3).birth(1);
}
}
@@ -0,0 +1,199 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of a block header.
#[cfg(feature = "std")]
use serde::{Deserialize, Serialize};
use crate::codec::{Decode, Encode, Codec, Input, Output, HasCompact, EncodeAsRef, Error};
use crate::traits::{
self, Member, SimpleArithmetic, SimpleBitOps, Hash as HashT,
MaybeSerializeDeserialize, MaybeSerialize, MaybeDisplay,
};
use crate::generic::Digest;
use primitives::U256;
use rstd::{
convert::TryFrom,
fmt::Debug,
};
/// Abstraction over a block header for a substrate chain.
#[derive(PartialEq, Eq, Clone, primitives::RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header<Number: Copy + Into<U256> + TryFrom<U256>, Hash: HashT> {
/// The parent hash.
pub parent_hash: Hash::Output,
/// The block number.
#[cfg_attr(feature = "std", serde(
serialize_with = "serialize_number",
deserialize_with = "deserialize_number"))]
pub number: Number,
/// The state trie merkle root
pub state_root: Hash::Output,
/// The merkle root of the extrinsics.
pub extrinsics_root: Hash::Output,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest<Hash::Output>,
}
#[cfg(feature = "std")]
pub fn serialize_number<S, T: Copy + Into<U256> + TryFrom<U256>>(
val: &T, s: S,
) -> Result<S::Ok, S::Error> where S: serde::Serializer {
let u256: U256 = (*val).into();
serde::Serialize::serialize(&u256, s)
}
#[cfg(feature = "std")]
pub fn deserialize_number<'a, D, T: Copy + Into<U256> + TryFrom<U256>>(
d: D,
) -> Result<T, D::Error> where D: serde::Deserializer<'a> {
let u256: U256 = serde::Deserialize::deserialize(d)?;
TryFrom::try_from(u256).map_err(|_| serde::de::Error::custom("Try from failed"))
}
impl<Number, Hash> Decode for Header<Number, Hash> where
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Decode,
{
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
Ok(Header {
parent_hash: Decode::decode(input)?,
number: <<Number as HasCompact>::Type>::decode(input)?.into(),
state_root: Decode::decode(input)?,
extrinsics_root: Decode::decode(input)?,
digest: Decode::decode(input)?,
})
}
}
impl<Number, Hash> Encode for Header<Number, Hash> where
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Encode,
{
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.parent_hash);
dest.push(&<<<Number as HasCompact>::Type as EncodeAsRef<_>>::RefType>::from(&self.number));
dest.push(&self.state_root);
dest.push(&self.extrinsics_root);
dest.push(&self.digest);
}
}
impl<Number, Hash> codec::EncodeLike for Header<Number, Hash> where
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Encode,
{}
impl<Number, Hash> traits::Header for Header<Number, Hash> where
Number: Member + MaybeSerializeDeserialize + Debug + rstd::hash::Hash + MaybeDisplay +
SimpleArithmetic + Codec + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Default + rstd::hash::Hash + Copy + Member +
MaybeSerialize + Debug + MaybeDisplay + SimpleBitOps + Codec,
{
type Number = Number;
type Hash = <Hash as HashT>::Output;
type Hashing = Hash;
fn number(&self) -> &Self::Number { &self.number }
fn set_number(&mut self, num: Self::Number) { self.number = num }
fn extrinsics_root(&self) -> &Self::Hash { &self.extrinsics_root }
fn set_extrinsics_root(&mut self, root: Self::Hash) { self.extrinsics_root = root }
fn state_root(&self) -> &Self::Hash { &self.state_root }
fn set_state_root(&mut self, root: Self::Hash) { self.state_root = root }
fn parent_hash(&self) -> &Self::Hash { &self.parent_hash }
fn set_parent_hash(&mut self, hash: Self::Hash) { self.parent_hash = hash }
fn digest(&self) -> &Digest<Self::Hash> { &self.digest }
fn digest_mut(&mut self) -> &mut Digest<Self::Hash> {
#[cfg(feature = "std")]
log::debug!(target: "header", "Retrieving mutable reference to digest");
&mut self.digest
}
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Digest<Self::Hash>,
) -> Self {
Header {
number,
extrinsics_root,
state_root,
parent_hash,
digest,
}
}
}
impl<Number, Hash> Header<Number, Hash> where
Number: Member + rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Default + rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec,
{
/// Convenience helper for computing the hash of the header without having
/// to import the trait.
pub fn hash(&self) -> Hash::Output {
Hash::hash_of(self)
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn should_serialize_numbers() {
fn serialize(num: u128) -> String {
let mut v = vec![];
{
let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v));
serialize_number(&num, &mut ser).unwrap();
}
String::from_utf8(v).unwrap()
}
assert_eq!(serialize(0), "\"0x0\"".to_owned());
assert_eq!(serialize(1), "\"0x1\"".to_owned());
assert_eq!(serialize(u64::max_value() as u128), "\"0xffffffffffffffff\"".to_owned());
assert_eq!(serialize(u64::max_value() as u128 + 1), "\"0x10000000000000000\"".to_owned());
}
#[test]
fn should_deserialize_number() {
fn deserialize(num: &str) -> u128 {
let mut der = serde_json::Deserializer::new(serde_json::de::StrRead::new(num));
deserialize_number(&mut der).unwrap()
}
assert_eq!(deserialize("\"0x0\""), 0);
assert_eq!(deserialize("\"0x1\""), 1);
assert_eq!(deserialize("\"0xffffffffffffffff\""), u64::max_value() as u128);
assert_eq!(deserialize("\"0x10000000000000000\""), u64::max_value() as u128 + 1);
}
}
@@ -0,0 +1,62 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
// tag::description[]
//! Generic implementations of Extrinsic/Header/Block.
// end::description[]
mod unchecked_extrinsic;
mod era;
mod checked_extrinsic;
mod header;
mod block;
mod digest;
#[cfg(test)]
mod tests;
pub use self::unchecked_extrinsic::{UncheckedExtrinsic, SignedPayload};
pub use self::era::{Era, Phase};
pub use self::checked_extrinsic::CheckedExtrinsic;
pub use self::header::Header;
pub use self::block::{Block, SignedBlock, BlockId};
pub use self::digest::{
Digest, DigestItem, DigestItemRef, OpaqueDigestItemId
};
use crate::codec::Encode;
use rstd::prelude::*;
fn encode_with_vec_prefix<T: Encode, F: Fn(&mut Vec<u8>)>(encoder: F) -> Vec<u8> {
let size = ::rstd::mem::size_of::<T>();
let reserve = match size {
0..=0b00111111 => 1,
0..=0b00111111_11111111 => 2,
_ => 4,
};
let mut v = Vec::with_capacity(reserve + size);
v.resize(reserve, 0);
encoder(&mut v);
// need to prefix with the total length to ensure it's binary compatible with
// Vec<u8>.
let mut length: Vec<()> = Vec::new();
length.resize(v.len() - reserve, ());
length.using_encoded(|s| {
v.splice(0..reserve, s.iter().cloned());
});
v
}
@@ -0,0 +1,60 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Tests for the generic implementations of Extrinsic/Header/Block.
use crate::codec::{Decode, Encode};
use primitives::H256;
use super::DigestItem;
#[test]
fn system_digest_item_encoding() {
let item = DigestItem::ChangesTrieRoot::<H256>(H256::default());
let encoded = item.encode();
assert_eq!(encoded, vec![
// type = DigestItemType::ChangesTrieRoot
2,
// trie root
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, 0,
]);
let decoded: DigestItem<H256> = Decode::decode(&mut &encoded[..]).unwrap();
assert_eq!(item, decoded);
}
#[test]
fn non_system_digest_item_encoding() {
let item = DigestItem::Other::<H256>(vec![10, 20, 30]);
let encoded = item.encode();
assert_eq!(encoded, vec![
// type = DigestItemType::Other
0,
// length of other data
12,
// authorities
10, 20, 30,
]);
let decoded: DigestItem<H256> = Decode::decode(&mut &encoded[..]).unwrap();
assert_eq!(item, decoded);
}
@@ -0,0 +1,420 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementation of an unchecked (pre-verification) extrinsic.
use rstd::{fmt, prelude::*};
use runtime_io::hashing::blake2_256;
use codec::{Decode, Encode, EncodeLike, Input, Error};
use crate::{
traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount},
generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction},
weights::{GetDispatchInfo, DispatchInfo},
};
const TRANSACTION_VERSION: u8 = 4;
/// A extrinsic right from the external world. This is unchecked and so
/// can contain a signature.
#[derive(PartialEq, Eq, Clone)]
pub struct UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Extra: SignedExtension
{
/// The signature, address, number of extrinsics have come before from
/// the same signer and an era describing the longevity of this transaction,
/// if this is a signed extrinsic.
pub signature: Option<(Address, Signature, Extra)>,
/// The function that should be called.
pub function: Call,
}
impl<Address, Call, Signature, Extra: SignedExtension>
UncheckedExtrinsic<Address, Call, Signature, Extra>
{
/// New instance of a signed extrinsic aka "transaction".
pub fn new_signed(
function: Call,
signed: Address,
signature: Signature,
extra: Extra
) -> Self {
UncheckedExtrinsic {
signature: Some((signed, signature, extra)),
function,
}
}
/// New instance of an unsigned extrinsic aka "inherent".
pub fn new_unsigned(function: Call) -> Self {
UncheckedExtrinsic {
signature: None,
function,
}
}
}
impl<Address, Call, Signature, Extra: SignedExtension> Extrinsic
for UncheckedExtrinsic<Address, Call, Signature, Extra>
{
type Call = Call;
type SignaturePayload = (
Address,
Signature,
Extra,
);
fn is_signed(&self) -> Option<bool> {
Some(self.signature.is_some())
}
fn new(function: Call, signed_data: Option<Self::SignaturePayload>) -> Option<Self> {
Some(if let Some((address, signature, extra)) = signed_data {
UncheckedExtrinsic::new_signed(function, address, signature, extra)
} else {
UncheckedExtrinsic::new_unsigned(function)
})
}
}
impl<Address, AccountId, Call, Signature, Extra, Lookup>
Checkable<Lookup>
for
UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Address: Member + MaybeDisplay,
Call: Encode + Member,
Signature: Member + traits::Verify,
<Signature as traits::Verify>::Signer: IdentifyAccount<AccountId=AccountId>,
Extra: SignedExtension<AccountId=AccountId>,
AccountId: Member + MaybeDisplay,
Lookup: traits::Lookup<Source=Address, Target=AccountId>,
{
type Checked = CheckedExtrinsic<AccountId, Call, Extra>;
fn check(self, lookup: &Lookup) -> Result<Self::Checked, TransactionValidityError> {
Ok(match self.signature {
Some((signed, signature, extra)) => {
let signed = lookup.lookup(signed)?;
let raw_payload = SignedPayload::new(self.function, extra)?;
if !raw_payload.using_encoded(|payload| {
signature.verify(payload, &signed)
}) {
return Err(InvalidTransaction::BadProof.into())
}
let (function, extra, _) = raw_payload.deconstruct();
CheckedExtrinsic {
signed: Some((signed, extra)),
function,
}
}
None => CheckedExtrinsic {
signed: None,
function: self.function,
},
})
}
}
/// A payload that has been signed for an unchecked extrinsics.
///
/// Note that the payload that we sign to produce unchecked extrinsic signature
/// is going to be different than the `SignaturePayload` - so the thing the extrinsic
/// actually contains.
pub struct SignedPayload<Call, Extra: SignedExtension>((
Call,
Extra,
Extra::AdditionalSigned,
));
impl<Call, Extra> SignedPayload<Call, Extra> where
Call: Encode,
Extra: SignedExtension,
{
/// Create new `SignedPayload`.
///
/// This function may fail if `additional_signed` of `Extra` is not available.
pub fn new(call: Call, extra: Extra) -> Result<Self, TransactionValidityError> {
let additional_signed = extra.additional_signed()?;
let raw_payload = (call, extra, additional_signed);
Ok(Self(raw_payload))
}
/// Create new `SignedPayload` from raw components.
pub fn from_raw(call: Call, extra: Extra, additional_signed: Extra::AdditionalSigned) -> Self {
Self((call, extra, additional_signed))
}
/// Deconstruct the payload into it's components.
pub fn deconstruct(self) -> (Call, Extra, Extra::AdditionalSigned) {
self.0
}
}
impl<Call, Extra> Encode for SignedPayload<Call, Extra> where
Call: Encode,
Extra: SignedExtension,
{
/// Get an encoded version of this payload.
///
/// Payloads longer than 256 bytes are going to be `blake2_256`-hashed.
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(|payload| {
if payload.len() > 256 {
f(&blake2_256(payload)[..])
} else {
f(payload)
}
})
}
}
impl<Call, Extra> EncodeLike for SignedPayload<Call, Extra>
where
Call: Encode,
Extra: SignedExtension,
{}
impl<Address, Call, Signature, Extra> Decode
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Address: Decode,
Signature: Decode,
Call: Decode,
Extra: SignedExtension,
{
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
// This is a little more complicated than usual since the binary format must be compatible
// with substrate's generic `Vec<u8>` type. Basically this just means accepting that there
// will be a prefix of vector length (we don't need
// to use this).
let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?;
let version = input.read_byte()?;
let is_signed = version & 0b1000_0000 != 0;
let version = version & 0b0111_1111;
if version != TRANSACTION_VERSION {
return Err("Invalid transaction version".into());
}
Ok(UncheckedExtrinsic {
signature: if is_signed { Some(Decode::decode(input)?) } else { None },
function: Decode::decode(input)?,
})
}
}
impl<Address, Call, Signature, Extra> Encode
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Address: Encode,
Signature: Encode,
Call: Encode,
Extra: SignedExtension,
{
fn encode(&self) -> Vec<u8> {
super::encode_with_vec_prefix::<Self, _>(|v| {
// 1 byte version id.
match self.signature.as_ref() {
Some(s) => {
v.push(TRANSACTION_VERSION | 0b1000_0000);
s.encode_to(v);
}
None => {
v.push(TRANSACTION_VERSION & 0b0111_1111);
}
}
self.function.encode_to(v);
})
}
}
impl<Address, Call, Signature, Extra> EncodeLike
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Address: Encode,
Signature: Encode,
Call: Encode,
Extra: SignedExtension,
{}
#[cfg(feature = "std")]
impl<Address: Encode, Signature: Encode, Call: Encode, Extra: SignedExtension> serde::Serialize
for UncheckedExtrinsic<Address, Call, Signature, Extra>
{
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
}
}
impl<Address, Call, Signature, Extra> fmt::Debug
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Address: fmt::Debug,
Call: fmt::Debug,
Extra: SignedExtension,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"UncheckedExtrinsic({:?}, {:?})",
self.signature.as_ref().map(|x| (&x.0, &x.2)),
self.function,
)
}
}
impl<Address, Call, Signature, Extra> GetDispatchInfo
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Call: GetDispatchInfo,
Extra: SignedExtension,
{
fn get_dispatch_info(&self) -> DispatchInfo {
self.function.get_dispatch_info()
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::hashing::blake2_256;
use crate::codec::{Encode, Decode};
use crate::traits::{SignedExtension, IdentifyAccount, IdentityLookup};
use serde::{Serialize, Deserialize};
type TestContext = IdentityLookup<u64>;
#[derive(Eq, PartialEq, Clone, Copy, Debug, Serialize, Deserialize, Encode, Decode)]
pub struct TestSigner(pub u64);
impl From<u64> for TestSigner { fn from(x: u64) -> Self { Self(x) } }
impl From<TestSigner> for u64 { fn from(x: TestSigner) -> Self { x.0 } }
impl IdentifyAccount for TestSigner {
type AccountId = u64;
fn into_account(self) -> u64 { self.into() }
}
#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Encode, Decode)]
struct TestSig(u64, Vec<u8>);
impl traits::Verify for TestSig {
type Signer = TestSigner;
fn verify<L: traits::Lazy<[u8]>>(&self, mut msg: L, signer: &u64) -> bool {
signer == &self.0 && msg.get() == &self.1[..]
}
}
type TestAccountId = u64;
type TestCall = Vec<u8>;
const TEST_ACCOUNT: TestAccountId = 0;
// NOTE: this is demonstration. One can simply use `()` for testing.
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, Ord, PartialOrd)]
struct TestExtra;
impl SignedExtension for TestExtra {
type AccountId = u64;
type Call = ();
type AdditionalSigned = ();
type Pre = ();
fn additional_signed(&self) -> rstd::result::Result<(), TransactionValidityError> { Ok(()) }
}
type Ex = UncheckedExtrinsic<TestAccountId, TestCall, TestSig, TestExtra>;
type CEx = CheckedExtrinsic<TestAccountId, TestCall, TestExtra>;
#[test]
fn unsigned_codec_should_work() {
let ux = Ex::new_unsigned(vec![0u8; 0]);
let encoded = ux.encode();
assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
}
#[test]
fn signed_codec_should_work() {
let ux = Ex::new_signed(
vec![0u8; 0],
TEST_ACCOUNT,
TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()),
TestExtra
);
let encoded = ux.encode();
assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
}
#[test]
fn large_signed_codec_should_work() {
let ux = Ex::new_signed(
vec![0u8; 0],
TEST_ACCOUNT,
TestSig(TEST_ACCOUNT, (vec![0u8; 257], TestExtra)
.using_encoded(blake2_256)[..].to_owned()),
TestExtra
);
let encoded = ux.encode();
assert_eq!(Ex::decode(&mut &encoded[..]), Ok(ux));
}
#[test]
fn unsigned_check_should_work() {
let ux = Ex::new_unsigned(vec![0u8; 0]);
assert!(!ux.is_signed().unwrap_or(false));
assert!(<Ex as Checkable<TestContext>>::check(ux, &Default::default()).is_ok());
}
#[test]
fn badly_signed_check_should_fail() {
let ux = Ex::new_signed(
vec![0u8; 0],
TEST_ACCOUNT,
TestSig(TEST_ACCOUNT, vec![0u8; 0]),
TestExtra,
);
assert!(ux.is_signed().unwrap_or(false));
assert_eq!(
<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
Err(InvalidTransaction::BadProof.into()),
);
}
#[test]
fn signed_check_should_work() {
let ux = Ex::new_signed(
vec![0u8; 0],
TEST_ACCOUNT,
TestSig(TEST_ACCOUNT, (vec![0u8; 0], TestExtra).encode()),
TestExtra,
);
assert!(ux.is_signed().unwrap_or(false));
assert_eq!(
<Ex as Checkable<TestContext>>::check(ux, &Default::default()),
Ok(CEx { signed: Some((TEST_ACCOUNT, TestExtra)), function: vec![0u8; 0] }),
);
}
#[test]
fn encoding_matches_vec() {
let ex = Ex::new_unsigned(vec![0u8; 0]);
let encoded = ex.encode();
let decoded = Ex::decode(&mut encoded.as_slice()).unwrap();
assert_eq!(decoded, ex);
let as_vec: Vec<u8> = Decode::decode(&mut encoded.as_slice()).unwrap();
assert_eq!(as_vec.encode(), encoded);
}
}
@@ -0,0 +1,697 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Runtime Modules shared primitive types.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
// to allow benchmarking
#![cfg_attr(feature = "bench", feature(test))]
#[cfg(feature = "bench")] extern crate test;
#[doc(hidden)]
pub use codec;
#[cfg(feature = "std")]
#[doc(hidden)]
pub use serde;
#[doc(hidden)]
pub use rstd;
#[doc(hidden)]
pub use paste;
#[doc(hidden)]
pub use app_crypto;
#[cfg(feature = "std")]
pub use primitives::storage::{StorageOverlay, ChildrenStorageOverlay};
use rstd::prelude::*;
use rstd::convert::TryFrom;
use primitives::{crypto, ed25519, sr25519, ecdsa, hash::{H256, H512}};
use codec::{Encode, Decode};
pub mod curve;
pub mod generic;
pub mod offchain;
#[cfg(feature = "std")]
pub mod testing;
pub mod traits;
pub mod transaction_validity;
pub mod weights;
/// Re-export these since they're only "kind of" generic.
pub use generic::{DigestItem, Digest};
/// Re-export this since it's part of the API of this crate.
pub use primitives::{TypeId, crypto::{key_types, KeyTypeId, CryptoType, AccountId32}};
pub use app_crypto::{RuntimeAppPublic, BoundToRuntimeAppPublic};
/// Re-export `RuntimeDebug`, to avoid dependency clutter.
pub use primitives::RuntimeDebug;
/// Re-export top-level arithmetic stuff.
pub use arithmetic::{Perquintill, Perbill, Permill, Percent, Rational128, Fixed64};
/// Re-export 128 bit helpers.
pub use arithmetic::helpers_128bit;
/// Re-export big_uint stuff.
pub use arithmetic::biguint;
/// An abstraction over justification for a block's validity under a consensus algorithm.
///
/// Essentially a finality proof. The exact formulation will vary between consensus
/// algorithms. In the case where there are multiple valid proofs, inclusion within
/// the block itself would allow swapping justifications to change the block's hash
/// (and thus fork the chain). Sending a `Justification` alongside a block instead
/// bypasses this problem.
pub type Justification = Vec<u8>;
use traits::{Verify, Lazy};
/// A module identifier. These are per module and should be stored in a registry somewhere.
#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode)]
pub struct ModuleId(pub [u8; 8]);
impl TypeId for ModuleId {
const TYPE_ID: [u8; 4] = *b"modl";
}
/// A String that is a `&'static str` on `no_std` and a `Cow<'static, str>` on `std`.
#[cfg(feature = "std")]
pub type RuntimeString = std::borrow::Cow<'static, str>;
/// A String that is a `&'static str` on `no_std` and a `Cow<'static, str>` on `std`.
#[cfg(not(feature = "std"))]
pub type RuntimeString = &'static str;
/// Create a const [`RuntimeString`].
#[cfg(feature = "std")]
#[macro_export]
macro_rules! create_runtime_str {
( $y:expr ) => {{ std::borrow::Cow::Borrowed($y) }}
}
/// Create a const [`RuntimeString`].
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! create_runtime_str {
( $y:expr ) => {{ $y }}
}
#[cfg(feature = "std")]
pub use serde::{Serialize, Deserialize, de::DeserializeOwned};
use crate::traits::IdentifyAccount;
/// Complex storage builder stuff.
#[cfg(feature = "std")]
pub trait BuildStorage: Sized {
/// Build the storage out of this builder.
fn build_storage(&self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> {
let mut storage = (Default::default(), Default::default());
self.assimilate_storage(&mut storage)?;
Ok(storage)
}
/// Assimilate the storage for this module into pre-existing overlays.
fn assimilate_storage(
&self,
storage: &mut (StorageOverlay, ChildrenStorageOverlay),
) -> Result<(), String>;
}
/// Something that can build the genesis storage of a module.
#[cfg(feature = "std")]
pub trait BuildModuleGenesisStorage<T, I>: Sized {
/// Create the module genesis storage into the given `storage` and `child_storage`.
fn build_module_genesis_storage(
&self,
storage: &mut (StorageOverlay, ChildrenStorageOverlay),
) -> Result<(), String>;
}
#[cfg(feature = "std")]
impl BuildStorage for (StorageOverlay, ChildrenStorageOverlay) {
fn assimilate_storage(
&self,
storage: &mut (StorageOverlay, ChildrenStorageOverlay),
)-> Result<(), String> {
storage.0.extend(self.0.iter().map(|(k, v)| (k.clone(), v.clone())));
for (k, other_map) in self.1.iter() {
let k = k.clone();
if let Some(map) = storage.1.get_mut(&k) {
map.extend(other_map.iter().map(|(k, v)| (k.clone(), v.clone())));
} else {
storage.1.insert(k, other_map.clone());
}
}
Ok(())
}
}
/// Consensus engine unique ID.
pub type ConsensusEngineId = [u8; 4];
/// Signature verify that can work with any known signature types..
#[derive(Eq, PartialEq, Clone, Encode, Decode, RuntimeDebug)]
pub enum MultiSignature {
/// An Ed25519 signature.
Ed25519(ed25519::Signature),
/// An Sr25519 signature.
Sr25519(sr25519::Signature),
/// An ECDSA/SECP256k1 signature.
Ecdsa(ecdsa::Signature),
}
impl From<ed25519::Signature> for MultiSignature {
fn from(x: ed25519::Signature) -> Self {
MultiSignature::Ed25519(x)
}
}
impl From<sr25519::Signature> for MultiSignature {
fn from(x: sr25519::Signature) -> Self {
MultiSignature::Sr25519(x)
}
}
impl From<ecdsa::Signature> for MultiSignature {
fn from(x: ecdsa::Signature) -> Self {
MultiSignature::Ecdsa(x)
}
}
impl Default for MultiSignature {
fn default() -> Self {
MultiSignature::Ed25519(Default::default())
}
}
/// Public key for any known crypto algorithm.
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum MultiSigner {
/// An Ed25519 identity.
Ed25519(ed25519::Public),
/// An Sr25519 identity.
Sr25519(sr25519::Public),
/// An SECP256k1/ECDSA identity (actually, the Blake2 hash of the pub key).
Ecdsa(ecdsa::Public),
}
impl Default for MultiSigner {
fn default() -> Self {
MultiSigner::Ed25519(Default::default())
}
}
/// NOTE: This implementations is required by `SimpleAddressDeterminator`,
/// we convert the hash into some AccountId, it's fine to use any scheme.
impl<T: Into<H256>> crypto::UncheckedFrom<T> for MultiSigner {
fn unchecked_from(x: T) -> Self {
ed25519::Public::unchecked_from(x.into()).into()
}
}
impl AsRef<[u8]> for MultiSigner {
fn as_ref(&self) -> &[u8] {
match *self {
MultiSigner::Ed25519(ref who) => who.as_ref(),
MultiSigner::Sr25519(ref who) => who.as_ref(),
MultiSigner::Ecdsa(ref who) => who.as_ref(),
}
}
}
impl traits::IdentifyAccount for MultiSigner {
type AccountId = AccountId32;
fn into_account(self) -> AccountId32 {
match self {
MultiSigner::Ed25519(who) => <[u8; 32]>::from(who).into(),
MultiSigner::Sr25519(who) => <[u8; 32]>::from(who).into(),
MultiSigner::Ecdsa(who) => runtime_io::hashing::blake2_256(who.as_ref()).into(),
}
}
}
impl From<ed25519::Public> for MultiSigner {
fn from(x: ed25519::Public) -> Self {
MultiSigner::Ed25519(x)
}
}
impl TryFrom<MultiSigner> for ed25519::Public {
type Error = ();
fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
if let MultiSigner::Ed25519(x) = m { Ok(x) } else { Err(()) }
}
}
impl From<sr25519::Public> for MultiSigner {
fn from(x: sr25519::Public) -> Self {
MultiSigner::Sr25519(x)
}
}
impl TryFrom<MultiSigner> for sr25519::Public {
type Error = ();
fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
if let MultiSigner::Sr25519(x) = m { Ok(x) } else { Err(()) }
}
}
impl From<ecdsa::Public> for MultiSigner {
fn from(x: ecdsa::Public) -> Self {
MultiSigner::Ecdsa(x)
}
}
impl TryFrom<MultiSigner> for ecdsa::Public {
type Error = ();
fn try_from(m: MultiSigner) -> Result<Self, Self::Error> {
if let MultiSigner::Ecdsa(x) = m { Ok(x) } else { Err(()) }
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for MultiSigner {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
MultiSigner::Ed25519(ref who) => write!(fmt, "ed25519: {}", who),
MultiSigner::Sr25519(ref who) => write!(fmt, "sr25519: {}", who),
MultiSigner::Ecdsa(ref who) => write!(fmt, "ecdsa: {}", who),
}
}
}
impl Verify for MultiSignature {
type Signer = MultiSigner;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId32) -> bool {
use primitives::crypto::Public;
match (self, signer) {
(MultiSignature::Ed25519(ref sig), who) => sig.verify(msg, &ed25519::Public::from_slice(who.as_ref())),
(MultiSignature::Sr25519(ref sig), who) => sig.verify(msg, &sr25519::Public::from_slice(who.as_ref())),
(MultiSignature::Ecdsa(ref sig), who) => {
let m = runtime_io::hashing::blake2_256(msg.get());
match runtime_io::crypto::secp256k1_ecdsa_recover_compressed(sig.as_ref(), &m) {
Ok(pubkey) =>
&runtime_io::hashing::blake2_256(pubkey.as_ref())
== <dyn AsRef<[u8; 32]>>::as_ref(who),
_ => false,
}
}
}
}
}
/// Signature verify that can work with any known signature types..
#[derive(Eq, PartialEq, Clone, Default, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct AnySignature(H512);
impl Verify for AnySignature {
type Signer = sr25519::Public;
fn verify<L: Lazy<[u8]>>(&self, mut msg: L, signer: &sr25519::Public) -> bool {
use primitives::crypto::Public;
let msg = msg.get();
sr25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
.map(|s| s.verify(msg, signer))
.unwrap_or(false)
|| ed25519::Signature::try_from(self.0.as_fixed_bytes().as_ref())
.map(|s| s.verify(msg, &ed25519::Public::from_slice(signer.as_ref())))
.unwrap_or(false)
}
}
impl From<sr25519::Signature> for AnySignature {
fn from(s: sr25519::Signature) -> Self {
AnySignature(s.into())
}
}
impl From<ed25519::Signature> for AnySignature {
fn from(s: ed25519::Signature) -> Self {
AnySignature(s.into())
}
}
#[derive(Eq, PartialEq, Clone, Copy, Decode, Encode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize))]
/// Reason why an extrinsic couldn't be applied (i.e. invalid extrinsic).
pub enum ApplyError {
/// General error to do with the permissions of the sender.
NoPermission,
/// General error to do with the state of the system in general.
BadState,
/// Any error to do with the transaction validity.
Validity(transaction_validity::TransactionValidityError),
}
impl ApplyError {
/// Returns if the reason for the error was block resource exhaustion.
pub fn exhausted_resources(&self) -> bool {
match self {
Self::Validity(e) => e.exhausted_resources(),
_ => false,
}
}
}
impl From<ApplyError> for &'static str {
fn from(err: ApplyError) -> &'static str {
match err {
ApplyError::NoPermission => "Transaction does not have required permissions",
ApplyError::BadState => "System state currently prevents this transaction",
ApplyError::Validity(v) => v.into(),
}
}
}
impl From<transaction_validity::TransactionValidityError> for ApplyError {
fn from(err: transaction_validity::TransactionValidityError) -> Self {
ApplyError::Validity(err)
}
}
/// The outcome of applying a transaction.
pub type ApplyOutcome = Result<(), DispatchError>;
impl From<DispatchError> for ApplyOutcome {
fn from(err: DispatchError) -> Self {
Err(err)
}
}
/// Result from attempt to apply an extrinsic.
pub type ApplyResult = Result<ApplyOutcome, ApplyError>;
#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize))]
/// Reason why a dispatch call failed
pub struct DispatchError {
/// Module index, matching the metadata module index
pub module: Option<u8>,
/// Module specific error value
pub error: u8,
/// Optional error message.
#[codec(skip)]
pub message: Option<&'static str>,
}
impl DispatchError {
/// Create a new instance of `DispatchError`.
pub fn new(module: Option<u8>, error: u8, message: Option<&'static str>) -> Self {
Self {
module,
error,
message,
}
}
}
impl traits::Printable for DispatchError {
fn print(&self) {
"DispatchError".print();
if let Some(module) = self.module {
module.print();
}
self.error.print();
if let Some(msg) = self.message {
msg.print();
}
}
}
impl traits::ModuleDispatchError for &'static str {
fn as_u8(&self) -> u8 {
0
}
fn as_str(&self) -> &'static str {
self
}
}
impl From<&'static str> for DispatchError {
fn from(err: &'static str) -> DispatchError {
DispatchError::new(None, 0, Some(err))
}
}
/// Verify a signature on an encoded value in a lazy manner. This can be
/// an optimization if the signature scheme has an "unsigned" escape hash.
pub fn verify_encoded_lazy<V: Verify, T: codec::Encode>(
sig: &V,
item: &T,
signer: &<V::Signer as IdentifyAccount>::AccountId
) -> bool {
// The `Lazy<T>` trait expresses something like `X: FnMut<Output = for<'a> &'a T>`.
// unfortunately this is a lifetime relationship that can't
// be expressed without generic associated types, better unification of HRTBs in type position,
// and some kind of integration into the Fn* traits.
struct LazyEncode<F> {
inner: F,
encoded: Option<Vec<u8>>,
}
impl<F: Fn() -> Vec<u8>> traits::Lazy<[u8]> for LazyEncode<F> {
fn get(&mut self) -> &[u8] {
self.encoded.get_or_insert_with(&self.inner).as_slice()
}
}
sig.verify(
LazyEncode { inner: || item.encode(), encoded: None },
signer,
)
}
/// Helper macro for `impl_outer_config`
#[macro_export]
macro_rules! __impl_outer_config_types {
// Generic + Instance
(
$concrete:ident $config:ident $snake:ident { $instance:ident } < $ignore:ident >;
$( $rest:tt )*
) => {
#[cfg(any(feature = "std", test))]
pub type $config = $snake::GenesisConfig<$concrete, $snake::$instance>;
$crate::__impl_outer_config_types! { $concrete $( $rest )* }
};
// Generic
(
$concrete:ident $config:ident $snake:ident < $ignore:ident >;
$( $rest:tt )*
) => {
#[cfg(any(feature = "std", test))]
pub type $config = $snake::GenesisConfig<$concrete>;
$crate::__impl_outer_config_types! { $concrete $( $rest )* }
};
// No Generic and maybe Instance
(
$concrete:ident $config:ident $snake:ident $( { $instance:ident } )?;
$( $rest:tt )*
) => {
#[cfg(any(feature = "std", test))]
pub type $config = $snake::GenesisConfig;
$crate::__impl_outer_config_types! { $concrete $( $rest )* }
};
($concrete:ident) => ()
}
/// Implement the output "meta" module configuration struct,
/// which is basically:
/// pub struct GenesisConfig {
/// rust_module_one: Option<ModuleOneConfig>,
/// ...
/// }
#[macro_export]
macro_rules! impl_outer_config {
(
pub struct $main:ident for $concrete:ident {
$( $config:ident =>
$snake:ident $( $instance:ident )? $( <$generic:ident> )*, )*
}
) => {
$crate::__impl_outer_config_types! {
$concrete $( $config $snake $( { $instance } )? $( <$generic> )*; )*
}
$crate::paste::item! {
#[cfg(any(feature = "std", test))]
#[derive($crate::serde::Serialize, $crate::serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct $main {
$(
pub [< $snake $(_ $instance )? >]: Option<$config>,
)*
}
#[cfg(any(feature = "std", test))]
impl $crate::BuildStorage for $main {
fn assimilate_storage(
&self,
storage: &mut ($crate::StorageOverlay, $crate::ChildrenStorageOverlay),
) -> std::result::Result<(), String> {
$(
if let Some(ref extra) = self.[< $snake $(_ $instance )? >] {
$crate::impl_outer_config! {
@CALL_FN
$concrete;
$snake;
$( $instance )?;
extra;
storage;
}
}
)*
Ok(())
}
}
}
};
(@CALL_FN
$runtime:ident;
$module:ident;
$instance:ident;
$extra:ident;
$storage:ident;
) => {
$crate::BuildModuleGenesisStorage::<$runtime, $module::$instance>::build_module_genesis_storage(
$extra,
$storage,
)?;
};
(@CALL_FN
$runtime:ident;
$module:ident;
;
$extra:ident;
$storage:ident;
) => {
$crate::BuildModuleGenesisStorage::<$runtime, $module::__InherentHiddenInstance>::build_module_genesis_storage(
$extra,
$storage,
)?;
}
}
/// Checks that `$x` is equal to `$y` with an error rate of `$error`.
///
/// # Example
///
/// ```rust
/// # fn main() {
/// sr_primitives::assert_eq_error_rate!(10, 10, 0);
/// sr_primitives::assert_eq_error_rate!(10, 11, 1);
/// sr_primitives::assert_eq_error_rate!(12, 10, 2);
/// # }
/// ```
///
/// ```rust,should_panic
/// # fn main() {
/// sr_primitives::assert_eq_error_rate!(12, 10, 1);
/// # }
/// ```
#[macro_export]
#[cfg(feature = "std")]
macro_rules! assert_eq_error_rate {
($x:expr, $y:expr, $error:expr $(,)?) => {
assert!(
($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)),
"{:?} != {:?} (with error rate {:?})",
$x,
$y,
$error,
);
};
}
/// Simple blob to hold an extrinsic without committing to its format and ensure it is serialized
/// correctly.
#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
pub struct OpaqueExtrinsic(pub Vec<u8>);
impl rstd::fmt::Debug for OpaqueExtrinsic {
#[cfg(feature = "std")]
fn fmt(&self, fmt: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
write!(fmt, "{}", primitives::hexdisplay::HexDisplay::from(&self.0))
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _fmt: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
Ok(())
}
}
#[cfg(feature = "std")]
impl ::serde::Serialize for OpaqueExtrinsic {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
codec::Encode::using_encoded(&self.0, |bytes| ::primitives::bytes::serialize(bytes, seq))
}
}
#[cfg(feature = "std")]
impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic {
fn deserialize<D>(de: D) -> Result<Self, D::Error> where D: ::serde::Deserializer<'a> {
let r = ::primitives::bytes::deserialize(de)?;
Decode::decode(&mut &r[..])
.map_err(|e| ::serde::de::Error::custom(format!("Decode error: {}", e)))
}
}
impl traits::Extrinsic for OpaqueExtrinsic {
type Call = ();
type SignaturePayload = ();
}
/// Print something that implements `Printable` from the runtime.
pub fn print(print: impl traits::Printable) {
print.print();
}
#[cfg(test)]
mod tests {
use crate::DispatchError;
use codec::{Encode, Decode};
#[test]
fn opaque_extrinsic_serialization() {
let ex = super::OpaqueExtrinsic(vec![1, 2, 3, 4]);
assert_eq!(serde_json::to_string(&ex).unwrap(), "\"0x1001020304\"".to_owned());
}
#[test]
fn dispatch_error_encoding() {
let error = DispatchError {
module: Some(1),
error: 2,
message: Some("error message"),
};
let encoded = error.encode();
let decoded = DispatchError::decode(&mut &encoded[..]).unwrap();
assert_eq!(encoded, vec![1, 1, 2]);
assert_eq!(
decoded,
DispatchError {
module: Some(1),
error: 2,
message: None,
},
);
}
}
@@ -0,0 +1,604 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! A high-level helpers for making HTTP requests from Offchain Workers.
//!
//! `sr-io` crate exposes a low level methods to make and control HTTP requests
//! available only for Offchain Workers. Those might be hard to use
//! and usually that level of control is not really necessary.
//! This module aims to provide high-level wrappers for those APIs
//! to simplify making HTTP requests.
//!
//!
//! Example:
//! ```rust,no_run
//! use sr_primitives::offchain::http::Request;
//!
//! // initiate a GET request to localhost:1234
//! let request: Request = Request::get("http://localhost:1234");
//! let pending = request
//! .add_header("X-Auth", "hunter2")
//! .send()
//! .unwrap();
//!
//! // wait for the response indefinitely
//! let mut response = pending.wait().unwrap();
//!
//! // then check the headers
//! let mut headers = response.headers().into_iter();
//! assert_eq!(headers.current(), None);
//!
//! // and collect the body
//! let body = response.body();
//! assert_eq!(body.clone().collect::<Vec<_>>(), b"1234".to_vec());
//! assert_eq!(body.error(), &None);
//! ```
use rstd::str;
use rstd::prelude::Vec;
#[cfg(not(feature = "std"))]
use rstd::prelude::vec;
use primitives::RuntimeDebug;
use primitives::offchain::{
Timestamp,
HttpRequestId as RequestId,
HttpRequestStatus as RequestStatus,
HttpError,
};
/// Request method (HTTP verb)
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
pub enum Method {
/// GET request
Get,
/// POST request
Post,
/// PUT request
Put,
/// PATCH request
Patch,
/// DELETE request
Delete,
/// Custom verb
Other(&'static str),
}
impl AsRef<str> for Method {
fn as_ref(&self) -> &str {
match *self {
Method::Get => "GET",
Method::Post => "POST",
Method::Put => "PUT",
Method::Patch => "PATCH",
Method::Delete => "DELETE",
Method::Other(m) => m,
}
}
}
mod header {
use super::*;
/// A header type.
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
pub struct Header {
name: Vec<u8>,
value: Vec<u8>,
}
impl Header {
/// Creates new header given it's name and value.
pub fn new(name: &str, value: &str) -> Self {
Header {
name: name.as_bytes().to_vec(),
value: value.as_bytes().to_vec(),
}
}
/// Returns the name of this header.
pub fn name(&self) -> &str {
// Header keys are always produced from `&str` so this is safe.
// we don't store them as `Strings` to avoid bringing `alloc::String` to rstd
// or here.
unsafe { str::from_utf8_unchecked(&self.name) }
}
/// Returns the value of this header.
pub fn value(&self) -> &str {
// Header values are always produced from `&str` so this is safe.
// we don't store them as `Strings` to avoid bringing `alloc::String` to rstd
// or here.
unsafe { str::from_utf8_unchecked(&self.value) }
}
}
}
/// An HTTP request builder.
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
pub struct Request<'a, T = Vec<&'static [u8]>> {
/// Request method
pub method: Method,
/// Request URL
pub url: &'a str,
/// Body of the request
pub body: T,
/// Deadline to finish sending the request
pub deadline: Option<Timestamp>,
/// Request list of headers.
headers: Vec<header::Header>,
}
impl<T: Default> Default for Request<'static, T> {
fn default() -> Self {
Request {
method: Method::Get,
url: "http://localhost",
headers: Vec::new(),
body: Default::default(),
deadline: None,
}
}
}
impl<'a> Request<'a> {
/// Start a simple GET request
pub fn get(url: &'a str) -> Self {
Self::new(url)
}
}
impl<'a, T> Request<'a, T> {
/// Create new POST request with given body.
pub fn post(url: &'a str, body: T) -> Self {
let req: Request = Request::default();
Request {
url,
body,
method: Method::Post,
headers: req.headers,
deadline: req.deadline,
}
}
}
impl<'a, T: Default> Request<'a, T> {
/// Create new Request builder with given URL and body.
pub fn new(url: &'a str) -> Self {
Request::default().url(url)
}
/// Change the method of the request
pub fn method(mut self, method: Method) -> Self {
self.method = method;
self
}
/// Change the URL of the request.
pub fn url(mut self, url: &'a str) -> Self {
self.url = url;
self
}
/// Set the body of the request.
pub fn body(mut self, body: T) -> Self {
self.body = body;
self
}
/// Add a header.
pub fn add_header(mut self, name: &str, value: &str) -> Self {
self.headers.push(header::Header::new(name, value));
self
}
/// Set the deadline of the request.
pub fn deadline(mut self, deadline: Timestamp) -> Self {
self.deadline = Some(deadline);
self
}
}
impl<'a, I: AsRef<[u8]>, T: IntoIterator<Item=I>> Request<'a, T> {
/// Send the request and return a handle.
///
/// Err is returned in case the deadline is reached
/// or the request timeouts.
pub fn send(self) -> Result<PendingRequest, HttpError> {
let meta = &[];
// start an http request.
let id = runtime_io::offchain::http_request_start(
self.method.as_ref(),
self.url,
meta,
).map_err(|_| HttpError::IoError)?;
// add custom headers
for header in &self.headers {
runtime_io::offchain::http_request_add_header(
id,
header.name(),
header.value(),
).map_err(|_| HttpError::IoError)?
}
// write body
for chunk in self.body {
runtime_io::offchain::http_request_write_body(id, chunk.as_ref(), self.deadline)?;
}
// finalise the request
runtime_io::offchain::http_request_write_body(id, &[], self.deadline)?;
Ok(PendingRequest {
id,
})
}
}
/// A request error
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
pub enum Error {
/// Deadline has been reached.
DeadlineReached,
/// Request had timed out.
IoError,
/// Unknown error has been ecountered.
Unknown,
}
/// A struct representing an uncompleted http request.
#[derive(PartialEq, Eq, RuntimeDebug)]
pub struct PendingRequest {
/// Request ID
pub id: RequestId,
}
/// A result of waiting for a pending request.
pub type HttpResult = Result<Response, Error>;
impl PendingRequest {
/// Wait for the request to complete.
///
/// NOTE this waits for the request indefinitely.
pub fn wait(self) -> HttpResult {
match self.try_wait(None) {
Ok(res) => res,
Err(_) => panic!("Since `None` is passed we will never get a deadline error; qed"),
}
}
/// Attempts to wait for the request to finish,
/// but will return `Err` in case the deadline is reached.
pub fn try_wait(self, deadline: impl Into<Option<Timestamp>>) -> Result<HttpResult, PendingRequest> {
Self::try_wait_all(vec![self], deadline).pop().expect("One request passed, one status received; qed")
}
/// Wait for all provided requests.
pub fn wait_all(requests: Vec<PendingRequest>) -> Vec<HttpResult> {
Self::try_wait_all(requests, None)
.into_iter()
.map(|r| match r {
Ok(r) => r,
Err(_) => panic!("Since `None` is passed we will never get a deadline error; qed"),
})
.collect()
}
/// Attempt to wait for all provided requests, but up to given deadline.
///
/// Requests that are complete will resolve to an `Ok` others will return a `DeadlineReached` error.
pub fn try_wait_all(
requests: Vec<PendingRequest>,
deadline: impl Into<Option<Timestamp>>
) -> Vec<Result<HttpResult, PendingRequest>> {
let ids = requests.iter().map(|r| r.id).collect::<Vec<_>>();
let statuses = runtime_io::offchain::http_response_wait(&ids, deadline.into());
statuses
.into_iter()
.zip(requests.into_iter())
.map(|(status, req)| match status {
RequestStatus::DeadlineReached => Err(req),
RequestStatus::IoError => Ok(Err(Error::IoError)),
RequestStatus::Invalid => Ok(Err(Error::Unknown)),
RequestStatus::Finished(code) => Ok(Ok(Response::new(req.id, code))),
})
.collect()
}
}
/// A HTTP response.
#[derive(RuntimeDebug)]
pub struct Response {
/// Request id
pub id: RequestId,
/// Response status code
pub code: u16,
/// A collection of headers.
headers: Option<Headers>,
}
impl Response {
fn new(id: RequestId, code: u16) -> Self {
Self {
id,
code,
headers: None,
}
}
/// Retrieve the headers for this response.
pub fn headers(&mut self) -> &Headers {
if self.headers.is_none() {
self.headers = Some(
Headers { raw: runtime_io::offchain::http_response_headers(self.id) },
);
}
self.headers.as_ref().expect("Headers were just set; qed")
}
/// Retrieve the body of this response.
pub fn body(&self) -> ResponseBody {
ResponseBody::new(self.id)
}
}
/// A buffered byte iterator over response body.
///
/// Note that reading the body may return `None` in following cases:
/// 1. Either the deadline you've set is reached (check via `#error`;
/// In such case you can resume the reader by setting a new deadline)
/// 2. Or because of IOError. In such case the reader is not resumable and will keep
/// returning `None`.
/// 3. The body has been returned. The reader will keep returning `None`.
#[derive(Clone)]
pub struct ResponseBody {
id: RequestId,
error: Option<HttpError>,
buffer: [u8; 4096],
filled_up_to: Option<usize>,
position: usize,
deadline: Option<Timestamp>,
}
#[cfg(feature = "std")]
impl std::fmt::Debug for ResponseBody {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.debug_struct("ResponseBody")
.field("id", &self.id)
.field("error", &self.error)
.field("buffer", &self.buffer.len())
.field("filled_up_to", &self.filled_up_to)
.field("position", &self.position)
.field("deadline", &self.deadline)
.finish()
}
}
impl ResponseBody {
fn new(id: RequestId) -> Self {
ResponseBody {
id,
error: None,
buffer: [0_u8; 4096],
filled_up_to: None,
position: 0,
deadline: None,
}
}
/// Set the deadline for reading the body.
pub fn deadline(&mut self, deadline: impl Into<Option<Timestamp>>) {
self.deadline = deadline.into();
self.error = None;
}
/// Return an error that caused the iterator to return `None`.
///
/// If the error is `DeadlineReached` you can resume the iterator by setting
/// a new deadline.
pub fn error(&self) -> &Option<HttpError> {
&self.error
}
}
impl Iterator for ResponseBody {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.error.is_some() {
return None;
}
if self.filled_up_to.is_none() {
let result = runtime_io::offchain::http_response_read_body(
self.id,
&mut self.buffer,
self.deadline);
match result {
Err(e) => {
self.error = Some(e);
return None;
}
Ok(0) => {
return None;
}
Ok(size) => {
self.position = 0;
self.filled_up_to = Some(size as usize);
}
}
}
if Some(self.position) == self.filled_up_to {
self.filled_up_to = None;
return self.next();
}
let result = self.buffer[self.position];
self.position += 1;
Some(result)
}
}
/// A collection of Headers in the response.
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
pub struct Headers {
/// Raw headers
pub raw: Vec<(Vec<u8>, Vec<u8>)>,
}
impl Headers {
/// Retrieve a single header from the list of headers.
///
/// Note this method is linearly looking from all the headers
/// comparing them with the needle byte-by-byte.
/// If you want to consume multiple headers it's better to iterate
/// and collect them on your own.
pub fn find(&self, name: &str) -> Option<&str> {
let raw = name.as_bytes();
for &(ref key, ref val) in &self.raw {
if &**key == raw {
return str::from_utf8(&val).ok()
}
}
None
}
/// Convert this headers into an iterator.
pub fn into_iter(&self) -> HeadersIterator {
HeadersIterator { collection: &self.raw, index: None }
}
}
/// A custom iterator traversing all the headers.
#[derive(Clone, RuntimeDebug)]
pub struct HeadersIterator<'a> {
collection: &'a [(Vec<u8>, Vec<u8>)],
index: Option<usize>,
}
impl<'a> HeadersIterator<'a> {
/// Move the iterator to the next position.
///
/// Returns `true` is `current` has been set by this call.
pub fn next(&mut self) -> bool {
let index = self.index.map(|x| x + 1).unwrap_or(0);
self.index = Some(index);
index < self.collection.len()
}
/// Returns current element (if any).
///
/// Note that you have to call `next` prior to calling this
pub fn current(&self) -> Option<(&str, &str)> {
self.collection.get(self.index?)
.map(|val| (str::from_utf8(&val.0).unwrap_or(""), str::from_utf8(&val.1).unwrap_or("")))
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::TestExternalities;
use substrate_offchain::testing;
use primitives::offchain::OffchainExt;
#[test]
fn should_send_a_basic_request_and_get_response() {
let (offchain, state) = testing::TestOffchainExt::new();
let mut t = TestExternalities::default();
t.register_extension(OffchainExt::new(offchain));
t.execute_with(|| {
let request: Request = Request::get("http://localhost:1234");
let pending = request
.add_header("X-Auth", "hunter2")
.send()
.unwrap();
// make sure it's sent correctly
state.write().fulfill_pending_request(
0,
testing::PendingRequest {
method: "GET".into(),
uri: "http://localhost:1234".into(),
headers: vec![("X-Auth".into(), "hunter2".into())],
sent: true,
..Default::default()
},
b"1234".to_vec(),
None,
);
// wait
let mut response = pending.wait().unwrap();
// then check the response
let mut headers = response.headers().into_iter();
assert_eq!(headers.current(), None);
assert_eq!(headers.next(), false);
assert_eq!(headers.current(), None);
let body = response.body();
assert_eq!(body.clone().collect::<Vec<_>>(), b"1234".to_vec());
assert_eq!(body.error(), &None);
})
}
#[test]
fn should_send_a_post_request() {
let (offchain, state) = testing::TestOffchainExt::new();
let mut t = TestExternalities::default();
t.register_extension(OffchainExt::new(offchain));
t.execute_with(|| {
let pending = Request::default()
.method(Method::Post)
.url("http://localhost:1234")
.body(vec![b"1234"])
.send()
.unwrap();
// make sure it's sent correctly
state.write().fulfill_pending_request(
0,
testing::PendingRequest {
method: "POST".into(),
uri: "http://localhost:1234".into(),
body: b"1234".to_vec(),
sent: true,
..Default::default()
},
b"1234".to_vec(),
Some(("Test".to_owned(), "Header".to_owned())),
);
// wait
let mut response = pending.wait().unwrap();
// then check the response
let mut headers = response.headers().into_iter();
assert_eq!(headers.current(), None);
assert_eq!(headers.next(), true);
assert_eq!(headers.current(), Some(("Test", "Header")));
let body = response.body();
assert_eq!(body.clone().collect::<Vec<_>>(), b"1234".to_vec());
assert_eq!(body.error(), &None);
})
}
}
@@ -0,0 +1,19 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! A collection of higher lever helpers for offchain workers.
pub mod http;
@@ -0,0 +1,377 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Testing utilities.
use serde::{Serialize, Serializer, Deserialize, de::Error as DeError, Deserializer};
use std::{fmt::Debug, ops::Deref, fmt, cell::RefCell};
use crate::codec::{Codec, Encode, Decode};
use crate::traits::{
self, Checkable, Applyable, BlakeTwo256, OpaqueKeys,
SignedExtension, Dispatchable,
};
#[allow(deprecated)]
use crate::traits::ValidateUnsigned;
use crate::{generic, KeyTypeId, ApplyResult};
use crate::weights::{GetDispatchInfo, DispatchInfo};
pub use primitives::{H256, sr25519};
use primitives::{crypto::{CryptoType, Dummy, key_types, Public}, U256};
use crate::transaction_validity::{TransactionValidity, TransactionValidityError};
/// Authority Id
#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, Debug, Hash, Serialize, Deserialize, PartialOrd, Ord)]
pub struct UintAuthorityId(pub u64);
impl From<u64> for UintAuthorityId {
fn from(id: u64) -> Self {
UintAuthorityId(id)
}
}
impl From<UintAuthorityId> for u64 {
fn from(id: UintAuthorityId) -> u64 {
id.0
}
}
impl UintAuthorityId {
/// Convert this authority id into a public key.
pub fn to_public_key<T: Public>(&self) -> T {
let bytes: [u8; 32] = U256::from(self.0).into();
T::from_slice(&bytes)
}
}
impl CryptoType for UintAuthorityId {
type Pair = Dummy;
}
impl AsRef<[u8]> for UintAuthorityId {
fn as_ref(&self) -> &[u8] {
// Unsafe, i know, but it's test code and it's just there because it's really convenient to
// keep `UintAuthorityId` as a u64 under the hood.
unsafe {
std::slice::from_raw_parts(&self.0 as *const u64 as *const _, std::mem::size_of::<u64>())
}
}
}
thread_local! {
/// A list of all UintAuthorityId keys returned to the runtime.
static ALL_KEYS: RefCell<Vec<UintAuthorityId>> = RefCell::new(vec![]);
}
impl UintAuthorityId {
/// Set the list of keys returned by the runtime call for all keys of that type.
pub fn set_all_keys<T: Into<UintAuthorityId>>(keys: impl IntoIterator<Item=T>) {
ALL_KEYS.with(|l| *l.borrow_mut() = keys.into_iter().map(Into::into).collect())
}
}
impl app_crypto::RuntimeAppPublic for UintAuthorityId {
const ID: KeyTypeId = key_types::DUMMY;
type Signature = u64;
fn all() -> Vec<Self> {
ALL_KEYS.with(|l| l.borrow().clone())
}
fn generate_pair(_: Option<Vec<u8>>) -> Self {
use rand::RngCore;
UintAuthorityId(rand::thread_rng().next_u64())
}
fn sign<M: AsRef<[u8]>>(&self, msg: &M) -> Option<Self::Signature> {
let mut signature = [0u8; 8];
msg.as_ref().iter()
.chain(std::iter::repeat(&42u8))
.take(8)
.enumerate()
.for_each(|(i, v)| { signature[i] = *v; });
Some(u64::from_le_bytes(signature))
}
fn verify<M: AsRef<[u8]>>(&self, msg: &M, signature: &Self::Signature) -> bool {
let mut msg_signature = [0u8; 8];
msg.as_ref().iter()
.chain(std::iter::repeat(&42))
.take(8)
.enumerate()
.for_each(|(i, v)| { msg_signature[i] = *v; });
u64::from_le_bytes(msg_signature) == *signature
}
}
impl OpaqueKeys for UintAuthorityId {
type KeyTypeIdProviders = ();
fn key_ids() -> &'static [KeyTypeId] {
&[key_types::DUMMY]
}
fn get_raw(&self, _: KeyTypeId) -> &[u8] {
self.as_ref()
}
fn get<T: Decode>(&self, _: KeyTypeId) -> Option<T> {
self.using_encoded(|mut x| T::decode(&mut x)).ok()
}
}
impl crate::BoundToRuntimeAppPublic for UintAuthorityId {
type Public = Self;
}
/// Digest item
pub type DigestItem = generic::DigestItem<H256>;
/// Header Digest
pub type Digest = generic::Digest<H256>;
/// Block Header
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode, Default)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct Header {
/// Parent hash
pub parent_hash: H256,
/// Block Number
pub number: u64,
/// Post-execution state trie root
pub state_root: H256,
/// Merkle root of block's extrinsics
pub extrinsics_root: H256,
/// Digest items
pub digest: Digest,
}
impl traits::Header for Header {
type Number = u64;
type Hashing = BlakeTwo256;
type Hash = H256;
fn number(&self) -> &Self::Number { &self.number }
fn set_number(&mut self, num: Self::Number) { self.number = num }
fn extrinsics_root(&self) -> &Self::Hash { &self.extrinsics_root }
fn set_extrinsics_root(&mut self, root: Self::Hash) { self.extrinsics_root = root }
fn state_root(&self) -> &Self::Hash { &self.state_root }
fn set_state_root(&mut self, root: Self::Hash) { self.state_root = root }
fn parent_hash(&self) -> &Self::Hash { &self.parent_hash }
fn set_parent_hash(&mut self, hash: Self::Hash) { self.parent_hash = hash }
fn digest(&self) -> &Digest { &self.digest }
fn digest_mut(&mut self) -> &mut Digest { &mut self.digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Digest,
) -> Self {
Header {
number,
extrinsics_root,
state_root,
parent_hash,
digest,
}
}
}
impl Header {
/// A new header with the given number and default hash for all other fields.
pub fn new_from_number(number: <Self as traits::Header>::Number) -> Self {
Self {
number,
..Default::default()
}
}
}
impl<'a> Deserialize<'a> for Header {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
let r = <Vec<u8>>::deserialize(de)?;
Decode::decode(&mut &r[..])
.map_err(|e| DeError::custom(format!("Invalid value passed into decode: {}", e.what())))
}
}
/// An opaque extrinsic wrapper type.
#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)]
pub struct ExtrinsicWrapper<Xt>(Xt);
impl<Xt> traits::Extrinsic for ExtrinsicWrapper<Xt> {
type Call = ();
type SignaturePayload = ();
fn is_signed(&self) -> Option<bool> {
None
}
}
impl<Xt: Encode> serde::Serialize for ExtrinsicWrapper<Xt> {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
}
}
impl<Xt> From<Xt> for ExtrinsicWrapper<Xt> {
fn from(xt: Xt) -> Self {
ExtrinsicWrapper(xt)
}
}
impl<Xt> Deref for ExtrinsicWrapper<Xt> {
type Target = Xt;
fn deref(&self) -> &Self::Target {
&self.0
}
}
/// Testing block
#[derive(PartialEq, Eq, Clone, Serialize, Debug, Encode, Decode)]
pub struct Block<Xt> {
/// Block header
pub header: Header,
/// List of extrinsics
pub extrinsics: Vec<Xt>,
}
impl<Xt: 'static + Codec + Sized + Send + Sync + Serialize + Clone + Eq + Debug + traits::Extrinsic> traits::Block
for Block<Xt>
{
type Extrinsic = Xt;
type Header = Header;
type Hash = <Header as traits::Header>::Hash;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.extrinsics[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.extrinsics)
}
fn new(header: Self::Header, extrinsics: Vec<Self::Extrinsic>) -> Self {
Block { header, extrinsics }
}
fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec<u8> {
(header, extrinsics).encode()
}
}
impl<'a, Xt> Deserialize<'a> for Block<Xt> where Block<Xt>: Decode {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
let r = <Vec<u8>>::deserialize(de)?;
Decode::decode(&mut &r[..])
.map_err(|e| DeError::custom(format!("Invalid value passed into decode: {}", e.what())))
}
}
/// Test transaction, tuple of (sender, call, signed_extra)
/// with index only used if sender is some.
///
/// If sender is some then the transaction is signed otherwise it is unsigned.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
pub struct TestXt<Call, Extra>(pub Option<(u64, Extra)>, pub Call);
impl<Call, Extra> Serialize for TestXt<Call, Extra> where TestXt<Call, Extra>: Encode {
fn serialize<S>(&self, seq: S) -> Result<S::Ok, S::Error> where S: Serializer {
self.using_encoded(|bytes| seq.serialize_bytes(bytes))
}
}
impl<Call, Extra> Debug for TestXt<Call, Extra> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestXt({:?}, ...)", self.0.as_ref().map(|x| &x.0))
}
}
impl<Call: Codec + Sync + Send, Context, Extra> Checkable<Context> for TestXt<Call, Extra> {
type Checked = Self;
fn check(self, _: &Context) -> Result<Self::Checked, TransactionValidityError> { Ok(self) }
}
impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra> {
type Call = Call;
type SignaturePayload = (u64, Extra);
fn is_signed(&self) -> Option<bool> {
Some(self.0.is_some())
}
fn new(c: Call, sig: Option<Self::SignaturePayload>) -> Option<Self> {
Some(TestXt(sig, c))
}
}
impl<Origin, Call, Extra> Applyable for TestXt<Call, Extra> where
Call: 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable<Origin=Origin>,
Extra: SignedExtension<AccountId=u64, Call=Call>,
Origin: From<Option<u64>>,
{
type AccountId = u64;
type Call = Call;
fn sender(&self) -> Option<&Self::AccountId> { self.0.as_ref().map(|x| &x.0) }
/// Checks to see if this is a valid *transaction*. It returns information on it if so.
#[allow(deprecated)] // Allow ValidateUnsigned
fn validate<U: ValidateUnsigned<Call=Self::Call>>(
&self,
_info: DispatchInfo,
_len: usize,
) -> TransactionValidity {
Ok(Default::default())
}
/// Executes all necessary logic needed prior to dispatch and deconstructs into function call,
/// index and sender.
#[allow(deprecated)] // Allow ValidateUnsigned
fn apply<U: ValidateUnsigned<Call=Self::Call>>(
self,
info: DispatchInfo,
len: usize,
) -> ApplyResult {
let maybe_who = if let Some((who, extra)) = self.0 {
Extra::pre_dispatch(extra, &who, &self.1, info, len)?;
Some(who)
} else {
Extra::pre_dispatch_unsigned(&self.1, info, len)?;
None
};
Ok(self.1.dispatch(maybe_who.into()).map_err(Into::into))
}
}
impl<Call: Encode, Extra: Encode> GetDispatchInfo for TestXt<Call, Extra> {
fn get_dispatch_info(&self) -> DispatchInfo {
// for testing: weight == size.
DispatchInfo {
weight: self.encode().len() as _,
..Default::default()
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,259 @@
// Copyright 2017-2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Transaction validity interface.
use rstd::prelude::*;
use crate::codec::{Encode, Decode};
use crate::RuntimeDebug;
/// Priority for a transaction. Additive. Higher is better.
pub type TransactionPriority = u64;
/// Minimum number of blocks a transaction will remain valid for.
/// `TransactionLongevity::max_value()` means "forever".
pub type TransactionLongevity = u64;
/// Tag for a transaction. No two transactions with the same tag should be placed on-chain.
pub type TransactionTag = Vec<u8>;
/// An invalid transaction validity.
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(serde::Serialize))]
pub enum InvalidTransaction {
/// The call of the transaction is not expected.
Call,
/// General error to do with the inability to pay some fees (e.g. account balance too low).
Payment,
/// General error to do with the transaction not yet being valid (e.g. nonce too high).
Future,
/// General error to do with the transaction being outdated (e.g. nonce too low).
Stale,
/// General error to do with the transaction's proofs (e.g. signature).
BadProof,
/// The transaction birth block is ancient.
AncientBirthBlock,
/// The transaction would exhaust the resources of current block.
///
/// The transaction might be valid, but there are not enough resources left in the current block.
ExhaustsResources,
/// Any other custom invalid validity that is not covered by this enum.
Custom(u8),
}
impl InvalidTransaction {
/// Returns if the reason for the invalidity was block resource exhaustion.
pub fn exhausted_resources(&self) -> bool {
match self {
Self::ExhaustsResources => true,
_ => false,
}
}
}
impl From<InvalidTransaction> for &'static str {
fn from(invalid: InvalidTransaction) -> &'static str {
match invalid {
InvalidTransaction::Call => "Transaction call is not expected",
InvalidTransaction::Future => "Transaction will be valid in the future",
InvalidTransaction::Stale => "Transaction is outdated",
InvalidTransaction::BadProof => "Transaction has a bad signature",
InvalidTransaction::AncientBirthBlock => "Transaction has an ancient birth block",
InvalidTransaction::ExhaustsResources =>
"Transaction would exhausts the block limits",
InvalidTransaction::Payment =>
"Inability to pay some fees (e.g. account balance too low)",
InvalidTransaction::Custom(_) => "InvalidTransaction custom error",
}
}
}
/// An unknown transaction validity.
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(serde::Serialize))]
pub enum UnknownTransaction {
/// Could not lookup some information that is required to validate the transaction.
CannotLookup,
/// No validator found for the given unsigned transaction.
NoUnsignedValidator,
/// Any other custom unknown validity that is not covered by this enum.
Custom(u8),
}
impl From<UnknownTransaction> for &'static str {
fn from(unknown: UnknownTransaction) -> &'static str {
match unknown {
UnknownTransaction::CannotLookup =>
"Could not lookup information required to validate the transaction",
UnknownTransaction::NoUnsignedValidator =>
"Could not find an unsigned validator for the unsigned transaction",
UnknownTransaction::Custom(_) => "UnknownTransaction custom error",
}
}
}
/// Errors that can occur while checking the validity of a transaction.
#[derive(Clone, PartialEq, Eq, Encode, Decode, Copy, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(serde::Serialize))]
pub enum TransactionValidityError {
/// The transaction is invalid.
Invalid(InvalidTransaction),
/// Transaction validity can't be determined.
Unknown(UnknownTransaction),
}
impl TransactionValidityError {
/// Returns `true` if the reason for the error was block resource exhaustion.
pub fn exhausted_resources(&self) -> bool {
match self {
Self::Invalid(e) => e.exhausted_resources(),
Self::Unknown(_) => false,
}
}
}
impl From<TransactionValidityError> for &'static str {
fn from(err: TransactionValidityError) -> &'static str {
match err {
TransactionValidityError::Invalid(invalid) => invalid.into(),
TransactionValidityError::Unknown(unknown) => unknown.into(),
}
}
}
impl From<InvalidTransaction> for TransactionValidityError {
fn from(err: InvalidTransaction) -> Self {
TransactionValidityError::Invalid(err)
}
}
impl From<UnknownTransaction> for TransactionValidityError {
fn from(err: UnknownTransaction) -> Self {
TransactionValidityError::Unknown(err)
}
}
impl From<InvalidTransaction> for crate::ApplyError {
fn from(invalid: InvalidTransaction) -> crate::ApplyError {
TransactionValidityError::from(invalid).into()
}
}
impl From<UnknownTransaction> for crate::ApplyError {
fn from(unknown: UnknownTransaction) -> crate::ApplyError {
TransactionValidityError::from(unknown).into()
}
}
/// Information on a transaction's validity and, if valid, on how it relates to other transactions.
pub type TransactionValidity = Result<ValidTransaction, TransactionValidityError>;
impl Into<TransactionValidity> for InvalidTransaction {
fn into(self) -> TransactionValidity {
Err(self.into())
}
}
impl Into<TransactionValidity> for UnknownTransaction {
fn into(self) -> TransactionValidity {
Err(self.into())
}
}
/// Information concerning a valid transaction.
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
pub struct ValidTransaction {
/// Priority of the transaction.
///
/// Priority determines the ordering of two transactions that have all
/// their dependencies (required tags) satisfied.
pub priority: TransactionPriority,
/// Transaction dependencies
///
/// A non-empty list signifies that some other transactions which provide
/// given tags are required to be included before that one.
pub requires: Vec<TransactionTag>,
/// Provided tags
///
/// A list of tags this transaction provides. Successfully importing the transaction
/// will enable other transactions that depend on (require) those tags to be included as well.
/// Provided and required tags allow Substrate to build a dependency graph of transactions
/// and import them in the right (linear) order.
pub provides: Vec<TransactionTag>,
/// Transaction longevity
///
/// Longevity describes minimum number of blocks the validity is correct.
/// After this period transaction should be removed from the pool or revalidated.
pub longevity: TransactionLongevity,
/// A flag indicating if the transaction should be propagated to other peers.
///
/// By setting `false` here the transaction will still be considered for
/// including in blocks that are authored on the current node, but will
/// never be sent to other peers.
pub propagate: bool,
}
impl Default for ValidTransaction {
fn default() -> Self {
ValidTransaction {
priority: 0,
requires: vec![],
provides: vec![],
longevity: TransactionLongevity::max_value(),
propagate: true,
}
}
}
impl ValidTransaction {
/// Combine two instances into one, as a best effort. This will take the superset of each of the
/// `provides` and `requires` tags, it will sum the priorities, take the minimum longevity and
/// the logic *And* of the propagate flags.
pub fn combine_with(mut self, mut other: ValidTransaction) -> Self {
ValidTransaction {
priority: self.priority.saturating_add(other.priority),
requires: { self.requires.append(&mut other.requires); self.requires },
provides: { self.provides.append(&mut other.provides); self.provides },
longevity: self.longevity.min(other.longevity),
propagate: self.propagate && other.propagate,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_encode_and_decode() {
let v: TransactionValidity = Ok(ValidTransaction {
priority: 5,
requires: vec![vec![1, 2, 3, 4]],
provides: vec![vec![4, 5, 6]],
longevity: 42,
propagate: false,
});
let encoded = v.encode();
assert_eq!(
encoded,
vec![0, 5, 0, 0, 0, 0, 0, 0, 0, 4, 16, 1, 2, 3, 4, 4, 12, 4, 5, 6, 42, 0, 0, 0, 0, 0, 0, 0, 0]
);
// decode back
assert_eq!(TransactionValidity::decode(&mut &*encoded), Ok(v));
}
}
@@ -0,0 +1,220 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! # Primitives for transaction weighting.
//!
//! All dispatchable functions defined in `decl_module!` must provide two trait implementations:
//! - [`WeightData`]: To determine the weight of the dispatch.
//! - [`ClassifyDispatch`]: To determine the class of the dispatch. See the enum definition for
//! more information on dispatch classes.
//!
//! Every dispatchable function is responsible for providing this data via an optional `#[weight =
//! $x]` attribute. In this snipped, `$x` can be any user provided struct that implements the
//! two aforementioned traits.
//!
//! Substrate then bundles then output information of the two traits into [`DispatchInfo`] struct
//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` variants, and opaque
//! extrinsic types.
//!
//! If no `#[weight]` is defined, the macro automatically injects the `Default` implementation of
//! the [`SimpleDispatchInfo`].
//!
//! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct
//! (something that does not implement `Weighable`) is passed in.
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use impl_trait_for_tuples::impl_for_tuples;
use codec::{Encode, Decode};
use arithmetic::traits::{Bounded, Zero};
use crate::RuntimeDebug;
/// Re-export priority as type
pub use crate::transaction_validity::TransactionPriority;
/// Numeric range of a transaction weight.
pub type Weight = u32;
/// Means of weighing some particular kind of data (`T`).
pub trait WeighData<T> {
/// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be
/// a tuple of all arguments given to the function (except origin).
fn weigh_data(&self, target: T) -> Weight;
}
/// Means of classifying a dispatchable function.
pub trait ClassifyDispatch<T> {
/// Classify the dispatch function based on input data `target` of type `T`. When implementing
/// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except
/// origin).
fn classify_dispatch(&self, target: T) -> DispatchClass;
}
/// Means of determining the weight of a block's lifecycle hooks: on_initialize, on_finalize and
/// such.
pub trait WeighBlock<BlockNumber> {
/// Return the weight of the block's on_initialize hook.
fn on_initialize(_: BlockNumber) -> Weight { Zero::zero() }
/// Return the weight of the block's on_finalize hook.
fn on_finalize(_: BlockNumber) -> Weight { Zero::zero() }
}
/// Maybe I can do something to remove the duplicate code here.
#[impl_for_tuples(30)]
impl<BlockNumber: Copy> WeighBlock<BlockNumber> for SingleModule {
fn on_initialize(n: BlockNumber) -> Weight {
let mut accumulated_weight: Weight = Zero::zero();
for_tuples!(
#( accumulated_weight = accumulated_weight.saturating_add(SingleModule::on_initialize(n)); )*
);
accumulated_weight
}
fn on_finalize(n: BlockNumber) -> Weight {
let mut accumulated_weight: Weight = Zero::zero();
for_tuples!(
#( accumulated_weight = accumulated_weight.saturating_add(SingleModule::on_finalize(n)); )*
);
accumulated_weight
}
}
/// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions
/// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`).
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)]
pub enum DispatchClass {
/// A normal dispatch.
Normal,
/// An operational dispatch.
Operational,
}
impl Default for DispatchClass {
fn default() -> Self {
DispatchClass::Normal
}
}
impl From<SimpleDispatchInfo> for DispatchClass {
fn from(tx: SimpleDispatchInfo) -> Self {
match tx {
SimpleDispatchInfo::FixedOperational(_) => DispatchClass::Operational,
SimpleDispatchInfo::MaxOperational => DispatchClass::Operational,
SimpleDispatchInfo::FreeOperational => DispatchClass::Operational,
SimpleDispatchInfo::FixedNormal(_) => DispatchClass::Normal,
SimpleDispatchInfo::MaxNormal => DispatchClass::Normal,
SimpleDispatchInfo::FreeNormal => DispatchClass::Normal,
}
}
}
/// A bundle of static information collected from the `#[weight = $x]` attributes.
#[cfg_attr(feature = "std", derive(PartialEq, Eq))]
#[derive(Clone, Copy, Default, RuntimeDebug)]
pub struct DispatchInfo {
/// Weight of this transaction.
pub weight: Weight,
/// Class of this transaction.
pub class: DispatchClass,
}
impl DispatchInfo {
/// Determine if this dispatch should pay the base length-related fee or not.
pub fn pay_length_fee(&self) -> bool {
match self.class {
DispatchClass::Normal => true,
// For now we assume all operational transactions don't pay the length fee.
DispatchClass::Operational => false,
}
}
}
/// A `Dispatchable` function (aka transaction) that can carry some static information along with
/// it, using the `#[weight]` attribute.
pub trait GetDispatchInfo {
/// Return a `DispatchInfo`, containing relevant information of this dispatch.
///
/// This is done independently of its encoded size.
fn get_dispatch_info(&self) -> DispatchInfo;
}
/// Default type used with the `#[weight = x]` attribute in a substrate chain.
///
/// A user may pass in any other type that implements the correct traits. If not, the `Default`
/// implementation of [`SimpleDispatchInfo`] is used.
///
/// For each generalized group (`Normal` and `Operation`):
/// - A `Fixed` variant means weight fee is charged normally and the weight is the number
/// specified in the inner value of the variant.
/// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion.
/// - A `Max` variant is equal to `::Fixed(Weight::max_value())`.
///
/// As for the generalized groups themselves:
/// - `Normal` variants will be assigned a priority proportional to their weight. They can only
/// consume a portion (defined in the system module) of the maximum block resource limits.
/// - `Operational` variants will be assigned the maximum priority. They can potentially consume
/// the entire block resource limit.
#[derive(Clone, Copy)]
pub enum SimpleDispatchInfo {
/// A normal dispatch with fixed weight.
FixedNormal(Weight),
/// A normal dispatch with the maximum weight.
MaxNormal,
/// A normal dispatch with no weight.
FreeNormal,
/// An operational dispatch with fixed weight.
FixedOperational(Weight),
/// An operational dispatch with the maximum weight.
MaxOperational,
/// An operational dispatch with no weight.
FreeOperational,
}
impl<T> WeighData<T> for SimpleDispatchInfo {
fn weigh_data(&self, _: T) -> Weight {
match self {
SimpleDispatchInfo::FixedNormal(w) => *w,
SimpleDispatchInfo::MaxNormal => Bounded::max_value(),
SimpleDispatchInfo::FreeNormal => Bounded::min_value(),
SimpleDispatchInfo::FixedOperational(w) => *w,
SimpleDispatchInfo::MaxOperational => Bounded::max_value(),
SimpleDispatchInfo::FreeOperational => Bounded::min_value(),
}
}
}
impl<T> ClassifyDispatch<T> for SimpleDispatchInfo {
fn classify_dispatch(&self, _: T) -> DispatchClass {
DispatchClass::from(*self)
}
}
impl Default for SimpleDispatchInfo {
fn default() -> Self {
// Default weight of all transactions.
SimpleDispatchInfo::FixedNormal(10_000)
}
}
impl SimpleDispatchInfo {
/// An _additive zero_ variant of SimpleDispatchInfo.
pub fn zero() -> Self {
Self::FixedNormal(0)
}
}