diff --git a/substrate/srml/balances/src/lib.rs b/substrate/srml/balances/src/lib.rs
index e205fa0aaa..c8f5c33d06 100644
--- a/substrate/srml/balances/src/lib.rs
+++ b/substrate/srml/balances/src/lib.rs
@@ -346,6 +346,21 @@ decl_module! {
/// of the transfer, the account will be reaped.
///
/// The dispatch origin for this call must be `Signed` by the transactor.
+ ///
+ /// #
+ /// - Dependent on arguments but not critical, given proper implementations for
+ /// input config types. See related functions below.
+ /// - It contains a limited number of reads and writes internally and no complex computation.
+ ///
+ /// Related functions:
+ ///
+ /// - `ensure_can_withdraw` is always called internally but has a bounded complexity.
+ /// - Transferring balances to accounts that did not exist before will cause
+ /// `T::OnNewAccount::on_new_account` to be called.
+ /// - Removing enough funds from an account will trigger
+ /// `T::DustRemoval::on_unbalanced` and `T::OnFreeBalanceZero::on_free_balance_zero`.
+ ///
+ /// #
pub fn transfer(
origin,
dest: ::Source,
@@ -364,6 +379,11 @@ decl_module! {
/// and reset the account nonce (`system::AccountNonce`).
///
/// The dispatch origin for this call is `root`.
+ ///
+ /// #
+ /// - Independent of the arguments.
+ /// - Contains a limited number of reads and writes.
+ /// #
fn set_balance(
who: ::Source,
#[compact] free: T::Balance,
@@ -700,6 +720,10 @@ where
>::get(who)
}
+ // #
+ // Despite iterating over a list of locks, they are limited by the number of
+ // lock IDs, which means the number of runtime modules that intend to use and create locks.
+ // #
fn ensure_can_withdraw(
who: &T::AccountId,
_amount: T::Balance,
diff --git a/substrate/srml/council/src/motions.rs b/substrate/srml/council/src/motions.rs
index df357ac8c8..8f31ee582f 100644
--- a/substrate/srml/council/src/motions.rs
+++ b/substrate/srml/council/src/motions.rs
@@ -120,6 +120,10 @@ decl_module! {
Self::deposit_event(RawEvent::MemberExecuted(proposal_hash, ok));
}
+ /// #
+ /// - Bounded storage reads and writes.
+ /// - Argument `threshold` has bearing on weight.
+ /// #
fn propose(origin, #[compact] threshold: MemberCount, proposal: Box<::Proposal>) {
let who = ensure_signed(origin)?;
@@ -145,6 +149,10 @@ decl_module! {
}
}
+ /// #
+ /// - Bounded storage read and writes.
+ /// - Will be slightly heavier if the proposal is approved / disapproved after the vote.
+ /// #
fn vote(origin, proposal: T::Hash, #[compact] index: ProposalIndex, approve: bool) {
let who = ensure_signed(origin)?;
diff --git a/substrate/srml/council/src/seats.rs b/substrate/srml/council/src/seats.rs
index 3e80584900..84b6f388f2 100644
--- a/substrate/srml/council/src/seats.rs
+++ b/substrate/srml/council/src/seats.rs
@@ -171,6 +171,12 @@ decl_module! {
///
/// Note that any trailing `false` votes in `votes` is ignored; In approval voting, not voting for a candidate
/// and voting false, are equal.
+ ///
+ /// #
+ /// - O(1).
+ /// - Two extra DB entries, one DB change.
+ /// - Argument `votes` is limited in length to number of candidates.
+ /// #
fn set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result {
let who = ensure_signed(origin)?;
Self::do_set_approvals(who, votes, index, hint)
@@ -178,6 +184,10 @@ decl_module! {
/// Set candidate approvals from a proxy. Approval slots stay valid as long as candidates in those slots
/// are registered.
+ ///
+ /// #
+ /// - Same as `set_approvals` with one additional storage read.
+ /// #
fn proxy_set_approvals(origin, votes: Vec, #[compact] index: VoteIndex, hint: SetIndex) -> Result {
let who = >::proxy(ensure_signed(origin)?).ok_or("not a proxy")?;
Self::do_set_approvals(who, votes, index, hint)
@@ -190,6 +200,11 @@ decl_module! {
/// Both indices must be provided as explained in [`voter_at`] function.
///
/// May be called by anyone. Returns the voter deposit to `signed`.
+ ///
+ /// #
+ /// - O(1).
+ /// - Two fewer DB entries, one DB change.
+ /// #
fn reap_inactive_voter(
origin,
#[compact] reporter_index: u32,
@@ -258,6 +273,11 @@ decl_module! {
/// The index must be provided as explained in [`voter_at`] function.
///
/// Also removes the lock on the balance of the voter. See [`do_set_approvals()`].
+ ///
+ /// #
+ /// - O(1).
+ /// - Two fewer DB entries, one DB change.
+ /// #
fn retract_voter(origin, #[compact] index: u32) {
let who = ensure_signed(origin)?;
@@ -280,6 +300,11 @@ decl_module! {
/// it will NOT have any usable funds to pass candidacy bond and must first retract.
/// Note that setting approvals will lock the entire balance of the voter until
/// retraction or being reported.
+ ///
+ /// #
+ /// - Independent of input.
+ /// - Three DB changes.
+ /// #
fn submit_candidacy(origin, #[compact] slot: u32) {
let who = ensure_signed(origin)?;
@@ -310,6 +335,11 @@ decl_module! {
/// Claim that `signed` is one of the top Self::carry_count() + current_vote().1 candidates.
/// Only works if the `block_number >= current_vote().0` and `< current_vote().0 + presentation_duration()`
/// `signed` should have at least
+ ///
+ /// #
+ /// - O(voters) compute.
+ /// - One DB change.
+ /// #
fn present_winner(
origin,
candidate: ::Source,
diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs
index 2ccff71869..b6d032d791 100644
--- a/substrate/srml/democracy/src/lib.rs
+++ b/substrate/srml/democracy/src/lib.rs
@@ -321,6 +321,11 @@ decl_module! {
fn deposit_event() = default;
/// Propose a sensitive action to be taken.
+ ///
+ /// #
+ /// - O(1).
+ /// - Two DB changes, one DB entry.
+ /// #
fn propose(origin,
proposal: Box,
#[compact] value: BalanceOf
@@ -343,6 +348,11 @@ decl_module! {
}
/// Propose a sensitive action to be taken.
+ ///
+ /// #
+ /// - O(1).
+ /// - One DB entry.
+ /// #
fn second(origin, #[compact] proposal: PropIndex) {
let who = ensure_signed(origin)?;
let mut deposit = Self::deposit_of(proposal)
@@ -355,6 +365,11 @@ decl_module! {
/// Vote in a referendum. If `vote.is_aye()`, the vote is to enact the proposal;
/// otherwise it is a vote to keep the status quo.
+ ///
+ /// #
+ /// - O(1).
+ /// - One DB change, one DB entry.
+ /// #
fn vote(origin,
#[compact] ref_index: ReferendumIndex,
vote: Vote
@@ -365,6 +380,11 @@ decl_module! {
/// Vote in a referendum on behalf of a stash. If `vote.is_aye()`, the vote is to enact
/// the proposal; otherwise it is a vote to keep the status quo.
+ ///
+ /// #
+ /// - O(1).
+ /// - One DB change, one DB entry.
+ /// #
fn proxy_vote(origin,
#[compact] ref_index: ReferendumIndex,
vote: Vote
@@ -492,6 +512,10 @@ decl_module! {
}
/// Specify a proxy. Called by the stash.
+ ///
+ /// #
+ /// - One extra DB entry.
+ /// #
fn set_proxy(origin, proxy: T::AccountId) {
let who = ensure_signed(origin)?;
ensure!(!>::exists(&proxy), "already a proxy");
@@ -499,12 +523,20 @@ decl_module! {
}
/// Clear the proxy. Called by the proxy.
+ ///
+ /// #
+ /// - One DB clear.
+ /// #
fn resign_proxy(origin) {
let who = ensure_signed(origin)?;
>::remove(who);
}
/// Clear the proxy. Called by the stash.
+ ///
+ /// #
+ /// - One DB clear.
+ /// #
fn remove_proxy(origin, proxy: T::AccountId) {
let who = ensure_signed(origin)?;
ensure!(&Self::proxy(&proxy).ok_or("not a proxy")? == &who, "wrong proxy");
@@ -512,6 +544,10 @@ decl_module! {
}
/// Delegate vote.
+ ///
+ /// #
+ /// - One extra DB entry.
+ /// #
pub fn delegate(origin, to: T::AccountId, conviction: Conviction) {
let who = ensure_signed(origin)?;
>::insert(who.clone(), (to.clone(), conviction));
@@ -527,6 +563,10 @@ decl_module! {
}
/// Undelegate vote.
+ ///
+ /// #
+ /// - O(1).
+ /// #
fn undelegate(origin) {
let who = ensure_signed(origin)?;
ensure!(>::exists(&who), "not delegated");
diff --git a/substrate/srml/indices/src/lib.rs b/substrate/srml/indices/src/lib.rs
index 38f7ee668d..45487e3b51 100644
--- a/substrate/srml/indices/src/lib.rs
+++ b/substrate/srml/indices/src/lib.rs
@@ -156,6 +156,21 @@ impl Module {
}
impl OnNewAccount for Module {
+ // Implementation of the config type managing the creation of new accounts.
+ // See Balances module for a concrete example.
+ //
+ // #
+ // - Independent of the arguments.
+ // - Given the correct value of `Self::next_enum_set`, it always has a limited
+ // number of reads and writes and no complex computation.
+ //
+ // As for storage, calling this function with _non-dead-indices_ will linearly grow the length of
+ // of `Self::enum_set`. Appropriate economic incentives should exist to make callers of this
+ // function provide a `who` argument that reclaims a dead account.
+ //
+ // At the time of this writing, only the Balances module calls this function upon creation
+ // of new accounts.
+ // #
fn on_new_account(who: &T::AccountId) {
let enum_set_size = Self::enum_set_size();
let next_set_index = Self::next_enum_set();
diff --git a/substrate/srml/session/src/lib.rs b/substrate/srml/session/src/lib.rs
index d13795e4bb..5c36f6fadc 100644
--- a/substrate/srml/session/src/lib.rs
+++ b/substrate/srml/session/src/lib.rs
@@ -161,8 +161,16 @@ decl_module! {
pub struct Module for enum Call where origin: T::Origin {
fn deposit_event() = default;
- /// Sets the session key of a validator (function caller) to `key`.
+ /// Sets the session key of the function caller to `key`.
+ /// Allows an account to set its session key prior to becoming a validator.
/// This doesn't take effect until the next session.
+ ///
+ /// The dispatch origin of this function must be signed.
+ ///
+ /// #
+ /// - O(1).
+ /// - One extra DB entry.
+ /// #
fn set_key(origin, key: T::SessionKey) {
let who = ensure_signed(origin)?;
// set new value for next session
@@ -170,11 +178,15 @@ decl_module! {
}
/// Set a new session length. Won't kick in until the next session change (at current length).
+ ///
+ /// Dispatch origin of this call must be _root_.
fn set_length(#[compact] new: T::BlockNumber) {
>::put(new);
}
/// Forces a new session.
+ ///
+ /// Dispatch origin of this call must be _root_.
fn force_new_session(apply_rewards: bool) -> Result {
Self::apply_force_new_session(apply_rewards)
}
diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs
index 3f6905f654..e76b73a749 100644
--- a/substrate/srml/staking/src/lib.rs
+++ b/substrate/srml/staking/src/lib.rs
@@ -155,7 +155,7 @@
//!
//! The term [`SlotStake`](./struct.Module.html#method.slot_stake) will be used throughout this section. It refers
//! to a value calculated at the end of each era, containing the _minimum value at stake among all validators._
-//! Note that a validator's value at stake might be a combination of The validator's own stake
+//! Note that a validator's value at stake might be a combination of the validator's own stake
//! and the votes it received. See [`Exposure`](./struct.Exposure.html) for more details.
//!
//! ### Reward Calculation
@@ -226,7 +226,7 @@
//!
//! The election algorithm, aside from electing the validators with the most stake value and votes, tries to divide
//! the nominator votes among candidates in an equal manner. To further assure this, an optional post-processing
-//! can be applied that iteractively normalizes the nominator staked values until the total difference among
+//! can be applied that iteratively normalizes the nominator staked values until the total difference among
//! votes of a particular nominator are less than a threshold.
//!
//! ## GenesisConfig
@@ -569,6 +569,19 @@ decl_module! {
/// account that controls it.
///
/// The dispatch origin for this call must be _Signed_ by the stash account.
+ ///
+ /// #
+ /// - Independent of the arguments. Moderate complexity.
+ /// - O(1).
+ /// - Three extra DB entries.
+ ///
+ /// NOTE: Two of the storage writes (`Self::bonded`, `Self::payee`) are _never_ cleaned unless
+ /// the `origin` falls below _existential deposit_ and gets removed as dust.
+ ///
+ /// NOTE: At the moment, there are no financial restrictions to bond
+ /// (which creates a bunch of storage items for an account). In essence, nothing prevents many accounts from
+ /// spamming `Staking` storage by bonding 1 UNIT. See test case: `bond_with_no_staked_value`.
+ /// #
fn bond(origin, controller: ::Source, #[compact] value: BalanceOf, payee: RewardDestination) {
let stash = ensure_signed(origin)?;
@@ -583,7 +596,7 @@ decl_module! {
}
// You're auto-bonded forever, here. We might improve this by only bonding when
- // you actually validate/nominate.
+ // you actually validate/nominate and remove once you unbond __everything__.
>::insert(&stash, controller.clone());
>::insert(&stash, payee);
@@ -598,6 +611,12 @@ decl_module! {
/// Use this if there are additional funds in your stash account that you wish to bond.
///
/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
+ ///
+ /// #
+ /// - Independent of the arguments. Insignificant complexity.
+ /// - O(1).
+ /// - One DB entry.
+ /// #
fn bond_extra(origin, #[compact] max_additional: BalanceOf) {
let stash = ensure_signed(origin)?;
@@ -628,6 +647,15 @@ decl_module! {
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
///
/// See also [`Call::withdraw_unbonded`].
+ ///
+ /// #
+ /// - Independent of the arguments. Limited but potentially exploitable complexity.
+ /// - Contains a limited number of reads.
+ /// - Each call (requires the remainder of the bonded balance to be above `minimum_balance`)
+ /// will cause a new entry to be inserted into a vector (`Ledger.unlocking`) kept in storage.
+ /// The only way to clean the aforementioned storage item is also user-controlled via `withdraw_unbonded`.
+ /// - One DB entry.
+ ///
fn unbond(origin, #[compact] value: BalanceOf) {
let controller = ensure_signed(origin)?;
let mut ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -661,6 +689,14 @@ decl_module! {
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
///
/// See also [`Call::unbond`].
+ ///
+ /// #
+ /// - Could be dependent on the `origin` argument and how much `unlocking` chunks exist. It implies
+ /// `consolidate_unlocked` which loops over `Ledger.unlocking`, which is indirectly
+ /// user-controlled. See [`unbond`] for more detail.
+ /// - Contains a limited number of reads, yet the size of which could be large based on `ledger`.
+ /// - Writes are limited to the `origin` account key.
+ /// #
fn withdraw_unbonded(origin) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -673,6 +709,12 @@ decl_module! {
/// Effects will be felt at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
+ ///
+ /// #
+ /// - Independent of the arguments. Insignificant complexity.
+ /// - Contains a limited number of reads.
+ /// - Writes are limited to the `origin` account key.
+ /// #
fn validate(origin, prefs: ValidatorPrefs>) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -687,6 +729,12 @@ decl_module! {
/// Effects will be felt at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
+ ///
+ /// #
+ /// - The transaction's complexity is proportional to the size of `targets`,
+ /// which is capped at `MAX_NOMINATIONS`.
+ /// - Both the reads and writes follow a similar pattern.
+ /// #
fn nominate(origin, targets: Vec<::Source>) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -706,6 +754,12 @@ decl_module! {
/// Effects will be felt at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
+ ///
+ /// #
+ /// - Independent of the arguments. Insignificant complexity.
+ /// - Contains one read.
+ /// - Writes are limited to the `origin` account key.
+ /// #
fn chill(origin) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -719,6 +773,12 @@ decl_module! {
/// Effects will be felt at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
+ ///
+ /// #
+ /// - Independent of the arguments. Insignificant complexity.
+ /// - Contains a limited number of reads.
+ /// - Writes are limited to the `origin` account key.
+ /// #
fn set_payee(origin, payee: RewardDestination) {
let controller = ensure_signed(origin)?;
let ledger = Self::ledger(&controller).ok_or("not a controller")?;
@@ -731,6 +791,12 @@ decl_module! {
/// Effects will be felt at the beginning of the next era.
///
/// The dispatch origin for this call must be _Signed_ by the stash, not the controller.
+ ///
+ /// #
+ /// - Independent of the arguments. Insignificant complexity.
+ /// - Contains a limited number of reads.
+ /// - Writes are limited to the `origin` account key.
+ /// #
fn set_controller(origin, controller: ::Source) {
let stash = ensure_signed(origin)?;
let old_controller = Self::bonded(&stash).ok_or("not a stash")?;
@@ -744,6 +810,8 @@ decl_module! {
}
}
+ // ----- Root calls.
+
/// Set the number of sessions in an era.
fn set_sessions_per_era(#[compact] new: T::BlockNumber) {
>::put(new);
@@ -761,6 +829,12 @@ decl_module! {
/// 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.
+ ///
+ /// #
+ /// - Independent of the arguments.
+ /// - Triggers the Phragmen election. Expensive but not user-controlled.
+ /// - Depends on state: `O(|edges| * |validators|)`.
+ /// #
fn force_new_era(apply_rewards: bool) -> Result {
Self::apply_force_new_era(apply_rewards)
}
diff --git a/substrate/srml/staking/src/tests.rs b/substrate/srml/staking/src/tests.rs
index eba6ce77a5..357a1c1427 100644
--- a/substrate/srml/staking/src/tests.rs
+++ b/substrate/srml/staking/src/tests.rs
@@ -1669,20 +1669,15 @@ fn bond_with_no_staked_value() {
System::set_block_number(1);
Session::check_rotate_session(System::block_number());
- // Not elected even though we want 3.
assert_eq_uvec!(Session::validators(), vec![30, 20, 10]);
// min of 10, 20 and 30 (30 got a payout into staking so it raised it from 1 to 11).
assert_eq!(Staking::slot_stake(), 11);
- // let's make the stingy one elected.
+ // make the stingy one elected.
assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller));
assert_ok!(Staking::nominate(Origin::signed(4), vec![1]));
- // no rewards paid to 2 and 4 yet
- assert_eq!(Balances::free_balance(&2), initial_balance_2);
- assert_eq!(Balances::free_balance(&4), initial_balance_4);
-
System::set_block_number(2);
Session::check_rotate_session(System::block_number());
@@ -1692,10 +1687,6 @@ fn bond_with_no_staked_value() {
// New slot stake.
assert_eq!(Staking::slot_stake(), 501);
- // no rewards paid to 2 and 4 yet
- assert_eq!(Balances::free_balance(&2), initial_balance_2);
- assert_eq!(Balances::free_balance(&4), initial_balance_4);
-
System::set_block_number(3);
Session::check_rotate_session(System::block_number());
diff --git a/substrate/srml/sudo/src/lib.rs b/substrate/srml/sudo/src/lib.rs
index 1caeac73b8..a421bdae68 100644
--- a/substrate/srml/sudo/src/lib.rs
+++ b/substrate/srml/sudo/src/lib.rs
@@ -110,6 +110,12 @@ decl_module! {
/// Authenticates the sudo key and dispatches a function call with `Root` origin.
///
/// The dispatch origin for this call must be _Signed_.
+ ///
+ /// #
+ /// - O(1).
+ /// - Limited storage reads.
+ /// - No DB writes.
+ /// #
fn sudo(origin, proposal: Box) {
// This is a public call, so we ensure that the origin is some signed account.
let sender = ensure_signed(origin)?;
@@ -129,6 +135,12 @@ decl_module! {
/// Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo key.
///
/// The dispatch origin for this call must be _Signed_.
+ ///
+ /// #
+ /// - O(1).
+ /// - Limited storage reads.
+ /// - One DB change.
+ /// #
fn set_key(origin, new: ::Source) {
// This is a public call, so we ensure that the origin is some signed account.
let sender = ensure_signed(origin)?;
diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs
index b08321f860..276b389dc1 100644
--- a/substrate/srml/system/src/lib.rs
+++ b/substrate/srml/system/src/lib.rs
@@ -475,7 +475,7 @@ impl Module {
/// Deposits an event into this block's event record adding this event
/// to the corresponding topic indexes.
///
- /// This will update storage entries that correpond to the specified topics.
+ /// This will update storage entries that correspond to the specified topics.
/// It is expected that light-clients could subscribe to this topics.
pub fn deposit_event_indexed(topics: &[T::Hash], event: T::Event) {
let extrinsic_index = Self::extrinsic_index();
diff --git a/substrate/srml/treasury/src/lib.rs b/substrate/srml/treasury/src/lib.rs
index cd9e781f66..fb3b68a6e9 100644
--- a/substrate/srml/treasury/src/lib.rs
+++ b/substrate/srml/treasury/src/lib.rs
@@ -110,6 +110,12 @@ decl_module! {
/// 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.
+ ///
+ /// #
+ /// - O(1).
+ /// - Limited storage reads.
+ /// - One DB change, one extra DB entry.
+ /// #
fn propose_spend(
origin,
#[compact] value: BalanceOf,
@@ -149,6 +155,12 @@ decl_module! {
}
/// Reject a proposed spend. The original deposit will be slashed.
+ ///
+ /// #
+ /// - O(1).
+ /// - Limited storage reads.
+ /// - One DB clear.
+ /// #
fn reject_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::RejectOrigin::ensure_origin(origin)?;
let proposal = >::take(proposal_id).ok_or("No proposal at that index")?;
@@ -160,6 +172,12 @@ decl_module! {
/// Approve a proposal. At a later time, the proposal will be allocated to the beneficiary
/// and the original deposit will be returned.
+ ///
+ /// #
+ /// - O(1).
+ /// - Limited storage reads.
+ /// - One DB change.
+ /// #
fn approve_proposal(origin, #[compact] proposal_id: ProposalIndex) {
T::ApproveOrigin::ensure_origin(origin)?;