-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Handling of disabled validators in backing subsystem #1259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 36 commits
800d8e5
936216d
7165ef9
24b5df5
eaca5ed
e4dee17
23023c4
8db76f5
e2846b2
8604b69
78afa76
9e39e58
0d0129c
23fbb41
91d1a8d
3d7efab
e68fa6a
5e7655f
c6bca9c
6fb4b7f
70dc6b6
bca3c83
f717d0b
2a5af89
2c53894
26866fa
a3bcb2f
863fc7d
c44093d
1e561e9
cf671f4
8807981
55f8e01
b5609e1
617e477
d7f4315
718f04b
275ce02
f2b17f1
7872f8f
3c89059
15b5069
96c1358
1a6648a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,6 +118,7 @@ use statement_table::{ | |
| }, | ||
| Config as TableConfig, Context as TableContextTrait, Table, | ||
| }; | ||
| use util::has_required_runtime; | ||
|
|
||
| mod error; | ||
|
|
||
|
|
@@ -383,6 +384,21 @@ struct TableContext { | |
| validator: Option<Validator>, | ||
| groups: HashMap<ParaId, Vec<ValidatorIndex>>, | ||
| validators: Vec<ValidatorId>, | ||
| disabled_validators: Vec<ValidatorIndex>, | ||
| } | ||
|
|
||
| impl TableContext { | ||
| // Returns `true` if the provided `ValidatorIndex` is in the disabled validators list | ||
| pub fn validator_is_disabled(&self, validator_idx: &ValidatorIndex) -> bool { | ||
| self.disabled_validators | ||
| .iter() | ||
| .any(|disabled_val_idx| *disabled_val_idx == *validator_idx) | ||
| } | ||
|
|
||
| // Returns `true` if the local validator is in the disabled validators list | ||
| pub fn local_validator_is_disabled(&self) -> Option<bool> { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to return Option ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I decided to return an |
||
| self.validator.as_ref().map(|v| v.disabled()) | ||
| } | ||
| } | ||
|
|
||
| impl TableContextTrait for TableContext { | ||
|
|
@@ -1010,21 +1026,50 @@ async fn construct_per_relay_parent_state<Context>( | |
| let minimum_backing_votes = | ||
| try_runtime_api!(request_min_backing_votes(parent, session_index, ctx.sender()).await); | ||
|
|
||
| // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 | ||
| // Once runtime ver `DISABLED_VALIDATORS_RUNTIME_REQUIREMENT` is released remove this `if` | ||
| // statement, add `request_from_runtime` call to the `try_join!` call above and use | ||
| // `try_runtime_api!` to get `disabled_validators` | ||
| let disabled_validators = if has_required_runtime( | ||
| ctx.sender(), | ||
| parent, | ||
| RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT, | ||
| ) | ||
| .await | ||
| { | ||
| let disabled_validators = request_from_runtime(parent, ctx.sender(), |tx| { | ||
| RuntimeApiRequest::DisabledValidators(tx) | ||
| }) | ||
| .await | ||
| .await | ||
| .map_err(Error::JoinMultiple)?; | ||
|
|
||
| let disabled_validators = try_runtime_api!(disabled_validators); | ||
| disabled_validators | ||
| } else { | ||
| gum::debug!(target: LOG_TARGET, "Runtime doesn't support `DisabledValidators` - continuing with an empty disabled validators set"); | ||
| vec![] | ||
| }; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code needs to stay until we release v8: #1940 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we extract that into subsystem-util or somewhere where statement-distribution and dispute-coordinator can reuse it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I was thinking about the same and I started working on it but against master. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went into a macro rabbit hole. I'll just extract this implementation here and finish the other version in a more appropriate time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, sounds good. However, I didn't mean to use a macro for that, just a regular function should be OK. |
||
| let signing_context = SigningContext { parent_hash: parent, session_index }; | ||
| let validator = | ||
| match Validator::construct(&validators, signing_context.clone(), keystore.clone()) { | ||
| Ok(v) => Some(v), | ||
| Err(util::Error::NotAValidator) => None, | ||
| Err(e) => { | ||
| gum::warn!( | ||
| target: LOG_TARGET, | ||
| err = ?e, | ||
| "Cannot participate in candidate backing", | ||
| ); | ||
| let validator = match Validator::construct( | ||
| &validators, | ||
| &disabled_validators, | ||
| signing_context.clone(), | ||
| keystore.clone(), | ||
| ) { | ||
| Ok(v) => Some(v), | ||
| Err(util::Error::NotAValidator) => None, | ||
| Err(e) => { | ||
| gum::warn!( | ||
| target: LOG_TARGET, | ||
| err = ?e, | ||
| "Cannot participate in candidate backing", | ||
| ); | ||
|
|
||
| return Ok(None) | ||
| }, | ||
| }; | ||
| return Ok(None) | ||
| }, | ||
| }; | ||
|
|
||
| let mut groups = HashMap::new(); | ||
| let n_cores = cores.len(); | ||
|
|
@@ -1054,7 +1099,7 @@ async fn construct_per_relay_parent_state<Context>( | |
| } | ||
| } | ||
|
|
||
| let table_context = TableContext { groups, validators, validator }; | ||
| let table_context = TableContext { validator, groups, validators, disabled_validators }; | ||
| let table_config = TableConfig { | ||
| allow_multiple_seconded: match mode { | ||
| ProspectiveParachainsMode::Enabled { .. } => true, | ||
|
|
@@ -1728,6 +1773,19 @@ async fn kick_off_validation_work<Context>( | |
| background_validation_tx: &mpsc::Sender<(Hash, ValidatedCandidateCommand)>, | ||
| attesting: AttestingData, | ||
| ) -> Result<(), Error> { | ||
| // Do nothing if the local validator is disabled or not a validator at all | ||
| match rp_state.table_context.local_validator_is_disabled() { | ||
| Some(true) => { | ||
| gum::debug!(target: LOG_TARGET, "We are disabled - don't kick off validation"); | ||
tdimitrov marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return Ok(()) | ||
| }, | ||
| Some(false) => {}, // we are not disabled - move on | ||
| None => { | ||
| gum::debug!(target: LOG_TARGET, "We are not a validator - don't kick off validation"); | ||
| return Ok(()) | ||
| }, | ||
| } | ||
|
|
||
| let candidate_hash = attesting.candidate.hash(); | ||
| if rp_state.issued_statements.contains(&candidate_hash) { | ||
| return Ok(()) | ||
|
|
@@ -1785,6 +1843,16 @@ async fn maybe_validate_and_import<Context>( | |
| }, | ||
| }; | ||
|
|
||
| // Don't import statement if the sender is disabled | ||
| if rp_state.table_context.validator_is_disabled(&statement.validator_index()) { | ||
| gum::debug!( | ||
| target: LOG_TARGET, | ||
| sender_validator_idx = ?statement.validator_index(), | ||
| "Not importing statement because the sender is disabled" | ||
| ); | ||
| return Ok(()) | ||
| } | ||
|
|
||
| let res = import_statement(ctx, rp_state, &mut state.per_candidate, &statement).await; | ||
|
|
||
| // if we get an Error::RejectedByProspectiveParachains, | ||
|
|
@@ -1946,6 +2014,13 @@ async fn handle_second_message<Context>( | |
| Some(r) => r, | ||
| }; | ||
|
|
||
| // Just return if the local validator is disabled. If we are here the local node should be a | ||
| // validator but defensively use `unwrap_or(false)` to continue processing in this case. | ||
| if rp_state.table_context.local_validator_is_disabled().unwrap_or(false) { | ||
| gum::warn!(target: LOG_TARGET, "Local validator is disabled. Don't validate and second"); | ||
| return Ok(()) | ||
| } | ||
|
|
||
| // Sanity check that candidate is from our assignment. | ||
| if Some(candidate.descriptor().para_id) != rp_state.assignment { | ||
| gum::debug!( | ||
|
|
@@ -1992,6 +2067,7 @@ async fn handle_statement_message<Context>( | |
| ) -> Result<(), Error> { | ||
| let _timer = metrics.time_process_statement(); | ||
|
|
||
| // Validator disabling is handled in `maybe_validate_and_import` | ||
| match maybe_validate_and_import(ctx, state, relay_parent, statement).await { | ||
| Err(Error::ValidationFailed(_)) => Ok(()), | ||
| Err(e) => Err(e), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.