Update beacon_block_store for new block struct

This commit is contained in:
Paul Hauner 2018-12-25 10:38:40 +11:00
parent b95395d1e1
commit f140e2938f
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C

View File

@ -1,9 +1,8 @@
extern crate ssz_helpers;
use self::ssz_helpers::ssz_beacon_block::SszBeaconBlock;
use super::BLOCKS_DB_COLUMN as DB_COLUMN; use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError}; use super::{ClientDB, DBError};
use ssz::{Decodable, DecodeError};
use std::sync::Arc; use std::sync::Arc;
use types::Hash256;
type BeaconBlockHash = Vec<u8>; type BeaconBlockHash = Vec<u8>;
type BeaconBlockSsz = Vec<u8>; type BeaconBlockSsz = Vec<u8>;
@ -60,21 +59,29 @@ impl<T: ClientDB> BeaconBlockStore<T> {
match self.get_serialized_block(head_hash)? { match self.get_serialized_block(head_hash)? {
None => Err(BeaconBlockAtSlotError::UnknownBeaconBlock), None => Err(BeaconBlockAtSlotError::UnknownBeaconBlock),
Some(ssz) => { Some(ssz) => {
let block = SszBeaconBlock::from_slice(&ssz) let (retrieved_slot, parent_hash) = slot_and_parent_from_block_ssz(&ssz, 0)
.map_err(|_| BeaconBlockAtSlotError::InvalidBeaconBlock)?; .map_err(|_| BeaconBlockAtSlotError::InvalidBeaconBlock)?;
match block.slot() { match retrieved_slot {
s if s == slot => Ok(Some((head_hash.to_vec(), ssz.to_vec()))), s if s == slot => Ok(Some((head_hash.to_vec(), ssz.to_vec()))),
s if s < slot => Ok(None), s if s < slot => Ok(None),
_ => match block.parent_hash() { _ => self.block_at_slot(&parent_hash, slot),
Some(parent_hash) => self.block_at_slot(parent_hash, slot),
None => Err(BeaconBlockAtSlotError::UnknownBeaconBlock),
},
} }
} }
} }
} }
} }
/// Read `block.slot` and `block.parent_root` from a SSZ-encoded block bytes.
///
/// Assumes the block starts at byte `i`.
fn slot_and_parent_from_block_ssz(ssz: &[u8], i: usize) -> Result<(u64, Hash256), DecodeError> {
// Assuming the slot is the first field on a block.
let (slot, i) = u64::ssz_decode(&ssz, i)?;
// Assuming the parent has is the second field on a block.
let (parent_root, _) = Hash256::ssz_decode(&ssz, i)?;
Ok((slot, parent_root))
}
impl From<DBError> for BeaconBlockAtSlotError { impl From<DBError> for BeaconBlockAtSlotError {
fn from(e: DBError) -> Self { fn from(e: DBError) -> Self {
BeaconBlockAtSlotError::DBError(e.message) BeaconBlockAtSlotError::DBError(e.message)
@ -83,19 +90,17 @@ impl From<DBError> for BeaconBlockAtSlotError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
extern crate ssz;
extern crate types;
use self::ssz::SszStream;
use self::types::attestation::Attestation;
use self::types::beacon_block::BeaconBlock;
use self::types::Hash256;
use super::super::super::MemoryDB; use super::super::super::MemoryDB;
use super::*; use super::*;
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
use ssz::ssz_encode;
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
use types::BeaconBlock;
use types::Hash256;
#[test] #[test]
fn test_put_serialized_block() { fn test_put_serialized_block() {
let db = Arc::new(MemoryDB::open()); let db = Arc::new(MemoryDB::open());
@ -247,60 +252,58 @@ mod tests {
fn test_block_at_slot() { fn test_block_at_slot() {
let db = Arc::new(MemoryDB::open()); let db = Arc::new(MemoryDB::open());
let bs = Arc::new(BeaconBlockStore::new(db.clone())); let bs = Arc::new(BeaconBlockStore::new(db.clone()));
let mut rng = XorShiftRng::from_seed([42; 16]);
let blocks = (0..5).into_iter().map(|_| { // Specify test block parameters.
let mut block = BeaconBlock::zero();
let ar = Attestation::zero();
block.attestations.push(ar);
block
});
let hashes = [ let hashes = [
Hash256::from("zero".as_bytes()), Hash256::from(&[0; 32][..]),
Hash256::from("one".as_bytes()), Hash256::from(&[1; 32][..]),
Hash256::from("two".as_bytes()), Hash256::from(&[2; 32][..]),
Hash256::from("three".as_bytes()), Hash256::from(&[3; 32][..]),
Hash256::from("four".as_bytes()), Hash256::from(&[4; 32][..]),
]; ];
let parent_hashes = [ let parent_hashes = [
Hash256::from("genesis".as_bytes()), Hash256::from(&[255; 32][..]), // Genesis block.
Hash256::from("zero".as_bytes()), Hash256::from(&[0; 32][..]),
Hash256::from("one".as_bytes()), Hash256::from(&[1; 32][..]),
Hash256::from("two".as_bytes()), Hash256::from(&[2; 32][..]),
Hash256::from("three".as_bytes()), Hash256::from(&[3; 32][..]),
]; ];
let slots = [0, 1, 3, 4, 5]; let slots = [0, 1, 3, 4, 5];
for (i, mut block) in blocks.enumerate() { // Generate a vec of random blocks and store them in the DB.
block.ancestor_hashes.push(parent_hashes[i]); let block_count = 5;
let mut blocks: Vec<BeaconBlock> = Vec::with_capacity(5);
for i in 0..block_count {
let mut block = BeaconBlock::random_for_test(&mut rng);
block.parent_root = parent_hashes[i];
block.slot = slots[i]; block.slot = slots[i];
let mut s = SszStream::new();
s.append(&block); let ssz = ssz_encode(&block);
let ssz = s.drain();
db.put(DB_COLUMN, &hashes[i].to_vec(), &ssz).unwrap(); db.put(DB_COLUMN, &hashes[i].to_vec(), &ssz).unwrap();
// Ensure the slot and parent_root decoding fn works correctly.
let (decoded_slot, decoded_parent_root) =
slot_and_parent_from_block_ssz(&ssz, 0).unwrap();
assert_eq!(decoded_slot, block.slot);
assert_eq!(decoded_parent_root, block.parent_root);
blocks.push(block);
} }
let tuple = bs.block_at_slot(&hashes[4], 5).unwrap().unwrap(); // Test that certain slots can be reached from certain hashes.
let block = SszBeaconBlock::from_slice(&tuple.1).unwrap(); let test_cases = vec![(4, 4), (4, 3), (4, 2), (4, 1), (4, 0)];
assert_eq!(block.slot(), 5); for (hashes_index, slot_index) in test_cases {
assert_eq!(tuple.0, hashes[4].to_vec()); let (matched_block_hash, matched_block_ssz) = bs
.block_at_slot(&hashes[hashes_index], slots[slot_index])
let tuple = bs.block_at_slot(&hashes[4], 4).unwrap().unwrap(); .unwrap()
let block = SszBeaconBlock::from_slice(&tuple.1).unwrap(); .unwrap();
assert_eq!(block.slot(), 4); let (retrieved_slot, _) =
assert_eq!(tuple.0, hashes[3].to_vec()); slot_and_parent_from_block_ssz(&matched_block_ssz, 0).unwrap();
assert_eq!(retrieved_slot, slots[slot_index]);
let tuple = bs.block_at_slot(&hashes[4], 3).unwrap().unwrap(); assert_eq!(matched_block_hash, hashes[slot_index].to_vec());
let block = SszBeaconBlock::from_slice(&tuple.1).unwrap(); }
assert_eq!(block.slot(), 3);
assert_eq!(tuple.0, hashes[2].to_vec());
let tuple = bs.block_at_slot(&hashes[4], 0).unwrap().unwrap();
let block = SszBeaconBlock::from_slice(&tuple.1).unwrap();
assert_eq!(block.slot(), 0);
assert_eq!(tuple.0, hashes[0].to_vec());
let ssz = bs.block_at_slot(&hashes[4], 2).unwrap(); let ssz = bs.block_at_slot(&hashes[4], 2).unwrap();
assert_eq!(ssz, None); assert_eq!(ssz, None);