Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
889 changes: 498 additions & 391 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2018"

[dependencies]
log = "0.4"
thiserror = "1.0"
thiserror = "1.0.22"
codec = { version = "1", package = "parity-scale-codec" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
Expand All @@ -15,15 +15,15 @@ derive_more = "0.99.3"
dyn-clone = "1.0"
hex = "0.4"

runtime-version = { package = "sp-version", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
pallet-indices = { package = "pallet-indices", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
pallet-democracy = { package = "pallet-democracy", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
pallet-identity = { package = "pallet-identity", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
runtime-version = { package = "sp-version", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }
pallet-indices = { package = "pallet-indices", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }
pallet-democracy = { package = "pallet-democracy", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }
pallet-identity = { package = "pallet-identity", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }

primitives = { package = "sp-core", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
runtime-primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
primitives = { package = "sp-core", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }
runtime-primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }

runtime-metadata-latest = { package = "frame-metadata", git = "https://github.com/paritytech/substrate", rev = "7314a78d49d0dc3862c6ef7c8115cb1b3d0c0fd2" }
runtime-metadata-latest = { package = "frame-metadata", git = "https://github.com/paritytech/substrate", rev = "a364e27d6e3971d756d28435efc468d95add52d3" }
runtime-metadata11 = { git = "https://github.com/insipx/substrate-metadata-versions", package = "frame-metadatav11", branch = "master" }
runtime-metadata10 = { git = "https://github.com/insipx/substrate-metadata-versions", package = "frame-metadatav10", branch = "master" }
runtime-metadata09 = { git = "https://github.com/insipx/substrate-metadata-versions", package = "frame-metadatav9", branch = "master" }
Expand Down
84 changes: 59 additions & 25 deletions core/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ impl Decoder {
RustTypeMarker::Array { size, ty } => {
log::trace!("Array::cursor={}", *cursor);
let mut decoded_arr = Vec::with_capacity(*size);
if *size == 0 as usize {
if *size == 0_usize {
log::trace!("Returning Empty Vector");
return Ok(SubstrateType::Composite(Vec::new()));
} else {
Expand Down Expand Up @@ -467,7 +467,7 @@ impl Decoder {
self.decode_single(module, spec, v, data, cursor, true)?
}
},
RustTypeMarker::Generic((outer, _)) => {
RustTypeMarker::Generic(outer, _) => {
log::trace!("Generic Type");
// disregard 'inner' type of a generic
self.decode_single(module, spec, outer, data, cursor, is_compact)?
Expand Down Expand Up @@ -732,34 +732,25 @@ impl Decoder {
*cursor += 1;
Ok(Some(SubstrateType::GenericVote(vote)))
}
// Old Address Format for backwards-compatibility https://github.com/paritytech/substrate/pull/7380
"Lookup" | "GenericAddress" | "GenericLookupSource" | "GenericAccountId" => {
// a specific type that is <T as StaticSource>::Lookup concatenated to just 'Lookup'
log::trace!("cursor={}, data length={}", cursor, data.len());
let inc: usize;
// TODO: requires more investigation
// cursor increments for 0x00 .. 0xfe may be incorrect
match data[*cursor] {
0x00..=0xef => {
inc = 0;
}
0xfc => {
inc = 2;
}
0xfd => {
inc = 4;
}
0xfe => {
inc = 8;
}
0xff => {
inc = 32;
}
_ => return Err(Error::Fail("Invalid Address".to_string())),
}

let val: substrate_types::Address = Decode::decode(&mut &data[*cursor..])?;
let val: substrate_types::Address = decode_old_address(data, cursor)?;

*cursor += inc + 1; // +1 for byte 0x00-0xff
Ok(Some(SubstrateType::Address(val)))
}
"GenericMultiAddress" => {
let val: substrate_types::Address = Decode::decode(&mut &data[*cursor..])?;
let cursor_offset = match &val {
substrate_types::Address::Id(_) => 32,
substrate_types::Address::Index(_) => 1,
substrate_types::Address::Raw(v) => v.len(),
substrate_types::Address::Address32(_) => 32,
substrate_types::Address::Address20(_) => 20,
};
*cursor += cursor_offset;
Ok(Some(SubstrateType::Address(val)))
}
"Era" => {
Expand Down Expand Up @@ -823,6 +814,49 @@ impl Decoder {
}
}

/// Decodes old address pre-refactor (https://github.com/paritytech/substrate/pull/7380)
/// and converts it to a MultiAddress, where "old" here means anything before v0.8.26 or 26/2026/46 on polkadot/kusama/westend respectively.
fn decode_old_address(data: &[u8], cursor: &mut usize) -> Result<substrate_types::Address, Error> {
Copy link
Contributor

@niklasad1 niklasad1 Dec 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU there's nothing checks that cursor and cursor + 1 are valid indexes into data slice but maybe checked somewhere else?

It may panic then.

Copy link
Contributor Author

@insipx insipx Dec 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah,

This is part of the larger issue that the function decode_single doesn't do any bounds checking on the cursor at all, and panics if anything goes wrong. I'd rather address that in it's own PR though, since it might be a bit of a larger/medium sized refactor so I opened #35 to track that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, cool

/// Kept around for backwards-compatibility with old address struct
fn need_more_than<T: PartialOrd>(a: T, b: T) -> Result<T, Error> {
if a < b {
Ok(b)
} else {
Err("Invalid range".into())
}
}

let inc;
let addr = match data[*cursor] {
x @ 0x00..=0xef => {
inc = 0;
substrate_types::Address::Index(x as u32)
}
0xfc => {
inc = 2;
substrate_types::Address::Index(need_more_than(0xef, u16::decode(&mut &data[(*cursor + 1)..])?)? as u32)
}
0xfd => {
inc = 4;
substrate_types::Address::Index(need_more_than(0xffff, u32::decode(&mut &data[(*cursor + 1)..])?)?)
}
0xfe => {
inc = 8;
substrate_types::Address::Index(need_more_than(
0xffff_ffff_u32,
Decode::decode(&mut &data[(*cursor + 1)..])?,
)?)
}
0xff => {
inc = 32;
substrate_types::Address::Id(Decode::decode(&mut &data[(*cursor + 1)..])?)
}
_ => return Err(Error::Fail("Invalid Address".to_string())),
};
*cursor += inc + 1; // +1 for byte 0x00-0xff
Ok(addr)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
6 changes: 3 additions & 3 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ pub enum RustTypeMarker {

/// A Generic Type, EX: HeartBeat<BlockNumber>
/// Tuple of (OuterType, InnerType)
Generic((Box<RustTypeMarker>, Box<RustTypeMarker>)),
Generic(Box<RustTypeMarker>, Box<RustTypeMarker>),
/// primitive unsigned 8 bit integer
U8,
/// primtiive unsigned 16 bit integer
/// primitive unsigned 16 bit integer
U16,
/// primitive unsigned 32 bit integer
U32,
Expand Down Expand Up @@ -288,7 +288,7 @@ impl Display for RustTypeMarker {
}
RustTypeMarker::Array { size, ty } => type_marker.push_str(&format!("[{};{}], ", ty, size)),
RustTypeMarker::Std(t) => type_marker.push_str(&t.to_string()),
RustTypeMarker::Generic((outer, inner)) => type_marker.push_str(&format!("{}<{}>", outer, inner)),
RustTypeMarker::Generic(outer, inner) => type_marker.push_str(&format!("{}<{}>", outer, inner)),
RustTypeMarker::U8 => type_marker.push_str("u8"),
RustTypeMarker::U16 => type_marker.push_str("u16"),
RustTypeMarker::U32 => type_marker.push_str("u32"),
Expand Down
54 changes: 52 additions & 2 deletions core/src/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use onig::{Regex, Region, SearchOptions};
#[derive(Debug, Clone, PartialEq, Eq)]
enum RegexSet {
ArrayPrimitive,
BitSize,
ArrayStruct,
Vec,
Option,
Expand All @@ -37,6 +38,8 @@ impl RegexSet {
fn get_type(s: &str) -> Option<RegexSet> {
if rust_array_decl_prim().is_match(s) {
Some(RegexSet::ArrayPrimitive)
} else if rust_bit_size().is_match(s) {
Some(RegexSet::BitSize)
} else if rust_array_decl_struct().is_match(s) {
Some(RegexSet::ArrayStruct)
} else if rust_vec_decl().is_match(s) {
Expand All @@ -61,6 +64,7 @@ impl RegexSet {
fn parse_type(&self, s: &str) -> Option<RustTypeMarker> {
match self {
RegexSet::ArrayPrimitive => parse_primitive_array(s),
RegexSet::BitSize => parse_bit_size(s),
RegexSet::ArrayStruct => parse_struct_array(s),
RegexSet::Vec => parse_vec(s),
RegexSet::Option => parse_option(s),
Expand Down Expand Up @@ -90,6 +94,10 @@ fn rust_array_decl_struct() -> Regex {
Regex::new(r"^\[ *?([\w><]+) *?; *?(\d+) *?\]").expect("Primitive Regex expression invalid")
}

pub fn rust_bit_size() -> Regex {
Regex::new(r"^(Int|UInt)<(\d+), *[\w\d]+>").expect("Regex expression should be infallible; qed")
}

/// Match a rust vector
/// allowed to be nested within, or have other (ie Option<>) nested within
pub fn rust_vec_decl() -> Regex {
Expand Down Expand Up @@ -354,7 +362,40 @@ fn parse_generic(s: &str) -> Option<RustTypeMarker> {
// account that a HeartBeat type in Polkadot is HeartBeat<T::BlockNumber>
let ty_inner = parse(ty_inner).expect("Must be a type; qed");

Some(RustTypeMarker::Generic((Box::new(ty_outer), Box::new(ty_inner))))
Some(RustTypeMarker::Generic(Box::new(ty_outer), Box::new(ty_inner)))
}

fn parse_bit_size(s: &str) -> Option<RustTypeMarker> {
let re = rust_bit_size();
if !re.is_match(s) {
return None;
}

let ty = re.captures(s)?.at(1)?;
let size = re.captures(s)?.at(2)?;

match ty {
"UInt" => match size.parse::<usize>().expect("Should always be a number") {
8 => Some(RustTypeMarker::U8),
16 => Some(RustTypeMarker::U16),
32 => Some(RustTypeMarker::U32),
64 => Some(RustTypeMarker::U64),
128 => Some(RustTypeMarker::U128),
s => Some(RustTypeMarker::Array { size: s, ty: Box::new(RustTypeMarker::U8) }),
},
"Int" => match size.parse::<usize>().expect("Should always be number") {
8 => Some(RustTypeMarker::I8),
16 => Some(RustTypeMarker::I16),
32 => Some(RustTypeMarker::I32),
64 => Some(RustTypeMarker::I64),
128 => Some(RustTypeMarker::I128),
s => Some(RustTypeMarker::Array { size: s, ty: Box::new(RustTypeMarker::U8) }),
},
_ => {
log::warn!("Could not ascertain type of bit-size declaration");
None
}
}
}

/// recursively parses a regex set
Expand Down Expand Up @@ -674,7 +715,7 @@ mod tests {
let re = rust_generic_decl();
let caps = re.captures("GenericOuterType<GenericInnerType>").unwrap();
assert_eq!(
vec![Some("GenericOuterType<GenericInnerType>"), Some("GenericOuterType"), Some("GenericInnerType")],
vec![Some("GenericOuterType<GenericInnerType>"), Some("GenericOuterType"), Some("GenericInnerType"),],
caps.iter().collect::<Vec<Option<&str>>>()
);
}
Expand Down Expand Up @@ -829,4 +870,13 @@ mod tests {
let res = parse_vec(ty).unwrap();
log::debug!("{:?}", res);
}

#[test]
fn should_parse_bit_size() {
pretty_env_logger::try_init();
let ty = "UInt<128, Balance>";
assert_eq!(parse_bit_size(ty).unwrap(), RustTypeMarker::U128);
let ty = "Int<64, Balance>";
assert_eq!(parse_bit_size(ty).unwrap(), RustTypeMarker::I64);
}
}
9 changes: 6 additions & 3 deletions core/src/substrate_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use primitives::crypto::{Ss58AddressFormat, Ss58Codec};
use serde::Serialize;
use std::{convert::TryFrom, fmt};

pub type Address = pallet_indices::address::Address<AccountId32, u32>;
pub type Address = runtime_primitives::MultiAddress<AccountId32, u32>;
pub type Vote = pallet_democracy::Vote;
pub type Conviction = pallet_democracy::Conviction;
pub type Data = pallet_identity::Data;
Expand Down Expand Up @@ -135,10 +135,13 @@ impl fmt::Display for SubstrateType {
},
SubstrateType::GenericVote(v) => write!(f, "Aye={}, Conviction={}", v.aye, v.conviction.lock_periods()),
SubstrateType::Address(v) => match v {
pallet_indices::address::Address::Id(ref i) => {
runtime_primitives::MultiAddress::Id(ref i) => {
write!(f, "Account::Id({})", i.to_ss58check_with_version(Ss58AddressFormat::SubstrateAccount))
}
pallet_indices::address::Address::Index(i) => write!(f, "Index: {:?}", i),
runtime_primitives::MultiAddress::Index(i) => write!(f, "Index: {:?}", i),
runtime_primitives::MultiAddress::Raw(bytes) => write!(f, "Raw: {:?}", bytes),
runtime_primitives::MultiAddress::Address32(ary) => write!(f, "Address32: {:?}", ary),
runtime_primitives::MultiAddress::Address20(ary) => write!(f, "Address20: {:?}", ary),
},
SubstrateType::Data(d) => write!(f, "{:?}", d),
SubstrateType::SignedExtra(v) => write!(f, "{}", v),
Expand Down
8 changes: 8 additions & 0 deletions core/src/substrate_types/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ use super::{Address, Conviction, Data, Vote};
#[derive(Serialize, Deserialize)]
#[serde(remote = "Address")]
pub enum RemoteAddress {
/// It's an account ID (pubkey).
Id(AccountId32),
/// It's an account index.
Index(u32),
/// It's some arbitrary raw bytes.
Raw(Vec<u8>),
/// It's a 32 byte representation.
Address32([u8; 32]),
/// It's a 20 byte representation.
Address20([u8; 20]),
}

#[derive(Serialize, Deserialize)]
Expand Down
7 changes: 5 additions & 2 deletions core/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,14 @@ pub fn as_substrate_address<S: Serializer>(ty: &SubstrateType, serializer: S) ->
serializer.serialize_str(&addr)
}
SubstrateType::Address(v) => match v {
pallet_indices::address::Address::Id(ref i) => {
runtime_primitives::MultiAddress::Id(ref i) => {
let addr = i.to_ss58check_with_version(Ss58AddressFormat::SubstrateAccount);
serializer.serialize_str(&addr)
}
pallet_indices::address::Address::Index(i) => serializer.serialize_str(&format!("{}", i)),
runtime_primitives::MultiAddress::Index(i) => serializer.serialize_str(&format!("{}", i)),
runtime_primitives::MultiAddress::Raw(bytes) => serializer.serialize_str(&format!("{:?}", bytes)),
runtime_primitives::MultiAddress::Address32(ary) => serializer.serialize_str(&format!("{:?}", ary)),
runtime_primitives::MultiAddress::Address20(ary) => serializer.serialize_str(&format!("{:?}", ary)),
},
_ => Err(ser::Error::custom(format!("Could not format {:?} as Ss58 Address", ty))),
}
Expand Down
Loading