Skip to content

Commit dda3a0b

Browse files
committed
fix(staking): ranked entries should instead iterate on StakeKey<Address>
1 parent 989e855 commit dda3a0b

File tree

2 files changed

+45
-46
lines changed

2 files changed

+45
-46
lines changed

data_structures/src/staking/stakes.rs

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -313,33 +313,32 @@ where
313313
.sum())
314314
}
315315

316-
/// For a given capability, obtain the full list of stakers ordered by their power in that
317-
/// capability.
316+
/// For a given capability, obtain the full list of positive stake entries reversely ordered by their power.
318317
/// TODO: we may memoize the rank by keeping the last one in a non-serializable field in `Self` that keeps a boxed
319-
/// iterator, so that this method doesn't have to sort multiple times if we are calling the `rank` method several
320-
/// times in the same epoch.
321-
pub fn rank(
318+
/// iterator, so that this method doesn't have to sort multiple times if we are calling the `rank` method
319+
/// several times in the same epoch.
320+
pub fn by_rank(
322321
&self,
323322
capability: Capability,
324323
current_epoch: Epoch,
325-
) -> impl Iterator<Item = (Address, Power)> + '_ {
326-
self.by_validator
324+
) -> impl Iterator<Item = (StakeKey<Address>, Power)> + '_ {
325+
self.by_key
327326
.iter()
328-
.map(move |(address, stakes)| {
329-
let power = stakes
330-
.first()
331-
.unwrap()
332-
.read_value()
333-
.power(capability, current_epoch);
334-
335-
(address.clone(), power)
327+
.filter(|(_, sync_entry)| {
328+
sync_entry.read_value().epochs.get(capability) <= current_epoch
329+
})
330+
.map(move |(key, entry)| {
331+
(key.clone(), entry.read_value().power(capability, current_epoch))
336332
})
337-
.sorted_by(|(address_1, power_1), (address_2, power_2)| {
338-
// Equal power, compare the addresses to achieve deterministic ordering
333+
.sorted_by(|(key_1, power_1), (key_2, power_2)| {
339334
if power_1 == power_2 {
340-
address_1.cmp(address_2)
335+
if key_1.validator == key_2.validator {
336+
key_1.withdrawer.cmp(&key_2.withdrawer)
337+
} else {
338+
key_1.validator.cmp(&key_2.validator)
339+
}
341340
} else {
342-
power_1.cmp(power_2)
341+
power_1.cmp(&power_2)
343342
}
344343
})
345344
.rev()
@@ -909,7 +908,7 @@ mod tests {
909908
#[test]
910909
fn test_stakes_initialization() {
911910
let stakes = StakesTester::default();
912-
let ranking = stakes.rank(Capability::Mining, 0).collect::<Vec<_>>();
911+
let ranking = stakes.by_rank(Capability::Mining, 0).collect::<Vec<_>>();
913912
assert_eq!(ranking, Vec::default());
914913
}
915914

@@ -1087,19 +1086,19 @@ mod tests {
10871086
Ok(2_100)
10881087
);
10891088
assert_eq!(
1090-
stakes.rank(Capability::Mining, 100).collect::<Vec<_>>(),
1089+
stakes.by_rank(Capability::Mining, 100).collect::<Vec<_>>(),
10911090
[
1092-
(charlie.into(), 2100),
1093-
(bob.into(), 1600),
1091+
(charlie_erin.into(), 2100),
1092+
(bob_david.into(), 1600),
10941093
(alice.into(), 1000)
10951094
]
10961095
);
10971096
assert_eq!(
1098-
stakes.rank(Capability::Witnessing, 100).collect::<Vec<_>>(),
1097+
stakes.by_rank(Capability::Witnessing, 100).collect::<Vec<_>>(),
10991098
[
1100-
(charlie.into(), 2100),
1101-
(bob.into(), 1600),
1102-
(alice.into(), 1000)
1099+
(charlie_erin.into(), 2100),
1100+
(bob_david.into(), 1600),
1101+
(alice_charlie.into(), 1000)
11031102
]
11041103
);
11051104

@@ -1126,19 +1125,19 @@ mod tests {
11261125
Ok(2_130)
11271126
);
11281127
assert_eq!(
1129-
stakes.rank(Capability::Mining, 101).collect::<Vec<_>>(),
1128+
stakes.by_rank(Capability::Mining, 101).collect::<Vec<_>>(),
11301129
[
1131-
(bob.into(), 1_620),
1132-
(alice.into(), 1_010),
1133-
(charlie.into(), 0)
1130+
(bob_david.into(), 1_620),
1131+
(alice_charlie.into(), 1_010),
1132+
(charlie_erin.into(), 0)
11341133
]
11351134
);
11361135
assert_eq!(
1137-
stakes.rank(Capability::Witnessing, 101).collect::<Vec<_>>(),
1136+
stakes.by_rank(Capability::Witnessing, 101).collect::<Vec<_>>(),
11381137
[
1139-
(charlie.into(), 2_130),
1140-
(bob.into(), 1_620),
1141-
(alice.into(), 1_010)
1138+
(charlie_erin.into(), 2_130),
1139+
(bob_david.into(), 1_620),
1140+
(alice_charlie.into(), 1_010)
11421141
]
11431142
);
11441143

@@ -1167,19 +1166,19 @@ mod tests {
11671166
Ok(8_100)
11681167
);
11691168
assert_eq!(
1170-
stakes.rank(Capability::Mining, 300).collect::<Vec<_>>(),
1169+
stakes.by_rank(Capability::Mining, 300).collect::<Vec<_>>(),
11711170
[
1172-
(charlie.into(), 5_970),
1173-
(bob.into(), 5_600),
1174-
(alice.into(), 3_000)
1171+
(charlie_erin.into(), 5_970),
1172+
(bob_david.into(), 5_600),
1173+
(alice_charlie.into(), 3_000)
11751174
]
11761175
);
11771176
assert_eq!(
1178-
stakes.rank(Capability::Witnessing, 300).collect::<Vec<_>>(),
1177+
stakes.by_rank(Capability::Witnessing, 300).collect::<Vec<_>>(),
11791178
[
1180-
(charlie.into(), 8_100),
1181-
(bob.into(), 5_600),
1182-
(alice.into(), 3_000)
1179+
(charlie_erin.into(), 8_100),
1180+
(bob_david.into(), 5_600),
1181+
(alice_charlie.into(), 3_000)
11831182
]
11841183
);
11851184
}
@@ -1222,10 +1221,10 @@ mod tests {
12221221
// charlie_david: 30 * (90 - 20) = 2100
12231222
// david_erin: 40 * (90 - 30) = 2400
12241223
// erin_alice: 50 * (90 - 40) = 2500
1225-
let rank_subset: Vec<_> = stakes.rank(Capability::Mining, 90).take(4).collect();
1224+
let rank_subset: Vec<_> = stakes.by_rank(Capability::Mining, 90).take(4).collect();
12261225
for (i, (validator, _)) in rank_subset.into_iter().enumerate() {
12271226
let _ = stakes.reset_age(
1228-
validator,
1227+
validator.validator,
12291228
Capability::Mining,
12301229
90,
12311230
(i + 1).try_into().unwrap(),

validations/src/eligibility/current.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ where
240240
));
241241
}
242242

243-
let mut rank = self.rank(Capability::Witnessing, epoch);
243+
let mut rank = self.by_rank(Capability::Witnessing, epoch);
244244
let (_, max_power) = rank.next().unwrap_or_default();
245245

246246
// Requirement no. 2 from the WIP:

0 commit comments

Comments
 (0)