Skip to content

Commit 0ea6f33

Browse files
authored
Merge pull request #157 from bifrost-platform/main
back-merge main to test
2 parents 50818c2 + 72c7e93 commit 0ea6f33

File tree

17 files changed

+244
-46
lines changed

17 files changed

+244
-46
lines changed

Cargo.lock

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

pallets/bfc-staking/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,12 @@ impl<
739739
self.commission = commission;
740740
}
741741

742-
pub fn reset_commission<T: Config>(&mut self) {
742+
pub fn reset_commission<T: Config>(&mut self, who: &T::AccountId) {
743+
let round = <Round<T>>::get();
744+
let mut commission_sets = <DelayedCommissionSets<T>>::get(round.current_round_index);
745+
commission_sets.retain(|c| c.who != *who);
746+
<DelayedCommissionSets<T>>::insert(round.current_round_index, commission_sets);
747+
743748
if self.tier == TierType::Full {
744749
self.commission = <DefaultFullValidatorCommission<T>>::get();
745750
} else {

pallets/bfc-staking/src/pallet/impls.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,8 @@ impl<T: Config> Pallet<T> {
444444
// replace `SelectedCandidates`
445445
if candidate.is_selected {
446446
Self::replace_from_selected_candidates(&c.old, &c.new, candidate.tier);
447+
}
448+
if candidate.tier == TierType::Full {
447449
T::RelayManager::replace_bonded_controller(c.old.clone(), c.new.clone());
448450
}
449451
// replace `TopNominations`
@@ -465,8 +467,10 @@ impl<T: Config> Pallet<T> {
465467
<BottomNominations<T>>::insert(&c.new, bottom_nominations);
466468
}
467469
// replace `AwardedPts`
468-
let points = <AwardedPts<T>>::take(now, &c.old);
469-
<AwardedPts<T>>::insert(now, &c.new, points);
470+
let current_points = <AwardedPts<T>>::take(now, &c.old);
471+
<AwardedPts<T>>::insert(now, &c.new, current_points);
472+
let previous_points = <AwardedPts<T>>::take(delayed_round, &c.old);
473+
<AwardedPts<T>>::insert(delayed_round, &c.new, previous_points);
470474
// replace `AtStake`
471475
let at_stake = <AtStake<T>>::take(now, &c.old);
472476
<AtStake<T>>::insert(now, &c.new, at_stake);
@@ -951,9 +955,10 @@ impl<T: Config> Pallet<T> {
951955
// snapshot total stake and storage state
952956
<Staked<T>>::insert(now, Total::<T>::get());
953957
<TotalAtStake<T>>::remove(now - 1);
958+
// handle delayed commission update requests
959+
Self::handle_delayed_commission_sets(now);
954960
// handle delayed controller update requests
955961
Self::handle_delayed_controller_sets(now);
956-
Self::handle_delayed_commission_sets(now);
957962

958963
Self::deposit_event(Event::NewRound {
959964
starting_block: round.first_round_block,

pallets/bfc-staking/src/pallet/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,7 @@ pub mod pallet {
10851085
T::RelayManager::leave_relayers(&controller);
10861086
}
10871087
state.tier = new;
1088-
state.reset_commission::<T>();
1088+
state.reset_commission::<T>(&controller);
10891089
<CandidateInfo<T>>::insert(&controller, state.clone());
10901090
Self::update_active(&controller, state.voting_power)?;
10911091
Ok(().into())
@@ -1167,6 +1167,14 @@ pub mod pallet {
11671167
ensure!(!<BondedStash<T>>::contains_key(&stash), Error::<T>::AlreadyBonded);
11681168
ensure!(!<CandidateInfo<T>>::contains_key(&controller), Error::<T>::AlreadyPaired);
11691169

1170+
// check if the controller account is already scheduled for update
1171+
let round = Round::<T>::get();
1172+
let controller_sets = DelayedControllerSets::<T>::get(round.current_round_index);
1173+
ensure!(
1174+
!controller_sets.into_iter().any(|c| c.new == controller),
1175+
Error::<T>::AlreadyControllerSetRequested
1176+
);
1177+
11701178
ensure!(!Self::is_nominator(&controller), Error::<T>::NominatorExists);
11711179
let mut candidates = <CandidatePool<T>>::get();
11721180
let old_count = candidates.len() as u32;

pallets/bfc-utility/src/pallet/mod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ pub mod pallet {
3636
pub enum Error<T> {
3737
/// The given amount is too low to process.
3838
AmountTooLow,
39+
/// The account is already blocked.
40+
AccountAlreadyBlocked,
41+
/// The account is not blocked.
42+
AccountNotBlocked,
3943
}
4044

4145
#[pallet::event]
@@ -56,6 +60,16 @@ pub mod pallet {
5660
/// Storage for proposal index. Whenever proposal is accepted, index will be increased.
5761
pub type ProposalIndex<T: Config> = StorageValue<_, PropIndex, ValueQuery>;
5862

63+
#[pallet::storage]
64+
#[pallet::unbounded]
65+
pub type BlockedAccounts<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;
66+
67+
impl<T: Config> Pallet<T> {
68+
pub fn is_blocked_account(account: &T::AccountId) -> bool {
69+
BlockedAccounts::<T>::get().contains(account)
70+
}
71+
}
72+
5973
#[pallet::hooks]
6074
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
6175
fn on_runtime_upgrade() -> Weight {
@@ -124,5 +138,35 @@ pub mod pallet {
124138

125139
Ok(().into())
126140
}
141+
142+
#[pallet::call_index(2)]
143+
#[pallet::weight((T::DbWeight::get().writes(1), DispatchClass::Operational,))]
144+
/// Add an account to the blocked accounts list.
145+
pub fn add_blocked_account(
146+
origin: OriginFor<T>,
147+
account: T::AccountId,
148+
) -> DispatchResultWithPostInfo {
149+
ensure_root(origin)?;
150+
ensure!(!Self::is_blocked_account(&account), Error::<T>::AccountAlreadyBlocked);
151+
let mut blocked_accounts = BlockedAccounts::<T>::get();
152+
blocked_accounts.push(account);
153+
BlockedAccounts::<T>::put(blocked_accounts);
154+
Ok(().into())
155+
}
156+
157+
#[pallet::call_index(3)]
158+
#[pallet::weight((T::DbWeight::get().writes(1), DispatchClass::Operational,))]
159+
/// Remove an account from the blocked accounts list.
160+
pub fn remove_blocked_account(
161+
origin: OriginFor<T>,
162+
account: T::AccountId,
163+
) -> DispatchResultWithPostInfo {
164+
ensure_root(origin)?;
165+
ensure!(Self::is_blocked_account(&account), Error::<T>::AccountNotBlocked);
166+
let mut blocked_accounts = BlockedAccounts::<T>::get();
167+
blocked_accounts.retain(|a| a != &account);
168+
BlockedAccounts::<T>::put(blocked_accounts);
169+
Ok(().into())
170+
}
127171
}
128172
}

pallets/btc-registration-pool/src/pallet/impls.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,17 @@ impl<T: Config> PoolManager<T::AccountId> for Pallet<T> {
122122
if let Some(mut vault) = SystemVault::<T>::get(round) {
123123
if vault.address == AddressState::Pending {
124124
vault.replace_authority(old, new);
125+
SystemVault::<T>::insert(round, vault);
125126
}
126127
}
127128
// replace authority in all registration pools (if they are pending)
128-
<RegistrationPool<T>>::iter_prefix(round).for_each(|(_, mut relay_target)| {
129+
<RegistrationPool<T>>::iter_prefix(round).for_each(|(address, relay_target)| {
129130
if relay_target.vault.address == AddressState::Pending {
130-
relay_target.vault.replace_authority(old, new);
131+
<RegistrationPool<T>>::mutate(round, &address, |relay_target| {
132+
if let Some(relay_target) = relay_target {
133+
relay_target.vault.replace_authority(old, new);
134+
}
135+
});
131136
}
132137
});
133138
}

pallets/btc-socket-queue/src/pallet/impls.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,15 @@ impl<T: Config> SocketQueueManager<T::AccountId> for Pallet<T> {
106106

107107
fn replace_authority(old: &T::AccountId, new: &T::AccountId) {
108108
// replace authority in pending requests
109-
<PendingRequests<T>>::iter().for_each(|(_, mut request)| {
109+
<PendingRequests<T>>::iter().for_each(|(txid, mut request)| {
110110
request.replace_authority(old, new);
111+
<PendingRequests<T>>::insert(&txid, request);
111112
});
112113
// replace authority in rollback requests (if not approved yet)
113-
<RollbackRequests<T>>::iter().for_each(|(_, mut request)| {
114+
<RollbackRequests<T>>::iter().for_each(|(txid, mut request)| {
114115
if !request.is_approved {
115116
request.replace_authority(old, new);
117+
<RollbackRequests<T>>::insert(&txid, request);
116118
}
117119
});
118120
}

pallets/relay-manager/src/pallet/impls.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -214,23 +214,24 @@ where
214214
let delayed_round = now - 1;
215215
let relayer_sets = <DelayedRelayerSets<T>>::take(delayed_round);
216216
relayer_sets.into_iter().for_each(|r| {
217-
Self::replace_bonded_relayer(&r.old, &r.new).expect("Replacement must success");
218-
T::SocketQueue::replace_authority(&r.old, &r.new);
219-
T::RegistrationPool::replace_authority(&r.old, &r.new);
220-
221-
// replace member of RelayExecutive (only if it's the old member)
222-
let mut members = Members::<T, Instance3>::get();
223-
if let Some(location) = members.binary_search(&r.old).ok() {
224-
if members.binary_search(&r.new).is_err() {
225-
members[location] = r.new.clone();
226-
members.sort();
227-
228-
Members::<T, Instance3>::put(members.clone());
229-
T::MembershipChanged::change_members_sorted(&[r.new.clone()], &[r.old.clone()], &members[..]);
230-
231-
if Prime::<T, Instance3>::get() == Some(r.old) {
232-
Prime::<T, Instance3>::put(&r.new);
233-
T::MembershipChanged::set_prime(Some(r.new));
217+
if Self::replace_bonded_relayer(&r.old, &r.new).expect("Replacement must success") {
218+
T::SocketQueue::replace_authority(&r.old, &r.new);
219+
T::RegistrationPool::replace_authority(&r.old, &r.new);
220+
221+
// replace member of RelayExecutive (only if it's the old member)
222+
let mut members = Members::<T, Instance3>::get();
223+
if let Some(location) = members.binary_search(&r.old).ok() {
224+
if members.binary_search(&r.new).is_err() {
225+
members[location] = r.new.clone();
226+
members.sort();
227+
228+
Members::<T, Instance3>::put(members.clone());
229+
T::MembershipChanged::change_members_sorted(&[r.new.clone()], &[r.old.clone()], &members[..]);
230+
231+
if Prime::<T, Instance3>::get() == Some(r.old) {
232+
Prime::<T, Instance3>::put(&r.new);
233+
T::MembershipChanged::set_prime(Some(r.new));
234+
}
234235
}
235236
}
236237
}
@@ -277,6 +278,14 @@ impl<T: Config> Pallet<T> {
277278
) -> Result<(), DispatchError> {
278279
ensure!(!Self::is_relayer(relayer), Error::<T>::RelayerAlreadyJoined);
279280
ensure!(!<BondedController<T>>::contains_key(controller), Error::<T>::RelayerAlreadyBonded);
281+
282+
let round = Round::<T>::get();
283+
let relayer_sets = DelayedRelayerSets::<T>::get(round);
284+
ensure!(
285+
!relayer_sets.into_iter().any(|r| r.new == *relayer),
286+
Error::<T>::AlreadyRelayerSetRequested
287+
);
288+
280289
Ok(().into())
281290
}
282291

@@ -316,6 +325,11 @@ impl<T: Config> Pallet<T> {
316325
pub fn add_to_relayer_sets(old: T::AccountId, new: T::AccountId) -> DispatchResult {
317326
let round = Round::<T>::get();
318327
<DelayedRelayerSets<T>>::try_mutate(round, |relayer_sets| -> DispatchResult {
328+
ensure!(
329+
!relayer_sets.into_iter().any(|r| r.old == old || r.new == new),
330+
Error::<T>::AlreadyRelayerSetRequested
331+
);
332+
319333
Ok(relayer_sets
320334
.try_push(DelayedRelayerSet::new(old, new))
321335
.map_err(|_| <Error<T>>::TooManyDelayedRelayers)?)

runtime/common/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ repository = { workspace = true }
1010

1111
[dependencies]
1212
parity-scale-codec = { workspace = true }
13+
scale-info = { workspace = true }
1314
ethereum = { workspace = true }
1415

1516
# Substrate
@@ -18,16 +19,19 @@ frame-support = { workspace = true }
1819
sp-core = { workspace = true }
1920
sp-runtime = { workspace = true }
2021
sp-std = { workspace = true }
22+
pallet-bfc-utility = { workspace = true }
2123

2224
[features]
2325
default = ["std"]
2426
std = [
27+
"scale-info/std",
2528
"ethereum/std",
2629
"parity-scale-codec/std",
2730
"frame-system/std",
2831
"frame-support/std",
2932
"sp-core/std",
3033
"sp-runtime/std",
3134
"sp-std/std",
35+
"pallet-bfc-utility/std",
3236
]
3337
try-runtime = ["frame-support/try-runtime"]

runtime/common/src/extensions.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use frame_support::pallet_prelude::{TransactionSource, TransactionValidityError};
2+
use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
3+
use scale_info::TypeInfo;
4+
5+
use sp_core::H160;
6+
use sp_runtime::{
7+
traits::{AsSystemOriginSigner, DispatchInfoOf, Dispatchable, TransactionExtension},
8+
Weight,
9+
};
10+
use sp_std::{
11+
fmt::{Debug, Formatter},
12+
marker::PhantomData,
13+
};
14+
15+
/// Transaction extension that blocks extrinsics from specific origins
16+
#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo, DecodeWithMemTracking)]
17+
#[scale_info(skip_type_params(T))]
18+
#[codec(encode_bound())]
19+
#[codec(decode_bound())]
20+
pub struct CheckBlockedOrigin<T, Call>(PhantomData<(T, Call)>);
21+
22+
impl<T, Call> Debug for CheckBlockedOrigin<T, Call> {
23+
fn fmt(&self, f: &mut Formatter) -> sp_std::fmt::Result {
24+
write!(f, "CheckBlockedOrigin")
25+
}
26+
}
27+
28+
impl<T, Call> Default for CheckBlockedOrigin<T, Call> {
29+
fn default() -> Self {
30+
Self::new()
31+
}
32+
}
33+
34+
impl<T, Call> CheckBlockedOrigin<T, Call> {
35+
pub fn new() -> Self {
36+
Self(PhantomData)
37+
}
38+
}
39+
40+
impl<T, Call> TransactionExtension<Call> for CheckBlockedOrigin<T, Call>
41+
where
42+
T: frame_system::Config + Send + Sync,
43+
T::AccountId: From<H160>,
44+
T: pallet_bfc_utility::Config,
45+
Call: Dispatchable + Clone + Eq + TypeInfo + Send + Sync + 'static,
46+
<Call as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId>,
47+
{
48+
const IDENTIFIER: &'static str = "CheckBlockedOrigin";
49+
type Implicit = ();
50+
type Pre = ();
51+
type Val = ();
52+
53+
fn weight(&self, _call: &Call) -> Weight {
54+
Weight::zero()
55+
}
56+
57+
fn validate(
58+
&self,
59+
origin: <Call as Dispatchable>::RuntimeOrigin,
60+
_call: &Call,
61+
_info: &DispatchInfoOf<Call>,
62+
_len: usize,
63+
_self_implicit: Self::Implicit,
64+
_inherited_implication: &impl Encode,
65+
_source: TransactionSource,
66+
) -> Result<
67+
(
68+
sp_runtime::transaction_validity::ValidTransaction,
69+
Self::Val,
70+
<Call as Dispatchable>::RuntimeOrigin,
71+
),
72+
TransactionValidityError,
73+
> {
74+
if let Some(who) = origin.as_system_origin_signer() {
75+
if pallet_bfc_utility::Pallet::<T>::is_blocked_account(who) {
76+
return Err(TransactionValidityError::Invalid(
77+
sp_runtime::transaction_validity::InvalidTransaction::BadSigner,
78+
));
79+
}
80+
}
81+
Ok((sp_runtime::transaction_validity::ValidTransaction::default(), (), origin))
82+
}
83+
84+
fn prepare(
85+
self,
86+
_val: Self::Val,
87+
_origin: &<Call as Dispatchable>::RuntimeOrigin,
88+
_call: &Call,
89+
_info: &DispatchInfoOf<Call>,
90+
_len: usize,
91+
) -> Result<Self::Pre, TransactionValidityError> {
92+
Ok(())
93+
}
94+
}

0 commit comments

Comments
 (0)