Allow decoding Events containing BitVecs (#408)

* Handle bitvec decoding

* clippy

* rework bitvec decoding; don't care about order and can handle other store primitives

* cargo fmt
This commit is contained in:
James Wilson
2022-01-27 16:02:15 +00:00
committed by GitHub
parent 5f5a7ef5f7
commit d1494b5cb6
+230 -139
View File
@@ -26,16 +26,20 @@ use crate::{
PhantomDataSendSync, PhantomDataSendSync,
Phase, Phase,
}; };
use bitvec::{
order::Lsb0,
vec::BitVec,
};
use codec::{ use codec::{
Codec, Codec,
Compact, Compact,
Decode, Decode,
Encode,
Error as CodecError, Error as CodecError,
Input, Input,
}; };
use derivative::Derivative; use derivative::Derivative;
use scale_info::{ use scale_info::{
PortableRegistry,
TypeDef, TypeDef,
TypeDefPrimitive, TypeDefPrimitive,
}; };
@@ -161,165 +165,189 @@ impl<T: Config> EventsDecoder<T> {
input: &mut &[u8], input: &mut &[u8],
output: &mut Vec<u8>, output: &mut Vec<u8>,
) -> Result<(), BasicError> { ) -> Result<(), BasicError> {
let ty = self let all_bytes = *input;
.metadata // consume some bytes, moving the cursor forward:
.resolve_type(type_id) decode_and_consume_type(type_id, &self.metadata.runtime_metadata().types, input)?;
.ok_or(MetadataError::TypeNotFound(type_id))?; // count how many bytes were consumed based on remaining length:
let consumed_len = all_bytes.len() - input.len();
// move those consumed bytes to the output vec unaltered:
output.extend(&all_bytes[0..consumed_len]);
Ok(())
}
}
fn decode_raw<T: Codec>( // Given a type Id and a type registry, attempt to consume the bytes
input: &mut &[u8], // corresponding to that type from our input.
output: &mut Vec<u8>, fn decode_and_consume_type(
) -> Result<(), BasicError> { type_id: u32,
let decoded = T::decode(input)?; types: &PortableRegistry,
decoded.encode_to(output); input: &mut &[u8],
) -> Result<(), BasicError> {
let ty = types
.resolve(type_id)
.ok_or(MetadataError::TypeNotFound(type_id))?;
fn consume_type<T: Codec>(input: &mut &[u8]) -> Result<(), BasicError> {
T::decode(input)?;
Ok(())
}
match ty.type_def() {
TypeDef::Composite(composite) => {
for field in composite.fields() {
decode_and_consume_type(field.ty().id(), types, input)?
}
Ok(()) Ok(())
} }
TypeDef::Variant(variant) => {
match ty.type_def() { let variant_index = u8::decode(input)?;
TypeDef::Composite(composite) => { let variant = variant
for field in composite.fields() { .variants()
self.decode_type(field.ty().id(), input, output)? .iter()
} .find(|v| v.index() == variant_index)
Ok(()) .ok_or_else(|| {
BasicError::Other(format!("Variant {} not found", variant_index))
})?;
for field in variant.fields() {
decode_and_consume_type(field.ty().id(), types, input)?;
} }
TypeDef::Variant(variant) => { Ok(())
let variant_index = u8::decode(input)?; }
variant_index.encode_to(output); TypeDef::Sequence(seq) => {
let variant = variant let len = <Compact<u32>>::decode(input)?;
.variants() for _ in 0..len.0 {
.iter() decode_and_consume_type(seq.type_param().id(), types, input)?;
.find(|v| v.index() == variant_index)
.ok_or_else(|| {
BasicError::Other(format!("Variant {} not found", variant_index))
})?;
for field in variant.fields() {
self.decode_type(field.ty().id(), input, output)?;
}
Ok(())
} }
TypeDef::Sequence(seq) => { Ok(())
let len = <Compact<u32>>::decode(input)?; }
len.encode_to(output); TypeDef::Array(arr) => {
for _ in 0..len.0 { for _ in 0..arr.len() {
self.decode_type(seq.type_param().id(), input, output)?; decode_and_consume_type(arr.type_param().id(), types, input)?;
}
Ok(())
} }
TypeDef::Array(arr) => { Ok(())
for _ in 0..arr.len() { }
self.decode_type(arr.type_param().id(), input, output)?; TypeDef::Tuple(tuple) => {
} for field in tuple.fields() {
Ok(()) decode_and_consume_type(field.id(), types, input)?;
} }
TypeDef::Tuple(tuple) => { Ok(())
for field in tuple.fields() { }
self.decode_type(field.id(), input, output)?; TypeDef::Primitive(primitive) => {
match primitive {
TypeDefPrimitive::Bool => consume_type::<bool>(input),
TypeDefPrimitive::Char => {
Err(
EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::Char)
.into(),
)
}
TypeDefPrimitive::Str => consume_type::<String>(input),
TypeDefPrimitive::U8 => consume_type::<u8>(input),
TypeDefPrimitive::U16 => consume_type::<u16>(input),
TypeDefPrimitive::U32 => consume_type::<u32>(input),
TypeDefPrimitive::U64 => consume_type::<u64>(input),
TypeDefPrimitive::U128 => consume_type::<u128>(input),
TypeDefPrimitive::U256 => {
Err(
EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::U256)
.into(),
)
}
TypeDefPrimitive::I8 => consume_type::<i8>(input),
TypeDefPrimitive::I16 => consume_type::<i16>(input),
TypeDefPrimitive::I32 => consume_type::<i32>(input),
TypeDefPrimitive::I64 => consume_type::<i64>(input),
TypeDefPrimitive::I128 => consume_type::<i128>(input),
TypeDefPrimitive::I256 => {
Err(
EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::I256)
.into(),
)
} }
Ok(())
} }
TypeDef::Primitive(primitive) => { }
TypeDef::Compact(compact) => {
let inner = types
.resolve(compact.type_param().id())
.ok_or(MetadataError::TypeNotFound(type_id))?;
let mut decode_compact_primitive = |primitive: &TypeDefPrimitive| {
match primitive { match primitive {
TypeDefPrimitive::Bool => decode_raw::<bool>(input, output), TypeDefPrimitive::U8 => consume_type::<Compact<u8>>(input),
TypeDefPrimitive::Char => { TypeDefPrimitive::U16 => consume_type::<Compact<u16>>(input),
Err(EventsDecodingError::UnsupportedPrimitive( TypeDefPrimitive::U32 => consume_type::<Compact<u32>>(input),
TypeDefPrimitive::Char, TypeDefPrimitive::U64 => consume_type::<Compact<u64>>(input),
) TypeDefPrimitive::U128 => consume_type::<Compact<u128>>(input),
.into()) prim => {
} Err(EventsDecodingError::InvalidCompactPrimitive(prim.clone())
TypeDefPrimitive::Str => decode_raw::<String>(input, output), .into())
TypeDefPrimitive::U8 => decode_raw::<u8>(input, output),
TypeDefPrimitive::U16 => decode_raw::<u16>(input, output),
TypeDefPrimitive::U32 => decode_raw::<u32>(input, output),
TypeDefPrimitive::U64 => decode_raw::<u64>(input, output),
TypeDefPrimitive::U128 => decode_raw::<u128>(input, output),
TypeDefPrimitive::U256 => {
Err(EventsDecodingError::UnsupportedPrimitive(
TypeDefPrimitive::U256,
)
.into())
}
TypeDefPrimitive::I8 => decode_raw::<i8>(input, output),
TypeDefPrimitive::I16 => decode_raw::<i16>(input, output),
TypeDefPrimitive::I32 => decode_raw::<i32>(input, output),
TypeDefPrimitive::I64 => decode_raw::<i64>(input, output),
TypeDefPrimitive::I128 => decode_raw::<i128>(input, output),
TypeDefPrimitive::I256 => {
Err(EventsDecodingError::UnsupportedPrimitive(
TypeDefPrimitive::I256,
)
.into())
} }
} }
} };
TypeDef::Compact(compact) => { match inner.type_def() {
let inner = self TypeDef::Primitive(primitive) => decode_compact_primitive(primitive),
.metadata TypeDef::Composite(composite) => {
.resolve_type(compact.type_param().id()) match composite.fields() {
.ok_or(MetadataError::TypeNotFound(type_id))?; [field] => {
let mut decode_compact_primitive = |primitive: &TypeDefPrimitive| { let field_ty =
match primitive { types.resolve(field.ty().id()).ok_or_else(|| {
TypeDefPrimitive::U8 => decode_raw::<Compact<u8>>(input, output), MetadataError::TypeNotFound(field.ty().id())
TypeDefPrimitive::U16 => { })?;
decode_raw::<Compact<u16>>(input, output) if let TypeDef::Primitive(primitive) = field_ty.type_def() {
} decode_compact_primitive(primitive)
TypeDefPrimitive::U32 => { } else {
decode_raw::<Compact<u32>>(input, output) Err(EventsDecodingError::InvalidCompactType(
}
TypeDefPrimitive::U64 => {
decode_raw::<Compact<u64>>(input, output)
}
TypeDefPrimitive::U128 => {
decode_raw::<Compact<u128>>(input, output)
}
prim => {
Err(EventsDecodingError::InvalidCompactPrimitive(
prim.clone(),
)
.into())
}
}
};
match inner.type_def() {
TypeDef::Primitive(primitive) => decode_compact_primitive(primitive),
TypeDef::Composite(composite) => {
match composite.fields() {
[field] => {
let field_ty = self
.metadata
.resolve_type(field.ty().id())
.ok_or_else(|| {
MetadataError::TypeNotFound(field.ty().id())
})?;
if let TypeDef::Primitive(primitive) = field_ty.type_def()
{
decode_compact_primitive(primitive)
} else {
Err(EventsDecodingError::InvalidCompactType(
"Composite type must have a single primitive field" "Composite type must have a single primitive field"
.into(), .into(),
) )
.into()) .into())
}
}
_ => {
Err(EventsDecodingError::InvalidCompactType(
"Composite type must have a single field".into(),
)
.into())
} }
} }
} _ => {
_ => { Err(EventsDecodingError::InvalidCompactType(
Err(EventsDecodingError::InvalidCompactType( "Composite type must have a single field".into(),
"Compact type must be a primitive or a composite type".into(), )
) .into())
.into()) }
} }
} }
_ => {
Err(EventsDecodingError::InvalidCompactType(
"Compact type must be a primitive or a composite type".into(),
)
.into())
}
} }
TypeDef::BitSequence(_bitseq) => { }
// decode_raw::<bitvec::BitVec> TypeDef::BitSequence(bitseq) => {
unimplemented!("BitVec decoding for events not implemented yet") let bit_store_def = types
.resolve(bitseq.bit_store_type().id())
.ok_or(MetadataError::TypeNotFound(type_id))?
.type_def();
// We just need to consume the correct number of bytes. Roughly, we encode this
// as a Compact<u32> length, and then a slice of T of that length, where T is the
// bit store type. So, we ignore the bit order and only care that the bit store type
// used lines up in terms of the number of bytes it will take to encode/decode it.
match bit_store_def {
TypeDef::Primitive(TypeDefPrimitive::U8) => {
consume_type::<BitVec<Lsb0, u8>>(input)
}
TypeDef::Primitive(TypeDefPrimitive::U16) => {
consume_type::<BitVec<Lsb0, u16>>(input)
}
TypeDef::Primitive(TypeDefPrimitive::U32) => {
consume_type::<BitVec<Lsb0, u32>>(input)
}
TypeDef::Primitive(TypeDefPrimitive::U64) => {
consume_type::<BitVec<Lsb0, u64>>(input)
}
store => {
return Err(EventsDecodingError::InvalidBitSequenceType(format!(
"{:?}",
store
))
.into())
}
} }
} }
} }
@@ -333,8 +361,12 @@ pub enum EventsDecodingError {
/// Invalid compact type, must be an unsigned int. /// Invalid compact type, must be an unsigned int.
#[error("Invalid compact primitive {0:?}")] #[error("Invalid compact primitive {0:?}")]
InvalidCompactPrimitive(TypeDefPrimitive), InvalidCompactPrimitive(TypeDefPrimitive),
/// Invalid compact type; error details in string.
#[error("Invalid compact composite type {0}")] #[error("Invalid compact composite type {0}")]
InvalidCompactType(String), InvalidCompactType(String),
/// Invalid bit sequence type; bit store type or bit order type used aren't supported.
#[error("Invalid bit sequence type; bit store type {0} is not supported")]
InvalidBitSequenceType(String),
} }
#[cfg(test)] #[cfg(test)]
@@ -345,6 +377,7 @@ mod tests {
DefaultConfig, DefaultConfig,
Phase, Phase,
}; };
use codec::Encode;
use frame_metadata::{ use frame_metadata::{
v14::{ v14::{
ExtrinsicMetadata, ExtrinsicMetadata,
@@ -360,6 +393,8 @@ mod tests {
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
type TypeId = scale_info::interner::UntrackedSymbol<std::any::TypeId>;
#[derive(Encode)] #[derive(Encode)]
pub struct EventRecord<E: Encode> { pub struct EventRecord<E: Encode> {
phase: Phase, phase: Phase,
@@ -377,6 +412,16 @@ mod tests {
} }
} }
fn singleton_type_registry<T: scale_info::TypeInfo + 'static>(
) -> (TypeId, PortableRegistry) {
let m = scale_info::MetaType::new::<T>();
let mut types = scale_info::Registry::new();
let id = types.register_type(&m);
let portable_registry: PortableRegistry = types.into();
(id, portable_registry)
}
fn pallet_metadata<E: TypeInfo + 'static>(pallet_index: u8) -> PalletMetadata { fn pallet_metadata<E: TypeInfo + 'static>(pallet_index: u8) -> PalletMetadata {
let event = PalletEventMetadata { let event = PalletEventMetadata {
ty: meta_type::<E>(), ty: meta_type::<E>(),
@@ -404,6 +449,19 @@ mod tests {
EventsDecoder::<DefaultConfig>::new(metadata) EventsDecoder::<DefaultConfig>::new(metadata)
} }
fn decode_and_consume_type_consumes_all_bytes<
T: codec::Encode + scale_info::TypeInfo + 'static,
>(
val: T,
) {
let (type_id, registry) = singleton_type_registry::<T>();
let bytes = val.encode();
let cursor = &mut &*bytes;
decode_and_consume_type(type_id.id(), &registry, cursor).unwrap();
assert_eq!(cursor.len(), 0);
}
#[test] #[test]
fn decode_single_event() { fn decode_single_event() {
#[derive(Clone, Encode, TypeInfo)] #[derive(Clone, Encode, TypeInfo)]
@@ -552,4 +610,37 @@ mod tests {
assert_eq!(events[0].1.variant_index, encoded_event[0]); assert_eq!(events[0].1.variant_index, encoded_event[0]);
assert_eq!(events[0].1.data.0, encoded_event[1..]); assert_eq!(events[0].1.data.0, encoded_event[1..]);
} }
#[test]
fn decode_bitvec() {
use bitvec::order::Msb0;
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Lsb0, u8; 0, 1, 1, 0, 1],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Msb0, u8; 0, 1, 1, 0, 1, 0, 1, 0, 0],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Lsb0, u16; 0, 1, 1, 0, 1],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Msb0, u16; 0, 1, 1, 0, 1, 0, 1, 0, 0],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Lsb0, u32; 0, 1, 1, 0, 1],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Msb0, u32; 0, 1, 1, 0, 1, 0, 1, 0, 0],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Lsb0, u64; 0, 1, 1, 0, 1],
);
decode_and_consume_type_consumes_all_bytes(
bitvec::bitvec![Msb0, u64; 0, 1, 1, 0, 1, 0, 1, 0, 0],
);
}
} }