Persist eth1 cache (#760)
* Add intermediate structures for bytes conversion * Expose byte conversion methods from `Eth1Service` * Add eth1 ssz containers * Fix type errors * Load eth1 cache on restart * Fix compile errors * Update Cargo.lock * Add comments and minor formatting * Add test for eth1 cache persistence * Restrict Deposit and Block cache field visibility * Add checks * Fix `SszDepositCache` check * Implement Encode/Decode directly on `BlockCache`
This commit is contained in:
parent
a8da36b913
commit
661ef65de8
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1087,6 +1087,7 @@ dependencies = [
|
|||||||
"eth1_test_rig 0.1.0",
|
"eth1_test_rig 0.1.0",
|
||||||
"eth2_hashing 0.1.1",
|
"eth2_hashing 0.1.1",
|
||||||
"eth2_ssz 0.1.2",
|
"eth2_ssz 0.1.2",
|
||||||
|
"eth2_ssz_derive 0.1.0",
|
||||||
"exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -116,7 +116,7 @@ pub trait BeaconChainTypes: Send + Sync + 'static {
|
|||||||
type StoreMigrator: store::Migrate<Self::Store, Self::EthSpec>;
|
type StoreMigrator: store::Migrate<Self::Store, Self::EthSpec>;
|
||||||
type SlotClock: slot_clock::SlotClock;
|
type SlotClock: slot_clock::SlotClock;
|
||||||
type LmdGhost: LmdGhost<Self::Store, Self::EthSpec>;
|
type LmdGhost: LmdGhost<Self::Store, Self::EthSpec>;
|
||||||
type Eth1Chain: Eth1ChainBackend<Self::EthSpec>;
|
type Eth1Chain: Eth1ChainBackend<Self::EthSpec, Self::Store>;
|
||||||
type EthSpec: types::EthSpec;
|
type EthSpec: types::EthSpec;
|
||||||
type EventHandler: EventHandler<Self::EthSpec>;
|
type EventHandler: EventHandler<Self::EthSpec>;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
|||||||
/// inclusion in a block.
|
/// inclusion in a block.
|
||||||
pub op_pool: OperationPool<T::EthSpec>,
|
pub op_pool: OperationPool<T::EthSpec>,
|
||||||
/// Provides information from the Ethereum 1 (PoW) chain.
|
/// 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.
|
/// 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>>,
|
pub(crate) canonical_head: TimeoutRwLock<CheckPoint<T::EthSpec>>,
|
||||||
/// The root of the genesis block.
|
/// The root of the genesis block.
|
||||||
@ -190,6 +190,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
genesis_block_root: self.genesis_block_root,
|
genesis_block_root: self.genesis_block_root,
|
||||||
ssz_head_tracker: self.head_tracker.to_ssz_container(),
|
ssz_head_tracker: self.head_tracker.to_ssz_container(),
|
||||||
fork_choice: self.fork_choice.as_ssz_container(),
|
fork_choice: self.fork_choice.as_ssz_container(),
|
||||||
|
eth1_cache: self.eth1_chain.as_ref().map(|x| x.as_ssz_container()),
|
||||||
block_root_tree: self.block_root_tree.as_ssz_container(),
|
block_root_tree: self.block_root_tree.as_ssz_container(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ where
|
|||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
|
|||||||
genesis_block_root: Option<Hash256>,
|
genesis_block_root: Option<Hash256>,
|
||||||
op_pool: Option<OperationPool<T::EthSpec>>,
|
op_pool: Option<OperationPool<T::EthSpec>>,
|
||||||
fork_choice: Option<ForkChoice<T>>,
|
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>,
|
event_handler: Option<T::EventHandler>,
|
||||||
slot_clock: Option<T::SlotClock>,
|
slot_clock: Option<T::SlotClock>,
|
||||||
persisted_beacon_chain: Option<PersistedBeaconChain<T>>,
|
persisted_beacon_chain: Option<PersistedBeaconChain<T>>,
|
||||||
@ -114,7 +114,7 @@ where
|
|||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -175,7 +175,7 @@ where
|
|||||||
/// Attempt to load an existing chain from the builder's `Store`.
|
/// Attempt to load an existing chain from the builder's `Store`.
|
||||||
///
|
///
|
||||||
/// May initialize several components; including the op_pool and finalized checkpoints.
|
/// 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
|
let log = self
|
||||||
.log
|
.log
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -226,6 +226,10 @@ where
|
|||||||
HeadTracker::from_ssz_container(&p.ssz_head_tracker)
|
HeadTracker::from_ssz_container(&p.ssz_head_tracker)
|
||||||
.map_err(|e| format!("Failed to decode head tracker for database: {:?}", e))?,
|
.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.block_root_tree = Some(Arc::new(p.block_root_tree.clone().into()));
|
self.block_root_tree = Some(Arc::new(p.block_root_tree.clone().into()));
|
||||||
self.persisted_beacon_chain = Some(p);
|
self.persisted_beacon_chain = Some(p);
|
||||||
|
|
||||||
@ -422,7 +426,7 @@ where
|
|||||||
TStore: Store<TEthSpec> + 'static,
|
TStore: Store<TEthSpec> + 'static,
|
||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -541,7 +545,7 @@ where
|
|||||||
TStore: Store<TEthSpec> + 'static,
|
TStore: Store<TEthSpec> + 'static,
|
||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -583,7 +587,7 @@ where
|
|||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec> + 'static,
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
{
|
{
|
||||||
/// Sets the `BeaconChain` event handler to `NullEventHandler`.
|
/// Sets the `BeaconChain` event handler to `NullEventHandler`.
|
||||||
|
@ -6,6 +6,7 @@ use futures::Future;
|
|||||||
use integer_sqrt::IntegerSquareRoot;
|
use integer_sqrt::IntegerSquareRoot;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use slog::{crit, debug, error, trace, Logger};
|
use slog::{crit, debug, error, trace, Logger};
|
||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
use state_processing::per_block_processing::get_new_eth1_data;
|
use state_processing::per_block_processing::get_new_eth1_data;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::DoubleEndedIterator;
|
use std::iter::DoubleEndedIterator;
|
||||||
@ -48,23 +49,31 @@ pub enum Error {
|
|||||||
UnknownPreviousEth1BlockHash,
|
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`.
|
/// Holds an `Eth1ChainBackend` and serves requests from the `BeaconChain`.
|
||||||
pub struct Eth1Chain<T, E>
|
pub struct Eth1Chain<T, E, S>
|
||||||
where
|
where
|
||||||
T: Eth1ChainBackend<E>,
|
T: Eth1ChainBackend<E, S>,
|
||||||
E: EthSpec,
|
E: EthSpec,
|
||||||
|
S: Store<E>,
|
||||||
{
|
{
|
||||||
backend: T,
|
backend: T,
|
||||||
/// When `true`, the backend will be ignored and dummy data from the 2019 Canada interop method
|
/// When `true`, the backend will be ignored and dummy data from the 2019 Canada interop method
|
||||||
/// will be used instead.
|
/// will be used instead.
|
||||||
pub use_dummy_backend: bool,
|
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
|
where
|
||||||
T: Eth1ChainBackend<E>,
|
T: Eth1ChainBackend<E, S>,
|
||||||
E: EthSpec,
|
E: EthSpec,
|
||||||
|
S: Store<E>,
|
||||||
{
|
{
|
||||||
pub fn new(backend: T) -> Self {
|
pub fn new(backend: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -82,7 +91,8 @@ where
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Eth1Data, Error> {
|
) -> Result<Eth1Data, Error> {
|
||||||
if self.use_dummy_backend {
|
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 {
|
} else {
|
||||||
self.backend.eth1_data(state, spec)
|
self.backend.eth1_data(state, spec)
|
||||||
}
|
}
|
||||||
@ -103,14 +113,41 @@ where
|
|||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Vec<Deposit>, Error> {
|
) -> Result<Vec<Deposit>, Error> {
|
||||||
if self.use_dummy_backend {
|
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 {
|
} else {
|
||||||
self.backend.queued_deposits(state, eth1_data_vote, spec)
|
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
|
/// Returns the `Eth1Data` that should be included in a block being produced for the given
|
||||||
/// `state`.
|
/// `state`.
|
||||||
fn eth1_data(&self, beacon_state: &BeaconState<T>, spec: &ChainSpec)
|
fn eth1_data(&self, beacon_state: &BeaconState<T>, spec: &ChainSpec)
|
||||||
@ -129,6 +166,17 @@ pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
|||||||
eth1_data_vote: &Eth1Data,
|
eth1_data_vote: &Eth1Data,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Vec<Deposit>, Error>;
|
) -> 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.
|
/// Provides a simple, testing-only backend that generates deterministic, meaningless eth1 data.
|
||||||
@ -136,9 +184,9 @@ pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
|||||||
/// Never creates deposits, therefore the validator set is static.
|
/// Never creates deposits, therefore the validator set is static.
|
||||||
///
|
///
|
||||||
/// This was used in the 2019 Canada interop workshops.
|
/// 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.
|
/// Produce some deterministic junk based upon the current epoch.
|
||||||
fn eth1_data(&self, state: &BeaconState<T>, _spec: &ChainSpec) -> Result<Eth1Data, Error> {
|
fn eth1_data(&self, state: &BeaconState<T>, _spec: &ChainSpec) -> Result<Eth1Data, Error> {
|
||||||
let current_epoch = state.current_epoch();
|
let current_epoch = state.current_epoch();
|
||||||
@ -164,9 +212,24 @@ impl<T: EthSpec> Eth1ChainBackend<T> for DummyEth1ChainBackend<T> {
|
|||||||
) -> Result<Vec<Deposit>, Error> {
|
) -> Result<Vec<Deposit>, Error> {
|
||||||
Ok(vec![])
|
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 {
|
fn default() -> Self {
|
||||||
Self(PhantomData)
|
Self(PhantomData)
|
||||||
}
|
}
|
||||||
@ -214,7 +277,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> {
|
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
|
// Note: we do not return random junk if this function call fails as it would be caused by
|
||||||
// an internal error.
|
// an internal error.
|
||||||
@ -346,6 +409,27 @@ impl<T: EthSpec, S: Store<T>> Eth1ChainBackend<T> for CachingEth1Backend<T, S> {
|
|||||||
.map(|(_deposit_root, deposits)| deposits)
|
.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()`.
|
/// Produces an `Eth1Data` with all fields sourced from `rand::thread_rng()`.
|
||||||
@ -584,7 +668,7 @@ mod test {
|
|||||||
use store::MemoryStore;
|
use store::MemoryStore;
|
||||||
use types::test_utils::{generate_deterministic_keypair, TestingDepositBuilder};
|
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 {
|
let eth1_config = Eth1Config {
|
||||||
..Eth1Config::default()
|
..Eth1Config::default()
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::eth1_chain::SszEth1;
|
||||||
use crate::fork_choice::SszForkChoice;
|
use crate::fork_choice::SszForkChoice;
|
||||||
use crate::head_tracker::SszHeadTracker;
|
use crate::head_tracker::SszHeadTracker;
|
||||||
use crate::{BeaconChainTypes, CheckPoint};
|
use crate::{BeaconChainTypes, CheckPoint};
|
||||||
@ -18,6 +19,7 @@ pub struct PersistedBeaconChain<T: BeaconChainTypes> {
|
|||||||
pub genesis_block_root: Hash256,
|
pub genesis_block_root: Hash256,
|
||||||
pub ssz_head_tracker: SszHeadTracker,
|
pub ssz_head_tracker: SszHeadTracker,
|
||||||
pub fork_choice: SszForkChoice,
|
pub fork_choice: SszForkChoice,
|
||||||
|
pub eth1_cache: Option<SszEth1>,
|
||||||
pub block_root_tree: SszBlockRootTree,
|
pub block_root_tree: SszBlockRootTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use crate::{
|
|||||||
events::NullEventHandler,
|
events::NullEventHandler,
|
||||||
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome,
|
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome,
|
||||||
};
|
};
|
||||||
|
use eth1::Config as Eth1Config;
|
||||||
use genesis::interop_genesis_state;
|
use genesis::interop_genesis_state;
|
||||||
use lmd_ghost::ThreadSafeReducedTree;
|
use lmd_ghost::ThreadSafeReducedTree;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
@ -175,7 +176,7 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
|
|||||||
.custom_spec(spec.clone())
|
.custom_spec(spec.clone())
|
||||||
.store(store.clone())
|
.store(store.clone())
|
||||||
.store_migrator(<BlockingMigrator<_> as Migrate<_, E>>::new(store))
|
.store_migrator(<BlockingMigrator<_> as Migrate<_, E>>::new(store))
|
||||||
.resume_from_db()
|
.resume_from_db(Eth1Config::default())
|
||||||
.expect("should resume beacon chain from db")
|
.expect("should resume beacon chain from db")
|
||||||
.dummy_eth1_backend()
|
.dummy_eth1_backend()
|
||||||
.expect("should build dummy backend")
|
.expect("should build dummy backend")
|
||||||
|
@ -84,7 +84,7 @@ where
|
|||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
||||||
TSlotClock: SlotClock + Clone + 'static,
|
TSlotClock: SlotClock + Clone + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -241,7 +241,10 @@ where
|
|||||||
Box::new(future)
|
Box::new(future)
|
||||||
}
|
}
|
||||||
ClientGenesis::Resume => {
|
ClientGenesis::Resume => {
|
||||||
let future = builder.resume_from_db().into_future().map(|v| (v, None));
|
let future = builder
|
||||||
|
.resume_from_db(config)
|
||||||
|
.into_future()
|
||||||
|
.map(|v| (v, None));
|
||||||
|
|
||||||
Box::new(future)
|
Box::new(future)
|
||||||
}
|
}
|
||||||
@ -401,7 +404,7 @@ where
|
|||||||
TStore: Store<TEthSpec> + 'static,
|
TStore: Store<TEthSpec> + 'static,
|
||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
||||||
TSlotClock: SlotClock + Clone + 'static,
|
TSlotClock: SlotClock + Clone + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -449,7 +452,7 @@ where
|
|||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
{
|
{
|
||||||
/// Specifies that the `BeaconChain` should publish events using the WebSocket server.
|
/// Specifies that the `BeaconChain` should publish events using the WebSocket server.
|
||||||
@ -498,7 +501,7 @@ where
|
|||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TStoreMigrator: store::Migrate<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TLmdGhost: LmdGhost<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, DiskStore<TEthSpec>> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -548,7 +551,7 @@ where
|
|||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TStoreMigrator: store::Migrate<SimpleDiskStore<TEthSpec>, TEthSpec> + 'static,
|
TStoreMigrator: store::Migrate<SimpleDiskStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TLmdGhost: LmdGhost<SimpleDiskStore<TEthSpec>, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<SimpleDiskStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, SimpleDiskStore<TEthSpec>> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -576,7 +579,7 @@ impl<TSlotClock, TLmdGhost, TEth1Backend, TEthSpec, TEventHandler>
|
|||||||
where
|
where
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<MemoryStore<TEthSpec>, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<MemoryStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, MemoryStore<TEthSpec>> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -606,7 +609,7 @@ impl<TSlotClock, TLmdGhost, TEth1Backend, TEthSpec, TEventHandler>
|
|||||||
where
|
where
|
||||||
TSlotClock: SlotClock + 'static,
|
TSlotClock: SlotClock + 'static,
|
||||||
TLmdGhost: LmdGhost<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<DiskStore<TEthSpec>, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, DiskStore<TEthSpec>> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
@ -737,7 +740,7 @@ where
|
|||||||
TStore: Store<TEthSpec> + 'static,
|
TStore: Store<TEthSpec> + 'static,
|
||||||
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
TStoreMigrator: store::Migrate<TStore, TEthSpec>,
|
||||||
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
TLmdGhost: LmdGhost<TStore, TEthSpec> + 'static,
|
||||||
TEth1Backend: Eth1ChainBackend<TEthSpec> + 'static,
|
TEth1Backend: Eth1ChainBackend<TEthSpec, TStore> + 'static,
|
||||||
TEthSpec: EthSpec + 'static,
|
TEthSpec: EthSpec + 'static,
|
||||||
TEventHandler: EventHandler<TEthSpec> + 'static,
|
TEventHandler: EventHandler<TEthSpec> + 'static,
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ hex = "0.3"
|
|||||||
types = { path = "../../eth2/types"}
|
types = { path = "../../eth2/types"}
|
||||||
merkle_proof = { path = "../../eth2/utils/merkle_proof"}
|
merkle_proof = { path = "../../eth2/utils/merkle_proof"}
|
||||||
eth2_ssz = { path = "../../eth2/utils/ssz"}
|
eth2_ssz = { path = "../../eth2/utils/ssz"}
|
||||||
|
eth2_ssz_derive = "0.1.0"
|
||||||
tree_hash = { path = "../../eth2/utils/tree_hash"}
|
tree_hash = { path = "../../eth2/utils/tree_hash"}
|
||||||
eth2_hashing = { path = "../../eth2/utils/eth2_hashing"}
|
eth2_hashing = { path = "../../eth2/utils/eth2_hashing"}
|
||||||
parking_lot = "0.7"
|
parking_lot = "0.7"
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use types::{Eth1Data, Hash256};
|
use types::{Eth1Data, Hash256};
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ pub enum Error {
|
|||||||
/// A block of the eth1 chain.
|
/// A block of the eth1 chain.
|
||||||
///
|
///
|
||||||
/// Contains all information required to add a `BlockCache` entry.
|
/// Contains all information required to add a `BlockCache` entry.
|
||||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
#[derive(Debug, PartialEq, Clone, Eq, Hash, Encode, Decode)]
|
||||||
pub struct Eth1Block {
|
pub struct Eth1Block {
|
||||||
pub hash: Hash256,
|
pub hash: Hash256,
|
||||||
pub timestamp: u64,
|
pub timestamp: u64,
|
||||||
@ -38,7 +39,7 @@ impl Eth1Block {
|
|||||||
|
|
||||||
/// Stores block and deposit contract information and provides queries based upon the block
|
/// Stores block and deposit contract information and provides queries based upon the block
|
||||||
/// timestamp.
|
/// timestamp.
|
||||||
#[derive(Debug, PartialEq, Clone, Default)]
|
#[derive(Debug, PartialEq, Clone, Default, Encode, Decode)]
|
||||||
pub struct BlockCache {
|
pub struct BlockCache {
|
||||||
blocks: Vec<Eth1Block>,
|
blocks: Vec<Eth1Block>,
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::DepositLog;
|
use crate::DepositLog;
|
||||||
use eth2_hashing::hash;
|
use eth2_hashing::hash;
|
||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::{Deposit, Hash256, DEPOSIT_TREE_DEPTH};
|
use types::{Deposit, Hash256, DEPOSIT_TREE_DEPTH};
|
||||||
|
|
||||||
@ -79,6 +80,48 @@ impl DepositDataTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Clone)]
|
||||||
|
pub struct SszDepositCache {
|
||||||
|
logs: Vec<DepositLog>,
|
||||||
|
leaves: Vec<Hash256>,
|
||||||
|
deposit_contract_deploy_block: u64,
|
||||||
|
deposit_roots: Vec<Hash256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SszDepositCache {
|
||||||
|
pub fn from_deposit_cache(cache: &DepositCache) -> Self {
|
||||||
|
Self {
|
||||||
|
logs: cache.logs.clone(),
|
||||||
|
leaves: cache.leaves.clone(),
|
||||||
|
deposit_contract_deploy_block: cache.deposit_contract_deploy_block,
|
||||||
|
deposit_roots: cache.deposit_roots.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_deposit_cache(&self) -> Result<DepositCache, String> {
|
||||||
|
let deposit_tree =
|
||||||
|
DepositDataTree::create(&self.leaves, self.leaves.len(), DEPOSIT_TREE_DEPTH);
|
||||||
|
// Check for invalid SszDepositCache conditions
|
||||||
|
if self.leaves.len() != self.logs.len() {
|
||||||
|
return Err("Invalid SszDepositCache: logs and leaves should have equal length".into());
|
||||||
|
}
|
||||||
|
// `deposit_roots` also includes the zero root
|
||||||
|
if self.leaves.len() + 1 != self.deposit_roots.len() {
|
||||||
|
return Err(
|
||||||
|
"Invalid SszDepositCache: deposit_roots length must be only one more than leaves"
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(DepositCache {
|
||||||
|
logs: self.logs.clone(),
|
||||||
|
leaves: self.leaves.clone(),
|
||||||
|
deposit_contract_deploy_block: self.deposit_contract_deploy_block,
|
||||||
|
deposit_tree,
|
||||||
|
deposit_roots: self.deposit_roots.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Mirrors the merkle tree of deposits in the eth1 deposit contract.
|
/// Mirrors the merkle tree of deposits in the eth1 deposit contract.
|
||||||
///
|
///
|
||||||
/// Provides `Deposit` objects with merkle proofs included.
|
/// Provides `Deposit` objects with merkle proofs included.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::http::Log;
|
use super::http::Log;
|
||||||
use ssz::Decode;
|
use ssz::Decode;
|
||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
use types::{DepositData, Hash256, PublicKeyBytes, SignatureBytes};
|
use types::{DepositData, Hash256, PublicKeyBytes, SignatureBytes};
|
||||||
|
|
||||||
/// The following constants define the layout of bytes in the deposit contract `DepositEvent`. The
|
/// The following constants define the layout of bytes in the deposit contract `DepositEvent`. The
|
||||||
@ -16,7 +17,7 @@ const INDEX_START: usize = SIG_START + 96 + 32;
|
|||||||
const INDEX_LEN: usize = 8;
|
const INDEX_LEN: usize = 8;
|
||||||
|
|
||||||
/// A fully parsed eth1 deposit contract log.
|
/// A fully parsed eth1 deposit contract log.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Encode, Decode)]
|
||||||
pub struct DepositLog {
|
pub struct DepositLog {
|
||||||
pub deposit_data: DepositData,
|
pub deposit_data: DepositData,
|
||||||
/// The block number of the log that included this `DepositData`.
|
/// The block number of the log that included this `DepositData`.
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
use crate::Config;
|
use crate::Config;
|
||||||
use crate::{block_cache::BlockCache, deposit_cache::DepositCache};
|
use crate::{
|
||||||
|
block_cache::BlockCache,
|
||||||
|
deposit_cache::{DepositCache, SszDepositCache},
|
||||||
|
};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use ssz::{Decode, Encode};
|
||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DepositUpdater {
|
pub struct DepositUpdater {
|
||||||
@ -34,4 +39,47 @@ impl Inner {
|
|||||||
self.block_cache.write().truncate(block_cache_truncation);
|
self.block_cache.write().truncate(block_cache_truncation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the eth1 block and deposit cache as bytes.
|
||||||
|
pub fn as_bytes(&self) -> Vec<u8> {
|
||||||
|
let ssz_eth1_cache = SszEth1Cache::from_inner(&self);
|
||||||
|
ssz_eth1_cache.as_ssz_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recover `Inner` given byte representation of eth1 deposit and block caches.
|
||||||
|
pub fn from_bytes(bytes: &[u8], config: Config) -> Result<Self, String> {
|
||||||
|
let ssz_cache = SszEth1Cache::from_ssz_bytes(bytes)
|
||||||
|
.map_err(|e| format!("Ssz decoding error: {:?}", e))?;
|
||||||
|
Ok(ssz_cache.to_inner(config)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Clone)]
|
||||||
|
pub struct SszEth1Cache {
|
||||||
|
block_cache: BlockCache,
|
||||||
|
deposit_cache: SszDepositCache,
|
||||||
|
last_processed_block: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SszEth1Cache {
|
||||||
|
pub fn from_inner(inner: &Inner) -> Self {
|
||||||
|
let deposit_updater = inner.deposit_cache.read();
|
||||||
|
let block_cache = inner.block_cache.read();
|
||||||
|
Self {
|
||||||
|
block_cache: (*block_cache).clone(),
|
||||||
|
deposit_cache: SszDepositCache::from_deposit_cache(&deposit_updater.cache),
|
||||||
|
last_processed_block: deposit_updater.last_processed_block,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_inner(&self, config: Config) -> Result<Inner, String> {
|
||||||
|
Ok(Inner {
|
||||||
|
block_cache: RwLock::new(self.block_cache.clone()),
|
||||||
|
deposit_cache: RwLock::new(DepositUpdater {
|
||||||
|
cache: self.deposit_cache.to_deposit_cache()?,
|
||||||
|
last_processed_block: self.last_processed_block,
|
||||||
|
}),
|
||||||
|
config: RwLock::new(config),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,5 @@ mod service;
|
|||||||
pub use block_cache::{BlockCache, Eth1Block};
|
pub use block_cache::{BlockCache, Eth1Block};
|
||||||
pub use deposit_cache::DepositCache;
|
pub use deposit_cache::DepositCache;
|
||||||
pub use deposit_log::DepositLog;
|
pub use deposit_log::DepositLog;
|
||||||
|
pub use inner::SszEth1Cache;
|
||||||
pub use service::{BlockCacheUpdateOutcome, Config, DepositCacheUpdateOutcome, Error, Service};
|
pub use service::{BlockCacheUpdateOutcome, Config, DepositCacheUpdateOutcome, Error, Service};
|
||||||
|
@ -151,6 +151,20 @@ impl Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return byte representation of deposit and block caches.
|
||||||
|
pub fn as_bytes(&self) -> Vec<u8> {
|
||||||
|
self.inner.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recover the deposit and block caches from encoded bytes.
|
||||||
|
pub fn from_bytes(bytes: &[u8], config: Config, log: Logger) -> Result<Self, String> {
|
||||||
|
let inner = Inner::from_bytes(bytes, config)?;
|
||||||
|
Ok(Self {
|
||||||
|
inner: Arc::new(inner),
|
||||||
|
log,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides access to the block cache.
|
/// Provides access to the block cache.
|
||||||
pub fn blocks(&self) -> &RwLock<BlockCache> {
|
pub fn blocks(&self) -> &RwLock<BlockCache> {
|
||||||
&self.inner.block_cache
|
&self.inner.block_cache
|
||||||
|
@ -803,3 +803,77 @@ mod fast {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod persist {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_persisit_caches() {
|
||||||
|
let mut env = new_env();
|
||||||
|
let log = env.core_context().log;
|
||||||
|
let runtime = env.runtime();
|
||||||
|
|
||||||
|
let eth1 = runtime
|
||||||
|
.block_on(GanacheEth1Instance::new())
|
||||||
|
.expect("should start eth1 environment");
|
||||||
|
let deposit_contract = ð1.deposit_contract;
|
||||||
|
let web3 = eth1.web3();
|
||||||
|
|
||||||
|
let now = get_block_number(runtime, &web3);
|
||||||
|
let config = Config {
|
||||||
|
endpoint: eth1.endpoint(),
|
||||||
|
deposit_contract_address: deposit_contract.address(),
|
||||||
|
deposit_contract_deploy_block: now,
|
||||||
|
lowest_cached_block_number: now,
|
||||||
|
follow_distance: 0,
|
||||||
|
block_cache_truncation: None,
|
||||||
|
..Config::default()
|
||||||
|
};
|
||||||
|
let service = Service::new(config.clone(), log.clone());
|
||||||
|
let n = 10;
|
||||||
|
let deposits: Vec<_> = (0..n).into_iter().map(|_| random_deposit_data()).collect();
|
||||||
|
for deposit in &deposits {
|
||||||
|
deposit_contract
|
||||||
|
.deposit(runtime, deposit.clone())
|
||||||
|
.expect("should perform a deposit");
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime
|
||||||
|
.block_on(service.update_deposit_cache())
|
||||||
|
.expect("should perform update");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
service.deposit_cache_len() >= n,
|
||||||
|
"should have imported n deposits"
|
||||||
|
);
|
||||||
|
|
||||||
|
let deposit_count = service.deposit_cache_len();
|
||||||
|
|
||||||
|
runtime
|
||||||
|
.block_on(service.update_block_cache())
|
||||||
|
.expect("should perform update");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
service.block_cache_len() >= n,
|
||||||
|
"should have imported n eth1 blocks"
|
||||||
|
);
|
||||||
|
|
||||||
|
let block_count = service.block_cache_len();
|
||||||
|
|
||||||
|
let eth1_bytes = service.as_bytes();
|
||||||
|
|
||||||
|
// Drop service and recover from bytes
|
||||||
|
drop(service);
|
||||||
|
|
||||||
|
let recovered_service = Service::from_bytes(ð1_bytes, config, log).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
recovered_service.block_cache_len(),
|
||||||
|
block_count,
|
||||||
|
"Should have equal cached blocks as before recovery"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
recovered_service.deposit_cache_len(),
|
||||||
|
deposit_count,
|
||||||
|
"Should have equal cached deposits as before recovery"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user