Generate runtime API from metadata (#294)

* Remove test macro

* Remove client crate

* Create tests crate and move pallet specific tests there

* Extract client, remove metadata and extra, more demolition

* Update substrate dependencies to git dependencies

* Remove Store stuff for now

* Comment out some Call usages

* Add back Runtime trait coped from original System trait

* Make subxt lib compile

* Delete old proc macros and copy over type generation from chameleon

* WIP make transfer balance test pass

* Change to subxt attribute macro

* WIP provide user defined type substitutes

* User defined type substitutes compile

* WIP submitting transactions

* WIP transfer balance test

* Fix macro

* Cargo fmt

* WIP generating storage hashers

* WIP add AccountData trait for fetching the nonce

* Support single type storage map keys

* WIP impl AccountInfo retrieval

* Fix up storage struct generation

* Implement AccountData triait directly on storage entry

* Borrow storage map key and convert account id

* Implement storage fetch client methods

* Remove legacy metadata storage key construction

* Rename CheckEra to CheckMortality

* Substitute perthings types for compact impls

* Fmt

* Downgrade dyn-clone for cargo-contract compat

* Scale-fo 1.0

* scale-info 1.0

* Remove special range handling

* Restore wildcard type params

* Frame metadata 14.0

* WIP decoding events

* WIP more dynamically decoding events

* Fmt

* Decode events, handle errors

* Uncomment some tests

* Remove unused get_mod function

* Fix some warnings

* Fix some more warnings

* Fix some more warnings

* Add tests mod

* Rename node-runtime tests mod to frame

* Fix some warnings

* Fmt

* WIP generate storage client with getters

* Storage client compiling

* Generate storage client api

* Fix up system account query account ids

* WIP generating tx api fns

* Only generate tx api fields when calls available

* Fix tx api call fns

* Fmt

* WIP generate event structs

* call functions not async

* Derive Eq for comparison on generated types

* Generate event structs

* Fix call name

* Fmt

* Update node runtime metadata to substrate c000780db

* Download latest substrate release for integration testing

* Fix event decoding

* Remove unused imports

* Fix plain storage access, total_issuance pass

* Fmt

* Restore contracts tests

* Backoff connecting to substrate node

* Add required TypeInfo impls for local SignedExtension impls

* Remove unnecessary assert formatting

* Fix handling of DispatchError

* Refactor contracts tests

* Troubleshooting contract not found

* Remove more client feature stuff

* Fix dynamic event variant decoding, write consumed index to output

* Fmt

* Use substrate branch with heavy dependency removed

* Remove sp-rcp dependency, define types locally

* Ignore cargo timeing files

* Use my branch for substrate test deps

* Fix storage key type gen

* Comment out fetching contract info

* Add key iteration, extract storage client from main client

* Debugging key generation

* Use substrate master branch

* Fix call test

* Remove TypeSegmenter and dynclone dependency

* Publicly expose Rpc mod

* Unused import warnings

* Add getter for runtime metadata

* Add pallet and event indices for raw events

* Add is_call and is_event convenience trait functions

* Add missing docs

* Refactor tests crate

* Restore remaining client tests

* Fmt

* Fix warnings

* Restore get_mod as test helper and fmt

* Use client references for api calls

* Fix api usages with methods

* Use Bytes for RawEvent debug

* Update metadata

* Restoring some Balances tests

* Populate runtime storage metadata

* Restore balances lock test

* Restore Balances error test

* Fmt

* Restore transfer subscription API

* Staking test

* Restore another staking test

* Restore another staking test

* Restore another staking test

* Partially restore chill_works_for_controller_only staking test

* Fix fetching Optional storage entries

* Restore staking bond test

* Restore remaining staking tests

* Fmt

* Restore sudo tests

* Add some system tests

* Fmt

* Resolve some todos

* Remove pass through rpc methods on Client, expose via rpc() getter

* Remove more rpc pass through methods

* Remove submit tx pass through rpc methods

* Add some comments to SubmittableExtrinsic methods

* Construct the runtime api from the client

* Fmt

* Use From trait instead of new for AccountData query

* Rename subxt_proc_macro crate to subxt_macro

* Fix AccountData From impl

* Extract codegen crate from macro crate

* Fmt

* Replace chameleon hidden field name

* Extract StructDef for generating structs

* More refactoring of StructDef, moving towards sharing with typegen

* Replace explicit tests crate with single implicit integration tests crate

* Rename from substrate-subxt to subxt

* Fix runtime path relative to root Cargo.toml

* Move RpcClient creation to RpcClient

* WIP get examples to compile

* Rename Runtime to Config trait

* WIP implementing default Config

* WIP implementing default extrinsic extras

* fix metadata constants (#299)

* Move DefaultConfig definition and impl to macro

* Extract type substitute parsing to ir mod

* Extract calls, events and storage from api generation

* Add some hardcoded type substitute defaults

* Fmt

* Add utility pallet tests (#300)

* add batch call test example

* add pallet utility tests

* add utility module

* fix warnings

* Add polkadot runtime metadata for example

* Fix system errors and fmt

* Add subxt-cli crate

* Add metadata and codegen subcommands

* Make subxt-cli codegen command work

* Fmt

* Add polkadot codegen test

* Comment about how to run codegen

* Derive AsCompact for structs with single concrete unsigned int field

* Fix bitvec codegen, adds as non optional dependency

* Regenerate polkadot api with bitvec fix

* Edition 2021

* Fix polkadot codegen with bitvec

* Polkadot balance transfer is working

* Fix fetch remote

* Fix transfer_subscribe example

* Fix submit_and_watch example

* Fmt

* Generate storage iter method for iterating over keys

* Fmt

* Fix existential deposit test

* Fix staking tests

* Add option for custom generated type derives

* Add generated type derives for test runtime api

* Fmt

* Copy WrapperTypeOpaque from substrate, add Encode/Decode

* Fmt

* Extract type generator to module, separate & fix tests

* Fully qualified primitive and prelude types

* Fix up remaining type gen tests

* Skip formatting of generated polkadot example code

* Remove empty utility test file.

* Newline

* Update cli/src/main.rs

Co-authored-by: David <dvdplm@gmail.com>

* Rename subxt-cli executable to subxt

* Update src/client.rs

Co-authored-by: David <dvdplm@gmail.com>

* Add some code docs to TypeGenerator.

* Extract TypePath to own file

* Extract type def generation to separate file

* Renamed ModuleType to TypeDefGen

* Fmt

* Factor out type parameter from final_key

* Fix some type paths

* Resolve some todos

* Resolve some panic todos in events

* Add EventsDecodingError

* Decode compact composite types with a single primitive field

* Decode compact composite types with a single primitive field

* Update src/metadata.rs

Co-authored-by: Andrew Plaza <aplaza@liquidthink.net>

* Remove Perbill compact substitute types

* Remove todos regarding maintaining Rust code items, promoted to follow up issue.

* Remove todo regarding overridding default config impl

* Remove todo regarding overridding default Extra

* Remove todo regarding AccountData storage type defintion

* Remove todo regarding borrowing storage key arguments

* Remove type substitution tests todo

* Remove `Box` field name type hack todo

* Remove Compact todo

* Remove sudo todos

* Remove BitVec implementation todo

* Fmt

* Add health warning to README

* Fix up health warning

Co-authored-by: Paulo Martins <paulormart@users.noreply.github.com>
Co-authored-by: David <dvdplm@gmail.com>
Co-authored-by: Andrew Plaza <aplaza@liquidthink.net>
This commit is contained in:
Andrew Jones
2021-11-03 11:28:59 +00:00
committed by GitHub
parent 8f0641e660
commit 793c945fbd
80 changed files with 5929 additions and 6475 deletions
+273 -356
View File
@@ -1,5 +1,5 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of substrate-subxt.
// This file is part of subxt.
//
// subxt is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.
// along with subxt. If not, see <http://www.gnu.org/licenses/>.
use codec::{
Codec,
@@ -20,115 +20,57 @@ use codec::{
Decode,
Encode,
Input,
Output,
};
use dyn_clone::DynClone;
use sp_runtime::{
DispatchError,
DispatchResult,
};
use std::{
collections::{
hash_map::{
Entry,
HashMap,
},
HashSet,
},
fmt,
marker::{
PhantomData,
Send,
},
};
use std::marker::PhantomData;
use crate::{
error::{
Error,
RuntimeError,
},
metadata::{
EventArg,
Metadata,
EventMetadata,
MetadataError,
},
Config,
Error,
Metadata,
Phase,
Runtime,
System,
RuntimeError,
};
use scale_info::{
TypeDef,
TypeDefPrimitive,
};
use sp_core::Bytes;
/// Raw bytes for an Event
#[derive(Debug)]
pub struct RawEvent {
/// The name of the module from whence the Event originated
pub module: String,
/// The name of the Event
/// The name of the pallet from whence the Event originated.
pub pallet: String,
/// The index of the pallet from whence the Event originated.
pub pallet_index: u8,
/// The name of the pallet Event variant.
pub variant: String,
/// The index of the pallet Event variant.
pub variant_index: u8,
/// The raw Event data
pub data: Vec<u8>,
}
impl std::fmt::Debug for RawEvent {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("RawEvent")
.field("module", &self.module)
.field("variant", &self.variant)
.field("data", &hex::encode(&self.data))
.finish()
}
}
pub trait TypeSegmenter: DynClone + Send + Sync {
/// 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 object safe Clone impl for `Box<dyn TypeSegmenter>`
dyn_clone::clone_trait_object!(TypeSegmenter);
struct TypeMarker<T>(PhantomData<T>);
impl<T> TypeSegmenter for TypeMarker<T>
where
T: Codec + Send + Sync,
{
fn segment(&self, input: &mut &[u8], output: &mut Vec<u8>) -> Result<(), Error> {
T::decode(input).map_err(Error::from)?.encode_to(output);
Ok(())
}
}
impl<T> Clone for TypeMarker<T> {
fn clone(&self) -> Self {
Self(Default::default())
}
}
impl<T> Default for TypeMarker<T> {
fn default() -> Self {
Self(Default::default())
}
pub data: Bytes,
}
/// Events decoder.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct EventsDecoder<T> {
metadata: Metadata,
event_type_registry: EventTypeRegistry<T>,
marker: PhantomData<T>,
}
impl<T> Clone for EventsDecoder<T> {
fn clone(&self) -> Self {
Self {
metadata: self.metadata.clone(),
event_type_registry: self.event_type_registry.clone(),
}
}
}
impl<T: Runtime + System> EventsDecoder<T> {
impl<T> EventsDecoder<T>
where
T: Config,
{
/// Creates a new `EventsDecoder`.
pub fn new(metadata: Metadata, event_type_registry: EventTypeRegistry<T>) -> Self {
pub fn new(metadata: Metadata) -> Self {
Self {
metadata,
event_type_registry,
marker: Default::default(),
}
}
@@ -136,28 +78,28 @@ impl<T: Runtime + System> EventsDecoder<T> {
pub fn decode_events(&self, input: &mut &[u8]) -> Result<Vec<(Phase, Raw)>, Error> {
let compact_len = <Compact<u32>>::decode(input)?;
let len = compact_len.0 as usize;
log::debug!("decoding {} events", len);
let mut r = Vec::new();
for _ in 0..len {
// decode EventRecord
let phase = Phase::decode(input)?;
let module_variant = input.read_byte()?;
let module = self.metadata.module_with_events(module_variant)?;
let event_variant = input.read_byte()?;
let event_metadata = module.event(event_variant)?;
let pallet_index = input.read_byte()?;
let variant_index = input.read_byte()?;
log::debug!(
"received event '{}::{}' ({:?})",
module.name(),
event_metadata.name,
event_metadata.arguments()
"phase {:?}, pallet_index {}, event_variant: {}",
phase,
pallet_index,
variant_index
);
log::debug!("remaining input: {}", hex::encode(&input));
let event_metadata = self.metadata.event(pallet_index, variant_index)?;
let mut event_data = Vec::<u8>::new();
let mut event_errors = Vec::<RuntimeError>::new();
let result = self.decode_raw_bytes(
&event_metadata.arguments(),
let result = self.decode_raw_event(
&event_metadata,
input,
&mut event_data,
&mut event_errors,
@@ -167,13 +109,17 @@ impl<T: Runtime + System> EventsDecoder<T> {
log::debug!("raw bytes: {}", hex::encode(&event_data),);
let event = RawEvent {
module: module.name().to_string(),
variant: event_metadata.name.clone(),
data: event_data,
pallet: event_metadata.pallet().to_string(),
pallet_index,
variant: event_metadata.event().to_string(),
variant_index,
data: event_data.into(),
};
// topics come after the event data in EventRecord
let _topics = Vec::<T::Hash>::decode(input)?;
let topics = Vec::<T::Hash>::decode(input)?;
log::debug!("topics: {:?}", topics);
Raw::Event(event)
}
Err(err) => return Err(err),
@@ -190,154 +136,200 @@ impl<T: Runtime + System> EventsDecoder<T> {
Ok(r)
}
fn decode_raw_bytes<W: Output>(
fn decode_raw_event(
&self,
args: &[EventArg],
event_metadata: &EventMetadata,
input: &mut &[u8],
output: &mut W,
output: &mut Vec<u8>,
errors: &mut Vec<RuntimeError>,
) -> Result<(), Error> {
for arg in args {
match arg {
EventArg::Vec(arg) => {
let len = <Compact<u32>>::decode(input)?;
len.encode_to(output);
for _ in 0..len.0 {
self.decode_raw_bytes(&[*arg.clone()], input, output, errors)?
}
}
EventArg::Option(arg) => {
match input.read_byte()? {
0 => output.push_byte(0),
1 => {
output.push_byte(1);
self.decode_raw_bytes(&[*arg.clone()], input, output, errors)?
}
_ => {
return Err(Error::Other(
"unexpected first byte decoding Option".into(),
))
}
}
}
EventArg::Tuple(args) => {
self.decode_raw_bytes(args, input, output, errors)?
}
EventArg::Primitive(name) => {
let result = match name.as_str() {
"DispatchResult" => DispatchResult::decode(input)?,
"DispatchError" => Err(DispatchError::decode(input)?),
_ => {
if let Some(seg) = self.event_type_registry.resolve(name) {
let mut buf = Vec::<u8>::new();
seg.segment(input, &mut buf)?;
output.write(&buf);
Ok(())
} else {
return Err(Error::TypeSizeUnavailable(name.to_owned()))
}
}
};
if let Err(error) = result {
// since the input may contain any number of args we propagate
// runtime errors to the caller for handling
errors.push(RuntimeError::from_dispatch(&self.metadata, error)?);
}
log::debug!(
"Decoding Event '{}::{}'",
event_metadata.pallet(),
event_metadata.event()
);
for arg in event_metadata.variant().fields() {
let type_id = arg.ty().id();
if event_metadata.pallet() == "System"
&& event_metadata.event() == "ExtrinsicFailed"
{
let ty = self
.metadata
.resolve_type(type_id)
.ok_or(MetadataError::TypeNotFound(type_id))?;
if ty.path().ident() == Some("DispatchError".to_string()) {
let dispatch_error = sp_runtime::DispatchError::decode(input)?;
log::info!("Dispatch Error {:?}", dispatch_error);
dispatch_error.encode_to(output);
let runtime_error =
RuntimeError::from_dispatch(&self.metadata, dispatch_error)?;
errors.push(runtime_error);
continue
}
}
self.decode_type(type_id, input, output)?
}
Ok(())
}
}
/// Registry for event types which cannot be directly inferred from the metadata.
#[derive(Default)]
pub struct EventTypeRegistry<T> {
segmenters: HashMap<String, Box<dyn TypeSegmenter>>,
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for EventTypeRegistry<T> {
fn clone(&self) -> Self {
Self {
segmenters: self.segmenters.clone(),
marker: PhantomData,
}
}
}
impl<T> fmt::Debug for EventTypeRegistry<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventTypeRegistry")
.field(
"segmenters",
&self.segmenters.keys().cloned().collect::<String>(),
)
.finish()
}
}
impl<T: Runtime> EventTypeRegistry<T> {
/// Create a new [`EventTypeRegistry`].
pub fn new() -> Self {
let mut registry = Self {
segmenters: HashMap::new(),
marker: PhantomData,
};
T::register_type_sizes(&mut registry);
registry
}
/// Register a type.
///
/// # Panics
///
/// If there is already a type size registered with this name.
pub fn register_type_size<U>(&mut self, name: &str)
where
U: Codec + Send + Sync + 'static,
{
// A segmenter decodes a type from an input stream (&mut &[u8]) and returns te serialized
// type to the output stream (&mut Vec<u8>).
match self.segmenters.entry(name.to_string()) {
Entry::Occupied(_) => panic!("Already a type registered with key {}", name),
Entry::Vacant(entry) => entry.insert(Box::new(TypeMarker::<U>::default())),
};
}
/// Check missing type sizes.
pub fn check_missing_type_sizes(
fn decode_type(
&self,
metadata: &Metadata,
) -> Result<(), HashSet<String>> {
let mut missing = HashSet::new();
for module in metadata.modules_with_events() {
for event in module.events() {
for arg in event.arguments() {
for primitive in arg.primitives() {
if !self.segmenters.contains_key(&primitive) {
missing.insert(format!(
"{}::{}::{}",
module.name(),
event.name,
primitive
));
}
type_id: u32,
input: &mut &[u8],
output: &mut Vec<u8>,
) -> Result<(), Error> {
let ty = self
.metadata
.resolve_type(type_id)
.ok_or(MetadataError::TypeNotFound(type_id))?;
fn decode_raw<T: Codec>(
input: &mut &[u8],
output: &mut Vec<u8>,
) -> Result<(), Error> {
let decoded = T::decode(input)?;
decoded.encode_to(output);
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)?;
variant_index.encode_to(output);
let variant = variant.variants().get(variant_index as usize).ok_or(
Error::Other(format!("Variant {} not found", variant_index)),
)?;
for field in variant.fields() {
self.decode_type(field.ty().id(), input, output)?;
}
Ok(())
}
TypeDef::Sequence(seq) => {
let len = <Compact<u32>>::decode(input)?;
len.encode_to(output);
for _ in 0..len.0 {
self.decode_type(seq.type_param().id(), input, output)?;
}
Ok(())
}
TypeDef::Array(arr) => {
for _ in 0..arr.len() {
self.decode_type(arr.type_param().id(), input, output)?;
}
Ok(())
}
TypeDef::Tuple(tuple) => {
for field in tuple.fields() {
self.decode_type(field.id(), input, output)?;
}
Ok(())
}
TypeDef::Primitive(primitive) => {
match primitive {
TypeDefPrimitive::Bool => decode_raw::<bool>(input, output),
TypeDefPrimitive::Char => {
Err(EventsDecodingError::UnsupportedPrimitive(
TypeDefPrimitive::Char,
)
.into())
}
TypeDefPrimitive::Str => decode_raw::<String>(input, output),
TypeDefPrimitive::U8 => decode_raw::<u8>(input, output),
TypeDefPrimitive::U16 => decode_raw::<u16>(input, output),
TypeDefPrimitive::U32 => decode_raw::<u32>(input, output),
TypeDefPrimitive::U64 => decode_raw::<u64>(input, output),
TypeDefPrimitive::U128 => decode_raw::<u128>(input, output),
TypeDefPrimitive::U256 => {
Err(EventsDecodingError::UnsupportedPrimitive(
TypeDefPrimitive::U256,
)
.into())
}
TypeDefPrimitive::I8 => decode_raw::<i8>(input, output),
TypeDefPrimitive::I16 => decode_raw::<i16>(input, output),
TypeDefPrimitive::I32 => decode_raw::<i32>(input, output),
TypeDefPrimitive::I64 => decode_raw::<i64>(input, output),
TypeDefPrimitive::I128 => decode_raw::<i128>(input, output),
TypeDefPrimitive::I256 => {
Err(EventsDecodingError::UnsupportedPrimitive(
TypeDefPrimitive::I256,
)
.into())
}
}
}
TypeDef::Compact(_compact) => {
let inner = self
.metadata
.resolve_type(type_id)
.ok_or(MetadataError::TypeNotFound(type_id))?;
let mut decode_compact_primitive = |primitive: &TypeDefPrimitive| {
match primitive {
TypeDefPrimitive::U8 => decode_raw::<Compact<u8>>(input, output),
TypeDefPrimitive::U16 => {
decode_raw::<Compact<u16>>(input, output)
}
TypeDefPrimitive::U32 => {
decode_raw::<Compact<u32>>(input, output)
}
TypeDefPrimitive::U64 => {
decode_raw::<Compact<u64>>(input, output)
}
TypeDefPrimitive::U128 => {
decode_raw::<Compact<u128>>(input, output)
}
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(
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(
"Compact type must be a primitive or a composite type".into(),
)
.into())
}
}
}
TypeDef::BitSequence(_bitseq) => {
// decode_raw::<bitvec::BitVec>
unimplemented!("BitVec decoding for events not implemented yet")
}
}
if !missing.is_empty() {
Err(missing)
} else {
Ok(())
}
}
/// Resolve a segmenter for a type by its name.
pub fn resolve(&self, name: &str) -> Option<&Box<dyn TypeSegmenter>> {
self.segmenters.get(name)
}
}
@@ -350,122 +342,47 @@ pub enum Raw {
Error(RuntimeError),
}
#[cfg(test)]
mod tests {
use super::*;
use frame_metadata::{
DecodeDifferent,
ErrorMetadata,
EventMetadata,
ExtrinsicMetadata,
ModuleMetadata,
RuntimeMetadata,
RuntimeMetadataPrefixed,
RuntimeMetadataV13,
META_RESERVED,
};
use std::convert::TryFrom;
type TestRuntime = crate::NodeTemplateRuntime;
#[test]
fn test_decode_option() {
let decoder = EventsDecoder::<TestRuntime>::new(
Metadata::default(),
EventTypeRegistry::new(),
);
let value = Some(0u8);
let input = value.encode();
let mut output = Vec::<u8>::new();
let mut errors = Vec::<RuntimeError>::new();
decoder
.decode_raw_bytes(
&[EventArg::Option(Box::new(EventArg::Primitive(
"u8".to_string(),
)))],
&mut &input[..],
&mut output,
&mut errors,
)
.unwrap();
assert_eq!(output, vec![1, 0]);
}
#[test]
fn test_decode_system_events_and_error() {
let decoder = EventsDecoder::<TestRuntime>::new(
Metadata::try_from(RuntimeMetadataPrefixed(
META_RESERVED,
RuntimeMetadata::V13(RuntimeMetadataV13 {
modules: DecodeDifferent::Decoded(vec![ModuleMetadata {
name: DecodeDifferent::Decoded("System".to_string()),
storage: None,
calls: None,
event: Some(DecodeDifferent::Decoded(vec![
EventMetadata {
name: DecodeDifferent::Decoded(
"ExtrinsicSuccess".to_string(),
),
arguments: DecodeDifferent::Decoded(vec![
"DispatchInfo".to_string()
]),
documentation: DecodeDifferent::Decoded(vec![]),
},
EventMetadata {
name: DecodeDifferent::Decoded(
"ExtrinsicFailed".to_string(),
),
arguments: DecodeDifferent::Decoded(vec![
"DispatchError".to_string(),
"DispatchInfo".to_string(),
]),
documentation: DecodeDifferent::Decoded(vec![]),
},
])),
constants: DecodeDifferent::Decoded(vec![]),
errors: DecodeDifferent::Decoded(vec![
ErrorMetadata {
name: DecodeDifferent::Decoded(
"InvalidSpecName".to_string(),
),
documentation: DecodeDifferent::Decoded(vec![]),
},
ErrorMetadata {
name: DecodeDifferent::Decoded(
"SpecVersionNeedsToIncrease".to_string(),
),
documentation: DecodeDifferent::Decoded(vec![]),
},
ErrorMetadata {
name: DecodeDifferent::Decoded(
"FailedToExtractRuntimeVersion".to_string(),
),
documentation: DecodeDifferent::Decoded(vec![]),
},
ErrorMetadata {
name: DecodeDifferent::Decoded(
"NonDefaultComposite".to_string(),
),
documentation: DecodeDifferent::Decoded(vec![]),
},
]),
index: 0,
}]),
extrinsic: ExtrinsicMetadata {
version: 0,
signed_extensions: vec![],
},
}),
))
.unwrap(),
EventTypeRegistry::new(),
);
// [(ApplyExtrinsic(0), Event(RawEvent { module: "System", variant: "ExtrinsicSuccess", data: "482d7c09000000000200" })), (ApplyExtrinsic(1), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" }))), (ApplyExtrinsic(2), Error(Module(ModuleError { module: "System", error: "NonDefaultComposite" })))]
let input = hex::decode("0c00000000000000482d7c0900000000020000000100000000010300035884723300000000000000000200000000010300035884723300000000000000").unwrap();
decoder.decode_events(&mut &input[..]).unwrap();
}
#[derive(Debug, thiserror::Error)]
pub enum EventsDecodingError {
/// Unsupported primitive type
#[error("Unsupported primitive type {0:?}")]
UnsupportedPrimitive(TypeDefPrimitive),
/// Invalid compact type, must be an unsigned int.
#[error("Invalid compact primitive {0:?}")]
InvalidCompactPrimitive(TypeDefPrimitive),
#[error("Invalid compact composite type {0}")]
InvalidCompactType(String),
}
// #[cfg(test)]
// mod tests {
// use super::*;
// use std::convert::TryFrom;
//
// type DefaultConfig = crate::NodeTemplateRuntime;
//
// #[test]
// fn test_decode_option() {
// let decoder = EventsDecoder::<DefaultConfig>::new(
// Metadata::default(),
// );
//
// let value = Some(0u8);
// let input = value.encode();
// let mut output = Vec::<u8>::new();
// let mut errors = Vec::<RuntimeError>::new();
//
// decoder
// .decode_raw_bytes(
// &[EventArg::Option(Box::new(EventArg::Primitive(
// "u8".to_string(),
// )))],
// &mut &input[..],
// &mut output,
// &mut errors,
// )
// .unwrap();
//
// assert_eq!(output, vec![1, 0]);
// }
// }