diff --git a/core/sr-primitives/src/generic/mod.rs b/core/sr-primitives/src/generic/mod.rs index 6732722c4db0a..2f944be29dc39 100644 --- a/core/sr-primitives/src/generic/mod.rs +++ b/core/sr-primitives/src/generic/mod.rs @@ -35,3 +35,28 @@ pub use self::checked_extrinsic::CheckedExtrinsic; pub use self::header::Header; pub use self::block::{Block, SignedBlock, BlockId}; pub use self::digest::{Digest, DigestItem, DigestItemRef}; + +use codec::Encode; +use rstd::prelude::*; + +fn encode_with_vec_prefix)>(encoder: F) -> Vec { + let size = ::rstd::mem::size_of::(); + let reserve = match size { + 0...0b00111111 => 1, + 0...0b00111111_11111111 => 2, + _ => 4, + }; + let mut v = Vec::with_capacity(reserve + size); + v.resize(reserve, 0); + encoder(&mut v); + + // need to prefix with the total length to ensure it's binary comptible with + // Vec. + let mut length: Vec<()> = Vec::new(); + length.resize(v.len() - reserve, ()); + length.using_encoded(|s| { + v.splice(0..reserve, s.iter().cloned()); + }); + + v +} diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index 4f3a32b34d156..b5cd01c2cd9e3 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -103,9 +103,9 @@ where fn decode(input: &mut I) -> Option { // This is a little more complicated than usual since the binary format must be compatible // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of u32, which has the total number of bytes following (we don't need + // will be a prefix of vector length (we don't need // to use this). - let _length_do_not_remove_me_see_above: u32 = Decode::decode(input)?; + let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?; Some(UncheckedExtrinsic { signature: Decode::decode(input)?, @@ -123,19 +123,10 @@ where Call: Encode, { fn encode(&self) -> Vec { - let mut v = Vec::new(); - - // need to prefix with the total length as u32 to ensure it's binary comptible with - // Vec. we'll make room for it here, then overwrite once we know the length. - v.extend(&[0u8; 4]); - - self.signature.encode_to(&mut v); - self.function.encode_to(&mut v); - - let length = (v.len() - 4) as u32; - length.using_encoded(|s| v[0..4].copy_from_slice(s)); - - v + super::encode_with_vec_prefix::(|v| { + self.signature.encode_to(v); + self.function.encode_to(v); + }) } } @@ -150,3 +141,20 @@ impl fmt::Debug for UncheckedExtrinsic; + let ex = Extrinsic::new_unsigned(42); + let encoded = ex.encode(); + let decoded = Extrinsic::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(decoded, ex); + let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(as_vec.encode(), encoded); + } +} diff --git a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs index c494bc00ff428..793532c0749fe 100644 --- a/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_mortal_extrinsic.rs @@ -113,9 +113,9 @@ where fn decode(input: &mut I) -> Option { // This is a little more complicated than usual since the binary format must be compatible // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of u32, which has the total number of bytes following (we don't need + // will be a prefix of vector length (we don't need // to use this). - let _length_do_not_remove_me_see_above: u32 = Decode::decode(input)?; + let _length_do_not_remove_me_see_above: Vec<()> = Decode::decode(input)?; let version = input.read_byte()?; @@ -141,28 +141,19 @@ where Call: Encode, { fn encode(&self) -> Vec { - let mut v = Vec::new(); - - // need to prefix with the total length as u32 to ensure it's binary comptible with - // Vec. we'll make room for it here, then overwrite once we know the length. - v.extend(&[0u8; 4]); - - // 1 byte version id. - match self.signature.as_ref() { - Some(s) => { - v.push(TRANSACTION_VERSION | 0b1000_0000); - s.encode_to(&mut v); - } - None => { - v.push(TRANSACTION_VERSION & 0b0111_1111); + super::encode_with_vec_prefix::(|v| { + // 1 byte version id. + match self.signature.as_ref() { + Some(s) => { + v.push(TRANSACTION_VERSION | 0b1000_0000); + s.encode_to(v); + } + None => { + v.push(TRANSACTION_VERSION & 0b0111_1111); + } } - } - self.function.encode_to(&mut v); - - let length = (v.len() - 4) as u32; - length.using_encoded(|s| v[0..4].copy_from_slice(s)); - - v + self.function.encode_to(v); + }) } } @@ -275,4 +266,14 @@ mod tests { assert!(ux.is_signed()); assert_eq!(>::check(ux, &TestContext), Err("bad signature in extrinsic")); } -} \ No newline at end of file + + #[test] + fn encoding_matches_vec() { + let ex = Ex::new_unsigned(DUMMY_FUNCTION); + let encoded = ex.encode(); + let decoded = Ex::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(decoded, ex); + let as_vec: Vec = Decode::decode(&mut encoded.as_slice()).unwrap(); + assert_eq!(as_vec.encode(), encoded); + } +} diff --git a/node/executor/src/lib.rs b/node/executor/src/lib.rs index 7fc4f51d69255..b0e7ba25f3200 100644 --- a/node/executor/src/lib.rs +++ b/node/executor/src/lib.rs @@ -312,7 +312,7 @@ mod tests { construct_block( 2, block1(false).1, - hex!("e312f8e2111124c57448050aed74c625382ed222f48ab55ada41afacd0a65fa6").into(), + hex!("0f107d73773b84409de8a444dd0d39e6d90b18b3ce393b379a4f6bf34226aa0a").into(), None, vec![ CheckedExtrinsic {