mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 00:42:42 +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 bytes::Bytes;
|
||||||
use environment::null_logger;
|
use environment::null_logger;
|
||||||
|
use execution_block_generator::ExecutionBlockGenerator;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use slog::{info, Logger};
|
use slog::{info, Logger};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
@@ -10,6 +11,11 @@ use tokio::sync::{oneshot, RwLock};
|
|||||||
use types::EthSpec;
|
use types::EthSpec;
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
|
const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||||
|
const DEFAULT_TERMINAL_BLOCK: u64 = 64;
|
||||||
|
|
||||||
|
mod execution_block_generator;
|
||||||
|
|
||||||
pub struct MockServer {
|
pub struct MockServer {
|
||||||
_shutdown_tx: oneshot::Sender<()>,
|
_shutdown_tx: oneshot::Sender<()>,
|
||||||
listen_socket_addr: SocketAddr,
|
listen_socket_addr: SocketAddr,
|
||||||
@@ -19,11 +25,14 @@ pub struct MockServer {
|
|||||||
impl MockServer {
|
impl MockServer {
|
||||||
pub fn unit_testing<T: EthSpec>() -> Self {
|
pub fn unit_testing<T: EthSpec>() -> Self {
|
||||||
let last_echo_request = Arc::new(RwLock::new(None));
|
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 {
|
let ctx: Arc<Context<T>> = Arc::new(Context {
|
||||||
config: <_>::default(),
|
config: <_>::default(),
|
||||||
log: null_logger().unwrap(),
|
log: null_logger().unwrap(),
|
||||||
last_echo_request: last_echo_request.clone(),
|
last_echo_request: last_echo_request.clone(),
|
||||||
|
execution_block_generator: Arc::new(RwLock::new(execution_block_generator)),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -87,6 +96,7 @@ pub struct Context<T> {
|
|||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub log: Logger,
|
pub log: Logger,
|
||||||
pub last_echo_request: Arc<RwLock<Option<Bytes>>>,
|
pub last_echo_request: Arc<RwLock<Option<Bytes>>>,
|
||||||
|
pub execution_block_generator: Arc<RwLock<ExecutionBlockGenerator>>,
|
||||||
pub _phantom: PhantomData<T>,
|
pub _phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user