Skip to content

Commit 3c46002

Browse files
authored
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
1 parent 5a0201c commit 3c46002

File tree

5 files changed

+149
-17
lines changed

5 files changed

+149
-17
lines changed

proc-macro/src/module.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,62 @@ fn events_decoder_trait_name(module: &syn::Ident) -> syn::Ident {
6969
fn with_module_ident(module: &syn::Ident) -> syn::Ident {
7070
format_ident!("with_{}", module.to_string().to_snake_case())
7171
}
72+
73+
type EventAttr = utils::UniAttr<syn::Type>;
74+
type EventAliasAttr = utils::UniAttr<utils::Attr<syn::Ident, syn::Type>>;
75+
76+
/// Parses the event type definition macros within #[module]
77+
///
78+
/// It supports two ways to define the associated event type:
79+
///
80+
/// ```ignore
81+
/// #[module]
82+
/// trait Pallet: System {
83+
/// #![event_type(SomeType)]
84+
/// #![event_alias(TypeNameAlias = SomeType)]
85+
/// #![event_alias(SomeOtherAlias = TypeWithAssociatedTypes<T>)]
86+
/// }
87+
/// ```
88+
fn parse_event_type_attr(attr: &syn::Attribute) -> Option<(String, syn::Type)> {
89+
let ident = utils::path_to_ident(&attr.path);
90+
if ident == "event_type" {
91+
let attrs: EventAttr = syn::parse2(attr.tokens.clone())
92+
.map_err(|err| abort!("{}", err))
93+
.unwrap();
94+
let ty = attrs.attr;
95+
let ident_str = quote!(#ty).to_string();
96+
Some((ident_str, ty))
97+
} else if ident == "event_alias" {
98+
let attrs: EventAliasAttr = syn::parse2(attr.tokens.clone())
99+
.map_err(|err| abort!("{}", err))
100+
.unwrap();
101+
let ty = attrs.attr.value;
102+
let ident_str = attrs.attr.key.to_string();
103+
Some((ident_str, ty))
104+
} else {
105+
None
106+
}
107+
}
108+
72109
/// Attribute macro that registers the type sizes used by the module; also sets the `MODULE` constant.
73110
pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
74111
let input: Result<syn::ItemTrait, _> = syn::parse2(tokens.clone());
75-
let input = if let Ok(input) = input {
112+
let mut input = if let Ok(input) = input {
76113
input
77114
} else {
78115
// handle #[module(ignore)] by just returning the tokens
79116
return tokens
80117
};
81118

119+
// Parse the inner attributes `event_type` and `event_alias` and remove them from the macro
120+
// outputs.
121+
let (other_attrs, event_types): (Vec<_>, Vec<_>) = input
122+
.attrs
123+
.iter()
124+
.cloned()
125+
.partition(|attr| parse_event_type_attr(attr).is_none());
126+
input.attrs = other_attrs;
127+
82128
let subxt = utils::use_crate("substrate-subxt");
83129
let module = &input.ident;
84130
let module_name = module.to_string();
@@ -96,7 +142,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
96142
None
97143
}
98144
});
99-
let types = input.items.iter().filter_map(|item| {
145+
let associated_types = input.items.iter().filter_map(|item| {
100146
if let syn::TraitItem::Type(ty) = item {
101147
if ignore(&ty.attrs) {
102148
return None
@@ -110,6 +156,12 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
110156
None
111157
}
112158
});
159+
let types = event_types.iter().map(|attr| {
160+
let (ident_str, ty) = parse_event_type_attr(&attr).unwrap();
161+
quote! {
162+
self.register_type_size::<#ty>(#ident_str);
163+
}
164+
});
113165

114166
quote! {
115167
#input
@@ -127,6 +179,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
127179
{
128180
fn #with_module(&mut self) {
129181
#(#bounds)*
182+
#(#associated_types)*
130183
#(#types)*
131184
}
132185
}

proc-macro/src/utils.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,21 @@ impl<K: Parse, V: Parse> Parse for Attr<K, V> {
214214
}
215215
}
216216

217+
#[derive(Debug)]
218+
pub struct UniAttr<A> {
219+
pub paren: syn::token::Paren,
220+
pub attr: A,
221+
}
222+
223+
impl<A: Parse> Parse for UniAttr<A> {
224+
fn parse(input: ParseStream) -> syn::Result<Self> {
225+
let content;
226+
let paren = syn::parenthesized!(content in input);
227+
let attr = content.parse()?;
228+
Ok(Self { paren, attr })
229+
}
230+
}
231+
217232
#[cfg(test)]
218233
pub(crate) fn assert_proc_macro(
219234
result: proc_macro2::TokenStream,

src/events.rs

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::{
3232
HashMap,
3333
HashSet,
3434
},
35+
fmt,
3536
marker::{
3637
PhantomData,
3738
Send,
@@ -71,20 +72,48 @@ impl std::fmt::Debug for RawEvent {
7172
}
7273
}
7374

75+
trait TypeSegmenter: Send {
76+
/// Consumes an object from an input stream, and output the serialized bytes.
77+
fn segment(&self, input: &mut &[u8], output: &mut Vec<u8>) -> Result<(), Error>;
78+
}
79+
80+
#[derive(Default)]
81+
struct TypeMarker<T>(PhantomData<T>);
82+
impl<T> TypeSegmenter for TypeMarker<T>
83+
where
84+
T: Codec + Send,
85+
{
86+
fn segment(&self, input: &mut &[u8], output: &mut Vec<u8>) -> Result<(), Error> {
87+
T::decode(input).map_err(Error::from)?.encode_to(output);
88+
Ok(())
89+
}
90+
}
91+
7492
/// Events decoder.
75-
#[derive(Debug)]
7693
pub struct EventsDecoder<T> {
7794
metadata: Metadata,
78-
type_sizes: HashMap<String, usize>,
95+
type_segmenters: HashMap<String, Box<dyn TypeSegmenter>>,
7996
marker: PhantomData<fn() -> T>,
8097
}
8198

99+
impl<T> fmt::Debug for EventsDecoder<T> {
100+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101+
f.debug_struct("EventsDecoder<T>")
102+
.field("metadata", &self.metadata)
103+
.field(
104+
"type_segmenters",
105+
&self.type_segmenters.keys().cloned().collect::<String>(),
106+
)
107+
.finish()
108+
}
109+
}
110+
82111
impl<T: System> EventsDecoder<T> {
83112
/// Creates a new `EventsDecoder`.
84113
pub fn new(metadata: Metadata) -> Self {
85114
let mut decoder = Self {
86115
metadata,
87-
type_sizes: HashMap::new(),
116+
type_segmenters: HashMap::new(),
88117
marker: PhantomData,
89118
};
90119
// register default event arg type sizes for dynamic decoding of events
@@ -109,6 +138,8 @@ impl<T: System> EventsDecoder<T> {
109138
decoder.register_type_size::<T::BlockNumber>("BlockNumber");
110139
decoder.register_type_size::<T::Hash>("Hash");
111140
decoder.register_type_size::<u8>("VoteThreshold");
141+
// Additional types
142+
decoder.register_type_size::<(T::BlockNumber, u32)>("TaskAddress<BlockNumber>");
112143
decoder
113144
}
114145

@@ -118,7 +149,10 @@ impl<T: System> EventsDecoder<T> {
118149
U: Default + Codec + Send + 'static,
119150
{
120151
let size = U::default().encode().len();
121-
self.type_sizes.insert(name.to_string(), size);
152+
// A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized
153+
// type to the output stream (&mut Vec<u8>).
154+
self.type_segmenters
155+
.insert(name.to_string(), Box::new(TypeMarker::<U>::default()));
122156
size
123157
}
124158

@@ -129,7 +163,7 @@ impl<T: System> EventsDecoder<T> {
129163
for event in module.events() {
130164
for arg in event.arguments() {
131165
for primitive in arg.primitives() {
132-
if !self.type_sizes.contains_key(&primitive) {
166+
if !self.type_segmenters.contains_key(&primitive) {
133167
missing.insert(format!(
134168
"{}::{}::{}",
135169
module.name(),
@@ -150,10 +184,10 @@ impl<T: System> EventsDecoder<T> {
150184
}
151185
}
152186

153-
fn decode_raw_bytes<I: Input, W: Output>(
187+
fn decode_raw_bytes<W: Output>(
154188
&self,
155189
args: &[EventArg],
156-
input: &mut I,
190+
input: &mut &[u8],
157191
output: &mut W,
158192
errors: &mut Vec<RuntimeError>,
159193
) -> Result<(), Error> {
@@ -188,9 +222,9 @@ impl<T: System> EventsDecoder<T> {
188222
"DispatchResult" => DispatchResult::decode(input)?,
189223
"DispatchError" => Err(DispatchError::decode(input)?),
190224
_ => {
191-
if let Some(size) = self.type_sizes.get(name) {
192-
let mut buf = vec![0; *size];
193-
input.read(&mut buf)?;
225+
if let Some(seg) = self.type_segmenters.get(name) {
226+
let mut buf = Vec::<u8>::new();
227+
seg.segment(input, &mut buf)?;
194228
output.write(&buf);
195229
Ok(())
196230
} else {
@@ -268,9 +302,12 @@ impl<T: System> EventsDecoder<T> {
268302
}
269303
}
270304

305+
/// Raw event or error event
271306
#[derive(Debug)]
272307
pub enum Raw {
308+
/// Event
273309
Event(RawEvent),
310+
/// Error
274311
Error(RuntimeError),
275312
}
276313

src/frame/session.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@
1515
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
1616

1717
//! Session support
18-
use crate::frame::system::{
19-
System,
20-
SystemEventsDecoder as _,
18+
use crate::frame::{
19+
balances::{
20+
Balances,
21+
BalancesEventsDecoder as _,
22+
},
23+
system::{
24+
System,
25+
SystemEventsDecoder as _,
26+
},
2127
};
2228
use codec::Encode;
2329
use frame_support::Parameter;
@@ -45,9 +51,18 @@ macro_rules! default_impl {
4551
};
4652
}
4753

54+
type IdentificationTuple<T> = (
55+
<T as Session>::ValidatorId,
56+
pallet_staking::Exposure<<T as System>::AccountId, <T as Balances>::Balance>,
57+
);
58+
4859
/// The trait needed for this module.
4960
#[module]
50-
pub trait Session: System {
61+
pub trait Session: System + Balances {
62+
#![event_alias(IdentificationTuple = IdentificationTuple<T>)]
63+
#![event_alias(OpaqueTimeSlot = Vec<u8>)]
64+
#![event_alias(SessionIndex = u32)]
65+
5166
/// The validator account identifier type for the runtime.
5267
type ValidatorId: Parameter + Debug + Ord + Default + Send + Sync + 'static;
5368

src/frame/staking.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,21 @@ pub struct SetPayeeCall<T: Staking> {
6262
pub _runtime: PhantomData<T>,
6363
}
6464

65+
/// Identity of a Grandpa authority.
66+
pub type AuthorityId = crate::runtimes::app::grandpa::Public;
67+
/// The weight of an authority.
68+
pub type AuthorityWeight = u64;
69+
/// A list of Grandpa authorities with associated weights.
70+
pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>;
71+
6572
/// The subset of the `frame::Trait` that a client must implement.
6673
#[module]
67-
pub trait Staking: Balances {}
74+
#[rustfmt::skip]
75+
pub trait Staking: Balances {
76+
#![event_alias(ElectionCompute = u8)]
77+
#![event_type(EraIndex)]
78+
#![event_type(AuthorityList)]
79+
}
6880

6981
/// Number of eras to keep in history.
7082
///

0 commit comments

Comments
 (0)