use super::*;
#[test]
fn paired_account_works() {
ExtBuilder::default().build_and_execute(|| {
assert_ok!(Staking::bond(RuntimeOrigin::signed(10), 100, RewardDestination::Account(10)));
assert_eq!(<Bonded<Test>>::get(&10), Some(10));
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Controller(10)), Some(10));
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(10)), Some(10));
assert_eq!(<Bonded<Test>>::get(&42), None);
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Controller(42)), None);
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(42)), None);
assert_ok!(bond_controller_stash(100, 200));
assert_eq!(<Bonded<Test>>::get(&200), Some(100));
assert_eq!(
StakingLedger::<Test>::paired_account(StakingAccount::Controller(100)),
Some(200)
);
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(200)), Some(100));
})
}
#[test]
fn get_ledger_works() {
ExtBuilder::default().build_and_execute(|| {
assert!(StakingLedger::<Test>::get(StakingAccount::Stash(42)).is_err());
assert_eq!(<Bonded<Test>>::get(&11), Some(11));
match StakingLedger::<Test>::get(StakingAccount::Stash(11)) {
Ok(ledger) => {
assert_eq!(ledger.controller(), Some(11));
assert_eq!(ledger.stash, 11);
},
Err(_) => panic!("staking ledger must exist"),
};
assert_ok!(bond_controller_stash(100, 200));
assert_eq!(<Bonded<Test>>::get(&200), Some(100));
match StakingLedger::<Test>::get(StakingAccount::Stash(200)) {
Ok(ledger) => {
assert_eq!(ledger.controller(), Some(100));
assert_eq!(ledger.stash, 200);
},
Err(_) => panic!("staking ledger must exist"),
};
match StakingLedger::<Test>::get(StakingAccount::Controller(100)) {
Ok(ledger) => {
assert_eq!(ledger.controller(), Some(100));
assert_eq!(ledger.stash, 200);
},
Err(_) => panic!("staking ledger must exist"),
};
})
}
#[test]
fn get_ledger_bad_state_fails() {
ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_eq!(Bonded::<Test>::get(444), Some(555));
assert_eq!(Ledger::<Test>::get(555).unwrap().stash, 444);
assert_eq!(Bonded::<Test>::get(333), Some(444));
assert_eq!(StakingLedger::<Test>::paired_account(StakingAccount::Stash(333)), Some(444));
assert_eq!(Ledger::<Test>::get(444).unwrap().stash, 333);
let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(444));
assert_eq!(ledger_result.unwrap().stash, 444);
let ledger_result = StakingLedger::<Test>::get(StakingAccount::Controller(444));
assert_eq!(ledger_result.unwrap().stash, 333);
let ledger_result = StakingLedger::<Test>::get(StakingAccount::Stash(333));
assert_eq!(ledger_result.unwrap().stash, 333);
let mut ledger = Ledger::<Test>::get(444).unwrap();
assert_eq!(ledger.stash, 333);
ledger.stash = 444;
Ledger::<Test>::insert(444, ledger);
assert!(StakingLedger::<Test>::get(StakingAccount::Stash(333)).is_err());
})
}
#[test]
fn bond_works() {
ExtBuilder::default().build_and_execute(|| {
asset::set_stakeable_balance::<T>(&42, 1000);
assert!(!StakingLedger::<Test>::is_bonded(StakingAccount::Stash(42)));
assert!(<Bonded<Test>>::get(&42).is_none());
let mut ledger: StakingLedger<Test> = StakingLedger::new(42, 84);
let reward_dest = RewardDestination::Account(10);
assert_ok!(ledger.clone().bond(reward_dest));
assert!(StakingLedger::<Test>::is_bonded(StakingAccount::Stash(42)));
assert!(<Bonded<Test>>::get(&42).is_some());
assert_eq!(<Payee<Test>>::get(&42), Some(reward_dest));
assert!(ledger.clone().bond(reward_dest).is_err());
ledger.unlocking = bounded_vec![UnlockChunk { era: 42, value: 42 }];
ledger.active -= 42;
assert_ok!(ledger.update());
})
}
#[test]
fn bond_controller_cannot_be_stash_works() {
ExtBuilder::default().build_and_execute(|| {
let (stash, controller) = testing_utils::create_unique_stash_controller::<Test>(
0,
10,
RewardDestination::Staked,
false,
)
.unwrap();
assert_eq!(Bonded::<Test>::get(stash), Some(controller));
assert_eq!(Ledger::<Test>::get(controller).map(|l| l.stash), Some(stash));
assert_noop!(
Staking::bond(RuntimeOrigin::signed(controller), 10, RewardDestination::Staked),
Error::<Test>::AlreadyPaired,
);
})
}
#[test]
fn is_bonded_works() {
ExtBuilder::default().build_and_execute(|| {
assert!(!StakingLedger::<Test>::is_bonded(StakingAccount::Stash(42)));
assert!(!StakingLedger::<Test>::is_bonded(StakingAccount::Controller(42)));
<Bonded<Test>>::insert(42, 42);
assert!(!StakingLedger::<Test>::is_bonded(StakingAccount::Controller(42)));
assert_eq!(<Bonded<Test>>::get(&11), Some(11));
assert!(StakingLedger::<Test>::is_bonded(StakingAccount::Stash(11)));
assert!(StakingLedger::<Test>::is_bonded(StakingAccount::Controller(11)));
<Bonded<Test>>::remove(42); })
}
#[test]
#[allow(deprecated)]
fn set_payee_errors_on_controller_destination() {
ExtBuilder::default().build_and_execute(|| {
Payee::<Test>::insert(11, RewardDestination::Staked);
assert_noop!(
Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Controller),
Error::<Test>::ControllerDeprecated
);
assert_eq!(Payee::<Test>::get(&11), Some(RewardDestination::Staked));
})
}
#[test]
#[allow(deprecated)]
fn update_payee_migration_works() {
ExtBuilder::default().build_and_execute(|| {
Payee::<Test>::insert(11, RewardDestination::Controller);
assert_eq!(Payee::<Test>::get(&11), Some(RewardDestination::Controller));
assert_ok!(Staking::update_payee(RuntimeOrigin::signed(11), 11));
assert_eq!(Payee::<Test>::get(&11), Some(RewardDestination::Account(11)));
Payee::<Test>::insert(21, RewardDestination::Stash);
assert_eq!(Payee::<Test>::get(&21), Some(RewardDestination::Stash));
assert_noop!(
Staking::update_payee(RuntimeOrigin::signed(11), 21),
Error::<Test>::NotController
);
assert_eq!(Payee::<Test>::get(&21), Some(RewardDestination::Stash));
})
}
#[test]
fn set_controller_with_bad_state_ok() {
ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333)));
assert_ok!(Staking::set_controller(RuntimeOrigin::signed(444)));
assert_ok!(Staking::set_controller(RuntimeOrigin::signed(555)));
})
}
#[test]
fn set_controller_with_bad_state_fails() {
ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_noop!(Staking::set_controller(RuntimeOrigin::signed(555)), Error::<Test>::BadState);
assert_noop!(Staking::set_controller(RuntimeOrigin::signed(444)), Error::<Test>::BadState);
assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333)));
})
}
mod deprecate_controller_call {
use super::*;
#[test]
fn deprecate_controller_batch_works_full_weight() {
ExtBuilder::default().try_state(false).build_and_execute(|| {
let start = 1001;
let mut controllers: Vec<_> = vec![];
for n in start..(start + MaxControllersInDeprecationBatch::get()).into() {
let ctlr: u64 = n.into();
let stash: u64 = (n + 10000).into();
Ledger::<Test>::insert(
ctlr,
StakingLedger {
controller: None,
total: (10 + ctlr).into(),
active: (10 + ctlr).into(),
..StakingLedger::default_from(stash)
},
);
Bonded::<Test>::insert(stash, ctlr);
Payee::<Test>::insert(stash, RewardDestination::Staked);
controllers.push(ctlr);
}
let bounded_controllers: BoundedVec<
_,
<Test as Config>::MaxControllersInDeprecationBatch,
> = BoundedVec::try_from(controllers).unwrap();
assert_noop!(
Staking::deprecate_controller_batch(
RuntimeOrigin::signed(2),
bounded_controllers.clone()
),
BadOrigin
);
let result =
Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers);
assert_ok!(result);
assert_eq!(
result.unwrap().actual_weight.unwrap(),
<Test as Config>::WeightInfo::deprecate_controller_batch(
<Test as Config>::MaxControllersInDeprecationBatch::get()
)
);
for n in start..(start + MaxControllersInDeprecationBatch::get()).into() {
let ctlr: u64 = n.into();
let stash: u64 = (n + 10000).into();
assert_eq!(Ledger::<Test>::get(ctlr), None);
assert_eq!(Bonded::<Test>::get(stash), Some(stash));
let ledger_updated = Ledger::<Test>::get(stash).unwrap();
assert_eq!(ledger_updated.stash, stash);
assert_eq!(ledger_updated.active, (10 + ctlr).into());
assert_eq!(ledger_updated.total, (10 + ctlr).into());
}
})
}
#[test]
fn deprecate_controller_batch_works_half_weight() {
ExtBuilder::default().build_and_execute(|| {
let start = 1001;
let mut controllers: Vec<_> = vec![];
for n in start..(start + MaxControllersInDeprecationBatch::get()).into() {
let ctlr: u64 = n.into();
let stash: u64 = if n % 2 == 0 { (n + 10000).into() } else { ctlr };
Ledger::<Test>::insert(
ctlr,
StakingLedger { controller: None, ..StakingLedger::default_from(stash) },
);
Bonded::<Test>::insert(stash, ctlr);
Payee::<Test>::insert(stash, RewardDestination::Staked);
controllers.push(ctlr);
}
let bounded_controllers: BoundedVec<
_,
<Test as Config>::MaxControllersInDeprecationBatch,
> = BoundedVec::try_from(controllers.clone()).unwrap();
let result =
Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers);
assert_ok!(result);
assert_eq!(
result.unwrap().actual_weight.unwrap(),
<Test as Config>::WeightInfo::deprecate_controller_batch(controllers.len() as u32)
);
for n in start..(start + MaxControllersInDeprecationBatch::get()).into() {
let unique_pair = n % 2 == 0;
let ctlr: u64 = n.into();
let stash: u64 = if unique_pair { (n + 10000).into() } else { ctlr };
if unique_pair {
assert_eq!(Ledger::<Test>::get(ctlr), None);
}
assert_eq!(Bonded::<Test>::get(stash), Some(stash));
let ledger_updated = Ledger::<Test>::get(stash).unwrap();
assert_eq!(ledger_updated.stash, stash);
}
})
}
#[test]
fn deprecate_controller_batch_skips_unmigrated_controller_payees() {
ExtBuilder::default().try_state(false).build_and_execute(|| {
let stash: u64 = 1000;
let ctlr: u64 = 1001;
Ledger::<Test>::insert(
ctlr,
StakingLedger { controller: None, ..StakingLedger::default_from(stash) },
);
Bonded::<Test>::insert(stash, ctlr);
#[allow(deprecated)]
Payee::<Test>::insert(stash, RewardDestination::Controller);
let bounded_controllers: BoundedVec<
_,
<Test as Config>::MaxControllersInDeprecationBatch,
> = BoundedVec::try_from(vec![ctlr]).unwrap();
let result =
Staking::deprecate_controller_batch(RuntimeOrigin::root(), bounded_controllers);
assert_ok!(result);
assert_eq!(
result.unwrap().actual_weight.unwrap(),
<Test as Config>::WeightInfo::deprecate_controller_batch(1 as u32)
);
assert_eq!(Ledger::<Test>::get(ctlr).is_some(), true);
assert_eq!(Bonded::<Test>::get(stash), Some(ctlr));
let ledger_updated = Ledger::<Test>::get(ctlr).unwrap();
assert_eq!(ledger_updated.stash, stash);
})
}
#[test]
fn deprecate_controller_batch_with_bad_state_ok() {
ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| {
setup_double_bonded_ledgers();
let bounded_controllers: BoundedVec<
_,
<Test as Config>::MaxControllersInDeprecationBatch,
> = BoundedVec::try_from(vec![333, 444, 555, 777]).unwrap();
assert_ok!(Staking::deprecate_controller_batch(
RuntimeOrigin::root(),
bounded_controllers
));
assert_eq!(
*staking_events().last().unwrap(),
Event::ControllerBatchDeprecated { failures: 0 }
);
})
}
#[test]
fn deprecate_controller_batch_with_bad_state_failures() {
ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
let bounded_controllers: BoundedVec<
_,
<Test as Config>::MaxControllersInDeprecationBatch,
> = BoundedVec::try_from(vec![777, 555, 444, 333]).unwrap();
assert_ok!(Staking::deprecate_controller_batch(
RuntimeOrigin::root(),
bounded_controllers
));
assert_eq!(
*staking_events().last().unwrap(),
Event::ControllerBatchDeprecated { failures: 2 }
);
})
}
}
mod ledger_recovery {
use super::*;
#[test]
fn inspect_recovery_ledger_simple_works() {
ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_eq!(Staking::inspect_bond_state(&11).unwrap(), LedgerIntegrityState::Ok);
assert!(Bonded::<Test>::get(&1111).is_none());
assert!(Staking::inspect_bond_state(&1111).is_err());
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
})
}
#[test]
fn inspect_recovery_ledger_corupted_killed_works() {
ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
let lock_333_before = asset::staked::<Test>(&333);
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
assert_ok!(StakingLedger::<Test>::kill(&333));
assert_eq!(Staking::inspect_bond_state(&333), Err(Error::<Test>::BadState));
assert_eq!(
Staking::inspect_bond_state(&444),
Ok(LedgerIntegrityState::CorruptedKilled)
);
assert_eq!(asset::staked::<Test>(&333), lock_333_before); assert!(Bonded::<Test>::get(&333).is_none()); assert!(Payee::<Test>::get(&333).is_none()); assert!(Ledger::<Test>::get(&444).is_none());
assert_eq!(asset::staked::<Test>(&444), 0); assert!(Bonded::<Test>::get(&444).is_some()); assert!(Payee::<Test>::get(&444).is_some()); assert!(Ledger::<Test>::get(&555).is_none());
assert!(Staking::do_try_state(System::block_number()).is_err());
})
}
#[test]
fn inspect_recovery_ledger_corupted_killed_other_works() {
ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
let lock_333_before = asset::staked::<Test>(&333);
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
assert_ok!(StakingLedger::<Test>::kill(&444));
assert_eq!(
Staking::inspect_bond_state(&333).unwrap(),
LedgerIntegrityState::CorruptedKilled,
);
assert_eq!(Ledger::<Test>::get(&444), None);
assert_eq!(Staking::inspect_bond_state(&444), Err(Error::<Test>::NotStash));
assert_eq!(asset::staked::<Test>(&333), lock_333_before); assert_eq!(Bonded::<Test>::get(&333), Some(444)); assert!(Payee::<Test>::get(&333).is_some());
assert!(Ledger::<Test>::get(&444).is_none());
assert_eq!(asset::staked::<Test>(&444), 0); assert!(Bonded::<Test>::get(&444).is_none()); assert!(Payee::<Test>::get(&444).is_none()); assert!(Ledger::<Test>::get(&555).is_none());
assert!(Staking::do_try_state(System::block_number()).is_err());
})
}
#[test]
fn inspect_recovery_ledger_lock_corrupted_works() {
ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
bond_extra_no_checks(&333, 10);
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
assert_eq!(
Staking::inspect_bond_state(&444).unwrap(),
LedgerIntegrityState::LockCorrupted
);
})
}
#[test]
fn restore_ledger_corrupted_works() {
ExtBuilder::default().has_stakers(true).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
assert_ok!(Staking::do_try_state(System::block_number()));
})
}
#[test]
fn restore_ledger_corrupted_killed_works() {
ExtBuilder::default().has_stakers(true).build_and_execute(|| {
setup_double_bonded_ledgers();
let total_444_before_corruption = asset::staked::<Test>(&444);
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert_ok!(StakingLedger::<Test>::kill(&333));
assert_eq!(Staking::inspect_bond_state(&333), Err(Error::<Test>::BadState));
assert!(Staking::ledger(StakingAccount::Stash(444)).is_err());
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
assert_noop!(
Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None),
Error::<Test>::CannotRestoreLedger
);
assert_ok!(Staking::restore_ledger(
RuntimeOrigin::root(),
444,
None,
Some(total_444_before_corruption),
None,
));
assert_ok!(Staking::do_try_state(System::block_number()));
})
}
#[test]
fn restore_ledger_corrupted_killed_other_works() {
ExtBuilder::default().has_stakers(true).build_and_execute(|| {
setup_double_bonded_ledgers();
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert!(Staking::do_try_state(System::block_number()).is_err());
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted);
assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok);
assert_ok!(StakingLedger::<Test>::kill(&444));
assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None));
assert_eq!(Staking::inspect_bond_state(&444), Err(Error::<Test>::NotStash));
assert_ok!(Staking::do_try_state(System::block_number()));
})
}
#[test]
fn restore_ledger_corrupted_bond_extra_works() {
ExtBuilder::default().has_stakers(true).build_and_execute(|| {
setup_double_bonded_ledgers();
let lock_333_before = asset::staked::<Test>(&333);
let lock_444_before = asset::staked::<Test>(&444);
assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok);
set_controller_no_checks(&444);
assert!(Staking::do_try_state(System::block_number()).is_err());
bond_extra_no_checks(&444, 40);
assert_eq!(asset::staked::<Test>(&333), lock_333_before);
assert_eq!(asset::staked::<Test>(&444), lock_444_before + 40);
bond_extra_no_checks(&333, 30);
assert_eq!(asset::staked::<Test>(&333), lock_444_before + 40 + 30); assert_eq!(asset::staked::<Test>(&444), lock_444_before + 40);
assert_ok!(Staking::restore_ledger(
RuntimeOrigin::root(),
333,
None,
Some(lock_333_before + 30),
None
));
assert_noop!(
Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None),
Error::<Test>::CannotRestoreLedger
);
assert_ok!(Staking::restore_ledger(
RuntimeOrigin::root(),
444,
None,
Some(lock_444_before + 40),
None
));
let ledger_333 = Bonded::<Test>::get(&333).and_then(Ledger::<Test>::get).unwrap();
let ledger_444 = Bonded::<Test>::get(&444).and_then(Ledger::<Test>::get).unwrap();
assert_eq!(ledger_333.total, lock_333_before + 30);
assert_eq!(asset::staked::<Test>(&333), ledger_333.total);
assert_eq!(ledger_444.total, lock_444_before + 40);
assert_eq!(asset::staked::<Test>(&444), ledger_444.total);
assert_ok!(Staking::do_try_state(System::block_number()));
})
}
}