|
| 1 | +// Copyright 2019 Parity Technologies (UK) Ltd. |
| 2 | +// This file is part of substrate-subxt. |
| 3 | +// |
| 4 | +// subxt is free software: you can redistribute it and/or modify |
| 5 | +// it under the terms of the GNU General Public License as published by |
| 6 | +// the Free Software Foundation, either version 3 of the License, or |
| 7 | +// (at your option) any later version. |
| 8 | +// |
| 9 | +// subxt is distributed in the hope that it will be useful, |
| 10 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | +// GNU General Public License for more details. |
| 13 | +// |
| 14 | +// You should have received a copy of the GNU General Public License |
| 15 | +// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +use std::{ |
| 18 | + collections::{ |
| 19 | + HashMap, |
| 20 | + HashSet, |
| 21 | + }, |
| 22 | + convert::TryFrom, |
| 23 | + marker::{ |
| 24 | +// PhantomData, |
| 25 | + Send, |
| 26 | + }, |
| 27 | +}; |
| 28 | + |
| 29 | +use codec::{ |
| 30 | + Codec, |
| 31 | + Compact, |
| 32 | + Decode, |
| 33 | + Encode, |
| 34 | + Error as CodecError, |
| 35 | + Input, |
| 36 | + Output, |
| 37 | +}; |
| 38 | +use sp_runtime::DispatchError; |
| 39 | +use support::weights::DispatchInfo; |
| 40 | +use system::Phase; |
| 41 | + |
| 42 | +use crate::{ |
| 43 | + node_metadata::{ |
| 44 | + EventArg, |
| 45 | + Metadata, |
| 46 | + MetadataError, |
| 47 | + }, |
| 48 | +}; |
| 49 | + |
| 50 | +/// Event for the System module. |
| 51 | +#[derive(Clone, Debug, Decode)] |
| 52 | +pub enum SystemEvent { |
| 53 | + /// An extrinsic completed successfully. |
| 54 | + ExtrinsicSuccess(DispatchInfo), |
| 55 | + /// An extrinsic failed. |
| 56 | + ExtrinsicFailed(DispatchError, DispatchInfo), |
| 57 | +} |
| 58 | + |
| 59 | +/// Top level Event that can be produced by a substrate runtime |
| 60 | +#[derive(Debug)] |
| 61 | +pub enum RuntimeEvent { |
| 62 | + System(SystemEvent), |
| 63 | + Raw(RawEvent), |
| 64 | +} |
| 65 | + |
| 66 | +/// Raw bytes for an Event |
| 67 | +#[derive(Debug)] |
| 68 | +pub struct RawEvent { |
| 69 | + /// The name of the module from whence the Event originated |
| 70 | + pub module: String, |
| 71 | + /// The name of the Event |
| 72 | + pub variant: String, |
| 73 | + /// The raw Event data |
| 74 | + pub data: Vec<u8>, |
| 75 | +} |
| 76 | + |
| 77 | +#[derive(Debug, thiserror::Error)] |
| 78 | +pub enum EventsError { |
| 79 | + #[error("Scale codec error: {0:?}")] |
| 80 | + CodecError(#[from] CodecError), |
| 81 | + #[error("Metadata error: {0:?}")] |
| 82 | + Metadata(#[from] MetadataError), |
| 83 | + #[error("Type Sizes Unavailable: {0:?}")] |
| 84 | + TypeSizeUnavailable(String), |
| 85 | +} |
| 86 | + |
| 87 | +pub struct EventsDecoder { |
| 88 | + metadata: Metadata, |
| 89 | + type_sizes: HashMap<String, usize>, |
| 90 | +// marker: PhantomData<fn() -> T>, |
| 91 | +} |
| 92 | + |
| 93 | +impl TryFrom<Metadata> for EventsDecoder { |
| 94 | + type Error = EventsError; |
| 95 | + |
| 96 | + fn try_from(metadata: Metadata) -> Result<Self, Self::Error> { |
| 97 | + let mut decoder = Self { |
| 98 | + metadata, |
| 99 | + type_sizes: HashMap::new(), |
| 100 | +// marker: PhantomData, |
| 101 | + }; |
| 102 | + // register default event arg type sizes for dynamic decoding of events |
| 103 | + decoder.register_type_size::<bool>("bool")?; |
| 104 | + decoder.register_type_size::<u32>("ReferendumIndex")?; |
| 105 | + decoder.register_type_size::<[u8; 16]>("Kind")?; |
| 106 | + decoder.register_type_size::<[u8; 32]>("AuthorityId")?; |
| 107 | + decoder.register_type_size::<u8>("u8")?; |
| 108 | + decoder.register_type_size::<u32>("u32")?; |
| 109 | + decoder.register_type_size::<u64>("u64")?; |
| 110 | + decoder.register_type_size::<u32>("AccountIndex")?; |
| 111 | + decoder.register_type_size::<u32>("SessionIndex")?; |
| 112 | + decoder.register_type_size::<u32>("PropIndex")?; |
| 113 | + decoder.register_type_size::<u32>("ProposalIndex")?; |
| 114 | + decoder.register_type_size::<u32>("AuthorityIndex")?; |
| 115 | + decoder.register_type_size::<u64>("AuthorityWeight")?; |
| 116 | + decoder.register_type_size::<u32>("MemberCount")?; |
| 117 | + decoder.register_type_size::<node_primitives::AccountId>("AccountId")?; |
| 118 | + decoder.register_type_size::<node_primitives::BlockNumber>("BlockNumber")?; |
| 119 | + decoder.register_type_size::<node_primitives::Hash>("Hash")?; |
| 120 | + decoder.register_type_size::<node_primitives::Balance>("Balance")?; |
| 121 | + // VoteThreshold enum index |
| 122 | + decoder.register_type_size::<u8>("VoteThreshold")?; |
| 123 | + |
| 124 | + Ok(decoder) |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +impl EventsDecoder { |
| 129 | + pub fn register_type_size<U>(&mut self, name: &str) -> Result<usize, EventsError> |
| 130 | + where |
| 131 | + U: Default + Codec + Send + 'static, |
| 132 | + { |
| 133 | + let size = U::default().encode().len(); |
| 134 | + if size > 0 { |
| 135 | + self.type_sizes.insert(name.to_string(), size); |
| 136 | + Ok(size) |
| 137 | + } else { |
| 138 | + Err(EventsError::TypeSizeUnavailable(name.to_owned())) |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + pub fn check_missing_type_sizes(&self) { |
| 143 | + let mut missing = HashSet::new(); |
| 144 | + for module in self.metadata.modules_with_events() { |
| 145 | + for event in module.events() { |
| 146 | + for arg in event.arguments() { |
| 147 | + for primitive in arg.primitives() { |
| 148 | + if module.name() != "System" |
| 149 | + && !self.type_sizes.contains_key(&primitive) |
| 150 | + && !primitive.contains("PhantomData") |
| 151 | + { |
| 152 | + missing.insert(format!( |
| 153 | + "{}::{}::{}", |
| 154 | + module.name(), |
| 155 | + event.name, |
| 156 | + primitive |
| 157 | + )); |
| 158 | + } |
| 159 | + } |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | + if missing.len() > 0 { |
| 164 | + log::warn!( |
| 165 | + "The following primitive types do not have registered sizes: {:?} \ |
| 166 | + If any of these events are received, an error will occur since we cannot decode them", |
| 167 | + missing |
| 168 | + ); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + fn decode_raw_bytes<I: Input, W: Output>( |
| 173 | + &self, |
| 174 | + args: &[EventArg], |
| 175 | + input: &mut I, |
| 176 | + output: &mut W, |
| 177 | + ) -> Result<(), EventsError> { |
| 178 | + for arg in args { |
| 179 | + match arg { |
| 180 | + EventArg::Vec(arg) => { |
| 181 | + let len = <Compact<u32>>::decode(input)?; |
| 182 | + len.encode_to(output); |
| 183 | + for _ in 0..len.0 { |
| 184 | + self.decode_raw_bytes(&[*arg.clone()], input, output)? |
| 185 | + } |
| 186 | + } |
| 187 | + EventArg::Tuple(args) => self.decode_raw_bytes(args, input, output)?, |
| 188 | + EventArg::Primitive(name) => { |
| 189 | + if name.contains("PhantomData") { |
| 190 | + // PhantomData is size 0 |
| 191 | + return Ok(()) |
| 192 | + } |
| 193 | + if let Some(size) = self.type_sizes.get(name) { |
| 194 | + let mut buf = vec![0; *size]; |
| 195 | + input.read(&mut buf)?; |
| 196 | + output.write(&buf); |
| 197 | + } else { |
| 198 | + return Err(EventsError::TypeSizeUnavailable(name.to_owned())) |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + Ok(()) |
| 204 | + } |
| 205 | + |
| 206 | + pub fn decode_events( |
| 207 | + &self, |
| 208 | + input: &mut &[u8], |
| 209 | + ) -> Result<Vec<(Phase, RuntimeEvent)>, EventsError> { |
| 210 | + log::debug!("Decoding compact len: {:?}", input); |
| 211 | + let compact_len = <Compact<u32>>::decode(input)?; |
| 212 | + let len = compact_len.0 as usize; |
| 213 | + |
| 214 | + let mut r = Vec::new(); |
| 215 | + for _ in 0..len { |
| 216 | + // decode EventRecord |
| 217 | + log::debug!("Decoding phase: {:?}", input); |
| 218 | + let phase = Phase::decode(input)?; |
| 219 | + let module_variant = input.read_byte()?; |
| 220 | + |
| 221 | + let module = self.metadata.module_with_events(module_variant)?; |
| 222 | + let event = if module.name() == "System" { |
| 223 | + log::debug!("Decoding system event, intput: {:?}", input); |
| 224 | + let system_event = SystemEvent::decode(input)?; |
| 225 | + log::debug!("Decoding successful, system_event: {:?}", system_event); |
| 226 | + RuntimeEvent::System(system_event) |
| 227 | + } else { |
| 228 | + let event_variant = input.read_byte()?; |
| 229 | + let event_metadata = module.event(event_variant)?; |
| 230 | + log::debug!("decoding event '{}::{}'", module.name(), event_metadata.name); |
| 231 | + |
| 232 | + let mut event_data = Vec::<u8>::new(); |
| 233 | + self.decode_raw_bytes( |
| 234 | + &event_metadata.arguments(), |
| 235 | + input, |
| 236 | + &mut event_data, |
| 237 | + )?; |
| 238 | + |
| 239 | + log::debug!( |
| 240 | + "received event '{}::{}', raw bytes: {}", |
| 241 | + module.name(), |
| 242 | + event_metadata.name, |
| 243 | + hex::encode(&event_data), |
| 244 | + ); |
| 245 | + |
| 246 | + RuntimeEvent::Raw(RawEvent { |
| 247 | + module: module.name().to_string(), |
| 248 | + variant: event_metadata.name.clone(), |
| 249 | + data: event_data, |
| 250 | + }) |
| 251 | + }; |
| 252 | + |
| 253 | +// topics come after the event data in EventRecord |
| 254 | + log::debug!("Phase {:?}, Event: {:?}", phase, event); |
| 255 | + |
| 256 | + log::debug!("Decoding topics {:?}", input); |
| 257 | + let _topics = Vec::<node_primitives::Hash>::decode(input)?; |
| 258 | + r.push((phase, event)); |
| 259 | + } |
| 260 | + Ok(r) |
| 261 | + } |
| 262 | +} |
0 commit comments