mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 01:38:32 +00:00
### Summary
Optimizes `award_session_performance_points` by batching all validator
rewards into a single storage mutation instead of performing individual
mutations inside the loop.
### Problem
The `award_session_performance_points` function, called during session
rotation via `SessionManager::end_session`, was calling `reward_by_ids`
inside the validator loop for each validator individually:
```rust
for validator in validators.iter() {
// ... calculate points ...
Self::reward_by_ids([(validator.clone(), points)].into_iter());
}
```
Each call to `reward_by_ids` performs a `StorageMap::mutate` on
`RewardPointsForEra`, which reads and writes the entire
`EraRewardPoints` structure (a `BTreeMap` containing up to N validator
entries). With N validators, this results in N separate
read-modify-write cycles of an O(N)-sized structure, leading to O(N²)
total storage I/O.
### Solution
Collect all reward points first, then perform a single batched call to
`reward_by_ids`:
```rust
let mut rewards = Vec::new();
for validator in validators.iter() {
// ... calculate points ...
rewards.push((validator.clone(), points));
}
if !rewards.is_empty() {
Self::reward_by_ids(rewards.into_iter());
}
```
This reduces the complexity from O(N²) to O(N) by performing only one
storage mutation that processes all validators at once.
### Why This Matters
Session rotation hooks are mandatory—they execute regardless of block
weight limits. While `pallet_session::on_initialize` returns `max_block`
weight during rotation (preventing user transactions), the actual
execution time still matters. With a large validator set, O(N²) storage
operations could exceed the block time target, potentially causing block
production delays.
### Test Plan
- [x] Existing unit tests pass (`cargo test -p
pallet-external-validators-rewards`)
|
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||