mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 21:17:56 +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:
@@ -0,0 +1,287 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! (very) Basic implementation of a graph node used in the reduce algorithm.
|
||||
|
||||
use sp_runtime::RuntimeDebug;
|
||||
use sp_std::{cell::RefCell, fmt, prelude::*, rc::Rc};
|
||||
|
||||
/// The role that a node can accept.
|
||||
#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, RuntimeDebug)]
|
||||
pub(crate) enum NodeRole {
|
||||
/// A voter. This is synonym to a nominator in a staking context.
|
||||
Voter,
|
||||
/// A target. This is synonym to a candidate/validator in a staking context.
|
||||
Target,
|
||||
}
|
||||
|
||||
pub(crate) type RefCellOf<T> = Rc<RefCell<T>>;
|
||||
pub(crate) type NodeRef<A> = RefCellOf<Node<A>>;
|
||||
|
||||
/// Identifier of a node. This is particularly handy to have a proper `PartialEq` implementation.
|
||||
/// Otherwise, self votes wouldn't have been indistinguishable.
|
||||
#[derive(PartialOrd, Ord, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct NodeId<A> {
|
||||
/// An account-like identifier representing the node.
|
||||
pub who: A,
|
||||
/// The role of the node.
|
||||
pub role: NodeRole,
|
||||
}
|
||||
|
||||
impl<A> NodeId<A> {
|
||||
/// Create a new [`NodeId`].
|
||||
pub fn from(who: A, role: NodeRole) -> Self {
|
||||
Self { who, role }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<A: fmt::Debug> sp_std::fmt::Debug for NodeId<A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> sp_std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Node({:?}, {:?})",
|
||||
self.who,
|
||||
if self.role == NodeRole::Voter {
|
||||
"V"
|
||||
} else {
|
||||
"T"
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A one-way graph note. This can only store a pointer to its parent.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Node<A> {
|
||||
/// The identifier of the note.
|
||||
pub(crate) id: NodeId<A>,
|
||||
/// The parent pointer.
|
||||
pub(crate) parent: Option<NodeRef<A>>,
|
||||
}
|
||||
|
||||
impl<A: PartialEq> PartialEq for Node<A> {
|
||||
fn eq(&self, other: &Node<A>) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: PartialEq> Eq for Node<A> {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<A: fmt::Debug + Clone> fmt::Debug for Node<A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"({:?} --> {:?})",
|
||||
self.id,
|
||||
self.parent.as_ref().map(|p| p.borrow().id.clone())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: PartialEq + Eq + Clone + fmt::Debug> Node<A> {
|
||||
/// Create a new [`Node`]
|
||||
pub fn new(id: NodeId<A>) -> Node<A> {
|
||||
Self { id, parent: None }
|
||||
}
|
||||
|
||||
/// Returns true if `other` is the parent of `who`.
|
||||
pub fn is_parent_of(who: &NodeRef<A>, other: &NodeRef<A>) -> bool {
|
||||
if who.borrow().parent.is_none() {
|
||||
return false;
|
||||
}
|
||||
who.borrow().parent.as_ref() == Some(other)
|
||||
}
|
||||
|
||||
/// Removes the parent of `who`.
|
||||
pub fn remove_parent(who: &NodeRef<A>) {
|
||||
who.borrow_mut().parent = None;
|
||||
}
|
||||
|
||||
/// Sets `who`'s parent to be `parent`.
|
||||
pub fn set_parent_of(who: &NodeRef<A>, parent: &NodeRef<A>) {
|
||||
who.borrow_mut().parent = Some(parent.clone());
|
||||
}
|
||||
|
||||
/// Finds the root of `start`. It return a tuple of `(root, root_vec)` where `root_vec` is the
|
||||
/// vector of Nodes leading to the root. Hence the first element is the start itself and the
|
||||
/// last one is the root. As convenient, the root itself is also returned as the first element
|
||||
/// of the tuple.
|
||||
///
|
||||
/// This function detects cycles and breaks as soon a duplicate node is visited, returning the
|
||||
/// cycle up to but not including the duplicate node.
|
||||
///
|
||||
/// If you are certain that no cycles exist, you can use [`root_unchecked`].
|
||||
pub fn root(start: &NodeRef<A>) -> (NodeRef<A>, Vec<NodeRef<A>>) {
|
||||
let mut parent_path: Vec<NodeRef<A>> = Vec::new();
|
||||
let mut visited: Vec<NodeRef<A>> = Vec::new();
|
||||
|
||||
parent_path.push(start.clone());
|
||||
visited.push(start.clone());
|
||||
let mut current = start.clone();
|
||||
|
||||
while let Some(ref next_parent) = current.clone().borrow().parent {
|
||||
if visited.contains(next_parent) {
|
||||
break;
|
||||
}
|
||||
parent_path.push(next_parent.clone());
|
||||
current = next_parent.clone();
|
||||
visited.push(current.clone());
|
||||
}
|
||||
|
||||
(current, parent_path)
|
||||
}
|
||||
|
||||
/// Consumes self and wraps it in a `Rc<RefCell<T>>`. This type can be used as the pointer type
|
||||
/// to a parent node.
|
||||
pub fn into_ref(self) -> NodeRef<A> {
|
||||
Rc::from(RefCell::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn id(i: u32) -> NodeId<u32> {
|
||||
NodeId::from(i, NodeRole::Target)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_create_works() {
|
||||
let node = Node::new(id(10));
|
||||
assert_eq!(
|
||||
node,
|
||||
Node {
|
||||
id: NodeId {
|
||||
who: 10,
|
||||
role: NodeRole::Target
|
||||
},
|
||||
parent: None
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_parent_works() {
|
||||
let a = Node::new(id(10)).into_ref();
|
||||
let b = Node::new(id(20)).into_ref();
|
||||
|
||||
assert_eq!(a.borrow().parent, None);
|
||||
Node::set_parent_of(&a, &b);
|
||||
assert_eq!(*a.borrow().parent.as_ref().unwrap(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_singular() {
|
||||
let a = Node::new(id(1)).into_ref();
|
||||
assert_eq!(Node::root(&a), (a.clone(), vec![a.clone()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_works() {
|
||||
// D <-- A <-- B <-- C
|
||||
// \
|
||||
// <-- E
|
||||
let a = Node::new(id(1)).into_ref();
|
||||
let b = Node::new(id(2)).into_ref();
|
||||
let c = Node::new(id(3)).into_ref();
|
||||
let d = Node::new(id(4)).into_ref();
|
||||
let e = Node::new(id(5)).into_ref();
|
||||
let f = Node::new(id(6)).into_ref();
|
||||
|
||||
Node::set_parent_of(&c, &b);
|
||||
Node::set_parent_of(&b, &a);
|
||||
Node::set_parent_of(&e, &a);
|
||||
Node::set_parent_of(&a, &d);
|
||||
|
||||
assert_eq!(
|
||||
Node::root(&e),
|
||||
(d.clone(), vec![e.clone(), a.clone(), d.clone()]),
|
||||
);
|
||||
|
||||
assert_eq!(Node::root(&a), (d.clone(), vec![a.clone(), d.clone()]),);
|
||||
|
||||
assert_eq!(
|
||||
Node::root(&c),
|
||||
(d.clone(), vec![c.clone(), b.clone(), a.clone(), d.clone()]),
|
||||
);
|
||||
|
||||
// D A <-- B <-- C
|
||||
// F <-- / \
|
||||
// <-- E
|
||||
Node::set_parent_of(&a, &f);
|
||||
|
||||
assert_eq!(Node::root(&a), (f.clone(), vec![a.clone(), f.clone()]),);
|
||||
|
||||
assert_eq!(
|
||||
Node::root(&c),
|
||||
(f.clone(), vec![c.clone(), b.clone(), a.clone(), f.clone()]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_on_cycle() {
|
||||
// A ---> B
|
||||
// | |
|
||||
// <---- C
|
||||
let a = Node::new(id(1)).into_ref();
|
||||
let b = Node::new(id(2)).into_ref();
|
||||
let c = Node::new(id(3)).into_ref();
|
||||
|
||||
Node::set_parent_of(&a, &b);
|
||||
Node::set_parent_of(&b, &c);
|
||||
Node::set_parent_of(&c, &a);
|
||||
|
||||
let (root, path) = Node::root(&a);
|
||||
assert_eq!(root, c);
|
||||
assert_eq!(path.clone(), vec![a.clone(), b.clone(), c.clone()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_root_on_cycle_2() {
|
||||
// A ---> B
|
||||
// | | |
|
||||
// - C
|
||||
let a = Node::new(id(1)).into_ref();
|
||||
let b = Node::new(id(2)).into_ref();
|
||||
let c = Node::new(id(3)).into_ref();
|
||||
|
||||
Node::set_parent_of(&a, &b);
|
||||
Node::set_parent_of(&b, &c);
|
||||
Node::set_parent_of(&c, &b);
|
||||
|
||||
let (root, path) = Node::root(&a);
|
||||
assert_eq!(root, c);
|
||||
assert_eq!(path.clone(), vec![a.clone(), b.clone(), c.clone()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn node_cmp_stack_overflows_on_non_unique_elements() {
|
||||
// To make sure we don't stack overflow on duplicate who. This needs manual impl of
|
||||
// PartialEq.
|
||||
let a = Node::new(id(1)).into_ref();
|
||||
let b = Node::new(id(2)).into_ref();
|
||||
let c = Node::new(id(3)).into_ref();
|
||||
|
||||
Node::set_parent_of(&a, &b);
|
||||
Node::set_parent_of(&b, &c);
|
||||
Node::set_parent_of(&c, &a);
|
||||
|
||||
Node::root(&a);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user