Update ssz_utils
for new AttestationRecord
.
This commit is contained in:
parent
6e0daec1da
commit
e0360edde0
@ -1,65 +1,45 @@
|
|||||||
|
use super::attestation_data::SSZ_ATTESTION_DATA_LENGTH;
|
||||||
use super::bls::{AggregateSignature, BLS_AGG_SIG_BYTE_SIZE};
|
use super::bls::{AggregateSignature, BLS_AGG_SIG_BYTE_SIZE};
|
||||||
use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream};
|
use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream, LENGTH_BYTES};
|
||||||
use super::{Bitfield, Hash256};
|
use super::{AttestationData, Bitfield};
|
||||||
|
|
||||||
pub const MIN_SSZ_ATTESTION_RECORD_LENGTH: usize = {
|
pub const MIN_SSZ_ATTESTION_RECORD_LENGTH: usize = {
|
||||||
8 + // slot
|
SSZ_ATTESTION_DATA_LENGTH + // data
|
||||||
2 + // shard_id
|
5 + // participation_bitfield (assuming 1 byte of bitfield)
|
||||||
4 + // oblique_parent_hashes (empty list)
|
5 + // custody_bitfield (assuming 1 byte of bitfield)
|
||||||
32 + // shard_block_hash
|
LENGTH_BYTES + BLS_AGG_SIG_BYTE_SIZE // aggregate sig
|
||||||
5 + // attester_bitfield (assuming 1 byte of bitfield)
|
|
||||||
8 + // justified_slot
|
|
||||||
32 + // justified_block_hash
|
|
||||||
4 + BLS_AGG_SIG_BYTE_SIZE // aggregate sig (two 256 bit points)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct AttestationRecord {
|
pub struct AttestationRecord {
|
||||||
pub slot: u64,
|
pub data: AttestationData,
|
||||||
pub shard_id: u16,
|
pub participation_bitfield: Bitfield,
|
||||||
pub oblique_parent_hashes: Vec<Hash256>,
|
pub custody_bitfield: Bitfield,
|
||||||
pub shard_block_hash: Hash256,
|
|
||||||
pub attester_bitfield: Bitfield,
|
|
||||||
pub justified_slot: u64,
|
|
||||||
pub justified_block_hash: Hash256,
|
|
||||||
pub aggregate_sig: AggregateSignature,
|
pub aggregate_sig: AggregateSignature,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for AttestationRecord {
|
impl Encodable for AttestationRecord {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.slot);
|
s.append(&self.data);
|
||||||
s.append(&self.shard_id);
|
s.append(&self.participation_bitfield);
|
||||||
s.append_vec(&self.oblique_parent_hashes);
|
s.append(&self.custody_bitfield);
|
||||||
s.append(&self.shard_block_hash);
|
|
||||||
s.append(&self.attester_bitfield);
|
|
||||||
s.append(&self.justified_slot);
|
|
||||||
s.append(&self.justified_block_hash);
|
|
||||||
s.append_vec(&self.aggregate_sig.as_bytes());
|
s.append_vec(&self.aggregate_sig.as_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for AttestationRecord {
|
impl Decodable for AttestationRecord {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (slot, i) = u64::ssz_decode(bytes, i)?;
|
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
|
||||||
let (shard_id, i) = u16::ssz_decode(bytes, i)?;
|
let (participation_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||||
let (oblique_parent_hashes, i) = decode_ssz_list(bytes, i)?;
|
let (custody_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||||
let (shard_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
|
||||||
let (attester_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
|
||||||
let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
|
|
||||||
let (justified_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
|
||||||
// Do aggregate sig decoding properly.
|
|
||||||
let (agg_sig_bytes, i) = decode_ssz_list(bytes, i)?;
|
let (agg_sig_bytes, i) = decode_ssz_list(bytes, i)?;
|
||||||
let aggregate_sig =
|
let aggregate_sig =
|
||||||
AggregateSignature::from_bytes(&agg_sig_bytes).map_err(|_| DecodeError::TooShort)?; // also could be TooLong
|
AggregateSignature::from_bytes(&agg_sig_bytes).map_err(|_| DecodeError::TooShort)?; // also could be TooLong
|
||||||
|
|
||||||
let attestation_record = Self {
|
let attestation_record = Self {
|
||||||
slot,
|
data,
|
||||||
shard_id,
|
participation_bitfield,
|
||||||
oblique_parent_hashes,
|
custody_bitfield,
|
||||||
shard_block_hash,
|
|
||||||
attester_bitfield,
|
|
||||||
justified_slot,
|
|
||||||
justified_block_hash,
|
|
||||||
aggregate_sig,
|
aggregate_sig,
|
||||||
};
|
};
|
||||||
Ok((attestation_record, i))
|
Ok((attestation_record, i))
|
||||||
@ -69,13 +49,9 @@ impl Decodable for AttestationRecord {
|
|||||||
impl AttestationRecord {
|
impl AttestationRecord {
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self {
|
Self {
|
||||||
slot: 0,
|
data: AttestationData::zero(),
|
||||||
shard_id: 0,
|
participation_bitfield: Bitfield::new(),
|
||||||
oblique_parent_hashes: vec![],
|
custody_bitfield: Bitfield::new(),
|
||||||
shard_block_hash: Hash256::zero(),
|
|
||||||
attester_bitfield: Bitfield::new(),
|
|
||||||
justified_slot: 0,
|
|
||||||
justified_block_hash: Hash256::zero(),
|
|
||||||
aggregate_sig: AggregateSignature::new(),
|
aggregate_sig: AggregateSignature::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,45 +59,29 @@ impl AttestationRecord {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::ssz::SszStream;
|
use super::super::ssz::ssz_encode;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_attestation_record_min_ssz_length() {
|
pub fn test_attestation_record_min_ssz_length() {
|
||||||
let ar = AttestationRecord::zero();
|
let ar = AttestationRecord::zero();
|
||||||
let mut ssz_stream = SszStream::new();
|
let ssz = ssz_encode(&ar);
|
||||||
ssz_stream.append(&ar);
|
|
||||||
let ssz = ssz_stream.drain();
|
|
||||||
|
|
||||||
assert_eq!(ssz.len(), MIN_SSZ_ATTESTION_RECORD_LENGTH);
|
assert_eq!(ssz.len(), MIN_SSZ_ATTESTION_RECORD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_attestation_record_min_ssz_encode_decode() {
|
pub fn test_attestation_record_ssz_round_trip() {
|
||||||
let original = AttestationRecord {
|
let original = AttestationRecord {
|
||||||
slot: 7,
|
data: AttestationData::zero(),
|
||||||
shard_id: 9,
|
participation_bitfield: Bitfield::from_bytes(&vec![17; 42][..]),
|
||||||
oblique_parent_hashes: vec![Hash256::from(&vec![14; 32][..])],
|
custody_bitfield: Bitfield::from_bytes(&vec![18; 12][..]),
|
||||||
shard_block_hash: Hash256::from(&vec![15; 32][..]),
|
|
||||||
attester_bitfield: Bitfield::from_bytes(&vec![17; 42][..]),
|
|
||||||
justified_slot: 19,
|
|
||||||
justified_block_hash: Hash256::from(&vec![15; 32][..]),
|
|
||||||
aggregate_sig: AggregateSignature::new(),
|
aggregate_sig: AggregateSignature::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ssz_stream = SszStream::new();
|
let ssz = ssz_encode(&original);
|
||||||
ssz_stream.append(&original);
|
let (decoded, _) = AttestationRecord::ssz_decode(&ssz, 0).unwrap();
|
||||||
|
|
||||||
let (decoded, _) = AttestationRecord::ssz_decode(&ssz_stream.drain(), 0).unwrap();
|
assert_eq!(original, decoded);
|
||||||
assert_eq!(original.slot, decoded.slot);
|
|
||||||
assert_eq!(original.shard_id, decoded.shard_id);
|
|
||||||
assert_eq!(
|
|
||||||
original.oblique_parent_hashes,
|
|
||||||
decoded.oblique_parent_hashes
|
|
||||||
);
|
|
||||||
assert_eq!(original.shard_block_hash, decoded.shard_block_hash);
|
|
||||||
assert_eq!(original.attester_bitfield, decoded.attester_bitfield);
|
|
||||||
assert_eq!(original.justified_slot, decoded.justified_slot);
|
|
||||||
assert_eq!(original.justified_block_hash, decoded.justified_block_hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use super::bls::BLS_AGG_SIG_BYTE_SIZE;
|
||||||
use super::ssz::decode::decode_length;
|
use super::ssz::decode::decode_length;
|
||||||
use super::ssz::LENGTH_BYTES;
|
use super::ssz::LENGTH_BYTES;
|
||||||
use super::types::attestation_record::MIN_SSZ_ATTESTION_RECORD_LENGTH as MIN_LENGTH;
|
use super::types::attestation_data::SSZ_ATTESTION_DATA_LENGTH;
|
||||||
|
use super::types::attestation_record::MIN_SSZ_ATTESTION_RECORD_LENGTH;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum AttestationSplitError {
|
pub enum AttestationSplitError {
|
||||||
@ -29,52 +31,89 @@ pub fn split_one_attestation(
|
|||||||
full_ssz: &[u8],
|
full_ssz: &[u8],
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> Result<(&[u8], usize), AttestationSplitError> {
|
) -> Result<(&[u8], usize), AttestationSplitError> {
|
||||||
if full_ssz.len() < MIN_LENGTH {
|
let length = determine_ssz_attestation_len(full_ssz, index)?;
|
||||||
|
let end = index + length;
|
||||||
|
|
||||||
|
// The check to ensure that the slice exists _should_ be redundant as it is already checked in
|
||||||
|
// `determine_ssz_attestation_len`, however it is checked here again for additional safety
|
||||||
|
// against panics.
|
||||||
|
match full_ssz.get(index..end) {
|
||||||
|
None => Err(AttestationSplitError::TooShort),
|
||||||
|
Some(slice) => Ok((slice, end)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given some SSZ, assume that a serialized `AttestationRecord` begins at the `index` position and
|
||||||
|
/// attempt to find the length (in bytes) of that serialized `AttestationRecord`.
|
||||||
|
///
|
||||||
|
/// This function does not perform validation on the `AttestationRecord`. It is very likely that
|
||||||
|
/// given some sufficiently long non-`AttestationRecord` bytes it will not raise an error.
|
||||||
|
fn determine_ssz_attestation_len(
|
||||||
|
full_ssz: &[u8],
|
||||||
|
index: usize,
|
||||||
|
) -> Result<usize, AttestationSplitError> {
|
||||||
|
if full_ssz.len() < MIN_SSZ_ATTESTION_RECORD_LENGTH {
|
||||||
return Err(AttestationSplitError::TooShort);
|
return Err(AttestationSplitError::TooShort);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hashes_len = decode_length(full_ssz, index + 10, LENGTH_BYTES)
|
let data_struct_end = index + SSZ_ATTESTION_DATA_LENGTH;
|
||||||
|
|
||||||
|
// Determine the end of the first bitfield.
|
||||||
|
let participation_bitfield_len = decode_length(full_ssz, data_struct_end, LENGTH_BYTES)
|
||||||
.map_err(|_| AttestationSplitError::TooShort)?;
|
.map_err(|_| AttestationSplitError::TooShort)?;
|
||||||
|
let participation_bitfield_end = data_struct_end + LENGTH_BYTES + participation_bitfield_len;
|
||||||
|
|
||||||
let bitfield_len = decode_length(full_ssz, index + hashes_len + 46, LENGTH_BYTES)
|
// Determine the end of the second bitfield.
|
||||||
|
let custody_bitfield_len = decode_length(full_ssz, participation_bitfield_end, LENGTH_BYTES)
|
||||||
.map_err(|_| AttestationSplitError::TooShort)?;
|
.map_err(|_| AttestationSplitError::TooShort)?;
|
||||||
|
let custody_bitfield_end = participation_bitfield_end + LENGTH_BYTES + custody_bitfield_len;
|
||||||
|
|
||||||
// Subtract one because the min length assumes 1 byte of bitfield
|
// Determine the very end of the AttestationRecord.
|
||||||
let len = MIN_LENGTH - 1 + hashes_len + bitfield_len;
|
let agg_sig_end = custody_bitfield_end + LENGTH_BYTES + BLS_AGG_SIG_BYTE_SIZE;
|
||||||
|
|
||||||
if full_ssz.len() < index + len {
|
if agg_sig_end > full_ssz.len() {
|
||||||
return Err(AttestationSplitError::TooShort);
|
Err(AttestationSplitError::TooShort)
|
||||||
|
} else {
|
||||||
|
Ok(agg_sig_end - index)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((&full_ssz[index..(index + len)], index + len))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::bls::AggregateSignature;
|
use super::super::bls::AggregateSignature;
|
||||||
use super::super::ssz::{Decodable, SszStream};
|
use super::super::ssz::{Decodable, SszStream};
|
||||||
use super::super::types::{AttestationRecord, Bitfield, Hash256};
|
use super::super::types::{AttestationData, AttestationRecord, Bitfield, Hash256};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn get_two_records() -> Vec<AttestationRecord> {
|
fn get_two_records() -> Vec<AttestationRecord> {
|
||||||
let a = AttestationRecord {
|
let a = AttestationRecord {
|
||||||
|
data: AttestationData {
|
||||||
slot: 7,
|
slot: 7,
|
||||||
shard_id: 9,
|
shard: 9,
|
||||||
oblique_parent_hashes: vec![Hash256::from(&vec![14; 32][..])],
|
beacon_block_hash: Hash256::from("a_beacon".as_bytes()),
|
||||||
shard_block_hash: Hash256::from(&vec![15; 32][..]),
|
epoch_boundary_hash: Hash256::from("a_epoch".as_bytes()),
|
||||||
attester_bitfield: Bitfield::from_bytes(&vec![17; 42][..]),
|
shard_block_hash: Hash256::from("a_shard".as_bytes()),
|
||||||
|
latest_crosslink_hash: Hash256::from("a_xlink".as_bytes()),
|
||||||
justified_slot: 19,
|
justified_slot: 19,
|
||||||
justified_block_hash: Hash256::from(&vec![15; 32][..]),
|
justified_block_hash: Hash256::from("a_justified".as_bytes()),
|
||||||
|
},
|
||||||
|
participation_bitfield: Bitfield::from_bytes(&vec![17; 42][..]),
|
||||||
|
custody_bitfield: Bitfield::from_bytes(&vec![255; 12][..]),
|
||||||
aggregate_sig: AggregateSignature::new(),
|
aggregate_sig: AggregateSignature::new(),
|
||||||
};
|
};
|
||||||
let b = AttestationRecord {
|
let b = AttestationRecord {
|
||||||
|
data: AttestationData {
|
||||||
slot: 9,
|
slot: 9,
|
||||||
shard_id: 7,
|
shard: 7,
|
||||||
oblique_parent_hashes: vec![Hash256::from(&vec![15; 32][..])],
|
beacon_block_hash: Hash256::from("b_beacon".as_bytes()),
|
||||||
shard_block_hash: Hash256::from(&vec![14; 32][..]),
|
epoch_boundary_hash: Hash256::from("b_epoch".as_bytes()),
|
||||||
attester_bitfield: Bitfield::from_bytes(&vec![19; 42][..]),
|
shard_block_hash: Hash256::from("b_shard".as_bytes()),
|
||||||
|
latest_crosslink_hash: Hash256::from("b_xlink".as_bytes()),
|
||||||
justified_slot: 15,
|
justified_slot: 15,
|
||||||
justified_block_hash: Hash256::from(&vec![17; 32][..]),
|
justified_block_hash: Hash256::from("b_justified".as_bytes()),
|
||||||
|
},
|
||||||
|
participation_bitfield: Bitfield::from_bytes(&vec![1; 42][..]),
|
||||||
|
custody_bitfield: Bitfield::from_bytes(&vec![11; 3][..]),
|
||||||
aggregate_sig: AggregateSignature::new(),
|
aggregate_sig: AggregateSignature::new(),
|
||||||
};
|
};
|
||||||
vec![a, b]
|
vec![a, b]
|
||||||
|
@ -293,8 +293,8 @@ mod tests {
|
|||||||
// will tell us if the hash changes, not that it matches some
|
// will tell us if the hash changes, not that it matches some
|
||||||
// canonical reference.
|
// canonical reference.
|
||||||
let expected_hash = [
|
let expected_hash = [
|
||||||
11, 181, 149, 114, 248, 15, 46, 0, 106, 135, 158, 31, 15, 194, 149, 176, 43, 110, 154,
|
254, 192, 124, 164, 240, 137, 162, 126, 50, 255, 118, 88, 189, 151, 221, 4, 40, 121,
|
||||||
26, 253, 67, 18, 139, 250, 84, 144, 219, 3, 208, 50, 145,
|
198, 33, 248, 221, 104, 255, 46, 234, 146, 161, 202, 140, 109, 175,
|
||||||
];
|
];
|
||||||
assert_eq!(hash, expected_hash);
|
assert_eq!(hash, expected_hash);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user