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

paras_inherent: reject only candidates with concluded disputes #3969

Merged
merged 2 commits into from
Sep 29, 2021

Conversation

ordian
Copy link
Member

@ordian ordian commented Sep 29, 2021

Triggers Error::<T>::CandidateConcludedInvalid (formerly Error::<T>::CandidateCouldBeInvalid) only if the dispute already has an AGAINST_SUPERMAJORITY. In other cases the dispute (and reverting) can still be handled later when needed.

@ordian ordian 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. D5-nicetohaveaudit ⚠️ PR contains trivial changes to logic that should be properly reviewed. labels Sep 29, 2021
@@ -238,14 +238,14 @@ pub mod pallet {
let backed_candidates = limit_backed_candidates::<T>(backed_candidates);
let backed_candidates_len = backed_candidates.len() as Weight;

// Refuse to back any candidates that are disputed or invalid.
// Refuse to back any candidates that were disputed and are concluded invalid.
for candidate in &backed_candidates {
ensure!(
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the point of this check in the first place. Candidates can only be disputed once included, so how can a candidate be disputed before it is even backed? I mean obviously because of a fake dispute, but in a legit way?

Copy link
Member

@eskimor eskimor Sep 29, 2021

Choose a reason for hiding this comment

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

Answering my own question - in theory via forks. Candidate is about to be backed on two forks, one is faster - where it gets backed and included and disputed, while the backing did not even happen on the other fork - especially with chain reversions/reorgs and such that could actually happen. The check is still not needed, I think, because if it gets backed, it will get included, then checked by approval voters and disputed again - correct?

Just testing my understanding here.... It could help with avoiding potential endless loops, any other motivation?

Copy link
Member

Choose a reason for hiding this comment

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

Avoiding endless loops is a good one, just curious whether I am missing something else.

Copy link
Member

@eskimor eskimor Sep 29, 2021

Choose a reason for hiding this comment

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

Ok, I should think more before I type: I actually think this can not happen at all. The disputes are recorded in chain state. So for a candidate to be disputed and considered for being backed it must have a relay parent that either is the block that contained the dispute or some later block. Even in the case of a chain reversion, the presence of the dispute, rules out the existence of such a candidate. As the dispute must have happened in one of the parents (even if transplanted), but if that's the case then the relay parent of the candidate cannot be the current head, as the dispute can not have happened for a candidate with a relay parent that has not existed yet - that's just not possible.

Candidate x with relay_parent: A

Relay Parent A: |Relay parent containing dispute for candidate x| 

How?!

Copy link
Member

Choose a reason for hiding this comment

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

Talking to myself again: It could happen in the future, with contextual execution, then the relay parent of a candidate can be older. 💡 Which makes me realize, we should be really careful with contextual execution...

Copy link
Contributor

@rphmeier rphmeier Sep 29, 2021

Choose a reason for hiding this comment

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

I don't understand the point of this check in the first place. Candidates can only be disputed once included, so how can a candidate be disputed before it is even backed? I mean obviously because of a fake dispute, but in a legit way?

It's the entire point of remote disputes. Typical flow:

B1[C1 backed] <- B2[C1 included] <- B3[C1 disputed]
      |
      | (B2 reverted)
      |
       \>  B2'[C1 disputed and dropped]

An adversary with a few block authors could withhold a small chain and wait for the reversion to successfully back the bad block unless this check is respected:

B1[C1 backed] <- B2[C1 included] <- B3[C1 disputed]
      |
      | (B2 reverted)
      |
      |
B1'[withheld by adversary until dispute]  <- B2''[C1 disputed] <- B3''[C1 backed]

This would land B3'' in an impossible state where C1 has already been disputed and cannot be disputed again.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks @rphmeier for those really useful illustrations! Ok, I understand that we need to drop an already backed candidate in case we find it disputed, but isn't the above code just dropping candidates that enter backing state in this very block? Like, in my understanding the enter function gets called with inherents of the currently imported block.

If that is the case then B3''[C1 backed] with the meaning that C1 gets backed in this block cannot exist as C1 would need to have B2'' as relay parent which already contained the dispute of C1, therefore C1 cannot have B2'' as relay parent. In fact the relay parent of C1 must be B0 (common ancestor of both B1' and B1). (B1'[witheld by adversary until dispute] must had C1 already backed, the adversary cannot just transplant a candidate to a later block as then the relay parent would not match)

My reasoning is based on the assumption that a candidate must be based on the relay parent right before the block where it is backed, which reflects my current understanding of things 🤔 .

Copy link
Member

Choose a reason for hiding this comment

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

Which is indeed ensured:

candidate.descriptor().relay_parent == parent_hash,

Copy link
Contributor

Choose a reason for hiding this comment

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

@eskimor Good point on the relay parent. The current code would still be affected if B1'[C1 disputed, C1 backed] if we assume that B1 and B1' have the same parent B0

Copy link
Member

Choose a reason for hiding this comment

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

Uuh, because disputes are imported before candidates - so disputes of the current block will be already available in the state, regardless of being added in the same block. 💡 Got it, thanks!

@rphmeier rphmeier merged commit d33794f into master Sep 29, 2021
@rphmeier rphmeier deleted the ao-disputes-against-supermajority-inherent branch September 29, 2021 18:58
ordian added a commit that referenced this pull request Sep 30, 2021
* master: (52 commits)
  Companion for substrate PR#9890 (#3961)
  Bump version, tx_version and spec_version in prep for v0.9.11 (#3970)
  Fix master compilation (#3977)
  Make most XCM APIs accept an Into<MultiLocation> where MultiLocation is accepted (#3627)
  fix disputes tests (#3974)
  Drop availability only for candidates that lose disputes (#3973)
  revert +1 change to be on the safer side (#3972)
  paras_inherent: reject only candidates with concluded disputes (#3969)
  feat: measured oneshots (#3902)
  remove `AllSubsystems` and `AllSubsystemsGen` types (#3874)
  Companion for Substrate#9867 (#3938)
  Substrate Companion for #9552 (#3834)
  CI: run disputes tests (#3962)
  Bump parity-scale-codec from 2.3.0 to 2.3.1 (#3959)
  approval-voting: populate session cache in advance (#3954)
  Bump libc from 0.2.102 to 0.2.103 (#3950)
  fix master (#3955)
  Docker files chore (#3880)
  Bump nix from 0.19.1 to 0.20.0 (#3587)
  remove connected disconnected state, 3rd attempt (#3898)
  ...
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. D5-nicetohaveaudit ⚠️ PR contains trivial changes to logic that should be properly reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants