Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Include a reference to the validation data in the candidate descriptor#1442

Merged
rphmeier merged 15 commits intomasterfrom
rh-validation-data
Jul 23, 2020
Merged

Include a reference to the validation data in the candidate descriptor#1442
rphmeier merged 15 commits intomasterfrom
rh-validation-data

Conversation

@rphmeier
Copy link
Contributor

While implementing the candidate validation subsystem in #1432, one of the deeper issues that's gone mostly unnoticed finally bubbled up to the surface.

The wrinkle started with this question: "How does the CandidateBackingSubsystem know which OccupiedCoreAssumption to make?". From the existing CandidateDescriptor struct, it wasn't clear how you were supposed to tell, once given a candidate, whether it assumed that the occupied core at the head of the chain had timed out or was free. Ignoring the case when the para was not occupying any core, as there is no choice on parameters.

There was also another issue floating around my head for a bit: if we want to eventually report bad candidates to the chain which were never actually included, we'll need the candidate descriptor to cryptographically reference all parameters to the validation function.

So this change satisfies both of those issues. I'm planning to answer the first question with a little bit of a side-step by doing it in CandidateValidation instead. What we'll do is be aware of the corresponding validation_data_hash for each of the two choices (TimedOut and Included) and compare against the validation_data_hash of the descriptor we've been asked to validate. If it's neither of those, then we'll return a ValidationFailed variant.

We might also return a ValidationResult::Invalid, although it is unclear how the dispute would actually resolve without heavily depending on state of the relay_parent remaining available - if the validation_data_hash references valid parameters to the validation function, just not those that are expected at the relay_parent, then as soon as the state data goes out of scope for the relay_parent on most validators, how can you tell if the candidate is indeed good or bad?

@rphmeier rphmeier added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. labels Jul 21, 2020
@rphmeier
Copy link
Contributor Author

What we'll do is be aware of the corresponding validation_data_hash for each of the two choices (TimedOut and Included) and compare against the validation_data_hash of the descriptor we've been asked to validate. If it's neither of those, then we'll return a ValidationFailed variant.

I expanded on this in 4530c51

@rphmeier rphmeier mentioned this pull request Jul 22, 2020
3 tasks
Comment on lines -64 to +72
) -> [u8; 68] {
) -> [u8; 100] {
// 32-byte hash length is protected in a test below.
let mut payload = [0u8; 68];
let mut payload = [0u8; 100];

payload[0..32].copy_from_slice(relay_parent.as_ref());
u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
payload[36..68].copy_from_slice(pov_hash.as_ref());
payload[36..68].copy_from_slice(validation_data_hash.as_ref());
payload[68..100].copy_from_slice(pov_hash.as_ref());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These numeric literals feel ripe for extraction into constants. Alternately, would SCALE do the right thing with (relay_parent.as_ref(), validation_data_hash.as_ref(), pov_hash.as_ref()).encode()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would, and maybe this is premature optimization, but I wanted to do this on the stack as this is called within the runtime and allocations might be expensive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why specifically would constants help here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(let's address this as follow-on, since the status quo is "no constants")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working on the stack is a plausible reason to copy from slices instead of using higher-level methods.

Constants help because they make typos into compiler errors. Contrast these approaches:

payload[0..32].copy_from_slice(relay_parent.as_ref());
u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
payload[36..68].copy_from_slice(pov_hash.as_ref());
payload[36..68].copy_from_slice(validation_data_hash.as_ref());
payload[66..100].copy_from_slice(pov_hash.as_ref()); // subtle bug which will panic
payload[0..PARA_ID].copy_from_slice(relay_parent.as_ref());
u32::from(*para_id).using_encoded(|s| payload[PARA_ID..PARA_ID + s.len()].copy_from_slice(s));
payload[POV_HASH..VALIDATION_DATA_HASH].copy_from_slice(pov_hash.as_ref());
payload[VALIDATION_DATA_HASH..POV_HASH].copy_from_slice(validation_data_hash.as_ref());
payload[POV_HASH..FINAL_SIZE].copy_from_slice(pov_hash.as_ref());

A reasonable test suite would catch the panic in this case, but that's not true in every situation. It just feels like a good practice to name applicable numeric constants and magic numbers instead of typing them by hand all the time.

Copy link
Contributor Author

@rphmeier rphmeier Jul 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also just as easily mess up the definition of POV_HASH. It doesn't guarantee anything except that when an offset is used twice, it's not mis-typed the second time.

I am in favor of extracting literals to constants when they are not hyper-localized. If there is a constant that an entire module needs to make use of, then it doesn't make sense to use a literal. But this is hyper-localized code within a single function that is less than 10 lines of implementation.

Copy link
Contributor

@drahnr drahnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @coriolinus already covered all major points, everything else is nitpicks from my side.

@drahnr drahnr self-requested a review July 23, 2020 13:58
@rphmeier rphmeier merged commit cce0a95 into master Jul 23, 2020
@rphmeier rphmeier deleted the rh-validation-data branch July 23, 2020 19:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants