bitfield: fix bit ordering issue with YAML parsing
This commit is contained in:
parent
8da8730dca
commit
0a02567440
@ -18,3 +18,16 @@ pub fn verify_bitfield_length(bitfield: &Bitfield, committee_size: usize) -> boo
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn bitfield_length() {
|
||||
assert!(verify_bitfield_length(
|
||||
&Bitfield::from_bytes(&[0b10000000]),
|
||||
4
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ edition = "2018"
|
||||
serde_hex = { path = "../serde_hex" }
|
||||
ssz = { path = "../ssz" }
|
||||
bit-vec = "0.5.0"
|
||||
bit_reverse = "0.1"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
tree_hash = { path = "../tree_hash" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_yaml = "0.8"
|
||||
|
@ -1,8 +1,8 @@
|
||||
extern crate bit_vec;
|
||||
extern crate ssz;
|
||||
|
||||
use bit_reverse::LookupReverse;
|
||||
use bit_vec::BitVec;
|
||||
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde_hex::{encode, PrefixedHexVisitor};
|
||||
@ -236,24 +236,36 @@ impl Decodable for BooleanBitfield {
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the bit order of a whole byte vec, so that the ith bit
|
||||
// of the input vec is placed in the (N - i)th bit of the output vec.
|
||||
// This function is necessary for converting bitfields to and from YAML,
|
||||
// as the BitVec library and the hex-parser use opposing bit orders.
|
||||
fn reverse_bit_order(mut bytes: Vec<u8>) -> Vec<u8> {
|
||||
bytes.reverse();
|
||||
bytes.into_iter().map(|b| b.swap_bits()).collect()
|
||||
}
|
||||
|
||||
impl Serialize for BooleanBitfield {
|
||||
/// Serde serialization is compliant the Ethereum YAML test format.
|
||||
/// Serde serialization is compliant with the Ethereum YAML test format.
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&encode(&self.to_bytes()))
|
||||
serializer.serialize_str(&encode(&reverse_bit_order(self.to_bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for BooleanBitfield {
|
||||
/// Serde serialization is compliant the Ethereum YAML test format.
|
||||
/// Serde serialization is compliant with the Ethereum YAML test format.
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
// We reverse the bit-order so that the BitVec library can read its 0th
|
||||
// bit from the end of the hex string, e.g.
|
||||
// "0xef01" => [0xef, 0x01] => [0b1000_0000, 0b1111_1110]
|
||||
let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?;
|
||||
Ok(BooleanBitfield::from_bytes(&bytes))
|
||||
Ok(BooleanBitfield::from_bytes(&reverse_bit_order(bytes)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +274,7 @@ tree_hash_ssz_encoding_as_list!(BooleanBitfield);
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_yaml;
|
||||
use ssz::{decode, ssz_encode, SszStream};
|
||||
|
||||
#[test]
|
||||
@ -462,6 +475,27 @@ mod tests {
|
||||
assert_eq!(field, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_deserialize() {
|
||||
use serde_yaml::Value;
|
||||
|
||||
let data: &[(_, &[_])] = &[
|
||||
("0x01", &[0b10000000]),
|
||||
("0xf301", &[0b10000000, 0b11001111]),
|
||||
];
|
||||
for (hex_data, bytes) in data {
|
||||
let bitfield = BooleanBitfield::from_bytes(bytes);
|
||||
assert_eq!(
|
||||
serde_yaml::from_str::<BooleanBitfield>(hex_data).unwrap(),
|
||||
bitfield
|
||||
);
|
||||
assert_eq!(
|
||||
serde_yaml::to_value(&bitfield).unwrap(),
|
||||
Value::String(hex_data.to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ssz_round_trip() {
|
||||
let original = BooleanBitfield::from_bytes(&vec![18; 12][..]);
|
||||
|
Loading…
Reference in New Issue
Block a user