-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Cleaner GRANDPA RPC API for proving finality #7339
Conversation
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.
Looks to be going in the right direction :)
pub(crate) fn get_set_id(&self, number: N) -> (u64, N) { | ||
let set_id = self | ||
.authority_set_changes | ||
.binary_search(&number) |
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 know I suggested not storing the set_id and instead implicitly figuring out by the position in the array. The only disadvantage of this approach is that it breaks for nodes that didn't sync from scratch with this code. I guess it might be better to store the set_id
explicitly. Additionally in the future we might start syncing from a specific checkpoint (rather from genesis always) or we may warp sync, in both cases we won't import all blocks.
// Tracks authority set changes. We store the block numbers for the last block of each authority | ||
// set. | ||
#[derive(Debug, Encode, Decode)] | ||
pub(crate) struct AuthoritySetChanges<N> { |
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.
Maybe this can go inside AuthoritySet
? We will always be operating on both at the same time, i.e. when we finalize something from AuthoritySet
is also when we update this.
Think this is probably ready for another round of feedback now, and finished enough to be upgraded from draft to PR Most things have been reworked according to feedback from previous versions, as well as #7546 landing in master gives us a lot more freedom in changing |
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.
lgtm ty
bot merge |
Trying merge. |
Merge failed: |
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.
LGTM as far as I understand it :P
let err = format!( | ||
"AuthoritySetChanges does not cover the requested block #{}. \ | ||
Maybe the subscription API is more appropriate.", | ||
block, | ||
); | ||
trace!(target: "afg", "{}", &err); |
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.
let err = format!( | |
"AuthoritySetChanges does not cover the requested block #{}. \ | |
Maybe the subscription API is more appropriate.", | |
block, | |
); | |
trace!(target: "afg", "{}", &err); | |
trace!( | |
target: "afg", | |
"AuthoritySetChanges does not cover the requested block #{}. \ | |
Maybe the subscription API is more appropriate.", | |
block, | |
); |
trace!( | ||
target: "afg", | ||
"Encountered new authorities when collecting unknown headers. \ | ||
Returning empty proof" |
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.
Returning empty proof" | |
Returning empty proof", |
fn decode<I: Input>(value: &mut I) -> Result<Self, parity_scale_codec::Error> { | ||
let legacy = LegacyAuthoritySet::decode(value)?; | ||
let authority_set_changes = match <AuthoritySetChanges<N>>::decode(value) { | ||
Ok(v) => v, | ||
Err(_) => AuthoritySetChanges::empty(), | ||
}; |
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.
Where is this decode being used @andresilva ?
If someone uses this where there is still data in I
, this could lead to decoding shit :P
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.
Currently it's only used through this https://github.com/paritytech/substrate/blob/master/client/finality-grandpa/src/aux_schema.rs#L110, so I don't think it is ever decoded as part of a bigger structure (i.e. there is no more data to decode). It would be nice that we don't have a footgun here though, do you have any suggestion?
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.
Maybe we should offer some migration? So, that we only apply this once? But I assume we don't have any way to store a version in aux?
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.
Besides that, I don't have better ideas.
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 was already not remembering the aux_schema
code for GRANDPA. We indeed do have a version there and we have code there that handles migrations of GRANDPA data. So yeah, we should definitely handle this the same way.
@@ -631,6 +689,45 @@ impl<H, N: Add<Output=N> + Clone> PendingChange<H, N> { | |||
} | |||
} | |||
|
|||
// Tracks historical authority set changes. We store the block numbers for the first block of each | |||
// authority set, once they have been finalalized. |
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.
// authority set, once they have been finalalized. | |
// authority set, once they have been finalized. |
// To make sure we have the right set we need to check that the one before it also exists. | ||
if idx > 0 { | ||
let (prev_set_id, _) = self.0[idx - 1usize]; | ||
if set_id != prev_set_id + 1u64 { |
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.
How can that fail? Wouldn't that mean that the entire object is wrong?
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.
Yeah pretty much, if this happens the object is missing authority set changes and something must have gone wrong applying changes. It's my understanding that this can't happen, but I'm not certain enough of that to omit this check ... @andresilva what do you think?
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.
We wanted to fail gracefully for nodes that will migrate to this and therefore won't have all set ids stored here (only when they sync from scratch), the only check that's really needed for this is the first one idx < self.0.len()
. These checks don't hurt but they can be removed since they would imply that this data structure skipped set ids spuriously which is wrong.
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.
@octol LegacyAuthoritySet
should be moved to aux_schema.rs
and renamed to V2AuthoritySet
. The CURRENT_VERSION
const there should be incremented and a method migration_from_version2
should be added (and then called from load_persistent
). This method will read all remaining GRANDPA structures as they are but decode the authority set as V2AuthoritySet
and then return the regular AuthoritySet
(with AuthoritySetChanges::empty()
).
Sorry for not suggesting this earlier but I didn't remember that we already had migration code for auxiliary GRANDPA data.
Oh thanks, yeah that will make it much better! |
Pushed a new commit that implements the migration logic as suggested by @andresilva |
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.
LGTM, thanks!
There were conflicts in |
bot merge |
Waiting for commit status. |
Checks failed; merge aborted. |
bot merge |
Waiting for commit status. |
Implements #7115 as in the description, with the exception that the RPC call takes block numbers instead of block hashes
polkadot companion: paritytech/polkadot#2100
TODO:
Store block numbers in aux_schemaAuthoritySet
insteadDecode
forAuthoritySet
for compatibilityfinality_proof.rs
now that the light client isn't using it anymoreFix: prove finality with the last block of the set failsFinalityProofFragment
with something more tailored for this use case?