mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 06:21:11 +00:00
Elastic scaling: use an assumed CoreIndex in candidate-backing (#3229)
First step in implementing https://github.com/paritytech/polkadot-sdk/issues/3144 ### Summary of changes - switch statement `Table` candidate mapping from `ParaId` to `CoreIndex` - introduce experimental `InjectCoreIndex` node feature. - determine and assume a `CoreIndex` for a candidate based on statement validator index. If the signature is valid it means validator controls the validator that index and we can easily map it to a validator group/core. - introduce a temporary provisioner fix until we fully enable elastic scaling in the subystem. The fix ensures we don't fetch the same backable candidate when calling `get_backable_candidate` for each core. TODO: - [x] fix backing tests - [x] fix statement table tests - [x] add new test --------- Signed-off-by: Andrei Sandu <andrei-mihail@parity.io> Signed-off-by: alindima <alin@parity.io> Co-authored-by: alindima <alin@parity.io>
This commit is contained in:
@@ -36,6 +36,7 @@ use primitives::{
|
||||
};
|
||||
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
const LOG_TARGET: &str = "parachain::statement-table";
|
||||
|
||||
/// Context for the statement table.
|
||||
pub trait Context {
|
||||
@@ -53,9 +54,6 @@ pub trait Context {
|
||||
/// get the digest of a candidate.
|
||||
fn candidate_digest(candidate: &Self::Candidate) -> Self::Digest;
|
||||
|
||||
/// get the group of a candidate.
|
||||
fn candidate_group(candidate: &Self::Candidate) -> Self::GroupId;
|
||||
|
||||
/// Whether a authority is a member of a group.
|
||||
/// Members are meant to submit candidates and vote on validity.
|
||||
fn is_member_of(&self, authority: &Self::AuthorityId, group: &Self::GroupId) -> bool;
|
||||
@@ -342,13 +340,13 @@ impl<Ctx: Context> Table<Ctx> {
|
||||
pub fn import_statement(
|
||||
&mut self,
|
||||
context: &Ctx,
|
||||
group_id: Ctx::GroupId,
|
||||
statement: SignedStatement<Ctx::Candidate, Ctx::Digest, Ctx::AuthorityId, Ctx::Signature>,
|
||||
) -> Option<Summary<Ctx::Digest, Ctx::GroupId>> {
|
||||
let SignedStatement { statement, signature, sender: signer } = statement;
|
||||
|
||||
let res = match statement {
|
||||
Statement::Seconded(candidate) =>
|
||||
self.import_candidate(context, signer.clone(), candidate, signature),
|
||||
self.import_candidate(context, signer.clone(), candidate, signature, group_id),
|
||||
Statement::Valid(digest) =>
|
||||
self.validity_vote(context, signer.clone(), digest, ValidityVote::Valid(signature)),
|
||||
};
|
||||
@@ -387,9 +385,10 @@ impl<Ctx: Context> Table<Ctx> {
|
||||
authority: Ctx::AuthorityId,
|
||||
candidate: Ctx::Candidate,
|
||||
signature: Ctx::Signature,
|
||||
group: Ctx::GroupId,
|
||||
) -> ImportResult<Ctx> {
|
||||
let group = Ctx::candidate_group(&candidate);
|
||||
if !context.is_member_of(&authority, &group) {
|
||||
gum::debug!(target: LOG_TARGET, authority = ?authority, group = ?group, "New `Misbehavior::UnauthorizedStatement`, candidate backed by validator that doesn't belong to expected group" );
|
||||
return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement {
|
||||
statement: SignedStatement {
|
||||
signature,
|
||||
@@ -634,10 +633,6 @@ mod tests {
|
||||
Digest(candidate.1)
|
||||
}
|
||||
|
||||
fn candidate_group(candidate: &Candidate) -> GroupId {
|
||||
GroupId(candidate.0)
|
||||
}
|
||||
|
||||
fn is_member_of(&self, authority: &AuthorityId, group: &GroupId) -> bool {
|
||||
self.authorities.get(authority).map(|v| v == group).unwrap_or(false)
|
||||
}
|
||||
@@ -675,10 +670,10 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, statement_a);
|
||||
table.import_statement(&context, GroupId(2), statement_a);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
|
||||
table.import_statement(&context, statement_b);
|
||||
table.import_statement(&context, GroupId(2), statement_b);
|
||||
assert_eq!(
|
||||
table.detected_misbehavior[&AuthorityId(1)][0],
|
||||
Misbehavior::MultipleCandidates(MultipleCandidates {
|
||||
@@ -711,10 +706,10 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, statement_a);
|
||||
table.import_statement(&context, GroupId(2), statement_a);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
|
||||
table.import_statement(&context, statement_b);
|
||||
table.import_statement(&context, GroupId(2), statement_b);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
}
|
||||
|
||||
@@ -735,7 +730,7 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, statement);
|
||||
table.import_statement(&context, GroupId(2), statement);
|
||||
|
||||
assert_eq!(
|
||||
table.detected_misbehavior[&AuthorityId(1)][0],
|
||||
@@ -769,7 +764,7 @@ mod tests {
|
||||
};
|
||||
let candidate_a_digest = Digest(100);
|
||||
|
||||
table.import_statement(&context, candidate_a);
|
||||
table.import_statement(&context, GroupId(2), candidate_a);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
|
||||
|
||||
@@ -779,7 +774,7 @@ mod tests {
|
||||
signature: Signature(2),
|
||||
sender: AuthorityId(2),
|
||||
};
|
||||
table.import_statement(&context, bad_validity_vote);
|
||||
table.import_statement(&context, GroupId(3), bad_validity_vote);
|
||||
|
||||
assert_eq!(
|
||||
table.detected_misbehavior[&AuthorityId(2)][0],
|
||||
@@ -811,7 +806,7 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, statement);
|
||||
table.import_statement(&context, GroupId(2), statement);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
|
||||
let invalid_statement = SignedStatement {
|
||||
@@ -820,7 +815,7 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, invalid_statement);
|
||||
table.import_statement(&context, GroupId(2), invalid_statement);
|
||||
assert!(table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
}
|
||||
|
||||
@@ -842,7 +837,7 @@ mod tests {
|
||||
};
|
||||
let candidate_digest = Digest(100);
|
||||
|
||||
table.import_statement(&context, statement);
|
||||
table.import_statement(&context, GroupId(2), statement);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
|
||||
let extra_vote = SignedStatement {
|
||||
@@ -851,7 +846,7 @@ mod tests {
|
||||
sender: AuthorityId(1),
|
||||
};
|
||||
|
||||
table.import_statement(&context, extra_vote);
|
||||
table.import_statement(&context, GroupId(2), extra_vote);
|
||||
assert_eq!(
|
||||
table.detected_misbehavior[&AuthorityId(1)][0],
|
||||
Misbehavior::ValidityDoubleVote(ValidityDoubleVote::IssuedAndValidity(
|
||||
@@ -910,7 +905,7 @@ mod tests {
|
||||
};
|
||||
let candidate_digest = Digest(100);
|
||||
|
||||
table.import_statement(&context, statement);
|
||||
table.import_statement(&context, GroupId(2), statement);
|
||||
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
assert!(table.attested_candidate(&candidate_digest, &context, 2).is_none());
|
||||
@@ -921,7 +916,7 @@ mod tests {
|
||||
sender: AuthorityId(2),
|
||||
};
|
||||
|
||||
table.import_statement(&context, vote);
|
||||
table.import_statement(&context, GroupId(2), vote);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
|
||||
assert!(table.attested_candidate(&candidate_digest, &context, 2).is_some());
|
||||
}
|
||||
@@ -944,7 +939,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let summary = table
|
||||
.import_statement(&context, statement)
|
||||
.import_statement(&context, GroupId(2), statement)
|
||||
.expect("candidate import to give summary");
|
||||
|
||||
assert_eq!(summary.candidate, Digest(100));
|
||||
@@ -971,7 +966,7 @@ mod tests {
|
||||
};
|
||||
let candidate_digest = Digest(100);
|
||||
|
||||
table.import_statement(&context, statement);
|
||||
table.import_statement(&context, GroupId(2), statement);
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
|
||||
|
||||
let vote = SignedStatement {
|
||||
@@ -980,8 +975,9 @@ mod tests {
|
||||
sender: AuthorityId(2),
|
||||
};
|
||||
|
||||
let summary =
|
||||
table.import_statement(&context, vote).expect("candidate vote to give summary");
|
||||
let summary = table
|
||||
.import_statement(&context, GroupId(2), vote)
|
||||
.expect("candidate vote to give summary");
|
||||
|
||||
assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ pub use generic::{Config, Context, Table};
|
||||
pub mod v2 {
|
||||
use crate::generic;
|
||||
use primitives::{
|
||||
CandidateHash, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement, Id,
|
||||
ValidatorIndex, ValidatorSignature,
|
||||
CandidateHash, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement,
|
||||
CoreIndex, ValidatorIndex, ValidatorSignature,
|
||||
};
|
||||
|
||||
/// Statements about candidates on the network.
|
||||
@@ -59,7 +59,7 @@ pub mod v2 {
|
||||
>;
|
||||
|
||||
/// A summary of import of a statement.
|
||||
pub type Summary = generic::Summary<CandidateHash, Id>;
|
||||
pub type Summary = generic::Summary<CandidateHash, CoreIndex>;
|
||||
|
||||
impl<'a> From<&'a Statement> for PrimitiveStatement {
|
||||
fn from(s: &'a Statement) -> PrimitiveStatement {
|
||||
|
||||
Reference in New Issue
Block a user