Skip to content
GitLab
Explore
Sign in
parity
Mirrored projects
polkadot-sdk
Compare revisions
be1d7d05e5f32b1bfa67aec2f6344d2c6ff60f50 to aceda4659509d426d364188fa72555de58b887ba
Show whitespace changes
Inline
Side-by-side
substrate/frame/staking/src/pallet/impls.rs
View file @
aceda465
...
...
@@ -43,7 +43,7 @@ use sp_runtime::{
};
use
sp_staking
::{
currency_to_vote
::
CurrencyToVote
,
offence
::{
DisableStrategy
,
OffenceDetails
,
OnOffenceHandler
},
offence
::{
OffenceDetails
,
OnOffenceHandler
},
EraIndex
,
OnStakingUpdate
,
Page
,
SessionIndex
,
Stake
,
StakingAccount
::{
self
,
Controller
,
Stash
},
StakingInterface
,
...
...
@@ -505,12 +505,10 @@ impl<T: Config> Pallet<T> {
}
// disable all offending validators that have been disabled for the whole era
for
(
index
,
disabled
)
in
<
OffendingValidators
<
T
>>
::
get
()
{
if
disabled
{
for
index
in
<
DisabledValidators
<
T
>>
::
get
()
{
T
::
SessionInterface
::
disable_validator
(
index
);
}
}
}
/// End a session potentially ending an era.
fn
end_session
(
session_index
:
SessionIndex
)
{
...
...
@@ -598,8 +596,8 @@ impl<T: Config> Pallet<T> {
<
ErasValidatorReward
<
T
>>
::
insert
(
&
active_era
.index
,
validator_payout
);
T
::
RewardRemainder
::
on_unbalanced
(
T
::
Currency
::
issue
(
remainder
));
// Clear
offending
validators.
<
Offending
Validators
<
T
>>
::
kill
();
// Clear
disabled
validators.
<
Disabled
Validators
<
T
>>
::
kill
();
}
}
...
...
@@ -868,14 +866,6 @@ impl<T: Config> Pallet<T> {
Self
::
deposit_event
(
Event
::
<
T
>
::
ForceEra
{
mode
});
}
/// Ensures that at the end of the current session there will be a new era.
pub
(
crate
)
fn
ensure_new_era
()
{
match
ForceEra
::
<
T
>
::
get
()
{
Forcing
::
ForceAlways
|
Forcing
::
ForceNew
=>
(),
_
=>
Self
::
set_force_era
(
Forcing
::
ForceNew
),
}
}
#[cfg(feature
=
"runtime-benchmarks"
)]
pub
fn
add_era_stakers
(
current_era
:
EraIndex
,
...
...
@@ -1447,7 +1437,6 @@ where
>
],
slash_fraction
:
&
[
Perbill
],
slash_session
:
SessionIndex
,
disable_strategy
:
DisableStrategy
,
)
->
Weight
{
let
reward_proportion
=
SlashRewardFraction
::
<
T
>
::
get
();
let
mut
consumed_weight
=
Weight
::
from_parts
(
0
,
0
);
...
...
@@ -1512,7 +1501,6 @@ where
window_start
,
now
:
active_era
,
reward_proportion
,
disable_strategy
,
});
Self
::
deposit_event
(
Event
::
<
T
>
::
SlashReported
{
...
...
@@ -1986,7 +1974,8 @@ impl<T: Config> Pallet<T> {
Self
::
check_nominators
()
?
;
Self
::
check_exposures
()
?
;
Self
::
check_paged_exposures
()
?
;
Self
::
check_count
()
Self
::
check_count
()
?
;
Self
::
ensure_disabled_validators_sorted
()
}
/// Invariants:
...
...
@@ -2300,4 +2289,12 @@ impl<T: Config> Pallet<T> {
Ok
(())
}
fn
ensure_disabled_validators_sorted
()
->
Result
<
(),
TryRuntimeError
>
{
ensure!
(
DisabledValidators
::
<
T
>
::
get
()
.windows
(
2
)
.all
(|
pair
|
pair
[
0
]
<=
pair
[
1
]),
"DisabledValidators is not sorted"
);
Ok
(())
}
}
substrate/frame/staking/src/pallet/mod.rs
View file @
aceda465
...
...
@@ -47,10 +47,11 @@ mod impls;
pub
use
impls
::
*
;
use
crate
::{
slashing
,
weights
::
WeightInfo
,
AccountIdLookupOf
,
ActiveEraInfo
,
BalanceOf
,
EraPayout
,
EraRewardPoints
,
Exposure
,
ExposurePage
,
Forcing
,
LedgerIntegrityState
,
MaxNominationsOf
,
NegativeImbalanceOf
,
Nominations
,
NominationsQuota
,
PositiveImbalanceOf
,
RewardDestination
,
SessionInterface
,
StakingLedger
,
UnappliedSlash
,
UnlockChunk
,
ValidatorPrefs
,
slashing
,
weights
::
WeightInfo
,
AccountIdLookupOf
,
ActiveEraInfo
,
BalanceOf
,
DisablingStrategy
,
EraPayout
,
EraRewardPoints
,
Exposure
,
ExposurePage
,
Forcing
,
LedgerIntegrityState
,
MaxNominationsOf
,
NegativeImbalanceOf
,
Nominations
,
NominationsQuota
,
PositiveImbalanceOf
,
RewardDestination
,
SessionInterface
,
StakingLedger
,
UnappliedSlash
,
UnlockChunk
,
ValidatorPrefs
,
};
// The speculative number of spans are used as an input of the weight annotation of
...
...
@@ -67,7 +68,7 @@ pub mod pallet {
use
super
::
*
;
/// The in-code storage version.
const
STORAGE_VERSION
:
StorageVersion
=
StorageVersion
::
new
(
1
4
);
const
STORAGE_VERSION
:
StorageVersion
=
StorageVersion
::
new
(
1
5
);
#[pallet::pallet]
#[pallet::storage_version(STORAGE_VERSION)]
...
...
@@ -217,10 +218,6 @@ pub mod pallet {
#[pallet::constant]
type
MaxExposurePageSize
:
Get
<
u32
>
;
/// The fraction of the validator set that is safe to be offending.
/// After the threshold is reached a new era will be forced.
type
OffendingValidatorsThreshold
:
Get
<
Perbill
>
;
/// Something that provides a best-effort sorted list of voters aka electing nominators,
/// used for NPoS election.
///
...
...
@@ -278,6 +275,9 @@ pub mod pallet {
/// WARNING: this only reports slashing and withdraw events for the time being.
type
EventListeners
:
sp_staking
::
OnStakingUpdate
<
Self
::
AccountId
,
BalanceOf
<
Self
>>
;
// `DisablingStragegy` controls how validators are disabled
type
DisablingStrategy
:
DisablingStrategy
<
Self
>
;
/// Some parameters of the benchmarking.
type
BenchmarkingConfig
:
BenchmarkingConfig
;
...
...
@@ -654,19 +654,16 @@ pub mod pallet {
#[pallet::getter(fn
current_planned_session)]
pub
type
CurrentPlannedSession
<
T
>
=
StorageValue
<
_
,
SessionIndex
,
ValueQuery
>
;
/// Indices of validators that have offended in the active era and whether they are currently
/// disabled.
/// Indices of validators that have offended in the active era. The offenders are disabled for a
/// whole era. For this reason they are kept here - only staking pallet knows about eras. The
/// implementor of [`DisablingStrategy`] defines if a validator should be disabled which
/// implicitly means that the implementor also controls the max number of disabled validators.
///
/// This value should be a superset of disabled validators since not all offences lead to the
/// validator being disabled (if there was no slash). This is needed to track the percentage of
/// validators that have offended in the current era, ensuring a new era is forced if
/// `OffendingValidatorsThreshold` is reached. The vec is always kept sorted so that we can find
/// whether a given validator has previously offended using binary search. It gets cleared when
/// the era ends.
/// The vec is always kept sorted so that we can find whether a given validator has previously
/// offended using binary search.
#[pallet::storage]
#[pallet::unbounded]
#[pallet::getter(fn
offending_validators)]
pub
type
OffendingValidators
<
T
:
Config
>
=
StorageValue
<
_
,
Vec
<
(
u32
,
bool
)
>
,
ValueQuery
>
;
pub
type
DisabledValidators
<
T
:
Config
>
=
StorageValue
<
_
,
Vec
<
u32
>
,
ValueQuery
>
;
/// The threshold for when users can start calling `chill_other` for other validators /
/// nominators. The threshold is compared to the actual number of validators / nominators
...
...
substrate/frame/staking/src/slashing.rs
View file @
aceda465
...
...
@@ -50,21 +50,21 @@
//! Based on research at <https://research.web3.foundation/en/latest/polkadot/slashing/npos.html>
use
crate
::{
BalanceOf
,
Config
,
Error
,
Exposure
,
NegativeImbalanceOf
,
NominatorSlashInEra
,
OffendingValidators
,
Pallet
,
Perbill
,
SessionInterface
,
SpanSlash
,
UnappliedSlash
,
BalanceOf
,
Config
,
DisabledValidators
,
DisablingStrategy
,
Error
,
Exposure
,
NegativeImbalanceOf
,
NominatorSlashInEra
,
Pallet
,
Perbill
,
SessionInterface
,
SpanSlash
,
UnappliedSlash
,
ValidatorSlashInEra
,
};
use
codec
::{
Decode
,
Encode
,
MaxEncodedLen
};
use
frame_support
::{
ensure
,
traits
::{
Currency
,
Defensive
,
DefensiveSaturating
,
Get
,
Imbalance
,
OnUnbalanced
},
traits
::{
Currency
,
Defensive
,
DefensiveSaturating
,
Imbalance
,
OnUnbalanced
},
};
use
scale_info
::
TypeInfo
;
use
sp_runtime
::{
traits
::{
Saturating
,
Zero
},
DispatchResult
,
RuntimeDebug
,
};
use
sp_staking
::
{
offence
::
DisableStrategy
,
EraIndex
}
;
use
sp_staking
::
EraIndex
;
use
sp_std
::
vec
::
Vec
;
/// The proportion of the slashing reward to be paid out on the first slashing detection.
...
...
@@ -220,8 +220,6 @@ pub(crate) struct SlashParams<'a, T: 'a + Config> {
/// The maximum percentage of a slash that ever gets paid out.
/// This is f_inf in the paper.
pub
(
crate
)
reward_proportion
:
Perbill
,
/// When to disable offenders.
pub
(
crate
)
disable_strategy
:
DisableStrategy
,
}
/// Computes a slash of a validator and nominators. It returns an unapplied
...
...
@@ -280,18 +278,13 @@ pub(crate) fn compute_slash<T: Config>(
let
target_span
=
spans
.compare_and_update_span_slash
(
params
.slash_era
,
own_slash
);
if
target_span
==
Some
(
spans
.span_index
())
{
// misbehavior occurred within the current slashing span - take appropriate
// actions.
// chill the validator - it misbehaved in the current span and should
// not continue in the next election. also end the slashing span.
// misbehavior occurred within the current slashing span - end current span.
// Check <https://github.com/paritytech/polkadot-sdk/issues/2650> for details.
spans
.end_span
(
params
.now
);
<
Pallet
<
T
>>
::
chill_stash
(
params
.stash
);
}
}
let
disable_when_slashed
=
params
.disable_strategy
!=
DisableStrategy
::
Never
;
add_offending_validator
::
<
T
>
(
params
.stash
,
disable_when_slashed
);
add_offending_validator
::
<
T
>
(
&
params
);
let
mut
nominators_slashed
=
Vec
::
new
();
reward_payout
+=
slash_nominators
::
<
T
>
(
params
.clone
(),
prior_slash_p
,
&
mut
nominators_slashed
);
...
...
@@ -320,54 +313,31 @@ fn kick_out_if_recent<T: Config>(params: SlashParams<T>) {
);
if
spans
.era_span
(
params
.slash_era
)
.map
(|
s
|
s
.index
)
==
Some
(
spans
.span_index
())
{
// Check https://github.com/paritytech/polkadot-sdk/issues/2650 for details
spans
.end_span
(
params
.now
);
<
Pallet
<
T
>>
::
chill_stash
(
params
.stash
);
}
let
disable_without_slash
=
params
.disable_strategy
==
DisableStrategy
::
Always
;
add_offending_validator
::
<
T
>
(
params
.stash
,
disable_without_slash
);
add_offending_validator
::
<
T
>
(
&
params
);
}
/// Add the given validator to the offenders list and optionally disable it.
/// If after adding the validator `OffendingValidatorsThreshold` is reached
/// a new era will be forced.
fn
add_offending_validator
<
T
:
Config
>
(
stash
:
&
T
::
AccountId
,
disable
:
bool
)
{
OffendingValidators
::
<
T
>
::
mutate
(|
offending
|
{
let
validators
=
T
::
SessionInterface
::
validators
();
let
validator_index
=
match
validators
.iter
()
.position
(|
i
|
i
==
stash
)
{
Some
(
index
)
=>
index
,
None
=>
return
,
};
let
validator_index_u32
=
validator_index
as
u32
;
match
offending
.binary_search_by_key
(
&
validator_index_u32
,
|(
index
,
_
)|
*
index
)
{
// this is a new offending validator
Err
(
index
)
=>
{
offending
.insert
(
index
,
(
validator_index_u32
,
disable
));
let
offending_threshold
=
T
::
OffendingValidatorsThreshold
::
get
()
*
validators
.len
()
as
u32
;
if
offending
.len
()
>=
offending_threshold
as
usize
{
// force a new era, to select a new validator set
<
Pallet
<
T
>>
::
ensure_new_era
()
}
if
disable
{
T
::
SessionInterface
::
disable_validator
(
validator_index_u32
);
}
},
Ok
(
index
)
=>
{
if
disable
&&
!
offending
[
index
]
.1
{
// the validator had previously offended without being disabled,
// let's make sure we disable it now
offending
[
index
]
.1
=
true
;
T
::
SessionInterface
::
disable_validator
(
validator_index_u32
);
/// Inform the [`DisablingStrategy`] implementation about the new offender and disable the list of
/// validators provided by [`make_disabling_decision`].
fn
add_offending_validator
<
T
:
Config
>
(
params
:
&
SlashParams
<
T
>
)
{
DisabledValidators
::
<
T
>
::
mutate
(|
disabled
|
{
if
let
Some
(
offender
)
=
T
::
DisablingStrategy
::
decision
(
params
.stash
,
params
.slash_era
,
&
disabled
)
{
// Add the validator to `DisabledValidators` and disable it. Do nothing if it is
// already disabled.
if
let
Err
(
index
)
=
disabled
.binary_search_by_key
(
&
offender
,
|
index
|
*
index
)
{
disabled
.insert
(
index
,
offender
);
T
::
SessionInterface
::
disable_validator
(
offender
);
}
},
}
});
// `DisabledValidators` should be kept sorted
debug_assert!
(
DisabledValidators
::
<
T
>
::
get
()
.windows
(
2
)
.all
(|
pair
|
pair
[
0
]
<
pair
[
1
]));
}
/// Slash nominators. Accepts general parameters and the prior slash percentage of the validator.
...
...
substrate/frame/staking/src/tests.rs
View file @
aceda465
...
...
@@ -38,7 +38,7 @@ use sp_runtime::{
Perbill
,
Percent
,
Perquintill
,
Rounding
,
TokenError
,
};
use
sp_staking
::{
offence
::{
DisableStrategy
,
OffenceDetails
,
OnOffenceHandler
},
offence
::{
OffenceDetails
,
OnOffenceHandler
},
SessionIndex
,
};
use
sp_std
::
prelude
::
*
;
...
...
@@ -716,7 +716,10 @@ fn nominating_and_rewards_should_work() {
#[test]
fn
nominators_also_get_slashed_pro_rata
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
4
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
let
slash_percent
=
Perbill
::
from_percent
(
5
);
let
initial_exposure
=
Staking
::
eras_stakers
(
active_era
(),
&
11
);
...
...
@@ -753,8 +756,14 @@ fn nominators_also_get_slashed_pro_rata() {
assert!
(
nominator_share
>
0
);
// both stakes must have been decreased pro-rata.
assert_eq!
(
Staking
::
ledger
(
101
.into
())
.unwrap
()
.active
,
nominator_stake
-
nominator_share
);
assert_eq!
(
Staking
::
ledger
(
11
.into
())
.unwrap
()
.active
,
validator_stake
-
validator_share
);
assert_eq!
(
Staking
::
ledger
(
101
.into
())
.unwrap
()
.active
,
nominator_stake
-
nominator_share
);
assert_eq!
(
Staking
::
ledger
(
11
.into
())
.unwrap
()
.active
,
validator_stake
-
validator_share
);
assert_eq!
(
balances
(
&
101
)
.0
,
// free balance
nominator_balance
-
nominator_share
,
...
...
@@ -2401,7 +2410,7 @@ fn era_is_always_same_length() {
}
#[test]
fn
offence_force
s
_new_era
()
{
fn
offence_
doesnt_
force_new_era
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
on_offence_now
(
&
[
OffenceDetails
{
...
...
@@ -2411,7 +2420,7 @@ fn offence_forces_new_era() {
&
[
Perbill
::
from_percent
(
5
)],
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
});
}
...
...
@@ -2435,7 +2444,13 @@ fn offence_ensures_new_era_without_clobbering() {
#[test]
fn
offence_deselects_validator_even_when_slash_is_zero
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
assert!
(
Session
::
validators
()
.contains
(
&
11
));
assert!
(
<
Validators
<
Test
>>
::
contains_key
(
11
));
...
...
@@ -2447,13 +2462,13 @@ fn offence_deselects_validator_even_when_slash_is_zero() {
&
[
Perbill
::
from_percent
(
0
)],
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
assert!
(
!<
Validators
<
Test
>>
::
contains_key
(
11
));
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
assert!
(
is_disabled
(
11
));
mock
::
start_active_era
(
1
);
assert!
(
!
Session
::
validators
()
.contains
(
&
11
));
assert!
(
!
<
Validators
<
Test
>>
::
contains_key
(
11
));
// The validator should be reenabled in the new era
assert!
(
!
is_disabled
(
11
));
});
}
...
...
@@ -2479,8 +2494,11 @@ fn slashing_performed_according_exposure() {
}
#[test]
fn
slash_in_old_span_does_not_deselect
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
fn
validator_is_not_disabled_for_an_offence_in_previous_era
()
{
ExtBuilder
::
default
()
.validator_count
(
4
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert!
(
<
Validators
<
Test
>>
::
contains_key
(
11
));
...
...
@@ -2494,21 +2512,20 @@ fn slash_in_old_span_does_not_deselect() {
&
[
Perbill
::
from_percent
(
0
)],
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
assert!
(
!<
Validators
<
Test
>>
::
contains_key
(
11
));
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
assert!
(
is_disabled
(
11
));
mock
::
start_active_era
(
2
);
// the validator is not disabled in the new era
Staking
::
validate
(
RuntimeOrigin
::
signed
(
11
),
Default
::
default
())
.unwrap
();
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
NotForcing
);
assert!
(
<
Validators
<
Test
>>
::
contains_key
(
11
));
assert!
(
!
Session
::
validators
()
.contains
(
&
11
));
assert!
(
Session
::
validators
()
.contains
(
&
11
));
mock
::
start_active_era
(
3
);
// this staker is in a new slashing span now, having re-registered after
// their prior slash.
// an offence committed in era 1 is reported in era 3
on_offence_in_era
(
&
[
OffenceDetails
{
offender
:
(
11
,
Staking
::
eras_stakers
(
active_era
(),
&
11
)),
...
...
@@ -2516,14 +2533,14 @@ fn slash_in_old_span_does_not_deselect() {
}],
&
[
Perbill
::
from_percent
(
0
)],
1
,
DisableStrategy
::
WhenSlashed
,
);
// the validator doesn't get
chilled again
// the validator doesn't get
disabled for an old offence
assert!
(
Validators
::
<
Test
>
::
iter
()
.any
(|(
stash
,
_
)|
stash
==
11
));
assert!
(
!
is_disabled
(
11
));
//
but
we are
still
forcing a new era
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
//
and
we are
not
forcing a new era
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
on_offence_in_era
(
&
[
OffenceDetails
{
...
...
@@ -2533,16 +2550,13 @@ fn slash_in_old_span_does_not_deselect() {
// NOTE: A 100% slash here would clean up the account, causing de-registration.
&
[
Perbill
::
from_percent
(
95
)],
1
,
DisableStrategy
::
WhenSlashed
,
);
// the validator doesn't get
chil
led again
// the validator doesn't get
disab
led again
assert!
(
Validators
::
<
Test
>
::
iter
()
.any
(|(
stash
,
_
)|
stash
==
11
));
// but it's disabled
assert!
(
is_disabled
(
11
));
// and we are still forcing a new era
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
ForceNew
);
assert!
(
!
is_disabled
(
11
));
// and we are still not forcing a new era
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
NotForcing
);
});
}
...
...
@@ -2671,7 +2685,7 @@ fn dont_slash_if_fraction_is_zero() {
// The validator hasn't been slashed. The new era is not forced.
assert_eq!
(
Balances
::
free_balance
(
11
),
1000
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
});
}
...
...
@@ -2692,7 +2706,7 @@ fn only_slash_for_max_in_era() {
// The validator has been slashed and has been force-chilled.
assert_eq!
(
Balances
::
free_balance
(
11
),
500
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Forc
eNew
);
assert_eq!
(
Staking
::
force_era
(),
Forcing
::
Not
Forc
ing
);
on_offence_now
(
&
[
OffenceDetails
{
...
...
@@ -2833,7 +2847,6 @@ fn slashing_nominators_by_span_max() {
}],
&
[
Perbill
::
from_percent
(
10
)],
2
,
DisableStrategy
::
WhenSlashed
,
);
assert_eq!
(
Balances
::
free_balance
(
11
),
900
);
...
...
@@ -2860,7 +2873,6 @@ fn slashing_nominators_by_span_max() {
}],
&
[
Perbill
::
from_percent
(
30
)],
3
,
DisableStrategy
::
WhenSlashed
,
);
// 11 was not further slashed, but 21 and 101 were.
...
...
@@ -2882,7 +2894,6 @@ fn slashing_nominators_by_span_max() {
}],
&
[
Perbill
::
from_percent
(
20
)],
2
,
DisableStrategy
::
WhenSlashed
,
);
// 11 was further slashed, but 21 and 101 were not.
...
...
@@ -2999,11 +3010,8 @@ fn deferred_slashes_are_deferred() {
assert!
(
matches!
(
staking_events_since_last_call
()
.as_slice
(),
&
[
Event
::
Chilled
{
stash
:
11
},
Event
::
ForceEra
{
mode
:
Forcing
::
ForceNew
},
Event
::
SlashReported
{
validator
:
11
,
slash_era
:
1
,
..
},
Event
::
StakersElected
,
Event
::
ForceEra
{
mode
:
Forcing
::
NotForcing
},
..
,
Event
::
Slashed
{
staker
:
11
,
amount
:
100
},
Event
::
Slashed
{
staker
:
101
,
amount
:
12
}
...
...
@@ -3029,7 +3037,6 @@ fn retroactive_deferred_slashes_two_eras_before() {
&
[
OffenceDetails
{
offender
:
(
11
,
exposure_11_at_era1
),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
10
)],
1
,
// should be deferred for two full eras, and applied at the beginning of era 4.
DisableStrategy
::
Never
,
);
mock
::
start_active_era
(
4
);
...
...
@@ -3037,8 +3044,6 @@ fn retroactive_deferred_slashes_two_eras_before() {
assert!
(
matches!
(
staking_events_since_last_call
()
.as_slice
(),
&
[
Event
::
Chilled
{
stash
:
11
},
Event
::
ForceEra
{
mode
:
Forcing
::
ForceNew
},
Event
::
SlashReported
{
validator
:
11
,
slash_era
:
1
,
..
},
..
,
Event
::
Slashed
{
staker
:
11
,
amount
:
100
},
...
...
@@ -3067,7 +3072,6 @@ fn retroactive_deferred_slashes_one_before() {
&
[
OffenceDetails
{
offender
:
(
11
,
exposure_11_at_era1
),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
10
)],
2
,
// should be deferred for two full eras, and applied at the beginning of era 5.
DisableStrategy
::
Never
,
);
mock
::
start_active_era
(
4
);
...
...
@@ -3197,7 +3201,6 @@ fn remove_deferred() {
&
[
OffenceDetails
{
offender
:
(
11
,
exposure
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
15
)],
1
,
DisableStrategy
::
WhenSlashed
,
);
// fails if empty
...
...
@@ -3312,9 +3315,15 @@ fn remove_multi_deferred() {
#[test]
fn
slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
]);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
,
51
,
201
,
202
]);
// pre-slash balance
assert_eq!
(
Balances
::
free_balance
(
11
),
1000
);
...
...
@@ -3340,8 +3349,6 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid
vec!
[
Event
::
StakersElected
,
Event
::
EraPaid
{
era_index
:
0
,
validator_payout
:
11075
,
remainder
:
33225
},
Event
::
Chilled
{
stash
:
11
},
Event
::
ForceEra
{
mode
:
Forcing
::
ForceNew
},
Event
::
SlashReported
{
validator
:
11
,
fraction
:
Perbill
::
from_percent
(
10
),
...
...
@@ -3357,8 +3364,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid
assert_eq!
(
Balances
::
free_balance
(
11
),
900
);
assert_eq!
(
Balances
::
free_balance
(
101
),
2000
-
nominator_slash_amount_11
);
// check that validator was
chil
led.
assert!
(
Validators
::
<
Test
>
::
iter
()
.all
(|(
stash
,
_
)|
stash
!=
11
));
// check that validator was
disab
led.
assert!
(
is_disabled
(
11
));
// actually re-bond the slashed validator
assert_ok!
(
Staking
::
validate
(
RuntimeOrigin
::
signed
(
11
),
Default
::
default
()));
...
...
@@ -3377,10 +3384,16 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid
}
#[test]
fn
non_slashable_offence_doesnt_disable_validator
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
fn
non_slashable_offence_disables_validator
()
{
ExtBuilder
::
default
()
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
]);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
,
51
,
201
,
202
]);
let
exposure_11
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
11
);
let
exposure_21
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
21
);
...
...
@@ -3408,14 +3421,11 @@ fn non_slashable_offence_doesnt_disable_validator() {
vec!
[
Event
::
StakersElected
,
Event
::
EraPaid
{
era_index
:
0
,
validator_payout
:
11075
,
remainder
:
33225
},
Event
::
Chilled
{
stash
:
11
},
Event
::
ForceEra
{
mode
:
Forcing
::
ForceNew
},
Event
::
SlashReported
{
validator
:
11
,
fraction
:
Perbill
::
from_percent
(
0
),
slash_era
:
1
},
Event
::
Chilled
{
stash
:
21
},
Event
::
SlashReported
{
validator
:
21
,
fraction
:
Perbill
::
from_percent
(
25
),
...
...
@@ -3426,41 +3436,43 @@ fn non_slashable_offence_doesnt_disable_validator() {
]
);
// the offence for validator 1
0
wasn't slashable
so
it
wasn't
disabled
assert!
(
!
is_disabled
(
11
));
//
whereas
validator 2
0
gets disabled
// the offence for validator 1
1
wasn't slashable
but
it
is
disabled
assert!
(
is_disabled
(
11
));
// validator 2
1
gets disabled
too
assert!
(
is_disabled
(
21
));
});
}
#[test]
fn
slashing_independent_of_disabling_validator
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
5
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
]);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
,
51
]);
let
exposure_11
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
11
);
let
exposure_21
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
21
);
let
now
=
Staking
::
active_era
()
.unwrap
()
.index
;
// offence with no slash associated
, BUT disabling
// offence with no slash associated
on_offence_in_era
(
&
[
OffenceDetails
{
offender
:
(
11
,
exposure_11
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
zero
()],
now
,
DisableStrategy
::
Always
,
);
// nomination remains untouched.
assert_eq!
(
Staking
::
nominators
(
101
)
.unwrap
()
.targets
,
vec!
[
11
,
21
]);
// offence that slashes 25% of the bond
, BUT not disabling
// offence that slashes 25% of the bond
on_offence_in_era
(
&
[
OffenceDetails
{
offender
:
(
21
,
exposure_21
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
25
)],
now
,
DisableStrategy
::
Never
,
);
// nomination remains untouched.
...
...
@@ -3471,14 +3483,11 @@ fn slashing_independent_of_disabling_validator() {
vec!
[
Event
::
StakersElected
,
Event
::
EraPaid
{
era_index
:
0
,
validator_payout
:
11075
,
remainder
:
33225
},
Event
::
Chilled
{
stash
:
11
},
Event
::
ForceEra
{
mode
:
Forcing
::
ForceNew
},
Event
::
SlashReported
{
validator
:
11
,
fraction
:
Perbill
::
from_percent
(
0
),
slash_era
:
1
},
Event
::
Chilled
{
stash
:
21
},
Event
::
SlashReported
{
validator
:
21
,
fraction
:
Perbill
::
from_percent
(
25
),
...
...
@@ -3489,15 +3498,15 @@ fn slashing_independent_of_disabling_validator() {
]
);
//
the offence for validator 10 was explicitly disabl
ed
//
first validator is disabled but not slash
ed
assert!
(
is_disabled
(
11
));
//
whereas
validator
21 is explicitly
not disabled
//
second
validator
is slashed but
not disabled
assert!
(
!
is_disabled
(
21
));
});
}
#[test]
fn
offence_threshold_trigger
s
_new_era
()
{
fn
offence_threshold_
doesnt_
trigger_new_era
()
{
ExtBuilder
::
default
()
.validator_count
(
4
)
.set_status
(
41
,
StakerStatus
::
Validator
)
...
...
@@ -3506,12 +3515,14 @@ fn offence_threshold_triggers_new_era() {
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
]);
assert_eq!
(
<
Test
as
Config
>
::
OffendingValidatorsThreshold
::
get
(),
Perbill
::
from_percent
(
75
),
UpToLimitDisablingStrategy
::
<
DISABLING_LIMIT_FACTOR
>
::
disable_limit
(
Session
::
validators
()
.len
()
),
1
);
// we have 4 validators and an offending validator threshold of
75%
,
//
once
the third validator commits an offence a new era should be forced
// we have 4 validators and an offending validator threshold of
1/3
,
//
even if
the third validator commits an offence a new era should
not
be forced
let
exposure_11
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
11
);
let
exposure_21
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
21
);
...
...
@@ -3522,6 +3533,9 @@ fn offence_threshold_triggers_new_era() {
&
[
Perbill
::
zero
()],
);
// 11 should be disabled because the byzantine threshold is 1
assert!
(
is_disabled
(
11
));
assert_eq!
(
ForceEra
::
<
Test
>
::
get
(),
Forcing
::
NotForcing
);
on_offence_now
(
...
...
@@ -3529,6 +3543,10 @@ fn offence_threshold_triggers_new_era() {
&
[
Perbill
::
zero
()],
);
// 21 should not be disabled because the number of disabled validators will be above the
// byzantine threshold
assert!
(
!
is_disabled
(
21
));
assert_eq!
(
ForceEra
::
<
Test
>
::
get
(),
Forcing
::
NotForcing
);
on_offence_now
(
...
...
@@ -3536,28 +3554,29 @@ fn offence_threshold_triggers_new_era() {
&
[
Perbill
::
zero
()],
);
assert_eq!
(
ForceEra
::
<
Test
>
::
get
(),
Forcing
::
ForceNew
);
// same for 31
assert!
(
!
is_disabled
(
31
));
assert_eq!
(
ForceEra
::
<
Test
>
::
get
(),
Forcing
::
NotForcing
);
});
}
#[test]
fn
disabled_validators_are_kept_disabled_for_whole_era
()
{
ExtBuilder
::
default
()
.validator_count
(
4
)
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
]);
assert_eq_uvec!
(
Session
::
validators
(),
vec!
[
11
,
21
,
31
,
41
,
51
,
201
,
202
]);
assert_eq!
(
<
Test
as
Config
>
::
SessionsPerEra
::
get
(),
3
);
let
exposure_11
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
11
);
let
exposure_21
=
Staking
::
eras_stakers
(
Staking
::
active_era
()
.unwrap
()
.index
,
&
21
);
on_offence_now
(
&
[
OffenceDetails
{
offender
:
(
11
,
exposure_11
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
zero
()],
);
on_offence_now
(
&
[
OffenceDetails
{
offender
:
(
21
,
exposure_21
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
25
)],
...
...
@@ -3566,18 +3585,15 @@ fn disabled_validators_are_kept_disabled_for_whole_era() {
// nominations are not updated.
assert_eq!
(
Staking
::
nominators
(
101
)
.unwrap
()
.targets
,
vec!
[
11
,
21
]);
// validator 11 should not be disabled since the offence wasn't slashable
assert!
(
!
is_disabled
(
11
));
// validator 21 gets disabled since it got slashed
assert!
(
is_disabled
(
21
));
advance_session
();
// disabled validators should carry-on through all sessions in the era
assert!
(
!
is_disabled
(
11
));
assert!
(
is_disabled
(
21
));
// validator 11
should now get disabled
// validator 11
commits an offence
on_offence_now
(
&
[
OffenceDetails
{
offender
:
(
11
,
exposure_11
.clone
()),
reporters
:
vec!
[]
}],
&
[
Perbill
::
from_percent
(
25
)],
...
...
@@ -3687,7 +3703,13 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() {
#[test]
fn
zero_slash_keeps_nominators
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
assert_eq!
(
Balances
::
free_balance
(
11
),
1000
);
...
...
@@ -3703,9 +3725,10 @@ fn zero_slash_keeps_nominators() {
assert_eq!
(
Balances
::
free_balance
(
11
),
1000
);
assert_eq!
(
Balances
::
free_balance
(
101
),
2000
);
// 11 is still removed..
assert!
(
Validators
::
<
Test
>
::
iter
()
.all
(|(
stash
,
_
)|
stash
!=
11
));
// but their nominations are kept.
// 11 is not removed but disabled
assert!
(
Validators
::
<
Test
>
::
iter
()
.any
(|(
stash
,
_
)|
stash
==
11
));
assert!
(
is_disabled
(
11
));
// and their nominations are kept.
assert_eq!
(
Staking
::
nominators
(
101
)
.unwrap
()
.targets
,
vec!
[
11
,
21
]);
});
}
...
...
@@ -4710,7 +4733,7 @@ fn offences_weight_calculated_correctly() {
let
zero_offence_weight
=
<
Test
as
frame_system
::
Config
>
::
DbWeight
::
get
()
.reads_writes
(
4
,
1
);
assert_eq!
(
Staking
::
on_offence
(
&
[],
&
[
Perbill
::
from_percent
(
50
)],
0
,
DisableStrategy
::
WhenSlashed
),
Staking
::
on_offence
(
&
[],
&
[
Perbill
::
from_percent
(
50
)],
0
),
zero_offence_weight
);
...
...
@@ -4735,7 +4758,6 @@ fn offences_weight_calculated_correctly() {
&
offenders
,
&
[
Perbill
::
from_percent
(
50
)],
0
,
DisableStrategy
::
WhenSlashed
),
n_offence_unapplied_weight
);
...
...
@@ -4765,7 +4787,6 @@ fn offences_weight_calculated_correctly() {
&
one_offender
,
&
[
Perbill
::
from_percent
(
50
)],
0
,
DisableStrategy
::
WhenSlashed
{}
),
one_offence_unapplied_weight
);
...
...
@@ -7011,7 +7032,13 @@ mod staking_unchecked {
#[test]
fn
virtual_nominators_are_lazily_slashed
()
{
ExtBuilder
::
default
()
.build_and_execute
(||
{
ExtBuilder
::
default
()
.validator_count
(
7
)
.set_status
(
41
,
StakerStatus
::
Validator
)
.set_status
(
51
,
StakerStatus
::
Validator
)
.set_status
(
201
,
StakerStatus
::
Validator
)
.set_status
(
202
,
StakerStatus
::
Validator
)
.build_and_execute
(||
{
mock
::
start_active_era
(
1
);
let
slash_percent
=
Perbill
::
from_percent
(
5
);
let
initial_exposure
=
Staking
::
eras_stakers
(
active_era
(),
&
11
);
...
...
@@ -7033,7 +7060,10 @@ mod staking_unchecked {
// 11 goes offline
on_offence_now
(
&
[
OffenceDetails
{
offender
:
(
11
,
initial_exposure
.clone
()),
reporters
:
vec!
[]
}],
&
[
OffenceDetails
{
offender
:
(
11
,
initial_exposure
.clone
()),
reporters
:
vec!
[],
}],
&
[
slash_percent
],
);
...
...
@@ -7926,3 +7956,69 @@ mod ledger_recovery {
})
}
}
mod
byzantine_threshold_disabling_strategy
{
use
crate
::{
tests
::
Test
,
ActiveEra
,
ActiveEraInfo
,
DisablingStrategy
,
UpToLimitDisablingStrategy
,
};
use
sp_staking
::
EraIndex
;
// Common test data - the stash of the offending validator, the era of the offence and the
// active set
const
OFFENDER_ID
:
<
Test
as
frame_system
::
Config
>
::
AccountId
=
7
;
const
SLASH_ERA
:
EraIndex
=
1
;
const
ACTIVE_SET
:
[
<
Test
as
pallet_session
::
Config
>
::
ValidatorId
;
7
]
=
[
1
,
2
,
3
,
4
,
5
,
6
,
7
];
const
OFFENDER_VALIDATOR_IDX
:
u32
=
6
;
// the offender is with index 6 in the active set
#[test]
fn
dont_disable_for_ancient_offence
()
{
sp_io
::
TestExternalities
::
default
()
.execute_with
(||
{
let
initially_disabled
=
vec!
[];
pallet_session
::
Validators
::
<
Test
>
::
put
(
ACTIVE_SET
.to_vec
());
ActiveEra
::
<
Test
>
::
put
(
ActiveEraInfo
{
index
:
2
,
start
:
None
});
let
disable_offender
=
<
UpToLimitDisablingStrategy
as
DisablingStrategy
<
Test
>>
::
decision
(
&
OFFENDER_ID
,
SLASH_ERA
,
&
initially_disabled
,
);
assert!
(
disable_offender
.is_none
());
});
}
#[test]
fn
dont_disable_beyond_byzantine_threshold
()
{
sp_io
::
TestExternalities
::
default
()
.execute_with
(||
{
let
initially_disabled
=
vec!
[
1
,
2
];
pallet_session
::
Validators
::
<
Test
>
::
put
(
ACTIVE_SET
.to_vec
());
let
disable_offender
=
<
UpToLimitDisablingStrategy
as
DisablingStrategy
<
Test
>>
::
decision
(
&
OFFENDER_ID
,
SLASH_ERA
,
&
initially_disabled
,
);
assert!
(
disable_offender
.is_none
());
});
}
#[test]
fn
disable_when_below_byzantine_threshold
()
{
sp_io
::
TestExternalities
::
default
()
.execute_with
(||
{
let
initially_disabled
=
vec!
[
1
];
pallet_session
::
Validators
::
<
Test
>
::
put
(
ACTIVE_SET
.to_vec
());
let
disable_offender
=
<
UpToLimitDisablingStrategy
as
DisablingStrategy
<
Test
>>
::
decision
(
&
OFFENDER_ID
,
SLASH_ERA
,
&
initially_disabled
,
);
assert_eq!
(
disable_offender
,
Some
(
OFFENDER_VALIDATOR_IDX
));
});
}
}
substrate/frame/support/procedural/src/runtime/expand/mod.rs
View file @
aceda465
...
...
@@ -244,7 +244,7 @@ fn construct_runtime_final_expansion(
// Prevent UncheckedExtrinsic to print unused warning.
const
_
:
()
=
{
#[allow(unused)]
type
__
h
idden
_use_of_u
nchecked
_e
xtrinsic
=
#
unchecked_extrinsic
;
type
__
H
idden
UseOfU
nchecked
E
xtrinsic
=
#
unchecked_extrinsic
;
};
#[derive(
...
...
substrate/frame/support/src/lib.rs
View file @
aceda465
...
...
@@ -2465,6 +2465,9 @@ pub mod pallet_macros {
/// Finally, the `RuntimeTask` can then used by a script or off-chain worker to create and
/// submit such tasks via an extrinsic defined in `frame_system` called `do_task`.
///
/// When submitted as unsigned transactions (for example via an off-chain workder), note
/// that the tasks will be executed in a random order.
///
/// ## Example
#[doc
=
docify::embed
!
(
"src/tests/tasks.rs"
,
tasks_example)]
/// Now, this can be executed as follows:
...
...
substrate/frame/support/src/traits/messages.rs
View file @
aceda465
...
...
@@ -46,6 +46,8 @@ pub enum ProcessMessageError {
/// the case that a queue is re-serviced within the same block after *yielding*. A queue is
/// not required to *yield* again when it is being re-serviced withing the same block.
Yield
,
/// The message could not be processed for reaching the stack depth limit.
StackLimitReached
,
}
/// Can process messages from a specific origin.
...
...
@@ -96,6 +98,8 @@ pub trait ServiceQueues {
/// - `weight_limit`: The maximum amount of dynamic weight that this call can use.
///
/// Returns the dynamic weight used by this call; is never greater than `weight_limit`.
/// Should only be called in top-level runtime entry points like `on_initialize` or `on_idle`.
/// Otherwise, stack depth limit errors may be miss-handled.
fn
service_queues
(
weight_limit
:
Weight
)
->
Weight
;
/// Executes a message that could not be executed by [`Self::service_queues()`] because it was
...
...
substrate/frame/support/src/traits/tasks.rs
View file @
aceda465
...
...
@@ -46,6 +46,10 @@ pub trait Task: Sized + FullCodec + TypeInfo + Clone + Debug + PartialEq + Eq {
fn
iter
()
->
Self
::
Enumeration
;
/// Checks if a particular instance of this `Task` variant is a valid piece of work.
///
/// This is used to validate tasks for unsigned execution. Hence, it MUST be cheap
/// with minimal to no storage reads. Else, it can make the blockchain vulnerable
/// to DoS attacks.
fn
is_valid
(
&
self
)
->
bool
;
/// Performs the work for this particular `Task` variant.
...
...
substrate/frame/support/src/traits/try_runtime/mod.rs
View file @
aceda465
...
...
@@ -161,22 +161,31 @@ impl<BlockNumber: Clone + sp_std::fmt::Debug + AtLeast32BitUnsigned> TryState<Bl
match
targets
{
Select
::
None
=>
Ok
(()),
Select
::
All
=>
{
let
mut
error_count
=
0
;
let
mut
errors
=
Vec
::
<
TryRuntimeError
>
::
new
();
for_tuples!
(
#
(
if
let
Err
(
_
)
=
Tuple
::
try_state
(
n
.clone
(),
targets
.clone
())
{
error
_count
+=
1
;
if
let
Err
(
err
)
=
Tuple
::
try_state
(
n
.clone
(),
targets
.clone
())
{
error
s
.push
(
err
)
;
}
)
*
);
if
error_count
>
0
{
if
!
errors
.is_empty
()
{
log
::
error!
(
target
:
"try-runtime"
,
"Detected errors while executing `try_state`:"
,
);
errors
.iter
()
.for_each
(|
err
|
{
log
::
error!
(
target
:
"try-runtime"
,
"{
} pallets exited with errors while executing try_state checks.
"
,
err
or_count
"{
:?}
"
,
err
);
});
return
Err
(
"Detected errors while executing try_state checks. See logs for more info."
"Detected errors while executing `try_state` checks. See logs for more
\
info."
.into
(),
)
}
...
...
substrate/frame/system/src/lib.rs
View file @
aceda465
...
...
@@ -741,9 +741,7 @@ pub mod pallet {
#[cfg(feature
=
"experimental"
)]
#[pallet::call_index(
8
)]
#[pallet::weight(task
.
weight())]
pub
fn
do_task
(
origin
:
OriginFor
<
T
>
,
task
:
T
::
RuntimeTask
)
->
DispatchResultWithPostInfo
{
ensure_signed
(
origin
)
?
;
pub
fn
do_task
(
_origin
:
OriginFor
<
T
>
,
task
:
T
::
RuntimeTask
)
->
DispatchResultWithPostInfo
{
if
!
task
.is_valid
()
{
return
Err
(
Error
::
<
T
>
::
InvalidTask
.into
())
}
...
...
@@ -1032,6 +1030,18 @@ pub mod pallet {
})
}
}
#[cfg(feature
=
"experimental"
)]
if
let
Call
::
do_task
{
ref
task
}
=
call
{
if
task
.is_valid
()
{
return
Ok
(
ValidTransaction
{
priority
:
u64
::
max_value
(),
requires
:
Vec
::
new
(),
provides
:
vec!
[
T
::
Hashing
::
hash_of
(
&
task
.encode
())
.as_ref
()
.to_vec
()],
longevity
:
TransactionLongevity
::
max_value
(),
propagate
:
true
,
})
}
}
Err
(
InvalidTransaction
::
Call
.into
())
}
}
...
...
substrate/primitives/consensus/beefy/src/commitment.rs
View file @
aceda465
...
...
@@ -19,8 +19,30 @@ use alloc::{vec, vec::Vec};
use
codec
::{
Decode
,
Encode
,
Error
,
Input
};
use
core
::
cmp
;
use
scale_info
::
TypeInfo
;
use
sp_application_crypto
::
RuntimeAppPublic
;
use
sp_runtime
::
traits
::
Hash
;
use
crate
::{
Payload
,
ValidatorSetId
};
use
crate
::{
BeefyAuthorityId
,
Payload
,
ValidatorSet
,
ValidatorSetId
};
/// A commitment signature, accompanied by the id of the validator that it belongs to.
#[derive(Debug)]
pub
struct
KnownSignature
<
TAuthorityId
,
TSignature
>
{
/// The signing validator.
pub
validator_id
:
TAuthorityId
,
/// The signature.
pub
signature
:
TSignature
,
}
impl
<
TAuthorityId
:
Clone
,
TSignature
:
Clone
>
KnownSignature
<&
TAuthorityId
,
&
TSignature
>
{
/// Creates a `KnownSignature<TAuthorityId, TSignature>` from an
/// `KnownSignature<&TAuthorityId, &TSignature>`.
pub
fn
to_owned
(
&
self
)
->
KnownSignature
<
TAuthorityId
,
TSignature
>
{
KnownSignature
{
validator_id
:
self
.validator_id
.clone
(),
signature
:
self
.signature
.clone
(),
}
}
}
/// A commitment signed by GRANDPA validators as part of BEEFY protocol.
///
...
...
@@ -113,9 +135,49 @@ impl<TBlockNumber: core::fmt::Debug, TSignature> core::fmt::Display
impl
<
TBlockNumber
,
TSignature
>
SignedCommitment
<
TBlockNumber
,
TSignature
>
{
/// Return the number of collected signatures.
pub
fn
no_of_
signature
s
(
&
self
)
->
usize
{
pub
fn
signature
_count
(
&
self
)
->
usize
{
self
.signatures
.iter
()
.filter
(|
x
|
x
.is_some
())
.count
()
}
/// Verify all the commitment signatures against the validator set that was active
/// at the block where the commitment was generated.
///
/// Returns the valid validator-signature pairs if the commitment can be verified.
pub
fn
verify_signatures
<
'a
,
TAuthorityId
,
MsgHash
>
(
&
'a
self
,
target_number
:
TBlockNumber
,
validator_set
:
&
'a
ValidatorSet
<
TAuthorityId
>
,
)
->
Result
<
Vec
<
KnownSignature
<&
'a
TAuthorityId
,
&
'a
TSignature
>>
,
u32
>
where
TBlockNumber
:
Clone
+
Encode
+
PartialEq
,
TAuthorityId
:
RuntimeAppPublic
<
Signature
=
TSignature
>
+
BeefyAuthorityId
<
MsgHash
>
,
MsgHash
:
Hash
,
{
if
self
.signatures
.len
()
!=
validator_set
.len
()
||
self
.commitment.validator_set_id
!=
validator_set
.id
()
||
self
.commitment.block_number
!=
target_number
{
return
Err
(
0
)
}
// Arrangement of signatures in the commitment should be in the same order
// as validators for that set.
let
encoded_commitment
=
self
.commitment
.encode
();
let
signatories
:
Vec
<
_
>
=
validator_set
.validators
()
.into_iter
()
.zip
(
self
.signatures
.iter
())
.filter_map
(|(
id
,
maybe_signature
)|
{
let
signature
=
maybe_signature
.as_ref
()
?
;
match
BeefyAuthorityId
::
verify
(
id
,
signature
,
&
encoded_commitment
)
{
true
=>
Some
(
KnownSignature
{
validator_id
:
id
,
signature
}),
false
=>
None
,
}
})
.collect
();
Ok
(
signatories
)
}
}
/// Type to be used to denote placement of signatures
...
...
@@ -439,13 +501,13 @@ mod tests {
commitment
,
signatures
:
vec!
[
None
,
None
,
Some
(
sigs
.0
),
Some
(
sigs
.1
)],
};
assert_eq!
(
signed
.
no_of_
signature
s
(),
2
);
assert_eq!
(
signed
.signature
_count
(),
2
);
// when
signed
.signatures
[
2
]
=
None
;
// then
assert_eq!
(
signed
.
no_of_
signature
s
(),
1
);
assert_eq!
(
signed
.signature
_count
(),
1
);
}
#[test]
...
...
substrate/primitives/consensus/beefy/src/lib.rs
View file @
aceda465
...
...
@@ -43,7 +43,7 @@ pub mod witness;
#[cfg(feature
=
"std"
)]
pub
mod
test_utils
;
pub
use
commitment
::{
Commitment
,
SignedCommitment
,
VersionedFinalityProof
};
pub
use
commitment
::{
Commitment
,
KnownSignature
,
SignedCommitment
,
VersionedFinalityProof
};
pub
use
payload
::{
known_payloads
,
BeefyPayloadId
,
Payload
,
PayloadProvider
};
use
alloc
::
vec
::
Vec
;
...
...
substrate/primitives/io/src/lib.rs
View file @
aceda465
...
...
@@ -182,7 +182,7 @@ impl From<MultiRemovalResults> for KillStorageResult {
pub
trait
Storage
{
/// Returns the data for `key` in the storage or `None` if the key can not be found.
fn
get
(
&
self
,
key
:
&
[
u8
])
->
Option
<
bytes
::
Bytes
>
{
self
.storage
(
key
)
.map
(
|
s
|
bytes
::
Bytes
::
from
(
s
.to_vec
())
)
self
.storage
(
key
)
.map
(
bytes
::
Bytes
::
from
)
}
/// Get `key` from storage, placing the value into `value_out` and return the number of
...
...
substrate/primitives/staking/src/offence.rs
View file @
aceda465
...
...
@@ -37,29 +37,6 @@ pub type Kind = [u8; 16];
/// so that we can slash it accordingly.
pub
type
OffenceCount
=
u32
;
/// In case of an offence, which conditions get an offending validator disabled.
#[derive(
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Encode,
Decode,
sp_runtime::RuntimeDebug,
scale_info::TypeInfo,
)]
pub
enum
DisableStrategy
{
/// Independently of slashing, this offence will not disable the offender.
Never
,
/// Only disable the offender if it is also slashed.
WhenSlashed
,
/// Independently of slashing, this offence will always disable the offender.
Always
,
}
/// A trait implemented by an offence report.
///
/// This trait assumes that the offence is legitimate and was validated already.
...
...
@@ -102,11 +79,6 @@ pub trait Offence<Offender> {
/// number. Note that for GRANDPA the round number is reset each epoch.
fn
time_slot
(
&
self
)
->
Self
::
TimeSlot
;
/// In which cases this offence needs to disable offenders until the next era starts.
fn
disable_strategy
(
&
self
)
->
DisableStrategy
{
DisableStrategy
::
WhenSlashed
}
/// A slash fraction of the total exposure that should be slashed for this
/// particular offence for the `offenders_count` that happened at a singular `TimeSlot`.
///
...
...
@@ -177,15 +149,12 @@ pub trait OnOffenceHandler<Reporter, Offender, Res> {
///
/// The `session` parameter is the session index of the offence.
///
/// The `disable_strategy` parameter decides if the offenders need to be disabled immediately.
///
/// The receiver might decide to not accept this offence. In this case, the call site is
/// responsible for queuing the report and re-submitting again.
fn
on_offence
(
offenders
:
&
[
OffenceDetails
<
Reporter
,
Offender
>
],
slash_fraction
:
&
[
Perbill
],
session
:
SessionIndex
,
disable_strategy
:
DisableStrategy
,
)
->
Res
;
}
...
...
@@ -194,7 +163,6 @@ impl<Reporter, Offender, Res: Default> OnOffenceHandler<Reporter, Offender, Res>
_offenders
:
&
[
OffenceDetails
<
Reporter
,
Offender
>
],
_slash_fraction
:
&
[
Perbill
],
_session
:
SessionIndex
,
_disable_strategy
:
DisableStrategy
,
)
->
Res
{
Default
::
default
()
}
...
...
substrate/utils/frame/remote-externalities/src/lib.rs
View file @
aceda465
...
...
@@ -830,16 +830,19 @@ where
child_prefix
:
StorageKey
,
at
:
B
::
Hash
,
)
->
Result
<
Vec
<
StorageKey
>
,
&
'static
str
>
{
// This is deprecated and will generate a warning which causes the CI to fail.
#[allow(warnings)]
let
child_keys
=
substrate_rpc_client
::
ChildStateApi
::
storage_keys
(
let
retry_strategy
=
FixedInterval
::
new
(
Self
::
KEYS_PAGE_RETRY_INTERVAL
)
.take
(
Self
::
MAX_RETRIES
);
let
get_child_keys_closure
=
||
{
#[allow(deprecated)]
substrate_rpc_client
::
ChildStateApi
::
storage_keys
(
client
,
PrefixedStorageKey
::
new
(
prefixed_top_key
.as_ref
()
.to_vec
()),
child_prefix
,
child_prefix
.clone
()
,
Some
(
at
),
)
.await
.map_err
(|
e
|
{
};
let
child_keys
=
Retry
::
spawn
(
retry_strategy
,
get_child_keys_closure
)
.await
.map_err
(|
e
|
{
error!
(
target
:
LOG_TARGET
,
"Error = {:?}"
,
e
);
"rpc child_get_keys failed."
})
?
;
...
...
substrate/utils/wasm-builder/src/builder.rs
View file @
aceda465
...
...
@@ -116,6 +116,39 @@ impl WasmBuilder {
WasmBuilderSelectProject
{
_ignore
:
()
}
}
/// Build the WASM binary using the recommended default values.
///
/// This is the same as calling:
/// ```no_run
/// substrate_wasm_builder::WasmBuilder::new()
/// .with_current_project()
/// .import_memory()
/// .export_heap_base()
/// .build();
/// ```
pub
fn
build_using_defaults
()
{
WasmBuilder
::
new
()
.with_current_project
()
.import_memory
()
.export_heap_base
()
.build
();
}
/// Init the wasm builder with the recommended default values.
///
/// In contrast to [`Self::build_using_defaults`] it does not build the WASM binary directly.
///
/// This is the same as calling:
/// ```no_run
/// substrate_wasm_builder::WasmBuilder::new()
/// .with_current_project()
/// .import_memory()
/// .export_heap_base();
/// ```
pub
fn
init_with_defaults
()
->
Self
{
WasmBuilder
::
new
()
.with_current_project
()
.import_memory
()
.export_heap_base
()
}
/// Enable exporting `__heap_base` as global variable in the WASM binary.
///
/// This adds `-Clink-arg=--export=__heap_base` to `RUST_FLAGS`.
...
...
substrate/utils/wasm-builder/src/lib.rs
View file @
aceda465
...
...
@@ -33,15 +33,9 @@
//! use substrate_wasm_builder::WasmBuilder;
//!
//! fn main() {
//! WasmBuilder::new()
//! // Tell the builder to build the project (crate) this `build.rs` is part of.
//! .with_current_project()
//! // Make sure to export the `heap_base` global, this is required by Substrate
//! .export_heap_base()
//! // Build the Wasm file so that it imports the memory (need to be provided by at instantiation)
//! .import_memory()
//! // Build it.
//! .build()
//! // Builds the WASM binary using the recommended defaults.
//! // If you need more control, you can call `new` or `init_with_defaults`.
//! WasmBuilder::build_using_defaults();
//! }
//! ```
//!
...
...
templates/minimal/runtime/build.rs
View file @
aceda465
...
...
@@ -18,10 +18,6 @@
fn
main
()
{
#[cfg(feature
=
"std"
)]
{
substrate_wasm_builder
::
WasmBuilder
::
new
()
.with_current_project
()
.export_heap_base
()
.import_memory
()
.build
();
substrate_wasm_builder
::
WasmBuilder
::
build_using_defaults
();
}
}
templates/parachain/runtime/build.rs
View file @
aceda465
#[cfg(feature
=
"std"
)]
fn
main
()
{
substrate_wasm_builder
::
WasmBuilder
::
new
()
.with_current_project
()
.export_heap_base
()
.import_memory
()
.build
()
substrate_wasm_builder
::
WasmBuilder
::
build_using_defaults
();
}
/// The wasm builder is deactivated when compiling
...
...
templates/parachain/runtime/src/configs/xcm_config.rs
View file @
aceda465
...
...
@@ -26,6 +26,8 @@ parameter_types! {
pub
const
RelayLocation
:
Location
=
Location
::
parent
();
pub
const
RelayNetwork
:
Option
<
NetworkId
>
=
None
;
pub
RelayChainOrigin
:
RuntimeOrigin
=
cumulus_pallet_xcm
::
Origin
::
Relay
.into
();
// For the real deployment, it is recommended to set `RelayNetwork` according to the relay chain
// and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`.
pub
UniversalLocation
:
InteriorLocation
=
Parachain
(
ParachainInfo
::
parachain_id
()
.into
())
.into
();
}
...
...
Prev
1
…
12
13
14
15
16
17
Next