use super::Error;
use crate::util;
use alloc::vec::Vec;
use core::{cmp, fmt, iter, num::NonZero, slice};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GrandpaConsensusLogRef<'a> {
ScheduledChange(GrandpaScheduledChangeRef<'a>),
ForcedChange {
reset_block_height: u64,
change: GrandpaScheduledChangeRef<'a>,
},
OnDisabled(u64),
Pause(u64),
Resume(u64),
}
impl<'a> GrandpaConsensusLogRef<'a> {
pub fn from_slice(slice: &'a [u8], block_number_bytes: usize) -> Result<Self, Error> {
Ok(nom::Parser::parse(
&mut nom::combinator::all_consuming(grandpa_consensus_log_ref(block_number_bytes)),
slice,
)
.map_err(|_: nom::Err<(&[u8], nom::error::ErrorKind)>| {
Error::GrandpaConsensusLogDecodeError
})?
.1)
}
pub fn scale_encoding(
&self,
block_number_bytes: usize,
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + use<'a>> + Clone + use<'a> {
let index = iter::once(match self {
GrandpaConsensusLogRef::ScheduledChange(_) => [1],
GrandpaConsensusLogRef::ForcedChange { .. } => [2],
GrandpaConsensusLogRef::OnDisabled(_) => [3],
GrandpaConsensusLogRef::Pause(_) => [4],
GrandpaConsensusLogRef::Resume(_) => [5],
});
let body = match self {
GrandpaConsensusLogRef::ScheduledChange(change) => either::Left(either::Left(
change
.scale_encoding(block_number_bytes)
.map(either::Left)
.map(either::Left),
)),
GrandpaConsensusLogRef::ForcedChange {
reset_block_height,
change,
} => {
let mut data = Vec::with_capacity(block_number_bytes);
data.extend_from_slice(&reset_block_height.to_le_bytes());
data.resize(block_number_bytes, 0);
either::Left(either::Right(
iter::once(either::Right(either::Right(data))).chain(
change
.scale_encoding(block_number_bytes)
.map(either::Right)
.map(either::Left),
),
))
}
GrandpaConsensusLogRef::OnDisabled(n) => {
either::Right(iter::once(either::Right(either::Left(n.to_le_bytes()))))
}
GrandpaConsensusLogRef::Pause(n) => {
let mut data = Vec::with_capacity(block_number_bytes);
data.extend_from_slice(&n.to_le_bytes());
data.resize(block_number_bytes, 0);
either::Right(iter::once(either::Right(either::Right(data))))
}
GrandpaConsensusLogRef::Resume(n) => {
let mut data = Vec::with_capacity(block_number_bytes);
data.extend_from_slice(&n.to_le_bytes());
data.resize(block_number_bytes, 0);
either::Right(iter::once(either::Right(either::Right(data))))
}
};
index.map(either::Left).chain(body.map(either::Right))
}
}
impl<'a> From<&'a GrandpaConsensusLog> for GrandpaConsensusLogRef<'a> {
fn from(a: &'a GrandpaConsensusLog) -> Self {
match a {
GrandpaConsensusLog::ScheduledChange(v) => {
GrandpaConsensusLogRef::ScheduledChange(v.into())
}
GrandpaConsensusLog::ForcedChange {
reset_block_height,
change,
} => GrandpaConsensusLogRef::ForcedChange {
reset_block_height: *reset_block_height,
change: change.into(),
},
GrandpaConsensusLog::OnDisabled(v) => GrandpaConsensusLogRef::OnDisabled(*v),
GrandpaConsensusLog::Pause(v) => GrandpaConsensusLogRef::Pause(*v),
GrandpaConsensusLog::Resume(v) => GrandpaConsensusLogRef::Resume(*v),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GrandpaConsensusLog {
ScheduledChange(GrandpaScheduledChange),
ForcedChange {
reset_block_height: u64,
change: GrandpaScheduledChange,
},
OnDisabled(u64),
Pause(u64),
Resume(u64),
}
impl<'a> From<GrandpaConsensusLogRef<'a>> for GrandpaConsensusLog {
fn from(a: GrandpaConsensusLogRef<'a>) -> Self {
match a {
GrandpaConsensusLogRef::ScheduledChange(v) => {
GrandpaConsensusLog::ScheduledChange(v.into())
}
GrandpaConsensusLogRef::ForcedChange {
reset_block_height,
change,
} => GrandpaConsensusLog::ForcedChange {
reset_block_height,
change: change.into(),
},
GrandpaConsensusLogRef::OnDisabled(v) => GrandpaConsensusLog::OnDisabled(v),
GrandpaConsensusLogRef::Pause(v) => GrandpaConsensusLog::Pause(v),
GrandpaConsensusLogRef::Resume(v) => GrandpaConsensusLog::Resume(v),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GrandpaScheduledChangeRef<'a> {
pub next_authorities: GrandpaAuthoritiesIter<'a>,
pub delay: u64,
}
impl<'a> GrandpaScheduledChangeRef<'a> {
pub fn scale_encoding(
&self,
block_number_bytes: usize,
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + use<'a>> + Clone + use<'a> {
let header = util::encode_scale_compact_usize(self.next_authorities.len());
let mut delay = Vec::with_capacity(block_number_bytes);
delay.extend_from_slice(&self.delay.to_le_bytes());
delay.resize(block_number_bytes, 0);
iter::once(either::Left(either::Left(header)))
.chain(
self.next_authorities
.clone()
.flat_map(|a| a.scale_encoding())
.map(either::Right),
)
.chain(iter::once(either::Left(either::Right(delay))))
}
}
impl<'a> From<&'a GrandpaScheduledChange> for GrandpaScheduledChangeRef<'a> {
fn from(gp: &'a GrandpaScheduledChange) -> Self {
GrandpaScheduledChangeRef {
next_authorities: GrandpaAuthoritiesIter(GrandpaAuthoritiesIterInner::Decoded(
gp.next_authorities.iter(),
)),
delay: gp.delay,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GrandpaScheduledChange {
pub next_authorities: Vec<GrandpaAuthority>,
pub delay: u64,
}
impl<'a> From<GrandpaScheduledChangeRef<'a>> for GrandpaScheduledChange {
fn from(gp: GrandpaScheduledChangeRef<'a>) -> Self {
GrandpaScheduledChange {
next_authorities: gp.next_authorities.map(Into::into).collect(),
delay: gp.delay,
}
}
}
#[derive(Clone)]
pub struct GrandpaAuthoritiesIter<'a>(GrandpaAuthoritiesIterInner<'a>);
#[derive(Clone)]
enum GrandpaAuthoritiesIterInner<'a> {
Encoded(slice::Chunks<'a, u8>),
Decoded(slice::Iter<'a, GrandpaAuthority>),
}
impl<'a> GrandpaAuthoritiesIter<'a> {
pub fn new(slice: &'a [GrandpaAuthority]) -> Self {
GrandpaAuthoritiesIter(GrandpaAuthoritiesIterInner::Decoded(slice.iter()))
}
}
impl<'a> Iterator for GrandpaAuthoritiesIter<'a> {
type Item = GrandpaAuthorityRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
GrandpaAuthoritiesIterInner::Decoded(inner) => inner.next().map(Into::into),
GrandpaAuthoritiesIterInner::Encoded(inner) => {
let item = inner.next()?;
Some(
nom::Parser::parse(
&mut nom::combinator::all_consuming::<_, (&[u8], nom::error::ErrorKind), _>(
grandpa_authority_ref,
),
item,
)
.unwrap()
.1,
)
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.0 {
GrandpaAuthoritiesIterInner::Encoded(inner) => inner.size_hint(),
GrandpaAuthoritiesIterInner::Decoded(inner) => inner.size_hint(),
}
}
}
impl<'a> ExactSizeIterator for GrandpaAuthoritiesIter<'a> {}
impl<'a> cmp::PartialEq<GrandpaAuthoritiesIter<'a>> for GrandpaAuthoritiesIter<'a> {
fn eq(&self, other: &GrandpaAuthoritiesIter<'a>) -> bool {
let mut a = self.clone();
let mut b = other.clone();
loop {
match (a.next(), b.next()) {
(Some(a), Some(b)) if a == b => {}
(None, None) => return true,
_ => return false,
}
}
}
}
impl<'a> cmp::Eq for GrandpaAuthoritiesIter<'a> {}
impl<'a> fmt::Debug for GrandpaAuthoritiesIter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GrandpaAuthorityRef<'a> {
pub public_key: &'a [u8; 32],
pub weight: NonZero<u64>,
}
impl<'a> GrandpaAuthorityRef<'a> {
pub fn scale_encoding(
&self,
) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + use<'a>> + Clone + use<'a> {
iter::once(either::Right(self.public_key))
.chain(iter::once(either::Left(self.weight.get().to_le_bytes())))
}
}
impl<'a> From<&'a GrandpaAuthority> for GrandpaAuthorityRef<'a> {
fn from(gp: &'a GrandpaAuthority) -> Self {
GrandpaAuthorityRef {
public_key: &gp.public_key,
weight: gp.weight,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GrandpaAuthority {
pub public_key: [u8; 32],
pub weight: NonZero<u64>,
}
impl GrandpaAuthority {
pub fn scale_encoding(&self) -> impl Iterator<Item = impl AsRef<[u8]> + Clone> + Clone {
GrandpaAuthorityRef::from(self).scale_encoding()
}
}
impl<'a> From<GrandpaAuthorityRef<'a>> for GrandpaAuthority {
fn from(gp: GrandpaAuthorityRef<'a>) -> Self {
GrandpaAuthority {
public_key: *gp.public_key,
weight: gp.weight,
}
}
}
fn grandpa_consensus_log_ref<
'a,
E: nom::error::ParseError<&'a [u8]> + nom::error::ContextError<&'a [u8]>,
>(
block_number_bytes: usize,
) -> impl nom::Parser<&'a [u8], Output = GrandpaConsensusLogRef<'a>, Error = E> {
nom::error::context(
"grandpa_consensus_log_ref",
nom::branch::alt((
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[1][..]),
grandpa_scheduled_change_ref(block_number_bytes),
),
GrandpaConsensusLogRef::ScheduledChange,
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[2][..]),
(
crate::util::nom_varsize_number_decode_u64(block_number_bytes),
grandpa_scheduled_change_ref(block_number_bytes),
),
),
|(reset_block_height, change)| GrandpaConsensusLogRef::ForcedChange {
reset_block_height,
change,
},
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[3][..]),
nom::number::streaming::le_u64,
),
GrandpaConsensusLogRef::OnDisabled,
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[4][..]),
crate::util::nom_varsize_number_decode_u64(block_number_bytes),
),
GrandpaConsensusLogRef::Pause,
),
nom::combinator::map(
nom::sequence::preceded(
nom::bytes::streaming::tag(&[5][..]),
crate::util::nom_varsize_number_decode_u64(block_number_bytes),
),
GrandpaConsensusLogRef::Resume,
),
)),
)
}
fn grandpa_scheduled_change_ref<
'a,
E: nom::error::ParseError<&'a [u8]> + nom::error::ContextError<&'a [u8]>,
>(
block_number_bytes: usize,
) -> impl nom::Parser<&'a [u8], Output = GrandpaScheduledChangeRef<'a>, Error = E> {
nom::error::context(
"grandpa_scheduled_change_ref",
nom::combinator::map(
(
nom::combinator::flat_map(util::nom_scale_compact_usize, |num_authorities| {
nom::combinator::map(
nom::combinator::recognize(nom::multi::fold_many_m_n(
num_authorities,
num_authorities,
grandpa_authority_ref,
|| {},
|(), _| (),
)),
|bytes| {
GrandpaAuthoritiesIter(GrandpaAuthoritiesIterInner::Encoded(
bytes.chunks(40),
))
},
)
}),
crate::util::nom_varsize_number_decode_u64(block_number_bytes),
),
|(next_authorities, delay)| GrandpaScheduledChangeRef {
next_authorities,
delay,
},
),
)
}
fn grandpa_authority_ref<
'a,
E: nom::error::ParseError<&'a [u8]> + nom::error::ContextError<&'a [u8]>,
>(
bytes: &'a [u8],
) -> nom::IResult<&'a [u8], GrandpaAuthorityRef<'a>, E> {
nom::Parser::parse(
&mut nom::error::context(
"grandpa_authority_ref",
nom::combinator::map(
(
nom::bytes::streaming::take(32u32),
nom::combinator::map_opt(nom::number::streaming::le_u64, NonZero::<u64>::new),
),
|(public_key, weight)| GrandpaAuthorityRef {
public_key: TryFrom::try_from(public_key).unwrap(),
weight,
},
),
),
bytes,
)
}