Skip to content

Commit e4e5426

Browse files
authored
fix: correct slice size for BitVec parsing (#34)
* fix: correct slice size for BitVec parsing * chore: restrict T in helper to BitStore
1 parent 8b83daa commit e4e5426

File tree

2 files changed

+131
-49
lines changed

2 files changed

+131
-49
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description = "parser for Substrate chain data"
33
license = "GPL-3.0-or-later"
44
name = "substrate_parser"
5-
version = "0.3.0"
5+
version = "0.3.1"
66
authors = ["Alexander Slesarev <[email protected]>", "Vera Abramova <[email protected]>"]
77
edition = "2021"
88
repository = "https://github.com/Alzymologist/substrate-parser"

src/decoding_sci.rs

Lines changed: 130 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! Decode data using [`RuntimeMetadataV14`].
2-
use bitvec::prelude::{BitVec, Lsb0, Msb0};
2+
use bitvec::prelude::{BitStore, BitVec, Lsb0, Msb0};
33
use frame_metadata::v14::RuntimeMetadataV14;
44
use num_bigint::{BigInt, BigUint};
5-
use parity_scale_codec::{Decode, OptionBool};
5+
use parity_scale_codec::{Decode, DecodeAll, OptionBool};
66
use scale_info::{
77
form::PortableForm, interner::UntrackedSymbol, Field, PortableRegistry, Type, TypeDef,
88
TypeDefBitSequence, TypeDefPrimitive, Variant,
99
};
1010
use sp_arithmetic::{PerU16, Perbill, Percent, Permill, Perquintill};
1111
use sp_core::{crypto::AccountId32, H160, H512};
12+
use std::mem::size_of;
1213

1314
use crate::cards::{
1415
Call, Documented, Event, ExtendedData, FieldData, Info, PalletSpecificData, ParsedData,
@@ -690,29 +691,7 @@ fn decode_type_def_bit_sequence(
690691
position: &mut usize,
691692
registry: &PortableRegistry,
692693
) -> Result<ParsedData, ParserError> {
693-
let found_compact = find_compact::<u32>(data, *position)?;
694-
let bit_length_found = found_compact.compact;
695-
let byte_length = match bit_length_found % 8 {
696-
0 => bit_length_found / 8,
697-
_ => (bit_length_found / 8) + 1,
698-
} as usize;
699-
700694
let bitvec_start = *position;
701-
let bitvec_end = found_compact.start_next_unit + byte_length;
702-
703-
let into_decode = match data.get(bitvec_start..bitvec_end) {
704-
Some(a) => {
705-
let into_decode = a.to_vec();
706-
*position = bitvec_end;
707-
into_decode
708-
}
709-
None => {
710-
return Err(ParserError::DataTooShort {
711-
position: bitvec_start,
712-
minimal_length: bitvec_end - bitvec_start,
713-
})
714-
}
715-
};
716695

717696
// BitOrder
718697
let bitorder_type = resolve_ty(registry, bit_ty.bit_order_type().id())?;
@@ -732,44 +711,147 @@ fn decode_type_def_bit_sequence(
732711
let bitstore_type = resolve_ty(registry, bit_ty.bit_store_type().id())?;
733712

734713
match bitstore_type.type_def() {
735-
TypeDef::Primitive(TypeDefPrimitive::U8) => match bitorder {
736-
FoundBitOrder::Lsb0 => {
737-
<BitVec<u8, Lsb0>>::decode(&mut &into_decode[..]).map(ParsedData::BitVecU8Lsb0)
738-
}
739-
FoundBitOrder::Msb0 => {
740-
<BitVec<u8, Msb0>>::decode(&mut &into_decode[..]).map(ParsedData::BitVecU8Msb0)
714+
TypeDef::Primitive(TypeDefPrimitive::U8) => {
715+
let into_decode = into_bitvec_decode::<u8>(data, position)?;
716+
match bitorder {
717+
FoundBitOrder::Lsb0 => <BitVec<u8, Lsb0>>::decode_all(&mut &into_decode[..])
718+
.map(ParsedData::BitVecU8Lsb0)
719+
.map_err(|_| ParserError::TypeFailure {
720+
position: bitvec_start,
721+
ty: "BitVec<u8, Lsb0>",
722+
}),
723+
FoundBitOrder::Msb0 => <BitVec<u8, Msb0>>::decode_all(&mut &into_decode[..])
724+
.map(ParsedData::BitVecU8Msb0)
725+
.map_err(|_| ParserError::TypeFailure {
726+
position: bitvec_start,
727+
ty: "BitVec<u8, Msb0>",
728+
}),
741729
}
742-
},
730+
}
743731
TypeDef::Primitive(TypeDefPrimitive::U16) => {
732+
let into_decode = into_bitvec_decode::<u16>(data, position)?;
744733
match bitorder {
745-
FoundBitOrder::Lsb0 => <BitVec<u16, Lsb0>>::decode(&mut &into_decode[..])
746-
.map(ParsedData::BitVecU16Lsb0),
747-
FoundBitOrder::Msb0 => <BitVec<u16, Msb0>>::decode(&mut &into_decode[..])
748-
.map(ParsedData::BitVecU16Msb0),
734+
FoundBitOrder::Lsb0 => <BitVec<u16, Lsb0>>::decode_all(&mut &into_decode[..])
735+
.map(ParsedData::BitVecU16Lsb0)
736+
.map_err(|_| ParserError::TypeFailure {
737+
position: bitvec_start,
738+
ty: "BitVec<u16, Lsb0>",
739+
}),
740+
FoundBitOrder::Msb0 => <BitVec<u16, Msb0>>::decode_all(&mut &into_decode[..])
741+
.map(ParsedData::BitVecU16Msb0)
742+
.map_err(|_| ParserError::TypeFailure {
743+
position: bitvec_start,
744+
ty: "BitVec<u16, Msb0>",
745+
}),
749746
}
750747
}
751748
TypeDef::Primitive(TypeDefPrimitive::U32) => {
749+
let into_decode = into_bitvec_decode::<u32>(data, position)?;
752750
match bitorder {
753-
FoundBitOrder::Lsb0 => <BitVec<u32, Lsb0>>::decode(&mut &into_decode[..])
754-
.map(ParsedData::BitVecU32Lsb0),
755-
FoundBitOrder::Msb0 => <BitVec<u32, Msb0>>::decode(&mut &into_decode[..])
756-
.map(ParsedData::BitVecU32Msb0),
751+
FoundBitOrder::Lsb0 => <BitVec<u32, Lsb0>>::decode_all(&mut &into_decode[..])
752+
.map(ParsedData::BitVecU32Lsb0)
753+
.map_err(|_| ParserError::TypeFailure {
754+
position: bitvec_start,
755+
ty: "BitVec<u32, Lsb0>",
756+
}),
757+
FoundBitOrder::Msb0 => <BitVec<u32, Msb0>>::decode_all(&mut &into_decode[..])
758+
.map(ParsedData::BitVecU32Msb0)
759+
.map_err(|_| ParserError::TypeFailure {
760+
position: bitvec_start,
761+
ty: "BitVec<u32, Msb0>",
762+
}),
757763
}
758764
}
759765
TypeDef::Primitive(TypeDefPrimitive::U64) => {
766+
let into_decode = into_bitvec_decode::<u64>(data, position)?;
760767
match bitorder {
761-
FoundBitOrder::Lsb0 => <BitVec<u64, Lsb0>>::decode(&mut &into_decode[..])
762-
.map(ParsedData::BitVecU64Lsb0),
763-
FoundBitOrder::Msb0 => <BitVec<u64, Msb0>>::decode(&mut &into_decode[..])
764-
.map(ParsedData::BitVecU64Msb0),
768+
FoundBitOrder::Lsb0 => <BitVec<u64, Lsb0>>::decode_all(&mut &into_decode[..])
769+
.map(ParsedData::BitVecU64Lsb0)
770+
.map_err(|_| ParserError::TypeFailure {
771+
position: bitvec_start,
772+
ty: "BitVec<u64, Lsb0>",
773+
}),
774+
FoundBitOrder::Msb0 => <BitVec<u64, Msb0>>::decode_all(&mut &into_decode[..])
775+
.map(ParsedData::BitVecU64Msb0)
776+
.map_err(|_| ParserError::TypeFailure {
777+
position: bitvec_start,
778+
ty: "BitVec<u64, Msb0>",
779+
}),
765780
}
766781
}
767-
_ => return Err(ParserError::NotBitStoreType { id }),
782+
_ => Err(ParserError::NotBitStoreType { id }),
783+
}
784+
}
785+
786+
/// Positions and related values for decoding `BitVec`.
787+
struct BitVecPositions {
788+
/// Encoded `BitVec` start position, includes bit length compact.
789+
bitvec_start: usize,
790+
791+
/// Encoded `BitVec` end position.
792+
bitvec_end: usize,
793+
794+
/// Minimal encoded data length.
795+
minimal_length: usize,
796+
}
797+
798+
impl BitVecPositions {
799+
/// New `BitVecPositions` for given input data and position.
800+
///
801+
/// `T` is corresponding `BitStore`.
802+
fn new<T: BitStore>(data: &[u8], position: usize) -> Result<Self, ParserError> {
803+
let found_compact = find_compact::<u32>(data, position)?;
804+
805+
let bitvec_start = position;
806+
let data_start = found_compact.start_next_unit;
807+
808+
let bit_length = found_compact.compact as usize;
809+
810+
const BITS_IN_BYTE: usize = 8;
811+
let byte_length = match bit_length % BITS_IN_BYTE {
812+
0 => bit_length / BITS_IN_BYTE,
813+
_ => (bit_length / BITS_IN_BYTE) + 1usize,
814+
};
815+
816+
let bytes_per_element = size_of::<T>();
817+
let number_of_elements = match byte_length % bytes_per_element {
818+
0 => byte_length / bytes_per_element,
819+
_ => (byte_length / bytes_per_element) + 1usize,
820+
};
821+
822+
let slice_length = number_of_elements * bytes_per_element;
823+
824+
let bitvec_end = data_start + slice_length;
825+
826+
let minimal_length = bitvec_end - bitvec_start;
827+
828+
Ok(Self {
829+
bitvec_start,
830+
bitvec_end,
831+
minimal_length,
832+
})
833+
}
834+
}
835+
836+
/// Select the slice to decode as a `BitVec`.
837+
///
838+
/// Current parser position gets changed.
839+
fn into_bitvec_decode<'a, T: BitStore>(
840+
data: &'a [u8],
841+
position: &'a mut usize,
842+
) -> Result<&'a [u8], ParserError> {
843+
let bitvec_positions = BitVecPositions::new::<T>(data, *position)?;
844+
845+
match data.get(bitvec_positions.bitvec_start..bitvec_positions.bitvec_end) {
846+
Some(into_bitvec_decode) => {
847+
*position = bitvec_positions.bitvec_end;
848+
Ok(into_bitvec_decode)
849+
}
850+
None => Err(ParserError::DataTooShort {
851+
position: bitvec_positions.bitvec_start,
852+
minimal_length: bitvec_positions.minimal_length,
853+
}),
768854
}
769-
.map_err(|_| ParserError::TypeFailure {
770-
position: bitvec_start,
771-
ty: "BitVec",
772-
})
773855
}
774856

775857
/// Type of set element, resolved as completely as possible.

0 commit comments

Comments
 (0)