mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 07:41:08 +00:00
Offchain Phragmén BREAKING. (#4517)
* Initial skeleton for offchain phragmen * Basic compact encoding decoding for results * add compact files * Bring back Self::ensure_storage_upgraded(); * Make staking use compact stuff. * First seemingly working version of reduce, full of todos * Everything phragmen related works again. * Signing made easier, still issues. * Signing from offchain compile fine 😎 * make compact work with staked asssignment * Evaluation basics are in place. * Move reduce into crate. Document stuff * move reduce into no_std * Add files * Remove other std deps. Runtime compiles * Seemingly it is al stable; cycle implemented but not integrated. * Add fuzzing code. * Cleanup reduce a bit more. * a metric ton of tests for staking; wip 🔨 * Implement a lot more of the tests. * wip getting the unsigned stuff to work * A bit gleanup for unsigned debug * Clean and finalize compact code. * Document reduce. * Still problems with signing * We officaly duct taped the transaction submission stuff. 🤓 * Deadlock with keys again * Runtime builds * Unsigned test works 🙌 * Some cleanups * Make all the tests compile and stuff * Minor cleanup * fix more merge stuff * Most tests work again. * a very nasty bug in reduce * Fix all integrations * Fix more todos * Revamp everything and everything * Remove bogus test * Some review grumbles. * Some fixes * Fix doc test * loop for submission * Fix cli, keyring etc. * some cleanup * Fix staking tests again * fix per-things; bring patches from benchmarking * better score prediction * Add fuzzer, more patches. * Some fixes * More docs * Remove unused generics * Remove max-nominator footgun * Better fuzzer * Disable it ❌ * Bump. * Another round of self-review * Refactor a lot * More major fixes in perThing * Add new fuzz file * Update lock * fix fuzzing code. * Fix nominator retain test * Add slashing check * Update frame/staking/src/tests.rs Co-Authored-By: Joshy Orndorff <JoshOrndorff@users.noreply.github.com> * Some formatting nits * Review comments. * Fix cargo file * Almost all tests work again * Update frame/staking/src/tests.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Fix review comments * More review stuff * Some nits * Fix new staking / session / babe relation * Update primitives/phragmen/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Update primitives/phragmen/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Update primitives/phragmen/compact/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Some doc updates to slashing * Fix derive * Remove imports * Remove unimplemented tests * nits * Remove dbg * Better fuzzing params * Remove unused pref map * Deferred Slashing/Offence for offchain Phragmen (#5151) * Some boilerplate * Add test * One more test * Review comments * Fix build * review comments * fix more * fix build * Some cleanups and self-reviews * More minor self reviews * Final nits * Some merge fixes. * opt comment * Fix build * Fix build again. * Update frame/staking/fuzz/fuzz_targets/submit_solution.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Update frame/staking/src/slashing.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Update frame/staking/src/offchain_election.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Fix review comments * fix test * === 🔑 Revamp without staking key. * final round of changes. * Fix cargo-deny * Update frame/staking/src/lib.rs Co-Authored-By: Gavin Wood <gavin@parity.io> Co-authored-by: Joshy Orndorff <JoshOrndorff@users.noreply.github.com> Co-authored-by: thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
@@ -26,11 +26,12 @@ mod tests;
|
||||
|
||||
use sp_std::vec::Vec;
|
||||
use frame_support::{
|
||||
decl_module, decl_event, decl_storage, Parameter,
|
||||
decl_module, decl_event, decl_storage, Parameter, debug,
|
||||
weights::{Weight, SimpleDispatchInfo, WeighData},
|
||||
};
|
||||
use sp_runtime::traits::Hash;
|
||||
use sp_runtime::{traits::Hash, Perbill};
|
||||
use sp_staking::{
|
||||
SessionIndex,
|
||||
offence::{Offence, ReportOffence, Kind, OnOffenceHandler, OffenceDetails, OffenceError},
|
||||
};
|
||||
use codec::{Encode, Decode};
|
||||
@@ -42,6 +43,13 @@ type OpaqueTimeSlot = Vec<u8>;
|
||||
/// A type alias for a report identifier.
|
||||
type ReportIdOf<T> = <T as frame_system::Trait>::Hash;
|
||||
|
||||
/// Type of data stored as a deferred offence
|
||||
type DeferredOffenceOf<T> = (
|
||||
Vec<OffenceDetails<<T as frame_system::Trait>::AccountId, <T as Trait>::IdentificationTuple>>,
|
||||
Vec<Perbill>,
|
||||
SessionIndex,
|
||||
);
|
||||
|
||||
/// Offences trait
|
||||
pub trait Trait: frame_system::Trait {
|
||||
/// The overarching event type.
|
||||
@@ -59,6 +67,10 @@ decl_storage! {
|
||||
map hasher(twox_64_concat) ReportIdOf<T>
|
||||
=> Option<OffenceDetails<T::AccountId, T::IdentificationTuple>>;
|
||||
|
||||
/// Deferred reports that have been rejected by the offence handler and need to be submitted
|
||||
/// at a later time.
|
||||
DeferredOffences get(deferred_offences): Vec<DeferredOffenceOf<T>>;
|
||||
|
||||
/// A vector of reports of the same kind that happened at the same time slot.
|
||||
ConcurrentReportsIndex:
|
||||
double_map hasher(twox_64_concat) Kind, hasher(twox_64_concat) OpaqueTimeSlot
|
||||
@@ -77,13 +89,13 @@ decl_storage! {
|
||||
decl_event!(
|
||||
pub enum Event {
|
||||
/// There is an offence reported of the given `kind` happened at the `session_index` and
|
||||
/// (kind-specific) time slot. This event is not deposited for duplicate slashes.
|
||||
Offence(Kind, OpaqueTimeSlot),
|
||||
/// (kind-specific) time slot. This event is not deposited for duplicate slashes. last
|
||||
/// element indicates of the offence was applied (true) or queued (false).
|
||||
Offence(Kind, OpaqueTimeSlot, bool),
|
||||
}
|
||||
);
|
||||
|
||||
decl_module! {
|
||||
/// Offences module, currently just responsible for taking offence reports.
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn deposit_event() = default;
|
||||
|
||||
@@ -94,6 +106,27 @@ decl_module! {
|
||||
|
||||
SimpleDispatchInfo::default().weigh_data(())
|
||||
}
|
||||
|
||||
fn on_initialize(now: T::BlockNumber) -> Weight {
|
||||
// only decode storage if we can actually submit anything again.
|
||||
if T::OnOffenceHandler::can_report() {
|
||||
<DeferredOffences<T>>::mutate(|deferred| {
|
||||
// keep those that fail to be reported again. An error log is emitted here; this
|
||||
// should not happen if staking's `can_report` is implemented properly.
|
||||
deferred.retain(|(o, p, s)| {
|
||||
T::OnOffenceHandler::on_offence(&o, &p, *s).map_err(|_| {
|
||||
debug::native::error!(
|
||||
target: "pallet-offences",
|
||||
"re-submitting a deferred slash returned Err at {}. This should not happen with pallet-staking",
|
||||
now,
|
||||
);
|
||||
}).is_err()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
SimpleDispatchInfo::default().weigh_data(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,9 +152,6 @@ where
|
||||
None => return Err(OffenceError::DuplicateReport),
|
||||
};
|
||||
|
||||
// Deposit the event.
|
||||
Self::deposit_event(Event::Offence(O::ID, time_slot.encode()));
|
||||
|
||||
let offenders_count = concurrent_offenders.len() as u32;
|
||||
|
||||
// The amount new offenders are slashed
|
||||
@@ -130,17 +160,42 @@ where
|
||||
let slash_perbill: Vec<_> = (0..concurrent_offenders.len())
|
||||
.map(|_| new_fraction.clone()).collect();
|
||||
|
||||
T::OnOffenceHandler::on_offence(
|
||||
let applied = Self::report_or_store_offence(
|
||||
&concurrent_offenders,
|
||||
&slash_perbill,
|
||||
offence.session_index(),
|
||||
);
|
||||
|
||||
// Deposit the event.
|
||||
Self::deposit_event(Event::Offence(O::ID, time_slot.encode(), applied));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Trait> Module<T> {
|
||||
/// Tries (without checking) to report an offence. Stores them in [`DeferredOffences`] in case
|
||||
/// it fails. Returns false in case it has to store the offence.
|
||||
fn report_or_store_offence(
|
||||
concurrent_offenders: &[OffenceDetails<T::AccountId, T::IdentificationTuple>],
|
||||
slash_perbill: &[Perbill],
|
||||
session_index: SessionIndex,
|
||||
) -> bool {
|
||||
match T::OnOffenceHandler::on_offence(
|
||||
&concurrent_offenders,
|
||||
&slash_perbill,
|
||||
session_index,
|
||||
) {
|
||||
Ok(_) => true,
|
||||
Err(_) => {
|
||||
<DeferredOffences<T>>::mutate(|d|
|
||||
d.push((concurrent_offenders.to_vec(), slash_perbill.to_vec(), session_index))
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the ID for the given report properties.
|
||||
///
|
||||
/// The report id depends on the offence kind, time slot and the id of offender.
|
||||
|
||||
@@ -43,6 +43,7 @@ pub struct OnOffenceHandler;
|
||||
|
||||
thread_local! {
|
||||
pub static ON_OFFENCE_PERBILL: RefCell<Vec<Perbill>> = RefCell::new(Default::default());
|
||||
pub static CAN_REPORT: RefCell<bool> = RefCell::new(true);
|
||||
}
|
||||
|
||||
impl<Reporter, Offender> offence::OnOffenceHandler<Reporter, Offender> for OnOffenceHandler {
|
||||
@@ -50,11 +51,25 @@ impl<Reporter, Offender> offence::OnOffenceHandler<Reporter, Offender> for OnOff
|
||||
_offenders: &[OffenceDetails<Reporter, Offender>],
|
||||
slash_fraction: &[Perbill],
|
||||
_offence_session: SessionIndex,
|
||||
) {
|
||||
ON_OFFENCE_PERBILL.with(|f| {
|
||||
*f.borrow_mut() = slash_fraction.to_vec();
|
||||
});
|
||||
) -> Result<(), ()> {
|
||||
if <Self as offence::OnOffenceHandler<Reporter, Offender>>::can_report() {
|
||||
ON_OFFENCE_PERBILL.with(|f| {
|
||||
*f.borrow_mut() = slash_fraction.to_vec();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn can_report() -> bool {
|
||||
CAN_REPORT.with(|c| *c.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_can_report(can_report: bool) {
|
||||
CAN_REPORT.with(|c| *c.borrow_mut() = can_report);
|
||||
}
|
||||
|
||||
pub fn with_on_offence_fractions<R, F: FnOnce(&mut Vec<Perbill>) -> R>(f: F) -> R {
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
Offences, System, Offence, TestEvent, KIND, new_test_ext, with_on_offence_fractions,
|
||||
offence_reports,
|
||||
offence_reports, set_can_report,
|
||||
};
|
||||
use sp_runtime::Perbill;
|
||||
use frame_support::traits::OnInitialize;
|
||||
use frame_system::{EventRecord, Phase};
|
||||
|
||||
#[test]
|
||||
@@ -130,7 +131,7 @@ fn should_deposit_event() {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::offences(crate::Event::Offence(KIND, time_slot.encode())),
|
||||
event: TestEvent::offences(crate::Event::Offence(KIND, time_slot.encode(), true)),
|
||||
topics: vec![],
|
||||
}]
|
||||
);
|
||||
@@ -165,7 +166,7 @@ fn doesnt_deposit_event_for_dups() {
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::offences(crate::Event::Offence(KIND, time_slot.encode())),
|
||||
event: TestEvent::offences(crate::Event::Offence(KIND, time_slot.encode(), true)),
|
||||
topics: vec![],
|
||||
}]
|
||||
);
|
||||
@@ -212,3 +213,54 @@ fn should_properly_count_offences() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_queue_and_resubmit_rejected_offence() {
|
||||
new_test_ext().execute_with(|| {
|
||||
set_can_report(false);
|
||||
|
||||
// will get deferred
|
||||
let offence = Offence {
|
||||
validator_set_count: 5,
|
||||
time_slot: 42,
|
||||
offenders: vec![5],
|
||||
};
|
||||
Offences::report_offence(vec![], offence).unwrap();
|
||||
assert_eq!(Offences::deferred_offences().len(), 1);
|
||||
// event also indicates unapplied.
|
||||
assert_eq!(
|
||||
System::events(),
|
||||
vec![EventRecord {
|
||||
phase: Phase::Initialization,
|
||||
event: TestEvent::offences(crate::Event::Offence(KIND, 42u128.encode(), false)),
|
||||
topics: vec![],
|
||||
}]
|
||||
);
|
||||
|
||||
// will not dequeue
|
||||
Offences::on_initialize(2);
|
||||
|
||||
// again
|
||||
let offence = Offence {
|
||||
validator_set_count: 5,
|
||||
time_slot: 62,
|
||||
offenders: vec![5],
|
||||
};
|
||||
Offences::report_offence(vec![], offence).unwrap();
|
||||
assert_eq!(Offences::deferred_offences().len(), 2);
|
||||
|
||||
set_can_report(true);
|
||||
|
||||
// can be submitted
|
||||
let offence = Offence {
|
||||
validator_set_count: 5,
|
||||
time_slot: 72,
|
||||
offenders: vec![5],
|
||||
};
|
||||
Offences::report_offence(vec![], offence).unwrap();
|
||||
assert_eq!(Offences::deferred_offences().len(), 2);
|
||||
|
||||
Offences::on_initialize(3);
|
||||
assert_eq!(Offences::deferred_offences().len(), 0);
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user