diff --git a/src/events.rs b/src/events.rs index 609af5ac99..d7f5fb9e93 100644 --- a/src/events.rs +++ b/src/events.rs @@ -26,16 +26,20 @@ use crate::{ PhantomDataSendSync, Phase, }; +use bitvec::{ + order::Lsb0, + vec::BitVec, +}; use codec::{ Codec, Compact, Decode, - Encode, Error as CodecError, Input, }; use derivative::Derivative; use scale_info::{ + PortableRegistry, TypeDef, TypeDefPrimitive, }; @@ -161,165 +165,189 @@ impl EventsDecoder { input: &mut &[u8], output: &mut Vec, ) -> Result<(), BasicError> { - let ty = self - .metadata - .resolve_type(type_id) - .ok_or(MetadataError::TypeNotFound(type_id))?; - - fn decode_raw( - input: &mut &[u8], - output: &mut Vec, - ) -> Result<(), BasicError> { - let decoded = T::decode(input)?; - decoded.encode_to(output); + let all_bytes = *input; + // consume some bytes, moving the cursor forward: + decode_and_consume_type(type_id, &self.metadata.runtime_metadata().types, input)?; + // 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(()) + } +} + +// Given a type Id and a type registry, attempt to consume the bytes +// corresponding to that type from our input. +fn decode_and_consume_type( + type_id: u32, + types: &PortableRegistry, + input: &mut &[u8], +) -> Result<(), BasicError> { + let ty = types + .resolve(type_id) + .ok_or(MetadataError::TypeNotFound(type_id))?; + + fn consume_type(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(()) } - - match ty.type_def() { - TypeDef::Composite(composite) => { - for field in composite.fields() { - self.decode_type(field.ty().id(), input, output)? - } - Ok(()) + TypeDef::Variant(variant) => { + let variant_index = u8::decode(input)?; + let variant = variant + .variants() + .iter() + .find(|v| v.index() == variant_index) + .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) => { - let variant_index = u8::decode(input)?; - variant_index.encode_to(output); - let variant = variant - .variants() - .iter() - .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(()) + Ok(()) + } + TypeDef::Sequence(seq) => { + let len = >::decode(input)?; + for _ in 0..len.0 { + decode_and_consume_type(seq.type_param().id(), types, input)?; } - TypeDef::Sequence(seq) => { - let len = >::decode(input)?; - len.encode_to(output); - for _ in 0..len.0 { - self.decode_type(seq.type_param().id(), input, output)?; - } - Ok(()) + Ok(()) + } + TypeDef::Array(arr) => { + for _ in 0..arr.len() { + decode_and_consume_type(arr.type_param().id(), types, input)?; } - TypeDef::Array(arr) => { - for _ in 0..arr.len() { - self.decode_type(arr.type_param().id(), input, output)?; - } - Ok(()) + Ok(()) + } + TypeDef::Tuple(tuple) => { + for field in tuple.fields() { + decode_and_consume_type(field.id(), types, input)?; } - TypeDef::Tuple(tuple) => { - for field in tuple.fields() { - self.decode_type(field.id(), input, output)?; + Ok(()) + } + TypeDef::Primitive(primitive) => { + match primitive { + TypeDefPrimitive::Bool => consume_type::(input), + TypeDefPrimitive::Char => { + Err( + EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::Char) + .into(), + ) } - Ok(()) - } - TypeDef::Primitive(primitive) => { - match primitive { - TypeDefPrimitive::Bool => decode_raw::(input, output), - TypeDefPrimitive::Char => { - Err(EventsDecodingError::UnsupportedPrimitive( - TypeDefPrimitive::Char, - ) - .into()) - } - TypeDefPrimitive::Str => decode_raw::(input, output), - TypeDefPrimitive::U8 => decode_raw::(input, output), - TypeDefPrimitive::U16 => decode_raw::(input, output), - TypeDefPrimitive::U32 => decode_raw::(input, output), - TypeDefPrimitive::U64 => decode_raw::(input, output), - TypeDefPrimitive::U128 => decode_raw::(input, output), - TypeDefPrimitive::U256 => { - Err(EventsDecodingError::UnsupportedPrimitive( - TypeDefPrimitive::U256, - ) - .into()) - } - TypeDefPrimitive::I8 => decode_raw::(input, output), - TypeDefPrimitive::I16 => decode_raw::(input, output), - TypeDefPrimitive::I32 => decode_raw::(input, output), - TypeDefPrimitive::I64 => decode_raw::(input, output), - TypeDefPrimitive::I128 => decode_raw::(input, output), - TypeDefPrimitive::I256 => { - Err(EventsDecodingError::UnsupportedPrimitive( - TypeDefPrimitive::I256, - ) - .into()) - } + TypeDefPrimitive::Str => consume_type::(input), + TypeDefPrimitive::U8 => consume_type::(input), + TypeDefPrimitive::U16 => consume_type::(input), + TypeDefPrimitive::U32 => consume_type::(input), + TypeDefPrimitive::U64 => consume_type::(input), + TypeDefPrimitive::U128 => consume_type::(input), + TypeDefPrimitive::U256 => { + Err( + EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::U256) + .into(), + ) + } + TypeDefPrimitive::I8 => consume_type::(input), + TypeDefPrimitive::I16 => consume_type::(input), + TypeDefPrimitive::I32 => consume_type::(input), + TypeDefPrimitive::I64 => consume_type::(input), + TypeDefPrimitive::I128 => consume_type::(input), + TypeDefPrimitive::I256 => { + Err( + EventsDecodingError::UnsupportedPrimitive(TypeDefPrimitive::I256) + .into(), + ) } } - TypeDef::Compact(compact) => { - let inner = self - .metadata - .resolve_type(compact.type_param().id()) - .ok_or(MetadataError::TypeNotFound(type_id))?; - let mut decode_compact_primitive = |primitive: &TypeDefPrimitive| { - match primitive { - TypeDefPrimitive::U8 => decode_raw::>(input, output), - TypeDefPrimitive::U16 => { - decode_raw::>(input, output) - } - TypeDefPrimitive::U32 => { - decode_raw::>(input, output) - } - TypeDefPrimitive::U64 => { - decode_raw::>(input, output) - } - TypeDefPrimitive::U128 => { - decode_raw::>(input, output) - } - prim => { - Err(EventsDecodingError::InvalidCompactPrimitive( - prim.clone(), - ) + } + 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 { + TypeDefPrimitive::U8 => consume_type::>(input), + TypeDefPrimitive::U16 => consume_type::>(input), + TypeDefPrimitive::U32 => consume_type::>(input), + TypeDefPrimitive::U64 => consume_type::>(input), + TypeDefPrimitive::U128 => consume_type::>(input), + 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( + } + }; + match inner.type_def() { + TypeDef::Primitive(primitive) => decode_compact_primitive(primitive), + TypeDef::Composite(composite) => { + match composite.fields() { + [field] => { + let field_ty = + types.resolve(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" .into(), ) .into()) - } - } - _ => { - Err(EventsDecodingError::InvalidCompactType( - "Composite type must have a single field".into(), - ) - .into()) } } + _ => { + Err(EventsDecodingError::InvalidCompactType( + "Composite type must have a single field".into(), + ) + .into()) + } } - _ => { - Err(EventsDecodingError::InvalidCompactType( - "Compact type must be a primitive or a composite type".into(), - ) - .into()) - } + } + _ => { + Err(EventsDecodingError::InvalidCompactType( + "Compact type must be a primitive or a composite type".into(), + ) + .into()) } } - TypeDef::BitSequence(_bitseq) => { - // decode_raw:: - unimplemented!("BitVec decoding for events not implemented yet") + } + TypeDef::BitSequence(bitseq) => { + 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 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::>(input) + } + TypeDef::Primitive(TypeDefPrimitive::U16) => { + consume_type::>(input) + } + TypeDef::Primitive(TypeDefPrimitive::U32) => { + consume_type::>(input) + } + TypeDef::Primitive(TypeDefPrimitive::U64) => { + consume_type::>(input) + } + store => { + return Err(EventsDecodingError::InvalidBitSequenceType(format!( + "{:?}", + store + )) + .into()) + } } } } @@ -333,8 +361,12 @@ pub enum EventsDecodingError { /// Invalid compact type, must be an unsigned int. #[error("Invalid compact primitive {0:?}")] InvalidCompactPrimitive(TypeDefPrimitive), + /// Invalid compact type; error details in string. #[error("Invalid compact composite type {0}")] 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)] @@ -345,6 +377,7 @@ mod tests { DefaultConfig, Phase, }; + use codec::Encode; use frame_metadata::{ v14::{ ExtrinsicMetadata, @@ -360,6 +393,8 @@ mod tests { }; use std::convert::TryFrom; + type TypeId = scale_info::interner::UntrackedSymbol; + #[derive(Encode)] pub struct EventRecord { phase: Phase, @@ -377,6 +412,16 @@ mod tests { } } + fn singleton_type_registry( + ) -> (TypeId, PortableRegistry) { + let m = scale_info::MetaType::new::(); + 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(pallet_index: u8) -> PalletMetadata { let event = PalletEventMetadata { ty: meta_type::(), @@ -404,6 +449,19 @@ mod tests { EventsDecoder::::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::(); + let bytes = val.encode(); + let cursor = &mut &*bytes; + + decode_and_consume_type(type_id.id(), ®istry, cursor).unwrap(); + assert_eq!(cursor.len(), 0); + } + #[test] fn decode_single_event() { #[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.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], + ); + } }