From 41ef019d57b92e0455e4d0d60db646af20800c5f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sat, 29 Dec 2018 14:39:56 +1100 Subject: [PATCH] Add unfinished chain code --- beacon_chain/abstract_chain/Cargo.toml | 10 + .../abstract_chain/src/block_reader.rs | 16 ++ beacon_chain/abstract_chain/src/lib.rs | 185 ++++++++++++++++++ .../db/src/stores/beacon_state_store.rs | 33 ++++ 4 files changed, 244 insertions(+) create mode 100644 beacon_chain/abstract_chain/Cargo.toml create mode 100644 beacon_chain/abstract_chain/src/block_reader.rs create mode 100644 beacon_chain/abstract_chain/src/lib.rs create mode 100644 lighthouse/db/src/stores/beacon_state_store.rs diff --git a/beacon_chain/abstract_chain/Cargo.toml b/beacon_chain/abstract_chain/Cargo.toml new file mode 100644 index 0000000000..6e11036cba --- /dev/null +++ b/beacon_chain/abstract_chain/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "abstract_chain" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dependencies] +hashing = { path = "../utils/hashing" } +ssz = { path = "../utils/ssz" } +types = { path = "../types" } diff --git a/beacon_chain/abstract_chain/src/block_reader.rs b/beacon_chain/abstract_chain/src/block_reader.rs new file mode 100644 index 0000000000..9d66dc5b69 --- /dev/null +++ b/beacon_chain/abstract_chain/src/block_reader.rs @@ -0,0 +1,16 @@ +use types::{BeaconBlock, Hash256}; + +pub trait BlockReader { + fn slot(&self) -> u64; + fn parent_root(&self) -> Hash256; +} + +impl BlockReader for BeaconBlock { + fn slot(&self) -> u64 { + self.slot + } + + fn parent_root(&self) -> Hash256 { + self.parent_root + } +} diff --git a/beacon_chain/abstract_chain/src/lib.rs b/beacon_chain/abstract_chain/src/lib.rs new file mode 100644 index 0000000000..e348dfdba6 --- /dev/null +++ b/beacon_chain/abstract_chain/src/lib.rs @@ -0,0 +1,185 @@ +/* + * + */ + + +use hashing::canonical_hash; +use ssz::{Encodable, Decodable, DecodeError, SszStream, ssz_encode}; +use std::collections::{HashMap, HashSet}; +use types::Hash256; + +mod block_reader; + +use crate::block_reader::BlockReader; + +pub trait AbstractChain { + type Block; + type Hash; + + fn genesis(&mut self); + + fn receive_block(&mut self, block: &BlockReader) -> bool; + + fn block_by_root(&self, root: &Self::Hash) -> Option<&Self::Block>; +} + +pub struct TestBlock { + slot: u64, + parent_root: Hash256, + state_root: Hash256, + weight: u8, +} + +impl Encodable for TestBlock { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.slot); + s.append(&self.parent_root); + } +} + +impl Decodable for TestBlock { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (slot, i) = <_>::ssz_decode(bytes, i)?; + let (parent_root, i) = <_>::ssz_decode(bytes, i)?; + let (state_root, i) = <_>::ssz_decode(bytes, i)?; + let (weight, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + slot, + parent_root, + state_root, + weight, + }, + i, + )) + } +} + +impl TestBlock { + fn canonical_hash(&self) -> Hash256 { + Hash256::from(&canonical_hash(&ssz_encode(self))[..]) + } +} + +impl BlockReader for TestBlock { + fn slot(&self) -> u64 { + self.slot + } + + fn parent_root(&self) -> Hash256 { + self.parent_root + } +} + +#[derive(Clone)] +pub struct TestState { + total_weight: u64, + skipped_slots: u64, +} + +impl Encodable for TestState { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.total_weight); + s.append(&self.skipped_slots); + } +} + +impl TestState { + fn canonical_hash(&self) -> Hash256 { + Hash256::from(&canonical_hash(&ssz_encode(self))[..]) + } +} + +impl Decodable for TestState { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (total_weight, i) = <_>::ssz_decode(bytes, i)?; + let (skipped_slots, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + total_weight, + skipped_slots, + }, + i, + )) + } +} + +pub struct TestChain { + slot: u64, + block_store: HashMap, + state_store: HashMap, + leaf_nodes: HashSet, + canonical_leaf_node: Hash256, +} + +impl AbstractChain for TestChain { + type Block = TestBlock; + type Hash = Hash256; + + fn genesis(&mut self) { + let genesis_state = TestState { + total_weight: 255, + skipped_slots: 0, + }; + let state_root = genesis_state.canonical_hash(); + let genesis_block = TestBlock { + slot: 0, + parent_root: Hash256::zero(), + state_root: state_root.clone(), + weight: 255, + }; + let block_root = genesis_block.canonical_hash(); + self.block_store.insert(block_root, genesis_block); + self.state_store.insert(state_root, genesis_state); + self.leaf_nodes.insert(block_root); + self.canonical_leaf_node = block_root; + self.slot = 0; + } + + fn block_by_root(&self, root: &Hash256) -> Option<&Self::Block> { + self.block_store.get(root) + } + + fn receive_block(&mut self, block: &BlockReader) -> bool { + let block_hash = block.canonical_hash(); + let parent_block = match self.block_by_root(&block.parent_root()) { + Some(block) => block, + None => return false + }; + let slot_distance = block.slot().saturating_sub(parent_block.slot()); + if slot_distance > 0 { + let mut state = self.state_store.get(&block.parent_root()).unwrap().clone(); + for _ in parent_block.slot()..(block.slot() - 1) { + state.skipped_slots += 1; + } + state.total_weight += u64::from(block.weight); + let state_root = state.canonical_hash(); + if state_root != block.state_root { + return false; + } + self.leaf_nodes.remove(&block.parent_root()); + self.leaf_nodes.insert(block_hash); + + let canonical_state = { + let canonical_block = self.block_store.get(&self.canonical_leaf_node).unwrap(); + self.state_store.get(&canonical_block.state_root).unwrap() + }; + // New block is canonical, chain weight is greatest. + if state.total_weight > canonical_state.total_weight { + self.canonical_leaf_node = block_hash; + } + // New block chain weight equals existing canonical block chain weight. + else if state.total_weight == canonical_state.total_weight { + // New block is canonical as hash is highest. + if block_hash > self.canonical_leaf_node { + self.canonical_leaf_node = block_hash; + } + } + true + } else { + false + } + } +} diff --git a/lighthouse/db/src/stores/beacon_state_store.rs b/lighthouse/db/src/stores/beacon_state_store.rs new file mode 100644 index 0000000000..4d3bbb36c9 --- /dev/null +++ b/lighthouse/db/src/stores/beacon_state_store.rs @@ -0,0 +1,33 @@ +use super::STATES_DB_COLUMN as DB_COLUMN; +use super::{ClientDB, DBError}; +use std::sync::Arc; +use types::Hash256; + +pub struct BeaconStateStore +where + T: ClientDB, +{ + db: Arc, +} + +impl BeaconStateStore { + pub fn new(db: Arc) -> Self { + Self { db } + } + + pub fn put(&self, hash: &Hash256, ssz: &[u8]) -> Result<(), DBError> { + self.db.put(DB_COLUMN, hash, ssz) + } + + pub fn get(&self, hash: &[u8]) -> Result>, DBError> { + self.db.get(DB_COLUMN, hash) + } + + pub fn exists(&self, hash: &[u8]) -> Result { + self.db.exists(DB_COLUMN, hash) + } + + pub fn delete(&self, hash: &[u8]) -> Result<(), DBError> { + self.db.delete(DB_COLUMN, hash) + } +}