diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 72400bd53..5409d3728 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -1,10 +1,10 @@ use crate::checkpoint::CheckPoint; use crate::errors::{BeaconChainError as Error, BlockProductionError}; +use crate::eth1_chain::{Eth1Chain, Eth1ChainBackend}; use crate::fork_choice::{Error as ForkChoiceError, ForkChoice}; use crate::iter::{ReverseBlockRootIterator, ReverseStateRootIterator}; use crate::metrics; use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY}; -use eth2_hashing::hash; use lmd_ghost::LmdGhost; use operation_pool::DepositInsertStatus; use operation_pool::{OperationPool, PersistedOperationPool}; @@ -113,6 +113,7 @@ pub trait BeaconChainTypes: Send + Sync + 'static { type Store: store::Store; type SlotClock: slot_clock::SlotClock; type LmdGhost: LmdGhost; + type Eth1Chain: Eth1ChainBackend; type EthSpec: types::EthSpec; } @@ -127,6 +128,8 @@ pub struct BeaconChain { /// Stores all operations (e.g., `Attestation`, `Deposit`, etc) that are candidates for /// inclusion in a block. pub op_pool: OperationPool, + /// Provides information from the Ethereum 1 (PoW) chain. + pub eth1_chain: Eth1Chain, /// Stores a "snapshot" of the chain at the time the head-of-the-chain block was received. canonical_head: RwLock>, /// The root of the genesis block. @@ -142,6 +145,7 @@ impl BeaconChain { /// Instantiate a new Beacon Chain, from genesis. pub fn from_genesis( store: Arc, + eth1_backend: T::Eth1Chain, mut genesis_state: BeaconState, mut genesis_block: BeaconBlock, spec: ChainSpec, @@ -186,6 +190,7 @@ impl BeaconChain { spec, slot_clock, op_pool: OperationPool::new(), + eth1_chain: Eth1Chain::new(eth1_backend), canonical_head, genesis_block_root, fork_choice: ForkChoice::new(store.clone(), &genesis_block, genesis_block_root), @@ -197,6 +202,7 @@ impl BeaconChain { /// Attempt to load an existing instance from the given `store`. pub fn from_store( store: Arc, + eth1_backend: T::Eth1Chain, spec: ChainSpec, log: Logger, ) -> Result>, Error> { @@ -233,6 +239,7 @@ impl BeaconChain { slot_clock, fork_choice: ForkChoice::new(store.clone(), last_finalized_block, last_finalized_root), op_pool, + eth1_chain: Eth1Chain::new(eth1_backend), canonical_head: RwLock::new(p.canonical_head), genesis_block_root: p.genesis_block_root, store, @@ -1205,12 +1212,12 @@ impl BeaconChain { body: BeaconBlockBody { randao_reveal, // TODO: replace with real data. - eth1_data: Self::eth1_data_stub(&state), + eth1_data: self.eth1_chain.eth1_data_for_block_production(&state)?, graffiti, proposer_slashings: proposer_slashings.into(), attester_slashings: attester_slashings.into(), attestations: self.op_pool.get_attestations(&state, &self.spec).into(), - deposits: self.op_pool.get_deposits(&state).into(), + deposits: self.eth1_chain.deposits_for_block_inclusion(&state)?.into(), voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec).into(), transfers: self.op_pool.get_transfers(&state, &self.spec).into(), }, @@ -1234,22 +1241,6 @@ impl BeaconChain { Ok((block, state)) } - fn eth1_data_stub(state: &BeaconState) -> Eth1Data { - let current_epoch = state.current_epoch(); - let slots_per_voting_period = T::EthSpec::slots_per_eth1_voting_period() as u64; - let current_voting_period: u64 = current_epoch.as_u64() / slots_per_voting_period; - - // TODO: confirm that `int_to_bytes32` is correct. - let deposit_root = hash(&int_to_bytes32(current_voting_period)); - let block_hash = hash(&deposit_root); - - Eth1Data { - deposit_root: Hash256::from_slice(&deposit_root), - deposit_count: state.eth1_deposit_index, - block_hash: Hash256::from_slice(&block_hash), - } - } - /// Execute the fork choice algorithm and enthrone the result as the canonical head. pub fn fork_choice(&self) -> Result<(), Error> { metrics::inc_counter(&metrics::FORK_CHOICE_REQUESTS); @@ -1445,13 +1436,6 @@ impl BeaconChain { } } -/// Returns `int` as little-endian bytes with a length of 32. -fn int_to_bytes32(int: u64) -> Vec { - let mut vec = int.to_le_bytes().to_vec(); - vec.resize(32, 0); - vec -} - impl From for Error { fn from(e: DBError) -> Error { Error::DBError(e) diff --git a/beacon_node/beacon_chain/src/beacon_chain_builder.rs b/beacon_node/beacon_chain/src/beacon_chain_builder.rs index 37039dce0..f03cbcc96 100644 --- a/beacon_node/beacon_chain/src/beacon_chain_builder.rs +++ b/beacon_node/beacon_chain/src/beacon_chain_builder.rs @@ -127,16 +127,23 @@ impl BeaconChainBuilder { } } - pub fn build(self, store: Arc) -> Result, String> { + pub fn build( + self, + store: Arc, + eth1_backend: T::Eth1Chain, + ) -> Result, String> { Ok(match self.build_strategy { - BuildStrategy::LoadFromStore => BeaconChain::from_store(store, self.spec, self.log) - .map_err(|e| format!("Error loading BeaconChain from database: {:?}", e))? - .ok_or_else(|| format!("Unable to find exising BeaconChain in database."))?, + BuildStrategy::LoadFromStore => { + BeaconChain::from_store(store, eth1_backend, self.spec, self.log) + .map_err(|e| format!("Error loading BeaconChain from database: {:?}", e))? + .ok_or_else(|| format!("Unable to find exising BeaconChain in database."))? + } BuildStrategy::FromGenesis { genesis_block, genesis_state, } => BeaconChain::from_genesis( store, + eth1_backend, genesis_state.as_ref().clone(), genesis_block.as_ref().clone(), self.spec, diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 5ef68f2cd..58cfed271 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -1,3 +1,4 @@ +use crate::eth1_chain::Error as Eth1ChainError; use crate::fork_choice::Error as ForkChoiceError; use state_processing::per_block_processing::errors::AttestationValidationError; use state_processing::BlockProcessingError; @@ -42,6 +43,7 @@ pub enum BeaconChainError { } easy_from_to!(SlotProcessingError, BeaconChainError); +easy_from_to!(AttestationValidationError, BeaconChainError); #[derive(Debug, PartialEq)] pub enum BlockProductionError { @@ -50,10 +52,11 @@ pub enum BlockProductionError { UnableToProduceAtSlot(Slot), SlotProcessingError(SlotProcessingError), BlockProcessingError(BlockProcessingError), + Eth1ChainError(Eth1ChainError), BeaconStateError(BeaconStateError), } easy_from_to!(BlockProcessingError, BlockProductionError); easy_from_to!(BeaconStateError, BlockProductionError); easy_from_to!(SlotProcessingError, BlockProductionError); -easy_from_to!(AttestationValidationError, BeaconChainError); +easy_from_to!(Eth1ChainError, BlockProductionError); diff --git a/beacon_node/beacon_chain/src/eth1_chain.rs b/beacon_node/beacon_chain/src/eth1_chain.rs index 5f148cd9b..3ea37c21d 100644 --- a/beacon_node/beacon_chain/src/eth1_chain.rs +++ b/beacon_node/beacon_chain/src/eth1_chain.rs @@ -5,6 +5,35 @@ use types::{BeaconState, Deposit, DepositData, Eth1Data, EthSpec, Hash256}; type Result = std::result::Result; +pub struct Eth1Chain { + backend: T::Eth1Chain, +} + +impl Eth1Chain { + pub fn new(backend: T::Eth1Chain) -> Self { + Self { backend } + } + + pub fn eth1_data_for_block_production( + &self, + state: &BeaconState, + ) -> Result { + self.backend.eth1_data(state) + } + + pub fn deposits_for_block_inclusion( + &self, + state: &BeaconState, + ) -> Result> { + let deposits = self.backend.queued_deposits(state)?; + + // TODO: truncate deposits if required. + + Ok(deposits) + } +} + +#[derive(Debug, PartialEq)] pub enum Error { /// Unable to return an Eth1Data for the given epoch. EpochUnavailable, @@ -12,10 +41,10 @@ pub enum Error { BackendError(String), } -pub trait Eth1Chain { +pub trait Eth1ChainBackend { /// Returns the `Eth1Data` that should be included in a block being produced for the given /// `state`. - fn eth1_data_for_epoch(&self, beacon_state: &BeaconState) -> Result; + fn eth1_data(&self, beacon_state: &BeaconState) -> Result; /// Returns all `Deposits` between `state.eth1_deposit_index` and /// `state.eth1_data.deposit_count`. @@ -24,20 +53,19 @@ pub trait Eth1Chain { /// /// It is possible that not all returned `Deposits` can be included in a block. E.g., there may /// be more than `MAX_DEPOSIT_COUNT` or the churn may be too high. - fn queued_deposits(&self, beacon_state: &BeaconState) -> Result>; + fn queued_deposits(&self, beacon_state: &BeaconState) -> Result>; } -pub struct InteropEth1Chain { +pub struct InteropEth1ChainBackend { _phantom: PhantomData, } -impl Eth1Chain for InteropEth1Chain { - fn eth1_data_for_epoch(&self, state: &BeaconState) -> Result { +impl Eth1ChainBackend for InteropEth1ChainBackend { + fn eth1_data(&self, state: &BeaconState) -> Result { let current_epoch = state.current_epoch(); - let slots_per_voting_period = T::EthSpec::slots_per_eth1_voting_period() as u64; + let slots_per_voting_period = T::slots_per_eth1_voting_period() as u64; let current_voting_period: u64 = current_epoch.as_u64() / slots_per_voting_period; - // TODO: confirm that `int_to_bytes32` is correct. let deposit_root = hash(&int_to_bytes32(current_voting_period)); let block_hash = hash(&deposit_root); @@ -48,11 +76,19 @@ impl Eth1Chain for InteropEth1Chain { }) } - fn queued_deposits(&self, beacon_state: &BeaconState) -> Result> { + fn queued_deposits(&self, beacon_state: &BeaconState) -> Result> { Ok(vec![]) } } +impl Default for InteropEth1ChainBackend { + fn default() -> Self { + Self { + _phantom: PhantomData, + } + } +} + /// Returns `int` as little-endian bytes with a length of 32. fn int_to_bytes32(int: u64) -> Vec { let mut vec = int.to_le_bytes().to_vec(); diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 25f8b74eb..7883019d7 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -19,6 +19,7 @@ pub use self::beacon_chain::{ pub use self::checkpoint::CheckPoint; pub use self::errors::{BeaconChainError, BlockProductionError}; pub use beacon_chain_builder::BeaconChainBuilder; +pub use eth1_chain::InteropEth1ChainBackend; pub use lmd_ghost; pub use metrics::scrape_for_metrics; pub use parking_lot; diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 1006fabf5..07d181a53 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1,4 +1,4 @@ -use crate::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome}; +use crate::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome, InteropEth1ChainBackend}; use lmd_ghost::LmdGhost; use rayon::prelude::*; use sloggers::{null::NullLoggerBuilder, Build}; @@ -60,6 +60,7 @@ where type Store = MemoryStore; type SlotClock = TestingSlotClock; type LmdGhost = L; + type Eth1Chain = InteropEth1ChainBackend; type EthSpec = E; } @@ -114,9 +115,15 @@ where let builder = NullLoggerBuilder; let log = builder.build().expect("logger should build"); - let chain = - BeaconChain::from_genesis(store, genesis_state, genesis_block, spec.clone(), log) - .expect("Terminate if beacon chain generation fails"); + let chain = BeaconChain::from_genesis( + store, + InteropEth1ChainBackend::default(), + genesis_state, + genesis_block, + spec.clone(), + log, + ) + .expect("Terminate if beacon chain generation fails"); Self { chain,