mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 00:31:07 +00:00
Make sure to preserve backing votes (#6382)
* Guide updates * Consider more dead forks. * Ensure backing votes don't get overridden. * Fix spelling. * Fix comments. * Update node/primitives/src/lib.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> Co-authored-by: eskimor <eskimor@no-such-url.com> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io>
This commit is contained in:
@@ -14,7 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::collections::{
|
||||
btree_map::{Entry as Bentry, Keys as Bkeys},
|
||||
BTreeMap, BTreeSet,
|
||||
};
|
||||
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
|
||||
@@ -49,7 +52,7 @@ pub struct CandidateVotes {
|
||||
/// The receipt of the candidate itself.
|
||||
pub candidate_receipt: CandidateReceipt,
|
||||
/// Votes of validity, sorted by validator index.
|
||||
pub valid: BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)>,
|
||||
pub valid: ValidCandidateVotes,
|
||||
/// Votes of invalidity, sorted by validator index.
|
||||
pub invalid: BTreeMap<ValidatorIndex, (InvalidDisputeStatementKind, ValidatorSignature)>,
|
||||
}
|
||||
@@ -69,6 +72,99 @@ impl CandidateVotes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Valid candidate votes.
|
||||
///
|
||||
/// Prefere backing votes over other votes.
|
||||
pub struct ValidCandidateVotes {
|
||||
votes: BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)>,
|
||||
}
|
||||
|
||||
impl ValidCandidateVotes {
|
||||
/// Create new empty `ValidCandidateVotes`
|
||||
pub fn new() -> Self {
|
||||
Self { votes: BTreeMap::new() }
|
||||
}
|
||||
/// Insert a vote, replacing any already existing vote.
|
||||
///
|
||||
/// Except, for backing votes: Backing votes are always kept, and will never get overridden.
|
||||
/// Import of other king of `valid` votes, will be ignored if a backing vote is already
|
||||
/// present. Any already existing `valid` vote, will be overridden by any given backing vote.
|
||||
///
|
||||
/// Returns: true, if the insert had any effect.
|
||||
pub fn insert_vote(
|
||||
&mut self,
|
||||
validator_index: ValidatorIndex,
|
||||
kind: ValidDisputeStatementKind,
|
||||
sig: ValidatorSignature,
|
||||
) -> bool {
|
||||
match self.votes.entry(validator_index) {
|
||||
Bentry::Vacant(vacant) => {
|
||||
vacant.insert((kind, sig));
|
||||
true
|
||||
},
|
||||
Bentry::Occupied(mut occupied) => match occupied.get().0 {
|
||||
ValidDisputeStatementKind::BackingValid(_) |
|
||||
ValidDisputeStatementKind::BackingSeconded(_) => false,
|
||||
ValidDisputeStatementKind::Explicit |
|
||||
ValidDisputeStatementKind::ApprovalChecking => {
|
||||
occupied.insert((kind, sig));
|
||||
kind != occupied.get().0
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Retain any votes that match the given criteria.
|
||||
pub fn retain<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&ValidatorIndex, &mut (ValidDisputeStatementKind, ValidatorSignature)) -> bool,
|
||||
{
|
||||
self.votes.retain(f)
|
||||
}
|
||||
|
||||
/// Get all the validator indeces we have votes for.
|
||||
pub fn keys(
|
||||
&self,
|
||||
) -> Bkeys<'_, ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> {
|
||||
self.votes.keys()
|
||||
}
|
||||
|
||||
/// Get read only direct access to underlying map.
|
||||
pub fn raw(
|
||||
&self,
|
||||
) -> &BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> {
|
||||
&self.votes
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature))>
|
||||
for ValidCandidateVotes
|
||||
{
|
||||
fn from_iter<T>(iter: T) -> Self
|
||||
where
|
||||
T: IntoIterator<Item = (ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature))>,
|
||||
{
|
||||
Self { votes: BTreeMap::from_iter(iter) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ValidCandidateVotes>
|
||||
for BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)>
|
||||
{
|
||||
fn from(wrapped: ValidCandidateVotes) -> Self {
|
||||
wrapped.votes
|
||||
}
|
||||
}
|
||||
impl IntoIterator for ValidCandidateVotes {
|
||||
type Item = (ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature));
|
||||
type IntoIter = <BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> as IntoIterator>::IntoIter;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.votes.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedDisputeStatement {
|
||||
/// Create a new `SignedDisputeStatement` from information
|
||||
/// that is available on-chain, and hence already can be trusted.
|
||||
|
||||
@@ -30,10 +30,10 @@ use parity_scale_codec::{Decode, Encode, Error as CodecError, Input};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use polkadot_primitives::v2::{
|
||||
BlakeTwo256, CandidateCommitments, CandidateHash, CollatorPair, CommittedCandidateReceipt,
|
||||
CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId, OutboundHrmpMessage,
|
||||
PersistedValidationData, SessionIndex, Signed, UncheckedSigned, UpwardMessage, ValidationCode,
|
||||
ValidatorIndex, MAX_CODE_SIZE, MAX_POV_SIZE,
|
||||
BlakeTwo256, BlockNumber, CandidateCommitments, CandidateHash, CollatorPair,
|
||||
CommittedCandidateReceipt, CompactStatement, EncodeAs, Hash, HashT, HeadData, Id as ParaId,
|
||||
OutboundHrmpMessage, PersistedValidationData, SessionIndex, Signed, UncheckedSigned,
|
||||
UpwardMessage, ValidationCode, ValidatorIndex, MAX_CODE_SIZE, MAX_POV_SIZE,
|
||||
};
|
||||
pub use sp_consensus_babe::{
|
||||
AllowedSlots as BabeAllowedSlots, BabeEpochConfiguration, Epoch as BabeEpoch,
|
||||
@@ -73,8 +73,28 @@ pub const BACKING_EXECUTION_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
/// ensure that in the absence of extremely large disparities between hardware,
|
||||
/// blocks that pass backing are considered executable by approval checkers or
|
||||
/// dispute participants.
|
||||
///
|
||||
/// NOTE: If this value is increased significantly, also check the dispute coordinator to consider
|
||||
/// candidates longer into finalization: `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION`.
|
||||
pub const APPROVAL_EXECUTION_TIMEOUT: Duration = Duration::from_secs(12);
|
||||
|
||||
/// How many blocks after finalization an information about backed/included candidate should be
|
||||
/// kept.
|
||||
///
|
||||
/// We don't want to remove scraped candidates on finalization because we want to
|
||||
/// be sure that disputes will conclude on abandoned forks.
|
||||
/// Removing the candidate on finalization creates a possibility for an attacker to
|
||||
/// avoid slashing. If a bad fork is abandoned too quickly because another
|
||||
/// better one gets finalized the entries for the bad fork will be pruned and we
|
||||
/// might never participate in a dispute for it.
|
||||
///
|
||||
/// This value should consider the timeout we allow for participation in approval-voting. In
|
||||
/// particular, the following condition should hold:
|
||||
///
|
||||
/// slot time * `DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION` > `APPROVAL_EXECUTION_TIMEOUT`
|
||||
/// + slot time
|
||||
pub const DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION: BlockNumber = 10;
|
||||
|
||||
/// Linked to `MAX_FINALITY_LAG` in relay chain selection,
|
||||
/// `MAX_HEADS_LOOK_BACK` in `approval-voting` and
|
||||
/// `MAX_BATCH_SCRAPE_ANCESTORS` in `dispute-coordinator`
|
||||
|
||||
Reference in New Issue
Block a user