diff --git a/substrate/primitives/src/sp_borsh.rs b/substrate/primitives/src/sp_borsh.rs index 9e601f65..b474c6ab 100644 --- a/substrate/primitives/src/sp_borsh.rs +++ b/substrate/primitives/src/sp_borsh.rs @@ -17,21 +17,45 @@ pub fn borsh_deserialize_bitvec<R: Read>( Ok(bitvec::vec::BitVec::from_vec(bitvec)) } -type SerializeBoundedVecAs<T> = alloc::vec::Vec<T>; - -// TODO: Don't serialize this as a Vec<u8>. Shorten the length-prefix, technically encoding as an -// enum. pub fn borsh_serialize_bounded_vec<W: Write, T: BorshSerialize, const B: u32>( bounded: &BoundedVec<T, ConstU32<B>>, writer: &mut W, ) -> Result<()> { - let vec: &SerializeBoundedVecAs<T> = bounded.as_ref(); - BorshSerialize::serialize(vec, writer) + // Won't panic as `bytes_for_length` is <= 4 + let bytes_for_length = + usize::try_from((u32::BITS - B.leading_zeros()).div_ceil(u8::BITS)).unwrap(); + // Won't panic as this vec is bounded to a length specified as a u32 + let length = u32::try_from(bounded.len()).unwrap().to_le_bytes(); + writer.write_all(&length[0 .. bytes_for_length])?; + + for item in bounded.as_slice() { + BorshSerialize::serialize(item, writer)?; + } + + Ok(()) } pub fn borsh_deserialize_bounded_vec<R: Read, T: BorshDeserialize, const B: u32>( reader: &mut R, ) -> Result<BoundedVec<T, ConstU32<B>>> { - let vec: SerializeBoundedVecAs<T> = BorshDeserialize::deserialize_reader(reader)?; - vec.try_into().map_err(|_| Error::new(ErrorKind::Other, "bound exceeded")) + // Won't panic as `bytes_for_length` is <= 4 + let bytes_for_length = + usize::try_from((u32::BITS - B.leading_zeros()).div_ceil(u8::BITS)).unwrap(); + let mut length = [0u8; 4]; + reader.read_exact(&mut length[.. bytes_for_length])?; + let length = u32::from_le_bytes(length); + if length > B { + Err(Error::new(ErrorKind::Other, "bound exceeded"))?; + } + + // Won't panic so long as usize >= u32 + const { + assert!(usize::BITS >= u32::BITS, "wasn't compiled for at least a 32-bit platform"); + } + let mut vec = alloc::vec::Vec::with_capacity(length.try_into().unwrap()); + for _ in 0 .. length { + vec.push(T::deserialize_reader(reader)?); + } + // Won't panic as we already checked against the bound + Ok(vec.try_into().map_err(|_| ()).unwrap()) }