Implement parameterisable modules (#1800)

* first implementation

* remove done comment

* origin done

* impl log for instance

* impl inherent for instance

* Fix wasm build + full example build

this requires parity codec implements codec for core::marker::PhantomData

* patch parity-codec link to github branch

* improve internal names and fix instance prefix

* Fix in macros

* add test modules for support

this allow to test for construct_runtime as well.

The reason to have put that in another crate is:
* if we put test in `tests/` dir of srml/support then decl_storage fails to get
  srml-support access because it believes it is inside srml-support
  crate and so derive access to `quote!{ crate }` but this is wrong
  (and I don't see any way to prevent that, and it only bother us so I
  don't think that matters that much)
* if we put test inside lib.rs then contruct_runtime cannot be used
  because it call some macros that are defined with macros
  (decl_outer_event and decl_outer_origin) and thus rustc complains.

* defaultinstance to its own struct to avoid errors

* enforce <T, I> for Event and Config, impl test

* add origin, log, inherent to test

* test more code generation

* basic storage test

* fix typo

* rename a few imports and field

* delete wip test in example and runtime

* change default prefix to make it backward compatible with test

* rename Instance to I and Instantiable to Instance

note: the name of generic parameter I is only enforce by decl_module!
and this could be rewritten

* doc

* clean old TODOs

* update parity-codec to 3.2

* update node impl version + builds

* fix warning

* fix unrelated grandpa test

* refactor code
This commit is contained in:
thiolliere
2019-03-15 19:25:18 +01:00
committed by Gav Wood
parent c52c528ee8
commit d743a8b71f
80 changed files with 1632 additions and 1016 deletions
+35 -34
View File
@@ -41,7 +41,7 @@ use system::{IsDeadAccount, OnNewAccount, ensure_signed};
mod mock;
mod tests;
pub trait Trait: system::Trait {
pub trait Trait<I: Instance = DefaultInstance>: system::Trait {
/// The balance of an account.
type Balance: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As<usize> + As<u64> + MaybeSerializeDebug;
@@ -55,7 +55,7 @@ pub trait Trait: system::Trait {
type OnNewAccount: OnNewAccount<Self::AccountId>;
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
type Event: From<Event<Self, I>> + Into<<Self as system::Trait>::Event>;
}
impl<T: Trait> ArithmeticType for Module<T> {
@@ -63,9 +63,9 @@ impl<T: Trait> ArithmeticType for Module<T> {
}
decl_event!(
pub enum Event<T> where
pub enum Event<T, I: Instance = DefaultInstance> where
<T as system::Trait>::AccountId,
<T as Trait>::Balance
<T as Trait<I>>::Balance
{
/// A new account was created.
NewAccount(AccountId, Balance),
@@ -107,9 +107,9 @@ pub struct BalanceLock<Balance, BlockNumber> {
}
decl_storage! {
trait Store for Module<T: Trait> as Balances {
trait Store for Module<T: Trait<I>, I: Instance=DefaultInstance> as Balances {
/// The total amount of stake on the system.
pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig<T>| {
pub TotalIssuance get(total_issuance) build(|config: &GenesisConfig<T, I>| {
config.balances.iter().fold(Zero::zero(), |acc: T::Balance, &(_, n)| acc + n)
}): T::Balance;
/// The minimum amount allowed to keep an account open.
@@ -120,7 +120,7 @@ decl_storage! {
pub CreationFee get(creation_fee) config(): T::Balance;
/// Information regarding the vesting of a given account.
pub Vesting get(vesting) build(|config: &GenesisConfig<T>| {
pub Vesting get(vesting) build(|config: &GenesisConfig<T, I>| {
config.vesting.iter().filter_map(|&(ref who, begin, length)| {
let begin: u64 = begin.as_();
let length: u64 = length.as_();
@@ -152,7 +152,7 @@ decl_storage! {
///
/// `system::AccountNonce` is also deleted if `ReservedBalance` is also zero (it also gets
/// collapsed to zero if it ever becomes less than `ExistentialDeposit`.
pub FreeBalance get(free_balance) build(|config: &GenesisConfig<T>| config.balances.clone()): map T::AccountId => T::Balance;
pub FreeBalance get(free_balance) build(|config: &GenesisConfig<T, I>| config.balances.clone()): map T::AccountId => T::Balance;
/// The amount of the balance of a given account that is externally reserved; this can still get
/// slashed, but gets slashed last of all.
@@ -175,11 +175,12 @@ decl_storage! {
config(balances): Vec<(T::AccountId, T::Balance)>;
config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber)>; // begin, length
}
extra_genesis_skip_phantom_data_field;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
pub struct Module<T: Trait<I>, I: Instance = DefaultInstance> for enum Call where origin: T::Origin {
fn deposit_event<T, I>() = default;
/// Transfer some liquid free balance to another staker.
pub fn transfer(
@@ -206,7 +207,7 @@ decl_module! {
}
// For funding methods, see Currency trait
impl<T: Trait> Module<T> {
impl<T: Trait<I>, I: Instance> Module<T, I> {
/// Get the amount that is currently being vested and cannot be transfered out of this account.
pub fn vesting_balance(who: &T::AccountId) -> T::Balance {
@@ -223,11 +224,11 @@ impl<T: Trait> Module<T> {
/// In that case it will return `AccountKilled`.
pub fn set_reserved_balance(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome {
if balance < Self::existential_deposit() {
<ReservedBalance<T>>::insert(who, balance);
<ReservedBalance<T, I>>::insert(who, balance);
Self::on_reserved_too_low(who);
UpdateBalanceOutcome::AccountKilled
} else {
<ReservedBalance<T>>::insert(who, balance);
<ReservedBalance<T, I>>::insert(who, balance);
UpdateBalanceOutcome::Updated
}
}
@@ -243,11 +244,11 @@ impl<T: Trait> Module<T> {
// Commented out for no - but consider it instructive.
// assert!(!Self::total_balance(who).is_zero());
if balance < Self::existential_deposit() {
<FreeBalance<T>>::insert(who, balance);
<FreeBalance<T, I>>::insert(who, balance);
Self::on_free_too_low(who);
UpdateBalanceOutcome::AccountKilled
} else {
<FreeBalance<T>>::insert(who, balance);
<FreeBalance<T, I>>::insert(who, balance);
UpdateBalanceOutcome::Updated
}
}
@@ -260,7 +261,7 @@ impl<T: Trait> Module<T> {
///
/// [`set_free_balance`]: #method.set_free_balance
pub fn set_free_balance_creating(who: &T::AccountId, balance: T::Balance) -> UpdateBalanceOutcome {
let ed = <Module<T>>::existential_deposit();
let ed = <Module<T, I>>::existential_deposit();
// If the balance is too low, then the account is reaped.
// NOTE: There are two balances for every account: `reserved_balance` and
// `free_balance`. This contract subsystem only cares about the latter: whenever
@@ -275,7 +276,7 @@ impl<T: Trait> Module<T> {
Self::set_free_balance(who, balance);
UpdateBalanceOutcome::AccountKilled
} else {
if !<FreeBalance<T>>::exists(who) {
if !<FreeBalance<T, I>>::exists(who) {
Self::new_account(&who, balance);
}
Self::set_free_balance(who, balance);
@@ -335,8 +336,8 @@ impl<T: Trait> Module<T> {
/// Kill an account's free portion.
fn on_free_too_low(who: &T::AccountId) {
Self::decrease_total_stake_by(Self::free_balance(who));
<FreeBalance<T>>::remove(who);
<Locks<T>>::remove(who);
<FreeBalance<T, I>>::remove(who);
<Locks<T, I>>::remove(who);
T::OnFreeBalanceZero::on_free_balance_zero(who);
@@ -348,7 +349,7 @@ impl<T: Trait> Module<T> {
/// Kill an account's reserved portion.
fn on_reserved_too_low(who: &T::AccountId) {
Self::decrease_total_stake_by(Self::reserved_balance(who));
<ReservedBalance<T>>::remove(who);
<ReservedBalance<T, I>>::remove(who);
if Self::free_balance(who).is_zero() {
Self::reap_account(who);
@@ -357,14 +358,14 @@ impl<T: Trait> Module<T> {
/// Increase TotalIssuance by Value.
pub fn increase_total_stake_by(value: T::Balance) {
if let Some(v) = <Module<T>>::total_issuance().checked_add(&value) {
<TotalIssuance<T>>::put(v);
if let Some(v) = <Module<T, I>>::total_issuance().checked_add(&value) {
<TotalIssuance<T, I>>::put(v);
}
}
/// Decrease TotalIssuance by Value.
pub fn decrease_total_stake_by(value: T::Balance) {
if let Some(v) = <Module<T>>::total_issuance().checked_sub(&value) {
<TotalIssuance<T>>::put(v);
if let Some(v) = <Module<T, I>>::total_issuance().checked_sub(&value) {
<TotalIssuance<T, I>>::put(v);
}
}
@@ -398,7 +399,7 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> Currency<T::AccountId> for Module<T>
impl<T: Trait<I>, I: Instance> Currency<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDebug
{
@@ -421,7 +422,7 @@ where
}
fn total_issuance() -> Self::Balance {
<TotalIssuance<T>>::get()
<TotalIssuance<T, I>>::get()
}
fn minimum_balance() -> Self::Balance {
@@ -429,11 +430,11 @@ where
}
fn free_balance(who: &T::AccountId) -> Self::Balance {
<FreeBalance<T>>::get(who)
<FreeBalance<T, I>>::get(who)
}
fn reserved_balance(who: &T::AccountId) -> Self::Balance {
<ReservedBalance<T>>::get(who)
<ReservedBalance<T, I>>::get(who)
}
fn slash(who: &T::AccountId, value: Self::Balance) -> Option<Self::Balance> {
@@ -517,7 +518,7 @@ where
}
}
impl<T: Trait> LockableCurrency<T::AccountId> for Module<T>
impl<T: Trait<I>, I: Instance> LockableCurrency<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDebug
{
@@ -543,7 +544,7 @@ where
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T>>::insert(who, locks);
<Locks<T, I>>::insert(who, locks);
}
fn extend_lock(
@@ -573,7 +574,7 @@ where
if let Some(lock) = new_lock {
locks.push(lock)
}
<Locks<T>>::insert(who, locks);
<Locks<T, I>>::insert(who, locks);
}
fn remove_lock(
@@ -587,11 +588,11 @@ where
} else {
None
}).collect::<Vec<_>>();
<Locks<T>>::insert(who, locks);
<Locks<T, I>>::insert(who, locks);
}
}
impl<T: Trait> TransferAsset<T::AccountId> for Module<T> {
impl<T: Trait<I>, I: Instance> TransferAsset<T::AccountId> for Module<T, I> {
type Amount = T::Balance;
fn transfer(from: &T::AccountId, to: &T::AccountId, amount: T::Balance) -> Result {
@@ -615,7 +616,7 @@ impl<T: Trait> TransferAsset<T::AccountId> for Module<T> {
}
}
impl<T: Trait> IsDeadAccount<T::AccountId> for Module<T>
impl<T: Trait<I>, I: Instance> IsDeadAccount<T::AccountId> for Module<T, I>
where
T::Balance: MaybeSerializeDebug
{