-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V14 Decoding #45
V14 Decoding #45
Changes from 1 commit
a3e7d11
e300f9a
9ed8410
d18eead
f113916
dfec7d1
5cfbc7d
6e6b90d
7133c32
1ace2ec
154947c
6241c72
0f98fd4
46400f2
a4cc70f
e38451e
07b7959
aa097b5
a9f1f20
2c8dd13
bca25c2
caea294
1f41c16
51a3aa4
4b80064
0f6a566
d1c8968
1d1daeb
a2cb527
14d882c
76ab0a0
e96deab
2098c40
5a0abd0
8daeb91
f989aa1
02f7318
2b4e55d
d487d27
6a72b06
72d49e3
9bd6564
b2b87cf
cd4deb0
5831844
3f10df4
5f2f917
79b282d
deafb08
fe608de
859145c
4111d6c
827a56d
4da194c
b0374da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use crate::{ | ||
substrate_type::SubstrateType, | ||
substrate_value::SubstrateValue, | ||
}; | ||
|
||
#[derive(Debug, Clone, thiserror::Error)] | ||
pub enum DecodeTypeError { | ||
|
||
} | ||
|
||
pub fn decode_type<'a>(data: &'a [u8], ty: &SubstrateType) -> Result<(SubstrateValue, &'a [u8]), (DecodeTypeError, &'a [u8])> { | ||
todo!() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
use crate::metadata::Metadata; | ||
use crate::metadata::{Metadata, MetadataError}; | ||
use crate::substrate_type::{CompositeType, SubstrateType}; | ||
use crate::substrate_value::SubstrateValue; | ||
use super::extrinsic_bytes::{ ExtrinsicBytes, ExtrinsicBytesError }; | ||
use super::decode_type::{ decode_type, DecodeTypeError }; | ||
|
||
pub struct Decoder { | ||
metadata: Metadata | ||
|
@@ -9,7 +11,17 @@ pub struct Decoder { | |
#[derive(Clone,Debug,thiserror::Error)] | ||
pub enum DecodeError { | ||
#[error("Failed to parse the provided vector of extrinsics: {0}")] | ||
UnexpectedExtrinsicsShape(#[from] ExtrinsicBytesError) | ||
UnexpectedExtrinsicsShape(#[from] ExtrinsicBytesError), | ||
#[error("Failed to decode type: {0}")] | ||
DecodeTypeError(#[from] DecodeTypeError), | ||
#[error("Failed to decode: expected more data")] | ||
EarlyEof(&'static str), | ||
#[error("Failed to decode unsupported extrinsic version '{0}'")] | ||
CannotDecodeExtrinsicVersion(u8), | ||
#[error("Cannot find call corresponding to extrinsic with pallet index {0} and call index {1}")] | ||
CannotFindCall(u8, u8), | ||
#[error("Failed to decode extrinsic: {0}")] | ||
CannotFindType(#[from] MetadataError), | ||
} | ||
|
||
impl Decoder { | ||
|
@@ -21,7 +33,7 @@ impl Decoder { | |
} | ||
|
||
/// Decode a SCALE encoded vector of extrinsics against the metadata provided | ||
pub fn decode_extrinsics(&self, data: &[u8]) -> Result<Vec<SubstrateValue>, DecodeError> { | ||
pub fn decode_extrinsics(&self, data: &[u8]) -> Result<Vec<GenericExtrinsic>, DecodeError> { | ||
let extrinsic_bytes = ExtrinsicBytes::new(data)?; | ||
log::trace!("Decoding {} Total Extrinsics.", extrinsic_bytes.len()); | ||
|
||
|
@@ -35,7 +47,96 @@ impl Decoder { | |
} | ||
|
||
/// Decode a SCALE encoded extrinsic against the metadata provided | ||
pub fn decode_extrinsic(&self, data: &[u8]) -> Result<SubstrateValue, DecodeError> { | ||
todo!() | ||
pub fn decode_extrinsic(&self, mut data: &[u8]) -> Result<GenericExtrinsic, DecodeError> { | ||
if data.len() == 0 { | ||
return Err(DecodeError::EarlyEof("extrinsic length should be > 0")); | ||
} | ||
|
||
let info = interpret_extrinsic_version(data[0]); | ||
|
||
// We only know how to decode V4 extrinsics at the moment | ||
if info.version != 4 { | ||
return Err(DecodeError::CannotDecodeExtrinsicVersion(info.version)); | ||
} | ||
|
||
// If the extrinsic is signed, decode the signature first. Remember that V4 | ||
// extrinsics are laid out roughly as follows: | ||
// | ||
// first byte: abbbbbbb (a = 0 for unsigned, 1 for signed, b = version) | ||
// signature, which is made up of (in order): | ||
// - sp_runtime::MultiAddress enum (sender) | ||
// - sp_runtime::MultiSignature enum | ||
// - sp_runtime::generic::Era enum | ||
// - compact encoded u32 (nonce; prior transaction count) | ||
// - compact encoded u128 (tip paid to block producer/treasury) | ||
// call, which is made up roughly of: | ||
// - enum pallet index (for pallets variant) | ||
// - call index (for inner variant) | ||
// - call args (types can be pulled from metadata for each arg we expect) | ||
let mut signature = None; | ||
if info.is_signed { | ||
|
||
} | ||
|
||
if data.len() < 2 { | ||
return Err(DecodeError::EarlyEof("expected at least 2 more bytes for the pallet/call index")); | ||
} | ||
|
||
// Work out which call the extrinsic data represents and get type info for it: | ||
let pallet_index = data[0]; | ||
let call_index = data[1]; | ||
data = &data[2..]; | ||
let (pallet_name, call) = match self.metadata.call_by_variant_index(pallet_index, call_index) { | ||
Some(call) => call, | ||
None => return Err(DecodeError::CannotFindCall(pallet_index, call_index)) | ||
}; | ||
|
||
// Decode each of the argument values in the extrinsic: | ||
let mut arguments = vec![]; | ||
for arg in call.args() { | ||
let ty = self.metadata.resolve_type(arg)?; | ||
let val = match decode_type(data, &ty) { | ||
Ok((val, rest)) => { | ||
data = rest; | ||
val | ||
}, | ||
Err((err, _rest)) => { | ||
return Err(err.into()) | ||
} | ||
}; | ||
arguments.push(val); | ||
} | ||
|
||
// Return a composite type representing the extrinsic arguments: | ||
Ok(GenericExtrinsic { | ||
pallet: pallet_name.to_owned(), | ||
call: call.name().to_owned(), | ||
signature, | ||
arguments, | ||
}) | ||
} | ||
} | ||
|
||
pub struct GenericExtrinsic { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to derive There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hrm,
What do you reckon? |
||
/// The name of the pallet that the extrinsic called into | ||
pub pallet: String, | ||
/// The name of the call made | ||
pub call: String, | ||
/// The signature (if any) associated with the extrinsic | ||
pub signature: Option<SubstrateValue>, | ||
/// The arguments to pass to the call | ||
pub arguments: Vec<SubstrateValue> | ||
} | ||
|
||
struct ExtrinsicVersionInfo { | ||
/// Which version is this extrinsic? | ||
version: u8, | ||
/// Does this extrinsic have a signature? | ||
is_signed: bool | ||
} | ||
|
||
fn interpret_extrinsic_version(byte: u8) -> ExtrinsicVersionInfo { | ||
let is_signed = byte & 0b1000_0000 != 0; | ||
let version = byte & 0b0111_1111; | ||
ExtrinsicVersionInfo { version, is_signed } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
mod decoder; | ||
mod decode_type; | ||
mod extrinsic_bytes; | ||
|
||
pub use decoder::Decoder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe s/Cannot/Unknown/?