Skip to content
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

Parse signed payload and expose call data type information #66

Merged
merged 13 commits into from
Nov 4, 2021
4 changes: 2 additions & 2 deletions bin/tx-decoder/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ impl Decoder {
}

// Decodes extrinsics and serializes to String
pub fn decode_extrinsics(&self, version: SpecVersion, data: &[u8]) -> Result<String, Error> {
pub fn decode_extrinsics(&self, version: SpecVersion, mut data: &[u8]) -> Result<String, Error> {
if self.is_version_new(version) {
log::debug!("DECODING NEW");
let decoder = self.new.get(&version.try_into()?).ok_or_else(|| anyhow!("version {} not found for new decoder", version))?;
match decoder.decode_extrinsics(data) {
match decoder.decode_extrinsics(&mut data) {
Ok(v) => Ok(format!("{:#?}", v)),
Err(e) => Err(e.1.into())
}
Expand Down
2 changes: 1 addition & 1 deletion bin/v14-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> Result<(), anyhow::Error> {
Err(e) => anyhow::bail!("Cannot decode hex string into bytes: {}", e),
};

let decoded = match decoder.decode_extrinsic(&bytes) {
let decoded = match decoder.decode_extrinsic(&mut &*bytes) {
Ok(decoded) => decoded,
Err(e) => anyhow::bail!("Cannot decode extrinsic: {}", e),
};
Expand Down
12 changes: 8 additions & 4 deletions core_v14/src/decoder/decode_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with substrate-desub. If not, see <http://www.gnu.org/licenses/>.

use crate::{
metadata::{Type, TypeDef, TypeId},
value::{BitSequence, Composite, Primitive, Value, Variant},
};
use crate::value::{BitSequence, Composite, Primitive, Value, Variant};
use codec::{Compact, Decode};
use scale_info::{
form::PortableForm, Field, PortableRegistry, TypeDefArray, TypeDefBitSequence, TypeDefCompact, TypeDefComposite,
TypeDefPrimitive, TypeDefSequence, TypeDefTuple, TypeDefVariant,
};

// Some type aliases used below. `scale-info` is re-exported at the root,
// so to avoid confusion we only publically export all scale-info types from that
// one place.
type TypeDef = scale_info::TypeDef<PortableForm>;
type Type = scale_info::Type<PortableForm>;
type TypeId = <scale_info::form::PortableForm as scale_info::form::Form>::Type;

#[derive(Debug, Clone, thiserror::Error)]
pub enum DecodeTypeError {
#[error("{0}")]
Expand Down
60 changes: 50 additions & 10 deletions core_v14/src/decoder/extrinsic_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,44 @@ impl<'a> AllExtrinsicBytes<'a> {
/// with each one (not including the length prefix), or an error containing the position
/// at which decoding failed.
pub fn iter(&self) -> ExtrinsicBytesIter<'a> {
ExtrinsicBytesIter { data: self.data, cursor: 0 }
ExtrinsicBytesIter { remaining_len: self.len, data: self.data, cursor: 0 }
}
}

/// An iterator that returns the set of bytes representing each extrinsic found.
/// On each iteration, we return either the extrinsic bytes, or an error containing
/// the position at which decoding failed.
pub struct ExtrinsicBytesIter<'a> {
/// The number of extrinsics we expect to be able to decode from the bytes.
/// this is decremented on each iteration.
remaining_len: usize,
data: &'a [u8],
cursor: usize,
}

impl<'a> ExtrinsicBytesIter<'a> {
/// Return the bytes remaining. If an iteration resulted in an error,
/// we'll return the bytes that we failed to decode, too.
pub fn remaining_bytes(&self) -> &'a [u8] {
&self.data[self.cursor..]
}
}

impl<'a> Iterator for ExtrinsicBytesIter<'a> {
type Item = Result<ExtrinsicBytes<'a>, ExtrinsicBytesError>;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.data.len() {
// Stop when we hit the number of item's we're supposed to have,
// or have exhausted the data.
if self.remaining_len == 0 || self.cursor >= self.data.len() {
return None;
}
self.remaining_len -= 1;

let (vec_len, vec_len_bytes) = match decode_compact_u32(&self.data[self.cursor..]) {
Some(res) => res,
None => {
// Ensure that if we try iterating again we get back `None`:
self.cursor = self.data.len();
self.remaining_len = 0;
return Some(Err(ExtrinsicBytesError { index: self.cursor }));
}
};
Expand All @@ -83,31 +97,26 @@ impl<'a> Iterator for ExtrinsicBytesIter<'a> {
// aren't as many bytes as we expect, we bail with an error.
if end > self.data.len() {
// Ensure that if we try iterating again we get back `None`:
self.cursor = self.data.len();
self.remaining_len = 0;
return Some(Err(ExtrinsicBytesError { index: self.data.len() }));
}

let res = &self.data[start..end];
self.cursor += vec_len + vec_len_bytes;

Some(Ok(ExtrinsicBytes { data: res, remaining: self.data.len() - self.cursor }))
Some(Ok(ExtrinsicBytes { data: res }))
}
}

pub struct ExtrinsicBytes<'a> {
data: &'a [u8],
remaining: usize,
}

impl<'a> ExtrinsicBytes<'a> {
/// The bytes representing a single extrinsic
pub fn bytes(&self) -> &'a [u8] {
self.data
}
/// How many bytes remain to be decoded after this extrinsic?
pub fn remaining(&self) -> usize {
self.remaining
}
}

/// An error containing the index into the byte slice at which decoding failed.
Expand Down Expand Up @@ -239,4 +248,35 @@ mod test {
assert_eq!(iter_result_to_bytes(exts.next()), Some(Err(ExtrinsicBytesError { index: 8 })));
assert_eq!(iter_result_to_bytes(exts.next()), None);
}

#[test]
fn wont_iterate_past_advertised_length() {
let mut bytes: Vec<u8> = vec![];

// 2 entries in block (but we have enough bytes for 3):
bytes.extend_from_slice(&Compact(2u32).encode());

// 3 correct entries:
bytes.extend_from_slice(&Compact(4u32).encode());
bytes.extend_from_slice(&[1, 2, 3, 4]);
bytes.extend_from_slice(&Compact(3u32).encode());
bytes.extend_from_slice(&[1, 2, 3]);
bytes.extend_from_slice(&Compact(5u32).encode());
bytes.extend_from_slice(&[1, 2, 3, 4, 5]);

let exts = AllExtrinsicBytes::new(&bytes).unwrap();
assert_eq!(exts.len(), 2);

let mut exts = exts.iter();
assert_eq!(iter_result_to_bytes(exts.next()), Some(Ok(&[1, 2, 3, 4][..])));
assert_eq!(iter_result_to_bytes(exts.next()), Some(Ok(&[1, 2, 3][..])));
assert_eq!(iter_result_to_bytes(exts.next()), None);

// The bytes we should have left (the third entry):
let mut remaining_bytes: Vec<u8> = vec![];
remaining_bytes.extend_from_slice(&Compact(5u32).encode());
remaining_bytes.extend_from_slice(&[1, 2, 3, 4, 5]);

assert_eq!(exts.remaining_bytes(), &remaining_bytes);
}
}
Loading