mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 20:07:56 +00:00
Issue 7143 | Refactor Treasury Pallet into Bounties, Tips, and Proposals (#7536)
* wk2046 | D5 | treasury refactor to bounties and tips * wk2046 | D5 | treasury refactor to bounties and tips | p2 * fix test compilation, ignoring events * initialize treasury in genesis * wk2046 | D7 | treasury refactor | fix bounties test build issues * wk2047 | D1 | treasury refactor | tips pallet bringup * wk2047 | D2 | treasury refactor | bounties pallet | unit test bringup * wk2047 | D2 | treasury refactor | bounties pallet | unit test bringup | p2 * wk2047 | D2 | treasury refactor | pallet-tips| test_last_reward_migration | test failure - analysis * wk2047 | D3 | treasury refactor | pallet-tips| test_last_reward_migration | test failure - fix * wk2047 | D3 | treasury refactor | pallet-bounties | on_initialize() fix * wk2047 | D3 | treasury refactor | pallet-bounties | on_initialize() fix | p2 * wk2047 | D4 | treasury refactor | pallet-bounties + pallet-treasury | spend_fund runtime hooks * wk2047 | D4 | treasury refactor | pallet-bounties + pallet-treasury | spend_fund runtime hooks | p2 * wk2047 | D4 | treasury refactor | pallet-bounties + pallet-treasury | spend_fund runtime hooks | p3 * wk2047 | D5 | treasury refactor | pallet-bounties + pallet-treasury | spend_fund runtime hooks | p4 * wk2047 | D6 | treasury refactor | review comments fix * some fixes * fix bounties instantiable * remove instantiable from tips and bounties * fix compile for benchmarks * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_treasury --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/treasury/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update lib.rs * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_tips --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/tips/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bounties --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bounties/src/weights.rs --template=./.maintain/frame-weight-template.hbs * add back `on_initialize_bounties` * patch up bounties benchmarks * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_bounties --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/bounties/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Remove development TODO from public doc comment (#7500) * refactor subtrait/elevated trait as not needed (#7497) * Fix comments of indices pallet events (#7511) Arguments for IndexAssigned and IndexFrozen were inverted in comments. * Skip slot lenience on first block in BABE (#7515) The genesis header doesn't have the BABE pre-digest and we insert `0` as slot number. The slot lenience calculation will return the maximum in this situation. Besides returning the maximum which is not bad at all, it also prints some a debug message that can be confusing in the first moment. To prevent printing this debug message, we now just return early when we see that the parent block is the genesis block. * slots: incrementally backoff claiming slots if finality lags behind (#7186) * babe: backoff authoring blocks when finality lags * babe: move backoff authoring params to default constructor * babe: deduplicate the test a bit * babe: set backoff constants in service * babe: use better names for backoff authoring block parameters * babe: remove last unwrap * babe: slight style tweak * babe: fix comment * slots: move backoff block authorship logic to SimpleSlotWorker * aura: append SlotInfo in on_slot * slots: use the correct types for parameters * slots: fix review comments * aura: add missing backoff authoring blocks parameters * slots: add comments for default values * slots: add additional checks in test * slots: update implementation for new master * slots: revert the change to SlotInfo * Fix review comments * slots: rework unit tests for backing off claiming slots * slots: add test for asymptotic behaviour for slot claims * slots: address review comments * slots: add test for max_interval * slots: add assertion for intervals between between claimed slots * slots: remove rustfmt directive * slots: another attempt at explaining authoring_rate * slots: up unfinalized_slack to 50 by default * slots: add tests for time to reach max_interval * slots: fix typo in comments * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * slots: additional tweaks to comments and info calls * slots: rename to BackoffAuthoringOnFinalizedHeadLagging * slots: make the backing off strategy generic * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * slots: implement backoff trait for () for simplicity * slots: move logging inside backing off function to make it more specific * aura: add missing function parameter Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Export app-crypto specific keystore functions (#7489) * Export app-crypto specific keystore functions * Also add back the insert function * Switch KeystoreContainer to an enum * Only export the bare minimal for LocalKeystore and fix service compile * fix: should return Arc * Add docs stating that functions only available in local keystore * Remove insert and generate functions * fix: generate function should be available in test * Add keypair function to trait * Revert "Add keypair function to trait" This reverts commit ad921b09ca73d3c09298e3a51b562ef8e0067781. * Add note for local_keystore function in service * Update doc for the --chain flag (#7520) * contracts: Add missing instruction to the `Schedule` (#7527) * Don't log with colors when we are writing to a tty (#7525) * Don't log with colors when we are writing to a tty This fixes a regression that was introduced by the switch to tracing. Before we killed all colors before writing to a tty, this pr brings the behaviour back. * Remove accidentally added crate * Review feedback * More feedback * Update client/cli/src/logging.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Update client/cli/src/logging.rs Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * MemoryId -> u32 (#7534) * Enable local addresses in DHT when chain type == `Local` | `Development` (#7538) * Enable local addresses in DHT when chain type == `Local` | `Development` This pr changes when to add local addresses to DHT. Instead of only checking if `--discover-local` and `--dev` are present, we now also check if the chain type is `Local` or `Development`. * Update the docs! * Update tiny-bip39 to v0.8 (#7539) It would improve secret zeroization due to https://github.com/maciejhirsz/tiny-bip39/pull/22, and would also remove one of the points where we depend on `failure` crate, which is deprecated (see https://github.com/rust-lang-nursery/failure/pull/347) * make LocalCallExecutor public (#7528) * Fix some weirdness in `offchain_worker` (#7541) We call `offchain_worker` with the state of the imported block and pass the header of this block. However in the runtime we call all `offchain_worker` functions with the number of the parent block. Besides that we also pass all digests and not only the pre runtime digests. In the context where the offchain worker is executed we have all digests, so there is no real reason to only pass pre runtime digests. Another fix is that we also insert the hash of the current header into the block hash map. * Use inbound peerslot slots when a substream is received, rather than a connection (#7464) * Use inbound peerslot slots when a substream is received, rather than a connection * Refactor PeerState * Some bugfixes * Fix warnings so that CI runs, gmlrlblbl * Bugfixes * Update docs * Apply suggestions from code review Co-authored-by: Roman Borschel <romanb@users.noreply.github.com> * Clean up Banned state * Refactor connections state * Fix possibility of Enabled with no Opening or Open connection * Line width * Add some debug_asserts! and fix TODO * Refactor legacy handler * Rewrite group.rs entirely [part 1] * Rewrite group.rs entirely [part 2] * Remove faulty assertion Because of the asynchronous nature of the behaviour <-> handler communications, it is possible to receive notifications while in the Closing state * Don't poll the legacy substream is not Open * Tolerate when not all substreams are accepted * Remove TODOs * Dummy commit to make CI log interesting things * Try race condition fix * Revert "Try race condition fix" This reverts commit 0675c659d06195c30f8c5bc13e2d88141d57a3ba. * Correctly rebuild pending_opening * Minor tweaks * Printlns for CI debugging * Revert "Printlns for CI debugging" This reverts commit e7852a231f4fc418898767aaa27c9a4358e12e8b. * Revert "Dummy commit to make CI log interesting things" This reverts commit 259ddd74088e53e7c6a9b0a62a8d1573a0063ce3. * mv group.rs ../handler.rs * Apply suggestions from code review Co-authored-by: Max Inden <mail@max-inden.de> * Banned => Backoff * Mention the actual PeerStates * OpenDesired -> OpenDesiredByRemote * OpeningThenClosing * Add doc links to PeerState * Simplify increment logic * One more debug_assert * debug_assert! * OpenDesiredByRemote * Update client/network/src/protocol/generic_proto/behaviour.rs Co-authored-by: Max Inden <mail@max-inden.de> Co-authored-by: Roman Borschel <romanb@users.noreply.github.com> Co-authored-by: Max Inden <mail@max-inden.de> * *: Update to libp2p v0.30.0 (#7508) * *: Update to libp2p v0.30.0 * Cargo.lock: Update * *: Update to libp2p v0.30.1 * make ClientConfig public (#7544) * sc-basic-authorship: remove useless dependencies (#7550) Signed-off-by: koushiro <koushiro.cqx@gmail.com> * Add slashing events to elections-phragmen. (#7543) * Add slashing events to elections-phragmen. * Fix build * Apply suggestions from code review * Update frame/elections-phragmen/src/lib.rs * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Remove necessity to pass ConsensusEngineId when registering notifications protocol (#7549) * Remove necessity to pass ConsensusEngineId when registering notifications protocol * Line width * Fix tests protocol name * Other renames * Doc update * Change issue in TODO * sc-cli: replace bip39 with tiny-bip39 (#7551) Signed-off-by: koushiro <koushiro.cqx@gmail.com> * Add extra docs to on_initialize (#7552) * Add some extra on_initialize docs. * Address review comments. * More Extensible Multiaddress Format (#7380) * More extensible multiaddress format * update name * Don't depend on indices to define multiaddress type * Use MultiAddress in Node Template too! * reduce traits, fix build * support multiple `StaticLookup` * bump tx version * feedback * Fix weight template to remove ugliness in rust doc (#7565) fixed weight template * Cargo.lock: Run cargo update (#7553) * Cargo.lock: Run cargo update * Cargo.lock: Downgrade cc to v1.0.62 * Cargo.lock: Revert wasm-* updates * .github: Add dependabot config and thus enable dependabot (#7509) * .github: Add dependabot config and thus enable dependabot * Update .github/dependabot.yml Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> * Thread-local parameter_types for testing. (#7542) * Thread-local parameter_types for testing. * Better docs. * Some minors * Merge'em * Update frame/support/src/lib.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Align more to basti's trick * Update frame/support/src/lib.rs * Update frame/support/src/lib.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> Co-authored-by: Bastian Köcher <git@kchr.de> * Bump wasm-bindgen-test from 0.3.12 to 0.3.17 (#7567) * Bump wasm-bindgen-test from 0.3.12 to 0.3.17 Bumps [wasm-bindgen-test](https://github.com/rustwasm/wasm-bindgen) from 0.3.12 to 0.3.17. - [Release notes](https://github.com/rustwasm/wasm-bindgen/releases) - [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/master/CHANGELOG.md) - [Commits](https://github.com/rustwasm/wasm-bindgen/commits) Signed-off-by: dependabot[bot] <support@github.com> * Update wasm-bindgen pin to 0.2.68 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> * wk2047 | D6 | treasury refactor | review comments fix | p2 * wk2048 | D1 | treasury refactor | review comments fix | p3 * Update bin/node/runtime/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * Update bin/node/runtime/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> * wk2048 | D3 | treasury refactor | review comments fix | p4 * wk2048 | D3 | treasury refactor | review comments fix | p5 * wk2048 | D4 | treasury refactor | review comments fix | removal of deadcode | p6 * remove broken link * wk2048 | D5 | treasury refactor | review comments fix | bountise doc string | p7 * wk2048 | D5 | treasury refactor | review comments fix | p8 * docs and formatting * Update frame/tips/src/benchmarking.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * formatting nits * Trait -> Config * trait -> config in benchmarks * clean up weight docs * Trait -> Config in Runtime * fix test build * try to fix polkadot build check * fix traits * Update lib.rs * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Apply suggestions from code review Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * fix trait location * nits * uncomment on_initialize for bounties benchmarks * update weights Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Parity Benchmarking Bot <admin@parity.io> Co-authored-by: Caio <c410.f3r@gmail.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Antoine Le Calvez <alecalve@users.noreply.github.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com> Co-authored-by: Wei Tang <wei@that.world> Co-authored-by: Sergei Shulepov <sergei@parity.io> Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> Co-authored-by: Kirill Pimenov <kirill@parity.io> Co-authored-by: Andrew Plaza <aplaza@liquidthink.net> Co-authored-by: Roman Borschel <romanb@users.noreply.github.com> Co-authored-by: Max Inden <mail@max-inden.de> Co-authored-by: Qinxuan Chen <koushiro.cqx@gmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Addie Wagenknecht <addie@nortd.com>
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Treasury tips benchmarking.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
|
||||
use frame_system::RawOrigin;
|
||||
use frame_benchmarking::{benchmarks, account, whitelisted_caller};
|
||||
use sp_runtime::{traits::{Saturating}};
|
||||
|
||||
use crate::Module as TipsMod;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
// Create the pre-requisite information needed to create a `report_awesome`.
|
||||
fn setup_awesome<T: Config>(length: u32) -> (T::AccountId, Vec<u8>, T::AccountId) {
|
||||
let caller = whitelisted_caller();
|
||||
let value = T::TipReportDepositBase::get()
|
||||
+ T::DataDepositPerByte::get() * length.into()
|
||||
+ T::Currency::minimum_balance();
|
||||
let _ = T::Currency::make_free_balance_be(&caller, value);
|
||||
let reason = vec![0; length as usize];
|
||||
let awesome_person = account("awesome", 0, SEED);
|
||||
(caller, reason, awesome_person)
|
||||
}
|
||||
|
||||
// Create the pre-requisite information needed to call `tip_new`.
|
||||
fn setup_tip<T: Config>(r: u32, t: u32) ->
|
||||
Result<(T::AccountId, Vec<u8>, T::AccountId, BalanceOf<T>), &'static str>
|
||||
{
|
||||
let tippers_count = T::Tippers::count();
|
||||
|
||||
for i in 0 .. t {
|
||||
let member = account("member", i, SEED);
|
||||
T::Tippers::add(&member);
|
||||
ensure!(T::Tippers::contains(&member), "failed to add tipper");
|
||||
}
|
||||
|
||||
ensure!(T::Tippers::count() == tippers_count + t as usize, "problem creating tippers");
|
||||
let caller = account("member", t - 1, SEED);
|
||||
let reason = vec![0; r as usize];
|
||||
let beneficiary = account("beneficiary", t, SEED);
|
||||
let value = T::Currency::minimum_balance().saturating_mul(100u32.into());
|
||||
Ok((caller, reason, beneficiary, value))
|
||||
}
|
||||
|
||||
// Create `t` new tips for the tip proposal with `hash`.
|
||||
// This function automatically makes the tip able to close.
|
||||
fn create_tips<T: Config>(t: u32, hash: T::Hash, value: BalanceOf<T>) ->
|
||||
Result<(), &'static str>
|
||||
{
|
||||
for i in 0 .. t {
|
||||
let caller = account("member", i, SEED);
|
||||
ensure!(T::Tippers::contains(&caller), "caller is not a tipper");
|
||||
TipsMod::<T>::tip(RawOrigin::Signed(caller).into(), hash, value)?;
|
||||
}
|
||||
Tips::<T>::mutate(hash, |maybe_tip| {
|
||||
if let Some(open_tip) = maybe_tip {
|
||||
open_tip.closes = Some(T::BlockNumber::zero());
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_pod_account<T: Config>() {
|
||||
let pot_account = TipsMod::<T>::account_id();
|
||||
let value = T::Currency::minimum_balance().saturating_mul(1_000_000_000u32.into());
|
||||
let _ = T::Currency::make_free_balance_be(&pot_account, value);
|
||||
}
|
||||
|
||||
const MAX_BYTES: u32 = 16384;
|
||||
const MAX_TIPPERS: u32 = 100;
|
||||
|
||||
benchmarks! {
|
||||
_ { }
|
||||
|
||||
report_awesome {
|
||||
let r in 0 .. MAX_BYTES;
|
||||
let (caller, reason, awesome_person) = setup_awesome::<T>(r);
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), reason, awesome_person)
|
||||
|
||||
retract_tip {
|
||||
let r = MAX_BYTES;
|
||||
let (caller, reason, awesome_person) = setup_awesome::<T>(r);
|
||||
TipsMod::<T>::report_awesome(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
reason.clone(),
|
||||
awesome_person.clone()
|
||||
)?;
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &awesome_person));
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), hash)
|
||||
|
||||
tip_new {
|
||||
let r in 0 .. MAX_BYTES;
|
||||
let t in 1 .. MAX_TIPPERS;
|
||||
|
||||
let (caller, reason, beneficiary, value) = setup_tip::<T>(r, t)?;
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), reason, beneficiary, value)
|
||||
|
||||
tip {
|
||||
let t in 1 .. MAX_TIPPERS;
|
||||
let (member, reason, beneficiary, value) = setup_tip::<T>(0, t)?;
|
||||
let value = T::Currency::minimum_balance().saturating_mul(100u32.into());
|
||||
TipsMod::<T>::tip_new(
|
||||
RawOrigin::Signed(member).into(),
|
||||
reason.clone(),
|
||||
beneficiary.clone(),
|
||||
value
|
||||
)?;
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary));
|
||||
ensure!(Tips::<T>::contains_key(hash), "tip does not exist");
|
||||
create_tips::<T>(t - 1, hash.clone(), value)?;
|
||||
let caller = account("member", t - 1, SEED);
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), hash, value)
|
||||
|
||||
close_tip {
|
||||
let t in 1 .. MAX_TIPPERS;
|
||||
|
||||
// Make sure pot is funded
|
||||
setup_pod_account::<T>();
|
||||
|
||||
// Set up a new tip proposal
|
||||
let (member, reason, beneficiary, value) = setup_tip::<T>(0, t)?;
|
||||
let value = T::Currency::minimum_balance().saturating_mul(100u32.into());
|
||||
TipsMod::<T>::tip_new(
|
||||
RawOrigin::Signed(member).into(),
|
||||
reason.clone(),
|
||||
beneficiary.clone(),
|
||||
value
|
||||
)?;
|
||||
|
||||
// Create a bunch of tips
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary));
|
||||
ensure!(Tips::<T>::contains_key(hash), "tip does not exist");
|
||||
create_tips::<T>(t, hash.clone(), value)?;
|
||||
|
||||
let caller = account("caller", t, SEED);
|
||||
// Whitelist caller account from further DB operations.
|
||||
let caller_key = frame_system::Account::<T>::hashed_key_for(&caller);
|
||||
frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into());
|
||||
}: _(RawOrigin::Signed(caller), hash)
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{new_test_ext, Test};
|
||||
use frame_support::assert_ok;
|
||||
|
||||
#[test]
|
||||
fn test_benchmarks() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_ok!(test_benchmark_report_awesome::<Test>());
|
||||
assert_ok!(test_benchmark_retract_tip::<Test>());
|
||||
assert_ok!(test_benchmark_tip_new::<Test>());
|
||||
assert_ok!(test_benchmark_tip::<Test>());
|
||||
assert_ok!(test_benchmark_close_tip::<Test>());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,576 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2017-2020 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! # Tipping Module ( pallet-tips )
|
||||
//!
|
||||
//! > NOTE: This pallet is tightly coupled with pallet-treasury.
|
||||
//!
|
||||
//! A subsystem to allow for an agile "tipping" process, whereby a reward may be given without first
|
||||
//! having a pre-determined stakeholder group come to consensus on how much should be paid.
|
||||
//!
|
||||
//! A group of `Tippers` is determined through the config `Config`. After half of these have declared
|
||||
//! some amount that they believe a particular reported reason deserves, then a countdown period is
|
||||
//! entered where any remaining members can declare their tip amounts also. After the close of the
|
||||
//! countdown period, the median of all declared tips is paid to the reported beneficiary, along
|
||||
//! with any finders fee, in case of a public (and bonded) original report.
|
||||
//!
|
||||
//!
|
||||
//! ### Terminology
|
||||
//!
|
||||
//! Tipping protocol:
|
||||
//! - **Tipping:** The process of gathering declarations of amounts to tip and taking the median
|
||||
//! amount to be transferred from the treasury to a beneficiary account.
|
||||
//! - **Tip Reason:** The reason for a tip; generally a URL which embodies or explains why a
|
||||
//! particular individual (identified by an account ID) is worthy of a recognition by the
|
||||
//! treasury.
|
||||
//! - **Finder:** The original public reporter of some reason for tipping.
|
||||
//! - **Finders Fee:** Some proportion of the tip amount that is paid to the reporter of the tip,
|
||||
//! rather than the main beneficiary.
|
||||
//!
|
||||
//! ## Interface
|
||||
//!
|
||||
//! ### Dispatchable Functions
|
||||
//!
|
||||
//! Tipping protocol:
|
||||
//! - `report_awesome` - Report something worthy of a tip and register for a finders fee.
|
||||
//! - `retract_tip` - Retract a previous (finders fee registered) report.
|
||||
//! - `tip_new` - Report an item worthy of a tip and declare a specific amount to tip.
|
||||
//! - `tip` - Declare or redeclare an amount to tip for a particular reason.
|
||||
//! - `close_tip` - Close and pay out a tip.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod tests;
|
||||
mod benchmarking;
|
||||
pub mod weights;
|
||||
|
||||
use sp_std::if_std;
|
||||
|
||||
use sp_std::prelude::*;
|
||||
use frame_support::{decl_module, decl_storage, decl_event, ensure, decl_error, Parameter};
|
||||
use frame_support::traits::{
|
||||
Currency, Get, ExistenceRequirement::{KeepAlive},
|
||||
ReservableCurrency
|
||||
};
|
||||
|
||||
use sp_runtime::{ Percent, RuntimeDebug, traits::{
|
||||
Zero, AccountIdConversion, Hash, BadOrigin
|
||||
}};
|
||||
|
||||
use frame_support::traits::{Contains, ContainsLengthBound};
|
||||
use codec::{Encode, Decode};
|
||||
use frame_system::{self as system, ensure_signed};
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
pub type BalanceOf<T> = pallet_treasury::BalanceOf<T>;
|
||||
pub type NegativeImbalanceOf<T> = pallet_treasury::NegativeImbalanceOf<T>;
|
||||
|
||||
pub trait Config: frame_system::Config + pallet_treasury::Config {
|
||||
/// Maximum acceptable reason length.
|
||||
type MaximumReasonLength: Get<u32>;
|
||||
|
||||
/// The amount held on deposit per byte within the tip report reason or bounty description.
|
||||
type DataDepositPerByte: Get<BalanceOf<Self>>;
|
||||
|
||||
/// Origin from which tippers must come.
|
||||
///
|
||||
/// `ContainsLengthBound::max_len` must be cost free (i.e. no storage read or heavy operation).
|
||||
type Tippers: Contains<Self::AccountId> + ContainsLengthBound;
|
||||
|
||||
/// The period for which a tip remains open after is has achieved threshold tippers.
|
||||
type TipCountdown: Get<Self::BlockNumber>;
|
||||
|
||||
/// The percent of the final tip which goes to the original reporter of the tip.
|
||||
type TipFindersFee: Get<Percent>;
|
||||
|
||||
/// The amount held on deposit for placing a tip report.
|
||||
type TipReportDepositBase: Get<BalanceOf<Self>>;
|
||||
|
||||
/// The overarching event type.
|
||||
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
|
||||
|
||||
/// Weight information for extrinsics in this pallet.
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// An open tipping "motion". Retains all details of a tip including information on the finder
|
||||
/// and the members who have voted.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct OpenTip<
|
||||
AccountId: Parameter,
|
||||
Balance: Parameter,
|
||||
BlockNumber: Parameter,
|
||||
Hash: Parameter,
|
||||
> {
|
||||
/// The hash of the reason for the tip. The reason should be a human-readable UTF-8 encoded string. A URL would be
|
||||
/// sensible.
|
||||
reason: Hash,
|
||||
/// The account to be tipped.
|
||||
who: AccountId,
|
||||
/// The account who began this tip.
|
||||
finder: AccountId,
|
||||
/// The amount held on deposit for this tip.
|
||||
deposit: Balance,
|
||||
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
|
||||
/// scheduled.
|
||||
closes: Option<BlockNumber>,
|
||||
/// The members who have voted for this tip. Sorted by AccountId.
|
||||
tips: Vec<(AccountId, Balance)>,
|
||||
/// Whether this tip should result in the finder taking a fee.
|
||||
finders_fee: bool,
|
||||
}
|
||||
|
||||
// Note :: For backward compatability reasons,
|
||||
// pallet-tips uses Treasury for storage.
|
||||
// This is temporary solution, soon will get replaced with
|
||||
// Own storage identifier.
|
||||
decl_storage! {
|
||||
trait Store for Module<T: Config> as Treasury {
|
||||
|
||||
/// TipsMap that are not yet completed. Keyed by the hash of `(reason, who)` from the value.
|
||||
/// This has the insecure enumerable hash function since the key itself is already
|
||||
/// guaranteed to be a secure hash.
|
||||
pub Tips get(fn tips):
|
||||
map hasher(twox_64_concat) T::Hash
|
||||
=> Option<OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>>;
|
||||
|
||||
/// Simple preimage lookup from the reason's hash to the original data. Again, has an
|
||||
/// insecure enumerable hash since the key is guaranteed to be the result of a secure hash.
|
||||
pub Reasons get(fn reasons): map hasher(identity) T::Hash => Option<Vec<u8>>;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
pub enum Event<T>
|
||||
where
|
||||
Balance = BalanceOf<T>,
|
||||
<T as frame_system::Config>::AccountId,
|
||||
<T as frame_system::Config>::Hash,
|
||||
{
|
||||
/// A new tip suggestion has been opened. \[tip_hash\]
|
||||
NewTip(Hash),
|
||||
/// A tip suggestion has reached threshold and is closing. \[tip_hash\]
|
||||
TipClosing(Hash),
|
||||
/// A tip suggestion has been closed. \[tip_hash, who, payout\]
|
||||
TipClosed(Hash, AccountId, Balance),
|
||||
/// A tip suggestion has been retracted. \[tip_hash\]
|
||||
TipRetracted(Hash),
|
||||
}
|
||||
);
|
||||
|
||||
decl_error! {
|
||||
/// Error for the tips module.
|
||||
pub enum Error for Module<T: Config> {
|
||||
/// The reason given is just too big.
|
||||
ReasonTooBig,
|
||||
/// The tip was already found/started.
|
||||
AlreadyKnown,
|
||||
/// The tip hash is unknown.
|
||||
UnknownTip,
|
||||
/// The account attempting to retract the tip is not the finder of the tip.
|
||||
NotFinder,
|
||||
/// The tip cannot be claimed/closed because there are not enough tippers yet.
|
||||
StillOpen,
|
||||
/// The tip cannot be claimed/closed because it's still in the countdown period.
|
||||
Premature,
|
||||
}
|
||||
}
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Config>
|
||||
for enum Call
|
||||
where origin: T::Origin
|
||||
{
|
||||
|
||||
/// The period for which a tip remains open after is has achieved threshold tippers.
|
||||
const TipCountdown: T::BlockNumber = T::TipCountdown::get();
|
||||
|
||||
/// The amount of the final tip which goes to the original reporter of the tip.
|
||||
const TipFindersFee: Percent = T::TipFindersFee::get();
|
||||
|
||||
/// The amount held on deposit for placing a tip report.
|
||||
const TipReportDepositBase: BalanceOf<T> = T::TipReportDepositBase::get();
|
||||
|
||||
/// The amount held on deposit per byte within the tip report reason.
|
||||
const DataDepositPerByte: BalanceOf<T> = T::DataDepositPerByte::get();
|
||||
|
||||
/// Maximum acceptable reason length.
|
||||
const MaximumReasonLength: u32 = T::MaximumReasonLength::get();
|
||||
|
||||
type Error = Error<T>;
|
||||
|
||||
fn deposit_event() = default;
|
||||
|
||||
/// Report something `reason` that deserves a tip and claim any eventual the finder's fee.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
///
|
||||
/// Payment: `TipReportDepositBase` will be reserved from the origin account, as well as
|
||||
/// `DataDepositPerByte` for each byte in `reason`.
|
||||
///
|
||||
/// - `reason`: The reason for, or the thing that deserves, the tip; generally this will be
|
||||
/// a UTF-8-encoded URL.
|
||||
/// - `who`: The account which should be credited for the tip.
|
||||
///
|
||||
/// Emits `NewTip` if successful.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(R)` where `R` length of `reason`.
|
||||
/// - encoding and hashing of 'reason'
|
||||
/// - DbReads: `Reasons`, `Tips`
|
||||
/// - DbWrites: `Reasons`, `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::report_awesome(reason.len() as u32)]
|
||||
fn report_awesome(origin, reason: Vec<u8>, who: T::AccountId) {
|
||||
let finder = ensure_signed(origin)?;
|
||||
|
||||
ensure!(reason.len() <= T::MaximumReasonLength::get() as usize, Error::<T>::ReasonTooBig);
|
||||
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
ensure!(!Reasons::<T>::contains_key(&reason_hash), Error::<T>::AlreadyKnown);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
|
||||
ensure!(!Tips::<T>::contains_key(&hash), Error::<T>::AlreadyKnown);
|
||||
|
||||
let deposit = T::TipReportDepositBase::get()
|
||||
+ T::DataDepositPerByte::get() * (reason.len() as u32).into();
|
||||
T::Currency::reserve(&finder, deposit)?;
|
||||
|
||||
Reasons::<T>::insert(&reason_hash, &reason);
|
||||
let tip = OpenTip {
|
||||
reason: reason_hash,
|
||||
who,
|
||||
finder,
|
||||
deposit,
|
||||
closes: None,
|
||||
tips: vec![],
|
||||
finders_fee: true
|
||||
};
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
Self::deposit_event(RawEvent::NewTip(hash));
|
||||
}
|
||||
|
||||
/// Retract a prior tip-report from `report_awesome`, and cancel the process of tipping.
|
||||
///
|
||||
/// If successful, the original deposit will be unreserved.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_ and the tip identified by `hash`
|
||||
/// must have been reported by the signing account through `report_awesome` (and not
|
||||
/// through `tip_new`).
|
||||
///
|
||||
/// - `hash`: The identity of the open tip for which a tip value is declared. This is formed
|
||||
/// as the hash of the tuple of the original tip `reason` and the beneficiary account ID.
|
||||
///
|
||||
/// Emits `TipRetracted` if successful.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(1)`
|
||||
/// - Depends on the length of `T::Hash` which is fixed.
|
||||
/// - DbReads: `Tips`, `origin account`
|
||||
/// - DbWrites: `Reasons`, `Tips`, `origin account`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::retract_tip()]
|
||||
fn retract_tip(origin, hash: T::Hash) {
|
||||
let who = ensure_signed(origin)?;
|
||||
let tip = Tips::<T>::get(&hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
ensure!(tip.finder == who, Error::<T>::NotFinder);
|
||||
|
||||
Reasons::<T>::remove(&tip.reason);
|
||||
Tips::<T>::remove(&hash);
|
||||
if !tip.deposit.is_zero() {
|
||||
let _ = T::Currency::unreserve(&who, tip.deposit);
|
||||
}
|
||||
Self::deposit_event(RawEvent::TipRetracted(hash));
|
||||
}
|
||||
|
||||
/// Give a tip for something new; no finder's fee will be taken.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_ and the signing account must be a
|
||||
/// member of the `Tippers` set.
|
||||
///
|
||||
/// - `reason`: The reason for, or the thing that deserves, the tip; generally this will be
|
||||
/// a UTF-8-encoded URL.
|
||||
/// - `who`: The account which should be credited for the tip.
|
||||
/// - `tip_value`: The amount of tip that the sender would like to give. The median tip
|
||||
/// value of active tippers will be given to the `who`.
|
||||
///
|
||||
/// Emits `NewTip` if successful.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(R + T)` where `R` length of `reason`, `T` is the number of tippers.
|
||||
/// - `O(T)`: decoding `Tipper` vec of length `T`
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// - `O(R)`: hashing and encoding of reason of length `R`
|
||||
/// - DbReads: `Tippers`, `Reasons`
|
||||
/// - DbWrites: `Reasons`, `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::tip_new(reason.len() as u32, T::Tippers::max_len() as u32)]
|
||||
fn tip_new(origin, reason: Vec<u8>, who: T::AccountId, #[compact] tip_value: BalanceOf<T>) {
|
||||
let tipper = ensure_signed(origin)?;
|
||||
ensure!(T::Tippers::contains(&tipper), BadOrigin);
|
||||
let reason_hash = T::Hashing::hash(&reason[..]);
|
||||
ensure!(!Reasons::<T>::contains_key(&reason_hash), Error::<T>::AlreadyKnown);
|
||||
let hash = T::Hashing::hash_of(&(&reason_hash, &who));
|
||||
|
||||
Reasons::<T>::insert(&reason_hash, &reason);
|
||||
Self::deposit_event(RawEvent::NewTip(hash.clone()));
|
||||
let tips = vec![(tipper.clone(), tip_value)];
|
||||
let tip = OpenTip {
|
||||
reason: reason_hash,
|
||||
who,
|
||||
finder: tipper,
|
||||
deposit: Zero::zero(),
|
||||
closes: None,
|
||||
tips,
|
||||
finders_fee: false,
|
||||
};
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
}
|
||||
|
||||
/// Declare a tip value for an already-open tip.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_ and the signing account must be a
|
||||
/// member of the `Tippers` set.
|
||||
///
|
||||
/// - `hash`: The identity of the open tip for which a tip value is declared. This is formed
|
||||
/// as the hash of the tuple of the hash of the original tip `reason` and the beneficiary
|
||||
/// account ID.
|
||||
/// - `tip_value`: The amount of tip that the sender would like to give. The median tip
|
||||
/// value of active tippers will be given to the `who`.
|
||||
///
|
||||
/// Emits `TipClosing` if the threshold of tippers has been reached and the countdown period
|
||||
/// has started.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers.
|
||||
/// decoding `Tipper` vec of length `T`, insert tip and check closing,
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
///
|
||||
/// Actually weight could be lower as it depends on how many tips are in `OpenTip` but it
|
||||
/// is weighted as if almost full i.e of length `T-1`.
|
||||
/// - DbReads: `Tippers`, `Tips`
|
||||
/// - DbWrites: `Tips`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::tip(T::Tippers::max_len() as u32)]
|
||||
fn tip(origin, hash: T::Hash, #[compact] tip_value: BalanceOf<T>) {
|
||||
let tipper = ensure_signed(origin)?;
|
||||
ensure!(T::Tippers::contains(&tipper), BadOrigin);
|
||||
|
||||
let mut tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
if Self::insert_tip_and_check_closing(&mut tip, tipper, tip_value) {
|
||||
Self::deposit_event(RawEvent::TipClosing(hash.clone()));
|
||||
}
|
||||
Tips::<T>::insert(&hash, tip);
|
||||
}
|
||||
|
||||
/// Close and payout a tip.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_.
|
||||
///
|
||||
/// The tip identified by `hash` must have finished its countdown period.
|
||||
///
|
||||
/// - `hash`: The identity of the open tip for which a tip value is declared. This is formed
|
||||
/// as the hash of the tuple of the original tip `reason` and the beneficiary account ID.
|
||||
///
|
||||
/// # <weight>
|
||||
/// - Complexity: `O(T)` where `T` is the number of tippers.
|
||||
/// decoding `Tipper` vec of length `T`.
|
||||
/// `T` is charged as upper bound given by `ContainsLengthBound`.
|
||||
/// The actual cost depends on the implementation of `T::Tippers`.
|
||||
/// - DbReads: `Tips`, `Tippers`, `tip finder`
|
||||
/// - DbWrites: `Reasons`, `Tips`, `Tippers`, `tip finder`
|
||||
/// # </weight>
|
||||
#[weight = <T as Config>::WeightInfo::close_tip(T::Tippers::max_len() as u32)]
|
||||
fn close_tip(origin, hash: T::Hash) {
|
||||
ensure_signed(origin)?;
|
||||
|
||||
let tip = Tips::<T>::get(hash).ok_or(Error::<T>::UnknownTip)?;
|
||||
let n = tip.closes.as_ref().ok_or(Error::<T>::StillOpen)?;
|
||||
ensure!(system::Module::<T>::block_number() >= *n, Error::<T>::Premature);
|
||||
// closed.
|
||||
Reasons::<T>::remove(&tip.reason);
|
||||
Tips::<T>::remove(hash);
|
||||
Self::payout_tip(hash, tip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Module<T> {
|
||||
// Add public immutables and private mutables.
|
||||
|
||||
/// The account ID of the treasury pot.
|
||||
///
|
||||
/// This actually does computation. If you need to keep using it, then make sure you cache the
|
||||
/// value and only call this once.
|
||||
pub fn account_id() -> T::AccountId {
|
||||
T::ModuleId::get().into_account()
|
||||
}
|
||||
|
||||
/// Given a mutable reference to an `OpenTip`, insert the tip into it and check whether it
|
||||
/// closes, if so, then deposit the relevant event and set closing accordingly.
|
||||
///
|
||||
/// `O(T)` and one storage access.
|
||||
fn insert_tip_and_check_closing(
|
||||
tip: &mut OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
|
||||
tipper: T::AccountId,
|
||||
tip_value: BalanceOf<T>,
|
||||
) -> bool {
|
||||
match tip.tips.binary_search_by_key(&&tipper, |x| &x.0) {
|
||||
Ok(pos) => tip.tips[pos] = (tipper, tip_value),
|
||||
Err(pos) => tip.tips.insert(pos, (tipper, tip_value)),
|
||||
}
|
||||
Self::retain_active_tips(&mut tip.tips);
|
||||
let threshold = (T::Tippers::count() + 1) / 2;
|
||||
if tip.tips.len() >= threshold && tip.closes.is_none() {
|
||||
tip.closes = Some(system::Module::<T>::block_number() + T::TipCountdown::get());
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove any non-members of `Tippers` from a `tips` vector. `O(T)`.
|
||||
fn retain_active_tips(tips: &mut Vec<(T::AccountId, BalanceOf<T>)>) {
|
||||
let members = T::Tippers::sorted_members();
|
||||
let mut members_iter = members.iter();
|
||||
let mut member = members_iter.next();
|
||||
tips.retain(|(ref a, _)| loop {
|
||||
match member {
|
||||
None => break false,
|
||||
Some(m) if m > a => break false,
|
||||
Some(m) => {
|
||||
member = members_iter.next();
|
||||
if m < a {
|
||||
continue
|
||||
} else {
|
||||
break true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Execute the payout of a tip.
|
||||
///
|
||||
/// Up to three balance operations.
|
||||
/// Plus `O(T)` (`T` is Tippers length).
|
||||
fn payout_tip(hash: T::Hash, tip: OpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>) {
|
||||
let mut tips = tip.tips;
|
||||
Self::retain_active_tips(&mut tips);
|
||||
tips.sort_by_key(|i| i.1);
|
||||
|
||||
let treasury = Self::account_id();
|
||||
let max_payout = pallet_treasury::Module::<T>::pot();
|
||||
|
||||
let mut payout = tips[tips.len() / 2].1.min(max_payout);
|
||||
if !tip.deposit.is_zero() {
|
||||
let _ = T::Currency::unreserve(&tip.finder, tip.deposit);
|
||||
}
|
||||
|
||||
if tip.finders_fee && tip.finder != tip.who {
|
||||
// pay out the finder's fee.
|
||||
let finders_fee = T::TipFindersFee::get() * payout;
|
||||
payout -= finders_fee;
|
||||
// this should go through given we checked it's at most the free balance, but still
|
||||
// we only make a best-effort.
|
||||
let _ = T::Currency::transfer(&treasury, &tip.finder, finders_fee, KeepAlive);
|
||||
}
|
||||
|
||||
// same as above: best-effort only.
|
||||
let _ = T::Currency::transfer(&treasury, &tip.who, payout, KeepAlive);
|
||||
Self::deposit_event(RawEvent::TipClosed(hash, tip.who, payout));
|
||||
}
|
||||
|
||||
pub fn migrate_retract_tip_for_tip_new() {
|
||||
/// An open tipping "motion". Retains all details of a tip including information on the finder
|
||||
/// and the members who have voted.
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct OldOpenTip<
|
||||
AccountId: Parameter,
|
||||
Balance: Parameter,
|
||||
BlockNumber: Parameter,
|
||||
Hash: Parameter,
|
||||
> {
|
||||
/// The hash of the reason for the tip. The reason should be a human-readable UTF-8 encoded string. A URL would be
|
||||
/// sensible.
|
||||
reason: Hash,
|
||||
/// The account to be tipped.
|
||||
who: AccountId,
|
||||
/// The account who began this tip and the amount held on deposit.
|
||||
finder: Option<(AccountId, Balance)>,
|
||||
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
|
||||
/// scheduled.
|
||||
closes: Option<BlockNumber>,
|
||||
/// The members who have voted for this tip. Sorted by AccountId.
|
||||
tips: Vec<(AccountId, Balance)>,
|
||||
}
|
||||
|
||||
use frame_support::{Twox64Concat, migration::StorageKeyIterator};
|
||||
|
||||
if_std! {
|
||||
println!("Inside migrate_retract_tip_for_tip_new()!");
|
||||
}
|
||||
|
||||
for (hash, old_tip) in StorageKeyIterator::<
|
||||
T::Hash,
|
||||
OldOpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
|
||||
Twox64Concat,
|
||||
>::new(b"Treasury", b"Tips").drain()
|
||||
{
|
||||
|
||||
if_std! {
|
||||
println!("Inside loop migrate_retract_tip_for_tip_new()!");
|
||||
}
|
||||
|
||||
let (finder, deposit, finders_fee) = match old_tip.finder {
|
||||
Some((finder, deposit)) => {
|
||||
if_std! {
|
||||
// This code is only being compiled and executed when the `std` feature is enabled.
|
||||
println!("OK case!");
|
||||
println!("value is: {:#?},{:#?}", finder, deposit);
|
||||
}
|
||||
(finder, deposit, true)
|
||||
},
|
||||
None => {
|
||||
if_std! {
|
||||
// This code is only being compiled and executed when the `std` feature is enabled.
|
||||
println!("None case!");
|
||||
// println!("value is: {:#?},{:#?}", T::AccountId::default(), Zero::zero());
|
||||
}
|
||||
(T::AccountId::default(), Zero::zero(), false)
|
||||
},
|
||||
};
|
||||
let new_tip = OpenTip {
|
||||
reason: old_tip.reason,
|
||||
who: old_tip.who,
|
||||
finder,
|
||||
deposit,
|
||||
closes: old_tip.closes,
|
||||
tips: old_tip.tips,
|
||||
finders_fee
|
||||
};
|
||||
Tips::<T>::insert(hash, new_tip)
|
||||
}
|
||||
|
||||
if_std! {
|
||||
println!("Exit migrate_retract_tip_for_tip_new()!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Treasury pallet tests.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use super::*;
|
||||
use std::cell::RefCell;
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, impl_outer_origin, parameter_types, weights::Weight,
|
||||
impl_outer_event, traits::{Contains}
|
||||
};
|
||||
use sp_runtime::{Permill};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
Perbill, ModuleId,
|
||||
testing::Header,
|
||||
traits::{BlakeTwo256, IdentityLookup, BadOrigin},
|
||||
};
|
||||
|
||||
impl_outer_origin! {
|
||||
pub enum Origin for Test where system = frame_system {}
|
||||
}
|
||||
|
||||
mod tips {
|
||||
// Re-export needed for `impl_outer_event!`.
|
||||
pub use crate::*;
|
||||
}
|
||||
|
||||
impl_outer_event! {
|
||||
pub enum Event for Test {
|
||||
system<T>,
|
||||
pallet_balances<T>,
|
||||
pallet_treasury<T>,
|
||||
tips<T>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Test;
|
||||
parameter_types! {
|
||||
pub const BlockHashCount: u64 = 250;
|
||||
pub const MaximumBlockWeight: Weight = 1024;
|
||||
pub const MaximumBlockLength: u32 = 2 * 1024;
|
||||
pub const AvailableBlockRatio: Perbill = Perbill::one();
|
||||
}
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = ();
|
||||
type BlockWeights = ();
|
||||
type BlockLength = ();
|
||||
type DbWeight = ();
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Call = ();
|
||||
type Hash = H256;
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = Event;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type Version = ();
|
||||
type PalletInfo = ();
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
type SystemWeightInfo = ();
|
||||
}
|
||||
parameter_types! {
|
||||
pub const ExistentialDeposit: u64 = 1;
|
||||
}
|
||||
impl pallet_balances::Config for Test {
|
||||
type MaxLocks = ();
|
||||
type Balance = u64;
|
||||
type Event = Event;
|
||||
type DustRemoval = ();
|
||||
type ExistentialDeposit = ExistentialDeposit;
|
||||
type AccountStore = System;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
thread_local! {
|
||||
static TEN_TO_FOURTEEN: RefCell<Vec<u128>> = RefCell::new(vec![10,11,12,13,14]);
|
||||
}
|
||||
pub struct TenToFourteen;
|
||||
impl Contains<u128> for TenToFourteen {
|
||||
fn sorted_members() -> Vec<u128> {
|
||||
TEN_TO_FOURTEEN.with(|v| {
|
||||
v.borrow().clone()
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
fn add(new: &u128) {
|
||||
TEN_TO_FOURTEEN.with(|v| {
|
||||
let mut members = v.borrow_mut();
|
||||
members.push(*new);
|
||||
members.sort();
|
||||
})
|
||||
}
|
||||
}
|
||||
impl ContainsLengthBound for TenToFourteen {
|
||||
fn max_len() -> usize {
|
||||
TEN_TO_FOURTEEN.with(|v| v.borrow().len())
|
||||
}
|
||||
fn min_len() -> usize { 0 }
|
||||
}
|
||||
parameter_types! {
|
||||
pub const ProposalBond: Permill = Permill::from_percent(5);
|
||||
pub const ProposalBondMinimum: u64 = 1;
|
||||
pub const SpendPeriod: u64 = 2;
|
||||
pub const Burn: Permill = Permill::from_percent(50);
|
||||
pub const DataDepositPerByte: u64 = 1;
|
||||
pub const TreasuryModuleId: ModuleId = ModuleId(*b"py/trsry");
|
||||
pub const MaximumReasonLength: u32 = 16384;
|
||||
}
|
||||
impl pallet_treasury::Config for Test {
|
||||
type ModuleId = TreasuryModuleId;
|
||||
type Currency = pallet_balances::Module<Test>;
|
||||
type ApproveOrigin = frame_system::EnsureRoot<u128>;
|
||||
type RejectOrigin = frame_system::EnsureRoot<u128>;
|
||||
type Event = Event;
|
||||
type OnSlash = ();
|
||||
type ProposalBond = ProposalBond;
|
||||
type ProposalBondMinimum = ProposalBondMinimum;
|
||||
type SpendPeriod = SpendPeriod;
|
||||
type Burn = Burn;
|
||||
type BurnDestination = (); // Just gets burned.
|
||||
type WeightInfo = ();
|
||||
type SpendFunds = ();
|
||||
}
|
||||
parameter_types! {
|
||||
pub const TipCountdown: u64 = 1;
|
||||
pub const TipFindersFee: Percent = Percent::from_percent(20);
|
||||
pub const TipReportDepositBase: u64 = 1;
|
||||
}
|
||||
impl Config for Test {
|
||||
type MaximumReasonLength = MaximumReasonLength;
|
||||
type Tippers = TenToFourteen;
|
||||
type TipCountdown = TipCountdown;
|
||||
type TipFindersFee = TipFindersFee;
|
||||
type TipReportDepositBase = TipReportDepositBase;
|
||||
type DataDepositPerByte = DataDepositPerByte;
|
||||
type Event = Event;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
type System = frame_system::Module<Test>;
|
||||
type Balances = pallet_balances::Module<Test>;
|
||||
type Treasury = pallet_treasury::Module<Test>;
|
||||
type TipsModTestInst = Module<Test>;
|
||||
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
pallet_balances::GenesisConfig::<Test>{
|
||||
// Total issuance will be 200 with treasury account initialized at ED.
|
||||
balances: vec![(0, 100), (1, 98), (2, 1)],
|
||||
}.assimilate_storage(&mut t).unwrap();
|
||||
pallet_treasury::GenesisConfig::default().assimilate_storage::<Test, _>(&mut t).unwrap();
|
||||
t.into()
|
||||
}
|
||||
|
||||
fn last_event() -> RawEvent<u64, u128, H256> {
|
||||
System::events().into_iter().map(|r| r.event)
|
||||
.filter_map(|e| {
|
||||
if let Event::tips(inner) = e { Some(inner) } else { None }
|
||||
})
|
||||
.last()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_config_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(Treasury::pot(), 0);
|
||||
assert_eq!(Treasury::proposal_count(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
fn tip_hash() -> H256 {
|
||||
BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 3u128))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tip_new_cannot_be_used_twice() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
assert_noop!(
|
||||
TipsModTestInst::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10),
|
||||
Error::<Test>::AlreadyKnown
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_awesome_and_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
assert_eq!(Balances::reserved_balance(0), 12);
|
||||
assert_eq!(Balances::free_balance(0), 88);
|
||||
|
||||
// other reports don't count.
|
||||
assert_noop!(
|
||||
TipsModTestInst::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3),
|
||||
Error::<Test>::AlreadyKnown
|
||||
);
|
||||
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(TipsModTestInst::tip(Origin::signed(9), h.clone(), 10), BadOrigin);
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(100), h.into()));
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
assert_eq!(Balances::free_balance(0), 102);
|
||||
assert_eq!(Balances::free_balance(3), 8);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn report_awesome_from_beneficiary_and_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0));
|
||||
assert_eq!(Balances::reserved_balance(0), 12);
|
||||
assert_eq!(Balances::free_balance(0), 88);
|
||||
let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u128));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(100), h.into()));
|
||||
assert_eq!(Balances::reserved_balance(0), 0);
|
||||
assert_eq!(Balances::free_balance(0), 110);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn close_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
System::set_block_number(1);
|
||||
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_eq!(Treasury::pot(), 100);
|
||||
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
|
||||
let h = tip_hash();
|
||||
|
||||
assert_eq!(last_event(), RawEvent::NewTip(h));
|
||||
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::signed(0), h.into()), Error::<Test>::StillOpen);
|
||||
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
|
||||
assert_eq!(last_event(), RawEvent::TipClosing(h));
|
||||
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::signed(0), h.into()), Error::<Test>::Premature);
|
||||
|
||||
System::set_block_number(2);
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::none(), h.into()), BadOrigin);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
|
||||
assert_eq!(last_event(), RawEvent::TipClosed(h, 3, 10));
|
||||
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::signed(100), h.into()), Error::<Test>::UnknownTip);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retract_tip_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// with report awesome
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(TipsModTestInst::retract_tip(Origin::signed(10), h.clone()), Error::<Test>::NotFinder);
|
||||
assert_ok!(TipsModTestInst::retract_tip(Origin::signed(0), h.clone()));
|
||||
System::set_block_number(2);
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::signed(0), h.into()), Error::<Test>::UnknownTip);
|
||||
|
||||
// with tip new
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10));
|
||||
assert_noop!(TipsModTestInst::retract_tip(Origin::signed(0), h.clone()), Error::<Test>::NotFinder);
|
||||
assert_ok!(TipsModTestInst::retract_tip(Origin::signed(10), h.clone()));
|
||||
System::set_block_number(2);
|
||||
assert_noop!(TipsModTestInst::close_tip(Origin::signed(10), h.into()), Error::<Test>::UnknownTip);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tip_median_calculation_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 1000000));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tip_changing_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
Balances::make_free_balance_be(&Treasury::account_id(), 101);
|
||||
assert_ok!(TipsModTestInst::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000));
|
||||
let h = tip_hash();
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 10000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 10000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(13), h.clone(), 0));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(14), h.clone(), 0));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(12), h.clone(), 1000));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(11), h.clone(), 100));
|
||||
assert_ok!(TipsModTestInst::tip(Origin::signed(10), h.clone(), 10));
|
||||
System::set_block_number(2);
|
||||
assert_ok!(TipsModTestInst::close_tip(Origin::signed(0), h.into()));
|
||||
assert_eq!(Balances::free_balance(3), 10);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_last_reward_migration() {
|
||||
use sp_storage::Storage;
|
||||
|
||||
let mut s = Storage::default();
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct OldOpenTip<
|
||||
AccountId: Parameter,
|
||||
Balance: Parameter,
|
||||
BlockNumber: Parameter,
|
||||
Hash: Parameter,
|
||||
> {
|
||||
/// The hash of the reason for the tip. The reason should be a human-readable UTF-8 encoded string. A URL would be
|
||||
/// sensible.
|
||||
reason: Hash,
|
||||
/// The account to be tipped.
|
||||
who: AccountId,
|
||||
/// The account who began this tip and the amount held on deposit.
|
||||
finder: Option<(AccountId, Balance)>,
|
||||
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
|
||||
/// scheduled.
|
||||
closes: Option<BlockNumber>,
|
||||
/// The members who have voted for this tip. Sorted by AccountId.
|
||||
tips: Vec<(AccountId, Balance)>,
|
||||
}
|
||||
|
||||
let reason1 = BlakeTwo256::hash(b"reason1");
|
||||
let hash1 = BlakeTwo256::hash_of(&(reason1, 10u64));
|
||||
|
||||
let old_tip_finder = OldOpenTip::<u128, u64, u64, H256> {
|
||||
reason: reason1,
|
||||
who: 10,
|
||||
finder: Some((20, 30)),
|
||||
closes: Some(13),
|
||||
tips: vec![(40, 50), (60, 70)]
|
||||
};
|
||||
|
||||
let reason2 = BlakeTwo256::hash(b"reason2");
|
||||
let hash2 = BlakeTwo256::hash_of(&(reason2, 20u64));
|
||||
|
||||
let old_tip_no_finder = OldOpenTip::<u128, u64, u64, H256> {
|
||||
reason: reason2,
|
||||
who: 20,
|
||||
finder: None,
|
||||
closes: Some(13),
|
||||
tips: vec![(40, 50), (60, 70)]
|
||||
};
|
||||
|
||||
let data = vec![
|
||||
(
|
||||
Tips::<Test>::hashed_key_for(hash1),
|
||||
old_tip_finder.encode().to_vec()
|
||||
),
|
||||
(
|
||||
Tips::<Test>::hashed_key_for(hash2),
|
||||
old_tip_no_finder.encode().to_vec()
|
||||
),
|
||||
];
|
||||
|
||||
s.top = data.into_iter().collect();
|
||||
|
||||
println!("Executing the test!");
|
||||
|
||||
sp_io::TestExternalities::new(s).execute_with(|| {
|
||||
|
||||
println!("Calling migrate_retract_tip_for_tip_new()!");
|
||||
|
||||
TipsModTestInst::migrate_retract_tip_for_tip_new();
|
||||
|
||||
// Test w/ finder
|
||||
assert_eq!(
|
||||
Tips::<Test>::get(hash1),
|
||||
Some(OpenTip {
|
||||
reason: reason1,
|
||||
who: 10,
|
||||
finder: 20,
|
||||
deposit: 30,
|
||||
closes: Some(13),
|
||||
tips: vec![(40, 50), (60, 70)],
|
||||
finders_fee: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Test w/o finder
|
||||
assert_eq!(
|
||||
Tips::<Test>::get(hash2),
|
||||
Some(OpenTip {
|
||||
reason: reason2,
|
||||
who: 20,
|
||||
finder: Default::default(),
|
||||
deposit: 0,
|
||||
closes: Some(13),
|
||||
tips: vec![(40, 50), (60, 70)],
|
||||
finders_fee: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_funding_works() {
|
||||
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
|
||||
let initial_funding = 100;
|
||||
pallet_balances::GenesisConfig::<Test>{
|
||||
// Total issuance will be 200 with treasury account initialized with 100.
|
||||
balances: vec![(0, 100), (Treasury::account_id(), initial_funding)],
|
||||
}.assimilate_storage(&mut t).unwrap();
|
||||
pallet_treasury::GenesisConfig::default().assimilate_storage::<Test, _>(&mut t).unwrap();
|
||||
let mut t: sp_io::TestExternalities = t.into();
|
||||
|
||||
t.execute_with(|| {
|
||||
assert_eq!(Balances::free_balance(Treasury::account_id()), initial_funding);
|
||||
assert_eq!(Treasury::pot(), initial_funding - Balances::minimum_balance());
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for pallet_tips
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0
|
||||
//! DATE: 2020-12-16, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: []
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// ./target/release/substrate
|
||||
// benchmark
|
||||
// --chain=dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=pallet_tips
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --output=./frame/tips/src/weights.rs
|
||||
// --template=./.maintain/frame-weight-template.hbs
|
||||
|
||||
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_tips.
|
||||
pub trait WeightInfo {
|
||||
fn report_awesome(r: u32, ) -> Weight;
|
||||
fn retract_tip() -> Weight;
|
||||
fn tip_new(r: u32, t: u32, ) -> Weight;
|
||||
fn tip(t: u32, ) -> Weight;
|
||||
fn close_tip(t: u32, ) -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for pallet_tips using the Substrate node and recommended hardware.
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
fn report_awesome(r: u32, ) -> Weight {
|
||||
(74_814_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((2_000 as Weight).saturating_mul(r as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn retract_tip() -> Weight {
|
||||
(62_962_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn tip_new(r: u32, t: u32, ) -> Weight {
|
||||
(48_132_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((2_000 as Weight).saturating_mul(r as Weight))
|
||||
// Standard Error: 0
|
||||
.saturating_add((155_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn tip(t: u32, ) -> Weight {
|
||||
(36_168_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((695_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn close_tip(t: u32, ) -> Weight {
|
||||
(119_313_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((372_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn report_awesome(r: u32, ) -> Weight {
|
||||
(74_814_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((2_000 as Weight).saturating_mul(r as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn retract_tip() -> Weight {
|
||||
(62_962_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn tip_new(r: u32, t: u32, ) -> Weight {
|
||||
(48_132_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((2_000 as Weight).saturating_mul(r as Weight))
|
||||
// Standard Error: 0
|
||||
.saturating_add((155_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn tip(t: u32, ) -> Weight {
|
||||
(36_168_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((695_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn close_tip(t: u32, ) -> Weight {
|
||||
(119_313_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((372_000 as Weight).saturating_mul(t as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user