mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 05:41:07 +00:00
Refactor event type decoding and declaration (#221)
* Refactor event type decoding hand declartion Fixes #196, #181, #28 ## Dyanmic sized types Before this change, the event decoder assume all the event types have fixed sizes. Some counterexamples are: Hashes, AuthorityList. In this change, instead of decoding by skipping the fixed-length bytes, we introduce `type_segmenter` registry which decodes the raw event bytes with the actual scale codec. So variable length types can be handled correctly. ## New attribute for pallet type definition In the past, trait associated type is the only way to add types to the EventsDecoder implementation of a pallet. But in reality it's common that the events in a pallet references some types not defined in the trait associated types. Some examples are: `IdentificationTuple` and `SessionIndex` in Session pallet. In this change, we introduce more attributes to add the types: ```rust #[module] trait Pallet: System { #![event_type(SomeType)] #![event_alias(TypeNameAlias = SomeType)] #![event_alias(SomeOtherAlias = TypeWithAssociatedTypes<T>)] } ``` ## Tested Compile with `nightly-2020-10-01`; smoke test to sync a full Phala bockchain. * Format code * Make rustfmt::skip an outer attribute * Ignore the sample code * Alias the event segmenter closure * Copy AuthorityList from sp_finality_grandpa * Remove the unused static event type size * Make segmenter as a trait, resue grandpa::Public * Wrap PhantomData in struct TypeMarker
This commit is contained in:
+47
-10
@@ -32,6 +32,7 @@ use std::{
|
||||
HashMap,
|
||||
HashSet,
|
||||
},
|
||||
fmt,
|
||||
marker::{
|
||||
PhantomData,
|
||||
Send,
|
||||
@@ -71,20 +72,48 @@ impl std::fmt::Debug for RawEvent {
|
||||
}
|
||||
}
|
||||
|
||||
trait TypeSegmenter: Send {
|
||||
/// Consumes an object from an input stream, and output the serialized bytes.
|
||||
fn segment(&self, input: &mut &[u8], output: &mut Vec<u8>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TypeMarker<T>(PhantomData<T>);
|
||||
impl<T> TypeSegmenter for TypeMarker<T>
|
||||
where
|
||||
T: Codec + Send,
|
||||
{
|
||||
fn segment(&self, input: &mut &[u8], output: &mut Vec<u8>) -> Result<(), Error> {
|
||||
T::decode(input).map_err(Error::from)?.encode_to(output);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Events decoder.
|
||||
#[derive(Debug)]
|
||||
pub struct EventsDecoder<T> {
|
||||
metadata: Metadata,
|
||||
type_sizes: HashMap<String, usize>,
|
||||
type_segmenters: HashMap<String, Box<dyn TypeSegmenter>>,
|
||||
marker: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for EventsDecoder<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EventsDecoder<T>")
|
||||
.field("metadata", &self.metadata)
|
||||
.field(
|
||||
"type_segmenters",
|
||||
&self.type_segmenters.keys().cloned().collect::<String>(),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: System> EventsDecoder<T> {
|
||||
/// Creates a new `EventsDecoder`.
|
||||
pub fn new(metadata: Metadata) -> Self {
|
||||
let mut decoder = Self {
|
||||
metadata,
|
||||
type_sizes: HashMap::new(),
|
||||
type_segmenters: HashMap::new(),
|
||||
marker: PhantomData,
|
||||
};
|
||||
// register default event arg type sizes for dynamic decoding of events
|
||||
@@ -109,6 +138,8 @@ impl<T: System> EventsDecoder<T> {
|
||||
decoder.register_type_size::<T::BlockNumber>("BlockNumber");
|
||||
decoder.register_type_size::<T::Hash>("Hash");
|
||||
decoder.register_type_size::<u8>("VoteThreshold");
|
||||
// Additional types
|
||||
decoder.register_type_size::<(T::BlockNumber, u32)>("TaskAddress<BlockNumber>");
|
||||
decoder
|
||||
}
|
||||
|
||||
@@ -118,7 +149,10 @@ impl<T: System> EventsDecoder<T> {
|
||||
U: Default + Codec + Send + 'static,
|
||||
{
|
||||
let size = U::default().encode().len();
|
||||
self.type_sizes.insert(name.to_string(), size);
|
||||
// A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized
|
||||
// type to the output stream (&mut Vec<u8>).
|
||||
self.type_segmenters
|
||||
.insert(name.to_string(), Box::new(TypeMarker::<U>::default()));
|
||||
size
|
||||
}
|
||||
|
||||
@@ -129,7 +163,7 @@ impl<T: System> EventsDecoder<T> {
|
||||
for event in module.events() {
|
||||
for arg in event.arguments() {
|
||||
for primitive in arg.primitives() {
|
||||
if !self.type_sizes.contains_key(&primitive) {
|
||||
if !self.type_segmenters.contains_key(&primitive) {
|
||||
missing.insert(format!(
|
||||
"{}::{}::{}",
|
||||
module.name(),
|
||||
@@ -150,10 +184,10 @@ impl<T: System> EventsDecoder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_raw_bytes<I: Input, W: Output>(
|
||||
fn decode_raw_bytes<W: Output>(
|
||||
&self,
|
||||
args: &[EventArg],
|
||||
input: &mut I,
|
||||
input: &mut &[u8],
|
||||
output: &mut W,
|
||||
errors: &mut Vec<RuntimeError>,
|
||||
) -> Result<(), Error> {
|
||||
@@ -188,9 +222,9 @@ impl<T: System> EventsDecoder<T> {
|
||||
"DispatchResult" => DispatchResult::decode(input)?,
|
||||
"DispatchError" => Err(DispatchError::decode(input)?),
|
||||
_ => {
|
||||
if let Some(size) = self.type_sizes.get(name) {
|
||||
let mut buf = vec![0; *size];
|
||||
input.read(&mut buf)?;
|
||||
if let Some(seg) = self.type_segmenters.get(name) {
|
||||
let mut buf = Vec::<u8>::new();
|
||||
seg.segment(input, &mut buf)?;
|
||||
output.write(&buf);
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -268,9 +302,12 @@ impl<T: System> EventsDecoder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw event or error event
|
||||
#[derive(Debug)]
|
||||
pub enum Raw {
|
||||
/// Event
|
||||
Event(RawEvent),
|
||||
/// Error
|
||||
Error(RuntimeError),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user