Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit a273b48

Browse files
authored
Allow retract_tip on tip_new (#6511)
* Allow `retract_tip` on `tip_new` * initial migration code * test migration * make pub * bump spec
1 parent 99ee2d7 commit a273b48

File tree

5 files changed

+194
-15
lines changed

5 files changed

+194
-15
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/node/runtime/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
9797
// and set impl_version to 0. If only runtime
9898
// implementation changes and behavior does not, then leave spec_version as
9999
// is and increment impl_version.
100-
spec_version: 254,
101-
impl_version: 1,
100+
spec_version: 255,
101+
impl_version: 0,
102102
apis: RUNTIME_API_VERSIONS,
103103
transaction_version: 1,
104104
};

frame/treasury/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ frame-benchmarking = { version = "2.0.0-rc4", default-features = false, path = "
2525
[dev-dependencies]
2626
sp-io ={ version = "2.0.0-rc4", path = "../../primitives/io" }
2727
sp-core = { version = "2.0.0-rc4", path = "../../primitives/core" }
28+
sp-storage = { version = "2.0.0-rc4", path = "../../primitives/storage" }
2829

2930
[features]
3031
default = ["std"]

frame/treasury/src/lib.rs

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,17 @@ pub struct OpenTip<
192192
reason: Hash,
193193
/// The account to be tipped.
194194
who: AccountId,
195-
/// The account who began this tip and the amount held on deposit.
196-
finder: Option<(AccountId, Balance)>,
195+
/// The account who began this tip.
196+
finder: AccountId,
197+
/// The amount held on deposit for this tip.
198+
deposit: Balance,
197199
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
198200
/// scheduled.
199201
closes: Option<BlockNumber>,
200202
/// The members who have voted for this tip. Sorted by AccountId.
201203
tips: Vec<(AccountId, Balance)>,
204+
/// Whether this tip should result in the finder taking a fee.
205+
finders_fee: bool,
202206
}
203207

204208
decl_storage! {
@@ -428,8 +432,15 @@ decl_module! {
428432
T::Currency::reserve(&finder, deposit)?;
429433

430434
Reasons::<T>::insert(&reason_hash, &reason);
431-
let finder = Some((finder, deposit));
432-
let tip = OpenTip { reason: reason_hash, who, finder, closes: None, tips: vec![] };
435+
let tip = OpenTip {
436+
reason: reason_hash,
437+
who,
438+
finder,
439+
deposit,
440+
closes: None,
441+
tips: vec![],
442+
finders_fee: true
443+
};
433444
Tips::<T>::insert(&hash, tip);
434445
Self::deposit_event(RawEvent::NewTip(hash));
435446
}
@@ -457,12 +468,13 @@ decl_module! {
457468
fn retract_tip(origin, hash: T::Hash) {
458469
let who = ensure_signed(origin)?;
459470
let tip = Tips::<T>::get(&hash).ok_or(Error::<T>::UnknownTip)?;
460-
let (finder, deposit) = tip.finder.ok_or(Error::<T>::NotFinder)?;
461-
ensure!(finder == who, Error::<T>::NotFinder);
471+
ensure!(tip.finder == who, Error::<T>::NotFinder);
462472

463473
Reasons::<T>::remove(&tip.reason);
464474
Tips::<T>::remove(&hash);
465-
let _ = T::Currency::unreserve(&who, deposit);
475+
if !tip.deposit.is_zero() {
476+
let _ = T::Currency::unreserve(&who, tip.deposit);
477+
}
466478
Self::deposit_event(RawEvent::TipRetracted(hash));
467479
}
468480

@@ -501,8 +513,16 @@ decl_module! {
501513

502514
Reasons::<T>::insert(&reason_hash, &reason);
503515
Self::deposit_event(RawEvent::NewTip(hash.clone()));
504-
let tips = vec![(tipper, tip_value)];
505-
let tip = OpenTip { reason: reason_hash, who, finder: None, closes: None, tips };
516+
let tips = vec![(tipper.clone(), tip_value)];
517+
let tip = OpenTip {
518+
reason: reason_hash,
519+
who,
520+
finder: tipper,
521+
deposit: Zero::zero(),
522+
closes: None,
523+
tips,
524+
finders_fee: false,
525+
};
506526
Tips::<T>::insert(&hash, tip);
507527
}
508528

@@ -667,15 +687,17 @@ impl<T: Trait> Module<T> {
667687
let treasury = Self::account_id();
668688
let max_payout = Self::pot();
669689
let mut payout = tips[tips.len() / 2].1.min(max_payout);
670-
if let Some((finder, deposit)) = tip.finder {
671-
let _ = T::Currency::unreserve(&finder, deposit);
672-
if finder != tip.who {
690+
if !tip.deposit.is_zero() {
691+
let _ = T::Currency::unreserve(&tip.finder, tip.deposit);
692+
}
693+
if tip.finders_fee {
694+
if tip.finder != tip.who {
673695
// pay out the finder's fee.
674696
let finders_fee = T::TipFindersFee::get() * payout;
675697
payout -= finders_fee;
676698
// this should go through given we checked it's at most the free balance, but still
677699
// we only make a best-effort.
678-
let _ = T::Currency::transfer(&treasury, &finder, finders_fee, KeepAlive);
700+
let _ = T::Currency::transfer(&treasury, &tip.finder, finders_fee, KeepAlive);
679701
}
680702
}
681703
// same as above: best-effort only.
@@ -753,6 +775,55 @@ impl<T: Trait> Module<T> {
753775
// Must never be less than 0 but better be safe.
754776
.saturating_sub(T::Currency::minimum_balance())
755777
}
778+
779+
pub fn migrate_retract_tip_for_tip_new() {
780+
/// An open tipping "motion". Retains all details of a tip including information on the finder
781+
/// and the members who have voted.
782+
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
783+
pub struct OldOpenTip<
784+
AccountId: Parameter,
785+
Balance: Parameter,
786+
BlockNumber: Parameter,
787+
Hash: Parameter,
788+
> {
789+
/// The hash of the reason for the tip. The reason should be a human-readable UTF-8 encoded string. A URL would be
790+
/// sensible.
791+
reason: Hash,
792+
/// The account to be tipped.
793+
who: AccountId,
794+
/// The account who began this tip and the amount held on deposit.
795+
finder: Option<(AccountId, Balance)>,
796+
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
797+
/// scheduled.
798+
closes: Option<BlockNumber>,
799+
/// The members who have voted for this tip. Sorted by AccountId.
800+
tips: Vec<(AccountId, Balance)>,
801+
}
802+
803+
use frame_support::{Twox64Concat, migration::StorageKeyIterator};
804+
805+
for (hash, old_tip) in StorageKeyIterator::<
806+
T::Hash,
807+
OldOpenTip<T::AccountId, BalanceOf<T>, T::BlockNumber, T::Hash>,
808+
Twox64Concat,
809+
>::new(b"Treasury", b"Tips").drain()
810+
{
811+
let (finder, deposit, finders_fee) = match old_tip.finder {
812+
Some((finder, deposit)) => (finder, deposit, true),
813+
None => (T::AccountId::default(), Zero::zero(), false),
814+
};
815+
let new_tip = OpenTip {
816+
reason: old_tip.reason,
817+
who: old_tip.who,
818+
finder,
819+
deposit,
820+
closes: old_tip.closes,
821+
tips: old_tip.tips,
822+
finders_fee
823+
};
824+
Tips::<T>::insert(hash, new_tip)
825+
}
826+
}
756827
}
757828

758829
impl<T: Trait> OnUnbalanced<NegativeImbalanceOf<T>> for Module<T> {

frame/treasury/src/tests.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ fn close_tip_works() {
293293
#[test]
294294
fn retract_tip_works() {
295295
new_test_ext().execute_with(|| {
296+
// with report awesome
296297
Balances::make_free_balance_be(&Treasury::account_id(), 101);
297298
assert_ok!(Treasury::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3));
298299
let h = tip_hash();
@@ -303,6 +304,17 @@ fn retract_tip_works() {
303304
assert_ok!(Treasury::retract_tip(Origin::signed(0), h.clone()));
304305
System::set_block_number(2);
305306
assert_noop!(Treasury::close_tip(Origin::signed(0), h.into()), Error::<Test>::UnknownTip);
307+
308+
// with tip new
309+
Balances::make_free_balance_be(&Treasury::account_id(), 101);
310+
assert_ok!(Treasury::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10));
311+
let h = tip_hash();
312+
assert_ok!(Treasury::tip(Origin::signed(11), h.clone(), 10));
313+
assert_ok!(Treasury::tip(Origin::signed(12), h.clone(), 10));
314+
assert_noop!(Treasury::retract_tip(Origin::signed(0), h.clone()), Error::<Test>::NotFinder);
315+
assert_ok!(Treasury::retract_tip(Origin::signed(10), h.clone()));
316+
System::set_block_number(2);
317+
assert_noop!(Treasury::close_tip(Origin::signed(10), h.into()), Error::<Test>::UnknownTip);
306318
});
307319
}
308320

@@ -544,3 +556,97 @@ fn inexistent_account_works() {
544556
assert_eq!(Balances::free_balance(3), 99); // Balance of `3` has changed
545557
});
546558
}
559+
560+
#[test]
561+
fn test_last_reward_migration() {
562+
use sp_storage::Storage;
563+
564+
let mut s = Storage::default();
565+
566+
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
567+
pub struct OldOpenTip<
568+
AccountId: Parameter,
569+
Balance: Parameter,
570+
BlockNumber: Parameter,
571+
Hash: Parameter,
572+
> {
573+
/// The hash of the reason for the tip. The reason should be a human-readable UTF-8 encoded string. A URL would be
574+
/// sensible.
575+
reason: Hash,
576+
/// The account to be tipped.
577+
who: AccountId,
578+
/// The account who began this tip and the amount held on deposit.
579+
finder: Option<(AccountId, Balance)>,
580+
/// The block number at which this tip will close if `Some`. If `None`, then no closing is
581+
/// scheduled.
582+
closes: Option<BlockNumber>,
583+
/// The members who have voted for this tip. Sorted by AccountId.
584+
tips: Vec<(AccountId, Balance)>,
585+
}
586+
587+
let reason1 = BlakeTwo256::hash(b"reason1");
588+
let hash1 = BlakeTwo256::hash_of(&(reason1, 10u64));
589+
590+
let old_tip_finder = OldOpenTip::<u64, u64, u64, H256> {
591+
reason: reason1,
592+
who: 10,
593+
finder: Some((20, 30)),
594+
closes: Some(13),
595+
tips: vec![(40, 50), (60, 70)]
596+
};
597+
598+
let reason2 = BlakeTwo256::hash(b"reason2");
599+
let hash2 = BlakeTwo256::hash_of(&(reason2, 20u64));
600+
601+
let old_tip_no_finder = OldOpenTip::<u64, u64, u64, H256> {
602+
reason: reason2,
603+
who: 20,
604+
finder: None,
605+
closes: Some(13),
606+
tips: vec![(40, 50), (60, 70)]
607+
};
608+
609+
let data = vec![
610+
(
611+
Tips::<Test>::hashed_key_for(hash1),
612+
old_tip_finder.encode().to_vec()
613+
),
614+
(
615+
Tips::<Test>::hashed_key_for(hash2),
616+
old_tip_no_finder.encode().to_vec()
617+
),
618+
];
619+
620+
s.top = data.into_iter().collect();
621+
sp_io::TestExternalities::new(s).execute_with(|| {
622+
Treasury::migrate_retract_tip_for_tip_new();
623+
624+
// Test w/ finder
625+
assert_eq!(
626+
Tips::<Test>::get(hash1),
627+
Some(OpenTip {
628+
reason: reason1,
629+
who: 10,
630+
finder: 20,
631+
deposit: 30,
632+
closes: Some(13),
633+
tips: vec![(40, 50), (60, 70)],
634+
finders_fee: true,
635+
})
636+
);
637+
638+
// Test w/o finder
639+
assert_eq!(
640+
Tips::<Test>::get(hash2),
641+
Some(OpenTip {
642+
reason: reason2,
643+
who: 20,
644+
finder: Default::default(),
645+
deposit: 0,
646+
closes: Some(13),
647+
tips: vec![(40, 50), (60, 70)],
648+
finders_fee: false,
649+
})
650+
);
651+
});
652+
}

0 commit comments

Comments
 (0)