mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-18 05:18:30 +00:00
Merge branch 'master' into proto-array
This commit is contained in:
@@ -23,6 +23,7 @@ use state_processing::{
|
||||
per_block_processing, per_slot_processing, BlockProcessingError, BlockSignatureStrategy,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::fs;
|
||||
use std::io::prelude::*;
|
||||
use std::sync::Arc;
|
||||
@@ -114,7 +115,7 @@ pub trait BeaconChainTypes: Send + Sync + 'static {
|
||||
type Store: store::Store<Self::EthSpec>;
|
||||
type StoreMigrator: store::Migrate<Self::Store, Self::EthSpec>;
|
||||
type SlotClock: slot_clock::SlotClock;
|
||||
type Eth1Chain: Eth1ChainBackend<Self::EthSpec>;
|
||||
type Eth1Chain: Eth1ChainBackend<Self::EthSpec, Self::Store>;
|
||||
type EthSpec: types::EthSpec;
|
||||
type EventHandler: EventHandler<Self::EthSpec>;
|
||||
}
|
||||
@@ -133,7 +134,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
||||
/// inclusion in a block.
|
||||
pub op_pool: OperationPool<T::EthSpec>,
|
||||
/// Provides information from the Ethereum 1 (PoW) chain.
|
||||
pub eth1_chain: Option<Eth1Chain<T::Eth1Chain, T::EthSpec>>,
|
||||
pub eth1_chain: Option<Eth1Chain<T::Eth1Chain, T::EthSpec, T::Store>>,
|
||||
/// Stores a "snapshot" of the chain at the time the head-of-the-chain block was received.
|
||||
pub(crate) canonical_head: TimeoutRwLock<CheckPoint<T::EthSpec>>,
|
||||
/// The root of the genesis block.
|
||||
@@ -187,6 +188,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
ssz_head_tracker: self.head_tracker.to_ssz_container(),
|
||||
fork_choice: self.fork_choice.as_ssz_container(),
|
||||
block_root_tree: vec![],
|
||||
eth1_cache: self.eth1_chain.as_ref().map(|x| x.as_ssz_container()),
|
||||
};
|
||||
|
||||
let key = Hash256::from_slice(&BEACON_CHAIN_DB_KEY.as_bytes());
|
||||
@@ -506,65 +508,67 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn state_at_slot(&self, slot: Slot) -> Result<BeaconState<T::EthSpec>, Error> {
|
||||
let head_state = self.head()?.beacon_state;
|
||||
|
||||
if slot == head_state.slot {
|
||||
Ok(head_state)
|
||||
} else if slot > head_state.slot {
|
||||
if slot > head_state.slot + T::EthSpec::slots_per_epoch() {
|
||||
warn!(
|
||||
self.log,
|
||||
"Skipping more than an epoch";
|
||||
"head_slot" => head_state.slot,
|
||||
"request_slot" => slot
|
||||
)
|
||||
}
|
||||
|
||||
let start_slot = head_state.slot;
|
||||
let task_start = Instant::now();
|
||||
let max_task_runtime = Duration::from_millis(self.spec.milliseconds_per_slot);
|
||||
|
||||
let head_state_slot = head_state.slot;
|
||||
let mut state = head_state;
|
||||
while state.slot < slot {
|
||||
// Do not allow and forward state skip that takes longer than the maximum task duration.
|
||||
//
|
||||
// This is a protection against nodes doing too much work when they're not synced
|
||||
// to a chain.
|
||||
if task_start + max_task_runtime < Instant::now() {
|
||||
return Err(Error::StateSkipTooLarge {
|
||||
start_slot,
|
||||
requested_slot: slot,
|
||||
max_task_runtime,
|
||||
});
|
||||
match slot.cmp(&head_state.slot) {
|
||||
Ordering::Equal => Ok(head_state),
|
||||
Ordering::Greater => {
|
||||
if slot > head_state.slot + T::EthSpec::slots_per_epoch() {
|
||||
warn!(
|
||||
self.log,
|
||||
"Skipping more than an epoch";
|
||||
"head_slot" => head_state.slot,
|
||||
"request_slot" => slot
|
||||
)
|
||||
}
|
||||
|
||||
// Note: supplying some `state_root` when it is known would be a cheap and easy
|
||||
// optimization.
|
||||
match per_slot_processing(&mut state, None, &self.spec) {
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
self.log,
|
||||
"Unable to load state at slot";
|
||||
"error" => format!("{:?}", e),
|
||||
"head_slot" => head_state_slot,
|
||||
"requested_slot" => slot
|
||||
);
|
||||
return Err(Error::NoStateForSlot(slot));
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(state)
|
||||
} else {
|
||||
let state_root = self
|
||||
.rev_iter_state_roots()?
|
||||
.take_while(|(_root, current_slot)| *current_slot >= slot)
|
||||
.find(|(_root, current_slot)| *current_slot == slot)
|
||||
.map(|(root, _slot)| root)
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?;
|
||||
let start_slot = head_state.slot;
|
||||
let task_start = Instant::now();
|
||||
let max_task_runtime = Duration::from_millis(self.spec.milliseconds_per_slot);
|
||||
|
||||
Ok(self
|
||||
.get_state_caching(&state_root, Some(slot))?
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?)
|
||||
let head_state_slot = head_state.slot;
|
||||
let mut state = head_state;
|
||||
while state.slot < slot {
|
||||
// Do not allow and forward state skip that takes longer than the maximum task duration.
|
||||
//
|
||||
// This is a protection against nodes doing too much work when they're not synced
|
||||
// to a chain.
|
||||
if task_start + max_task_runtime < Instant::now() {
|
||||
return Err(Error::StateSkipTooLarge {
|
||||
start_slot,
|
||||
requested_slot: slot,
|
||||
max_task_runtime,
|
||||
});
|
||||
}
|
||||
|
||||
// Note: supplying some `state_root` when it is known would be a cheap and easy
|
||||
// optimization.
|
||||
match per_slot_processing(&mut state, None, &self.spec) {
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
self.log,
|
||||
"Unable to load state at slot";
|
||||
"error" => format!("{:?}", e),
|
||||
"head_slot" => head_state_slot,
|
||||
"requested_slot" => slot
|
||||
);
|
||||
return Err(Error::NoStateForSlot(slot));
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
Ordering::Less => {
|
||||
let state_root = self
|
||||
.rev_iter_state_roots()?
|
||||
.take_while(|(_root, current_slot)| *current_slot >= slot)
|
||||
.find(|(_root, current_slot)| *current_slot == slot)
|
||||
.map(|(root, _slot)| root)
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?;
|
||||
|
||||
Ok(self
|
||||
.get_state_caching(&state_root, Some(slot))?
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,7 +636,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let head_state = &self.head()?.beacon_state;
|
||||
|
||||
let mut state = if epoch(slot) == epoch(head_state.slot) {
|
||||
self.head()?.beacon_state.clone()
|
||||
self.head()?.beacon_state
|
||||
} else {
|
||||
self.state_at_slot(slot)?
|
||||
};
|
||||
@@ -665,7 +669,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let head_state = &self.head()?.beacon_state;
|
||||
|
||||
let mut state = if epoch == as_epoch(head_state.slot) {
|
||||
self.head()?.beacon_state.clone()
|
||||
self.head()?.beacon_state
|
||||
} else {
|
||||
self.state_at_slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))?
|
||||
};
|
||||
@@ -1501,7 +1505,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: self.op_pool.get_attestations(&state, &self.spec).into(),
|
||||
attestations: self
|
||||
.op_pool
|
||||
.get_attestations(&state, &self.spec)
|
||||
.map_err(BlockProductionError::OpPoolError)?
|
||||
.into(),
|
||||
deposits,
|
||||
voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec).into(),
|
||||
},
|
||||
@@ -1729,9 +1737,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let mut dump = vec![];
|
||||
|
||||
let mut last_slot = CheckPoint {
|
||||
beacon_block: self.head()?.beacon_block.clone(),
|
||||
beacon_block: self.head()?.beacon_block,
|
||||
beacon_block_root: self.head()?.beacon_block_root,
|
||||
beacon_state: self.head()?.beacon_state.clone(),
|
||||
beacon_state: self.head()?.beacon_state,
|
||||
beacon_state_root: self.head()?.beacon_state_root,
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ where
|
||||
TStore: Store<TEthSpec> + 'static,
|
||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||
TSlotClock: SlotClock + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||
TEthSpec: EthSpec + 'static,
|
||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||
{
|
||||
@@ -67,7 +67,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
|
||||
genesis_block_root: Option<Hash256>,
|
||||
op_pool: Option<OperationPool<T::EthSpec>>,
|
||||
fork_choice: Option<ForkChoice<T>>,
|
||||
eth1_chain: Option<Eth1Chain<T::Eth1Chain, T::EthSpec>>,
|
||||
eth1_chain: Option<Eth1Chain<T::Eth1Chain, T::EthSpec, T::Store>>,
|
||||
event_handler: Option<T::EventHandler>,
|
||||
slot_clock: Option<T::SlotClock>,
|
||||
persisted_beacon_chain: Option<PersistedBeaconChain<T>>,
|
||||
@@ -84,7 +84,7 @@ where
|
||||
TStore: Store<TEthSpec> + 'static,
|
||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||
TSlotClock: SlotClock + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||
TEthSpec: EthSpec + 'static,
|
||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||
{
|
||||
@@ -144,7 +144,7 @@ where
|
||||
/// Attempt to load an existing chain from the builder's `Store`.
|
||||
///
|
||||
/// May initialize several components; including the op_pool and finalized checkpoints.
|
||||
pub fn resume_from_db(mut self) -> Result<Self, String> {
|
||||
pub fn resume_from_db(mut self, config: Eth1Config) -> Result<Self, String> {
|
||||
let log = self
|
||||
.log
|
||||
.as_ref()
|
||||
@@ -187,6 +187,10 @@ where
|
||||
HeadTracker::from_ssz_container(&p.ssz_head_tracker)
|
||||
.map_err(|e| format!("Failed to decode head tracker for database: {:?}", e))?,
|
||||
);
|
||||
self.eth1_chain = match &p.eth1_cache {
|
||||
Some(cache) => Some(Eth1Chain::from_ssz_container(cache, config, store, log)?),
|
||||
None => None,
|
||||
};
|
||||
self.persisted_beacon_chain = Some(p);
|
||||
|
||||
Ok(self)
|
||||
@@ -358,7 +362,7 @@ where
|
||||
TStore: Store<TEthSpec> + 'static,
|
||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||
TSlotClock: SlotClock + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||
TEthSpec: EthSpec + 'static,
|
||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||
{
|
||||
@@ -460,7 +464,7 @@ impl<TStore, TStoreMigrator, TEth1Backend, TEthSpec, TEventHandler>
|
||||
where
|
||||
TStore: Store<TEthSpec> + 'static,
|
||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||
TEthSpec: EthSpec + 'static,
|
||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||
{
|
||||
@@ -500,7 +504,7 @@ where
|
||||
TStore: Store<TEthSpec> + 'static,
|
||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||
TSlotClock: SlotClock + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
||||
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||
TEthSpec: EthSpec + 'static,
|
||||
{
|
||||
/// Sets the `BeaconChain` event handler to `NullEventHandler`.
|
||||
@@ -539,7 +543,7 @@ mod test {
|
||||
#[test]
|
||||
fn recent_genesis() {
|
||||
let validator_count = 8;
|
||||
let genesis_time = 13371337;
|
||||
let genesis_time = 13_371_337;
|
||||
|
||||
let log = get_logger();
|
||||
let store = Arc::new(MemoryStore::open());
|
||||
@@ -554,7 +558,7 @@ mod test {
|
||||
|
||||
let chain = BeaconChainBuilder::new(MinimalEthSpec)
|
||||
.logger(log.clone())
|
||||
.store(store.clone())
|
||||
.store(store)
|
||||
.store_migrator(NullMigrator)
|
||||
.genesis_state(genesis_state)
|
||||
.expect("should build state using recent genesis")
|
||||
@@ -575,7 +579,7 @@ mod test {
|
||||
|
||||
assert_eq!(state.slot, Slot::new(0), "should start from genesis");
|
||||
assert_eq!(
|
||||
state.genesis_time, 13371337,
|
||||
state.genesis_time, 13_371_337,
|
||||
"should have the correct genesis time"
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::eth1_chain::Error as Eth1ChainError;
|
||||
use crate::fork_choice::Error as ForkChoiceError;
|
||||
use operation_pool::OpPoolError;
|
||||
use ssz_types::Error as SszTypesError;
|
||||
use state_processing::per_block_processing::errors::AttestationValidationError;
|
||||
use state_processing::BlockProcessingError;
|
||||
@@ -64,6 +65,7 @@ pub enum BlockProductionError {
|
||||
BlockProcessingError(BlockProcessingError),
|
||||
Eth1ChainError(Eth1ChainError),
|
||||
BeaconStateError(BeaconStateError),
|
||||
OpPoolError(OpPoolError),
|
||||
/// The `BeaconChain` was explicitly configured _without_ a connection to eth1, therefore it
|
||||
/// cannot produce blocks.
|
||||
NoEth1ChainConnection,
|
||||
|
||||
@@ -6,7 +6,9 @@ use futures::Future;
|
||||
use integer_sqrt::IntegerSquareRoot;
|
||||
use rand::prelude::*;
|
||||
use slog::{crit, debug, error, trace, Logger};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use state_processing::per_block_processing::get_new_eth1_data;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::DoubleEndedIterator;
|
||||
use std::iter::FromIterator;
|
||||
@@ -48,23 +50,31 @@ pub enum Error {
|
||||
UnknownPreviousEth1BlockHash,
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone)]
|
||||
pub struct SszEth1 {
|
||||
use_dummy_backend: bool,
|
||||
backend_bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Holds an `Eth1ChainBackend` and serves requests from the `BeaconChain`.
|
||||
pub struct Eth1Chain<T, E>
|
||||
pub struct Eth1Chain<T, E, S>
|
||||
where
|
||||
T: Eth1ChainBackend<E>,
|
||||
T: Eth1ChainBackend<E, S>,
|
||||
E: EthSpec,
|
||||
S: Store<E>,
|
||||
{
|
||||
backend: T,
|
||||
/// When `true`, the backend will be ignored and dummy data from the 2019 Canada interop method
|
||||
/// will be used instead.
|
||||
pub use_dummy_backend: bool,
|
||||
_phantom: PhantomData<E>,
|
||||
_phantom: PhantomData<(E, S)>,
|
||||
}
|
||||
|
||||
impl<T, E> Eth1Chain<T, E>
|
||||
impl<T, E, S> Eth1Chain<T, E, S>
|
||||
where
|
||||
T: Eth1ChainBackend<E>,
|
||||
T: Eth1ChainBackend<E, S>,
|
||||
E: EthSpec,
|
||||
S: Store<E>,
|
||||
{
|
||||
pub fn new(backend: T) -> Self {
|
||||
Self {
|
||||
@@ -82,7 +92,8 @@ where
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Eth1Data, Error> {
|
||||
if self.use_dummy_backend {
|
||||
DummyEth1ChainBackend::default().eth1_data(state, spec)
|
||||
let dummy_backend: DummyEth1ChainBackend<E, S> = DummyEth1ChainBackend::default();
|
||||
dummy_backend.eth1_data(state, spec)
|
||||
} else {
|
||||
self.backend.eth1_data(state, spec)
|
||||
}
|
||||
@@ -103,14 +114,41 @@ where
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Vec<Deposit>, Error> {
|
||||
if self.use_dummy_backend {
|
||||
DummyEth1ChainBackend::default().queued_deposits(state, eth1_data_vote, spec)
|
||||
let dummy_backend: DummyEth1ChainBackend<E, S> = DummyEth1ChainBackend::default();
|
||||
dummy_backend.queued_deposits(state, eth1_data_vote, spec)
|
||||
} else {
|
||||
self.backend.queued_deposits(state, eth1_data_vote, spec)
|
||||
}
|
||||
}
|
||||
|
||||
/// Instantiate `Eth1Chain` from a persisted `SszEth1`.
|
||||
///
|
||||
/// The `Eth1Chain` will have the same caches as the persisted `SszEth1`.
|
||||
pub fn from_ssz_container(
|
||||
ssz_container: &SszEth1,
|
||||
config: Eth1Config,
|
||||
store: Arc<S>,
|
||||
log: &Logger,
|
||||
) -> Result<Self, String> {
|
||||
let backend =
|
||||
Eth1ChainBackend::from_bytes(&ssz_container.backend_bytes, config, store, log.clone())?;
|
||||
Ok(Self {
|
||||
use_dummy_backend: ssz_container.use_dummy_backend,
|
||||
backend,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a `SszEth1` containing the state of `Eth1Chain`.
|
||||
pub fn as_ssz_container(&self) -> SszEth1 {
|
||||
SszEth1 {
|
||||
use_dummy_backend: self.use_dummy_backend,
|
||||
backend_bytes: self.backend.as_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
||||
pub trait Eth1ChainBackend<T: EthSpec, S: Store<T>>: Sized + Send + Sync {
|
||||
/// Returns the `Eth1Data` that should be included in a block being produced for the given
|
||||
/// `state`.
|
||||
fn eth1_data(&self, beacon_state: &BeaconState<T>, spec: &ChainSpec)
|
||||
@@ -129,6 +167,17 @@ pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
||||
eth1_data_vote: &Eth1Data,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Vec<Deposit>, Error>;
|
||||
|
||||
/// Encode the `Eth1ChainBackend` instance to bytes.
|
||||
fn as_bytes(&self) -> Vec<u8>;
|
||||
|
||||
/// Create a `Eth1ChainBackend` instance given encoded bytes.
|
||||
fn from_bytes(
|
||||
bytes: &[u8],
|
||||
config: Eth1Config,
|
||||
store: Arc<S>,
|
||||
log: Logger,
|
||||
) -> Result<Self, String>;
|
||||
}
|
||||
|
||||
/// Provides a simple, testing-only backend that generates deterministic, meaningless eth1 data.
|
||||
@@ -136,9 +185,9 @@ pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
||||
/// Never creates deposits, therefore the validator set is static.
|
||||
///
|
||||
/// This was used in the 2019 Canada interop workshops.
|
||||
pub struct DummyEth1ChainBackend<T: EthSpec>(PhantomData<T>);
|
||||
pub struct DummyEth1ChainBackend<T: EthSpec, S: Store<T>>(PhantomData<(T, S)>);
|
||||
|
||||
impl<T: EthSpec> Eth1ChainBackend<T> for DummyEth1ChainBackend<T> {
|
||||
impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T, S> for DummyEth1ChainBackend<T, S> {
|
||||
/// Produce some deterministic junk based upon the current epoch.
|
||||
fn eth1_data(&self, state: &BeaconState<T>, _spec: &ChainSpec) -> Result<Eth1Data, Error> {
|
||||
let current_epoch = state.current_epoch();
|
||||
@@ -164,9 +213,24 @@ impl<T: EthSpec> Eth1ChainBackend<T> for DummyEth1ChainBackend<T> {
|
||||
) -> Result<Vec<Deposit>, Error> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
/// Return empty Vec<u8> for dummy backend.
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Create dummy eth1 backend.
|
||||
fn from_bytes(
|
||||
_bytes: &[u8],
|
||||
_config: Eth1Config,
|
||||
_store: Arc<S>,
|
||||
_log: Logger,
|
||||
) -> Result<Self, String> {
|
||||
Ok(Self(PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Default for DummyEth1ChainBackend<T> {
|
||||
impl<T: EthSpec, S: Store<T>> Default for DummyEth1ChainBackend<T, S> {
|
||||
fn default() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
@@ -214,7 +278,7 @@ impl<T: EthSpec, S: Store<T>> CachingEth1Backend<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T> for CachingEth1Backend<T, S> {
|
||||
impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T, S> for CachingEth1Backend<T, S> {
|
||||
fn eth1_data(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Result<Eth1Data, Error> {
|
||||
// Note: we do not return random junk if this function call fails as it would be caused by
|
||||
// an internal error.
|
||||
@@ -280,8 +344,7 @@ impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T> for CachingEth1Backend<T, S> {
|
||||
.iter()
|
||||
.rev()
|
||||
.skip_while(|eth1_block| eth1_block.timestamp > voting_period_start_seconds)
|
||||
.skip(eth1_follow_distance as usize)
|
||||
.next()
|
||||
.nth(eth1_follow_distance as usize)
|
||||
.map(|block| {
|
||||
trace!(
|
||||
self.log,
|
||||
@@ -329,23 +392,44 @@ impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T> for CachingEth1Backend<T, S> {
|
||||
state.eth1_data.deposit_count
|
||||
};
|
||||
|
||||
if deposit_index > deposit_count {
|
||||
Err(Error::DepositIndexTooHigh)
|
||||
} else if deposit_index == deposit_count {
|
||||
Ok(vec![])
|
||||
} else {
|
||||
let next = deposit_index;
|
||||
let last = std::cmp::min(deposit_count, next + T::MaxDeposits::to_u64());
|
||||
match deposit_index.cmp(&deposit_count) {
|
||||
Ordering::Greater => Err(Error::DepositIndexTooHigh),
|
||||
Ordering::Equal => Ok(vec![]),
|
||||
Ordering::Less => {
|
||||
let next = deposit_index;
|
||||
let last = std::cmp::min(deposit_count, next + T::MaxDeposits::to_u64());
|
||||
|
||||
self.core
|
||||
.deposits()
|
||||
.read()
|
||||
.cache
|
||||
.get_deposits(next, last, deposit_count, DEPOSIT_TREE_DEPTH)
|
||||
.map_err(|e| Error::BackendError(format!("Failed to get deposits: {:?}", e)))
|
||||
.map(|(_deposit_root, deposits)| deposits)
|
||||
self.core
|
||||
.deposits()
|
||||
.read()
|
||||
.cache
|
||||
.get_deposits(next, last, deposit_count, DEPOSIT_TREE_DEPTH)
|
||||
.map_err(|e| Error::BackendError(format!("Failed to get deposits: {:?}", e)))
|
||||
.map(|(_deposit_root, deposits)| deposits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return encoded byte representation of the block and deposit caches.
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
self.core.as_bytes()
|
||||
}
|
||||
|
||||
/// Recover the cached backend from encoded bytes.
|
||||
fn from_bytes(
|
||||
bytes: &[u8],
|
||||
config: Eth1Config,
|
||||
store: Arc<S>,
|
||||
log: Logger,
|
||||
) -> Result<Self, String> {
|
||||
let inner = HttpService::from_bytes(bytes, config, log.clone())?;
|
||||
Ok(Self {
|
||||
core: inner,
|
||||
store,
|
||||
log,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces an `Eth1Data` with all fields sourced from `rand::thread_rng()`.
|
||||
@@ -584,7 +668,7 @@ mod test {
|
||||
use store::MemoryStore;
|
||||
use types::test_utils::{generate_deterministic_keypair, TestingDepositBuilder};
|
||||
|
||||
fn get_eth1_chain() -> Eth1Chain<CachingEth1Backend<E, MemoryStore<E>>, E> {
|
||||
fn get_eth1_chain() -> Eth1Chain<CachingEth1Backend<E, MemoryStore<E>>, E, MemoryStore<E>> {
|
||||
let eth1_config = Eth1Config {
|
||||
..Eth1Config::default()
|
||||
};
|
||||
@@ -691,7 +775,7 @@ mod test {
|
||||
|
||||
let deposits_for_inclusion = eth1_chain
|
||||
.deposits_for_block_inclusion(&state, &random_eth1_data(), spec)
|
||||
.expect(&format!("should find deposit for {}", i));
|
||||
.unwrap_or_else(|_| panic!("should find deposit for {}", i));
|
||||
|
||||
let expected_len =
|
||||
std::cmp::min(i - initial_deposit_index, max_deposits as usize);
|
||||
@@ -769,7 +853,7 @@ mod test {
|
||||
state.slot = Slot::new(period * 1_000 + period / 2);
|
||||
|
||||
// Add 50% of the votes so a lookup is required.
|
||||
for _ in 0..period / 2 + 1 {
|
||||
for _ in 0..=period / 2 {
|
||||
state
|
||||
.eth1_data_votes
|
||||
.push(random_eth1_data())
|
||||
@@ -848,7 +932,7 @@ mod test {
|
||||
state.slot = Slot::new(period / 2);
|
||||
|
||||
// Add 50% of the votes so a lookup is required.
|
||||
for _ in 0..period / 2 + 1 {
|
||||
for _ in 0..=period / 2 {
|
||||
state
|
||||
.eth1_data_votes
|
||||
.push(random_eth1_data())
|
||||
@@ -1006,7 +1090,7 @@ mod test {
|
||||
eth1_block.number,
|
||||
*new_eth1_data
|
||||
.get(ð1_block.clone().eth1_data().unwrap())
|
||||
.expect(&format!(
|
||||
.unwrap_or_else(|| panic!(
|
||||
"new_eth1_data should have expected block #{}",
|
||||
eth1_block.number
|
||||
))
|
||||
@@ -1051,8 +1135,8 @@ mod test {
|
||||
|
||||
let votes = collect_valid_votes(
|
||||
&state,
|
||||
HashMap::from_iter(new_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(new_eth1_data.into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.into_iter()),
|
||||
);
|
||||
assert_eq!(
|
||||
votes.len(),
|
||||
@@ -1080,7 +1164,7 @@ mod test {
|
||||
let votes = collect_valid_votes(
|
||||
&state,
|
||||
HashMap::from_iter(new_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.into_iter()),
|
||||
);
|
||||
assert_votes!(
|
||||
votes,
|
||||
@@ -1112,8 +1196,8 @@ mod test {
|
||||
|
||||
let votes = collect_valid_votes(
|
||||
&state,
|
||||
HashMap::from_iter(new_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(new_eth1_data.into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.into_iter()),
|
||||
);
|
||||
assert_votes!(
|
||||
votes,
|
||||
@@ -1146,12 +1230,12 @@ mod test {
|
||||
.expect("should have some eth1 data")
|
||||
.clone();
|
||||
|
||||
state.eth1_data_votes = vec![non_new_eth1_data.0.clone()].into();
|
||||
state.eth1_data_votes = vec![non_new_eth1_data.0].into();
|
||||
|
||||
let votes = collect_valid_votes(
|
||||
&state,
|
||||
HashMap::from_iter(new_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(new_eth1_data.into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.into_iter()),
|
||||
);
|
||||
|
||||
assert_votes!(
|
||||
@@ -1184,8 +1268,8 @@ mod test {
|
||||
|
||||
let votes = collect_valid_votes(
|
||||
&state,
|
||||
HashMap::from_iter(new_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.clone().into_iter()),
|
||||
HashMap::from_iter(new_eth1_data.into_iter()),
|
||||
HashMap::from_iter(all_eth1_data.into_iter()),
|
||||
);
|
||||
|
||||
assert_votes!(
|
||||
|
||||
@@ -59,10 +59,10 @@ impl HeadTracker {
|
||||
let slots_len = ssz_container.slots.len();
|
||||
|
||||
if roots_len != slots_len {
|
||||
return Err(Error::MismatchingLengths {
|
||||
Err(Error::MismatchingLengths {
|
||||
roots_len,
|
||||
slots_len,
|
||||
});
|
||||
})
|
||||
} else {
|
||||
let map = HashMap::from_iter(
|
||||
ssz_container
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::eth1_chain::SszEth1;
|
||||
use crate::fork_choice::SszForkChoice;
|
||||
use crate::head_tracker::SszHeadTracker;
|
||||
use crate::{BeaconChainTypes, CheckPoint};
|
||||
@@ -20,6 +21,7 @@ pub struct PersistedBeaconChain<T: BeaconChainTypes> {
|
||||
pub fork_choice: SszForkChoice,
|
||||
// TODO: remove this.
|
||||
pub block_root_tree: Vec<u8>,
|
||||
pub eth1_cache: Option<SszEth1>,
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> SimpleStoreItem for PersistedBeaconChain<T> {
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
events::NullEventHandler,
|
||||
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome,
|
||||
};
|
||||
use eth1::Config as Eth1Config;
|
||||
use genesis::interop_genesis_state;
|
||||
use rayon::prelude::*;
|
||||
use sloggers::{terminal::TerminalLoggerBuilder, types::Severity, Build};
|
||||
@@ -170,10 +171,10 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
|
||||
|
||||
let chain = BeaconChainBuilder::new(eth_spec_instance)
|
||||
.logger(log.clone())
|
||||
.custom_spec(spec.clone())
|
||||
.custom_spec(spec)
|
||||
.store(store.clone())
|
||||
.store_migrator(<BlockingMigrator<_> as Migrate<_, E>>::new(store))
|
||||
.resume_from_db()
|
||||
.resume_from_db(Eth1Config::default())
|
||||
.expect("should resume beacon chain from db")
|
||||
.dummy_eth1_backend()
|
||||
.expect("should build dummy backend")
|
||||
@@ -233,7 +234,6 @@ where
|
||||
self.chain
|
||||
.state_at_slot(state_slot)
|
||||
.expect("should find state for slot")
|
||||
.clone()
|
||||
};
|
||||
|
||||
// Determine the first slot where a block should be built.
|
||||
|
||||
Reference in New Issue
Block a user