use alloc::vec::Vec;
use bytes::{Buf, Bytes};
use codec::{Compact, Decode, Encode};
use ed25519_consensus::{Signature, VerificationKey};
const SIGNATURE_LEN: usize = 64;
#[derive(Encode, Debug, Default, Clone)]
pub struct InputChunk {
pub video: Bytes,
pub audio: Bytes,
pub console: Bytes,
pub host_messages: Vec<Bytes>,
}
impl InputChunk {
pub fn decode_signed(mut input: Bytes, key: &VerificationKey) -> Result<Self, codec::Error> {
let signature_offset = input.len().checked_sub(SIGNATURE_LEN).ok_or("No signature")?;
let signature = input.split_off(signature_offset);
let signature: Signature = (&signature[..]).try_into().expect("Signature size is constant");
key.verify(&signature, &input[..]).map_err(|_| "Bad signature")?;
let mut input = BytesInput(input);
let video = input.decode_bytes()?;
let audio = input.decode_bytes()?;
let console = input.decode_bytes()?;
let Compact(len) = Compact::<u32>::decode(&mut input)?;
let mut host_messages = Vec::new();
for _ in 0..len {
host_messages.push(input.decode_bytes()?);
}
if !input.0.is_empty() {
return Err("Invalid InputChunk".into());
}
Ok(Self { video, audio, console, host_messages })
}
pub fn decode_multiple_signed(
extrinsic: Bytes,
key: &VerificationKey,
) -> Result<Vec<Self>, codec::Error> {
let mut chunks = Vec::new();
let mut input = BytesInput(extrinsic);
while !input.0.is_empty() {
let raw_chunk = input.decode_bytes()?;
let chunk = Self::decode_signed(raw_chunk, key)?;
chunks.push(chunk);
}
Ok(chunks)
}
}
struct BytesInput(Bytes);
impl BytesInput {
fn decode_bytes(&mut self) -> Result<Bytes, codec::Error> {
let Compact(len) = Compact::<u32>::decode(self)?;
if len > self.0.len() as u32 {
return Err("Invalid bytes".into());
}
let bytes = self.0.split_to(len as usize);
Ok(bytes)
}
}
impl codec::Input for BytesInput {
fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
Ok(Some(self.0.len()))
}
fn read(&mut self, buf: &mut [u8]) -> Result<(), codec::Error> {
let n = buf.len();
if n > self.0.len() {
return Err("Buffer overflow".into());
}
buf.copy_from_slice(&self.0[..n]);
self.0.advance(n);
Ok(())
}
}