mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-17 03:42:46 +00:00
Add basic block generator impl
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
use crate::ExecutionBlock;
|
||||
use types::{Hash256, Uint256};
|
||||
|
||||
pub struct ExecutionBlockGenerator {
|
||||
pub seconds_since_genesis: u64,
|
||||
pub block_interval_secs: u64,
|
||||
pub terminal_total_difficulty: u64,
|
||||
pub terminal_block_number: u64,
|
||||
pub latest_merge_block: Option<u64>,
|
||||
}
|
||||
|
||||
impl ExecutionBlockGenerator {
|
||||
pub fn new(terminal_total_difficulty: u64, terminal_block_number: u64) -> Self {
|
||||
Self {
|
||||
seconds_since_genesis: 0,
|
||||
block_interval_secs: 1,
|
||||
terminal_total_difficulty,
|
||||
terminal_block_number,
|
||||
latest_merge_block: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_seconds_since_genesis(&mut self, inc: u64) {
|
||||
self.seconds_since_genesis += inc;
|
||||
}
|
||||
|
||||
fn block_number_at(&self, unix_seconds: u64) -> u64 {
|
||||
unix_seconds
|
||||
.checked_div(self.block_interval_secs)
|
||||
.expect("block interval cannot be zero")
|
||||
}
|
||||
|
||||
fn total_difficulty_for_block(&self, number: u64) -> u64 {
|
||||
if number >= self.terminal_block_number {
|
||||
self.terminal_total_difficulty
|
||||
} else {
|
||||
let increment = self
|
||||
.terminal_total_difficulty
|
||||
.checked_div(self.terminal_block_number)
|
||||
.expect("terminal block number must be non-zero");
|
||||
increment
|
||||
.checked_mul(number)
|
||||
.expect("overflow computing total difficulty")
|
||||
}
|
||||
}
|
||||
|
||||
fn latest_block_number(&self) -> u64 {
|
||||
let time_based = self.block_number_at(self.seconds_since_genesis);
|
||||
|
||||
if time_based < self.terminal_block_number {
|
||||
time_based
|
||||
} else {
|
||||
self.latest_merge_block
|
||||
.unwrap_or(self.terminal_block_number)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn latest_block(&self) -> Option<ExecutionBlock> {
|
||||
self.block_by_number(self.latest_block_number())
|
||||
}
|
||||
|
||||
pub fn block_by_number(&self, number: u64) -> Option<ExecutionBlock> {
|
||||
let parent_hash = number
|
||||
.checked_sub(1)
|
||||
.map(block_number_to_block_hash)
|
||||
.unwrap_or_else(Hash256::zero);
|
||||
let block_hash = block_number_to_block_hash(number);
|
||||
|
||||
if number <= self.terminal_block_number {
|
||||
if number <= self.latest_block_number() {
|
||||
Some(ExecutionBlock {
|
||||
block_hash,
|
||||
parent_hash,
|
||||
total_difficulty: Uint256::from(self.total_difficulty_for_block(number)),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let latest_block = self
|
||||
.latest_merge_block
|
||||
.unwrap_or(self.terminal_block_number);
|
||||
|
||||
if number <= latest_block {
|
||||
Some(ExecutionBlock {
|
||||
block_hash,
|
||||
parent_hash,
|
||||
total_difficulty: Uint256::from(self.terminal_total_difficulty),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_by_hash(&self, hash: Hash256) -> Option<ExecutionBlock> {
|
||||
let block_number = block_hash_to_block_number(hash);
|
||||
self.block_by_number(block_number)
|
||||
}
|
||||
}
|
||||
|
||||
fn block_number_to_block_hash(n: u64) -> Hash256 {
|
||||
Hash256::from_low_u64_be(n + 1)
|
||||
}
|
||||
|
||||
fn block_hash_to_block_number(hash: Hash256) -> u64 {
|
||||
hash.to_low_u64_be()
|
||||
.checked_sub(1)
|
||||
.expect("do not query for zero hash")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple() {
|
||||
const TERMINAL_DIFFICULTY: u64 = 10;
|
||||
const TERMINAL_BLOCK: u64 = 10;
|
||||
const DIFFICULTY_INCREMENT: u64 = 1;
|
||||
|
||||
let mut generator = ExecutionBlockGenerator::new(TERMINAL_DIFFICULTY, TERMINAL_BLOCK);
|
||||
|
||||
for mut i in 0..(TERMINAL_BLOCK + 5) {
|
||||
i = std::cmp::min(i, TERMINAL_BLOCK);
|
||||
|
||||
/*
|
||||
* Generate a block, inspect it.
|
||||
*/
|
||||
|
||||
let block = generator.latest_block().unwrap();
|
||||
assert_eq!(block.block_hash, block_number_to_block_hash(i));
|
||||
assert_eq!(block_hash_to_block_number(block.block_hash), i);
|
||||
|
||||
let expected_parent = i
|
||||
.checked_sub(1)
|
||||
.map(block_number_to_block_hash)
|
||||
.unwrap_or_else(Hash256::zero);
|
||||
assert_eq!(block.parent_hash, expected_parent);
|
||||
|
||||
assert_eq!(block.total_difficulty, (i * DIFFICULTY_INCREMENT).into());
|
||||
|
||||
assert_eq!(generator.block_by_hash(block.block_hash).unwrap(), block);
|
||||
assert_eq!(generator.block_by_number(i).unwrap(), block);
|
||||
|
||||
/*
|
||||
* Check the parent is accessible.
|
||||
*/
|
||||
|
||||
if let Some(prev_i) = i.checked_sub(1) {
|
||||
assert_eq!(
|
||||
generator.block_by_number(prev_i).unwrap(),
|
||||
generator.block_by_hash(block.parent_hash).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the next block is inaccessible.
|
||||
*/
|
||||
|
||||
let next_i = i + 1;
|
||||
dbg!(next_i);
|
||||
assert!(generator.block_by_number(next_i).is_none());
|
||||
assert!(generator
|
||||
.block_by_hash(block_number_to_block_hash(next_i))
|
||||
.is_none());
|
||||
|
||||
generator.increment_seconds_since_genesis(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use bytes::Bytes;
|
||||
use environment::null_logger;
|
||||
use execution_block_generator::ExecutionBlockGenerator;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slog::{info, Logger};
|
||||
use std::future::Future;
|
||||
@@ -10,6 +11,11 @@ use tokio::sync::{oneshot, RwLock};
|
||||
use types::EthSpec;
|
||||
use warp::Filter;
|
||||
|
||||
const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||
const DEFAULT_TERMINAL_BLOCK: u64 = 64;
|
||||
|
||||
mod execution_block_generator;
|
||||
|
||||
pub struct MockServer {
|
||||
_shutdown_tx: oneshot::Sender<()>,
|
||||
listen_socket_addr: SocketAddr,
|
||||
@@ -19,11 +25,14 @@ pub struct MockServer {
|
||||
impl MockServer {
|
||||
pub fn unit_testing<T: EthSpec>() -> Self {
|
||||
let last_echo_request = Arc::new(RwLock::new(None));
|
||||
let execution_block_generator =
|
||||
ExecutionBlockGenerator::new(DEFAULT_TERMINAL_DIFFICULTY, DEFAULT_TERMINAL_BLOCK);
|
||||
|
||||
let ctx: Arc<Context<T>> = Arc::new(Context {
|
||||
config: <_>::default(),
|
||||
log: null_logger().unwrap(),
|
||||
last_echo_request: last_echo_request.clone(),
|
||||
execution_block_generator: Arc::new(RwLock::new(execution_block_generator)),
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
|
||||
@@ -87,6 +96,7 @@ pub struct Context<T> {
|
||||
pub config: Config,
|
||||
pub log: Logger,
|
||||
pub last_echo_request: Arc<RwLock<Option<Bytes>>>,
|
||||
pub execution_block_generator: Arc<RwLock<ExecutionBlockGenerator>>,
|
||||
pub _phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user