New extrinsic dispatch model (#678)

* System and Balances switched to new call model

* Fixed up executive for new pardigm

* Consensus works with Origin

* Timestamp ported over

* Session now compatible

* Ported staking

* Treasury compatible

* Expunge MaybeEmpty

* Make democracy work

* Council compatible

* Remove some aux-dispatch stuff and fix balances

* Rename aux -> origin, fix contracts

* Fix test

* Fix example

* Update macro to remove superfluous cruft

* Make work with new macro

* Tests

* Fix some tests

* Tests

* Fix grumbles

* Final grumble
This commit is contained in:
Gav Wood
2018-09-07 19:28:18 +02:00
committed by GitHub
parent 6571842c99
commit 761bc9f763
46 changed files with 1753 additions and 1918 deletions
-4
View File
@@ -2769,15 +2769,11 @@ dependencies = [
"substrate-codec-derive 0.1.0",
"substrate-primitives 0.1.0",
"substrate-runtime-balances 0.1.0",
"substrate-runtime-consensus 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-session 0.1.0",
"substrate-runtime-staking 0.1.0",
"substrate-runtime-std 0.1.0",
"substrate-runtime-support 0.1.0",
"substrate-runtime-system 0.1.0",
"substrate-runtime-timestamp 0.1.0",
]
[[package]]
+38 -35
View File
@@ -52,11 +52,11 @@ mod tests {
use primitives::{twox_128, KeccakHasher};
use demo_primitives::{Hash, BlockNumber, AccountId};
use runtime_primitives::traits::Header as HeaderT;
use runtime_primitives::{ApplyOutcome, ApplyError, ApplyResult, MaybeUnsigned};
use runtime_primitives::{ApplyOutcome, ApplyError, ApplyResult};
use {balances, staking, session, system, consensus};
use system::{EventRecord, Phase};
use demo_runtime::{Header, Block, UncheckedExtrinsic, Extrinsic, Call, Runtime, Balances,
BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, BareExtrinsic, System, Event};
use demo_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, Event};
use ed25519::{Public, Pair};
const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm");
@@ -77,20 +77,32 @@ mod tests {
AccountId::from(Keyring::Bob.to_raw_public())
}
fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic {
match xt.signed {
Some(signed) => {
let payload = (xt.index, xt.function);
let pair = Pair::from(Keyring::from_public(Public::from_raw(signed.clone().into())).unwrap());
let signature = pair.sign(&payload.encode()).into();
UncheckedExtrinsic {
signature: Some((balances::address::Address::Id(signed), signature)),
index: payload.0,
function: payload.1,
}
}
None => UncheckedExtrinsic {
signature: None,
index: xt.index,
function: xt.function,
},
}
}
fn xt() -> UncheckedExtrinsic {
let extrinsic = BareExtrinsic {
signed: alice(),
sign(CheckedExtrinsic {
signed: Some(alice()),
index: 0,
function: Call::Balances(balances::Call::transfer::<Runtime>(bob().into(), 69)),
};
let signature = MaybeUnsigned(Keyring::from_raw_public(extrinsic.signed.0.clone()).unwrap()
.sign(&extrinsic.encode()).into());
let extrinsic = Extrinsic {
signed: extrinsic.signed.into(),
index: extrinsic.index,
function: extrinsic.function,
};
UncheckedExtrinsic::new(extrinsic, signature)
})
}
fn from_block_number(n: u64) -> Header {
@@ -225,19 +237,10 @@ mod tests {
}.build_storage().unwrap().into()
}
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, extrinsics: Vec<BareExtrinsic>) -> (Vec<u8>, Hash) {
fn construct_block(number: BlockNumber, parent_hash: Hash, state_root: Hash, extrinsics: Vec<CheckedExtrinsic>) -> (Vec<u8>, Hash) {
use triehash::ordered_trie_root;
let extrinsics = extrinsics.into_iter().map(|extrinsic| {
let signature = MaybeUnsigned(Pair::from(Keyring::from_public(Public::from_raw(extrinsic.signed.0.clone())).unwrap())
.sign(&extrinsic.encode()).into());
let extrinsic = Extrinsic {
signed: extrinsic.signed.into(),
index: extrinsic.index,
function: extrinsic.function,
};
UncheckedExtrinsic::new(extrinsic, signature)
}).collect::<Vec<_>>();
let extrinsics = extrinsics.into_iter().map(sign).collect::<Vec<_>>();
let extrinsics_root = ordered_trie_root::<KeccakHasher, _, _>(extrinsics.iter().map(Encode::encode)).0.into();
@@ -261,8 +264,8 @@ mod tests {
// hex!("3437bf4b182ab17bb322af5c67e55f6be487a77084ad2b4e27ddac7242e4ad21").into(),
// Keccak
hex!("508a68a0918f614b86b2ccfd0975754f6d2abe1026a34e42d6d8d5abdf4db010").into(),
vec![BareExtrinsic {
signed: alice(),
vec![CheckedExtrinsic {
signed: Some(alice()),
index: 0,
function: Call::Balances(balances::Call::transfer(bob().into(), 69)),
}]
@@ -276,15 +279,15 @@ mod tests {
// Blake
// hex!("741fcb660e6fa9f625fbcd993b49f6c1cc4040f5e0cc8727afdedf11fd3c464b").into(),
// Keccak
hex!("171f1b2c01c9c616e40ee2d842a699286b50a5a74874b56d826094dadedffb27").into(),
hex!("a72ec570c7642d9ad06ef0e5dd37be65fb04b71e0ab52b3927d760ed6c777a1f").into(),
vec![
BareExtrinsic {
signed: bob(),
CheckedExtrinsic {
signed: Some(bob()),
index: 0,
function: Call::Balances(balances::Call::transfer(alice().into(), 5)),
},
BareExtrinsic {
signed: alice(),
CheckedExtrinsic {
signed: Some(alice()),
index: 1,
function: Call::Balances(balances::Call::transfer(bob().into(), 15)),
}
@@ -300,10 +303,10 @@ mod tests {
// hex!("2c7231a9c210a7aa4bea169d944bc4aaacd517862b244b8021236ffa7f697991").into(),
// Keccak
hex!("e45221804da3a3609454d4e09debe6364cc6af63c2ff067d802d1af62fea32ae").into(),
vec![BareExtrinsic {
signed: alice(),
vec![CheckedExtrinsic {
signed: Some(alice()),
index: 0,
function: Call::Consensus(consensus::Call::remark(vec![0; 60000])),
function: Call::Consensus(consensus::Call::remark(vec![0; 60000000])),
}]
)
}
+1 -1
View File
@@ -53,4 +53,4 @@ pub type Index = u64;
pub type Hash = primitives::H256;
/// Alias to 512-bit hash when used in the context of a signature on the relay chain.
pub type Signature = runtime_primitives::MaybeUnsigned<runtime_primitives::Ed25519Signature>;
pub type Signature = runtime_primitives::Ed25519Signature;
+33 -51
View File
@@ -64,7 +64,7 @@ pub use runtime_primitives::BuildStorage;
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
/// Runtime runtime type used to parameterize the various modules.
/// Runtime type used to collate and parameterize the various modules.
pub struct Runtime;
/// Runtime version.
@@ -76,15 +76,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
impl_version: 0,
};
/// Version module for this concrete runtime.
pub type Version = version::Module<Runtime>;
impl version::Trait for Runtime {
const VERSION: RuntimeVersion = VERSION;
}
impl system::Trait for Runtime {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = Index;
type BlockNumber = BlockNumber;
type Hash = Hash;
@@ -154,7 +147,7 @@ impl staking::Trait for Runtime {
pub type Staking = staking::Module<Runtime>;
impl democracy::Trait for Runtime {
type Proposal = PrivCall;
type Proposal = Call;
}
/// Democracy module for this concrete runtime.
@@ -179,20 +172,13 @@ impl_outer_log! {
}
}
impl DigestItem for Log {
type AuthoritiesChange = consensus::AuthoritiesChange<SessionKey>;
fn as_authorities_change(&self) -> Option<&Self::AuthoritiesChange> {
match *self {
Log::consensus(ref item) => item.as_authorities_change(),
}
impl_outer_origin! {
pub enum Origin for Runtime {
}
}
impl_outer_dispatch! {
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum Call where aux: <Runtime as system::Trait>::PublicAux {
pub enum Call where origin: Origin {
Consensus,
Balances,
Session,
@@ -202,38 +188,8 @@ impl_outer_dispatch! {
Council,
CouncilVoting,
}
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum PrivCall {
Consensus,
Balances,
Session,
Staking,
Democracy,
Council,
CouncilVoting,
}
}
/// The address format for describing accounts.
pub type Address = balances::Address<Runtime>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Index, Call, Signature>;
/// Extrinsic type as expected by this runtime. This is not the type that is signed.
pub type Extrinsic = generic::Extrinsic<Address, Index, Call>;
/// Extrinsic type that is signed.
pub type BareExtrinsic = generic::Extrinsic<AccountId, Index, Call>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances,
(((((), Council), Democracy), Staking), Session)>;
impl_outer_config! {
pub struct GenesisConfig for Runtime {
ConsensusConfig => consensus,
@@ -247,9 +203,35 @@ impl_outer_config! {
}
}
impl DigestItem for Log {
type AuthoritiesChange = consensus::AuthoritiesChange<SessionKey>;
fn as_authorities_change(&self) -> Option<&Self::AuthoritiesChange> {
match *self {
Log::consensus(ref item) => item.as_authorities_change(),
}
}
}
/// The address format for describing accounts.
pub type Address = balances::Address<Runtime>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Index, Call, Signature>;
/// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances,
(((((), Council), Democracy), Staking), Session)>;
pub mod api {
impl_stubs!(
version => |()| super::Version::version(),
version => |()| super::VERSION,
authorities => |()| super::Consensus::authorities(),
events => |()| super::System::events(),
initialise_block => |header| super::Executive::initialise_block(&header),
-1
View File
@@ -688,7 +688,6 @@ dependencies = [
"serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)",
"substrate-codec 0.1.0",
"substrate-codec-derive 0.1.0",
"substrate-runtime-io 0.1.0",
"substrate-runtime-primitives 0.1.0",
"substrate-runtime-std 0.1.0",
@@ -27,29 +27,11 @@ pub use codec::{Codec, Decode, Encode, Input, Output};
pub type Result = result::Result<(), &'static str>;
pub trait Dispatchable {
type Origin;
type Trait;
fn dispatch(self) -> Result;
fn dispatch(self, origin: Self::Origin) -> Result;
}
pub trait AuxDispatchable {
type Aux;
type Trait;
fn dispatch(self, aux: &Self::Aux) -> Result;
}
#[cfg(feature = "std")]
pub trait AuxCallable {
type Call: AuxDispatchable + Codec + ::serde::Serialize + Clone + PartialEq + Eq;
}
#[cfg(not(feature = "std"))]
pub trait AuxCallable {
type Call: AuxDispatchable + Codec + Clone + PartialEq + Eq;
}
// dirty hack to work around serde_derive issue
// https://github.com/rust-lang/rust/issues/51331
pub type AuxCallableCallFor<A> = <A as AuxCallable>::Call;
#[cfg(feature = "std")]
pub trait Callable {
type Call: Dispatchable + Codec + ::serde::Serialize + Clone + PartialEq + Eq;
@@ -59,9 +41,9 @@ pub trait Callable {
type Call: Dispatchable + Codec + Clone + PartialEq + Eq;
}
// dirty hack to work around serde_derive issue.
// dirty hack to work around serde_derive issue
// https://github.com/rust-lang/rust/issues/51331
pub type CallableCallFor<C> = <C as Callable>::Call;
pub type CallableCallFor<A> = <A as Callable>::Call;
#[cfg(feature = "std")]
pub trait Parameter: Codec + serde::Serialize + Clone + Eq + fmt::Debug {}
@@ -81,8 +63,15 @@ impl<T> Parameter for T where T: Codec + Clone + Eq {}
macro_rules! decl_module {
(
$(#[$attr:meta])*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$($rest:tt)*
pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>
for enum $call_type:ident where origin: $origin_type:ty {$(
$(#[doc = $doc_attr:tt])*
fn $fn_name:ident(origin
$(
, $param_name:ident : $param:ty
)*
) -> $result:ty;
)*}
) => {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
@@ -91,244 +80,20 @@ macro_rules! decl_module {
// serde-derive for when we attempt to derive `Deserialize` on these types,
// in a situation where we've imported `substrate_runtime_support` as another name.
#[cfg(feature = "std")]
$(#[$attr])*
pub struct $mod_type<$trait_instance: $trait_name>(::std::marker::PhantomData<$trait_instance>);
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg(not(feature = "std"))]
$(#[$attr])*
pub struct $mod_type<$trait_instance: $trait_name>(::core::marker::PhantomData<$trait_instance>);
decl_dispatch! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
__impl_json_metadata! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
};
(
$(#[$attr:meta])*
struct $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$($rest:tt)*
) => {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg(feature = "std")]
$(#[$attr])*
struct $mod_type<$trait_instance: $trait_name>(::std::marker::PhantomData<$trait_instance>);
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg(not(feature = "std"))]
$(#[$attr])*
struct $mod_type<$trait_instance: $trait_name>(::core::marker::PhantomData<$trait_instance>);
decl_dispatch! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
__impl_json_metadata! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
}
}
/// Implement several dispatch modules to create a pairing of a dispatch trait and enum.
#[macro_export]
macro_rules! decl_dispatch {
// WITHOUT AUX
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$(#[$attr:meta])*
pub enum $call_type:ident {
$(
$(#[$fn_attr:meta])*
fn $fn_name:ident(
$(
$param_name:ident : $param:ty
),*
) -> $result:ty;
)*
}
$($rest:tt)*
) => {
__decl_dispatch_module_without_aux! {
impl for $mod_type<$trait_instance: $trait_name>;
$(#[$attr])*
pub enum $call_type;
$(
fn $fn_name( $( $param_name: $param ),* ) -> $result;
)*
}
decl_dispatch! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
};
// WITH AUX
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$(#[$attr:meta])*
pub enum $call_type:ident where aux: $aux_type:ty {
$(
$(#[$fn_attr:meta])*
fn $fn_name:ident(aux
$(
, $param_name:ident : $param:ty
)*
) -> $result:ty;
)*
}
$($rest:tt)*
) => {
__decl_dispatch_module_with_aux! {
impl for $mod_type<$trait_instance: $trait_name>;
$(#[$attr])*
pub enum $call_type where aux: $aux_type;
$(
fn $fn_name(aux $(, $param_name: $param )*) -> $result;
)*
}
decl_dispatch! {
impl for $mod_type<$trait_instance: $trait_name>;
$($rest)*
}
};
// BASE CASE
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
) => {
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
pub fn aux_dispatch<D: $crate::dispatch::AuxDispatchable<Trait = $trait_instance>>(d: D, aux: &D::Aux) -> $crate::dispatch::Result {
d.dispatch(aux)
}
pub fn dispatch<D: $crate::dispatch::Dispatchable<Trait = $trait_instance>>(d: D) -> $crate::dispatch::Result {
d.dispatch()
}
}
}
}
#[macro_export]
#[doc(hidden)]
/// Implement a single dispatch modules to create a pairing of a dispatch trait and enum.
macro_rules! __decl_dispatch_module_without_aux {
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$(#[$attr:meta])*
pub enum $call_type:ident;
$(
fn $fn_name:ident(
$(
$param_name:ident : $param:ty
),*
)
-> $result:ty;
)*
) => {
__decl_dispatch_module_common! {
impl for $mod_type<$trait_instance: $trait_name>;
$(#[$attr])*
pub enum $call_type;
$( fn $fn_name( $( $param_name : $param ),* ) -> $result; )*
}
impl<$trait_instance: $trait_name> $crate::dispatch::Dispatchable
for $call_type<$trait_instance>
{
type Trait = $trait_instance;
fn dispatch(self) -> $crate::dispatch::Result {
match self {
$(
$call_type::$fn_name( $( $param_name ),* ) =>
<$mod_type<$trait_instance>>::$fn_name( $( $param_name ),* ),
)*
$call_type::__PhantomItem(_) => { panic!("__PhantomItem should never be used.") },
}
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::Callable
for $mod_type<$trait_instance>
{
type Call = $call_type<$trait_instance>;
}
}
}
#[macro_export]
#[doc(hidden)]
/// Implement a single dispatch modules to create a pairing of a dispatch trait and enum.
macro_rules! __decl_dispatch_module_with_aux {
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$(#[$attr:meta])*
pub enum $call_type:ident where aux: $aux_type:ty;
$(
fn $fn_name:ident(aux
$(
, $param_name:ident : $param:ty
)*
)
-> $result:ty;
)*
) => {
__decl_dispatch_module_common! {
impl for $mod_type<$trait_instance: $trait_name>;
$(#[$attr])*
pub enum $call_type;
$( fn $fn_name( $( $param_name : $param ),* ) -> $result; )*
}
impl<$trait_instance: $trait_name> $crate::dispatch::AuxDispatchable
for $call_type<$trait_instance>
{
type Trait = $trait_instance;
type Aux = $aux_type;
fn dispatch(self, aux: &Self::Aux) -> $crate::dispatch::Result {
match self {
$(
$call_type::$fn_name( $( $param_name ),* ) =>
<$mod_type<$trait_instance>>::$fn_name( aux $(, $param_name )* ),
)*
$call_type::__PhantomItem(_) => { panic!("__PhantomItem should never be used.") },
}
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::AuxCallable
for $mod_type<$trait_instance>
{
type Call = $call_type<$trait_instance>;
}
};
}
/// Implement a single dispatch modules to create a pairing of a dispatch trait and enum.
#[macro_export]
#[doc(hidden)]
macro_rules! __decl_dispatch_module_common {
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$(#[$attr:meta])*
pub enum $call_type:ident;
$(
fn $fn_name:ident(
$(
$param_name:ident : $param:ty
),*
)
-> $result:ty;
)*
) => {
#[cfg(feature = "std")]
$(#[$attr])*
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum $call_type<$trait_instance: $trait_name> {
__PhantomItem(::std::marker::PhantomData<$trait_instance>),
__OtherPhantomItem(::std::marker::PhantomData<$trait_instance>),
$(
#[allow(non_camel_case_types)]
$fn_name ( $( $param ),* ),
@@ -337,8 +102,10 @@ macro_rules! __decl_dispatch_module_common {
#[cfg(not(feature = "std"))]
$(#[$attr])*
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum $call_type<$trait_instance: $trait_name> {
__PhantomItem(::core::marker::PhantomData<$trait_instance>),
__OtherPhantomItem(::core::marker::PhantomData<$trait_instance>),
$(
#[allow(non_camel_case_types)]
$fn_name ( $( $param ),* ),
@@ -356,30 +123,30 @@ macro_rules! __decl_dispatch_module_common {
$call_type::$fn_name( $( ref $param_name ),* ) =>
$call_type::$fn_name( $( $param_name.clone() ),* )
,)*
$call_type::__PhantomItem(_) => unreachable!(),
_ => unreachable!(),
}
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::PartialEq
for $call_type<$trait_instance>
{
fn eq(&self, other: &Self) -> bool {
fn eq(&self, _other: &Self) -> bool {
match *self {
$(
$call_type::$fn_name( $( ref $param_name ),* ) => {
let self_params = ( $( $param_name, )* );
if let $call_type::$fn_name( $( ref $param_name ),* ) = *other {
if let $call_type::$fn_name( $( ref $param_name ),* ) = *_other {
self_params == ( $( $param_name, )* )
} else {
if let $call_type::__PhantomItem(_) = *other {
unreachable!()
} else {
false
match *_other {
$call_type::__PhantomItem(_) => unreachable!(),
$call_type::__OtherPhantomItem(_) => unreachable!(),
_ => false,
}
}
}
)*
$call_type::__PhantomItem(_) => unreachable!(),
_ => unreachable!(),
}
}
}
@@ -391,33 +158,65 @@ macro_rules! __decl_dispatch_module_common {
impl<$trait_instance: $trait_name> $crate::dispatch::fmt::Debug
for $call_type<$trait_instance>
{
fn fmt(&self, f: &mut $crate::dispatch::fmt::Formatter) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> {
fn fmt(&self, _f: &mut $crate::dispatch::fmt::Formatter) -> $crate::dispatch::result::Result<(), $crate::dispatch::fmt::Error> {
match *self {
$(
$call_type::$fn_name( $( ref $param_name ),* ) =>
write!(f, "{}{:?}",
write!(_f, "{}{:?}",
stringify!($fn_name),
( $( $param_name.clone(), )* )
)
,)*
$call_type::__PhantomItem(_) => unreachable!(),
_ => unreachable!(),
}
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::Decode for $call_type<$trait_instance> {
fn decode<I: $crate::dispatch::Input>(input: &mut I) -> Option<Self> {
let input_id = input.read_byte()?;
__impl_decode!(input; input_id; 0; $call_type; $( fn $fn_name( $( $param_name ),* ); )*)
let _input_id = input.read_byte()?;
__impl_decode!(input; _input_id; 0; $call_type; $( fn $fn_name( $( $param_name ),* ); )*)
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::Encode for $call_type<$trait_instance> {
fn encode_to<W: $crate::dispatch::Output>(&self, dest: &mut W) {
__impl_encode!(dest; *self; 0; $call_type; $( fn $fn_name( $( $param_name ),* ); )*);
fn encode_to<W: $crate::dispatch::Output>(&self, _dest: &mut W) {
__impl_encode!(_dest; *self; 0; $call_type; $( fn $fn_name( $( $param_name ),* ); )*);
if let $call_type::__PhantomItem(_) = *self { unreachable!() }
if let $call_type::__OtherPhantomItem(_) = *self { unreachable!() }
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::Dispatchable
for $call_type<$trait_instance>
{
type Trait = $trait_instance;
type Origin = $origin_type;
fn dispatch(self, _origin: Self::Origin) -> $crate::dispatch::Result {
match self {
$(
$call_type::$fn_name( $( $param_name ),* ) =>
<$mod_type<$trait_instance>>::$fn_name( _origin $(, $param_name )* ),
)*
_ => { panic!("__PhantomItem should never be used.") },
}
}
}
impl<$trait_instance: $trait_name> $crate::dispatch::Callable
for $mod_type<$trait_instance>
{
type Call = $call_type<$trait_instance>;
}
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
pub fn dispatch<D: $crate::dispatch::Dispatchable<Trait = $trait_instance>>(d: D, origin: D::Origin) -> $crate::dispatch::Result {
d.dispatch(origin)
}
}
__impl_json_metadata! {
$mod_type $trait_instance $trait_name $call_type $origin_type
{$( $(#[doc = $doc_attr])* fn $fn_name(origin $(, $param_name : $param )*) -> $result; )*}
}
}
}
@@ -492,10 +291,7 @@ macro_rules! __impl_encode {
}
pub trait IsSubType<T: Callable> {
fn is_sub_type(&self) -> Option<&<T as Callable>::Call>;
}
pub trait IsAuxSubType<T: AuxCallable> {
fn is_aux_sub_type(&self) -> Option<&<T as AuxCallable>::Call>;
fn is_aux_sub_type(&self) -> Option<&<T as Callable>::Call>;
}
/// Implement a meta-dispatch module to dispatch to other dispatchers.
@@ -504,47 +300,7 @@ macro_rules! impl_outer_dispatch {
() => ();
(
$(#[$attr:meta])*
pub enum $call_type:ident where aux: $aux:ty {
$(
$camelcase:ident,
)*
}
$( $rest:tt )*
) => {
$(#[$attr])*
pub enum $call_type {
$(
$camelcase ( $crate::dispatch::AuxCallableCallFor<$camelcase> )
,)*
}
__impl_outer_dispatch_common! { $call_type, $($camelcase,)* }
impl $crate::dispatch::AuxDispatchable for $call_type {
type Aux = $aux;
type Trait = $call_type;
fn dispatch(self, aux: &$aux) -> $crate::dispatch::Result {
match self {
$(
$call_type::$camelcase(call) => call.dispatch(&aux),
)*
}
}
}
$(
impl $crate::dispatch::IsAuxSubType<$camelcase> for $call_type {
fn is_aux_sub_type(&self) -> Option<&<$camelcase as $crate::dispatch::AuxCallable>::Call> {
if let $call_type::$camelcase ( ref r ) = *self {
Some(r)
} else {
None
}
}
}
)*
impl_outer_dispatch!{ $($rest)* }
};
(
$(#[$attr:meta])*
pub enum $call_type:ident {
pub enum $call_type:ident where origin: $origin:ty {
$(
$camelcase:ident,
)*
@@ -552,6 +308,8 @@ macro_rules! impl_outer_dispatch {
$( $rest:tt )*
) => {
$(#[$attr])*
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub enum $call_type {
$(
$camelcase ( $crate::dispatch::CallableCallFor<$camelcase> )
@@ -559,18 +317,19 @@ macro_rules! impl_outer_dispatch {
}
__impl_outer_dispatch_common! { $call_type, $($camelcase,)* }
impl $crate::dispatch::Dispatchable for $call_type {
type Origin = $origin;
type Trait = $call_type;
fn dispatch(self) -> $crate::dispatch::Result {
fn dispatch(self, origin: $origin) -> $crate::dispatch::Result {
match self {
$(
$call_type::$camelcase(call) => call.dispatch(),
$call_type::$camelcase(call) => call.dispatch(origin),
)*
}
}
}
$(
impl $crate::dispatch::IsSubType<$camelcase> for $call_type {
fn is_sub_type(&self) -> Option<&<$camelcase as $crate::dispatch::Callable>::Call> {
fn is_aux_sub_type(&self) -> Option<&<$camelcase as $crate::dispatch::Callable>::Call> {
if let $call_type::$camelcase ( ref r ) = *self {
Some(r)
} else {
@@ -611,13 +370,13 @@ macro_rules! __impl_outer_dispatch_common {
#[doc(hidden)]
macro_rules! __impl_json_metadata {
(
impl for $mod_type:ident<$trait_instance:ident: $trait_name:ident>;
$mod_type:ident $trait_instance:ident $trait_name:ident
$($rest:tt)*
) => {
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
pub fn json_metadata() -> &'static str {
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "calls": ["#,
__calls_to_json!(""; $($rest)*), " ] }")
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "call": [ "#,
__call_to_json!($($rest)*), " ] }")
}
}
}
@@ -626,66 +385,31 @@ macro_rules! __impl_json_metadata {
/// Convert the list of calls into their JSON representation, joined by ",".
#[macro_export]
#[doc(hidden)]
macro_rules! __calls_to_json {
// WITHOUT AUX
(
$prefix_str:tt;
$(#[$attr:meta])*
pub enum $call_type:ident {
$(
$(#[doc = $doc_attr:tt])*
fn $fn_name:ident(
$(
$param_name:ident : $param:ty
),*
) -> $result:ty;
)*
}
$($rest:tt)*
) => {
concat!($prefix_str, " ",
r#"{ "name": ""#, stringify!($call_type),
r#"", "functions": {"#,
__functions_to_json!(""; 0; $(
fn $fn_name( $( $param_name: $param ),* ) -> $result;
__function_doc_to_json!(""; $($doc_attr)*);
)*), " } }", __calls_to_json!(","; $($rest)*)
)
};
macro_rules! __call_to_json {
// WITH AUX
(
$prefix_str:tt;
$(#[$attr:meta])*
pub enum $call_type:ident where aux: $aux_type:ty {
$(
$call_type:ident $origin_type:ty
{$(
$(#[doc = $doc_attr:tt])*
fn $fn_name:ident(aux
fn $fn_name:ident(origin
$(
, $param_name:ident : $param:ty
)*
) -> $result:ty;
)*
}
$($rest:tt)*
)*}
) => {
concat!($prefix_str, " ",
concat!(
r#"{ "name": ""#, stringify!($call_type),
r#"", "functions": {"#,
__functions_to_json!(""; 0; $aux_type; $(
fn $fn_name(aux $(, $param_name: $param )* ) -> $result;
__functions_to_json!(""; 0; $origin_type; $(
fn $fn_name(origin $(, $param_name: $param )* ) -> $result;
__function_doc_to_json!(""; $($doc_attr)*);
)*), " } }", __calls_to_json!(","; $($rest)*)
)*), " } }"
)
};
// BASE CASE
(
$prefix_str:tt;
) => {
""
}
}
/// Convert a list of function into their JSON representation, joined by ",".
/// Convert a list of functions into their JSON representation, joined by ",".
#[macro_export]
#[doc(hidden)]
macro_rules! __functions_to_json {
@@ -713,8 +437,8 @@ macro_rules! __functions_to_json {
(
$prefix_str:tt;
$fn_id:expr;
$aux_type:ty;
fn $fn_name:ident(aux
$origin_type:ty;
fn $fn_name:ident(origin
$(
, $param_name:ident : $param:ty
)*
@@ -725,19 +449,19 @@ macro_rules! __functions_to_json {
concat!($prefix_str, " ",
__function_to_json!(
fn $fn_name(
aux: $aux_type
origin: $origin_type
$(, $param_name : $param)*
) -> $result;
$fn_doc;
$fn_id;
), __functions_to_json!(","; $fn_id + 1; $aux_type; $($rest)*)
), __functions_to_json!(","; $fn_id + 1; $origin_type; $($rest)*)
)
};
// BASE CASE
(
$prefix_str:tt;
$fn_id:expr;
$($aux_type:ty;)*
$($origin_type:ty;)*
) => {
""
}
@@ -799,75 +523,47 @@ mod tests {
use serde_json;
pub trait Trait {
type PublicAux;
type Origin;
}
decl_module! {
pub struct Module<T: Trait>;
#[derive(Serialize, Deserialize)]
pub enum Call where aux: T::PublicAux {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// Hi, this is a comment.
fn aux_0(aux) -> Result;
fn aux_1(aux, data: i32) -> Result;
fn aux_2(aux, data: i32, data2: String) -> Result;
}
#[derive(Serialize, Deserialize)]
pub enum PrivCall {
/// Hi, this is a comment.
/// Hi, this is a second comment.
fn priv_0(data: String) -> Result;
fn priv_1(data: String, data2: u32) -> Result;
fn aux_0(origin) -> Result;
fn aux_1(origin, data: i32) -> Result;
fn aux_2(origin, data: i32, data2: String) -> Result;
}
}
const EXPECTED_METADATA: &str = concat!(
r#"{ "name": "Module", "calls": [ "#,
r#"{ "name": "Module", "call": [ "#,
r#"{ "name": "Call", "functions": { "#,
r#""0": { "name": "aux_0", "params": [ "#,
r#"{ "name": "aux", "type": "T::PublicAux" }"#,
r#"{ "name": "origin", "type": "T::Origin" }"#,
r#" ], "description": [ " Hi, this is a comment." ] }, "#,
r#""0 + 1": { "name": "aux_1", "params": [ "#,
r#"{ "name": "aux", "type": "T::PublicAux" }, "#,
r#"{ "name": "origin", "type": "T::Origin" }, "#,
r#"{ "name": "data", "type": "i32" }"#,
r#" ], "description": [ ] }, "#,
r#""0 + 1 + 1": { "name": "aux_2", "params": [ "#,
r#"{ "name": "aux", "type": "T::PublicAux" }, "#,
r#"{ "name": "origin", "type": "T::Origin" }, "#,
r#"{ "name": "data", "type": "i32" }, "#,
r#"{ "name": "data2", "type": "String" }"#,
r#" ], "description": [ ] }"#,
r#" } }, "#,
r#"{ "name": "PrivCall", "functions": { "#,
r#""0": { "name": "priv_0", "params": [ "#,
r#"{ "name": "data", "type": "String" }"#,
r#" ], "description": [ " Hi, this is a comment.", " Hi, this is a second comment." ] }, "#,
r#""0 + 1": { "name": "priv_1", "params": [ "#,
r#"{ "name": "data", "type": "String" }, "#,
r#"{ "name": "data2", "type": "u32" }"#,
r#" ], "description": [ ] }"#,
r#" } }"#,
r#" ] }"#,
);
impl<T: Trait> Module<T> {
fn aux_0(_: &T::PublicAux) -> Result {
fn aux_0(_: T::Origin) -> Result {
unreachable!()
}
fn aux_1(_: &T::PublicAux, _: i32) -> Result {
fn aux_1(_: T::Origin, _: i32) -> Result {
unreachable!()
}
fn aux_2(_: &T::PublicAux, _: i32, _: String) -> Result {
unreachable!()
}
fn priv_0(_: String) -> Result {
unreachable!()
}
fn priv_1(_: String, _: u32) -> Result {
fn aux_2(_: T::Origin, _: i32, _: String) -> Result {
unreachable!()
}
}
@@ -875,7 +571,7 @@ mod tests {
struct TraitImpl {}
impl Trait for TraitImpl {
type PublicAux = u32;
type Origin = u32;
}
#[test]
+77 -1
View File
@@ -50,7 +50,7 @@ mod event;
pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap};
pub use self::hashable::Hashable;
pub use self::dispatch::{Parameter, Dispatchable, Callable, AuxDispatchable, AuxCallable, IsSubType, IsAuxSubType};
pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType};
pub use runtime_io::print;
@@ -99,6 +99,82 @@ macro_rules! assert_ok {
}
}
/// The void type - it cannot exist.
// Oh rust, you crack me up...
#[derive(Clone, Eq, PartialEq)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Void {}
#[macro_export]
macro_rules! impl_outer_origin {
($(#[$attr:meta])* pub enum $name:ident for $trait:ident where system = $system:ident { $( $module:ident ),* }) => {
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))]
$(#[$attr])*
#[allow(non_camel_case_types)]
pub enum $name {
system($system::Origin<$trait>),
$(
$module($module::Origin<$trait>),
)*
#[allow(dead_code)]
Void($crate::Void)
}
#[allow(dead_code)]
impl $name {
pub const INHERENT: Self = $name::system($system::RawOrigin::Inherent);
pub const ROOT: Self = $name::system($system::RawOrigin::Root);
pub fn signed(by: <$trait as $system::Trait>::AccountId) -> Self {
$name::system($system::RawOrigin::Signed(by))
}
}
impl From<$system::Origin<$trait>> for $name {
fn from(x: $system::Origin<$trait>) -> Self {
$name::system(x)
}
}
impl Into<Option<$system::Origin<$trait>>> for $name {
fn into(self) -> Option<$system::Origin<$trait>> {
if let $name::system(l) = self {
Some(l)
} else {
None
}
}
}
impl From<Option<<$trait as $system::Trait>::AccountId>> for $name {
fn from(x: Option<<$trait as $system::Trait>::AccountId>) -> Self {
<$system::Origin<$trait>>::from(x).into()
}
}
$(
impl From<$module::Origin<$trait>> for $name {
fn from(x: $module::Origin<$trait>) -> Self {
$name::$module(x)
}
}
impl<T: Trait> Into<Option<$module::Origin<T>>> for $name<T> {
fn into(self) -> Option<$module::Origin<T>> {
if let $name::$module(l) = self {
Some(l)
} else {
None
}
}
}
)*
};
($(#[$attr:meta])* pub enum $name:ident for $trait:ident { $( $module:ident ),* }) => {
impl_outer_origin! {
$(#[$attr])*
pub enum $name for $trait where system = system {
$( $module ),*
}
}
}
}
#[macro_export]
macro_rules! impl_outer_log {
@@ -1456,11 +1456,11 @@ mod tests {
}
pub trait Trait {
type PublicAux;
type Origin;
}
decl_module! {
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
decl_storage! {
@@ -1500,7 +1500,7 @@ mod tests {
struct TraitImpl {}
impl Trait for TraitImpl {
type PublicAux = u32;
type Origin = u32;
}
const EXPECTED_METADATA: &str = concat!(
+21 -28
View File
@@ -45,9 +45,10 @@ use rstd::{cmp, result};
use codec::{Encode, Decode, Codec, Input, Output};
use runtime_support::{StorageValue, StorageMap, Parameter};
use runtime_support::dispatch::Result;
use primitives::traits::{Zero, One, RefInto, SimpleArithmetic, OnFinalise, MakePayment,
As, AuxLookup, Member, CheckedAdd, CheckedSub};
use primitives::traits::{Zero, One, SimpleArithmetic, OnFinalise, MakePayment,
As, Lookup, Member, CheckedAdd, CheckedSub};
use address::Address as RawAddress;
use system::{ensure_signed, ensure_root};
mod mock;
@@ -132,16 +133,9 @@ pub trait Trait: system::Trait {
}
decl_module! {
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn transfer(aux, dest: RawAddress<T::AccountId, T::AccountIndex>, value: T::Balance) -> Result;
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn set_balance(who: RawAddress<T::AccountId, T::AccountIndex>, free: T::Balance, reserved: T::Balance) -> Result;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn transfer(origin, dest: RawAddress<T::AccountId, T::AccountIndex>, value: T::Balance) -> Result;
fn set_balance(origin, who: RawAddress<T::AccountId, T::AccountIndex>, free: T::Balance, reserved: T::Balance) -> Result;
}
}
@@ -233,6 +227,11 @@ pub enum UpdateBalanceOutcome {
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
// PUBLIC IMMUTABLES
/// The combined balance of `who`.
@@ -283,11 +282,11 @@ impl<T: Trait> Module<T> {
// PUBLIC DISPATCH
/// Transfer some liquid free balance to another staker.
pub fn transfer(aux: &T::PublicAux, dest: Address<T>, value: T::Balance) -> Result {
let dest = Self::lookup(dest)?;
pub fn transfer(origin: T::Origin, dest: Address<T>, value: T::Balance) -> Result {
let transactor = ensure_signed(origin)?;
let transactor = aux.ref_into();
let from_balance = Self::free_balance(transactor);
let dest = Self::lookup(dest)?;
let from_balance = Self::free_balance(&transactor);
let would_create = from_balance.is_zero();
let fee = if would_create { Self::creation_fee() } else { Self::transfer_fee() };
let liability = value + fee;
@@ -299,7 +298,7 @@ impl<T: Trait> Module<T> {
if would_create && value < Self::existential_deposit() {
return Err("value too low to create account");
}
T::EnsureAccountLiquid::ensure_account_liquid(transactor)?;
T::EnsureAccountLiquid::ensure_account_liquid(&transactor)?;
let to_balance = Self::free_balance(&dest);
// NOTE: total stake being stored in the same type means that this could never overflow
@@ -309,8 +308,8 @@ impl<T: Trait> Module<T> {
None => return Err("destination balance too high to receive value"),
};
if transactor != &dest {
Self::set_free_balance(transactor, new_from_balance);
if transactor != dest {
Self::set_free_balance(&transactor, new_from_balance);
Self::decrease_total_stake_by(fee);
Self::set_free_balance_creating(&dest, new_to_balance);
}
@@ -318,15 +317,9 @@ impl<T: Trait> Module<T> {
Ok(())
}
// PRIV DISPATCH
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
/// Set the balances of a given account.
fn set_balance(who: Address<T>, free: T::Balance, reserved: T::Balance) -> Result {
fn set_balance(origin: T::Origin, who: Address<T>, free: T::Balance, reserved: T::Balance) -> Result {
ensure_root(origin)?;
let who = Self::lookup(who)?;
Self::set_free_balance(&who, free);
Self::set_reserved_balance(&who, reserved);
@@ -647,7 +640,7 @@ impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
}
}
impl<T: Trait> AuxLookup for Module<T> {
impl<T: Trait> Lookup for Module<T> {
type Source = address::Address<T::AccountId, T::AccountIndex>;
type Target = T::AccountId;
fn lookup(a: Self::Source) -> result::Result<Self::Target, &'static str> {
@@ -24,11 +24,15 @@ use substrate_primitives::{H256, KeccakHasher};
use runtime_io;
use {GenesisConfig, Module, Trait, system};
impl_outer_origin!{
pub enum Origin for Runtime {}
}
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
pub struct Runtime;
impl system::Trait for Runtime {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -38,7 +42,7 @@ impl system::Trait for Test {
type Header = Header;
type Event = ();
}
impl Trait for Test {
impl Trait for Runtime {
type Balance = u64;
type AccountIndex = u64;
type OnFreeBalanceZero = ();
@@ -47,13 +51,13 @@ impl Trait for Test {
}
pub fn new_test_ext(ext_deposit: u64, monied: bool) -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
let mut t = system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
let balance_factor = if ext_deposit > 0 {
256
} else {
1
};
t.extend(GenesisConfig::<Test>{
t.extend(GenesisConfig::<Runtime>{
balances: if monied {
vec![(1, 10 * balance_factor), (2, 20 * balance_factor), (3, 30 * balance_factor), (4, 40 * balance_factor)]
} else {
@@ -69,5 +73,5 @@ pub fn new_test_ext(ext_deposit: u64, monied: bool) -> runtime_io::TestExternali
t.into()
}
pub type System = system::Module<Test>;
pub type Balances = Module<Test>;
pub type System = system::Module<Runtime>;
pub type Balances = Module<Runtime>;
@@ -20,7 +20,7 @@
use super::*;
use runtime_io::with_externalities;
use mock::{Balances, System, Test, new_test_ext};
use mock::{Balances, System, Runtime, new_test_ext};
#[test]
fn reward_should_work() {
@@ -28,7 +28,7 @@ fn reward_should_work() {
assert_eq!(Balances::total_balance(&1), 10);
assert_ok!(Balances::reward(&1, 10));
assert_eq!(Balances::total_balance(&1), 20);
assert_eq!(<TotalIssuance<Test>>::get(), 110);
assert_eq!(<TotalIssuance<Runtime>>::get(), 110);
});
}
@@ -47,7 +47,7 @@ fn indexing_lookup_should_work() {
fn default_indexing_on_new_accounts_should_work() {
with_externalities(&mut new_test_ext(10, true), || {
assert_eq!(Balances::lookup_index(4), None);
assert_ok!(Balances::transfer(&1, 5.into(), 10));
assert_ok!(Balances::transfer(Some(1).into(), 5.into(), 10));
assert_eq!(Balances::lookup_index(4), Some(5));
});
}
@@ -59,7 +59,7 @@ fn dust_account_removal_should_work() {
assert_eq!(System::account_nonce(&2), 1);
assert_eq!(Balances::total_balance(&2), 256 * 20);
assert_ok!(Balances::transfer(&2, 5.into(), 256 * 10 + 1)); // index 1 (account 2) becomes zombie
assert_ok!(Balances::transfer(Some(2).into(), 5.into(), 256 * 10 + 1)); // index 1 (account 2) becomes zombie
assert_eq!(Balances::total_balance(&2), 0);
assert_eq!(Balances::total_balance(&5), 256 * 10 + 1);
assert_eq!(System::account_nonce(&2), 0);
@@ -73,10 +73,10 @@ fn reclaim_indexing_on_new_accounts_should_work() {
assert_eq!(Balances::lookup_index(4), None);
assert_eq!(Balances::total_balance(&2), 256 * 20);
assert_ok!(Balances::transfer(&2, 5.into(), 256 * 20)); // account 2 becomes zombie freeing index 1 for reclaim)
assert_ok!(Balances::transfer(Some(2).into(), 5.into(), 256 * 20)); // account 2 becomes zombie freeing index 1 for reclaim)
assert_eq!(Balances::total_balance(&2), 0);
assert_ok!(Balances::transfer(&5, 6.into(), 256 * 1 + 0x69)); // account 6 takes index 1.
assert_ok!(Balances::transfer(Some(5).into(), 6.into(), 256 * 1 + 0x69)); // account 6 takes index 1.
assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69);
assert_eq!(Balances::lookup_index(1), Some(6));
});
@@ -95,7 +95,7 @@ fn reserved_balance_should_prevent_reclaim_count() {
assert_eq!(Balances::total_balance(&2), 256 * 19 + 1); // reserve still exists.
assert_eq!(System::account_nonce(&2), 1);
assert_ok!(Balances::transfer(&4, 5.into(), 256 * 1 + 0x69)); // account 4 tries to take index 1 for account 5.
assert_ok!(Balances::transfer(Some(4).into(), 5.into(), 256 * 1 + 0x69)); // account 4 tries to take index 1 for account 5.
assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69);
assert_eq!(Balances::lookup_index(1), Some(2)); // but fails.
assert_eq!(System::account_nonce(&2), 1);
@@ -104,7 +104,7 @@ fn reserved_balance_should_prevent_reclaim_count() {
assert_eq!(Balances::total_balance(&2), 0); // "free" account deleted."
assert_eq!(System::account_nonce(&2), 0);
assert_ok!(Balances::transfer(&4, 6.into(), 256 * 1 + 0x69)); // account 4 tries to take index 1 again for account 6.
assert_ok!(Balances::transfer(Some(4).into(), 6.into(), 256 * 1 + 0x69)); // account 4 tries to take index 1 again for account 6.
assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69);
assert_eq!(Balances::lookup_index(1), Some(6)); // and succeeds.
});
@@ -128,7 +128,7 @@ fn balance_transfer_works() {
with_externalities(&mut new_test_ext(0, false), || {
Balances::set_free_balance(&1, 111);
Balances::increase_total_stake_by(111);
assert_ok!(Balances::transfer(&1, 2.into(), 69));
assert_ok!(Balances::transfer(Some(1).into(), 2.into(), 69));
assert_eq!(Balances::total_balance(&1), 42);
assert_eq!(Balances::total_balance(&2), 69);
});
@@ -156,7 +156,7 @@ fn balance_transfer_when_reserved_should_not_work() {
with_externalities(&mut new_test_ext(0, false), || {
Balances::set_free_balance(&1, 111);
assert_ok!(Balances::reserve(&1, 69));
assert_noop!(Balances::transfer(&1, 2.into(), 69), "balance too low to send value");
assert_noop!(Balances::transfer(Some(1).into(), 2.into(), 69), "balance too low to send value");
});
}
@@ -189,7 +189,7 @@ fn slashing_balance_should_work() {
assert!(Balances::slash(&1, 69).is_none());
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(&1), 42);
assert_eq!(<TotalIssuance<Test>>::get(), 44);
assert_eq!(<TotalIssuance<Runtime>>::get(), 44);
});
}
@@ -202,7 +202,7 @@ fn slashing_incomplete_balance_should_work() {
assert!(Balances::slash(&1, 69).is_some());
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 2);
assert_eq!(<TotalIssuance<Runtime>>::get(), 2);
});
}
@@ -226,7 +226,7 @@ fn slashing_reserved_balance_should_work() {
assert!(Balances::slash_reserved(&1, 42).is_none());
assert_eq!(Balances::reserved_balance(&1), 69);
assert_eq!(Balances::free_balance(&1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 71);
assert_eq!(<TotalIssuance<Runtime>>::get(), 71);
});
}
@@ -239,7 +239,7 @@ fn slashing_incomplete_reserved_balance_should_work() {
assert!(Balances::slash_reserved(&1, 69).is_some());
assert_eq!(Balances::free_balance(&1), 69);
assert_eq!(Balances::reserved_balance(&1), 0);
assert_eq!(<TotalIssuance<Test>>::get(), 71);
assert_eq!(<TotalIssuance<Runtime>>::get(), 71);
});
}
@@ -283,11 +283,11 @@ fn transferring_incomplete_reserved_balance_should_work() {
#[test]
fn transferring_too_high_value_should_not_panic() {
with_externalities(&mut new_test_ext(0, false), || {
<FreeBalance<Test>>::insert(1, u64::max_value());
<FreeBalance<Test>>::insert(2, 1);
<FreeBalance<Runtime>>::insert(1, u64::max_value());
<FreeBalance<Runtime>>::insert(2, 1);
assert_err!(
Balances::transfer(&1, 2.into(), u64::max_value()),
Balances::transfer(Some(1).into(), 2.into(), u64::max_value()),
"destination balance too high to receive value"
);
@@ -307,18 +307,18 @@ fn account_removal_on_free_too_low() {
Balances::set_free_balance(&2, 110);
Balances::increase_total_stake_by(110);
assert_eq!(<TotalIssuance<Test>>::get(), 732);
assert_eq!(<TotalIssuance<Runtime>>::get(), 732);
}
// Transfer funds from account 1 of such amount that after this transfer
// the balance of account 1 will be below the exsistential threshold.
// This should lead to the removal of all balance of this account.
assert_ok!(Balances::transfer(&1, 2.into(), 20));
assert_ok!(Balances::transfer(Some(1).into(), 2.into(), 20));
// Verify free balance removal of account 1.
assert_eq!(Balances::free_balance(&1), 0);
// Verify that TotalIssuance tracks balance removal when free balance is too low.
assert_eq!(<TotalIssuance<Test>>::get(), 642);
assert_eq!(<TotalIssuance<Runtime>>::get(), 642);
});
}
@@ -46,8 +46,9 @@ use runtime_support::{storage, Parameter};
use runtime_support::dispatch::Result;
use runtime_support::storage::StorageValue;
use runtime_support::storage::unhashed::StorageVec;
use primitives::traits::{MaybeSerializeDebug, MaybeEmpty, OnFinalise, Member, AuthoritiesChangeDigest};
use primitives::traits::{MaybeSerializeDebug, OnFinalise, Member, AuthoritiesChangeDigest};
use primitives::bft::MisbehaviorReport;
use system::{ensure_signed, ensure_inherent, ensure_root};
#[cfg(any(feature = "std", test))]
use substrate_primitives::KeccakHasher;
@@ -141,19 +142,12 @@ decl_storage! {
}
decl_module! {
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn report_misbehavior(aux, report: MisbehaviorReport<T::Hash, T::BlockNumber>) -> Result;
fn note_offline(aux, offline_val_indices: Vec<u32>) -> Result;
fn remark(aux, remark: Vec<u8>) -> Result;
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn set_code(new: Vec<u8>) -> Result;
fn set_storage(items: Vec<KeyValue>) -> Result;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn report_misbehavior(origin, report: MisbehaviorReport<T::Hash, T::BlockNumber>) -> Result;
fn note_offline(origin, offline_val_indices: Vec<u32>) -> Result;
fn remark(origin, remark: Vec<u8>) -> Result;
fn set_code(origin, new: Vec<u8>) -> Result;
fn set_storage(origin, items: Vec<KeyValue>) -> Result;
}
}
@@ -164,13 +158,15 @@ impl<T: Trait> Module<T> {
}
/// Set the new code.
fn set_code(new: Vec<u8>) -> Result {
fn set_code(origin: T::Origin, new: Vec<u8>) -> Result {
ensure_root(origin)?;
storage::unhashed::put_raw(CODE, &new);
Ok(())
}
/// Set some items of storage.
fn set_storage(items: Vec<KeyValue>) -> Result {
fn set_storage(origin: T::Origin, items: Vec<KeyValue>) -> Result {
ensure_root(origin)?;
for i in &items {
storage::unhashed::put_raw(&i.0, &i.1);
}
@@ -178,7 +174,8 @@ impl<T: Trait> Module<T> {
}
/// Report some misbehaviour.
fn report_misbehavior(_aux: &T::PublicAux, _report: MisbehaviorReport<T::Hash, T::BlockNumber>) -> Result {
fn report_misbehavior(origin: T::Origin, _report: MisbehaviorReport<T::Hash, T::BlockNumber>) -> Result {
ensure_signed(origin)?;
// TODO.
Ok(())
}
@@ -186,8 +183,8 @@ impl<T: Trait> Module<T> {
/// Note the previous block's validator missed their opportunity to propose a block. This only comes in
/// if 2/3+1 of the validators agree that no proposal was submitted. It's only relevant
/// for the previous block.
fn note_offline(aux: &T::PublicAux, offline_val_indices: Vec<u32>) -> Result {
assert!(aux.is_empty());
fn note_offline(origin: T::Origin, offline_val_indices: Vec<u32>) -> Result {
ensure_inherent(origin)?;
assert!(
<system::Module<T>>::extrinsic_index() == Some(T::NOTE_OFFLINE_POSITION),
"note_offline extrinsic must be at position {} in the block",
@@ -202,7 +199,8 @@ impl<T: Trait> Module<T> {
}
/// Make some on-chain remark.
fn remark(_aux: &T::PublicAux, _remark: Vec<u8>) -> Result {
fn remark(origin: T::Origin, _remark: Vec<u8>) -> Result {
ensure_signed(origin)?;
Ok(())
}
@@ -7,8 +7,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives" }
substrate-runtime-primitives = { path = "../../runtime/primitives" }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-primitives = { path = "../../runtime/primitives", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-sandbox = { path = "../../runtime-sandbox", default_features = false }
@@ -28,6 +28,7 @@ std = [
"serde_derive",
"serde/std",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-primitives/std",
"substrate-runtime-io/std",
"substrate-runtime-std/std",
+17 -19
View File
@@ -101,9 +101,10 @@ use account_db::{AccountDb, OverlayAccountDb};
use double_map::StorageDoubleMap;
use codec::Codec;
use runtime_primitives::traits::{As, RefInto, SimpleArithmetic, OnFinalise};
use runtime_primitives::traits::{As, SimpleArithmetic, OnFinalise};
use runtime_support::dispatch::Result;
use runtime_support::{Parameter, StorageMap, StorageValue};
use system::ensure_signed;
pub trait Trait: balances::Trait {
/// Function type to get the contract address given the creator.
@@ -119,13 +120,10 @@ pub trait ContractAddressFor<AccountId: Sized> {
decl_module! {
/// Contracts module.
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
// TODO: Change AccountId to staking::Address
fn call(
aux,
origin,
dest: T::AccountId,
value: T::Balance,
gas_limit: T::Gas,
@@ -133,7 +131,7 @@ decl_module! {
) -> Result;
fn create(
aux,
origin,
value: T::Balance,
gas_limit: T::Gas,
ctor: Vec<u8>,
@@ -181,26 +179,26 @@ impl<T: Trait> double_map::StorageDoubleMap for StorageOf<T> {
impl<T: Trait> Module<T> {
/// Make a call to a specified account, optionally transferring some balance.
fn call(
aux: &<T as system::Trait>::PublicAux,
origin: <T as system::Trait>::Origin,
dest: T::AccountId,
value: T::Balance,
gas_limit: T::Gas,
data: Vec<u8>,
) -> Result {
let aux = aux.ref_into();
let origin = ensure_signed(origin)?;
// Pay for the gas upfront.
//
// NOTE: it is very important to avoid any state changes before
// paying for the gas.
let mut gas_meter = gas::buy_gas::<T>(aux, gas_limit)?;
let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?;
let mut ctx = ExecutionContext {
self_account: aux.clone(),
self_account: origin.clone(),
depth: 0,
overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb),
};
let result = ctx.call(aux.clone(), dest, value, &mut gas_meter, &data);
let result = ctx.call(origin.clone(), dest, value, &mut gas_meter, &data);
if let Ok(_) = result {
// Commit all changes that made it thus far into the persistant storage.
@@ -211,7 +209,7 @@ impl<T: Trait> Module<T> {
//
// NOTE: this should go after the commit to the storage, since the storage changes
// can alter the balance of the caller.
gas::refund_unused_gas::<T>(aux, gas_meter);
gas::refund_unused_gas::<T>(&origin, gas_meter);
result.map(|_| ())
}
@@ -226,26 +224,26 @@ impl<T: Trait> Module<T> {
/// after the execution is saved as the `code` of the account. That code will be invoked
/// upon any message received by this account.
fn create(
aux: &<T as system::Trait>::PublicAux,
origin: <T as system::Trait>::Origin,
endowment: T::Balance,
gas_limit: T::Gas,
ctor_code: Vec<u8>,
data: Vec<u8>,
) -> Result {
let aux = aux.ref_into();
let origin = ensure_signed(origin)?;
// Pay for the gas upfront.
//
// NOTE: it is very important to avoid any state changes before
// paying for the gas.
let mut gas_meter = gas::buy_gas::<T>(aux, gas_limit)?;
let mut gas_meter = gas::buy_gas::<T>(&origin, gas_limit)?;
let mut ctx = ExecutionContext {
self_account: aux.clone(),
self_account: origin.clone(),
depth: 0,
overlay: OverlayAccountDb::<T>::new(&account_db::DirectAccountDb),
};
let result = ctx.create(aux.clone(), endowment, &mut gas_meter, &ctor_code, &data);
let result = ctx.create(origin.clone(), endowment, &mut gas_meter, &ctor_code, &data);
if let Ok(_) = result {
// Commit all changes that made it thus far into the persistant storage.
@@ -256,7 +254,7 @@ impl<T: Trait> Module<T> {
//
// NOTE: this should go after the commit to the storage, since the storage changes
// can alter the balance of the caller.
gas::refund_unused_gas::<T>(aux, gas_meter);
gas::refund_unused_gas::<T>(&origin, gas_meter);
result.map(|_| ())
}
@@ -27,10 +27,14 @@ use {
GenesisConfig, Module, StorageOf, Trait,
};
impl_outer_origin! {
pub enum Origin for Test {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -170,7 +174,7 @@ fn contract_transfer() {
Balances::set_free_balance(&1, 11);
Balances::increase_total_stake_by(11);
assert_ok!(Contract::call(&0, 1, 3, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), 1, 3, 100_000, Vec::new()));
assert_eq!(
Balances::free_balance(&0),
@@ -205,7 +209,7 @@ fn contract_transfer_oog() {
Balances::set_free_balance(&1, 11);
Balances::increase_total_stake_by(11);
assert_ok!(Contract::call(&0, 1, 3, 135 + 135 + 7, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), 1, 3, 135 + 135 + 7, Vec::new()));
assert_eq!(
Balances::free_balance(&0),
@@ -237,7 +241,7 @@ fn contract_transfer_max_depth() {
Balances::set_free_balance(&CONTRACT_SHOULD_TRANSFER_TO, 11);
Balances::increase_total_stake_by(11);
assert_ok!(Contract::call(&0, CONTRACT_SHOULD_TRANSFER_TO, 3, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), CONTRACT_SHOULD_TRANSFER_TO, 3, 100_000, Vec::new()));
assert_eq!(
Balances::free_balance(&0),
@@ -349,7 +353,7 @@ fn contract_create() {
<CodeOf<Test>>::insert(1, code_create.to_vec());
// When invoked, the contract at address `1` must create a contract with 'transfer' code.
assert_ok!(Contract::call(&0, 1, 11, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), 1, 11, 100_000, Vec::new()));
let derived_address = <Test as Trait>::DetermineContractAddress::contract_address_for(
&code_ctor_transfer,
@@ -368,7 +372,7 @@ fn contract_create() {
assert_eq!(Balances::free_balance(&derived_address), 3);
// Initiate transfer to the newly created contract.
assert_ok!(Contract::call(&0, derived_address, 22, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), derived_address, 22, 100_000, Vec::new()));
assert_eq!(
Balances::free_balance(&0),
@@ -400,7 +404,7 @@ fn top_level_create() {
Balances::increase_total_stake_by(30);
assert_ok!(Contract::create(
&0,
Origin::signed(0),
11,
100_000,
code_ctor_transfer.clone(),
@@ -439,7 +443,7 @@ fn refunds_unused_gas() {
Balances::set_free_balance(&0, 100_000_000);
Balances::increase_total_stake_by(100_000_000);
assert_ok!(Contract::call(&0, 1, 0, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new()));
assert_eq!(Balances::free_balance(&0), 100_000_000 - 4 - (2 * 135));
});
@@ -453,7 +457,7 @@ fn call_with_zero_value() {
Balances::set_free_balance(&0, 100_000_000);
Balances::increase_total_stake_by(100_000_000);
assert_ok!(Contract::call(&0, 1, 0, 100_000, Vec::new()));
assert_ok!(Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new()));
assert_eq!(Balances::free_balance(&0), 100_000_000 - (2 * 135));
});
@@ -467,7 +471,7 @@ fn create_with_zero_endowment() {
Balances::set_free_balance(&0, 100_000_000);
Balances::increase_total_stake_by(100_000_000);
assert_ok!(Contract::create(&0, 0, 100_000, code_nop, Vec::new()));
assert_ok!(Contract::create(Origin::signed(0), 0, 100_000, code_nop, Vec::new()));
assert_eq!(
Balances::free_balance(&0),
@@ -500,7 +504,7 @@ fn account_removal_removes_storage() {
// the balance of account 1 is will be below than exsistential threshold.
//
// This should lead to the removal of all storage associated with this account.
assert_ok!(Balances::transfer(&1, 2.into(), 20));
assert_ok!(Balances::transfer(Origin::signed(1), 2.into(), 20));
// Verify that all entries from account 1 is removed, while
// entries from account 2 is in place.
@@ -540,7 +544,7 @@ fn top_level_call_refunds_even_if_fails() {
Balances::increase_total_stake_by(100_000_000);
assert_err!(
Contract::call(&0, 1, 0, 100_000, Vec::new()),
Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new()),
"vm execute returned error while call"
);
@@ -571,19 +575,19 @@ fn block_gas_limit() {
// Spend 50_000 units of gas (OOG).
assert_err!(
Contract::call(&0, 1, 0, 50_000, Vec::new()),
Contract::call(Origin::signed(0), 1, 0, 50_000, Vec::new()),
"vm execute returned error while call"
);
// Ensure we can't spend more gas than available in block gas limit.
assert_err!(
Contract::call(&0, 1, 0, 50_001, Vec::new()),
Contract::call(Origin::signed(0), 1, 0, 50_001, Vec::new()),
"block gas limit is reached"
);
// However, we can spend another 50_000
assert_err!(
Contract::call(&0, 1, 0, 50_000, Vec::new()),
Contract::call(Origin::signed(0), 1, 0, 50_000, Vec::new()),
"vm execute returned error while call"
);
},
@@ -656,7 +660,7 @@ fn input_data() {
Balances::set_free_balance(&0, 100_000_000);
Balances::increase_total_stake_by(100_000_000);
assert_ok!(Contract::call(&0, 1, 0, 50_000, vec![0, 1, 2, 3]));
assert_ok!(Contract::call(Origin::signed(0), 1, 0, 50_000, vec![0, 1, 2, 3]));
// all asserts are made within contract code itself.
},
File diff suppressed because it is too large Load Diff
@@ -18,27 +18,22 @@
use rstd::prelude::*;
use rstd::borrow::Borrow;
use primitives::traits::{OnFinalise, RefInto, Hash};
use primitives::traits::{OnFinalise, Hash};
use runtime_io::print;
use substrate_runtime_support::dispatch::Result;
use substrate_runtime_support::{StorageValue, StorageMap, IsSubType};
use {system, democracy};
use super::{Trait, Module as Council};
use system::{ensure_signed, ensure_root};
decl_module! {
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn propose(origin, proposal: Box<T::Proposal>) -> Result;
fn vote(origin, proposal: T::Hash, approve: bool) -> Result;
fn veto(origin, proposal_hash: T::Hash) -> Result;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn propose(aux, proposal: Box<T::Proposal>) -> Result;
fn vote(aux, proposal: T::Hash, approve: bool) -> Result;
fn veto(aux, proposal_hash: T::Hash) -> Result;
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn set_cooloff_period(blocks: T::BlockNumber) -> Result;
fn set_voting_period(blocks: T::BlockNumber) -> Result;
fn set_cooloff_period(origin, blocks: T::BlockNumber) -> Result;
fn set_voting_period(origin, blocks: T::BlockNumber) -> Result;
}
}
@@ -78,9 +73,11 @@ impl<T: Trait> Module<T> {
}
// Dispatch
fn propose(aux: &T::PublicAux, proposal: Box<T::Proposal>) -> Result {
fn propose(origin: T::Origin, proposal: Box<T::Proposal>) -> Result {
let who = ensure_signed(origin)?;
let expiry = <system::Module<T>>::block_number() + Self::voting_period();
ensure!(Self::will_still_be_councillor_at(aux.ref_into(), expiry), "proposer would not be on council");
ensure!(Self::will_still_be_councillor_at(&who, expiry), "proposer would not be on council");
let proposal_hash = T::Hashing::hash_of(&proposal);
@@ -93,31 +90,35 @@ impl<T: Trait> Module<T> {
Self::set_proposals(&proposals);
<ProposalOf<T>>::insert(proposal_hash, *proposal);
<ProposalVoters<T>>::insert(proposal_hash, vec![aux.ref_into().clone()]);
<CouncilVoteOf<T>>::insert((proposal_hash, aux.ref_into().clone()), true);
<ProposalVoters<T>>::insert(proposal_hash, vec![who.clone()]);
<CouncilVoteOf<T>>::insert((proposal_hash, who), true);
Ok(())
}
fn vote(aux: &T::PublicAux, proposal: T::Hash, approve: bool) -> Result {
if Self::vote_of((proposal, aux.ref_into().clone())).is_none() {
fn vote(origin: T::Origin, proposal: T::Hash, approve: bool) -> Result {
let who = ensure_signed(origin)?;
if Self::vote_of((proposal, who.clone())).is_none() {
let mut voters = Self::proposal_voters(&proposal);
voters.push(aux.ref_into().clone());
voters.push(who.clone());
<ProposalVoters<T>>::insert(proposal, voters);
}
<CouncilVoteOf<T>>::insert((proposal, aux.ref_into().clone()), approve);
<CouncilVoteOf<T>>::insert((proposal, who), approve);
Ok(())
}
fn veto(aux: &T::PublicAux, proposal_hash: T::Hash) -> Result {
ensure!(Self::is_councillor(aux.ref_into()), "only councillors may veto council proposals");
fn veto(origin: T::Origin, proposal_hash: T::Hash) -> Result {
let who = ensure_signed(origin)?;
ensure!(Self::is_councillor(&who), "only councillors may veto council proposals");
ensure!(<ProposalVoters<T>>::exists(&proposal_hash), "proposal must exist to be vetoed");
let mut existing_vetoers = Self::veto_of(&proposal_hash)
.map(|pair| pair.1)
.unwrap_or_else(Vec::new);
let insert_position = existing_vetoers.binary_search(aux.ref_into())
let insert_position = existing_vetoers.binary_search(&who)
.err().ok_or("a councillor may not veto a proposal twice")?;
existing_vetoers.insert(insert_position, aux.ref_into().clone());
existing_vetoers.insert(insert_position, who);
Self::set_veto_of(&proposal_hash, <system::Module<T>>::block_number() + Self::cooloff_period(), existing_vetoers);
Self::set_proposals(&Self::proposals().into_iter().filter(|&(_, h)| h != proposal_hash).collect::<Vec<_>>());
@@ -129,12 +130,14 @@ impl<T: Trait> Module<T> {
Ok(())
}
fn set_cooloff_period(blocks: T::BlockNumber) -> Result {
fn set_cooloff_period(origin: T::Origin, blocks: T::BlockNumber) -> Result {
ensure_root(origin)?;
<CooloffPeriod<T>>::put(blocks);
Ok(())
}
fn set_voting_period(blocks: T::BlockNumber) -> Result {
fn set_voting_period(origin: T::Origin, blocks: T::BlockNumber) -> Result {
ensure_root(origin)?;
<VotingPeriod<T>>::put(blocks);
Ok(())
}
@@ -182,7 +185,7 @@ impl<T: Trait> Module<T> {
fn end_block(now: T::BlockNumber) -> Result {
while let Some((proposal, proposal_hash)) = Self::take_proposal_if_expiring_at(now) {
let tally = Self::take_tally(&proposal_hash);
if let Some(&democracy::PrivCall::cancel_referendum(ref_index)) = IsSubType::<democracy::Module<T>>::is_sub_type(&proposal) {
if let Some(&democracy::Call::cancel_referendum(ref_index)) = IsSubType::<democracy::Module<T>>::is_aux_sub_type(&proposal) {
if let (_, 0, 0) = tally {
<democracy::Module<T>>::internal_cancel_referendum(ref_index);
}
@@ -217,6 +220,7 @@ impl<T: Trait> OnFinalise<T::BlockNumber> for Council<T> {
mod tests {
use super::*;
use ::tests::*;
use ::tests::Call;
use substrate_runtime_support::Hashable;
use democracy::VoteThreshold;
@@ -242,12 +246,12 @@ mod tests {
});
}
fn set_balance_proposal(value: u64) -> Proposal {
Proposal::Balances(balances::PrivCall::set_balance(balances::address::Address::Id(42), value, 0))
fn set_balance_proposal(value: u64) -> Call {
Call::Balances(balances::Call::set_balance(balances::address::Address::Id(42), value, 0))
}
fn cancel_referendum_proposal(id: u32) -> Proposal {
Proposal::Democracy(democracy::PrivCall::cancel_referendum(id))
fn cancel_referendum_proposal(id: u32) -> Call {
Call::Democracy(democracy::Call::cancel_referendum(id))
}
#[test]
@@ -260,9 +264,9 @@ mod tests {
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(&2, hash, true));
assert_ok!(CouncilVoting::vote(&3, hash, true));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(Origin::signed(2), hash, true));
assert_ok!(CouncilVoting::vote(Origin::signed(3), hash, true));
assert_eq!(CouncilVoting::proposals(), vec![(2, hash)]);
assert_ok!(CouncilVoting::end_block(System::block_number()));
@@ -282,9 +286,9 @@ mod tests {
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(&2, hash, true));
assert_ok!(CouncilVoting::vote(&3, hash, false));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(Origin::signed(2), hash, true));
assert_ok!(CouncilVoting::vote(Origin::signed(3), hash, false));
assert_ok!(CouncilVoting::end_block(System::block_number()));
System::set_block_number(2);
@@ -302,8 +306,8 @@ mod tests {
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(&2, hash, true));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(cancellation)));
assert_ok!(CouncilVoting::vote(Origin::signed(2), hash, true));
assert_ok!(CouncilVoting::end_block(System::block_number()));
System::set_block_number(2);
@@ -318,8 +322,8 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&2, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(2), hash));
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums().len(), 0);
});
@@ -331,12 +335,12 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&2, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(2), hash));
System::set_block_number(3);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_noop!(CouncilVoting::veto(&2, hash), "a councillor may not veto a proposal twice");
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_noop!(CouncilVoting::veto(Origin::signed(2), hash), "a councillor may not veto a proposal twice");
});
}
@@ -346,11 +350,11 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&2, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(2), hash));
System::set_block_number(2);
assert_noop!(CouncilVoting::propose(&1, Box::new(proposal.clone())), "proposal is vetoed");
assert_noop!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())), "proposal is vetoed");
});
}
@@ -360,13 +364,13 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&2, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(2), hash));
System::set_block_number(3);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(&2, hash, false));
assert_ok!(CouncilVoting::vote(&3, hash, true));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(Origin::signed(2), hash, false));
assert_ok!(CouncilVoting::vote(Origin::signed(3), hash, true));
assert_ok!(CouncilVoting::end_block(System::block_number()));
System::set_block_number(4);
@@ -382,12 +386,12 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&2, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(2), hash));
System::set_block_number(3);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(&3, hash));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::veto(Origin::signed(3), hash));
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums().len(), 0);
});
@@ -399,7 +403,7 @@ mod tests {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
let hash = proposal.blake2_256().into();
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_eq!(CouncilVoting::proposals().len(), 1);
assert_eq!(CouncilVoting::proposal_voters(&hash), vec![1]);
assert_eq!(CouncilVoting::vote_of((hash, 1)), Some(true));
@@ -412,7 +416,7 @@ mod tests {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (1, 0, 2));
assert_ok!(CouncilVoting::end_block(System::block_number()));
@@ -428,9 +432,9 @@ mod tests {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(&2, proposal.blake2_256().into(), true));
assert_ok!(CouncilVoting::vote(&3, proposal.blake2_256().into(), true));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(Origin::signed(2), proposal.blake2_256().into(), true));
assert_ok!(CouncilVoting::vote(Origin::signed(3), proposal.blake2_256().into(), true));
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (3, 0, 0));
assert_ok!(CouncilVoting::end_block(System::block_number()));
@@ -446,9 +450,9 @@ mod tests {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
assert_ok!(CouncilVoting::propose(&1, Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(&2, proposal.blake2_256().into(), true));
assert_ok!(CouncilVoting::vote(&3, proposal.blake2_256().into(), false));
assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone())));
assert_ok!(CouncilVoting::vote(Origin::signed(2), proposal.blake2_256().into(), true));
assert_ok!(CouncilVoting::vote(Origin::signed(3), proposal.blake2_256().into(), false));
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (2, 1, 0));
assert_ok!(CouncilVoting::end_block(System::block_number()));
@@ -464,7 +468,7 @@ mod tests {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = set_balance_proposal(42);
assert_noop!(CouncilVoting::propose(&4, Box::new(proposal)), "proposer would not be on council");
assert_noop!(CouncilVoting::propose(Origin::signed(4), Box::new(proposal)), "proposer would not be on council");
});
}
}
@@ -31,6 +31,7 @@ std = [
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-consensus/std",
"substrate-runtime-balances/std",
"substrate-runtime-system/std",
]
@@ -43,9 +43,10 @@ extern crate substrate_runtime_system as system;
use rstd::prelude::*;
use rstd::result;
use primitives::traits::{Zero, OnFinalise, RefInto, As, MaybeSerializeDebug};
use primitives::traits::{Zero, OnFinalise, As, MaybeSerializeDebug};
use substrate_runtime_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType};
use substrate_runtime_support::dispatch::Result;
use system::{ensure_signed, ensure_root};
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
@@ -59,23 +60,17 @@ pub type PropIndex = u32;
pub type ReferendumIndex = u32;
pub trait Trait: balances::Trait + Sized {
type Proposal: Parameter + Dispatchable + IsSubType<Module<Self>> + MaybeSerializeDebug;
type Proposal: Parameter + Dispatchable<Origin=Self::Origin> + IsSubType<Module<Self>> + MaybeSerializeDebug;
}
decl_module! {
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn propose(origin, proposal: Box<T::Proposal>, value: T::Balance) -> Result;
fn second(origin, proposal: PropIndex) -> Result;
fn vote(origin, ref_index: ReferendumIndex, approve_proposal: bool) -> Result;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn propose(aux, proposal: Box<T::Proposal>, value: T::Balance) -> Result;
fn second(aux, proposal: PropIndex) -> Result;
fn vote(aux, ref_index: ReferendumIndex, approve_proposal: bool) -> Result;
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result;
fn cancel_referendum(ref_index: ReferendumIndex) -> Result;
fn start_referendum(origin, proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result;
fn cancel_referendum(origin, ref_index: ReferendumIndex) -> Result;
}
}
@@ -156,49 +151,53 @@ impl<T: Trait> Module<T> {
// dispatching.
/// Propose a sensitive action to be taken.
fn propose(aux: &T::PublicAux, proposal: Box<T::Proposal>, value: T::Balance) -> Result {
fn propose(origin: T::Origin, proposal: Box<T::Proposal>, value: T::Balance) -> Result {
let who = ensure_signed(origin)?;
ensure!(value >= Self::minimum_deposit(), "value too low");
<balances::Module<T>>::reserve(aux.ref_into(), value)
<balances::Module<T>>::reserve(&who, value)
.map_err(|_| "proposer's balance too low")?;
let index = Self::public_prop_count();
<PublicPropCount<T>>::put(index + 1);
<DepositOf<T>>::insert(index, (value, vec![aux.ref_into().clone()]));
<DepositOf<T>>::insert(index, (value, vec![who.clone()]));
let mut props = Self::public_props();
props.push((index, (*proposal).clone(), aux.ref_into().clone()));
props.push((index, (*proposal).clone(), who));
<PublicProps<T>>::put(props);
Ok(())
}
/// Propose a sensitive action to be taken.
fn second(aux: &T::PublicAux, proposal: PropIndex) -> Result {
fn second(origin: T::Origin, proposal: PropIndex) -> Result {
let who = ensure_signed(origin)?;
let mut deposit = Self::deposit_of(proposal)
.ok_or("can only second an existing proposal")?;
<balances::Module<T>>::reserve(aux.ref_into(), deposit.0)
<balances::Module<T>>::reserve(&who, deposit.0)
.map_err(|_| "seconder's balance too low")?;
deposit.1.push(aux.ref_into().clone());
deposit.1.push(who);
<DepositOf<T>>::insert(proposal, deposit);
Ok(())
}
/// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal;
/// false would be a vote to keep the status quo..
fn vote(aux: &T::PublicAux, ref_index: ReferendumIndex, approve_proposal: bool) -> Result {
fn vote(origin: T::Origin, ref_index: ReferendumIndex, approve_proposal: bool) -> Result {
let who = ensure_signed(origin)?;
ensure!(Self::is_active_referendum(ref_index), "vote given for invalid referendum.");
ensure!(!<balances::Module<T>>::total_balance(aux.ref_into()).is_zero(),
ensure!(!<balances::Module<T>>::total_balance(&who).is_zero(),
"transactor must have balance to signal approval.");
if !<VoteOf<T>>::exists(&(ref_index, aux.ref_into().clone())) {
if !<VoteOf<T>>::exists(&(ref_index, who.clone())) {
let mut voters = Self::voters_for(ref_index);
voters.push(aux.ref_into().clone());
voters.push(who.clone());
<VotersFor<T>>::insert(ref_index, voters);
}
<VoteOf<T>>::insert(&(ref_index, aux.ref_into().clone()), approve_proposal);
<VoteOf<T>>::insert(&(ref_index, who), approve_proposal);
Ok(())
}
/// Start a referendum.
fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result {
fn start_referendum(origin: T::Origin, proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) -> Result {
ensure_root(origin)?;
Self::inject_referendum(
<system::Module<T>>::block_number() + Self::voting_period(),
*proposal,
@@ -207,7 +206,8 @@ impl<T: Trait> Module<T> {
}
/// Remove a referendum.
fn cancel_referendum(ref_index: ReferendumIndex) -> Result {
fn cancel_referendum(origin: T::Origin, ref_index: ReferendumIndex) -> Result {
ensure_root(origin)?;
Self::clear_referendum(ref_index);
Ok(())
}
@@ -280,7 +280,7 @@ impl<T: Trait> Module<T> {
let total_stake = <balances::Module<T>>::total_stake();
Self::clear_referendum(index);
if vote_threshold.approved(approve, against, total_stake) {
proposal.dispatch()?;
proposal.dispatch(system::RawOrigin::Root.into())?;
}
<NextTally<T>>::put(index + 1);
}
@@ -354,9 +354,12 @@ mod tests {
use primitives::traits::{BlakeTwo256};
use primitives::testing::{Digest, Header};
impl_outer_origin! {
pub enum Origin for Test {}
}
impl_outer_dispatch! {
#[derive(Debug, Clone, Eq, Serialize, Deserialize, PartialEq)]
pub enum Proposal {
pub enum Call where origin: Origin {
Balances,
Democracy,
}
@@ -366,7 +369,7 @@ mod tests {
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -384,7 +387,7 @@ mod tests {
type Event = ();
}
impl Trait for Test {
type Proposal = Proposal;
type Proposal = Call;
}
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
@@ -422,12 +425,12 @@ mod tests {
});
}
fn set_balance_proposal(value: u64) -> Proposal {
Proposal::Balances(balances::PrivCall::set_balance(balances::address::Address::Id(42), value, 0))
fn set_balance_proposal(value: u64) -> Call {
Call::Balances(balances::Call::set_balance(balances::address::Address::Id(42), value, 0))
}
fn propose_set_balance(who: u64, value: u64, locked: u64) -> super::Result {
Democracy::propose(&who, Box::new(set_balance_proposal(value)), locked)
Democracy::propose(Origin::signed(who), Box::new(set_balance_proposal(value)), locked)
}
#[test]
@@ -452,7 +455,7 @@ mod tests {
System::set_block_number(2);
let r = 0;
assert_ok!(Democracy::vote(&1, r, true));
assert_ok!(Democracy::vote(Origin::signed(1), r, true));
assert_eq!(Democracy::referendum_count(), 1);
assert_eq!(Democracy::voters_for(r), vec![1]);
@@ -470,10 +473,10 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
assert_ok!(propose_set_balance(1, 2, 5));
assert_ok!(Democracy::second(&2, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(Origin::signed(2), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_eq!(Balances::free_balance(&1), 5);
assert_eq!(Balances::free_balance(&2), 15);
assert_eq!(Balances::free_balance(&5), 35);
@@ -485,10 +488,10 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
assert_ok!(propose_set_balance(1, 2, 5));
assert_ok!(Democracy::second(&2, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(&5, 0));
assert_ok!(Democracy::second(Origin::signed(2), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_ok!(Democracy::second(Origin::signed(5), 0));
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
assert_eq!(Balances::free_balance(&1), 10);
assert_eq!(Balances::free_balance(&2), 20);
@@ -517,7 +520,7 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
assert_ok!(propose_set_balance(2, 2, 11));
assert_noop!(Democracy::second(&1, 0), "seconder\'s balance too low");
assert_noop!(Democracy::second(Origin::signed(1), 0), "seconder\'s balance too low");
});
}
@@ -531,17 +534,17 @@ mod tests {
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
System::set_block_number(1);
assert_ok!(Democracy::vote(&1, 0, true));
assert_ok!(Democracy::vote(Origin::signed(1), 0, true));
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
assert_eq!(Balances::free_balance(&42), 4);
System::set_block_number(2);
assert_ok!(Democracy::vote(&1, 1, true));
assert_ok!(Democracy::vote(Origin::signed(1), 1, true));
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
assert_eq!(Balances::free_balance(&42), 3);
System::set_block_number(3);
assert_ok!(Democracy::vote(&1, 2, true));
assert_ok!(Democracy::vote(Origin::signed(1), 2, true));
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
});
}
@@ -551,7 +554,7 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&1, r, true));
assert_ok!(Democracy::vote(Origin::signed(1), r, true));
assert_eq!(Democracy::voters_for(r), vec![1]);
assert_eq!(Democracy::vote_of((r, 1)), Some(true));
@@ -568,8 +571,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&1, r, true));
assert_ok!(Democracy::cancel_referendum(r));
assert_ok!(Democracy::vote(Origin::signed(1), r, true));
assert_ok!(Democracy::cancel_referendum(Origin::ROOT, r));
assert_eq!(Democracy::end_block(System::block_number()), Ok(()));
@@ -582,7 +585,7 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&1, r, false));
assert_ok!(Democracy::vote(Origin::signed(1), r, false));
assert_eq!(Democracy::voters_for(r), vec![1]);
assert_eq!(Democracy::vote_of((r, 1)), Some(false));
@@ -599,12 +602,12 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&1, r, true));
assert_ok!(Democracy::vote(&2, r, false));
assert_ok!(Democracy::vote(&3, r, false));
assert_ok!(Democracy::vote(&4, r, true));
assert_ok!(Democracy::vote(&5, r, false));
assert_ok!(Democracy::vote(&6, r, true));
assert_ok!(Democracy::vote(Origin::signed(1), r, true));
assert_ok!(Democracy::vote(Origin::signed(2), r, false));
assert_ok!(Democracy::vote(Origin::signed(3), r, false));
assert_ok!(Democracy::vote(Origin::signed(4), r, true));
assert_ok!(Democracy::vote(Origin::signed(5), r, false));
assert_ok!(Democracy::vote(Origin::signed(6), r, true));
assert_eq!(Democracy::tally(r), (110, 100));
@@ -619,8 +622,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&5, r, false));
assert_ok!(Democracy::vote(&6, r, true));
assert_ok!(Democracy::vote(Origin::signed(5), r, false));
assert_ok!(Democracy::vote(Origin::signed(6), r, true));
assert_eq!(Democracy::tally(r), (60, 50));
@@ -638,9 +641,9 @@ mod tests {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, set_balance_proposal(2), VoteThreshold::SuperMajorityApprove).unwrap();
assert_ok!(Democracy::vote(&4, r, true));
assert_ok!(Democracy::vote(&5, r, false));
assert_ok!(Democracy::vote(&6, r, true));
assert_ok!(Democracy::vote(Origin::signed(4), r, true));
assert_ok!(Democracy::vote(Origin::signed(5), r, false));
assert_ok!(Democracy::vote(Origin::signed(6), r, true));
assert_eq!(Democracy::tally(r), (100, 50));
+54 -44
View File
@@ -60,6 +60,7 @@ extern crate substrate_runtime_balances as balances;
use runtime_primitives::traits::OnFinalise;
use runtime_support::{StorageValue, dispatch::Result};
use system::{ensure_signed, ensure_root};
/// Our module's configuration trait. All our types and consts go in here. If the
/// module is dependent on specific other modules, then their configuration traits
@@ -73,45 +74,44 @@ pub trait Trait: balances::Trait {
// The module declaration. This states the entry points that we handle. The
// macro takes care of the marshalling of arguments and dispatch.
//
// Anyone can have these functions execute by signing and submitting
// an extrinsic. Ensure that calls into each of these execute in a time, memory and
// using storage space proportional to any costs paid for by the caller or otherwise the
// difficulty of forcing the call to happen.
//
// Generally you'll want to split these into three groups:
// - Public calls that are signed by an external account.
// - Root calls that are allowed to be made only by the governance system.
// - Inherent calls that are allowed to be made only by the block authors and validators.
//
// Information about where this dispatch initiated from is provided as the first argument
// "origin". As such functions must always look like:
//
// `fn foo(origin, bar: Bar, baz: Baz) -> Result = 0;`
//
// The `Result` is required as part of the syntax (and expands to the conventional dispatch
// result of `Result<(), &'static str>`).
//
// When you come to `impl` them later in the module, you must specify the full type for `origin`:
//
// `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }`
//
// There are three entries in the `system::Origin` enum that correspond
// to the above bullets: `::Signed(AccountId)`, `::Root` and `::Inherent`. You should always match
// against them as the first thing you do in your function. There are three convenience calls
// in system that do the matching for you and return a convenient result: `ensure_signed`,
// `ensure_root` and `ensure_inherent`.
decl_module! {
// Simple declaration of the `Module` type. Lets the macro know what its working on.
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// This is your public interface. Be extremely careful.
/// This is just a simple example of how to interact with the module from the external
/// world.
fn accumulate_dummy(origin, increase_by: T::Balance) -> Result;
// The unpriviledged entry points. Any account can call into these by signing and submitting
// an extrinsic. Ensure that calls into each of these execute in a time, memory and
// using storage space proportional to any costs paid for by the caller.
//
// The account that is calling this (i.e. the one that signed the extrinsic) is provided
// via the `aux` argument, always first in each function call. As such functions must
// always look like:
//
// `fn foo(aux, bar: Bar, baz: Baz) -> Result = 0;`
//
// The `Result` is required as part of the syntax (and expands to the conventional dispatch
// result of `Result<(), &'static str>`). The index after `=` must be unique within this
// enum (the `PrivCall` enum is allowed to reuse indexes).
//
// When you come to `impl` them later in the module, you must specify the full type for `aux`:
//
// `fn foo(aux: T::PublicAux, bar: Bar, baz: Baz) { ... }`
//
// This is your public interface. Be extremely careful.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
// This is just a simple example of how to interact with the module from the external
// world.
fn accumulate_dummy(aux, increase_by: T::Balance) -> Result;
}
// The priviledged entry points. These are provided to allow any governance modules in
// the runtime to be able to execute common functions. Unlike for `Call` there is no
// auxilliary data to encode the sender (since there is no sender). Though still important
// to ensure that these execute in reasonable time and space, they can do what would
// otherwise be costly or unsafe operations.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
// A priviledged call; in this case it resets our dummy value to something new.
fn set_dummy(new_dummy: T::Balance) -> Result;
/// A priviledged call; in this case it resets our dummy value to something new.
fn set_dummy(origin, new_dummy: T::Balance) -> Result;
}
}
@@ -190,7 +190,7 @@ impl<T: Trait> Module<T> {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
// Implement Calls/PrivCalls and add public immutables and private mutables.
// Implement Calls and add public immutables and private mutables.
// Implement dispatched function `accumulate_dummy`. This just increases the value
// of `Dummy` by `increase_by`.
@@ -206,7 +206,7 @@ impl<T: Trait> Module<T> {
// The first is relatively easy to audit for - just ensure all panickers are removed from
// logic that executes in production (which you do anyway, right?!). To ensure the second
// is followed, you should do all tests for validity at the top of your function. This
// is stuff like checking the sender (`aux`) or that state is such that the operation
// is stuff like checking the sender (`origin`) or that state is such that the operation
// makes sense.
//
// Once you've determined that it's all good, then enact the operation and change storage.
@@ -227,7 +227,10 @@ impl<T: Trait> Module<T> {
// no progress.
//
// If you don't respect these rules, it is likely that your chain will be attackable.
fn accumulate_dummy(_aux: &T::PublicAux, increase_by: T::Balance) -> Result {
fn accumulate_dummy(origin: T::Origin, increase_by: T::Balance) -> Result {
// This is a public call, so we ensure that the origin is some signed account.
let _sender = ensure_signed(origin)?;
// Read the value of dummy from storage.
let dummy = Self::dummy();
// Will also work using the `::get` on the storage item type iself:
@@ -248,13 +251,16 @@ impl<T: Trait> Module<T> {
Ok(())
}
// Implementation of a priviledged call. This doesn't have an `aux` parameter because
// Implementation of a priviledged call. This doesn't have an `origin` parameter because
// it's not (directly) from an extrinsic, but rather the system as a whole has decided
// to execute it. Different runtimes have different reasons for allow priviledged
// calls to be executed - we don't need to care why. Because it's priviledged, we can
// assume it's a one-off operation and substantial processing/storage/memory can be used
// without worrying about gameability or attack scenarios.
fn set_dummy(new_value: T::Balance) -> Result {
fn set_dummy(origin: T::Origin, new_value: T::Balance) -> Result {
// This is a privileged call, so we ensure that the origin is "Root".
ensure_root(origin)?;
// Put the new value into storage.
<Dummy<T>>::put(new_value);
@@ -323,13 +329,17 @@ mod tests {
// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
use runtime_primitives::testing::{Digest, Header};
impl_outer_origin! {
pub enum Origin for Test {}
}
// For testing the module, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of modules we want to use.
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -370,7 +380,7 @@ mod tests {
assert_eq!(Example::dummy(), Some(42));
// Check that accumulate works when we have Some value in Dummy already.
assert_ok!(Example::accumulate_dummy(&0, 27));
assert_ok!(Example::accumulate_dummy(Origin::signed(1), 27));
assert_eq!(Example::dummy(), Some(69));
// Check that finalising the block removes Dummy from storage.
@@ -378,7 +388,7 @@ mod tests {
assert_eq!(Example::dummy(), None);
// Check that accumulate works when we Dummy has None in it.
assert_ok!(Example::accumulate_dummy(&0, 42));
assert_ok!(Example::accumulate_dummy(Origin::signed(1), 42));
assert_eq!(Example::dummy(), Some(42));
});
}
@@ -8,7 +8,6 @@ hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-codec-derive = { path = "../../codec/derive", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
@@ -18,10 +17,7 @@ substrate-runtime-system = { path = "../system", default_features = false }
[dev-dependencies]
substrate-primitives = { path = "../../primitives" }
substrate-runtime-balances = { path = "../balances" }
substrate-runtime-session = { path = "../session" }
substrate-runtime-staking = { path = "../staking" }
substrate-runtime-consensus = { path = "../consensus" }
substrate-runtime-timestamp = { path = "../timestamp" }
substrate-codec-derive = { path = "../../codec/derive" }
[features]
default = ["std"]
@@ -31,7 +27,6 @@ std = [
"serde/std",
"serde_derive",
"substrate-codec/std",
"substrate-codec-derive/std",
"substrate-runtime-primitives/std",
"substrate-runtime-io/std",
"substrate-runtime-system/std",
@@ -37,9 +37,6 @@ extern crate substrate_codec as codec;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_runtime_system as system;
#[cfg(test)]
extern crate substrate_runtime_timestamp as timestamp;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
@@ -47,23 +44,14 @@ extern crate hex_literal;
#[cfg(test)]
extern crate substrate_primitives;
#[cfg(test)]
extern crate substrate_runtime_consensus as consensus;
#[cfg(test)]
extern crate substrate_runtime_session as session;
#[cfg(test)]
extern crate substrate_runtime_balances as balances;
#[cfg(test)]
extern crate substrate_runtime_staking as staking;
use rstd::prelude::*;
use rstd::marker::PhantomData;
use rstd::result;
use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalise,
MakePayment, Hash, AuxLookup};
MakePayment, Hash};
use codec::{Codec, Encode};
use system::extrinsics_root;
use primitives::{ApplyOutcome, ApplyError};
@@ -94,7 +82,7 @@ impl<
Address,
System: system::Trait,
Block: traits::Block<Header=System::Header, Hash=System::Hash>,
Lookup: AuxLookup<Source=Address, Target=System::AccountId>,
Lookup: traits::Lookup<Source=Address, Target=System::AccountId>,
Payment: MakePayment<System::AccountId>,
Finalisation: OnFinalise<System::BlockNumber>,
> Executive<System, Block, Lookup, Payment, Finalisation> where
@@ -186,20 +174,20 @@ impl<
// Verify the signature is good.
let xt = uxt.check_with(Lookup::lookup).map_err(internal::ApplyError::BadSignature)?;
if xt.sender() != &Default::default() {
if let Some(sender) = xt.sender() {
// check index
let expected_index = <system::Module<System>>::account_nonce(xt.sender());
let expected_index = <system::Module<System>>::account_nonce(sender);
if xt.index() != &expected_index { return Err(
if xt.index() < &expected_index { internal::ApplyError::Stale } else { internal::ApplyError::Future }
) }
// pay any fees.
Payment::make_payment(xt.sender(), encoded_len).map_err(|_| internal::ApplyError::CantPay)?;
Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?;
// AUDIT: Under no circumstances may this function panic from here onwards.
// increment nonce in storage
<system::Module<System>>::inc_account_nonce(xt.sender());
<system::Module<System>>::inc_account_nonce(sender);
}
// decode parameters and dispatch
@@ -231,12 +219,12 @@ mod tests {
use runtime_io::with_externalities;
use substrate_primitives::{H256, KeccakHasher};
use primitives::BuildStorage;
use primitives::traits::{Identity, Header as HeaderT, BlakeTwo256, AuxLookup};
use primitives::traits::{Header as HeaderT, BlakeTwo256, Lookup};
use primitives::testing::{Digest, Header, Block};
use system;
struct NullLookup;
impl AuxLookup for NullLookup {
impl Lookup for NullLookup {
type Source = u64;
type Target = u64;
fn lookup(s: Self::Source) -> Result<Self::Target, &'static str> {
@@ -244,30 +232,22 @@ mod tests {
}
}
impl_outer_origin! {
pub enum Origin for Runtime {
}
}
impl_outer_event!{
pub enum MetaEvent for Test {
balances, session, staking
pub enum MetaEvent for Runtime {
balances
}
}
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Test;
impl consensus::Trait for Test {
const NOTE_OFFLINE_POSITION: u32 = 1;
type Log = u64;
type SessionKey = u64;
type OnOfflineValidator = staking::Module<Test>;
}
impl balances::Trait for Test {
type Balance = u64;
type AccountIndex = u64;
type OnFreeBalanceZero = staking::Module<Test>;
type EnsureAccountLiquid = staking::Module<Test>;
type Event = MetaEvent;
}
impl system::Trait for Test {
type PublicAux = Self::AccountId;
pub struct Runtime;
impl system::Trait for Runtime {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = substrate_primitives::H256;
@@ -277,27 +257,21 @@ mod tests {
type Header = Header;
type Event = MetaEvent;
}
impl session::Trait for Test {
type ConvertAccountIdToSessionKey = Identity;
type OnSessionChange = staking::Module<Test>;
impl balances::Trait for Runtime {
type Balance = u64;
type AccountIndex = u64;
type OnFreeBalanceZero = ();
type EnsureAccountLiquid = ();
type Event = MetaEvent;
}
impl staking::Trait for Test {
type OnRewardMinted = ();
type Event = MetaEvent;
}
impl timestamp::Trait for Test {
const TIMESTAMP_SET_POSITION: u32 = 0;
type Moment = u64;
}
type TestXt = primitives::testing::TestXt<Call<Test>>;
type Executive = super::Executive<Test, Block<TestXt>, NullLookup, balances::Module<Test>, (session::Module<Test>, staking::Module<Test>)>;
type TestXt = primitives::testing::TestXt<Call<Runtime>>;
type Executive = super::Executive<Runtime, Block<TestXt>, NullLookup, balances::Module<Runtime>, ()>;
#[test]
fn staking_balance_transfer_dispatch_works() {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(balances::GenesisConfig::<Test> {
fn balance_transfer_dispatch_works() {
let mut t = system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
t.extend(balances::GenesisConfig::<Runtime> {
balances: vec![(1, 111)],
transaction_base_fee: 10,
transaction_byte_fee: 0,
@@ -306,34 +280,19 @@ mod tests {
creation_fee: 0,
reclaim_rebate: 0,
}.build_storage().unwrap());
t.extend(staking::GenesisConfig::<Test> {
sessions_per_era: 0,
current_era: 0,
intentions: vec![],
validator_count: 0,
minimum_validator_count: 0,
bonding_duration: 0,
early_era_slash: 0,
session_reward: 0,
offline_slash_grace: 0,
}.build_storage().unwrap());
let xt = primitives::testing::TestXt((1, 0, Call::transfer(2.into(), 69)));
let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2.into(), 69));
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Executive::initialise_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()));
Executive::apply_extrinsic(xt).unwrap();
assert_eq!(<balances::Module<Test>>::total_balance(&1), 32);
assert_eq!(<balances::Module<Test>>::total_balance(&2), 69);
assert_eq!(<balances::Module<Runtime>>::total_balance(&1), 32);
assert_eq!(<balances::Module<Runtime>>::total_balance(&2), 69);
});
}
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(balances::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(consensus::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(session::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(staking::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(timestamp::GenesisConfig::<Test>::default().build_storage().unwrap());
let mut t = system::GenesisConfig::<Runtime>::default().build_storage().unwrap();
t.extend(balances::GenesisConfig::<Runtime>::default().build_storage().unwrap());
t.into()
}
@@ -347,7 +306,7 @@ mod tests {
// Blake
// state_root: hex!("02532989c613369596025dfcfc821339fc9861987003924913a5a1382f87034a").into(),
// Keccak
state_root: hex!("ffe27b4c3a8b421fa10592be61fb28eca7ebbe04cbfa99cdda9f703f35522569").into(),
state_root: hex!("14a253cb1c5f38beeec8bee962a941b2ba0773b7593564fbe62b9c3a46784df5").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
},
@@ -381,7 +340,7 @@ mod tests {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("ffe27b4c3a8b421fa10592be61fb28eca7ebbe04cbfa99cdda9f703f35522569").into(),
state_root: hex!("14a253cb1c5f38beeec8bee962a941b2ba0773b7593564fbe62b9c3a46784df5").into(),
extrinsics_root: [0u8; 32].into(),
digest: Digest { logs: vec![], },
},
@@ -393,11 +352,11 @@ mod tests {
#[test]
fn bad_extrinsic_not_inserted() {
let mut t = new_test_ext();
let xt = primitives::testing::TestXt((1, 42, Call::transfer(33.into(), 69)));
let xt = primitives::testing::TestXt(Some(1), 42, Call::transfer(33.into(), 69));
with_externalities(&mut t, || {
Executive::initialise_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()));
assert!(Executive::apply_extrinsic(xt).is_err());
assert_eq!(<system::Module<Test>>::extrinsic_index(), Some(0));
assert_eq!(<system::Module<Runtime>>::extrinsic_index(), Some(0));
});
}
}
@@ -1,514 +0,0 @@
// Copyright 2017 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 implementations of Extrinsic/Header/Block.
#[cfg(feature = "std")]
use std::fmt;
#[cfg(feature = "std")]
use serde::{Deserialize, Deserializer};
use rstd::prelude::*;
use codec::{Decode, Encode, Codec, Input, Output};
use runtime_support::AuxDispatchable;
use traits::{self, Member, SimpleArithmetic, SimpleBitOps, MaybeDisplay, Block as BlockT,
Header as HeaderT, Hash as HashT, DigestItem as DigestItemT};
use rstd::ops;
use bft::Justification;
/// Definition of something that the external world might want to say.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct Extrinsic<Address, Index, Call> {
/// Who signed it (note this is not a signature).
pub signed: Address,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// The function that should be called.
pub function: Call,
}
/// A extrinsic right from the external world. Unchecked.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UncheckedExtrinsic<Address, Index, Call, Signature> {
/// The actual extrinsic information.
pub extrinsic: Extrinsic<Address, Index, Call>,
/// The signature.
pub signature: Signature,
}
impl<Address, Index, Call, Signature> UncheckedExtrinsic<Address, Index, Call, Signature> {
/// New instance.
pub fn new(extrinsic: Extrinsic<Address, Index, Call>, signature: Signature) -> Self {
UncheckedExtrinsic {
extrinsic,
signature,
}
}
}
impl<Address, AccountId, Index, Call, Signature> UncheckedExtrinsic<Address, Index, Call, ::MaybeUnsigned<Signature>> where
Signature: traits::Verify<Signer=AccountId> + Default + Eq,
AccountId: Default + Eq,
{
/// `true` if this extrinsic is signed.
pub fn is_signed(&self) -> bool {
self.signature.is_signed()
}
}
impl<Address, AccountId, Index, Call, Signature, ThisLookup> traits::Checkable<ThisLookup>
for UncheckedExtrinsic<Address, Index, Call, ::MaybeUnsigned<Signature>>
where
Address: Member + Default + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
Call: Member,
Signature: traits::Verify<Signer=AccountId> + Eq + Default,
AccountId: Member + Default + MaybeDisplay,
::MaybeUnsigned<Signature>: Member,
Extrinsic<AccountId, Index, Call>: Codec,
ThisLookup: FnOnce(Address) -> Result<AccountId, &'static str>,
{
type Checked = CheckedExtrinsic<AccountId, Index, Call>;
fn check_with(self, lookup: ThisLookup) -> Result<Self::Checked, &'static str> {
if !self.is_signed() {
Ok(CheckedExtrinsic(Extrinsic {
signed: Default::default(),
index: self.extrinsic.index,
function: self.extrinsic.function,
}))
} else {
let extrinsic: Extrinsic<AccountId, Index, Call>
= Extrinsic {
signed: lookup(self.extrinsic.signed)?,
index: self.extrinsic.index,
function: self.extrinsic.function,
};
if ::verify_encoded_lazy(&self.signature, &extrinsic, &extrinsic.signed) {
Ok(CheckedExtrinsic(extrinsic))
} else {
Err("bad signature in extrinsic")
}
}
}
}
impl<Address, Index, Call, Signature> Decode
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Signature: Decode,
Extrinsic<Address, Index, Call>: Decode,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
// 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 u32, which has the total number of bytes following (we don't need
// to use this).
let _length_do_not_remove_me_see_above: u32 = Decode::decode(input)?;
Some(UncheckedExtrinsic::new(
Decode::decode(input)?,
Decode::decode(input)?
))
}
}
impl<Address, Index, Call, Signature> Encode
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Signature: Encode,
Extrinsic<Address, Index, Call>: Encode,
{
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
// need to prefix with the total length as u32 to ensure it's binary comptible with
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
v.extend(&[0u8; 4]);
self.extrinsic.encode_to(&mut v);
self.signature.encode_to(&mut v);
let length = (v.len() - 4) as u32;
length.using_encoded(|s| v[0..4].copy_from_slice(s));
v
}
}
/// TODO: use derive when possible.
#[cfg(feature = "std")]
impl<Address, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<Address, Index, Call, Signature> where
Address: fmt::Debug,
Index: fmt::Debug,
Call: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedExtrinsic({:?})", self.extrinsic)
}
}
/// A type-safe indicator that a extrinsic has been checked.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct CheckedExtrinsic<AccountId, Index, Call>
(Extrinsic<AccountId, Index, Call>);
impl<AccountId, Index, Call> ops::Deref
for CheckedExtrinsic<AccountId, Index, Call>
where
AccountId: Member + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
Call: Member,
{
type Target = Extrinsic<AccountId, Index, Call>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<AccountId, Index, Call> traits::Applyable
for CheckedExtrinsic<AccountId, Index, Call>
where
AccountId: Member + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
Call: Member + AuxDispatchable<Aux = AccountId>,
{
type Index = Index;
type AccountId = AccountId;
fn index(&self) -> &Self::Index {
&self.0.index
}
fn sender(&self) -> &Self::AccountId {
&self.0.signed
}
fn apply(self) -> Result<(), &'static str> {
let xt = self.0;
xt.function.dispatch(&xt.signed)
}
}
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Digest<Item> {
pub logs: Vec<Item>,
}
impl<Item> Default for Digest<Item> {
fn default() -> Self {
Digest { logs: Vec::new(), }
}
}
impl<Item> traits::Digest for Digest<Item> where
Item: DigestItemT + Codec
{
type Item = Item;
fn logs(&self) -> &[Self::Item] {
&self.logs
}
fn push(&mut self, item: Self::Item) {
self.logs.push(item);
}
}
/// Abstraction over a block header for a substrate chain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header<Number, Hash: HashT, DigestItem> {
/// The parent hash.
pub parent_hash: <Hash as HashT>::Output,
/// The block number.
pub number: Number,
/// The state trie merkle root
pub state_root: <Hash as HashT>::Output,
/// The merkle root of the extrinsics.
pub extrinsics_root: <Hash as HashT>::Output,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest<DigestItem>,
}
// Hack to work around the fact that deriving deserialize doesn't work nicely with
// the `hashing` trait used as a parameter.
// dummy struct that uses the hash type directly.
// https://github.com/serde-rs/serde/issues/1296
#[cfg(feature = "std")]
#[serde(rename_all = "camelCase")]
#[derive(Deserialize)]
struct DeserializeHeader<N, H, D> {
parent_hash: H,
number: N,
state_root: H,
extrinsics_root: H,
digest: Digest<D>,
}
#[cfg(feature = "std")]
impl<N, D, Hash: HashT> From<DeserializeHeader<N, Hash::Output, D>> for Header<N, Hash, D> {
fn from(other: DeserializeHeader<N, Hash::Output, D>) -> Self {
Header {
parent_hash: other.parent_hash,
number: other.number,
state_root: other.state_root,
extrinsics_root: other.extrinsics_root,
digest: other.digest,
}
}
}
#[cfg(feature = "std")]
impl<'a, Number: 'a, Hash: 'a + HashT, DigestItem: 'a> Deserialize<'a> for Header<Number, Hash, DigestItem> where
Number: Deserialize<'a>,
Hash::Output: Deserialize<'a>,
DigestItem: Deserialize<'a>,
{
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
DeserializeHeader::<Number, Hash::Output, DigestItem>::deserialize(de).map(Into::into)
}
}
// TODO [ToDr] Issue with bounds
impl<Number, Hash, DigestItem> Decode for Header<Number, Hash, DigestItem> where
Number: Decode,
Hash: HashT,
Hash::Output: Decode,
DigestItem: Decode,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Header {
parent_hash: Decode::decode(input)?,
number: Decode::decode(input)?,
state_root: Decode::decode(input)?,
extrinsics_root: Decode::decode(input)?,
digest: Decode::decode(input)?,
})
}
}
impl<Number, Hash, DigestItem> Encode for Header<Number, Hash, DigestItem> where
Number: Encode,
Hash: HashT,
Hash::Output: Encode,
DigestItem: Encode,
{
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.parent_hash);
dest.push(&self.number);
dest.push(&self.state_root);
dest.push(&self.extrinsics_root);
dest.push(&self.digest);
}
}
impl<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestItem> where
Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec,
Hash: HashT,
DigestItem: DigestItemT + Codec,
Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec,
{
type Number = Number;
type Hash = <Hash as HashT>::Output;
type Hashing = Hash;
type Digest = Digest<DigestItem>;
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) -> &Self::Digest { &self.digest }
fn set_digest(&mut self, digest: Self::Digest) { self.digest = digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self {
Header {
number, extrinsics_root: extrinsics_root, state_root, parent_hash, digest
}
}
}
impl<Number, Hash, DigestItem> Header<Number, Hash, DigestItem> where
Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec,
Hash: HashT,
DigestItem: DigestItemT + Codec,
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)
}
}
/// Something to identify a block.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, 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) -> Result<(), fmt::Error> {
write!(f, "{:?}", self)
}
}
/// Abstraction over a substrate block.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Block<Header, Extrinsic> {
/// The block header.
pub header: Header,
/// The accompanying extrinsics.
pub extrinsics: Vec<Extrinsic>,
}
impl<Header, Extrinsic> traits::Block for Block<Header, Extrinsic>
where
Header: HeaderT,
Extrinsic: Member + Codec,
{
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 }
}
}
/// Abstraction over a substrate block and justification.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct SignedBlock<Header, Extrinsic, Hash> {
/// Full block.
pub block: Block<Header, Extrinsic>,
/// Block header justification.
pub justification: Justification<Hash>,
}
#[cfg(test)]
mod tests {
use codec::{Decode, Encode};
use substrate_primitives::{H256, H512};
use super::{Digest, Header, UncheckedExtrinsic, Extrinsic};
type Block = super::Block<
Header<u64, ::traits::BlakeTwo256, Vec<u8>>,
UncheckedExtrinsic<H256, u64, u64, ::Ed25519Signature>,
>;
#[test]
fn block_roundtrip_serialization() {
let block: Block = Block {
header: Header {
parent_hash: [0u8; 32].into(),
number: 100_000,
state_root: [1u8; 32].into(),
extrinsics_root: [2u8; 32].into(),
digest: Digest { logs: vec![vec![1, 2, 3], vec![4, 5, 6]] },
},
extrinsics: vec![
UncheckedExtrinsic::new(
Extrinsic {
signed: [255u8; 32].into(),
index: 0,
function: 100,
},
H512::from([0u8; 64]).into()
),
UncheckedExtrinsic::new(
Extrinsic {
signed: [128u8; 32].into(),
index: 100,
function: 99,
},
H512::from([255u8; 64]).into()
)
]
};
{
let encoded = ::serde_json::to_vec(&block).unwrap();
let decoded: Block = ::serde_json::from_slice(&encoded).unwrap();
assert_eq!(block, decoded);
}
{
let encoded = block.encode();
let decoded = Block::decode(&mut &encoded[..]).unwrap();
assert_eq!(block, decoded);
}
}
}
@@ -0,0 +1,105 @@
// Copyright 2017 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;
use rstd::prelude::*;
use codec::Codec;
use traits::{self, Member, Block as BlockT, Header as HeaderT};
use bft::Justification;
/// Something to identify a block.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, 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) -> Result<(), fmt::Error> {
write!(f, "{:?}", self)
}
}
/// Abstraction over a substrate block.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Block<Header, Extrinsic> {
/// The block header.
pub header: Header,
/// The accompanying extrinsics.
pub extrinsics: Vec<Extrinsic>,
}
impl<Header, Extrinsic> traits::Block for Block<Header, Extrinsic>
where
Header: HeaderT,
Extrinsic: Member + Codec,
{
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 }
}
}
/// Abstraction over a substrate block and justification.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct SignedBlock<Header, Extrinsic, Hash> {
/// Full block.
pub block: Block<Header, Extrinsic>,
/// Block header justification.
pub justification: Justification<Hash>,
}
@@ -0,0 +1,59 @@
// Copyright 2017 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 runtime_support::Dispatchable;
use traits::{self, Member, SimpleArithmetic, MaybeDisplay};
/// 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)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
pub struct CheckedExtrinsic<AccountId, Index, Call> {
/// Who this purports to be from, if anyone (note this is not a signature).
pub signed: Option<AccountId>,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// The function that should be called.
pub function: Call,
}
impl<AccountId, Index, Call> traits::Applyable
for CheckedExtrinsic<AccountId, Index, Call>
where
AccountId: Member + MaybeDisplay,
Index: Member + MaybeDisplay + SimpleArithmetic,
Call: Member + Dispatchable,
<Call as Dispatchable>::Origin: From<Option<AccountId>>
{
type Index = Index;
type AccountId = AccountId;
fn index(&self) -> &Self::Index {
&self.index
}
fn sender(&self) -> Option<&Self::AccountId> {
self.signed.as_ref()
}
fn apply(self) -> Result<(), &'static str> {
self.function.dispatch(self.signed.into())
}
}
@@ -0,0 +1,193 @@
// Copyright 2017 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 header and digest.
#[cfg(feature = "std")]
use serde::{Deserialize, Deserializer};
use rstd::prelude::*;
use codec::{Decode, Encode, Codec, Input, Output};
use traits::{self, Member, SimpleArithmetic, SimpleBitOps, MaybeDisplay,
Hash as HashT, DigestItem as DigestItemT};
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct Digest<Item> {
pub logs: Vec<Item>,
}
impl<Item> Default for Digest<Item> {
fn default() -> Self {
Digest { logs: Vec::new(), }
}
}
impl<Item> traits::Digest for Digest<Item> where
Item: DigestItemT + Codec
{
type Item = Item;
fn logs(&self) -> &[Self::Item] {
&self.logs
}
fn push(&mut self, item: Self::Item) {
self.logs.push(item);
}
}
/// Abstraction over a block header for a substrate chain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header<Number, Hash: HashT, DigestItem> {
/// The parent hash.
pub parent_hash: <Hash as HashT>::Output,
/// The block number.
pub number: Number,
/// The state trie merkle root
pub state_root: <Hash as HashT>::Output,
/// The merkle root of the extrinsics.
pub extrinsics_root: <Hash as HashT>::Output,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest<DigestItem>,
}
// Hack to work around the fact that deriving deserialize doesn't work nicely with
// the `hashing` trait used as a parameter.
// dummy struct that uses the hash type directly.
// https://github.com/serde-rs/serde/issues/1296
#[cfg(feature = "std")]
#[serde(rename_all = "camelCase")]
#[derive(Deserialize)]
struct DeserializeHeader<N, H, D> {
parent_hash: H,
number: N,
state_root: H,
extrinsics_root: H,
digest: Digest<D>,
}
#[cfg(feature = "std")]
impl<N, D, Hash: HashT> From<DeserializeHeader<N, Hash::Output, D>> for Header<N, Hash, D> {
fn from(other: DeserializeHeader<N, Hash::Output, D>) -> Self {
Header {
parent_hash: other.parent_hash,
number: other.number,
state_root: other.state_root,
extrinsics_root: other.extrinsics_root,
digest: other.digest,
}
}
}
#[cfg(feature = "std")]
impl<'a, Number: 'a, Hash: 'a + HashT, DigestItem: 'a> Deserialize<'a> for Header<Number, Hash, DigestItem> where
Number: Deserialize<'a>,
Hash::Output: Deserialize<'a>,
DigestItem: Deserialize<'a>,
{
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
DeserializeHeader::<Number, Hash::Output, DigestItem>::deserialize(de).map(Into::into)
}
}
// TODO [ToDr] Issue with bounds
impl<Number, Hash, DigestItem> Decode for Header<Number, Hash, DigestItem> where
Number: Decode,
Hash: HashT,
Hash::Output: Decode,
DigestItem: Decode,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Header {
parent_hash: Decode::decode(input)?,
number: Decode::decode(input)?,
state_root: Decode::decode(input)?,
extrinsics_root: Decode::decode(input)?,
digest: Decode::decode(input)?,
})
}
}
impl<Number, Hash, DigestItem> Encode for Header<Number, Hash, DigestItem> where
Number: Encode,
Hash: HashT,
Hash::Output: Encode,
DigestItem: Encode,
{
fn encode_to<T: Output>(&self, dest: &mut T) {
dest.push(&self.parent_hash);
dest.push(&self.number);
dest.push(&self.state_root);
dest.push(&self.extrinsics_root);
dest.push(&self.digest);
}
}
impl<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestItem> where
Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec,
Hash: HashT,
DigestItem: DigestItemT + Codec,
Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec,
{
type Number = Number;
type Hash = <Hash as HashT>::Output;
type Hashing = Hash;
type Digest = Digest<DigestItem>;
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) -> &Self::Digest { &self.digest }
fn set_digest(&mut self, digest: Self::Digest) { self.digest = digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self {
Header {
number, extrinsics_root: extrinsics_root, state_root, parent_hash, digest
}
}
}
impl<Number, Hash, DigestItem> Header<Number, Hash, DigestItem> where
Number: Member + ::rstd::hash::Hash + Copy + Codec + MaybeDisplay + SimpleArithmetic + Codec,
Hash: HashT,
DigestItem: DigestItemT + Codec,
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)
}
}
@@ -0,0 +1,29 @@
// Copyright 2017 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 implementations of Extrinsic/Header/Block.
mod unchecked_extrinsic;
mod checked_extrinsic;
mod header;
mod block;
#[cfg(test)]
mod tests;
pub use self::unchecked_extrinsic::UncheckedExtrinsic;
pub use self::checked_extrinsic::CheckedExtrinsic;
pub use self::header::{Header, Digest};
pub use self::block::{Block, SignedBlock, BlockId};
@@ -0,0 +1,66 @@
// Copyright 2017 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 codec::{Decode, Encode};
use substrate_primitives::{H256, H512};
use super::{Digest, Header, UncheckedExtrinsic};
type Block = super::Block<
Header<u64, ::traits::BlakeTwo256, Vec<u8>>,
UncheckedExtrinsic<H256, u64, u64, ::Ed25519Signature>,
>;
#[test]
fn block_roundtrip_serialization() {
let block: Block = Block {
header: Header {
parent_hash: [0u8; 32].into(),
number: 100_000,
state_root: [1u8; 32].into(),
extrinsics_root: [2u8; 32].into(),
digest: Digest { logs: vec![vec![1, 2, 3], vec![4, 5, 6]] },
},
extrinsics: vec![
UncheckedExtrinsic::new_signed(
0,
100,
[255u8; 32].into(),
H512::from([0u8; 64]).into()
),
UncheckedExtrinsic::new_signed(
100,
99,
[128u8; 32].into(),
H512::from([255u8; 64]).into()
)
]
};
{
let encoded = ::serde_json::to_vec(&block).unwrap();
let decoded: Block = ::serde_json::from_slice(&encoded).unwrap();
assert_eq!(block, decoded);
}
{
let encoded = block.encode();
let decoded = Block::decode(&mut &encoded[..]).unwrap();
assert_eq!(block, decoded);
}
}
@@ -0,0 +1,159 @@
// Copyright 2017 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 std::fmt;
use rstd::prelude::*;
use codec::{Decode, Encode, Input};
use traits::{self, Member, SimpleArithmetic, MaybeDisplay};
use super::CheckedExtrinsic;
/// A extrinsic right from the external world. This is unchecked and so
/// can contain a signature.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct UncheckedExtrinsic<Address, Index, Call, Signature> {
/// The signature and address, if this is a signed extrinsic.
pub signature: Option<(Address, Signature)>,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// The function that should be called.
pub function: Call,
}
impl<Address, Index, Call, Signature> UncheckedExtrinsic<Address, Index, Call, Signature> {
/// New instance of a signed extrinsic aka "transaction".
pub fn new_signed(index: Index, function: Call, signed: Address, signature: Signature) -> Self {
UncheckedExtrinsic {
signature: Some((signed, signature)),
index,
function,
}
}
/// New instance of an unsigned extrinsic aka "inherent".
pub fn new_unsigned(index: Index, function: Call) -> Self {
UncheckedExtrinsic {
signature: None,
index,
function,
}
}
/// `true` if there is a signature.
pub fn is_signed(&self) -> bool {
self.signature.is_some()
}
}
impl<Address, AccountId, Index, Call, Signature, ThisLookup> traits::Checkable<ThisLookup>
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Address: Member + MaybeDisplay,
Index: Encode + Member + MaybeDisplay + SimpleArithmetic,
Call: Encode + Member,
Signature: Member + traits::Verify<Signer=AccountId>,
AccountId: Member + MaybeDisplay,
ThisLookup: FnOnce(Address) -> Result<AccountId, &'static str>,
{
type Checked = CheckedExtrinsic<AccountId, Index, Call>;
fn check_with(self, lookup: ThisLookup) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature)) => {
let payload = (self.index, self.function);
let signed = lookup(signed)?;
if !::verify_encoded_lazy(&signature, &payload, &signed) {
return Err("bad signature in extrinsic")
}
CheckedExtrinsic {
signed: Some(signed),
index: payload.0,
function: payload.1,
}
}
None => CheckedExtrinsic {
signed: None,
index: self.index,
function: self.function,
},
})
}
}
impl<Address, Index, Call, Signature> Decode
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Address: Decode,
Signature: Decode,
Index: Decode,
Call: Decode,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
// 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 u32, which has the total number of bytes following (we don't need
// to use this).
let _length_do_not_remove_me_see_above: u32 = Decode::decode(input)?;
Some(UncheckedExtrinsic {
signature: Decode::decode(input)?,
index: Decode::decode(input)?,
function: Decode::decode(input)?,
})
}
}
impl<Address, Index, Call, Signature> Encode
for UncheckedExtrinsic<Address, Index, Call, Signature>
where
Address: Encode,
Signature: Encode,
Index: Encode,
Call: Encode,
{
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
// need to prefix with the total length as u32 to ensure it's binary comptible with
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
v.extend(&[0u8; 4]);
self.signature.encode_to(&mut v);
self.index.encode_to(&mut v);
self.function.encode_to(&mut v);
let length = (v.len() - 4) as u32;
length.using_encoded(|s| v[0..4].copy_from_slice(s));
v
}
}
/// TODO: use derive when possible.
#[cfg(feature = "std")]
impl<Address, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<Address, Index, Call, Signature> where
Address: fmt::Debug,
Index: fmt::Debug,
Call: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedExtrinsic({:?}, {:?}, {:?})", self.signature.as_ref().map(|x| &x.0), self.function, self.index)
}
}
@@ -146,44 +146,6 @@ impl codec::Encode for ApplyError {
/// Result from attempt to apply an extrinsic.
pub type ApplyResult = Result<ApplyOutcome, ApplyError>;
/// Potentially "unsigned" signature verification.
#[derive(Eq, PartialEq, Clone, Default, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
pub struct MaybeUnsigned<T>(pub T);
impl<T: Verify> MaybeUnsigned<T> where
T: Default + Eq,
<T as Verify>::Signer: Default + Eq,
{
fn is_signed(&self) -> bool {
self.0 != T::default()
}
fn is_addressed(&self, signer: &<Self as Verify>::Signer) -> bool {
signer != &Default::default()
}
}
impl<T: Verify> Verify for MaybeUnsigned<T> where
T: Default + Eq,
<T as Verify>::Signer: Default + Eq,
{
type Signer = T::Signer;
fn verify<L: Lazy<[u8]>>(&self, msg: L, signer: &Self::Signer) -> bool {
if !self.is_signed() {
!self.is_addressed(signer)
} else {
self.0.verify(msg, signer)
}
}
}
impl<T> From<T> for MaybeUnsigned<T> {
fn from(t: T) -> Self {
MaybeUnsigned(t)
}
}
/// 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) -> bool {
@@ -19,7 +19,7 @@
use serde::{Serialize, de::DeserializeOwned};
use std::fmt::Debug;
use codec::Codec;
use runtime_support::AuxDispatchable;
use runtime_support::Dispatchable;
use traits::{self, Checkable, Applyable, BlakeTwo256};
pub use substrate_primitives::H256;
@@ -116,16 +116,19 @@ impl<Xt: 'static + Codec + Sized + Send + Sync + Serialize + DeserializeOwned +
}
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Debug, Encode, Decode)]
pub struct TestXt<Call>(pub (u64, u64, Call));
pub struct TestXt<Call>(pub Option<u64>, pub u64, pub Call);
impl<Call: Codec + Sync + Send + Serialize + AuxDispatchable, Context> Checkable<Context> for TestXt<Call> {
impl<Call: Codec + Sync + Send + Serialize + Dispatchable, Context> Checkable<Context> for TestXt<Call> {
type Checked = Self;
fn check_with(self, _: Context) -> Result<Self::Checked, &'static str> { Ok(self) }
}
impl<Call: AuxDispatchable<Aux = u64> + Codec + Sized + Send + Sync + Serialize + DeserializeOwned + Clone + Eq + Debug> Applyable for TestXt<Call> {
impl<Call> Applyable for TestXt<Call> where
Call: Sized + Send + Sync + Clone + Eq + Dispatchable + Codec + Debug + Serialize + DeserializeOwned,
<Call as Dispatchable>::Origin: From<Option<u64>>
{
type AccountId = u64;
type Index = u64;
fn sender(&self) -> &u64 { &(self.0).0 }
fn index(&self) -> &u64 { &(self.0).1 }
fn apply(self) -> Result<(), &'static str> { (self.0).2.dispatch(&(self.0).0) }
fn sender(&self) -> Option<&u64> { self.0.as_ref() }
fn index(&self) -> &u64 { &self.1 }
fn apply(self) -> Result<(), &'static str> { self.2.dispatch(self.0.into()) }
}
@@ -47,7 +47,7 @@ pub trait Verify {
}
/// Means of changing one type into another in a manner dependent on the source type.
pub trait AuxLookup {
pub trait Lookup {
/// Type to lookup from.
type Source;
/// Type to lookup into.
@@ -108,24 +108,6 @@ impl<T> Convert<T, ()> for () {
fn convert(_: T) -> () { () }
}
pub trait MaybeEmpty {
fn is_empty(&self) -> bool;
}
// AccountId is `u64` in tests
impl MaybeEmpty for u64 {
fn is_empty(&self) -> bool {
self.is_zero()
}
}
// AccountId is H256 in production
impl MaybeEmpty for substrate_primitives::H256 {
fn is_empty(&self) -> bool {
self.is_zero()
}
}
pub trait RefInto<T> {
fn ref_into(&self) -> &T;
}
@@ -427,7 +409,7 @@ pub trait Applyable: Sized + Send + Sync {
type AccountId: Member + MaybeDisplay;
type Index: Member + MaybeDisplay + SimpleArithmetic;
fn index(&self) -> &Self::Index;
fn sender(&self) -> &Self::AccountId;
fn sender(&self) -> Option<&Self::AccountId>;
fn apply(self) -> Result<(), &'static str>;
}
+31 -24
View File
@@ -49,9 +49,10 @@ extern crate substrate_runtime_system as system;
extern crate substrate_runtime_timestamp as timestamp;
use rstd::prelude::*;
use primitives::traits::{Zero, One, RefInto, OnFinalise, Convert, As};
use primitives::traits::{Zero, One, OnFinalise, Convert, As};
use runtime_support::{StorageValue, StorageMap};
use runtime_support::dispatch::Result;
use system::{ensure_signed, ensure_root};
#[cfg(any(feature = "std", test))]
use std::collections::HashMap;
@@ -75,17 +76,11 @@ pub trait Trait: timestamp::Trait {
pub type Event<T> = RawEvent<<T as system::Trait>::BlockNumber>;
decl_module! {
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set_key(origin, key: T::SessionKey) -> Result;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn set_key(aux, key: T::SessionKey) -> Result;
}
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn set_length(new: T::BlockNumber) -> Result;
fn force_new_session(apply_rewards: bool) -> Result;
fn set_length(origin, new: T::BlockNumber) -> Result;
fn force_new_session(origin, apply_rewards: bool) -> Result;
}
}
@@ -139,26 +134,34 @@ impl<T: Trait> Module<T> {
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
/// session.
fn set_key(aux: &T::PublicAux, key: T::SessionKey) -> Result {
fn set_key(origin: T::Origin, key: T::SessionKey) -> Result {
let who = ensure_signed(origin)?;
// set new value for next session
<NextKeyFor<T>>::insert(aux.ref_into(), key);
<NextKeyFor<T>>::insert(who, key);
Ok(())
}
/// Set a new era length. Won't kick in until the next era change (at current length).
fn set_length(new: T::BlockNumber) -> Result {
fn set_length(origin: T::Origin, new: T::BlockNumber) -> Result {
ensure_root(origin)?;
<NextSessionLength<T>>::put(new);
Ok(())
}
/// Forces a new session.
pub fn force_new_session(apply_rewards: bool) -> Result {
<ForcingNewSession<T>>::put(apply_rewards);
Ok(())
pub fn force_new_session(origin: T::Origin, apply_rewards: bool) -> Result {
ensure_root(origin)?;
Self::apply_force_new_session(apply_rewards)
}
// INTERNAL API (available to other runtime modules)
/// Forces a new session, no origin.
pub fn apply_force_new_session(apply_rewards: bool) -> Result {
<ForcingNewSession<T>>::put(apply_rewards);
Ok(())
}
/// Set the current set of validators.
///
/// Called by `staking::next_era()` only. `next_session` should be called after this in order to
@@ -291,6 +294,10 @@ mod tests {
use primitives::traits::{Identity, BlakeTwo256};
use primitives::testing::{Digest, Header};
impl_outer_origin!{
pub enum Origin for Test {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl consensus::Trait for Test {
@@ -300,7 +307,7 @@ mod tests {
type OnOfflineValidator = ();
}
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -353,7 +360,7 @@ mod tests {
fn should_work_with_early_exit() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
assert_ok!(Session::set_length(10));
assert_ok!(Session::set_length(Origin::ROOT, 10));
assert_eq!(Session::blocks_remaining(), 1);
Session::check_rotate_session(1);
@@ -365,7 +372,7 @@ mod tests {
System::set_block_number(7);
assert_eq!(Session::current_index(), 1);
assert_eq!(Session::blocks_remaining(), 5);
assert_ok!(Session::force_new_session(false));
assert_ok!(Session::force_new_session(Origin::ROOT, false));
Session::check_rotate_session(7);
System::set_block_number(8);
@@ -388,14 +395,14 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
// Block 1: Change to length 3; no visible change.
System::set_block_number(1);
assert_ok!(Session::set_length(3));
assert_ok!(Session::set_length(Origin::ROOT, 3));
Session::check_rotate_session(1);
assert_eq!(Session::length(), 2);
assert_eq!(Session::current_index(), 0);
// Block 2: Length now changed to 3. Index incremented.
System::set_block_number(2);
assert_ok!(Session::set_length(3));
assert_ok!(Session::set_length(Origin::ROOT, 3));
Session::check_rotate_session(2);
assert_eq!(Session::length(), 3);
assert_eq!(Session::current_index(), 1);
@@ -408,7 +415,7 @@ mod tests {
// Block 4: Change to length 2; no visible change.
System::set_block_number(4);
assert_ok!(Session::set_length(2));
assert_ok!(Session::set_length(Origin::ROOT, 2));
Session::check_rotate_session(4);
assert_eq!(Session::length(), 3);
assert_eq!(Session::current_index(), 1);
@@ -448,7 +455,7 @@ mod tests {
// Block 3: Set new key for validator 2; no visible change.
System::set_block_number(3);
assert_ok!(Session::set_key(&2, 5));
assert_ok!(Session::set_key(Origin::signed(2), 5));
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
Session::check_rotate_session(3);
+66 -58
View File
@@ -49,9 +49,10 @@ use rstd::prelude::*;
use runtime_support::{Parameter, StorageValue, StorageMap};
use runtime_support::dispatch::Result;
use session::OnSessionChange;
use primitives::traits::{Zero, One, Bounded, RefInto, OnFinalise,
As, AuxLookup};
use primitives::traits::{Zero, One, Bounded, OnFinalise,
As, Lookup};
use balances::{address::Address, OnMinted};
use system::{ensure_root, ensure_signed};
mod mock;
@@ -104,25 +105,19 @@ pub trait Trait: balances::Trait + session::Trait {
}
decl_module! {
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(bound(deserialize = "T::Balance: ::serde::de::DeserializeOwned")))]
pub enum Call where aux: T::PublicAux {
fn stake(aux) -> Result;
fn unstake(aux, intentions_index: u32) -> Result;
fn nominate(aux, target: Address<T::AccountId, T::AccountIndex>) -> Result;
fn unnominate(aux, target_index: u32) -> Result;
fn register_preferences(aux, intentions_index: u32, prefs: ValidatorPrefs<T::Balance>) -> Result;
}
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn stake(origin) -> Result;
fn unstake(origin, intentions_index: u32) -> Result;
fn nominate(origin, target: Address<T::AccountId, T::AccountIndex>) -> Result;
fn unnominate(origin, target_index: u32) -> Result;
fn register_preferences(origin, intentions_index: u32, prefs: ValidatorPrefs<T::Balance>) -> Result;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
fn set_sessions_per_era(new: T::BlockNumber) -> Result;
fn set_bonding_duration(new: T::BlockNumber) -> Result;
fn set_validator_count(new: u32) -> Result;
fn force_new_era(apply_rewards: bool) -> Result;
fn set_offline_slash_grace(new: u32) -> Result;
fn set_sessions_per_era(origin, new: T::BlockNumber) -> Result;
fn set_bonding_duration(origin, new: T::BlockNumber) -> Result;
fn set_validator_count(origin, new: u32) -> Result;
fn force_new_era(origin, apply_rewards: bool) -> Result;
fn set_offline_slash_grace(origin, new: u32) -> Result;
}
}
@@ -192,6 +187,11 @@ decl_storage! {
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
// PUBLIC IMMUTABLES
/// MinimumValidatorCount getter, introduces a default.
@@ -232,60 +232,62 @@ impl<T: Trait> Module<T> {
/// Declare the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
fn stake(aux: &T::PublicAux) -> Result {
let aux = aux.ref_into();
ensure!(Self::nominating(aux).is_none(), "Cannot stake if already nominating.");
fn stake(origin: T::Origin) -> Result {
let who = ensure_signed(origin)?;
ensure!(Self::nominating(&who).is_none(), "Cannot stake if already nominating.");
let mut intentions = <Intentions<T>>::get();
// can't be in the list twice.
ensure!(intentions.iter().find(|&t| t == aux).is_none(), "Cannot stake if already staked.");
intentions.push(aux.clone());
ensure!(intentions.iter().find(|&t| t == &who).is_none(), "Cannot stake if already staked.");
<Bondage<T>>::insert(&who, T::BlockNumber::max_value());
intentions.push(who);
<Intentions<T>>::put(intentions);
<Bondage<T>>::insert(aux, T::BlockNumber::max_value());
Ok(())
}
/// Retract the desire to stake for the transactor.
///
/// Effects will be felt at the beginning of the next era.
fn unstake(aux: &T::PublicAux, intentions_index: u32) -> Result {
fn unstake(origin: T::Origin, intentions_index: u32) -> Result {
let who = ensure_signed(origin)?;
// unstake fails in degenerate case of having too few existing staked parties
if Self::intentions().len() <= Self::minimum_validator_count() {
return Err("cannot unstake when there are too few staked participants")
}
Self::apply_unstake(aux.ref_into(), intentions_index as usize)
Self::apply_unstake(&who, intentions_index as usize)
}
fn nominate(aux: &T::PublicAux, target: Address<T::AccountId, T::AccountIndex>) -> Result {
fn nominate(origin: T::Origin, target: Address<T::AccountId, T::AccountIndex>) -> Result {
let who = ensure_signed(origin)?;
let target = <balances::Module<T>>::lookup(target)?;
let aux = aux.ref_into();
ensure!(Self::nominating(aux).is_none(), "Cannot nominate if already nominating.");
ensure!(Self::intentions().iter().find(|&t| t == aux.ref_into()).is_none(), "Cannot nominate if already staked.");
ensure!(Self::nominating(&who).is_none(), "Cannot nominate if already nominating.");
ensure!(Self::intentions().iter().find(|&t| t == &who).is_none(), "Cannot nominate if already staked.");
// update nominators_for
let mut t = Self::nominators_for(&target);
t.push(aux.clone());
t.push(who.clone());
<NominatorsFor<T>>::insert(&target, t);
// update nominating
<Nominating<T>>::insert(aux, &target);
<Nominating<T>>::insert(&who, &target);
// Update bondage
<Bondage<T>>::insert(aux.ref_into(), T::BlockNumber::max_value());
<Bondage<T>>::insert(&who, T::BlockNumber::max_value());
Ok(())
}
/// Will panic if called when source isn't currently nominating target.
/// Updates Nominating, NominatorsFor and NominationBalance.
fn unnominate(aux: &T::PublicAux, target_index: u32) -> Result {
let source = aux.ref_into();
fn unnominate(origin: T::Origin, target_index: u32) -> Result {
let source = ensure_signed(origin)?;
let target_index = target_index as usize;
let target = <Nominating<T>>::get(source).ok_or("Account must be nominating")?;
let target = <Nominating<T>>::get(&source).ok_or("Account must be nominating")?;
let mut t = Self::nominators_for(&target);
if t.get(target_index) != Some(source) {
if t.get(target_index) != Some(&source) {
return Err("Invalid target index")
}
@@ -296,66 +298,72 @@ impl<T: Trait> Module<T> {
<NominatorsFor<T>>::insert(&target, t);
// update nominating
<Nominating<T>>::remove(source);
<Nominating<T>>::remove(&source);
// update bondage
<Bondage<T>>::insert(aux.ref_into(), <system::Module<T>>::block_number() + Self::bonding_duration());
<Bondage<T>>::insert(source, <system::Module<T>>::block_number() + Self::bonding_duration());
Ok(())
}
/// Set the given account's preference for slashing behaviour should they be a validator.
///
/// An error (no-op) if `Self::intentions()[intentions_index] != aux`.
/// An error (no-op) if `Self::intentions()[intentions_index] != origin`.
fn register_preferences(
aux: &T::PublicAux,
origin: T::Origin,
intentions_index: u32,
prefs: ValidatorPrefs<T::Balance>
) -> Result {
let aux = aux.ref_into();
let who = ensure_signed(origin)?;
if Self::intentions().get(intentions_index as usize) != Some(aux) {
if Self::intentions().get(intentions_index as usize) != Some(&who) {
return Err("Invalid index")
}
<ValidatorPreferences<T>>::insert(aux, prefs);
<ValidatorPreferences<T>>::insert(who, prefs);
Ok(())
}
// PRIV DISPATCH
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
/// Set the number of sessions in an era.
fn set_sessions_per_era(new: T::BlockNumber) -> Result {
fn set_sessions_per_era(origin: T::Origin, new: T::BlockNumber) -> Result {
ensure_root(origin)?;
<NextSessionsPerEra<T>>::put(&new);
Ok(())
}
/// The length of the bonding duration in eras.
fn set_bonding_duration(new: T::BlockNumber) -> Result {
fn set_bonding_duration(origin: T::Origin, new: T::BlockNumber) -> Result {
ensure_root(origin)?;
<BondingDuration<T>>::put(&new);
Ok(())
}
/// The length of a staking era in sessions.
fn set_validator_count(new: u32) -> Result {
fn set_validator_count(origin: T::Origin, new: u32) -> Result {
ensure_root(origin)?;
<ValidatorCount<T>>::put(&new);
Ok(())
}
/// Force there to be a new era. This also forces a new session immediately after.
/// `apply_rewards` should be true for validators to get the session reward.
fn force_new_era(apply_rewards: bool) -> Result {
<ForcingNewEra<T>>::put(());
<session::Module<T>>::force_new_session(apply_rewards)
fn force_new_era(origin: T::Origin, apply_rewards: bool) -> Result {
ensure_root(origin)?;
Self::apply_force_new_era(apply_rewards)
}
// Just force_new_era without origin check.
fn apply_force_new_era(apply_rewards: bool) -> Result {
<ForcingNewEra<T>>::put(());
<session::Module<T>>::apply_force_new_session(apply_rewards)
}
/// Set the offline slash grace period.
fn set_offline_slash_grace(new: u32) -> Result {
fn set_offline_slash_grace(origin: T::Origin, new: u32) -> Result {
ensure_root(origin)?;
<OfflineSlashGrace<T>>::put(&new);
Ok(())
}
@@ -555,7 +563,7 @@ impl<T: Trait> consensus::OnOfflineValidator for Module<T> {
apply_unstake can only fail if pos wrong; \
Self::intentions() doesn't change; qed");
}
let _ = Self::force_new_era(false);
let _ = Self::apply_force_new_era(false);
}
RawEvent::OfflineSlash(v, slash)
} else {
@@ -25,6 +25,10 @@ use substrate_primitives::{H256, KeccakHasher};
use runtime_io;
use {GenesisConfig, Module, Trait, consensus, session, system, timestamp, balances};
impl_outer_origin!{
pub enum Origin for Test {}
}
// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct Test;
@@ -35,7 +39,7 @@ impl consensus::Trait for Test {
type OnOfflineValidator = ();
}
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -21,7 +21,7 @@
use super::*;
use consensus::OnOfflineValidator;
use runtime_io::with_externalities;
use mock::{Balances, Session, Staking, System, Timestamp, Test, new_test_ext};
use mock::{Balances, Session, Staking, System, Timestamp, Test, new_test_ext, Origin};
#[test]
fn note_null_offline_should_work() {
@@ -75,7 +75,7 @@ fn note_offline_grace_should_work() {
with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {
Balances::set_free_balance(&10, 70);
Balances::set_free_balance(&20, 70);
assert_ok!(Staking::set_offline_slash_grace(1));
assert_ok!(Staking::set_offline_slash_grace(Origin::ROOT, 1));
assert_eq!(Staking::offline_slash_grace(), 1);
assert_eq!(Staking::slash_count(&10), 0);
@@ -104,7 +104,7 @@ fn note_offline_force_unstake_session_change_should_work() {
with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {
Balances::set_free_balance(&10, 70);
Balances::set_free_balance(&20, 70);
assert_ok!(Staking::stake(&1));
assert_ok!(Staking::stake(Origin::signed(1)));
assert_eq!(Staking::slash_count(&10), 0);
assert_eq!(Balances::free_balance(&10), 70);
@@ -130,7 +130,7 @@ fn note_offline_auto_unstake_session_change_should_work() {
with_externalities(&mut new_test_ext(0, 3, 3, 0, true, 10), || {
Balances::set_free_balance(&10, 7000);
Balances::set_free_balance(&20, 7000);
assert_ok!(Staking::register_preferences(&10, 0, ValidatorPrefs { unstake_threshold: 1, validator_payment: 0 }));
assert_ok!(Staking::register_preferences(Origin::signed(10), 0, ValidatorPrefs { unstake_threshold: 1, validator_payment: 0 }));
assert_eq!(Staking::intentions(), vec![10, 20]);
@@ -236,14 +236,14 @@ fn staking_should_work() {
assert_eq!(Staking::validator_count(), 2);
assert_eq!(Session::validators(), vec![10, 20]);
assert_ok!(Staking::set_bonding_duration(2));
assert_ok!(Staking::set_bonding_duration(Origin::ROOT, 2));
assert_eq!(Staking::bonding_duration(), 2);
// Block 1: Add three validators. No obvious change.
System::set_block_number(1);
assert_ok!(Staking::stake(&1));
assert_ok!(Staking::stake(&2));
assert_ok!(Staking::stake(&4));
assert_ok!(Staking::stake(Origin::signed(1)));
assert_ok!(Staking::stake(Origin::signed(2)));
assert_ok!(Staking::stake(Origin::signed(4)));
Session::check_rotate_session(System::block_number());
assert_eq!(Staking::current_era(), 0);
assert_eq!(Session::validators(), vec![10, 20]);
@@ -256,8 +256,8 @@ fn staking_should_work() {
// Block 3: Unstake highest, introduce another staker. No change yet.
System::set_block_number(3);
assert_ok!(Staking::stake(&3));
assert_ok!(Staking::unstake(&4, Staking::intentions().iter().position(|&x| x == 4).unwrap() as u32));
assert_ok!(Staking::stake(Origin::signed(3)));
assert_ok!(Staking::unstake(Origin::signed(4), Staking::intentions().iter().position(|&x| x == 4).unwrap() as u32));
assert_eq!(Staking::current_era(), 1);
Session::check_rotate_session(System::block_number());
@@ -269,7 +269,7 @@ fn staking_should_work() {
// Block 5: Transfer stake from highest to lowest. No change yet.
System::set_block_number(5);
assert_ok!(Balances::transfer(&4, 1.into(), 40));
assert_ok!(Balances::transfer(Origin::signed(4), 1.into(), 40));
Session::check_rotate_session(System::block_number());
// Block 6: Lowest now validator.
@@ -279,7 +279,7 @@ fn staking_should_work() {
// Block 7: Unstake three. No change yet.
System::set_block_number(7);
assert_ok!(Staking::unstake(&3, Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32));
assert_ok!(Staking::unstake(Origin::signed(3), Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32));
Session::check_rotate_session(System::block_number());
assert_eq!(Session::validators(), vec![1, 3]);
@@ -299,10 +299,10 @@ fn nominating_and_rewards_should_work() {
assert_eq!(Session::validators(), vec![10, 20]);
System::set_block_number(1);
assert_ok!(Staking::stake(&1));
assert_ok!(Staking::stake(&2));
assert_ok!(Staking::stake(&3));
assert_ok!(Staking::nominate(&4, 1.into()));
assert_ok!(Staking::stake(Origin::signed(1)));
assert_ok!(Staking::stake(Origin::signed(2)));
assert_ok!(Staking::stake(Origin::signed(3)));
assert_ok!(Staking::nominate(Origin::signed(4), 1.into()));
Session::check_rotate_session(System::block_number());
assert_eq!(Staking::current_era(), 1);
assert_eq!(Session::validators(), vec![1, 3]); // 4 + 1, 3
@@ -312,7 +312,7 @@ fn nominating_and_rewards_should_work() {
assert_eq!(Balances::total_balance(&4), 40);
System::set_block_number(2);
assert_ok!(Staking::unnominate(&4, 0));
assert_ok!(Staking::unnominate(Origin::signed(4), 0));
Session::check_rotate_session(System::block_number());
assert_eq!(Staking::current_era(), 2);
assert_eq!(Session::validators(), vec![3, 2]);
@@ -322,9 +322,9 @@ fn nominating_and_rewards_should_work() {
assert_eq!(Balances::total_balance(&4), 48);
System::set_block_number(3);
assert_ok!(Staking::stake(&4));
assert_ok!(Staking::unstake(&3, Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32));
assert_ok!(Staking::nominate(&3, 1.into()));
assert_ok!(Staking::stake(Origin::signed(4)));
assert_ok!(Staking::unstake(Origin::signed(3), Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32));
assert_ok!(Staking::nominate(Origin::signed(3), 1.into()));
Session::check_rotate_session(System::block_number());
assert_eq!(Session::validators(), vec![1, 4]);
assert_eq!(Balances::total_balance(&1), 12);
@@ -345,9 +345,9 @@ fn nominating_and_rewards_should_work() {
fn rewards_with_off_the_table_should_work() {
with_externalities(&mut new_test_ext(0, 1, 1, 0, true, 10), || {
System::set_block_number(1);
assert_ok!(Staking::stake(&1));
assert_ok!(Staking::nominate(&2, 1.into()));
assert_ok!(Staking::stake(&3));
assert_ok!(Staking::stake(Origin::signed(1)));
assert_ok!(Staking::nominate(Origin::signed(2), 1.into()));
assert_ok!(Staking::stake(Origin::signed(3)));
Session::check_rotate_session(System::block_number());
assert_eq!(Session::validators(), vec![1, 3]); // 1 + 2, 3
assert_eq!(Balances::total_balance(&1), 10);
@@ -355,7 +355,7 @@ fn rewards_with_off_the_table_should_work() {
assert_eq!(Balances::total_balance(&3), 30);
System::set_block_number(2);
assert_ok!(Staking::register_preferences(&1, Staking::intentions().into_iter().position(|i| i == 1).unwrap() as u32, ValidatorPrefs { unstake_threshold: 3, validator_payment: 4 }));
assert_ok!(Staking::register_preferences(Origin::signed(1), Staking::intentions().into_iter().position(|i| i == 1).unwrap() as u32, ValidatorPrefs { unstake_threshold: 3, validator_payment: 4 }));
Session::check_rotate_session(System::block_number());
assert_eq!(Balances::total_balance(&1), 16);
assert_eq!(Balances::total_balance(&2), 24);
@@ -376,10 +376,10 @@ fn nominating_slashes_should_work() {
Timestamp::set_timestamp(15);
System::set_block_number(4);
assert_ok!(Staking::stake(&1));
assert_ok!(Staking::stake(&3));
assert_ok!(Staking::nominate(&2, 3.into()));
assert_ok!(Staking::nominate(&4, 1.into()));
assert_ok!(Staking::stake(Origin::signed(1)));
assert_ok!(Staking::stake(Origin::signed(3)));
assert_ok!(Staking::nominate(Origin::signed(2), 3.into()));
assert_ok!(Staking::nominate(Origin::signed(4), 1.into()));
Session::check_rotate_session(System::block_number());
assert_eq!(Staking::current_era(), 1);
@@ -404,12 +404,12 @@ fn nominating_slashes_should_work() {
fn double_staking_should_fail() {
with_externalities(&mut new_test_ext(0, 1, 2, 0, true, 0), || {
System::set_block_number(1);
assert_ok!(Staking::stake(&1));
assert_noop!(Staking::stake(&1), "Cannot stake if already staked.");
assert_noop!(Staking::nominate(&1, 1.into()), "Cannot nominate if already staked.");
assert_ok!(Staking::nominate(&2, 1.into()));
assert_noop!(Staking::stake(&2), "Cannot stake if already nominating.");
assert_noop!(Staking::nominate(&2, 1.into()), "Cannot nominate if already nominating.");
assert_ok!(Staking::stake(Origin::signed(1)));
assert_noop!(Staking::stake(Origin::signed(1)), "Cannot stake if already staked.");
assert_noop!(Staking::nominate(Origin::signed(1), 1.into()), "Cannot nominate if already staked.");
assert_ok!(Staking::nominate(Origin::signed(2), 1.into()));
assert_noop!(Staking::stake(Origin::signed(2)), "Cannot stake if already nominating.");
assert_noop!(Staking::nominate(Origin::signed(2), 1.into()), "Cannot nominate if already nominating.");
});
}
@@ -440,7 +440,7 @@ fn staking_eras_work() {
// Block 3: Schedule an era length change; no visible changes.
System::set_block_number(3);
assert_ok!(Staking::set_sessions_per_era(3));
assert_ok!(Staking::set_sessions_per_era(Origin::ROOT, 3));
Session::check_rotate_session(System::block_number());
assert_eq!(Session::current_index(), 3);
assert_eq!(Staking::sessions_per_era(), 2);
@@ -485,8 +485,8 @@ fn staking_eras_work() {
fn staking_balance_transfer_when_bonded_should_not_work() {
with_externalities(&mut new_test_ext(0, 1, 3, 1, false, 0), || {
Balances::set_free_balance(&1, 111);
assert_ok!(Staking::stake(&1));
assert_noop!(Balances::transfer(&1, 2.into(), 69), "cannot transfer illiquid funds");
assert_ok!(Staking::stake(Origin::signed(1)));
assert_noop!(Balances::transfer(Origin::signed(1), 2.into(), 69), "cannot transfer illiquid funds");
});
}
+65 -6
View File
@@ -45,7 +45,7 @@ extern crate safe_mix;
use rstd::prelude::*;
use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, One, Bounded,
Hash, Member, MaybeDisplay, RefInto, MaybeEmpty};
Hash, Member, MaybeDisplay};
use runtime_support::{StorageValue, StorageMap, Parameter};
use safe_mix::TripletMix;
@@ -69,9 +69,7 @@ pub fn extrinsics_data_root<H: Hash>(xts: Vec<Vec<u8>>) -> H::Output {
}
pub trait Trait: Eq + Clone {
// We require that PublicAux impl MaybeEmpty, since we require that inherents - or unsigned
// user-level extrinsics - can exist.
type PublicAux: RefInto<Self::AccountId> + MaybeEmpty;
type Origin: Into<Option<RawOrigin<Self::AccountId>>> + From<RawOrigin<Self::AccountId>>;
type Index: Parameter + Member + Default + MaybeDisplay + SimpleArithmetic + Copy;
type BlockNumber: Parameter + Member + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy + rstd::hash::Hash;
type Hash: Parameter + Member + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]>;
@@ -89,7 +87,7 @@ pub trait Trait: Eq + Clone {
pub type DigestItemOf<T> = <<T as Trait>::Digest as traits::Digest>::Item;
decl_module! {
pub struct Module<T: Trait>;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
/// A phase of a block's execution.
@@ -126,6 +124,30 @@ impl From<Event> for () {
fn from(_: Event) -> () { () }
}
/// Origin for the system module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum RawOrigin<AccountId> {
/// The system itself ordained this dispatch to happen: this is the highest privilege level.
Root,
/// It is signed by some public key and we provide the AccountId.
Signed(AccountId),
/// It is signed by nobody but included and agreed upon by the validators anyway: it's "inherently" true.
Inherent,
}
impl<AccountId> From<Option<AccountId>> for RawOrigin<AccountId> {
fn from(s: Option<AccountId>) -> RawOrigin<AccountId> {
match s {
Some(who) => RawOrigin::Signed(who),
None => RawOrigin::Inherent,
}
}
}
/// Exposed trait-generic origin type.
pub type Origin<T> = RawOrigin<<T as Trait>::AccountId>;
decl_storage! {
trait Store for Module<T: Trait> as System {
@@ -146,6 +168,37 @@ decl_storage! {
}
}
/// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction).
/// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise.
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, &'static str>
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
{
match o.into() {
Some(RawOrigin::Signed(t)) => Ok(t),
_ => Err("bad origin: expected to be a signed origin"),
}
}
/// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise.
pub fn ensure_root<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
{
match o.into() {
Some(RawOrigin::Root) => Ok(()),
_ => Err("bad origin: expected to be a root origin"),
}
}
/// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise.
pub fn ensure_inherent<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<(), &'static str>
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
{
match o.into() {
Some(RawOrigin::Inherent) => Ok(()),
_ => Err("bad origin: expected to be an inherent origin"),
}
}
impl<T: Trait> Module<T> {
/// Start the execution of a particular block.
pub fn initialise(number: &T::BlockNumber, parent_hash: &T::Hash, txs_root: &T::Hash) {
@@ -307,10 +360,14 @@ mod tests {
use primitives::traits::BlakeTwo256;
use primitives::testing::{Digest, Header};
impl_outer_origin!{
pub enum Origin for Test where system = super {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl Trait for Test {
type PublicAux = u64;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -332,6 +389,8 @@ mod tests {
type System = Module<Test>;
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
GenesisConfig::<Test>::default().build_storage().unwrap().into()
}
@@ -40,11 +40,10 @@ extern crate substrate_codec as codec;
use runtime_support::{StorageValue, Parameter};
use runtime_support::dispatch::Result;
use runtime_primitives::traits::{OnFinalise, MaybeEmpty, SimpleArithmetic, As, Zero};
use runtime_primitives::traits::{OnFinalise, SimpleArithmetic, As, Zero};
use system::ensure_inherent;
pub trait Trait: consensus::Trait where
<Self as system::Trait>::PublicAux: MaybeEmpty
{
pub trait Trait: consensus::Trait + system::Trait {
// the position of the required timestamp-set extrinsic.
const TIMESTAMP_SET_POSITION: u32;
@@ -52,11 +51,8 @@ pub trait Trait: consensus::Trait where
}
decl_module! {
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
fn set(aux, now: T::Moment) -> Result;
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set(origin, now: T::Moment) -> Result;
}
}
@@ -77,8 +73,8 @@ impl<T: Trait> Module<T> {
}
/// Set the current time.
fn set(aux: &T::PublicAux, now: T::Moment) -> Result {
assert!(aux.is_empty());
fn set(origin: T::Origin, now: T::Moment) -> Result {
ensure_inherent(origin)?;
assert!(!<Self as Store>::DidUpdate::exists(), "Timestamp must be updated only once in the block");
assert!(
<system::Module<T>>::extrinsic_index() == Some(T::TIMESTAMP_SET_POSITION),
@@ -146,10 +142,14 @@ mod tests {
use runtime_primitives::traits::{BlakeTwo256};
use runtime_primitives::testing::{Digest, Header};
impl_outer_origin! {
pub enum Origin for Test {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -178,7 +178,7 @@ mod tests {
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
assert_ok!(Timestamp::aux_dispatch(Call::set(69), &0));
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::INHERENT));
assert_eq!(Timestamp::now(), 69);
});
}
@@ -191,8 +191,8 @@ mod tests {
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
assert_ok!(Timestamp::aux_dispatch(Call::set(69), &0));
let _ = Timestamp::aux_dispatch(Call::set(70), &0);
assert_ok!(Timestamp::dispatch(Call::set(69), Origin::INHERENT));
let _ = Timestamp::dispatch(Call::set(70), Origin::INHERENT);
});
}
@@ -204,7 +204,7 @@ mod tests {
let mut t = runtime_io::TestExternalities::from(t);
with_externalities(&mut t, || {
Timestamp::set_timestamp(42);
let _ = Timestamp::aux_dispatch(Call::set(46), &0);
let _ = Timestamp::dispatch(Call::set(46), Origin::INHERENT);
});
}
}
+45 -46
View File
@@ -44,8 +44,9 @@ extern crate substrate_runtime_balances as balances;
use rstd::ops::{Mul, Div};
use runtime_support::{StorageValue, StorageMap};
use runtime_support::dispatch::Result;
use runtime_primitives::traits::{As, OnFinalise, Zero, RefInto};
use runtime_primitives::traits::{As, OnFinalise, Zero};
use balances::OnMinted;
use system::{ensure_signed, ensure_root};
/// Our module's configuration trait. All our types and consts go in here. If the
/// module is dependent on specific other modules, then their configuration traits
@@ -63,35 +64,24 @@ type ProposalIndex = u32;
// macro takes care of the marshalling of arguments and dispatch.
decl_module! {
// Simple declaration of the `Module` type. Lets the macro know what its working on.
pub struct Module<T: Trait>;
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum Call where aux: T::PublicAux {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
// Put forward a suggestion for spending. A deposit proportional to the value
// is reserved and slashed if the proposal is rejected. It is returned once the
// proposal is awarded.
fn propose_spend(aux, value: T::Balance, beneficiary: T::AccountId) -> Result;
}
fn propose_spend(origin, value: T::Balance, beneficiary: T::AccountId) -> Result;
// The priviledged entry points. These are provided to allow any governance modules in
// the runtime to be able to execute common functions. Unlike for `Call` there is no
// auxilliary data to encode the sender (since there is no sender). Though still important
// to ensure that these execute in reasonable time and space, they can do what would
// otherwise be costly or unsafe operations.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum PrivCall {
// Set the balance of funds available to spend.
fn set_pot(new_pot: T::Balance) -> Result;
fn set_pot(origin, new_pot: T::Balance) -> Result;
// (Re-)configure this module.
fn configure(proposal_bond: Permill, proposal_bond_minimum: T::Balance, spend_period: T::BlockNumber, burn: Permill) -> Result;
fn configure(origin, proposal_bond: Permill, proposal_bond_minimum: T::Balance, spend_period: T::BlockNumber, burn: Permill) -> Result;
// Reject a proposed spend. The original deposit will be slashed.
fn reject_proposal(proposal_id: ProposalIndex) -> Result;
fn reject_proposal(origin, roposal_id: ProposalIndex) -> Result;
// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary
// and the original deposit will be returned.
fn approve_proposal(proposal_id: ProposalIndex) -> Result;
fn approve_proposal(origin, proposal_id: ProposalIndex) -> Result;
}
}
@@ -183,25 +173,26 @@ impl<T: Trait> Module<T> {
<system::Module<T>>::deposit_event(<T as Trait>::Event::from(event).into());
}
// Implement Calls/PrivCalls and add public immutables and private mutables.
// Implement Calls and add public immutables and private mutables.
fn propose_spend(aux: &T::PublicAux, value: T::Balance, beneficiary: T::AccountId) -> Result {
let proposer = aux.ref_into();
fn propose_spend(origin: T::Origin, value: T::Balance, beneficiary: T::AccountId) -> Result {
let proposer = ensure_signed(origin)?;
let bond = Self::calculate_bond(value);
<balances::Module<T>>::reserve(proposer, bond)
<balances::Module<T>>::reserve(&proposer, bond)
.map_err(|_| "Proposer's balance too low")?;
let c = Self::proposal_count();
<ProposalCount<T>>::put(c + 1);
<Proposals<T>>::insert(c, Proposal { proposer: proposer.clone(), value, beneficiary, bond });
<Proposals<T>>::insert(c, Proposal { proposer, value, beneficiary, bond });
Self::deposit_event(RawEvent::Proposed(c));
Ok(())
}
fn reject_proposal(proposal_id: ProposalIndex) -> Result {
fn reject_proposal(origin: T::Origin, proposal_id: ProposalIndex) -> Result {
ensure_root(origin)?;
let proposal = <Proposals<T>>::take(proposal_id).ok_or("No proposal at that index")?;
let value = proposal.bond;
@@ -210,7 +201,8 @@ impl<T: Trait> Module<T> {
Ok(())
}
fn approve_proposal(proposal_id: ProposalIndex) -> Result {
fn approve_proposal(origin: T::Origin, proposal_id: ProposalIndex) -> Result {
ensure_root(origin)?;
ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index");
{
@@ -224,7 +216,8 @@ impl<T: Trait> Module<T> {
Ok(())
}
fn set_pot(new_pot: T::Balance) -> Result {
fn set_pot(origin: T::Origin, new_pot: T::Balance) -> Result {
ensure_root(origin)?;
// Put the new value into storage.
<Pot<T>>::put(new_pot);
@@ -233,11 +226,13 @@ impl<T: Trait> Module<T> {
}
fn configure(
origin: T::Origin,
proposal_bond: Permill,
proposal_bond_minimum: T::Balance,
spend_period: T::BlockNumber,
burn: Permill
) -> Result {
ensure_root(origin)?;
<ProposalBond<T>>::put(proposal_bond);
<ProposalBondMinimum<T>>::put(proposal_bond_minimum);
<SpendPeriod<T>>::put(spend_period);
@@ -358,10 +353,14 @@ mod tests {
use runtime_primitives::traits::{BlakeTwo256};
use runtime_primitives::testing::{Digest, Header};
impl_outer_origin! {
pub enum Origin for Test {}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
impl system::Trait for Test {
type PublicAux = Self::AccountId;
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -428,7 +427,7 @@ mod tests {
#[test]
fn spend_proposal_takes_min_deposit() {
with_externalities(&mut new_test_ext(), || {
assert_ok!(Treasury::propose_spend(&0, 1, 3));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3));
assert_eq!(Balances::free_balance(&0), 99);
assert_eq!(Balances::reserved_balance(&0), 1);
});
@@ -437,7 +436,7 @@ mod tests {
#[test]
fn spend_proposal_takes_proportional_deposit() {
with_externalities(&mut new_test_ext(), || {
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_eq!(Balances::free_balance(&0), 95);
assert_eq!(Balances::reserved_balance(&0), 5);
});
@@ -446,7 +445,7 @@ mod tests {
#[test]
fn spend_proposal_fails_when_proposer_poor() {
with_externalities(&mut new_test_ext(), || {
assert_noop!(Treasury::propose_spend(&2, 100, 3), "Proposer's balance too low");
assert_noop!(Treasury::propose_spend(Origin::signed(2), 100, 3), "Proposer's balance too low");
});
}
@@ -455,8 +454,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::approve_proposal(0));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0));
<Treasury as OnFinalise<u64>>::on_finalise(1);
assert_eq!(Balances::free_balance(&3), 0);
@@ -479,8 +478,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::reject_proposal(0));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
<Treasury as OnFinalise<u64>>::on_finalise(2);
assert_eq!(Balances::free_balance(&3), 0);
@@ -493,23 +492,23 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::reject_proposal(0));
assert_noop!(Treasury::reject_proposal(0), "No proposal at that index");
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), "No proposal at that index");
});
}
#[test]
fn reject_non_existant_spend_proposal_fails() {
with_externalities(&mut new_test_ext(), || {
assert_noop!(Treasury::reject_proposal(0), "No proposal at that index");
assert_noop!(Treasury::reject_proposal(Origin::ROOT, 0), "No proposal at that index");
});
}
#[test]
fn accept_non_existant_spend_proposal_fails() {
with_externalities(&mut new_test_ext(), || {
assert_noop!(Treasury::approve_proposal(0), "No proposal at that index");
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), "No proposal at that index");
});
}
@@ -518,9 +517,9 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::reject_proposal(0));
assert_noop!(Treasury::approve_proposal(0), "No proposal at that index");
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::reject_proposal(Origin::ROOT, 0));
assert_noop!(Treasury::approve_proposal(Origin::ROOT, 0), "No proposal at that index");
});
}
@@ -529,8 +528,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 100, 3));
assert_ok!(Treasury::approve_proposal(0));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3));
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0));
<Treasury as OnFinalise<u64>>::on_finalise(2);
assert_eq!(Balances::free_balance(&3), 100);
@@ -543,8 +542,8 @@ mod tests {
with_externalities(&mut new_test_ext(), || {
Treasury::on_minted(100);
assert_ok!(Treasury::propose_spend(&0, 150, 3));
assert_ok!(Treasury::approve_proposal(0));
assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3));
assert_ok!(Treasury::approve_proposal(Origin::ROOT, 0));
<Treasury as OnFinalise<u64>>::on_finalise(2);
assert_eq!(Treasury::pot(), 100);
@@ -29,16 +29,11 @@ extern crate serde_derive;
#[macro_use]
extern crate substrate_runtime_std as rstd;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
#[macro_use]
extern crate substrate_codec_derive;
extern crate substrate_codec as codec;
use rstd::prelude::*;
#[cfg(feature = "std")]
use std::fmt;
@@ -133,18 +128,3 @@ impl RuntimeVersion {
self.spec_name == other.spec_name
}
}
pub trait Trait {
const VERSION: RuntimeVersion;
}
decl_module! {
pub struct Module<T: Trait>;
}
impl<T: Trait> Module<T> {
/// Get runtime version.
pub fn version() -> RuntimeVersion {
T::VERSION.clone()
}
}