From c1344cc54df0b059312bad9c424b1c2adcd9da91 Mon Sep 17 00:00:00 2001 From: DenzelPenzel Date: Wed, 1 Apr 2026 21:27:40 +0100 Subject: [PATCH 1/2] statement-store: add channel replacement logic tests --- substrate/client/statement-store/src/lib.rs | 81 ++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/substrate/client/statement-store/src/lib.rs b/substrate/client/statement-store/src/lib.rs index 69066f285365..d2ab00be84a8 100644 --- a/substrate/client/statement-store/src/lib.rs +++ b/substrate/client/statement-store/src/lib.rs @@ -1534,8 +1534,8 @@ mod tests { use sc_keystore::Keystore; use sp_core::{Decode, Encode, Pair}; use sp_statement_store::{ - AccountId, Channel, DecryptionKey, InvalidReason, Proof, Statement, StatementSource, - StatementStore, SubmitResult, Topic, + AccountId, Channel, DecryptionKey, InvalidReason, Proof, RejectionReason, Statement, + StatementSource, StatementStore, SubmitResult, Topic, }; type Extrinsic = sp_runtime::OpaqueExtrinsic; @@ -2899,4 +2899,81 @@ mod tests { assert!(!index.entries.contains_key(&h1), "Lower priority should be evicted"); assert_eq!(index.total_size, 600); } + + #[test] + fn channel_replacement_only_higher_priority_succeeds() { + let (store, _temp) = test_store(); + let source = StatementSource::Network; + + // Account 1: max_count=1, max_size=1000 + // Submit channel 1 with priority 5 + let s1 = statement(1, 5, Some(1), 100); + let h1 = s1.hash(); + assert_eq!(store.submit(s1, source), SubmitResult::New); + + // Lower priority on same channel → ChannelPriorityTooLow + let result = store.submit(statement(1, 3, Some(1), 100), source); + assert!( + matches!(result, SubmitResult::Rejected(RejectionReason::ChannelPriorityTooLow { .. })), + "Lower priority should be rejected with ChannelPriorityTooLow, got: {result:?}" + ); + + // Equal priority on same channel → ChannelPriorityTooLow (check is <=) + // Use different data_len to get a distinct hash with same priority + let result = store.submit(statement(1, 5, Some(1), 101), source); + assert!( + matches!(result, SubmitResult::Rejected(RejectionReason::ChannelPriorityTooLow { .. })), + "Equal priority should be rejected with ChannelPriorityTooLow, got: {result:?}" + ); + + // Higher priority on same channel → replaces + let s2 = statement(1, 10, Some(1), 200); + let h2 = s2.hash(); + assert_eq!(store.submit(s2, source), SubmitResult::New); + + { + let index = store.index.read(); + assert_eq!(index.entries.len(), 1); + assert!(!index.entries.contains_key(&h1), "Old channel message should be gone"); + assert!(index.entries.contains_key(&h2), "New channel message should exist"); + assert!(index.expired.contains_key(&h1), "Old should be in expired"); + assert_eq!(index.total_size, 200); + } + } + + #[test] + fn channel_replacement_with_size_increase_evicts_others() { + let (store, _temp) = test_store(); + let source = StatementSource::Network; + + // Account 3: max_count=3, max_size=1000 + // channel msg (200b) + two non-channel msgs (300b each) = 800b + let s_ch = statement(3, 5, Some(1), 200); + let s_low = statement(3, 2, None, 300); + let s_mid = statement(3, 3, None, 300); + let h_ch = s_ch.hash(); + let h_low = s_low.hash(); + let h_mid = s_mid.hash(); + + assert_eq!(store.submit(s_ch, source), SubmitResult::New); + assert_eq!(store.submit(s_low, source), SubmitResult::New); + assert_eq!(store.submit(s_mid, source), SubmitResult::New); + assert_eq!(store.index.read().total_size, 800); + + // Replace channel with 600b message (priority 10 > 5) + // Must evict lowest priority non-channel statement (priority 2) to fit + let s_ch_big = statement(3, 10, Some(1), 600); + let h_ch_big = s_ch_big.hash(); + assert_eq!(store.submit(s_ch_big, source), SubmitResult::New); + + { + let index = store.index.read(); + assert_eq!(index.entries.len(), 2); + assert!(!index.entries.contains_key(&h_ch), "Old channel message replaced"); + assert!(!index.entries.contains_key(&h_low), "Priority 2 evicted to fit size"); + assert!(index.entries.contains_key(&h_mid), "Priority 3 should remain"); + assert!(index.entries.contains_key(&h_ch_big), "New channel message added"); + assert_eq!(index.total_size, 900); // 300 (mid) + 600 (new channel) + } + } } From 0cf1e2cb6cb43cb69d6a76aec048e3669e854a4b Mon Sep 17 00:00:00 2001 From: "cmd[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 19:53:33 +0000 Subject: [PATCH 2/2] Update from github-actions[bot] running command 'prdoc --audience node_dev --bump patch' --- prdoc/pr_11617.prdoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 prdoc/pr_11617.prdoc diff --git a/prdoc/pr_11617.prdoc b/prdoc/pr_11617.prdoc new file mode 100644 index 000000000000..f18dd6d30a35 --- /dev/null +++ b/prdoc/pr_11617.prdoc @@ -0,0 +1,14 @@ +title: 'statement-store: add channel replacement logic tests' +doc: +- audience: Node Dev + description: |- + # Description + Implement unit tests for "Channel replacement: verify only higher-priority statements replace existing entries, corner cases of replacement logic." #11534 + + ## Summary + - `channel_replacement_only_higher_priority_succeeds` -> verifies lower/equal priority rejected with `ChannelPriorityTooLow`, higher priority replaces, one-per-channel invariant preserved + + - `channel_replacement_with_size_increase_evicts_others` -> verifies that replacing a channel message with a larger one triggers additional eviction of lowest-priority non-channel statements to satisfy size constraints +crates: +- name: sc-statement-store + bump: patch