mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Fixed extrinsic encoding (#794)
* Fixed extrinsic encoding * Reserve heuristic * Fixed no-std build
This commit is contained in:
committed by
Gav Wood
parent
68e3e3ee11
commit
a613c62dc1
@@ -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<T: Encode, F: Fn(&mut Vec<u8>)>(encoder: F) -> Vec<u8> {
|
||||
let size = ::rstd::mem::size_of::<T>();
|
||||
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<u8>.
|
||||
let mut length: Vec<()> = Vec::new();
|
||||
length.resize(v.len() - reserve, ());
|
||||
length.using_encoded(|s| {
|
||||
v.splice(0..reserve, s.iter().cloned());
|
||||
});
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
@@ -103,9 +103,9 @@ where
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
// This is a little more complicated than usual since the binary format must be compatible
|
||||
// with substrate's generic `Vec<u8>` 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<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
// need to prefix with the total length as u32 to ensure it's binary comptible with
|
||||
// Vec<u8>. 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::<Self, _>(|v| {
|
||||
self.signature.encode_to(v);
|
||||
self.function.encode_to(v);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,3 +141,20 @@ impl<Address, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<Address,
|
||||
write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use codec::{Decode, Encode};
|
||||
use super::UncheckedExtrinsic;
|
||||
|
||||
#[test]
|
||||
fn encoding_matches_vec() {
|
||||
type Extrinsic = UncheckedExtrinsic<u32, u32, u32, u32>;
|
||||
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<u8> = Decode::decode(&mut encoded.as_slice()).unwrap();
|
||||
assert_eq!(as_vec.encode(), encoded);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +113,9 @@ where
|
||||
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||
// This is a little more complicated than usual since the binary format must be compatible
|
||||
// with substrate's generic `Vec<u8>` 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<u8> {
|
||||
let mut v = Vec::new();
|
||||
|
||||
// need to prefix with the total length as u32 to ensure it's binary comptible with
|
||||
// Vec<u8>. 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);
|
||||
super::encode_with_vec_prefix::<Self, _>(|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);
|
||||
}
|
||||
}
|
||||
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!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Err("bad signature in extrinsic"));
|
||||
}
|
||||
}
|
||||
|
||||
#[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<u8> = Decode::decode(&mut encoded.as_slice()).unwrap();
|
||||
assert_eq!(as_vec.encode(), encoded);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user