frame_suite/
elections.rs

1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ``````````````````````````````` ELECTIONS SUITE ```````````````````````````````
14// ===============================================================================
15
16//! Provides generic traits for **election management**, **weight computation**,
17//! and **influence calculation** using [`plugin`](crate::plugins)-based models.
18//!
19//! The traits include:
20//! - [`ElectionManager`]: Core election management for candidates.
21//! - [`InspectWeight`]: Provides candidate weight lookup.
22//! - [`Influence`]: Computes influence values from raw input using plugin models.
23//!
24//! ## Note
25//!
26//! Elections are **pluggable by design**, meaning:
27//! - The **inputs** generally consist of candidates along with their backing
28//! weights (or votes).  
29//! - The **outputs** can be a single candidate or a collection of candidates
30//! (stored via an iterator).  
31//!
32//! Because of this, we define **generic plugin-based traits**, enabling:
33//! 1. Multiple election models to be implemented over the same trait interfaces.  
34//! 2. Flexible storage and computation strategies depending on the election logic.  
35//! 3. Strong type-safety while maintaining runtime configurability via plugins.  
36
37// ===============================================================================
38// ``````````````````````````````````` IMPORTS ```````````````````````````````````
39// ===============================================================================
40
41// --- Local crate imports ---
42use crate::{
43    base::{Buffer, Delimited, Elastic, Keyed, RuntimeType, Sortable, Storable},
44    plugin_output, plugin_types,
45};
46
47// --- Substrate primitives ---
48use sp_runtime::{DispatchError, DispatchResult};
49
50// ===============================================================================
51// `````````````````````````````` ELECTION MANAGER ```````````````````````````````
52// ===============================================================================
53
54/// A trait for **managing elections** of candidates with associated weights.
55///
56/// This trait is designed to be **highly generic** and
57/// [`plugin-driven`](crate::plugins), enabling multiple election models
58/// to be used without modifying the trait itself.
59///
60/// Elections are inherently **pluggable and diverse**:
61/// - Different elections may use distinct **weighting rules** or
62///   **selection algorithms**.
63/// - Inputs consist of candidates paired with their backing weights.
64/// - Outputs may represent either a single winner or multiple winners.
65/// - A plugin-based design allows flexible implementations while
66///   preserving type safety and runtime configurability.
67///
68/// ## Type Parameters
69/// - `Candidate`: The type representing a candidate in the election.
70pub trait ElectionManager<Candidate>: InspectWeight<Candidate, Self::ElectionWeightOf>
71where
72    Candidate: Keyed,
73{
74    /// Represents a single vote or its associated weight.
75    ///
76    /// This can either:
77    /// - Store a numeric weight for a vote, or
78    /// - Represent a single vote implicitly.
79    ///
80    /// Must implement [`Ord`] to allow comparison and sorting within
81    /// [`Self::ElectionWeightOf`].
82    type ElectionWeight: Sortable;
83
84    /// Collection type for storing candidate weights.
85    ///
86    /// This allows flexibility in the underlying container, such as:
87    /// - `Vec`
88    /// - Arrays
89    /// - Custom buffer types
90    ///
91    /// Must support:
92    /// - Iteration via [`Buffer`]
93    /// - Ordering via [`Ord`]
94    /// - Storage via [`Storable`]
95    type ElectionWeightOf: Buffer<Self::ElectionWeight> + Ord + Storable;
96
97    /// Input type for election computation.
98    ///
99    /// Each entry maps a candidate to a collection of associated weights.
100    ///
101    /// This abstraction ensures that plugin implementations only accept
102    /// well-structured and compatible input formats.
103    type Params: Buffer<(Candidate, Self::ElectionWeightOf)>;
104
105    /// Output type representing elected candidates.
106    ///
107    /// This can represent:
108    /// - Multiple winners (e.g., committee selection), or
109    /// - A single winner (as a single-element collection)
110    ///
111    /// If the output implies ranking, the elements are expected to be
112    /// ordered by priority.
113    ///
114    /// If truncation occurs (e.g., selecting top-N winners), the ordering
115    /// must reflect the final priority of elected candidates.
116    type Elected: Buffer<Candidate>;
117
118    plugin_types!(
119        input: Self::Params,
120        output: Self::Elected,
121        /// The plugin responsible for computing election results.
122        ///
123        /// This model defines the election strategy by:
124        /// - Consuming [`Self::Params`] as input, and
125        /// - Producing [`Self::Elected`] as output.
126        ///
127        /// This abstraction allows multiple election strategies to be
128        /// plugged in safely and interchangeably.
129        ///
130        /// If the resulting [`Self::Elected`] is truncated (e.g., selecting top-N),
131        /// the candidates must be ordered by priority.
132        model: ElectionModel,
133
134        /// Provides runtime configuration for the [`Self::ElectionModel`] computation.
135        ///
136        /// This context supplies dynamic parameters such as:
137        /// - Thresholds
138        /// - Weights
139        /// - Other runtime-specific settings
140        ///
141        /// It enables flexible behavior without requiring hardcoded values.
142        context: ElectionContext,
143    );
144
145    /// Executes the election process and persists the results.
146    ///
147    /// This function:
148    /// 1. Runs the election model using [`Self::run_model`]
149    /// 2. Stores the resulting elected candidates via [`Self::store`]
150    fn prepare(from: Self::Params) -> DispatchResult {
151        // Computes the plugin output
152        let out = &Self::run_model(from);
153        // stores the output of elected candidates
154        if let Err(e) = Self::store(out) {
155            Self::on_prepare_fail(e);
156            return Ok(());
157        };
158        Self::on_prepare_success(out);
159        Ok(())
160    }
161
162    plugin_output! {
163        /// [`Self::ElectionModel`] plugin output function.
164        ///
165        /// Utilizes the plugin model's context [`Self::ElectionContext`]
166        fn run_model,
167        input: Self::Params,
168        output: Self::Elected,
169        model: Self::ElectionModel,
170        context: Self::ElectionContext
171    }
172
173    /// Persist the election results. Must be implemented by the consumer.
174    fn store(_elects: &Self::Elected) -> DispatchResult;
175
176    /// Retrieve currently elected candidates.
177    fn reveal() -> Option<Self::Elected>;
178
179    /// Remove a candidate from the elected pool.
180    fn remove(who: &Candidate);
181
182    /// Check if a candidate exist in the elected pool.
183    fn is_candidate(who: &Candidate) -> DispatchResult;
184
185    /// Check if election preparation is possible with the given parameters.
186    fn can_prepare(from: &Self::Params) -> DispatchResult;
187
188    /// Hook called after a successful election preparation. Default is no-op.
189    fn on_prepare_success(_elects: &Self::Elected) {}
190
191    /// Hook called after an election preparation failure. Default is no-op.
192    fn on_prepare_fail(_err: DispatchError) {}
193}
194
195// ===============================================================================
196// ``````````````````````````````` INSPECT WEIGHT ````````````````````````````````
197// ===============================================================================
198
199/// Trait for inspecting the **weight of a candidate** for an upcoming
200/// election.
201///
202/// - Different election models may compute or store weights differently.
203/// - Providing a trait allows generic election managers or plugins
204///   to query a candidate's weight without knowing the underlying structure.
205///
206/// ## Type Parameters
207/// - `Candidate`: The type representing a candidate.
208/// - `Weight`: The type representing the candidate's vote weight.
209pub trait InspectWeight<Candidate, Weight>
210where
211    Candidate: Keyed,
212    Weight: RuntimeType,
213{
214    /// Return the weight of a candidate if available.
215    ///
216    /// Returns an error if the candidate has no associated weight.
217    fn weight_of(who: &Candidate) -> Result<Weight, DispatchError>;
218}
219
220// ===============================================================================
221// `````````````````````````````````` INFLUENCE ``````````````````````````````````
222// ===============================================================================
223
224/// A trait for computing **influence**, a normalized and comparable metric
225/// representing the relative power or importance of an entity.
226///
227/// Influence is intended to capture **non-transferable system weight**,
228/// derived from various inputs such as votes, stake, participation,
229/// or other domain-specific factors.
230///
231/// ## Key Properties
232///
233/// - **Non-transferable**:
234///   Influence is a derived metric and must not be directly traded or transferred.
235/// - **Model-dependent**:
236///   Different systems may define influence differently based on their
237///   weighting rules or algorithms.
238/// - **Deterministic**:
239///   Given the same input and context, the computed influence should be consistent.
240/// - **Comparable**:
241///   Influence values must be bounded and comparable across entities.
242///
243/// ## Design
244///
245/// This trait follows a [`plugin`](crate::plugins)-based architecture:
246/// - The computation logic is delegated to pluggable models.
247/// - Different influence strategies can coexist without changing the trait.
248/// - Runtime configuration is supported via context.
249///
250/// ## Type Parameters
251/// - `RawFrom`: The raw input type used to derive influence.
252///
253///   This allows flexibility in supporting various input formats, such as:
254///   - Numeric values (e.g., stake or balance)
255///   - Account identifiers
256///   - Structured or aggregated data
257pub trait Influence<RawFrom>
258where
259    RawFrom: Elastic,
260{
261    /// Type representing the computed influence.
262    type Influence: Delimited;
263
264    plugin_types!(
265        input: RawFrom,
266        output: Self::Influence,
267        /// The plugin responsible for computing influence.
268        ///
269        /// This model defines how raw input is transformed into
270        /// a bounded influence value.
271        ///
272        /// Different models may implement:
273        /// - Linear scaling
274        /// - Weighted aggregation
275        /// - Non-linear transformations (e.g., logarithmic influence)
276        model: InfluenceModel,
277
278        /// Provides runtime configuration for [`Self::InfluenceModel`].
279        ///
280        /// This context supplies dynamic parameters such as:
281        /// - Scaling factors
282        /// - Thresholds
283        /// - External weights or modifiers
284        ///
285        /// This enables flexible and adaptive influence computation
286        /// without hardcoding logic.
287        context: InfluenceContext,
288    );
289
290    plugin_output! {
291        /// Computes influence from a raw input using the configured plugin.
292        ///
293        /// This function:
294        /// - Delegates computation to [`Self::InfluenceModel`]
295        /// - Uses [`Self::InfluenceContext`] for parameterization
296        ///
297        /// ## Returns
298        /// A bounded influence value derived from the given input.
299        fn influence,
300        input: RawFrom,
301        output: Self::Influence,
302        model: Self::InfluenceModel,
303        context: Self::InfluenceContext
304    }
305}