Skip to content
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

Fix candidate tracking on async backing #675

Merged
merged 21 commits into from
Apr 19, 2024
Merged
8 changes: 7 additions & 1 deletion essentials/src/chain_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub struct SubxtCandidateEvent {
pub parachain_id: u32,
/// The event type
pub event_type: SubxtCandidateEventType,
/// Core index
pub core_idx: u32,
}

/// A helper structure to keep track of a dispute and it's relay parent
Expand Down Expand Up @@ -126,6 +128,7 @@ pub async fn decode_chain_event<T: subxt::Config>(
return Ok(ChainEvent::CandidateChanged(Box::new(create_candidate_event(
decoded.0.commitments_hash,
decoded.0.descriptor,
decoded.2 .0,
SubxtCandidateEventType::Backed,
))))
}
Expand All @@ -135,6 +138,7 @@ pub async fn decode_chain_event<T: subxt::Config>(
return Ok(ChainEvent::CandidateChanged(Box::new(create_candidate_event(
decoded.0.commitments_hash,
decoded.0.descriptor,
decoded.2 .0,
SubxtCandidateEventType::Included,
))))
}
Expand All @@ -144,6 +148,7 @@ pub async fn decode_chain_event<T: subxt::Config>(
return Ok(ChainEvent::CandidateChanged(Box::new(create_candidate_event(
decoded.0.commitments_hash,
decoded.0.descriptor,
decoded.2 .0,
SubxtCandidateEventType::TimedOut,
))))
}
Expand Down Expand Up @@ -190,9 +195,10 @@ fn decode_to_specific_event<E: subxt::events::StaticEvent, C: subxt::Config>(
fn create_candidate_event(
commitments_hash: <PolkadotConfig as subxt::Config>::Hash,
candidate_descriptor: CandidateDescriptor<<PolkadotConfig as subxt::Config>::Hash>,
core_idx: u32,
event_type: SubxtCandidateEventType,
) -> SubxtCandidateEvent {
let candidate_hash = BlakeTwo256::hash_of(&(&candidate_descriptor, commitments_hash));
let parachain_id = candidate_descriptor.para_id.0;
SubxtCandidateEvent { event_type, candidate_descriptor, parachain_id, candidate_hash }
SubxtCandidateEvent { event_type, candidate_descriptor, parachain_id, candidate_hash, core_idx }
}
11 changes: 10 additions & 1 deletion essentials/src/collector/candidate_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct CandidateInclusionRecord<T: Encode + Decode + Clone> {
/// Relay parent block number when a candidate was timed out
pub timedout: Option<u32>,
/// Observed core index
pub core_idx: Option<u32>,
pub core_idx: u32,
/// Stated relay parent
pub relay_parent: T,
/// Stated relay parent number
Expand Down Expand Up @@ -109,6 +109,11 @@ pub struct CandidateRecord {
}

impl CandidateRecord {
/// Returns if a candidate has been included
pub fn is_included(&self) -> bool {
self.candidate_inclusion.included.is_some()
}

/// Returns if a candidate has been disputed
#[allow(dead_code)]
pub fn is_disputed(&self) -> bool {
Expand Down Expand Up @@ -144,4 +149,8 @@ impl CandidateRecord {
pub fn parachain_id(&self) -> u32 {
self.candidate_inclusion.parachain_id
}

pub fn core_idx(&self) -> u32 {
self.candidate_inclusion.core_idx
}
}
2 changes: 1 addition & 1 deletion essentials/src/collector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ impl Collector {
relay_parent_number: relay_parent.number,
parachain_id: change_event.parachain_id,
backed: relay_block_number,
core_idx: None,
core_idx: change_event.core_idx,
timedout: None,
included: None,
};
Expand Down
105 changes: 15 additions & 90 deletions parachain-tracer/src/parachain_block_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,30 @@ use subxt::config::{substrate::BlakeTwo256, Hasher};
/// This is used for displaying CLI updates and also goes to Storage.
#[derive(Encode, Decode, Debug, Default)]
pub struct ParachainBlockInfo {
/// The candidate information as observed during backing
pub candidate: Option<BackedCandidate<H256>>,
/// Candidate hash
pub candidate_hash: Option<H256>,
/// The current state.
state: ParachainBlockState,
pub candidate_hash: H256,
/// The number of signed bitfields.
pub bitfield_count: u32,
/// The maximum expected number of availability bits that can be set. Corresponds to `max_validators`.
pub max_availability_bits: u32,
/// The current number of observed availability bits set to 1.
pub current_availability_bits: u32,
/// Parachain availability core assignment information.
pub assigned_core: Option<u32>,
pub assigned_core: u32,
/// Core occupation status.
pub core_occupied: bool,
/// The current state.
pub state: ParachainBlockState,
}

impl ParachainBlockInfo {
pub fn maybe_reset(&mut self) {
if self.is_included() {
self.state = ParachainBlockState::Idle;
self.candidate = None;
self.candidate_hash = None;
}
pub fn new(candidate_hash: H256, assigned_core: u32, bitfield_count: u32) -> Self {
Self { candidate_hash, assigned_core, bitfield_count, ..Default::default() }
}

pub fn set_idle(&mut self) {
self.state = ParachainBlockState::Idle
}

pub fn set_backed(&mut self) {
self.state = ParachainBlockState::Backed
pub fn candidate_hash(candidate: &BackedCandidate<H256>) -> H256 {
let commitments_hash = BlakeTwo256::hash_of(&candidate.candidate.commitments);
BlakeTwo256::hash_of(&(&candidate.candidate.descriptor, commitments_hash))
}

pub fn set_pending(&mut self) {
Expand All @@ -65,45 +56,24 @@ impl ParachainBlockInfo {
self.state = ParachainBlockState::Included
}

pub fn set_candidate(&mut self, candidate: BackedCandidate<H256>) {
let commitments_hash = BlakeTwo256::hash_of(&candidate.candidate.commitments);
let candidate_hash = BlakeTwo256::hash_of(&(&candidate.candidate.descriptor, commitments_hash));
self.candidate_hash = Some(candidate_hash);
self.candidate = Some(candidate);
}

pub fn is_idle(&self) -> bool {
self.state == ParachainBlockState::Idle
}

pub fn is_backed(&self) -> bool {
self.state == ParachainBlockState::Backed
}

pub fn is_pending(&self) -> bool {
self.state == ParachainBlockState::PendingAvailability
}

pub fn is_included(&self) -> bool {
self.state == ParachainBlockState::Included
}

pub fn is_data_available(&self) -> bool {
self.current_availability_bits > (self.max_availability_bits / 3) * 2
}

pub fn is_bitfield_propagation_slow(&self) -> bool {
self.max_availability_bits > 0 && !self.is_idle() && self.bitfield_count <= (self.max_availability_bits / 3) * 2
self.max_availability_bits > 0 && self.bitfield_count <= (self.max_availability_bits / 3) * 2
}
}

/// The state of parachain block.
#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, Eq)]
enum ParachainBlockState {
// Parachain block pipeline is idle.
#[default]
Idle,
pub enum ParachainBlockState {
// A candidate is currently backed.
#[default]
Backed,
// A candidate is pending inclusion.
PendingAvailability,
Expand All @@ -115,60 +85,15 @@ enum ParachainBlockState {
mod tests {
use crate::test_utils::create_para_block_info;

#[test]
sandreim marked this conversation as resolved.
Show resolved Hide resolved
fn test_does_not_reset_state_if_not_included() {
let mut info = create_para_block_info();
info.set_backed();

assert!(info.is_backed());
assert!(info.candidate.is_some());
assert!(info.candidate_hash.is_some());

info.maybe_reset();

assert!(info.is_backed());
assert!(info.candidate.is_some());
assert!(info.candidate_hash.is_some());
}

#[test]
fn test_resets_state_if_included() {
let mut info = create_para_block_info();
info.set_included();

assert!(info.is_included());
assert!(info.candidate.is_some());
assert!(info.candidate_hash.is_some());

info.maybe_reset();

assert!(info.is_idle());
assert!(info.candidate.is_none());
assert!(info.candidate_hash.is_none());
}

#[test]
fn test_is_data_available() {
let mut info = create_para_block_info();
assert!(!info.is_data_available());

info.max_availability_bits = 200;
info.current_availability_bits = 134;
assert!(info.is_data_available());
}

#[test]
fn test_is_bitfield_propagation_slow() {
let mut info = create_para_block_info();
let mut info = create_para_block_info(100);
assert!(!info.is_bitfield_propagation_slow());

info.max_availability_bits = 200;
assert!(!info.is_bitfield_propagation_slow());

info.bitfield_count = 100;
assert!(!info.is_bitfield_propagation_slow());
assert!(info.is_bitfield_propagation_slow());

info.set_backed();
info.bitfield_count = 120;
assert!(info.is_bitfield_propagation_slow());
}
}
38 changes: 7 additions & 31 deletions parachain-tracer/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,17 @@ pub fn create_hrmp_channels() -> BTreeMap<u32, SubxtHrmpChannel> {
pub fn create_candidate_record(
para_id: u32,
backed: u32,
included: Option<u32>,
relay_parent: H256,
relay_parent_number: u32,
) -> CandidateRecord {
CandidateRecord {
candidate_inclusion: CandidateInclusionRecord {
parachain_id: para_id,
backed,
included: None,
included,
timedout: None,
core_idx: None,
core_idx: 0,
relay_parent,
relay_parent_number,
},
Expand All @@ -161,35 +162,10 @@ pub fn create_candidate_record(
}
}

pub fn create_para_block_info() -> ParachainBlockInfo {
let mut info = ParachainBlockInfo::default();
info.set_candidate(BackedCandidate {
candidate: CommittedCandidateReceipt {
descriptor: CandidateDescriptor {
para_id: Id(100),
relay_parent: Default::default(),
collator: collator_app::Public(Public([0; 32])),
persisted_validation_data_hash: Default::default(),
pov_hash: Default::default(),
erasure_root: Default::default(),
signature: collator_app::Signature(Signature([0; 64])),
para_head: Default::default(),
validation_code_hash: ValidationCodeHash(Default::default()),
},
commitments: CandidateCommitments {
upward_messages: BoundedVec(Default::default()),
horizontal_messages: BoundedVec(Default::default()),
new_validation_code: Default::default(),
head_data: HeadData(Default::default()),
processed_downward_messages: Default::default(),
hrmp_watermark: Default::default(),
},
},
validity_votes: vec![],
validator_indices: DecodedBits::from_iter([true]),
});

info
pub fn create_para_block_info(para_id: u32) -> ParachainBlockInfo {
let candidate = create_backed_candidate(para_id);
let hash = ParachainBlockInfo::candidate_hash(&candidate);
ParachainBlockInfo::new(hash, 0, 0)
}

pub async fn storage_write<T: Encode>(
Expand Down
Loading
Loading