Skip to content

Commit 2cdbab6

Browse files
authored
Merge branch 'master' into pkhry/external_transient_storage
2 parents eaae888 + 21df44e commit 2cdbab6

File tree

10 files changed

+248
-73
lines changed

10 files changed

+248
-73
lines changed

.github/workflows/release-70_combined-publish-release.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ jobs:
106106
version: ${{ inputs.version }}
107107
stable_tag: ${{ needs.promote-rc-to-final.outputs.final_tag }}
108108
secrets: inherit
109+
permissions:
110+
contents: write
109111

110112
publish-docker-polkadot-parachain:
111113
name: Publish Docker image - polkadot-parachain
@@ -121,6 +123,8 @@ jobs:
121123
version: ${{ inputs.version }}
122124
stable_tag: ${{ needs.promote-rc-to-final.outputs.final_tag }}
123125
secrets: inherit
126+
permissions:
127+
contents: write
124128

125129
publish-docker-polkadot-omni-node:
126130
name: Publish Docker image - polkadot-omni-node
@@ -136,6 +140,8 @@ jobs:
136140
version: ${{ inputs.version }}
137141
stable_tag: ${{ needs.promote-rc-to-final.outputs.final_tag }}
138142
secrets: inherit
143+
permissions:
144+
contents: write
139145

140146
publish-docker-chain-spec-builder:
141147
name: Publish Docker image - chain-spec-builder
@@ -151,3 +157,5 @@ jobs:
151157
version: ${{ inputs.version }}
152158
stable_tag: ${{ needs.promote-rc-to-final.outputs.final_tag }}
153159
secrets: inherit
160+
permissions:
161+
contents: write

prdoc/pr_10880.prdoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
title: Remove failing assertion related to VoterList count mismatch
2+
doc:
3+
- audience: Runtime Dev
4+
description:
5+
Updated bags-list so that on_insert queues items into PendingRebag instead of failing,
6+
and removed the invariant that required VoterList's count to equal the combined number
7+
of Nominators and Validators. This is safe while bags-list is locked. After unlocking,
8+
on_idle drains PendingRebag, and the counts converge back to consistency over time.
9+
crates:
10+
- name: pallet-staking-async
11+
bump: patch
12+
- name: pallet-bags-list
13+
bump: patch

prdoc/pr_10882.prdoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
title: "statement-store: make encode/hash faster"
2+
doc:
3+
- audience: Node Dev
4+
description: |
5+
Optimizes statement encoding and hashing by pre-allocating memory for the encoded buffer.
6+
This reduces allocation overhead and improves performance, particularly when receiving
7+
statements from multiple peers. Benchmarks show ~16% speedup when receiving statements
8+
from 16 peers.
9+
crates:
10+
- name: sp-statement-store
11+
bump: minor
12+
- name: sc-network-statement
13+
bump: patch

substrate/client/network/statement/benches/statement_network.rs

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ fn blocking_executor(
282282
fn bench_on_statements(c: &mut Criterion) {
283283
let statement_counts = [100, 500, 1000, 2000];
284284
let thread_counts = [1, 2, 4, 8];
285+
let peer_counts = [1, 2, 4, 8, 16];
285286
let max_runtime_instances = 8;
286287
let executor_types = [("blocking", true), ("non_blocking", false)];
287288

@@ -292,39 +293,45 @@ fn bench_on_statements(c: &mut Criterion) {
292293
for &num_statements in &statement_counts {
293294
for &num_threads in &thread_counts {
294295
for &(executor_name, is_blocking) in &executor_types {
295-
let statements: Vec<Statement> =
296-
(0..num_statements).map(|i| create_signed_statement(i, &keypair)).collect();
297-
let executor = if is_blocking {
298-
blocking_executor(&handle)
299-
} else {
300-
non_blocking_executor(&handle)
301-
};
302-
303-
let benchmark_name = format!(
304-
"on_statements/statements_{}/threads_{}/{}",
305-
num_statements, num_threads, executor_name
306-
);
307-
308-
c.bench_function(&benchmark_name, |b| {
309-
b.iter_batched(
310-
|| build_handler(executor.clone(), num_threads, max_runtime_instances),
311-
|(mut handler, peer_id, _temp_dir)| {
312-
handler.on_statements(peer_id, statements.clone());
313-
314-
runtime.block_on(async {
315-
while handler.pending_statements_mut().next().await.is_some() {}
316-
});
317-
318-
let pending = handler.pending_statements_mut();
319-
assert!(
320-
pending.is_empty(),
321-
"Pending statements not empty: {}",
322-
pending.len()
323-
);
324-
},
325-
criterion::BatchSize::LargeInput,
326-
)
327-
});
296+
for num_peers in &peer_counts {
297+
let statements: Vec<Statement> =
298+
(0..num_statements).map(|i| create_signed_statement(i, &keypair)).collect();
299+
let executor = if is_blocking {
300+
blocking_executor(&handle)
301+
} else {
302+
non_blocking_executor(&handle)
303+
};
304+
305+
let benchmark_name = format!(
306+
"on_statements/statements_{}/peers_{}/threads_{}/{}",
307+
num_statements, num_peers, num_threads, executor_name
308+
);
309+
310+
c.bench_function(&benchmark_name, |b| {
311+
b.iter_batched(
312+
|| build_handler(executor.clone(), num_threads, max_runtime_instances),
313+
|(mut handler, peer_id, _temp_dir)| {
314+
// The number of peers determines how many times we might receive a
315+
// statement.
316+
for _ in 0..*num_peers {
317+
handler.on_statements(peer_id, statements.clone());
318+
}
319+
320+
runtime.block_on(async {
321+
while handler.pending_statements_mut().next().await.is_some() {}
322+
});
323+
324+
let pending = handler.pending_statements_mut();
325+
assert!(
326+
pending.is_empty(),
327+
"Pending statements not empty: {}",
328+
pending.len()
329+
);
330+
},
331+
criterion::BatchSize::LargeInput,
332+
)
333+
});
334+
}
328335
}
329336
}
330337
}

substrate/client/network/statement/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
use crate::config::*;
3030

3131
use codec::{Compact, Decode, Encode, MaxEncodedLen};
32+
#[cfg(any(test, feature = "test-helpers"))]
33+
use futures::future::pending;
3234
use futures::{channel::oneshot, future::FusedFuture, prelude::*, stream::FuturesUnordered};
3335
use prometheus_endpoint::{
3436
prometheus, register, Counter, Gauge, Histogram, HistogramOpts, PrometheusError, Registry, U64,
@@ -59,7 +61,6 @@ use std::{
5961
sync::Arc,
6062
};
6163
use tokio::time::timeout;
62-
6364
pub mod config;
6465

6566
/// A set of statements.
@@ -432,7 +433,7 @@ where
432433
statement_store,
433434
queue_sender,
434435
metrics: None,
435-
initial_sync_timeout: Box::pin(tokio::time::sleep(INITIAL_SYNC_BURST_INTERVAL).fuse()),
436+
initial_sync_timeout: Box::pin(pending().fuse()),
436437
pending_initial_syncs: HashMap::new(),
437438
initial_sync_peer_queue: VecDeque::new(),
438439
}

substrate/frame/bags-list/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -708,13 +708,16 @@ impl<T: Config<I>, I: 'static> SortedListProvider<T::AccountId> for Pallet<T, I>
708708
}
709709

710710
fn on_insert(id: T::AccountId, score: T::Score) -> Result<(), ListError> {
711-
Pallet::<T, I>::ensure_unlocked().inspect_err(|_| {
711+
if Pallet::<T, I>::ensure_unlocked().is_err() {
712712
// Pallet is locked - store in PendingRebag for later processing
713713
// Only queue if auto-rebagging is enabled
714714
if T::MaxAutoRebagPerBlock::get() > 0u32 {
715715
PendingRebag::<T, I>::insert(&id, ());
716+
return Ok(());
716717
}
717-
})?;
718+
719+
return Err(ListError::Locked);
720+
};
718721
List::<T, I>::insert(id, score)
719722
}
720723

substrate/frame/bags-list/src/tests.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,12 +1041,12 @@ mod on_idle {
10411041
BagsList::lock();
10421042

10431043
// Try to insert 6 new nodes while locked - 5 regular + 1 that will lose staking status
1044-
assert_eq!(BagsList::on_insert(5, 15), Err(ListError::Locked));
1045-
assert_eq!(BagsList::on_insert(6, 45), Err(ListError::Locked));
1046-
assert_eq!(BagsList::on_insert(7, 55), Err(ListError::Locked));
1047-
assert_eq!(BagsList::on_insert(8, 1500), Err(ListError::Locked));
1048-
assert_eq!(BagsList::on_insert(11, 100), Err(ListError::Locked));
1049-
assert_eq!(BagsList::on_insert(99, 500), Err(ListError::Locked)); // Will lose staking
1044+
assert_ok!(BagsList::on_insert(5, 15));
1045+
assert_ok!(BagsList::on_insert(6, 45));
1046+
assert_ok!(BagsList::on_insert(7, 55));
1047+
assert_ok!(BagsList::on_insert(8, 1500));
1048+
assert_ok!(BagsList::on_insert(11, 100));
1049+
assert_ok!(BagsList::on_insert(99, 500)); // Will lose staking
10501050

10511051
// Verify they're in PendingRebag
10521052
let pending: Vec<_> = PendingRebag::<Runtime>::iter_keys().collect();
@@ -1184,7 +1184,7 @@ mod on_idle {
11841184

11851185
// Try to insert while locked - should go to PendingRebag
11861186
StakingMock::set_score_of(&1, 1000);
1187-
assert_eq!(BagsList::on_insert(1, 1000), Err(ListError::Locked));
1187+
assert_ok!(BagsList::on_insert(1, 1000));
11881188
assert!(PendingRebag::<Runtime>::contains_key(&1));
11891189
assert!(!List::<Runtime>::contains(&1));
11901190

substrate/frame/staking-async/src/pallet/impls.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,16 +1897,20 @@ impl<T: Config> Pallet<T> {
18971897
}
18981898

18991899
/// Invariants:
1900-
/// * Number of voters in `VoterList` match that of the number of Nominators and Validators in
1901-
/// the system (validator is both voter and target).
19021900
/// * Number of targets in `TargetList` matches the number of validators in the system.
19031901
/// * Current validator count is bounded by the election provider's max winners.
19041902
fn check_count() -> Result<(), TryRuntimeError> {
1905-
ensure!(
1906-
<T as Config>::VoterList::count() ==
1907-
Nominators::<T>::count() + Validators::<T>::count(),
1908-
"wrong external count"
1903+
// When the bags list is locked, nominators and validators may be temporarily
1904+
// missing from the voter set. If `PendingRebag` is enabled, it will later
1905+
// reconcile the mismatch.
1906+
crate::log!(
1907+
debug,
1908+
"VoterList count: {}, Nominators count: {}, Validators count: {}",
1909+
<T as Config>::VoterList::count(),
1910+
Nominators::<T>::count(),
1911+
Validators::<T>::count()
19091912
);
1913+
19101914
ensure!(
19111915
<T as Config>::TargetList::count() == Validators::<T>::count(),
19121916
"wrong external count"

substrate/frame/staking-async/src/tests/mod.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -284,25 +284,6 @@ fn basic_setup_sessions_per_era() {
284284

285285
mod try_state_assertions {
286286
use super::*;
287-
#[test]
288-
#[should_panic]
289-
fn count_check_works() {
290-
ExtBuilder::default().build_and_execute(|| {
291-
// We should never insert into the validators or nominators map directly as this will
292-
// not keep track of the count. This test should panic as we verify the count is
293-
// accurate after every test using the `post_checks` in `mock`.
294-
Validators::<Test>::insert(987654321, ValidatorPrefs::default());
295-
Nominators::<Test>::insert(
296-
987654321,
297-
Nominations {
298-
targets: Default::default(),
299-
submitted_in: Default::default(),
300-
suppressed: false,
301-
},
302-
);
303-
})
304-
}
305-
306287
#[test]
307288
#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"number of entries in payee storage items does not match the number of bonded ledgers\")"]
308289
fn check_payee_invariant1_works() {

0 commit comments

Comments
 (0)