Skip to content

Commit 2202fd6

Browse files
committed
fix(predict): fixed voter data fetch and ordering
1 parent 55e1502 commit 2202fd6

File tree

4 files changed

+204
-198
lines changed

4 files changed

+204
-198
lines changed

src/commands/predict.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,6 @@ where
9696
get_election_data::<T>(n_pages, current_round, storage).await?
9797
};
9898

99-
// Take the minimum of targets
100-
let desired_targets =
101-
std::cmp::min(desired_targets, (target_snapshot.len().saturating_sub(1)) as u32);
102-
10399
log::info!(
104100
target: LOG_TARGET,
105101
"Mining solution with desired_targets={}, candidates={}, voter pages={}",

src/dynamic/election_data.rs

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -44,94 +44,6 @@ pub struct PredictionContext<'a> {
4444
pub data_source: ElectionDataSource,
4545
}
4646

47-
/// Inject validator self-votes to ensure every candidate backs itself when generating
48-
/// synthetic election snapshots.
49-
///
50-
/// - If an account is a nominator, use their nominator data BUT ensure they vote for themselves
51-
/// - If an account is a validator but NOT a nominator, inject them as voting for themselves
52-
///
53-
/// We do NOT merge stakes - we respect the nominator data if it exists.
54-
pub(crate) fn inject_self_votes(
55-
candidates: &[ValidatorData],
56-
nominators: Vec<NominatorData>,
57-
) -> Vec<NominatorData> {
58-
// Build a map of validator accounts to their stakes for lookup
59-
let validator_stakes: HashMap<AccountId, u64> = candidates
60-
.iter()
61-
.map(|(account, stake)| {
62-
let stake_u64 = if *stake > u64::MAX as u128 {
63-
log::warn!(
64-
target: LOG_TARGET,
65-
"Validator {:?} stake {} exceeds u64::MAX; truncating to {}",
66-
account,
67-
stake,
68-
u64::MAX
69-
);
70-
u64::MAX
71-
} else {
72-
*stake as u64
73-
};
74-
(account.clone(), stake_u64)
75-
})
76-
.collect();
77-
78-
// Build a set of all validator accounts for fast lookup
79-
let validator_accounts: HashSet<AccountId> =
80-
candidates.iter().map(|(account, _)| account.clone()).collect();
81-
82-
let mut combined: Vec<NominatorData> = Vec::with_capacity(nominators.len() + candidates.len());
83-
84-
let mut self_votes_added = 0usize;
85-
86-
// Process all nominators, ensuring validators vote for themselves
87-
for (account, stake, mut targets) in nominators {
88-
// If this nominator is also a validator, ensure they vote for themselves
89-
if validator_accounts.contains(&account) {
90-
// Add self-target if not already present
91-
if !targets.iter().any(|t| t == &account) {
92-
targets.push(account.clone());
93-
self_votes_added += 1;
94-
}
95-
}
96-
combined.push((account, stake, targets));
97-
}
98-
99-
// Then, for validators that are NOT nominators, inject them as self-voters
100-
let mut injected = 0usize;
101-
for (account, _stake) in candidates {
102-
// Skip if this validator is already a nominator (we already processed them above)
103-
if combined.iter().any(|(acc, _, _)| acc == account) {
104-
continue;
105-
}
106-
107-
// Get the validator stake (already converted to u64 in validator_stakes map)
108-
let stake_u64 = validator_stakes
109-
.get(account)
110-
.copied()
111-
.expect("Validator stake should exist in map");
112-
113-
// Add validator as a self-voter (voting only for themselves)
114-
combined.push((account.clone(), stake_u64, vec![account.clone()]));
115-
injected += 1;
116-
}
117-
log::info!(
118-
target: LOG_TARGET,
119-
"Ensured {} validator self-votes in nominators, injected {} new validator self-voters (total: {} voters)",
120-
self_votes_added,
121-
injected,
122-
combined.len()
123-
);
124-
125-
combined.sort_by(|a, b| {
126-
// Sort by Stake Descending (High stake first)
127-
b.1.cmp(&a.1)
128-
// Tie-breaker: AccountId Ascending (for deterministic stability)
129-
.then_with(|| a.0.cmp(&b.0))
130-
});
131-
132-
combined
133-
}
134-
13547
/// Convert staking pallet data into the in-memory snapshot format expected by the miner.
13648
///
13749
/// Returns a single-page target snapshot and a Vec of voter pages (not bounded, so no pages are
@@ -408,6 +320,7 @@ where
408320
// try to fetch election data from the snapshot
409321
// if snapshot is not available fetch from staking
410322
log::info!(target: LOG_TARGET, "Trying to fetch data from snapshot");
323+
411324
match try_fetch_snapshot::<T>(n_pages, round, &storage).await {
412325
Ok((target_snapshot, voter_pages)) => {
413326
log::info!(target: LOG_TARGET, "Snapshot found");
@@ -428,11 +341,10 @@ where
428341
.await
429342
.map_err(|e| Error::Other(format!("Failed to fetch nominators: {e}")))?;
430343

431-
let nominators = inject_self_votes(&candidates, nominators);
432-
433-
let (target_snapshot, voter_snapshot) =
344+
let (target_snapshot, mut voter_snapshot) =
434345
convert_staking_data_to_snapshots::<T>(candidates, nominators)?;
435-
346+
// Fix the order
347+
voter_snapshot.reverse();
436348
Ok((target_snapshot, voter_snapshot, ElectionDataSource::Staking))
437349
},
438350
}

src/dynamic/pallet_api.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,5 @@ pub mod voter_list {
171171
use super::{super::*, *};
172172
pub const LIST_NODES: PalletItem = PalletItem::new(NAME, "ListNodes");
173173
pub const LIST_BAGS: PalletItem = PalletItem::new(NAME, "ListBags");
174-
pub const COUNTER_FOR_LIST_NODES: PalletItem = PalletItem::new(NAME, "CounterForListNodes");
175174
}
176175
}

0 commit comments

Comments
 (0)