Add attester to beacon chain test harness

This commit is contained in:
Paul Hauner 2019-01-28 15:50:42 +11:00
parent e1698102e0
commit 5bbffcb053
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
24 changed files with 311 additions and 166 deletions

View File

@ -9,12 +9,14 @@ pub struct AttestationAggregator {
store: HashMap<Vec<u8>, Attestation>, store: HashMap<Vec<u8>, Attestation>,
} }
#[derive(Debug, PartialEq)]
pub enum ProcessOutcome { pub enum ProcessOutcome {
AggregationNotRequired, AggregationNotRequired,
Aggregated, Aggregated,
NewAttestationCreated, NewAttestationCreated,
} }
#[derive(Debug, PartialEq)]
pub enum ProcessError { pub enum ProcessError {
BadValidatorIndex, BadValidatorIndex,
BadSignature, BadSignature,

View File

@ -0,0 +1,47 @@
use super::{BeaconChain, ClientDB, SlotClock};
pub use crate::attestation_aggregator::{ProcessError as AggregatorError, ProcessOutcome};
use crate::canonical_head::Error as HeadError;
use types::{AttestationData, Signature};
#[derive(Debug, PartialEq)]
pub enum Error {
PresentSlotUnknown,
AggregatorError(AggregatorError),
HeadError(HeadError),
}
impl<T, U> BeaconChain<T, U>
where
T: ClientDB,
U: SlotClock,
{
pub fn process_free_attestation(
&self,
attestation_data: &AttestationData,
signature: &Signature,
validator_index: u64,
) -> Result<ProcessOutcome, Error> {
let present_slot = self
.present_slot()
.ok_or_else(|| Error::PresentSlotUnknown)?;
let state = self.state(present_slot)?;
self.attestation_aggregator
.write()
.expect("Aggregator unlock failed.")
.process_free_attestation(&state, attestation_data, signature, validator_index)
.map_err(|e| e.into())
}
}
impl From<AggregatorError> for Error {
fn from(e: AggregatorError) -> Error {
Error::AggregatorError(e)
}
}
impl From<HeadError> for Error {
fn from(e: HeadError) -> Error {
Error::HeadError(e)
}
}

View File

@ -3,11 +3,6 @@ use types::{AttestationData, Hash256};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
/*
DBError(String),
StateTransitionError(TransitionError),
PresentSlotIsNone,
*/
SlotTooOld, SlotTooOld,
PresentSlotUnknown, PresentSlotUnknown,
StateError, StateError,

View File

@ -2,6 +2,7 @@ use crate::{BeaconChain, CheckPoint, ClientDB, SlotClock};
use std::sync::RwLockReadGuard; use std::sync::RwLockReadGuard;
use types::{beacon_state::SlotProcessingError, BeaconBlock, BeaconState, Hash256}; use types::{beacon_state::SlotProcessingError, BeaconBlock, BeaconState, Hash256};
#[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
PastSlot, PastSlot,
UnableToDetermineProducer, UnableToDetermineProducer,

View File

@ -52,4 +52,11 @@ where
.beacon_block .beacon_block
.slot .slot
} }
pub fn validator_attestion_slot_and_shard(&self, validator_index: usize) -> Option<(u64, u64)> {
let present_slot = self.present_slot()?;
let state = self.state(present_slot).ok()?;
Some(state.attestation_slot_and_shard_for_validator(validator_index, &self.spec))
}
} }

View File

@ -1,4 +1,5 @@
mod attestation_aggregation; mod attestation_aggregator;
pub mod attestation_processing;
mod attestation_production; mod attestation_production;
mod attestation_targets; mod attestation_targets;
mod block_graph; mod block_graph;
@ -14,7 +15,7 @@ mod state_transition;
use self::attestation_targets::AttestationTargets; use self::attestation_targets::AttestationTargets;
use self::block_graph::BlockGraph; use self::block_graph::BlockGraph;
use attestation_aggregation::AttestationAggregator; use attestation_aggregator::AttestationAggregator;
use db::{ use db::{
stores::{BeaconBlockStore, BeaconStateStore}, stores::{BeaconBlockStore, BeaconStateStore},
ClientDB, DBError, ClientDB, DBError,

View File

@ -12,11 +12,13 @@ harness = false
criterion = "0.2" criterion = "0.2"
[dependencies] [dependencies]
attester = { path = "../../../eth2/attester" }
beacon_chain = { path = "../../beacon_chain" } beacon_chain = { path = "../../beacon_chain" }
block_producer = { path = "../../../eth2/block_producer" } block_producer = { path = "../../../eth2/block_producer" }
bls = { path = "../../../eth2/utils/bls" } bls = { path = "../../../eth2/utils/bls" }
boolean-bitfield = { path = "../../../eth2/utils/boolean-bitfield" } boolean-bitfield = { path = "../../../eth2/utils/boolean-bitfield" }
db = { path = "../../db" } db = { path = "../../db" }
parking_lot = "0.7"
failure = "0.1" failure = "0.1"
failure_derive = "0.1" failure_derive = "0.1"
genesis = { path = "../../../eth2/genesis" } genesis = { path = "../../../eth2/genesis" }

View File

@ -1,71 +0,0 @@
use beacon_chain::block_processing::{Error as ProcessingError, Outcome as ProcessingOutcome};
use beacon_chain::{block_production::Error as BlockProductionError, BeaconChain};
use block_producer::{
BeaconNode as BeaconBlockNode, BeaconNodeError as BeaconBlockNodeError, PublishOutcome,
};
use db::ClientDB;
use slot_clock::SlotClock;
use std::sync::Arc;
use types::{BeaconBlock, PublicKey, Signature};
pub struct DirectBeaconNode<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
}
impl<T: ClientDB, U: SlotClock> DirectBeaconNode<T, U> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
Self { beacon_chain }
}
}
impl<T: ClientDB, U: SlotClock> BeaconBlockNode for DirectBeaconNode<T, U>
where
BlockProductionError: From<<U>::Error>,
ProcessingError: From<<U as SlotClock>::Error>,
{
fn proposer_nonce(&self, pubkey: &PublicKey) -> Result<u64, BeaconBlockNodeError> {
let validator_index = self
.beacon_chain
.validator_index(pubkey)
.ok_or_else(|| BeaconBlockNodeError::RemoteFailure("pubkey unknown.".to_string()))?;
self.beacon_chain
.proposer_slots(validator_index)
.ok_or_else(|| {
BeaconBlockNodeError::RemoteFailure("validator_index unknown.".to_string())
})
}
fn produce_beacon_block(
&self,
slot: u64,
randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconBlockNodeError>
where {
let (block, _state) = self
.beacon_chain
.produce_block(randao_reveal.clone())
.map_err(|e| BeaconBlockNodeError::RemoteFailure(format!("{:?}", e)))?;
if block.slot == slot {
Ok(Some(block))
} else {
Err(BeaconBlockNodeError::RemoteFailure(
"Unable to produce at non-current slot.".to_string(),
))
}
}
fn publish_beacon_block(
&self,
block: BeaconBlock,
) -> Result<PublishOutcome, BeaconBlockNodeError> {
match self.beacon_chain.process_block(block) {
Ok(ProcessingOutcome::ValidBlock(_)) => Ok(PublishOutcome::ValidBlock),
Ok(ProcessingOutcome::InvalidBlock(reason)) => {
Ok(PublishOutcome::InvalidBlock(format!("{:?}", reason)))
}
Err(error) => Err(BeaconBlockNodeError::RemoteFailure(format!("{:?}", error))),
}
}
}

View File

@ -1,38 +0,0 @@
use beacon_chain::{block_production::Error as BlockProductionError, BeaconChain};
use block_producer::{DutiesReader, DutiesReaderError};
use db::ClientDB;
use slot_clock::SlotClock;
use std::sync::Arc;
use types::PublicKey;
pub struct DirectDuties<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
pubkey: PublicKey,
}
impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> {
pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
Self {
beacon_chain,
pubkey,
}
}
}
impl<T: ClientDB, U: SlotClock> DutiesReader for DirectDuties<T, U>
where
BlockProductionError: From<<U>::Error>,
{
fn is_block_production_slot(&self, slot: u64) -> Result<bool, DutiesReaderError> {
let validator_index = self
.beacon_chain
.validator_index(&self.pubkey)
.ok_or_else(|| DutiesReaderError::UnknownValidator)?;
match self.beacon_chain.block_proposer(slot) {
Some(proposer) if proposer == validator_index => Ok(true),
Some(_) => Ok(false),
None => Err(DutiesReaderError::UnknownEpoch),
}
}
}

View File

@ -1,11 +1,5 @@
mod beacon_chain_harness; mod harness;
mod benching_beacon_node;
mod direct_beacon_node;
mod direct_duties;
mod validator; mod validator;
pub use self::beacon_chain_harness::BeaconChainHarness; pub use self::harness::BeaconChainHarness;
pub use self::benching_beacon_node::BenchingBeaconNode;
pub use self::direct_beacon_node::DirectBeaconNode;
pub use self::direct_duties::DirectDuties;
pub use self::validator::TestValidator; pub use self::validator::TestValidator;

View File

@ -0,0 +1,40 @@
use super::BenchingBeaconNode;
use attester::{BeaconNode as AttesterBeaconNode, BeaconNodeError as NodeError, PublishOutcome};
use beacon_chain::block_processing::Error as ProcessingError;
use beacon_chain::block_production::Error as BlockProductionError;
use db::ClientDB;
use slot_clock::SlotClock;
use types::{AttestationData, Signature};
impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for BenchingBeaconNode<T, U>
where
BlockProductionError: From<<U>::Error>,
ProcessingError: From<<U as SlotClock>::Error>,
{
fn produce_attestation_data(
&self,
slot: u64,
shard: u64,
) -> Result<Option<AttestationData>, NodeError> {
match self.beacon_chain.produce_attestation_data(slot, shard) {
Ok(attestation_data) => Ok(Some(attestation_data)),
Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))),
}
}
fn publish_attestation_data(
&self,
attestation_data: AttestationData,
signature: Signature,
validator_index: u64,
) -> Result<PublishOutcome, NodeError> {
match self.beacon_chain.process_free_attestation(
&attestation_data,
&signature,
validator_index,
) {
Ok(_) => Ok(PublishOutcome::ValidAttestation),
Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))),
}
}
}

View File

@ -0,0 +1,34 @@
use beacon_chain::BeaconChain;
use db::ClientDB;
use parking_lot::RwLock;
use slot_clock::SlotClock;
use std::sync::Arc;
use types::{AttestationData, BeaconBlock, Signature};
mod attester;
mod producer;
/// An attestation that hasn't been aggregated into an `Attestation`.
///
/// (attestation_data, signature, validator_index)
pub type FreeAttestation = (AttestationData, Signature, u64);
pub struct BenchingBeaconNode<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
published_blocks: RwLock<Vec<BeaconBlock>>,
published_attestations: RwLock<Vec<FreeAttestation>>,
}
impl<T: ClientDB, U: SlotClock> BenchingBeaconNode<T, U> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
Self {
beacon_chain,
published_blocks: RwLock::new(vec![]),
published_attestations: RwLock::new(vec![]),
}
}
pub fn last_published_block(&self) -> Option<BeaconBlock> {
Some(self.published_blocks.read().last()?.clone())
}
}

View File

@ -1,37 +1,13 @@
use super::BenchingBeaconNode;
use beacon_chain::block_processing::Error as ProcessingError; use beacon_chain::block_processing::Error as ProcessingError;
use beacon_chain::{block_production::Error as BlockProductionError, BeaconChain}; use beacon_chain::block_production::Error as BlockProductionError;
use block_producer::{ use block_producer::{
BeaconNode as BeaconBlockNode, BeaconNodeError as BeaconBlockNodeError, PublishOutcome, BeaconNode as BeaconBlockNode, BeaconNodeError as BeaconBlockNodeError, PublishOutcome,
}; };
use db::ClientDB; use db::ClientDB;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::{Arc, RwLock};
use types::{BeaconBlock, PublicKey, Signature}; use types::{BeaconBlock, PublicKey, Signature};
pub struct BenchingBeaconNode<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
published_blocks: RwLock<Vec<BeaconBlock>>,
}
impl<T: ClientDB, U: SlotClock> BenchingBeaconNode<T, U> {
pub fn new(beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
Self {
beacon_chain,
published_blocks: RwLock::new(vec![]),
}
}
pub fn last_published_block(&self) -> Option<BeaconBlock> {
Some(
self.published_blocks
.read()
.expect("Unable to unlock `published_blocks` for reading.")
.last()?
.clone(),
)
}
}
impl<T: ClientDB, U: SlotClock> BeaconBlockNode for BenchingBeaconNode<T, U> impl<T: ClientDB, U: SlotClock> BeaconBlockNode for BenchingBeaconNode<T, U>
where where
BlockProductionError: From<<U>::Error>, BlockProductionError: From<<U>::Error>,
@ -56,8 +32,7 @@ where
&self, &self,
slot: u64, slot: u64,
randao_reveal: &Signature, randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconBlockNodeError> ) -> Result<Option<BeaconBlock>, BeaconBlockNodeError> {
where {
let (block, _state) = self let (block, _state) = self
.beacon_chain .beacon_chain
.produce_block(randao_reveal.clone()) .produce_block(randao_reveal.clone())
@ -81,10 +56,7 @@ where {
&self, &self,
block: BeaconBlock, block: BeaconBlock,
) -> Result<PublishOutcome, BeaconBlockNodeError> { ) -> Result<PublishOutcome, BeaconBlockNodeError> {
self.published_blocks self.published_blocks.write().push(block);
.write()
.expect("Unable to unlock `published_blocks` for writing.")
.push(block);
Ok(PublishOutcome::ValidBlock) Ok(PublishOutcome::ValidBlock)
} }
} }

View File

@ -0,0 +1,70 @@
use attester::{
DutiesReader as AttesterDutiesReader, DutiesReaderError as AttesterDutiesReaderError,
};
use beacon_chain::{block_production::Error as BlockProductionError, BeaconChain};
use block_producer::{
DutiesReader as ProducerDutiesReader, DutiesReaderError as ProducerDutiesReaderError,
};
use db::ClientDB;
use slot_clock::SlotClock;
use std::sync::Arc;
use types::PublicKey;
pub struct DirectDuties<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>,
pubkey: PublicKey,
}
impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> {
pub fn new(pubkey: PublicKey, beacon_chain: Arc<BeaconChain<T, U>>) -> Self {
Self {
beacon_chain,
pubkey,
}
}
}
impl<T: ClientDB, U: SlotClock> ProducerDutiesReader for DirectDuties<T, U>
where
BlockProductionError: From<<U>::Error>,
{
fn is_block_production_slot(&self, slot: u64) -> Result<bool, ProducerDutiesReaderError> {
let validator_index = self
.beacon_chain
.validator_index(&self.pubkey)
.ok_or_else(|| ProducerDutiesReaderError::UnknownValidator)?;
match self.beacon_chain.block_proposer(slot) {
Some(proposer) if proposer == validator_index => Ok(true),
Some(_) => Ok(false),
None => Err(ProducerDutiesReaderError::UnknownEpoch),
}
}
}
impl<T: ClientDB, U: SlotClock> AttesterDutiesReader for DirectDuties<T, U>
where
BlockProductionError: From<<U>::Error>,
{
fn validator_index(&self) -> Option<u64> {
match self.beacon_chain.validator_index(&self.pubkey) {
Some(index) => Some(index as u64),
None => None,
}
}
fn attestation_shard(&self, slot: u64) -> Result<Option<u64>, AttesterDutiesReaderError> {
if let Some(validator_index) = self.validator_index() {
match self
.beacon_chain
.validator_attestion_slot_and_shard(validator_index as usize)
{
Some((attest_slot, attest_shard)) if attest_slot == slot => Ok(Some(attest_shard)),
Some(_) => Ok(None),
None => Err(AttesterDutiesReaderError::UnknownEpoch),
}
} else {
Err(AttesterDutiesReaderError::UnknownValidator)
}
}
}

View File

@ -1,11 +1,18 @@
use super::{BenchingBeaconNode, DirectDuties}; use attester::Attester;
use beacon_chain::BeaconChain; use beacon_chain::BeaconChain;
use block_producer::{test_utils::TestSigner, BlockProducer, Error as PollError}; use block_producer::{BlockProducer, Error as PollError};
use db::MemoryDB; use db::MemoryDB;
use signer::TestSigner;
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Keypair}; use types::{BeaconBlock, ChainSpec, Keypair};
mod beacon_node;
mod direct_duties;
mod signer;
pub use self::beacon_node::BenchingBeaconNode;
pub use self::direct_duties::DirectDuties;
pub use block_producer::PollOutcome; pub use block_producer::PollOutcome;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -21,6 +28,12 @@ pub struct TestValidator {
DirectDuties<MemoryDB, TestingSlotClock>, DirectDuties<MemoryDB, TestingSlotClock>,
TestSigner, TestSigner,
>, >,
pub attester: Attester<
TestingSlotClock,
BenchingBeaconNode<MemoryDB, TestingSlotClock>,
DirectDuties<MemoryDB, TestingSlotClock>,
TestSigner,
>,
pub spec: Arc<ChainSpec>, pub spec: Arc<ChainSpec>,
pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock>>, pub epoch_map: Arc<DirectDuties<MemoryDB, TestingSlotClock>>,
pub keypair: Keypair, pub keypair: Keypair,
@ -49,8 +62,16 @@ impl TestValidator {
signer.clone(), signer.clone(),
); );
let attester = Attester::new(
epoch_map.clone(),
slot_clock.clone(),
beacon_node.clone(),
signer.clone(),
);
Self { Self {
block_producer, block_producer,
attester,
spec, spec,
epoch_map, epoch_map,
keypair, keypair,

View File

@ -0,0 +1,46 @@
use attester::Signer as AttesterSigner;
use block_producer::Signer as BlockProposerSigner;
use std::sync::RwLock;
use types::{Keypair, Signature};
/// A test-only struct used to simulate a Beacon Node.
pub struct TestSigner {
keypair: Keypair,
should_sign: RwLock<bool>,
}
impl TestSigner {
/// Produce a new TestSigner with signing enabled by default.
pub fn new(keypair: Keypair) -> Self {
Self {
keypair,
should_sign: RwLock::new(true),
}
}
/// If set to `false`, the service will refuse to sign all messages. Otherwise, all messages
/// will be signed.
pub fn enable_signing(&self, enabled: bool) {
*self.should_sign.write().unwrap() = enabled;
}
fn bls_sign(&self, message: &[u8]) -> Option<Signature> {
Some(Signature::new(message, &self.keypair.sk))
}
}
impl BlockProposerSigner for TestSigner {
fn sign_block_proposal(&self, message: &[u8]) -> Option<Signature> {
self.bls_sign(message)
}
fn sign_randao_reveal(&self, message: &[u8]) -> Option<Signature> {
self.bls_sign(message)
}
}
impl AttesterSigner for TestSigner {
fn sign_attestation_message(&self, message: &[u8]) -> Option<Signature> {
self.bls_sign(message)
}
}

View File

@ -131,7 +131,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V,
self.store_produce(attestation_data); self.store_produce(attestation_data);
self.signer self.signer
.bls_sign(&attestation_data.signable_message(PHASE_0_CUSTODY_BIT)[..]) .sign_attestation_message(&attestation_data.signable_message(PHASE_0_CUSTODY_BIT)[..])
} }
/// Returns `true` if signing some attestation_data is safe (non-slashable). /// Returns `true` if signing some attestation_data is safe (non-slashable).

View File

@ -25,7 +25,7 @@ impl TestSigner {
} }
impl Signer for TestSigner { impl Signer for TestSigner {
fn bls_sign(&self, message: &[u8]) -> Option<Signature> { fn sign_attestation_message(&self, message: &[u8]) -> Option<Signature> {
Some(Signature::new(message, &self.keypair.sk)) Some(Signature::new(message, &self.keypair.sk))
} }
} }

View File

@ -47,5 +47,5 @@ pub trait DutiesReader: Send + Sync {
/// Signs message using an internally-maintained private key. /// Signs message using an internally-maintained private key.
pub trait Signer { pub trait Signer {
fn bls_sign(&self, message: &[u8]) -> Option<Signature>; fn sign_attestation_message(&self, message: &[u8]) -> Option<Signature>;
} }

View File

@ -4,7 +4,7 @@ mod traits;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use ssz::ssz_encode; use ssz::ssz_encode;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Hash256, ProposalSignedData, PublicKey}; use types::{BeaconBlock, ChainSpec, PublicKey};
pub use self::traits::{ pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
@ -139,7 +139,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
// TODO: add domain, etc to this message. // TODO: add domain, etc to this message.
let message = ssz_encode(&producer_nonce); let message = ssz_encode(&producer_nonce);
match self.signer.bls_sign(&message) { match self.signer.sign_randao_reveal(&message) {
None => return Ok(PollOutcome::SignerRejection(slot)), None => return Ok(PollOutcome::SignerRejection(slot)),
Some(signature) => signature, Some(signature) => signature,
} }
@ -171,7 +171,10 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
fn sign_block(&mut self, mut block: BeaconBlock) -> Option<BeaconBlock> { fn sign_block(&mut self, mut block: BeaconBlock) -> Option<BeaconBlock> {
self.store_produce(&block); self.store_produce(&block);
match self.signer.bls_sign(&block.proposal_root(&self.spec)[..]) { match self
.signer
.sign_block_proposal(&block.proposal_root(&self.spec)[..])
{
None => None, None => None,
Some(signature) => { Some(signature) => {
block.signature = signature; block.signature = signature;

View File

@ -25,7 +25,11 @@ impl TestSigner {
} }
impl Signer for TestSigner { impl Signer for TestSigner {
fn bls_sign(&self, message: &[u8]) -> Option<Signature> { fn sign_block_proposal(&self, message: &[u8]) -> Option<Signature> {
Some(Signature::new(message, &self.keypair.sk))
}
fn sign_randao_reveal(&self, message: &[u8]) -> Option<Signature> {
Some(Signature::new(message, &self.keypair.sk)) Some(Signature::new(message, &self.keypair.sk))
} }
} }

View File

@ -47,5 +47,6 @@ pub trait DutiesReader: Send + Sync {
/// Signs message using an internally-maintained private key. /// Signs message using an internally-maintained private key.
pub trait Signer { pub trait Signer {
fn bls_sign(&self, message: &[u8]) -> Option<Signature>; fn sign_block_proposal(&self, message: &[u8]) -> Option<Signature>;
fn sign_randao_reveal(&self, message: &[u8]) -> Option<Signature>;
} }

View File

@ -38,6 +38,20 @@ impl BeaconState {
let validator_count = self.validator_registry.len(); let validator_count = self.validator_registry.len();
Some((slot as usize) % validator_count) Some((slot as usize) % validator_count)
} }
pub fn attestation_slot_and_shard_for_validator(
&self,
validator_index: usize,
spec: &ChainSpec,
) -> (u64, u64) {
// TODO: this is a stub; implement it properly.
let validator_index = validator_index as u64;
let slot = validator_index % spec.epoch_length;
let shard = validator_index % spec.shard_count;
(slot, shard)
}
} }
fn merkle_root(_input: &[Hash256]) -> Hash256 { fn merkle_root(_input: &[Hash256]) -> Hash256 {