mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-16 07:15:41 +00:00
Custom Codec Implenetation for NPoS Election (#6720)
* Fancy compact encode/decode impl for compact solution * Make it optional * Remove extra file * Update primitives/npos-elections/compact/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Final fixes. Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -15,11 +15,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Code generation for the ratio assignment type.
|
||||
//! Code generation for the ratio assignment type' compact representation.
|
||||
|
||||
use crate::field_name_for;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use syn::GenericArgument;
|
||||
use quote::quote;
|
||||
|
||||
fn from_impl(count: usize) -> TokenStream2 {
|
||||
@@ -27,8 +26,8 @@ fn from_impl(count: usize) -> TokenStream2 {
|
||||
let name = field_name_for(1);
|
||||
quote!(1 => compact.#name.push(
|
||||
(
|
||||
index_of_voter(&who).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_target(&distribution[0].0).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_voter(&who).or_invalid_index()?,
|
||||
index_of_target(&distribution[0].0).or_invalid_index()?,
|
||||
)
|
||||
),)
|
||||
};
|
||||
@@ -37,29 +36,29 @@ fn from_impl(count: usize) -> TokenStream2 {
|
||||
let name = field_name_for(2);
|
||||
quote!(2 => compact.#name.push(
|
||||
(
|
||||
index_of_voter(&who).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_voter(&who).or_invalid_index()?,
|
||||
(
|
||||
index_of_target(&distribution[0].0).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_target(&distribution[0].0).or_invalid_index()?,
|
||||
distribution[0].1,
|
||||
),
|
||||
index_of_target(&distribution[1].0).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_target(&distribution[1].0).or_invalid_index()?,
|
||||
)
|
||||
),)
|
||||
};
|
||||
|
||||
let from_impl_rest = (3..=count).map(|c| {
|
||||
let inner = (0..c-1).map(|i|
|
||||
quote!((index_of_target(&distribution[#i].0).ok_or(_phragmen::Error::CompactInvalidIndex)?, distribution[#i].1),)
|
||||
quote!((index_of_target(&distribution[#i].0).or_invalid_index()?, distribution[#i].1),)
|
||||
).collect::<TokenStream2>();
|
||||
|
||||
let field_name = field_name_for(c);
|
||||
let last_index = c - 1;
|
||||
let last = quote!(index_of_target(&distribution[#last_index].0).ok_or(_phragmen::Error::CompactInvalidIndex)?);
|
||||
let last = quote!(index_of_target(&distribution[#last_index].0).or_invalid_index()?);
|
||||
|
||||
quote!(
|
||||
#c => compact.#field_name.push(
|
||||
(
|
||||
index_of_voter(&who).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
index_of_voter(&who).or_invalid_index()?,
|
||||
[#inner],
|
||||
#last,
|
||||
)
|
||||
@@ -74,15 +73,15 @@ fn from_impl(count: usize) -> TokenStream2 {
|
||||
)
|
||||
}
|
||||
|
||||
fn into_impl(count: usize) -> TokenStream2 {
|
||||
fn into_impl(count: usize, per_thing: syn::Type) -> TokenStream2 {
|
||||
let into_impl_single = {
|
||||
let name = field_name_for(1);
|
||||
quote!(
|
||||
for (voter_index, target_index) in self.#name {
|
||||
assignments.push(_phragmen::Assignment {
|
||||
who: voter_at(voter_index).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
who: voter_at(voter_index).or_invalid_index()?,
|
||||
distribution: vec![
|
||||
(target_at(target_index).ok_or(_phragmen::Error::CompactInvalidIndex)?, Accuracy::one())
|
||||
(target_at(target_index).or_invalid_index()?, #per_thing::one())
|
||||
],
|
||||
})
|
||||
}
|
||||
@@ -93,21 +92,21 @@ fn into_impl(count: usize) -> TokenStream2 {
|
||||
let name = field_name_for(2);
|
||||
quote!(
|
||||
for (voter_index, (t1_idx, p1), t2_idx) in self.#name {
|
||||
if p1 >= Accuracy::one() {
|
||||
if p1 >= #per_thing::one() {
|
||||
return Err(_phragmen::Error::CompactStakeOverflow);
|
||||
}
|
||||
|
||||
// defensive only. Since Percent doesn't have `Sub`.
|
||||
let p2 = _phragmen::sp_arithmetic::traits::Saturating::saturating_sub(
|
||||
Accuracy::one(),
|
||||
#per_thing::one(),
|
||||
p1,
|
||||
);
|
||||
|
||||
assignments.push( _phragmen::Assignment {
|
||||
who: voter_at(voter_index).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
who: voter_at(voter_index).or_invalid_index()?,
|
||||
distribution: vec![
|
||||
(target_at(t1_idx).ok_or(_phragmen::Error::CompactInvalidIndex)?, p1),
|
||||
(target_at(t2_idx).ok_or(_phragmen::Error::CompactInvalidIndex)?, p2),
|
||||
(target_at(t1_idx).or_invalid_index()?, p1),
|
||||
(target_at(t2_idx).or_invalid_index()?, p2),
|
||||
]
|
||||
});
|
||||
}
|
||||
@@ -118,30 +117,30 @@ fn into_impl(count: usize) -> TokenStream2 {
|
||||
let name = field_name_for(c);
|
||||
quote!(
|
||||
for (voter_index, inners, t_last_idx) in self.#name {
|
||||
let mut sum = Accuracy::zero();
|
||||
let mut sum = #per_thing::zero();
|
||||
let mut inners_parsed = inners
|
||||
.iter()
|
||||
.map(|(ref t_idx, p)| {
|
||||
sum = _phragmen::sp_arithmetic::traits::Saturating::saturating_add(sum, *p);
|
||||
let target = target_at(*t_idx).ok_or(_phragmen::Error::CompactInvalidIndex)?;
|
||||
let target = target_at(*t_idx).or_invalid_index()?;
|
||||
Ok((target, *p))
|
||||
})
|
||||
.collect::<Result<Vec<(A, Accuracy)>, _phragmen::Error>>()?;
|
||||
.collect::<Result<Vec<(A, #per_thing)>, _phragmen::Error>>()?;
|
||||
|
||||
if sum >= Accuracy::one() {
|
||||
if sum >= #per_thing::one() {
|
||||
return Err(_phragmen::Error::CompactStakeOverflow);
|
||||
}
|
||||
|
||||
// defensive only. Since Percent doesn't have `Sub`.
|
||||
let p_last = _phragmen::sp_arithmetic::traits::Saturating::saturating_sub(
|
||||
Accuracy::one(),
|
||||
#per_thing::one(),
|
||||
sum,
|
||||
);
|
||||
|
||||
inners_parsed.push((target_at(t_last_idx).ok_or(_phragmen::Error::CompactInvalidIndex)?, p_last));
|
||||
inners_parsed.push((target_at(t_last_idx).or_invalid_index()?, p_last));
|
||||
|
||||
assignments.push(_phragmen::Assignment {
|
||||
who: voter_at(voter_index).ok_or(_phragmen::Error::CompactInvalidIndex)?,
|
||||
who: voter_at(voter_index).or_invalid_index()?,
|
||||
distribution: inners_parsed,
|
||||
});
|
||||
}
|
||||
@@ -157,39 +156,28 @@ fn into_impl(count: usize) -> TokenStream2 {
|
||||
|
||||
pub(crate) fn assignment(
|
||||
ident: syn::Ident,
|
||||
voter_type: GenericArgument,
|
||||
target_type: GenericArgument,
|
||||
voter_type: syn::Type,
|
||||
target_type: syn::Type,
|
||||
weight_type: syn::Type,
|
||||
count: usize,
|
||||
) -> TokenStream2 {
|
||||
|
||||
let from_impl = from_impl(count);
|
||||
let into_impl = into_impl(count);
|
||||
let into_impl = into_impl(count, weight_type.clone());
|
||||
|
||||
quote!(
|
||||
impl<
|
||||
#voter_type: _phragmen::codec::Codec + Default + Copy,
|
||||
#target_type: _phragmen::codec::Codec + Default + Copy,
|
||||
Accuracy:
|
||||
_phragmen::codec::Codec + Default + Clone + _phragmen::sp_arithmetic::PerThing +
|
||||
PartialOrd,
|
||||
>
|
||||
#ident<#voter_type, #target_type, Accuracy>
|
||||
{
|
||||
use _phragmen::__OrInvalidIndex;
|
||||
impl #ident {
|
||||
pub fn from_assignment<FV, FT, A>(
|
||||
assignments: Vec<_phragmen::Assignment<A, Accuracy>>,
|
||||
assignments: Vec<_phragmen::Assignment<A, #weight_type>>,
|
||||
index_of_voter: FV,
|
||||
index_of_target: FT,
|
||||
) -> Result<Self, _phragmen::Error>
|
||||
where
|
||||
A: _phragmen::IdentifierT,
|
||||
for<'r> FV: Fn(&'r A) -> Option<#voter_type>,
|
||||
for<'r> FT: Fn(&'r A) -> Option<#target_type>,
|
||||
A: _phragmen::IdentifierT,
|
||||
{
|
||||
let mut compact: #ident<
|
||||
#voter_type,
|
||||
#target_type,
|
||||
Accuracy,
|
||||
> = Default::default();
|
||||
let mut compact: #ident = Default::default();
|
||||
|
||||
for _phragmen::Assignment { who, distribution } in assignments {
|
||||
match distribution.len() {
|
||||
@@ -207,8 +195,8 @@ pub(crate) fn assignment(
|
||||
self,
|
||||
voter_at: impl Fn(#voter_type) -> Option<A>,
|
||||
target_at: impl Fn(#target_type) -> Option<A>,
|
||||
) -> Result<Vec<_phragmen::Assignment<A, Accuracy>>, _phragmen::Error> {
|
||||
let mut assignments: Vec<_phragmen::Assignment<A, Accuracy>> = Default::default();
|
||||
) -> Result<Vec<_phragmen::Assignment<A, #weight_type>>, _phragmen::Error> {
|
||||
let mut assignments: Vec<_phragmen::Assignment<A, #weight_type>> = Default::default();
|
||||
#into_impl
|
||||
Ok(assignments)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user