Skip to content

Commit 22f0855

Browse files
committed
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.
1 parent 754b184 commit 22f0855

File tree

6 files changed

+129
-13
lines changed

6 files changed

+129
-13
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ frame-metadata = "12.0.1"
3838
frame-support = "2.0.1"
3939
sp-runtime = "2.0.1"
4040
sp-version = "2.0.1"
41+
sp-finality-grandpa = { version = "2.0.1", default-features = false }
4142
pallet-indices = "2.0.1"
4243
hex = "0.4.2"
4344
sp-std = "2.0.1"

proc-macro/src/module.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,61 @@ 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+
/// ```
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.attrs
122+
.iter()
123+
.cloned()
124+
.partition(|attr| parse_event_type_attr(attr).is_none());
125+
input.attrs = other_attrs;
126+
82127
let subxt = utils::use_crate("substrate-subxt");
83128
let module = &input.ident;
84129
let module_name = module.to_string();
@@ -96,7 +141,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
96141
None
97142
}
98143
});
99-
let types = input.items.iter().filter_map(|item| {
144+
let associated_types = input.items.iter().filter_map(|item| {
100145
if let syn::TraitItem::Type(ty) = item {
101146
if ignore(&ty.attrs) {
102147
return None
@@ -110,6 +155,12 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
110155
None
111156
}
112157
});
158+
let types = event_types.iter().map(|attr| {
159+
let (ident_str, ty) = parse_event_type_attr(&attr).unwrap();
160+
quote! {
161+
self.register_type_size::<#ty>(#ident_str);
162+
}
163+
});
113164

114165
quote! {
115166
#input
@@ -127,6 +178,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
127178
{
128179
fn #with_module(&mut self) {
129180
#(#bounds)*
181+
#(#associated_types)*
130182
#(#types)*
131183
}
132184
}

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: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use sp_runtime::{
2828
DispatchResult,
2929
};
3030
use std::{
31+
fmt,
3132
collections::{
3233
HashMap,
3334
HashSet,
@@ -72,19 +73,32 @@ impl std::fmt::Debug for RawEvent {
7273
}
7374

7475
/// Events decoder.
75-
#[derive(Debug)]
7676
pub struct EventsDecoder<T> {
7777
metadata: Metadata,
7878
type_sizes: HashMap<String, usize>,
79+
type_segmenters: HashMap<
80+
String,
81+
Box<dyn Fn(&mut &[u8], &mut Vec<u8>) -> Result<(), Error> + Send>
82+
>,
7983
marker: PhantomData<fn() -> T>,
8084
}
8185

86+
impl<T> fmt::Debug for EventsDecoder<T> {
87+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88+
f.debug_struct("EventsDecoder<T>")
89+
.field("metadata", &self.metadata)
90+
.field("type_sizes", &self.type_sizes)
91+
.finish()
92+
}
93+
}
94+
8295
impl<T: System> EventsDecoder<T> {
8396
/// Creates a new `EventsDecoder`.
8497
pub fn new(metadata: Metadata) -> Self {
8598
let mut decoder = Self {
8699
metadata,
87100
type_sizes: HashMap::new(),
101+
type_segmenters: HashMap::new(),
88102
marker: PhantomData,
89103
};
90104
// register default event arg type sizes for dynamic decoding of events
@@ -109,6 +123,8 @@ impl<T: System> EventsDecoder<T> {
109123
decoder.register_type_size::<T::BlockNumber>("BlockNumber");
110124
decoder.register_type_size::<T::Hash>("Hash");
111125
decoder.register_type_size::<u8>("VoteThreshold");
126+
// Additional types
127+
decoder.register_type_size::<(T::BlockNumber, u32)>("TaskAddress<BlockNumber>");
112128
decoder
113129
}
114130

@@ -119,6 +135,13 @@ impl<T: System> EventsDecoder<T> {
119135
{
120136
let size = U::default().encode().len();
121137
self.type_sizes.insert(name.to_string(), size);
138+
// A segmenter decodes a type from an input stream (&mut &[u8]) and returns the serialized
139+
// type to the output stream (&mut Vec<u8>).
140+
self.type_segmenters.insert(name.to_string(),
141+
Box::new(|input: &mut &[u8], output: &mut Vec<u8>| -> Result<(), Error> {
142+
U::decode(input).map_err(Error::from)?.encode_to(output);
143+
Ok(())
144+
}));
122145
size
123146
}
124147

@@ -150,10 +173,10 @@ impl<T: System> EventsDecoder<T> {
150173
}
151174
}
152175

153-
fn decode_raw_bytes<I: Input, W: Output>(
176+
fn decode_raw_bytes<W: Output>(
154177
&self,
155178
args: &[EventArg],
156-
input: &mut I,
179+
input: &mut &[u8],
157180
output: &mut W,
158181
errors: &mut Vec<RuntimeError>,
159182
) -> Result<(), Error> {
@@ -188,9 +211,9 @@ impl<T: System> EventsDecoder<T> {
188211
"DispatchResult" => DispatchResult::decode(input)?,
189212
"DispatchError" => Err(DispatchError::decode(input)?),
190213
_ => {
191-
if let Some(size) = self.type_sizes.get(name) {
192-
let mut buf = vec![0; *size];
193-
input.read(&mut buf)?;
214+
if let Some(seg) = self.type_segmenters.get(name) {
215+
let mut buf = Vec::<u8>::new();
216+
seg(input, &mut buf)?;
194217
output.write(&buf);
195218
Ok(())
196219
} else {
@@ -268,9 +291,12 @@ impl<T: System> EventsDecoder<T> {
268291
}
269292
}
270293

294+
/// Raw event or error event
271295
#[derive(Debug)]
272296
pub enum Raw {
297+
/// Event
273298
Event(RawEvent),
299+
/// Error
274300
Error(RuntimeError),
275301
}
276302

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+
system::{
20+
System,
21+
SystemEventsDecoder as _,
22+
},
23+
balances::{
24+
Balances,
25+
BalancesEventsDecoder 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: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use std::{
3131
marker::PhantomData,
3232
};
3333

34+
use sp_finality_grandpa::AuthorityList;
35+
3436
pub use pallet_staking::{
3537
ActiveEraInfo,
3638
EraIndex,
@@ -42,6 +44,7 @@ pub use pallet_staking::{
4244
ValidatorPrefs,
4345
};
4446

47+
4548
/// Rewards for the last `HISTORY_DEPTH` eras.
4649
/// If reward hasn't been set or has been removed then 0 reward is returned.
4750
#[derive(Clone, Encode, Decode, Debug, Store)]
@@ -64,7 +67,11 @@ pub struct SetPayeeCall<T: Staking> {
6467

6568
/// The subset of the `frame::Trait` that a client must implement.
6669
#[module]
67-
pub trait Staking: Balances {}
70+
pub trait Staking: Balances {
71+
#![event_alias(ElectionCompute = u8)]
72+
#![event_type(EraIndex)]
73+
#![event_type(AuthorityList)]
74+
}
6875

6976
/// Number of eras to keep in history.
7077
///

0 commit comments

Comments
 (0)