use crate::header;
use alloc::vec;
use nom::Finish as _;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BlockAnnouncesHandshakeRef<'a> {
pub role: Role,
pub best_number: u64,
pub best_hash: &'a [u8; 32],
pub genesis_hash: &'a [u8; 32],
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Role {
Authority,
Full,
Light,
}
impl Role {
pub fn scale_encoding(&self) -> [u8; 1] {
match *self {
Role::Full => [0b1],
Role::Light => [0b10],
Role::Authority => [0b100],
}
}
}
#[derive(Debug)]
pub struct BlockAnnounceRef<'a> {
pub scale_encoded_header: &'a [u8],
pub is_best: bool,
}
pub fn encode_block_announce(announce: BlockAnnounceRef) -> impl Iterator<Item = impl AsRef<[u8]>> {
let is_best = if announce.is_best { [1u8] } else { [0u8] };
[
either::Left(announce.scale_encoded_header),
either::Right(is_best),
either::Right([0u8]),
]
.into_iter()
}
pub fn decode_block_announce(
bytes: &'_ [u8],
block_number_bytes: usize,
) -> Result<BlockAnnounceRef<'_>, DecodeBlockAnnounceError> {
let result: Result<_, nom::error::Error<_>> = nom::Parser::parse(
&mut nom::combinator::all_consuming(nom::combinator::complete(nom::combinator::map(
(
nom::combinator::recognize(|enc_hdr| {
match header::decode_partial(enc_hdr, block_number_bytes) {
Ok((hdr, rest)) => Ok((rest, hdr)),
Err(_) => Err(nom::Err::Failure(nom::error::make_error(
enc_hdr,
nom::error::ErrorKind::Verify,
))),
}
}),
nom::branch::alt((
nom::combinator::map(nom::bytes::streaming::tag(&[0][..]), |_| false),
nom::combinator::map(nom::bytes::streaming::tag(&[1][..]), |_| true),
)),
crate::util::nom_bytes_decode,
),
|(scale_encoded_header, is_best, _)| BlockAnnounceRef {
scale_encoded_header,
is_best,
},
))),
bytes,
)
.finish();
match result {
Ok((_, ann)) => Ok(ann),
Err(err) => Err(DecodeBlockAnnounceError(err.code)),
}
}
#[derive(Debug, derive_more::Display, derive_more::Error)]
#[display("Failed to decode a block announcement")]
pub struct DecodeBlockAnnounceError(#[error(not(source))] nom::error::ErrorKind);
pub fn encode_block_announces_handshake(
handshake: BlockAnnouncesHandshakeRef,
block_number_bytes: usize,
) -> impl Iterator<Item = impl AsRef<[u8]>> {
let mut header = vec![0; 1 + block_number_bytes];
header[0] = handshake.role.scale_encoding()[0];
header[1..].copy_from_slice(&handshake.best_number.to_le_bytes()[..block_number_bytes]);
[
either::Left(header),
either::Right(handshake.best_hash),
either::Right(handshake.genesis_hash),
]
.into_iter()
}
pub fn decode_block_announces_handshake(
expected_block_number_bytes: usize,
handshake: &'_ [u8],
) -> Result<BlockAnnouncesHandshakeRef<'_>, BlockAnnouncesHandshakeDecodeError> {
let result: Result<_, nom::error::Error<_>> = nom::Parser::parse(
&mut nom::combinator::all_consuming(nom::combinator::complete(nom::combinator::map(
(
nom::branch::alt((
nom::combinator::map(nom::bytes::streaming::tag(&[0b1][..]), |_| Role::Full),
nom::combinator::map(nom::bytes::streaming::tag(&[0b10][..]), |_| Role::Light),
nom::combinator::map(nom::bytes::streaming::tag(&[0b100][..]), |_| {
Role::Authority
}),
)),
crate::util::nom_varsize_number_decode_u64(expected_block_number_bytes),
nom::bytes::streaming::take(32u32),
nom::bytes::streaming::take(32u32),
),
|(role, best_number, best_hash, genesis_hash)| BlockAnnouncesHandshakeRef {
role,
best_number,
best_hash: TryFrom::try_from(best_hash).unwrap(),
genesis_hash: TryFrom::try_from(genesis_hash).unwrap(),
},
))),
handshake,
)
.finish();
match result {
Ok((_, hs)) => Ok(hs),
Err(err) => Err(BlockAnnouncesHandshakeDecodeError(err.code)),
}
}
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
#[display("Failed to decode a block announces handshake")]
pub struct BlockAnnouncesHandshakeDecodeError(#[error(not(source))] nom::error::ErrorKind);