mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 14:01:02 +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::header::Header;
|
||||||
pub use self::block::{Block, SignedBlock, BlockId};
|
pub use self::block::{Block, SignedBlock, BlockId};
|
||||||
pub use self::digest::{Digest, DigestItem, DigestItemRef};
|
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> {
|
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||||
// This is a little more complicated than usual since the binary format must be compatible
|
// 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
|
// 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).
|
// 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 {
|
Some(UncheckedExtrinsic {
|
||||||
signature: Decode::decode(input)?,
|
signature: Decode::decode(input)?,
|
||||||
@@ -123,19 +123,10 @@ where
|
|||||||
Call: Encode,
|
Call: Encode,
|
||||||
{
|
{
|
||||||
fn encode(&self) -> Vec<u8> {
|
fn encode(&self) -> Vec<u8> {
|
||||||
let mut v = Vec::new();
|
super::encode_with_vec_prefix::<Self, _>(|v| {
|
||||||
|
self.signature.encode_to(v);
|
||||||
// need to prefix with the total length as u32 to ensure it's binary comptible with
|
self.function.encode_to(v);
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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)
|
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> {
|
fn decode<I: Input>(input: &mut I) -> Option<Self> {
|
||||||
// This is a little more complicated than usual since the binary format must be compatible
|
// 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
|
// 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).
|
// 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()?;
|
let version = input.read_byte()?;
|
||||||
|
|
||||||
@@ -141,28 +141,19 @@ where
|
|||||||
Call: Encode,
|
Call: Encode,
|
||||||
{
|
{
|
||||||
fn encode(&self) -> Vec<u8> {
|
fn encode(&self) -> Vec<u8> {
|
||||||
let mut v = Vec::new();
|
super::encode_with_vec_prefix::<Self, _>(|v| {
|
||||||
|
// 1 byte version id.
|
||||||
// need to prefix with the total length as u32 to ensure it's binary comptible with
|
match self.signature.as_ref() {
|
||||||
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
|
Some(s) => {
|
||||||
v.extend(&[0u8; 4]);
|
v.push(TRANSACTION_VERSION | 0b1000_0000);
|
||||||
|
s.encode_to(v);
|
||||||
// 1 byte version id.
|
}
|
||||||
match self.signature.as_ref() {
|
None => {
|
||||||
Some(s) => {
|
v.push(TRANSACTION_VERSION & 0b0111_1111);
|
||||||
v.push(TRANSACTION_VERSION | 0b1000_0000);
|
}
|
||||||
s.encode_to(&mut v);
|
|
||||||
}
|
}
|
||||||
None => {
|
self.function.encode_to(v);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,4 +266,14 @@ mod tests {
|
|||||||
assert!(ux.is_signed());
|
assert!(ux.is_signed());
|
||||||
assert_eq!(<Ex as Checkable<TestContext>>::check(ux, &TestContext), Err("bad signature in extrinsic"));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,7 @@ mod tests {
|
|||||||
construct_block(
|
construct_block(
|
||||||
2,
|
2,
|
||||||
block1(false).1,
|
block1(false).1,
|
||||||
hex!("e312f8e2111124c57448050aed74c625382ed222f48ab55ada41afacd0a65fa6").into(),
|
hex!("0f107d73773b84409de8a444dd0d39e6d90b18b3ce393b379a4f6bf34226aa0a").into(),
|
||||||
None,
|
None,
|
||||||
vec![
|
vec![
|
||||||
CheckedExtrinsic {
|
CheckedExtrinsic {
|
||||||
|
|||||||
Reference in New Issue
Block a user