-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Generic authorship and uncle inclusion module #2941
Conversation
@demimarie-parity Opinions on whether this is using inherent digests as you intended as well as compatibility with #2929 would be appreciated along with general review. @dvc94ch Thoughts on #2949 w.r.t. your other session refactorings? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very good. I have not reviewed the tests yet, but the only suggestions are trivial.
/// A filter on uncles which verifies seals and does no additional checks. | ||
/// This is well-suited to consensus modes such as PoW where the cost of | ||
/// equivocating is high. | ||
pub struct SealVerify<T>(rstd::marker::PhantomData<T>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub struct SealVerify<T>(rstd::marker::PhantomData<T>); | |
pub struct OnlySealVerify<T>(rstd::marker::PhantomData<T>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought for a moment of naming it something like this, but every piece of code implicitly should only do what it says on the tin. So I think it's redundant to call it that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good point. That said, it might be a good idea to include Only
as a warning.
pub struct SealVerify<T>(rstd::marker::PhantomData<T>); | ||
|
||
impl<Header, Author, T: VerifySeal<Header, Author>> FilterUncle<Header, Author> | ||
for SealVerify<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for SealVerify<T> | |
for OnlySealVerify<T> |
return Err("uncle not recent enough to be included"); | ||
} | ||
|
||
let duplicate = uncles.iter().find(|entry| match entry { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a very efficient data structure. Can we use a better one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The uncles list or a variant thereof is decent enough for tracking garbage to collect. Maybe not ideal for scanning against duplicates. We could shift the actual data into a map of Hash -> bool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then the main question is (given that in the code here we have the whole uncles list in contiguous memory) how much slower/faster the trie access to query the map is going to be vs. doing this iteration (for in practice, what is typically less than 50 elements and probably less than 20).
We could also construct a BTreeSet<Hash>
or something from the uncles list and then query that. It might be well faster than doing the few iterations. On the other hand, maybe not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we need to load/store this every time, then an array is definitely faster. On the other hand, if this is loaded once and then accessed many times, I would go with a BTreeSet
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also requires T::Hash: Ord
, which isn't currently a bound on system::Trait
. Let's consider this future optimization.
Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>
Pushed a commit to cover an index-based variant of #2949 as well. The idea is that BABE/Aura/other consensus tells us the index of the author in the canonical list of validators. |
srml/authorship/src/lib.rs
Outdated
fn note_uncle(author: Author, age: BlockNumber); | ||
} | ||
|
||
impl<A, B> EventHandler<A, B> for () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use for_each_tuple!
like for example the session module does?
* generalized uncle processing * add some uncle tests * set author and do event handling * OnePerAuthorPerHeight no longer O(n^2) and test * bump impl_version of node * Documentation and style fixes Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com> * fix paritytech#2949: index-based FindAuthor wrapper for srml-session * use for_each_tuple
This module aims to make an author available to runtime modules in order to query. It does so in a way which intends to be used with the inherent digest abstraction: consensus engines will implement a
FindAuthor
trait for extracting an author ID from a block header. This will probably have to coupled with a specialFindAuthor
wrapper forSession
, which converts from validator indices to account IDs (#2949)It also manages a set of uncles (from up to configurable number of blocks back) and handles import of them. Generation of the
Authorship::set_uncles
inherent is not currently done in this PR. Extra care has to be taken about importing uncles in a PoS scenario because of the possibility of an unbounded number of equivocations. This PR includes an uncle inclusion filter for mitigating that.TODO:
SessionFindAuthor
wrapper