Skip to content

Commit

Permalink
Approve multiple candidates with a single signature
Browse files Browse the repository at this point in the history
The pr migrates:
- paritytech/polkadot#7554

Signed-off-by: Alexandru Gheorghe <alexandru.gheorghe@parity.io>
  • Loading branch information
alexggh committed Aug 27, 2023
1 parent f4f0e70 commit 341c7af
Show file tree
Hide file tree
Showing 53 changed files with 2,941 additions and 635 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use polkadot_core_primitives::{Block, BlockNumber, Hash, Header};
use polkadot_overseer::RuntimeApiSubsystemClient;
use polkadot_primitives::{
slashing,
vstaging::{AsyncBackingParams, BackingState},
vstaging::{ApprovalVotingParams, AsyncBackingParams, BackingState},
};
use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError};
use sp_api::{ApiError, RuntimeApiInfo};
Expand Down Expand Up @@ -349,6 +349,10 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient {
) -> Result<Option<BackingState>, ApiError> {
Ok(self.rpc_client.parachain_host_staging_para_backing_state(at, para_id).await?)
}
/// Approval voting configuration parameters
async fn approval_voting_params(&self, _at: Hash) -> Result<ApprovalVotingParams, ApiError> {
Ok(ApprovalVotingParams { max_approval_coalesce_count: 1 })
}
}

#[async_trait::async_trait]
Expand Down
67 changes: 41 additions & 26 deletions polkadot/node/core/approval-voting/src/approval_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub enum RequiredTranches {
}

/// The result of a check.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Check {
/// The candidate is unapproved.
Unapproved,
Expand Down Expand Up @@ -372,19 +372,22 @@ pub fn tranches_to_approve(
block_tick: Tick,
no_show_duration: Tick,
needed_approvals: usize,
) -> RequiredTranches {
) -> (RequiredTranches, usize) {
let tick_now = tranche_now as Tick + block_tick;
let n_validators = approval_entry.n_validators();

let initial_state = State {
assignments: 0,
depth: 0,
covered: 0,
covering: needed_approvals,
uncovered: 0,
next_no_show: None,
last_assignment_tick: None,
};
let initial_state = (
State {
assignments: 0,
depth: 0,
covered: 0,
covering: needed_approvals,
uncovered: 0,
next_no_show: None,
last_assignment_tick: None,
},
0usize,
);

// The `ApprovalEntry` doesn't have any data for empty tranches. We still want to iterate over
// these empty tranches, so we create an iterator to fill the gaps.
Expand All @@ -395,7 +398,7 @@ pub fn tranches_to_approve(
tranches_with_gaps_filled
.scan(Some(initial_state), |state, (tranche, assignments)| {
// The `Option` here is used for early exit.
let s = state.take()?;
let (s, prev_no_shows) = state.take()?;

let clock_drift = s.clock_drift(no_show_duration);
let drifted_tick_now = tick_now.saturating_sub(clock_drift);
Expand Down Expand Up @@ -444,11 +447,11 @@ pub fn tranches_to_approve(
RequiredTranches::Pending { .. } => {
// Pending results are only interesting when they are the last result of the iterator
// i.e. we never achieve a satisfactory level of assignment.
Some(s)
Some((s, no_shows + prev_no_shows))
}
};

Some(output)
Some((output, no_shows + prev_no_shows))
})
.last()
.expect("the underlying iterator is infinite, starts at 0, and never exits early before tranche 1; qed")
Expand Down Expand Up @@ -675,7 +678,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Exact {
needed: 1,
tolerated_missing: 0,
Expand Down Expand Up @@ -715,7 +719,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 2,
next_no_show: Some(block_tick + no_show_duration),
Expand Down Expand Up @@ -759,7 +764,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 11,
next_no_show: None,
Expand Down Expand Up @@ -807,7 +813,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 1,
next_no_show: None,
Expand All @@ -826,7 +833,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 1,
next_no_show: None,
Expand Down Expand Up @@ -879,7 +887,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Exact {
needed: 1,
tolerated_missing: 0,
Expand All @@ -898,7 +907,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Exact {
needed: 2,
tolerated_missing: 1,
Expand All @@ -917,7 +927,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 2,
next_no_show: None,
Expand Down Expand Up @@ -970,7 +981,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Exact {
needed: 2,
tolerated_missing: 1,
Expand All @@ -992,7 +1004,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 2,
next_no_show: None,
Expand All @@ -1013,7 +1026,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Exact {
needed: 3,
tolerated_missing: 2,
Expand Down Expand Up @@ -1068,7 +1082,8 @@ mod tests {
block_tick,
no_show_duration,
needed_approvals,
),
)
.0,
RequiredTranches::Pending {
considered: 10,
next_no_show: None,
Expand Down
34 changes: 30 additions & 4 deletions polkadot/node/core/approval-voting/src/approval_db/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
//! Version 2 of the DB schema.

use parity_scale_codec::{Decode, Encode};
use polkadot_node_primitives::approval::{v1::DelayTranche, v2::AssignmentCertV2};
use polkadot_node_primitives::approval::{
v1::DelayTranche,
v2::{AssignmentCertV2, CandidateBitfield},
};
use polkadot_node_subsystem::{SubsystemError, SubsystemResult};
use polkadot_node_subsystem_util::database::{DBTransaction, Database};
use polkadot_primitives::{
BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, GroupIndex, Hash, SessionIndex,
ValidatorIndex, ValidatorSignature,
BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, GroupIndex, Hash,
SessionIndex, ValidatorIndex, ValidatorSignature,
};

use sp_consensus_slots::Slot;
Expand Down Expand Up @@ -197,14 +200,24 @@ pub struct TrancheEntry {
pub assignments: Vec<(ValidatorIndex, Tick)>,
}

/// Metadata about our approval signature
#[derive(Encode, Decode, Debug, Clone, PartialEq)]
pub struct OurApproval {
/// The signature for the candidates hashes pointed by indices.
pub signature: ValidatorSignature,
/// The indices of the candidates signed in this approval, an empty value means only
/// the candidate referred by this approval entry was signed.
pub signed_candidates_indices: Option<CandidateBitfield>,
}

/// Metadata regarding approval of a particular candidate within the context of some
/// particular block.
#[derive(Encode, Decode, Debug, Clone, PartialEq)]
pub struct ApprovalEntry {
pub tranches: Vec<TrancheEntry>,
pub backing_group: GroupIndex,
pub our_assignment: Option<OurAssignment>,
pub our_approval_sig: Option<ValidatorSignature>,
pub our_approval_sig: Option<OurApproval>,
// `n_validators` bits.
pub assigned_validators: Bitfield,
pub approved: bool,
Expand Down Expand Up @@ -241,12 +254,25 @@ pub struct BlockEntry {
// block. The block can be considered approved if the bitfield has all bits set to `true`.
pub approved_bitfield: Bitfield,
pub children: Vec<Hash>,
// A list of candidates that has been approved, but we didn't not sign and
// advertise the vote yet.
pub candidates_pending_signature: BTreeMap<CandidateIndex, CandidateSigningContext>,
// Assignments we already distributed. A 1 bit means the candidate index for which
// we already have sent out an assignment. We need this to avoid distributing
// multiple core assignments more than once.
pub distributed_assignments: Bitfield,
}

#[derive(Encode, Decode, Debug, Clone, PartialEq)]

/// Context needed for creating an approval signature for a given candidate.
pub struct CandidateSigningContext {
/// The candidate hash, to be included in the signature.
pub candidate_hash: CandidateHash,
/// The latest tick we have to create and send the approval.
pub send_no_later_than_tick: Tick,
}

impl From<crate::Tick> for Tick {
fn from(tick: crate::Tick) -> Tick {
Tick(tick)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ fn make_block_entry(
approved_bitfield: make_bitvec(candidates.len()),
candidates,
children: Vec::new(),
candidates_pending_signature: Default::default(),
distributed_assignments: Default::default(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion polkadot/node/core/approval-voting/src/criteria.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ impl AssignmentCriteria for RealAssignmentCriteria {
config: &Config,
leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>,
) -> HashMap<CoreIndex, OurAssignment> {
compute_assignments(keystore, relay_vrf_story, config, leaving_cores, false)
compute_assignments(keystore, relay_vrf_story, config, leaving_cores, true)
}

fn check_assignment_cert(
Expand Down
3 changes: 3 additions & 0 deletions polkadot/node/core/approval-voting/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ pub(crate) async fn handle_new_head<Context, B: Backend>(
.collect(),
approved_bitfield,
children: Vec::new(),
candidates_pending_signature: Default::default(),
distributed_assignments: Default::default(),
};

Expand Down Expand Up @@ -639,6 +640,7 @@ pub(crate) mod tests {
clock: Box::new(MockClock::default()),
assignment_criteria: Box::new(MockAssignmentCriteria),
spans: HashMap::new(),
approval_voting_params_cache: None,
}
}

Expand Down Expand Up @@ -1267,6 +1269,7 @@ pub(crate) mod tests {
candidates: Vec::new(),
approved_bitfield: Default::default(),
children: Vec::new(),
candidates_pending_signature: Default::default(),
distributed_assignments: Default::default(),
}
.into(),
Expand Down
Loading

0 comments on commit 341c7af

Please sign in to comment.