Implement very raw state transition logic
This commit is contained in:
parent
b555916808
commit
1256ba0d01
@ -16,6 +16,7 @@ members = [
|
|||||||
"eth2/validator_shuffling",
|
"eth2/validator_shuffling",
|
||||||
"beacon_node",
|
"beacon_node",
|
||||||
"beacon_node/db",
|
"beacon_node/db",
|
||||||
|
"beacon_node/beacon_chain",
|
||||||
"protos",
|
"protos",
|
||||||
"validator_client",
|
"validator_client",
|
||||||
]
|
]
|
||||||
|
@ -6,6 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bls = { path = "../eth2/utils/bls" }
|
bls = { path = "../eth2/utils/bls" }
|
||||||
|
beacon_chain = { path = "beacon_chain" }
|
||||||
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
|
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
|
||||||
protobuf = "2.0.2"
|
protobuf = "2.0.2"
|
||||||
protos = { path = "../protos" }
|
protos = { path = "../protos" }
|
||||||
|
18
beacon_node/beacon_chain/Cargo.toml
Normal file
18
beacon_node/beacon_chain/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "beacon_chain"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bls = { path = "../../eth2/utils/bls" }
|
||||||
|
boolean-bitfield = { path = "../../eth2/utils/boolean-bitfield" }
|
||||||
|
db = { path = "../db" }
|
||||||
|
failure = "0.1"
|
||||||
|
failure_derive = "0.1"
|
||||||
|
genesis = { path = "../../eth2/genesis" }
|
||||||
|
serde_derive = "1.0"
|
||||||
|
slot_clock = { path = "../../eth2/utils/slot_clock" }
|
||||||
|
spec = { path = "../../eth2/spec" }
|
||||||
|
ssz = { path = "../../eth2/utils/ssz" }
|
||||||
|
types = { path = "../../eth2/types" }
|
136
beacon_node/beacon_chain/src/block_processing.rs
Normal file
136
beacon_node/beacon_chain/src/block_processing.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use super::state_transition::Error as TransitionError;
|
||||||
|
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
||||||
|
use slot_clock::{SystemTimeSlotClockError, TestingSlotClockError};
|
||||||
|
use ssz::{ssz_encode, Encodable};
|
||||||
|
use types::{
|
||||||
|
readers::{BeaconBlockReader, BeaconStateReader},
|
||||||
|
Hash256,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Outcome {
|
||||||
|
FutureSlot,
|
||||||
|
Processed,
|
||||||
|
NewCanonicalBlock,
|
||||||
|
NewReorgBlock,
|
||||||
|
NewForkBlock,
|
||||||
|
StateTransitionFailed(TransitionError),
|
||||||
|
StateRootMismatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
DBError(String),
|
||||||
|
SlotClockError(SystemTimeSlotClockError),
|
||||||
|
|
||||||
|
NotImplemented,
|
||||||
|
PresentSlotIsNone,
|
||||||
|
UnableToDecodeBlock,
|
||||||
|
MissingParentState(Hash256),
|
||||||
|
InvalidParentState(Hash256),
|
||||||
|
MissingBeaconBlock(Hash256),
|
||||||
|
InvalidBeaconBlock(Hash256),
|
||||||
|
MissingParentBlock(Hash256),
|
||||||
|
NoBlockProducer,
|
||||||
|
StateSlotMismatch,
|
||||||
|
BadBlockSignature,
|
||||||
|
BadRandaoSignature,
|
||||||
|
MaxProposerSlashingsExceeded,
|
||||||
|
BadProposerSlashing,
|
||||||
|
MaxAttestationsExceeded,
|
||||||
|
BadAttestation,
|
||||||
|
NoBlockRoot,
|
||||||
|
MaxDepositsExceeded,
|
||||||
|
MaxExitsExceeded,
|
||||||
|
BadExit,
|
||||||
|
BadCustodyReseeds,
|
||||||
|
BadCustodyChallenges,
|
||||||
|
BadCustodyResponses,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> BeaconChain<T, U>
|
||||||
|
where
|
||||||
|
T: ClientDB,
|
||||||
|
U: SlotClock,
|
||||||
|
Error: From<<U as SlotClock>::Error>,
|
||||||
|
{
|
||||||
|
pub fn process_block<V>(&mut self, block: V) -> Result<Outcome, Error>
|
||||||
|
where
|
||||||
|
V: BeaconBlockReader + Encodable + Sized,
|
||||||
|
{
|
||||||
|
let block = block
|
||||||
|
.into_beacon_block()
|
||||||
|
.ok_or(Error::UnableToDecodeBlock)?;
|
||||||
|
let block_root = block.canonical_root();
|
||||||
|
|
||||||
|
let present_slot = self
|
||||||
|
.slot_clock
|
||||||
|
.present_slot()?
|
||||||
|
.ok_or(Error::PresentSlotIsNone)?;
|
||||||
|
|
||||||
|
// Block from future slots (i.e., greater than the present slot) should not be processed.
|
||||||
|
if block.slot() > present_slot {
|
||||||
|
return Ok(Outcome::FutureSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent_block_root = block.parent_root();
|
||||||
|
|
||||||
|
let parent_block = self
|
||||||
|
.block_store
|
||||||
|
.get_reader(&parent_block_root)?
|
||||||
|
.ok_or(Error::MissingParentBlock(parent_block_root))?;
|
||||||
|
|
||||||
|
let parent_state_root = parent_block.parent_root();
|
||||||
|
let parent_state = self
|
||||||
|
.state_store
|
||||||
|
.get_reader(&parent_state_root)?
|
||||||
|
.ok_or(Error::MissingParentState(parent_state_root))?
|
||||||
|
.into_beacon_state()
|
||||||
|
.ok_or(Error::InvalidParentState(parent_state_root))?;
|
||||||
|
|
||||||
|
let state = match self.state_transition(parent_state, &block) {
|
||||||
|
Ok(state) => state,
|
||||||
|
Err(error) => return Ok(Outcome::StateTransitionFailed(error)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let state_root = state.canonical_root();
|
||||||
|
|
||||||
|
if block.state_root != state_root {
|
||||||
|
return Ok(Outcome::StateRootMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the block and state.
|
||||||
|
self.block_store.put(&block_root, &ssz_encode(&block)[..])?;
|
||||||
|
self.state_store.put(&state_root, &ssz_encode(&state)[..])?;
|
||||||
|
|
||||||
|
// Update leaf blocks so the implementation can track the chain heads.
|
||||||
|
if self.leaf_blocks.contains(&block.parent_root()) {
|
||||||
|
self.leaf_blocks.remove(&block.parent_root());
|
||||||
|
}
|
||||||
|
if self.canonical_leaf_block == block.parent_root() {
|
||||||
|
self.canonical_leaf_block = block_root;
|
||||||
|
}
|
||||||
|
self.leaf_blocks.insert(block_root);
|
||||||
|
|
||||||
|
// The block was sucessfully processed.
|
||||||
|
Ok(Outcome::Processed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DBError> for Error {
|
||||||
|
fn from(e: DBError) -> Error {
|
||||||
|
Error::DBError(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestingSlotClockError> for Error {
|
||||||
|
fn from(_: TestingSlotClockError) -> Error {
|
||||||
|
unreachable!(); // Testing clock never throws an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SystemTimeSlotClockError> for Error {
|
||||||
|
fn from(e: SystemTimeSlotClockError) -> Error {
|
||||||
|
Error::SlotClockError(e)
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
|
use super::state_transition::Error as TransitionError;
|
||||||
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
||||||
|
use bls::Signature;
|
||||||
use slot_clock::TestingSlotClockError;
|
use slot_clock::TestingSlotClockError;
|
||||||
use types::{
|
use types::{
|
||||||
readers::{BeaconBlockReader, BeaconStateReader},
|
readers::{BeaconBlockReader, BeaconStateReader},
|
||||||
BeaconBlock, BeaconState, Hash256,
|
BeaconBlock, BeaconBlockBody, BeaconState, Hash256,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
DBError(String),
|
DBError(String),
|
||||||
|
StateTransitionError(TransitionError),
|
||||||
PresentSlotIsNone,
|
PresentSlotIsNone,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,43 +20,48 @@ where
|
|||||||
U: SlotClock,
|
U: SlotClock,
|
||||||
Error: From<<U as SlotClock>::Error>,
|
Error: From<<U as SlotClock>::Error>,
|
||||||
{
|
{
|
||||||
pub fn produce_block(&mut self) -> Result<(BeaconBlock, BeaconState), Error> {
|
pub fn produce_block(
|
||||||
/*
|
&mut self,
|
||||||
* Important: this code is a big stub and only exists to ensure that tests pass.
|
randao_reveal: Signature,
|
||||||
*
|
) -> Result<(BeaconBlock, BeaconState), Error> {
|
||||||
* https://github.com/sigp/lighthouse/issues/107
|
|
||||||
*/
|
|
||||||
let present_slot = self
|
let present_slot = self
|
||||||
.slot_clock
|
.slot_clock
|
||||||
.present_slot()?
|
.present_slot()?
|
||||||
.ok_or(Error::PresentSlotIsNone)?;
|
.ok_or(Error::PresentSlotIsNone)?;
|
||||||
|
|
||||||
let parent_root = self.canonical_leaf_block;
|
let parent_root = self.canonical_leaf_block;
|
||||||
let parent_block_reader = self
|
let parent_block_reader = self
|
||||||
.block_store
|
.block_store
|
||||||
.get_reader(&parent_root)?
|
.get_reader(&parent_root)?
|
||||||
.ok_or_else(|| Error::DBError("Block not found.".to_string()))?;
|
.ok_or_else(|| Error::DBError("Block not found.".to_string()))?;
|
||||||
let parent_state_reader = self
|
let parent_state = self
|
||||||
.state_store
|
.state_store
|
||||||
.get_reader(&parent_block_reader.state_root())?
|
.get_reader(&parent_block_reader.state_root())?
|
||||||
.ok_or_else(|| Error::DBError("State not found.".to_string()))?;
|
.ok_or_else(|| Error::DBError("State not found.".to_string()))?
|
||||||
|
.into_beacon_state()
|
||||||
|
.ok_or_else(|| Error::DBError("State invalid.".to_string()))?;
|
||||||
|
|
||||||
let parent_block = parent_block_reader
|
|
||||||
.into_beacon_block()
|
|
||||||
.ok_or_else(|| Error::DBError("Bad parent block SSZ.".to_string()))?;
|
|
||||||
let mut block = BeaconBlock {
|
let mut block = BeaconBlock {
|
||||||
slot: present_slot,
|
slot: present_slot,
|
||||||
parent_root,
|
parent_root,
|
||||||
state_root: Hash256::zero(), // Updated after the state is calculated.
|
state_root: Hash256::zero(), // Updated after the state is calculated.
|
||||||
..parent_block
|
randao_reveal: randao_reveal,
|
||||||
|
candidate_pow_receipt_root: Hash256::zero(), // TODO: replace w/ eth1 data.
|
||||||
|
signature: self.spec.empty_signature.clone(), // To be completed by a validator.
|
||||||
|
body: BeaconBlockBody {
|
||||||
|
proposer_slashings: vec![],
|
||||||
|
casper_slashings: vec![],
|
||||||
|
attestations: vec![],
|
||||||
|
custody_reseeds: vec![],
|
||||||
|
custody_challenges: vec![],
|
||||||
|
custody_responses: vec![],
|
||||||
|
deposits: vec![],
|
||||||
|
exits: vec![],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent_state = parent_state_reader
|
let state = self.state_transition(parent_state, &block)?;
|
||||||
.into_beacon_state()
|
|
||||||
.ok_or_else(|| Error::DBError("Bad parent block SSZ.".to_string()))?;
|
|
||||||
let state = BeaconState {
|
|
||||||
slot: present_slot,
|
|
||||||
..parent_state
|
|
||||||
};
|
|
||||||
let state_root = state.canonical_root();
|
let state_root = state.canonical_root();
|
||||||
|
|
||||||
block.state_root = state_root;
|
block.state_root = state_root;
|
||||||
@ -68,6 +76,12 @@ impl From<DBError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TransitionError> for Error {
|
||||||
|
fn from(e: TransitionError) -> Error {
|
||||||
|
Error::StateTransitionError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<TestingSlotClockError> for Error {
|
impl From<TestingSlotClockError> for Error {
|
||||||
fn from(_: TestingSlotClockError) -> Error {
|
fn from(_: TestingSlotClockError) -> Error {
|
||||||
unreachable!(); // Testing clock never throws an error.
|
unreachable!(); // Testing clock never throws an error.
|
@ -1,8 +1,7 @@
|
|||||||
mod block_processing;
|
mod block_processing;
|
||||||
mod block_production;
|
mod block_production;
|
||||||
#[cfg(test)]
|
|
||||||
mod chain_test;
|
|
||||||
mod lmd_ghost;
|
mod lmd_ghost;
|
||||||
|
mod state_transition;
|
||||||
|
|
||||||
use db::{
|
use db::{
|
||||||
stores::{BeaconBlockStore, BeaconStateStore},
|
stores::{BeaconBlockStore, BeaconStateStore},
|
484
beacon_node/beacon_chain/src/state_transition.rs
Normal file
484
beacon_node/beacon_chain/src/state_transition.rs
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
||||||
|
use bls::{AggregatePublicKey, AggregateSignature, PublicKey, Signature};
|
||||||
|
use boolean_bitfield::BooleanBitfield;
|
||||||
|
use slot_clock::{SystemTimeSlotClockError, TestingSlotClockError};
|
||||||
|
use ssz::ssz_encode;
|
||||||
|
use types::{
|
||||||
|
readers::{BeaconBlockReader, BeaconStateReader},
|
||||||
|
AttestationData, AttestationDataAndCustodyBit, BeaconBlock, BeaconState, Exit, ForkData,
|
||||||
|
Hash256, PendingAttestationRecord, ProposalSignedData,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: define elsehwere.
|
||||||
|
const DOMAIN_ATTESTATION: u64 = 1;
|
||||||
|
const DOMAIN_PROPOSAL: u64 = 2;
|
||||||
|
const DOMAIN_EXIT: u64 = 3;
|
||||||
|
const DOMAIN_RANDAO: u64 = 4;
|
||||||
|
|
||||||
|
macro_rules! ensure {
|
||||||
|
($condition: expr, $result: expr) => {
|
||||||
|
if !$condition {
|
||||||
|
return Err($result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
DBError(String),
|
||||||
|
StateAlreadyTransitioned,
|
||||||
|
NotImplemented,
|
||||||
|
PresentSlotIsNone,
|
||||||
|
UnableToDecodeBlock,
|
||||||
|
MissingParentState(Hash256),
|
||||||
|
InvalidParentState(Hash256),
|
||||||
|
MissingBeaconBlock(Hash256),
|
||||||
|
InvalidBeaconBlock(Hash256),
|
||||||
|
MissingParentBlock(Hash256),
|
||||||
|
NoBlockProducer,
|
||||||
|
StateSlotMismatch,
|
||||||
|
BadBlockSignature,
|
||||||
|
BadRandaoSignature,
|
||||||
|
MaxProposerSlashingsExceeded,
|
||||||
|
BadProposerSlashing,
|
||||||
|
MaxAttestationsExceeded,
|
||||||
|
BadAttestation,
|
||||||
|
NoBlockRoot,
|
||||||
|
MaxDepositsExceeded,
|
||||||
|
MaxExitsExceeded,
|
||||||
|
BadExit,
|
||||||
|
BadCustodyReseeds,
|
||||||
|
BadCustodyChallenges,
|
||||||
|
BadCustodyResponses,
|
||||||
|
SlotClockError(SystemTimeSlotClockError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> BeaconChain<T, U>
|
||||||
|
where
|
||||||
|
T: ClientDB,
|
||||||
|
U: SlotClock,
|
||||||
|
{
|
||||||
|
pub fn state_transition(
|
||||||
|
&self,
|
||||||
|
mut state: BeaconState,
|
||||||
|
block: &BeaconBlock,
|
||||||
|
) -> Result<BeaconState, Error> {
|
||||||
|
ensure!(state.slot < block.slot, Error::StateAlreadyTransitioned);
|
||||||
|
|
||||||
|
for _ in state.slot..block.slot {
|
||||||
|
self.per_slot_processing(&mut state, &block.parent_root)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slot
|
||||||
|
*/
|
||||||
|
|
||||||
|
ensure!(block.slot() == state.slot, Error::StateSlotMismatch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proposer Signature
|
||||||
|
*/
|
||||||
|
|
||||||
|
let block_without_signature_root = {
|
||||||
|
let mut block_without_signature = block.clone();
|
||||||
|
block_without_signature.signature = self.spec.empty_signature.clone();
|
||||||
|
block_without_signature.canonical_root()
|
||||||
|
};
|
||||||
|
|
||||||
|
let proposal_root = {
|
||||||
|
let proposal = ProposalSignedData {
|
||||||
|
slot: state.slot,
|
||||||
|
shard: self.spec.beacon_chain_shard_number,
|
||||||
|
block_root: block_without_signature_root,
|
||||||
|
};
|
||||||
|
hash_tree_root(&proposal)
|
||||||
|
};
|
||||||
|
|
||||||
|
let block_proposer_index =
|
||||||
|
get_beacon_proposer_index(&state, block.slot, self.spec.epoch_length)
|
||||||
|
.ok_or(Error::NoBlockProducer)?;
|
||||||
|
let block_proposer = &state.validator_registry[block_proposer_index];
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
bls_verify(
|
||||||
|
&block_proposer.pubkey,
|
||||||
|
&proposal_root,
|
||||||
|
&block.signature,
|
||||||
|
get_domain(&state.fork_data, state.slot, DOMAIN_PROPOSAL)
|
||||||
|
),
|
||||||
|
Error::BadBlockSignature
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RANDAO
|
||||||
|
*/
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
bls_verify(
|
||||||
|
&block_proposer.pubkey,
|
||||||
|
&ssz_encode(&block_proposer.proposer_slots),
|
||||||
|
&block.randao_reveal,
|
||||||
|
get_domain(&state.fork_data, state.slot, DOMAIN_RANDAO)
|
||||||
|
),
|
||||||
|
Error::BadRandaoSignature
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_mix = {
|
||||||
|
let mut mix = state.latest_randao_mixes
|
||||||
|
[(state.slot % self.spec.latest_randao_mixes_length) as usize]
|
||||||
|
.to_vec();
|
||||||
|
mix.append(&mut ssz_encode(&block.randao_reveal));
|
||||||
|
hash(&mix)
|
||||||
|
};
|
||||||
|
|
||||||
|
state.latest_randao_mixes[(state.slot % self.spec.latest_randao_mixes_length) as usize] =
|
||||||
|
new_mix;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Eth1 data
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: Eth1 data stuff.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OPERATIONS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proposer slashings
|
||||||
|
*/
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
block.body.proposer_slashings.len() as u64 <= self.spec.max_proposer_slashings,
|
||||||
|
Error::MaxProposerSlashingsExceeded
|
||||||
|
);
|
||||||
|
for proposer_slashing in &block.body.proposer_slashings {
|
||||||
|
let proposer = state
|
||||||
|
.validator_registry
|
||||||
|
.get(proposer_slashing.proposer_index as usize)
|
||||||
|
.ok_or(Error::BadProposerSlashing)?;
|
||||||
|
ensure!(
|
||||||
|
proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot,
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
proposer_slashing.proposal_data_1.shard == proposer_slashing.proposal_data_2.shard,
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
proposer_slashing.proposal_data_1.block_root
|
||||||
|
!= proposer_slashing.proposal_data_2.block_root,
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
proposer.penalized_slot > state.slot,
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
bls_verify(
|
||||||
|
&proposer.pubkey,
|
||||||
|
&hash_tree_root(&proposer_slashing.proposal_data_1),
|
||||||
|
&proposer_slashing.proposal_signature_1,
|
||||||
|
get_domain(
|
||||||
|
&state.fork_data,
|
||||||
|
proposer_slashing.proposal_data_1.slot,
|
||||||
|
DOMAIN_PROPOSAL
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
bls_verify(
|
||||||
|
&proposer.pubkey,
|
||||||
|
&hash_tree_root(&proposer_slashing.proposal_data_2),
|
||||||
|
&proposer_slashing.proposal_signature_2,
|
||||||
|
get_domain(
|
||||||
|
&state.fork_data,
|
||||||
|
proposer_slashing.proposal_data_2.slot,
|
||||||
|
DOMAIN_PROPOSAL
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
penalize_validator(&state, proposer_slashing.proposer_index as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attestations
|
||||||
|
*/
|
||||||
|
ensure!(
|
||||||
|
block.body.attestations.len() as u64 <= self.spec.max_attestations,
|
||||||
|
Error::MaxAttestationsExceeded
|
||||||
|
);
|
||||||
|
|
||||||
|
for attestation in &block.body.attestations {
|
||||||
|
ensure!(
|
||||||
|
attestation.data.slot + self.spec.min_attestation_inclusion_delay <= state.slot,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
attestation.data.slot + self.spec.epoch_length >= state.slot,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
if state.justified_slot >= state.slot - (state.slot % self.spec.epoch_length) {
|
||||||
|
ensure!(
|
||||||
|
attestation.data.justified_slot == state.justified_slot,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ensure!(
|
||||||
|
attestation.data.justified_slot == state.previous_justified_slot,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ensure!(
|
||||||
|
attestation.data.justified_block_root
|
||||||
|
== *get_block_root(
|
||||||
|
&state,
|
||||||
|
attestation.data.justified_slot,
|
||||||
|
self.spec.latest_block_roots_length
|
||||||
|
)
|
||||||
|
.ok_or(Error::NoBlockRoot)?,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
(attestation.data.latest_crosslink_root
|
||||||
|
== state.latest_crosslinks[attestation.data.shard as usize].shard_block_root)
|
||||||
|
|| (attestation.data.shard_block_root
|
||||||
|
== state.latest_crosslinks[attestation.data.shard as usize]
|
||||||
|
.shard_block_root),
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
let participants = get_attestation_participants(
|
||||||
|
&state,
|
||||||
|
&attestation.data,
|
||||||
|
&attestation.aggregation_bitfield,
|
||||||
|
);
|
||||||
|
let mut group_public_key = AggregatePublicKey::new();
|
||||||
|
for participant in participants {
|
||||||
|
group_public_key.add(
|
||||||
|
state.validator_registry[participant as usize]
|
||||||
|
.pubkey
|
||||||
|
.as_raw(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let attestation_message = {
|
||||||
|
let attestation_data_and_custody_bit = AttestationDataAndCustodyBit {
|
||||||
|
data: attestation.data.clone(),
|
||||||
|
custody_bit: false,
|
||||||
|
};
|
||||||
|
hash_tree_root(&attestation_data_and_custody_bit).to_vec()
|
||||||
|
};
|
||||||
|
// Signature verification.
|
||||||
|
ensure!(
|
||||||
|
bls_verify_aggregate(
|
||||||
|
&group_public_key,
|
||||||
|
&attestation_message[..],
|
||||||
|
&attestation.aggregate_signature,
|
||||||
|
get_domain(&state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION)
|
||||||
|
),
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
attestation.data.shard_block_root == self.spec.zero_hash,
|
||||||
|
Error::BadAttestation
|
||||||
|
);
|
||||||
|
let pending_attestation = PendingAttestationRecord {
|
||||||
|
data: attestation.data.clone(),
|
||||||
|
aggregation_bitfield: attestation.aggregation_bitfield.clone(),
|
||||||
|
custody_bitfield: attestation.custody_bitfield.clone(),
|
||||||
|
slot_included: state.slot,
|
||||||
|
};
|
||||||
|
state.latest_attestations.push(pending_attestation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deposits
|
||||||
|
*/
|
||||||
|
ensure!(
|
||||||
|
block.body.deposits.len() as u64 <= self.spec.max_deposits,
|
||||||
|
Error::MaxDepositsExceeded
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: process deposits.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exits
|
||||||
|
*/
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
block.body.exits.len() as u64 <= self.spec.max_exits,
|
||||||
|
Error::MaxExitsExceeded
|
||||||
|
);
|
||||||
|
|
||||||
|
for exit in &block.body.exits {
|
||||||
|
let validator = state
|
||||||
|
.validator_registry
|
||||||
|
.get(exit.validator_index as usize)
|
||||||
|
.ok_or(Error::BadExit)?;
|
||||||
|
ensure!(
|
||||||
|
validator.exit_slot > state.slot + self.spec.entry_exit_delay,
|
||||||
|
Error::BadExit
|
||||||
|
);
|
||||||
|
ensure!(state.slot >= exit.slot, Error::BadExit);
|
||||||
|
let exit_message = {
|
||||||
|
let exit_struct = Exit {
|
||||||
|
slot: exit.slot,
|
||||||
|
validator_index: exit.validator_index,
|
||||||
|
signature: self.spec.empty_signature.clone(),
|
||||||
|
};
|
||||||
|
hash_tree_root(&exit_struct)
|
||||||
|
};
|
||||||
|
ensure!(
|
||||||
|
bls_verify(
|
||||||
|
&validator.pubkey,
|
||||||
|
&exit_message,
|
||||||
|
&exit.signature,
|
||||||
|
get_domain(&state.fork_data, exit.slot, DOMAIN_EXIT)
|
||||||
|
),
|
||||||
|
Error::BadProposerSlashing
|
||||||
|
);
|
||||||
|
initiate_validator_exit(&state, exit.validator_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custody
|
||||||
|
*/
|
||||||
|
ensure!(
|
||||||
|
block.body.custody_reseeds.is_empty(),
|
||||||
|
Error::BadCustodyReseeds
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
block.body.custody_challenges.is_empty(),
|
||||||
|
Error::BadCustodyChallenges
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
block.body.custody_responses.is_empty(),
|
||||||
|
Error::BadCustodyResponses
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn per_slot_processing(
|
||||||
|
&self,
|
||||||
|
state: &mut BeaconState,
|
||||||
|
previous_block_root: &Hash256,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let epoch_length = self.spec.epoch_length;
|
||||||
|
let latest_randao_mixes_length = self.spec.latest_randao_mixes_length;
|
||||||
|
let latest_block_roots_length = self.spec.latest_block_roots_length;
|
||||||
|
|
||||||
|
// Misc counters.
|
||||||
|
state.slot += 1;
|
||||||
|
let block_proposer = get_beacon_proposer_index(&state, state.slot, epoch_length)
|
||||||
|
.ok_or(Error::NoBlockProducer)?;
|
||||||
|
state.validator_registry[block_proposer].proposer_slots += 1;
|
||||||
|
state.latest_randao_mixes[(state.slot % latest_randao_mixes_length) as usize] =
|
||||||
|
state.latest_randao_mixes[((state.slot - 1) % latest_randao_mixes_length) as usize];
|
||||||
|
|
||||||
|
// Block roots.
|
||||||
|
state.latest_block_roots
|
||||||
|
[((state.slot - 1) % self.spec.latest_block_roots_length) as usize] =
|
||||||
|
*previous_block_root;
|
||||||
|
|
||||||
|
if state.slot % latest_block_roots_length == 0 {
|
||||||
|
let root = merkle_root(&state.latest_block_roots[..]);
|
||||||
|
state.batched_block_roots.push(root);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initiate_validator_exit(_state: &BeaconState, _index: u32) {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_attestation_participants(
|
||||||
|
_state: &BeaconState,
|
||||||
|
_attestation_data: &AttestationData,
|
||||||
|
_aggregation_bitfield: &BooleanBitfield,
|
||||||
|
) -> Vec<usize> {
|
||||||
|
vec![0, 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_block_root(
|
||||||
|
state: &BeaconState,
|
||||||
|
slot: u64,
|
||||||
|
latest_block_roots_length: u64,
|
||||||
|
) -> Option<&Hash256> {
|
||||||
|
// TODO: test
|
||||||
|
if state.slot <= slot + latest_block_roots_length && slot <= state.slot {
|
||||||
|
state
|
||||||
|
.latest_block_roots
|
||||||
|
.get((slot % latest_block_roots_length) as usize)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn penalize_validator(_state: &BeaconState, _proposer_index: usize) {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash<T>(_input: &T) -> Hash256 {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
Hash256::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_domain(_fork: &ForkData, _slot: u64, _domain_type: u64) -> u64 {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bls_verify(_pubkey: &PublicKey, _message: &[u8], _signature: &Signature, _domain: u64) -> bool {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bls_verify_aggregate(
|
||||||
|
_pubkey: &AggregatePublicKey,
|
||||||
|
_message: &[u8],
|
||||||
|
_signature: &AggregateSignature,
|
||||||
|
_domain: u64,
|
||||||
|
) -> bool {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_tree_root<T>(_input: &T) -> Hash256 {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
Hash256::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merkle_root(_input: &[Hash256]) -> Hash256 {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
Hash256::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_beacon_proposer_index(
|
||||||
|
_state: &BeaconState,
|
||||||
|
_slot: u64,
|
||||||
|
_epoch_length: u64,
|
||||||
|
) -> Option<usize> {
|
||||||
|
// TODO: stubbed out.
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DBError> for Error {
|
||||||
|
fn from(e: DBError) -> Error {
|
||||||
|
Error::DBError(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestingSlotClockError> for Error {
|
||||||
|
fn from(_: TestingSlotClockError) -> Error {
|
||||||
|
unreachable!(); // Testing clock never throws an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SystemTimeSlotClockError> for Error {
|
||||||
|
fn from(e: SystemTimeSlotClockError) -> Error {
|
||||||
|
Error::SlotClockError(e)
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use super::{BeaconChain, BlockProcessingOutcome};
|
use beacon_chain::{BeaconChain, BlockProcessingOutcome};
|
||||||
|
use bls::Signature;
|
||||||
use db::{
|
use db::{
|
||||||
stores::{BeaconBlockStore, BeaconStateStore},
|
stores::{BeaconBlockStore, BeaconStateStore},
|
||||||
MemoryDB,
|
MemoryDB,
|
||||||
@ -43,7 +44,7 @@ fn it_produces() {
|
|||||||
fn it_processes_a_block_it_produces() {
|
fn it_processes_a_block_it_produces() {
|
||||||
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||||
let (block, _state) = chain.produce_block().unwrap();
|
let (block, _state) = chain.produce_block().unwrap();
|
||||||
let (outcome, new_block_hash) = chain.process_block(&block).unwrap();
|
let (outcome, new_block_hash) = chain.process_block(block).unwrap();
|
||||||
assert_eq!(outcome, BlockProcessingOutcome::Processed);
|
assert_eq!(outcome, BlockProcessingOutcome::Processed);
|
||||||
assert_eq!(chain.canonical_leaf_block, new_block_hash);
|
assert_eq!(chain.canonical_leaf_block, new_block_hash);
|
||||||
}
|
}
|
@ -1,72 +0,0 @@
|
|||||||
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
|
||||||
use slot_clock::TestingSlotClockError;
|
|
||||||
use ssz::{ssz_encode, Encodable};
|
|
||||||
use types::{readers::BeaconBlockReader, Hash256};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Outcome {
|
|
||||||
FutureSlot,
|
|
||||||
Processed,
|
|
||||||
|
|
||||||
NewCanonicalBlock,
|
|
||||||
NewReorgBlock,
|
|
||||||
NewForkBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
DBError(String),
|
|
||||||
NotImplemented,
|
|
||||||
PresentSlotIsNone,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> BeaconChain<T, U>
|
|
||||||
where
|
|
||||||
T: ClientDB,
|
|
||||||
U: SlotClock,
|
|
||||||
Error: From<<U as SlotClock>::Error>,
|
|
||||||
{
|
|
||||||
pub fn process_block<V>(&mut self, block: &V) -> Result<(Outcome, Hash256), Error>
|
|
||||||
where
|
|
||||||
V: BeaconBlockReader + Encodable + Sized,
|
|
||||||
{
|
|
||||||
let block_root = block.canonical_root();
|
|
||||||
|
|
||||||
let present_slot = self
|
|
||||||
.slot_clock
|
|
||||||
.present_slot()?
|
|
||||||
.ok_or(Error::PresentSlotIsNone)?;
|
|
||||||
|
|
||||||
// Block from future slots (i.e., greater than the present slot) should not be processed.
|
|
||||||
if block.slot() > present_slot {
|
|
||||||
return Ok((Outcome::FutureSlot, block_root));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: block processing has been removed.
|
|
||||||
// https://github.com/sigp/lighthouse/issues/98
|
|
||||||
|
|
||||||
// Update leaf blocks.
|
|
||||||
self.block_store.put(&block_root, &ssz_encode(block)[..])?;
|
|
||||||
if self.leaf_blocks.contains(&block.parent_root()) {
|
|
||||||
self.leaf_blocks.remove(&block.parent_root());
|
|
||||||
}
|
|
||||||
if self.canonical_leaf_block == block.parent_root() {
|
|
||||||
self.canonical_leaf_block = block_root;
|
|
||||||
}
|
|
||||||
self.leaf_blocks.insert(block_root);
|
|
||||||
|
|
||||||
Ok((Outcome::Processed, block_root))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DBError> for Error {
|
|
||||||
fn from(e: DBError) -> Error {
|
|
||||||
Error::DBError(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TestingSlotClockError> for Error {
|
|
||||||
fn from(_: TestingSlotClockError) -> Error {
|
|
||||||
unreachable!(); // Testing clock never throws an error.
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +1,13 @@
|
|||||||
extern crate slog;
|
extern crate slog;
|
||||||
|
|
||||||
mod beacon_chain;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use self::beacon_chain::BeaconChain;
|
|
||||||
use crate::config::LighthouseConfig;
|
use crate::config::LighthouseConfig;
|
||||||
use crate::rpc::start_server;
|
use crate::rpc::start_server;
|
||||||
|
use beacon_chain::BeaconChain;
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use db::{
|
use db::{
|
||||||
stores::{BeaconBlockStore, BeaconStateStore},
|
stores::{BeaconBlockStore, BeaconStateStore},
|
||||||
|
@ -7,7 +7,7 @@ pub fn genesis_beacon_block(state_root: Hash256, spec: &ChainSpec) -> BeaconBloc
|
|||||||
slot: spec.genesis_slot_number,
|
slot: spec.genesis_slot_number,
|
||||||
parent_root: spec.zero_hash,
|
parent_root: spec.zero_hash,
|
||||||
state_root,
|
state_root,
|
||||||
randao_reveal: spec.zero_hash,
|
randao_reveal: spec.empty_signature.clone(),
|
||||||
candidate_pow_receipt_root: spec.zero_hash,
|
candidate_pow_receipt_root: spec.zero_hash,
|
||||||
signature: spec.empty_signature.clone(),
|
signature: spec.empty_signature.clone(),
|
||||||
body: BeaconBlockBody {
|
body: BeaconBlockBody {
|
||||||
@ -47,7 +47,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(genesis_block.slot == 0);
|
assert!(genesis_block.slot == 0);
|
||||||
assert!(genesis_block.parent_root.is_zero());
|
assert!(genesis_block.parent_root.is_zero());
|
||||||
assert!(genesis_block.randao_reveal.is_zero());
|
assert_eq!(genesis_block.randao_reveal, spec.empty_signature);
|
||||||
assert!(genesis_block.candidate_pow_receipt_root.is_zero()); // aka deposit_root
|
assert!(genesis_block.candidate_pow_receipt_root.is_zero()); // aka deposit_root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,7 @@ fn initial_validators_for_testing() -> Vec<ValidatorRecord> {
|
|||||||
let validator_record = ValidatorRecord {
|
let validator_record = ValidatorRecord {
|
||||||
pubkey: keypair.pk.clone(),
|
pubkey: keypair.pk.clone(),
|
||||||
withdrawal_credentials: Hash256::zero(),
|
withdrawal_credentials: Hash256::zero(),
|
||||||
|
proposer_slots: 0,
|
||||||
randao_commitment: Hash256::zero(),
|
randao_commitment: Hash256::zero(),
|
||||||
randao_layers: 0,
|
randao_layers: 0,
|
||||||
activation_slot: u64::max_value(),
|
activation_slot: u64::max_value(),
|
||||||
|
@ -7,32 +7,32 @@ use rand::RngCore;
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Attestation {
|
pub struct Attestation {
|
||||||
pub data: AttestationData,
|
pub data: AttestationData,
|
||||||
pub participation_bitfield: Bitfield,
|
pub aggregation_bitfield: Bitfield,
|
||||||
pub custody_bitfield: Bitfield,
|
pub custody_bitfield: Bitfield,
|
||||||
pub aggregate_sig: AggregateSignature,
|
pub aggregate_signature: AggregateSignature,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for Attestation {
|
impl Encodable for Attestation {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.data);
|
s.append(&self.data);
|
||||||
s.append(&self.participation_bitfield);
|
s.append(&self.aggregation_bitfield);
|
||||||
s.append(&self.custody_bitfield);
|
s.append(&self.custody_bitfield);
|
||||||
s.append(&self.aggregate_sig);
|
s.append(&self.aggregate_signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for Attestation {
|
impl Decodable for Attestation {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
|
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
|
||||||
let (participation_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
let (aggregation_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||||
let (custody_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
let (custody_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||||
let (aggregate_sig, i) = AggregateSignature::ssz_decode(bytes, i)?;
|
let (aggregate_signature, i) = AggregateSignature::ssz_decode(bytes, i)?;
|
||||||
|
|
||||||
let attestation_record = Self {
|
let attestation_record = Self {
|
||||||
data,
|
data,
|
||||||
participation_bitfield,
|
aggregation_bitfield,
|
||||||
custody_bitfield,
|
custody_bitfield,
|
||||||
aggregate_sig,
|
aggregate_signature,
|
||||||
};
|
};
|
||||||
Ok((attestation_record, i))
|
Ok((attestation_record, i))
|
||||||
}
|
}
|
||||||
@ -42,9 +42,9 @@ impl Attestation {
|
|||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: AttestationData::zero(),
|
data: AttestationData::zero(),
|
||||||
participation_bitfield: Bitfield::new(),
|
aggregation_bitfield: Bitfield::new(),
|
||||||
custody_bitfield: Bitfield::new(),
|
custody_bitfield: Bitfield::new(),
|
||||||
aggregate_sig: AggregateSignature::new(),
|
aggregate_signature: AggregateSignature::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,9 +53,9 @@ impl<T: RngCore> TestRandom<T> for Attestation {
|
|||||||
fn random_for_test(rng: &mut T) -> Self {
|
fn random_for_test(rng: &mut T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: <_>::random_for_test(rng),
|
data: <_>::random_for_test(rng),
|
||||||
participation_bitfield: <_>::random_for_test(rng),
|
aggregation_bitfield: <_>::random_for_test(rng),
|
||||||
custody_bitfield: <_>::random_for_test(rng),
|
custody_bitfield: <_>::random_for_test(rng),
|
||||||
aggregate_sig: <_>::random_for_test(rng),
|
aggregate_signature: <_>::random_for_test(rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ pub const SSZ_ATTESTION_DATA_LENGTH: usize = {
|
|||||||
8 + // shard
|
8 + // shard
|
||||||
32 + // beacon_block_hash
|
32 + // beacon_block_hash
|
||||||
32 + // epoch_boundary_hash
|
32 + // epoch_boundary_hash
|
||||||
32 + // shard_block_hash
|
32 + // shard_block_root
|
||||||
32 + // latest_crosslink_hash
|
32 + // latest_crosslink_root
|
||||||
8 + // justified_slot
|
8 + // justified_slot
|
||||||
32 // justified_block_hash
|
32 // justified_block_root
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
@ -20,10 +20,10 @@ pub struct AttestationData {
|
|||||||
pub shard: u64,
|
pub shard: u64,
|
||||||
pub beacon_block_hash: Hash256,
|
pub beacon_block_hash: Hash256,
|
||||||
pub epoch_boundary_hash: Hash256,
|
pub epoch_boundary_hash: Hash256,
|
||||||
pub shard_block_hash: Hash256,
|
pub shard_block_root: Hash256,
|
||||||
pub latest_crosslink_hash: Hash256,
|
pub latest_crosslink_root: Hash256,
|
||||||
pub justified_slot: u64,
|
pub justified_slot: u64,
|
||||||
pub justified_block_hash: Hash256,
|
pub justified_block_root: Hash256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttestationData {
|
impl AttestationData {
|
||||||
@ -33,10 +33,10 @@ impl AttestationData {
|
|||||||
shard: 0,
|
shard: 0,
|
||||||
beacon_block_hash: Hash256::zero(),
|
beacon_block_hash: Hash256::zero(),
|
||||||
epoch_boundary_hash: Hash256::zero(),
|
epoch_boundary_hash: Hash256::zero(),
|
||||||
shard_block_hash: Hash256::zero(),
|
shard_block_root: Hash256::zero(),
|
||||||
latest_crosslink_hash: Hash256::zero(),
|
latest_crosslink_root: Hash256::zero(),
|
||||||
justified_slot: 0,
|
justified_slot: 0,
|
||||||
justified_block_hash: Hash256::zero(),
|
justified_block_root: Hash256::zero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +53,10 @@ impl Encodable for AttestationData {
|
|||||||
s.append(&self.shard);
|
s.append(&self.shard);
|
||||||
s.append(&self.beacon_block_hash);
|
s.append(&self.beacon_block_hash);
|
||||||
s.append(&self.epoch_boundary_hash);
|
s.append(&self.epoch_boundary_hash);
|
||||||
s.append(&self.shard_block_hash);
|
s.append(&self.shard_block_root);
|
||||||
s.append(&self.latest_crosslink_hash);
|
s.append(&self.latest_crosslink_root);
|
||||||
s.append(&self.justified_slot);
|
s.append(&self.justified_slot);
|
||||||
s.append(&self.justified_block_hash);
|
s.append(&self.justified_block_root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,20 +66,20 @@ impl Decodable for AttestationData {
|
|||||||
let (shard, i) = u64::ssz_decode(bytes, i)?;
|
let (shard, i) = u64::ssz_decode(bytes, i)?;
|
||||||
let (beacon_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
let (beacon_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
||||||
let (epoch_boundary_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
let (epoch_boundary_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
||||||
let (shard_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
let (shard_block_root, i) = Hash256::ssz_decode(bytes, i)?;
|
||||||
let (latest_crosslink_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
let (latest_crosslink_root, i) = Hash256::ssz_decode(bytes, i)?;
|
||||||
let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
|
let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
|
||||||
let (justified_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
let (justified_block_root, i) = Hash256::ssz_decode(bytes, i)?;
|
||||||
|
|
||||||
let attestation_data = AttestationData {
|
let attestation_data = AttestationData {
|
||||||
slot,
|
slot,
|
||||||
shard,
|
shard,
|
||||||
beacon_block_hash,
|
beacon_block_hash,
|
||||||
epoch_boundary_hash,
|
epoch_boundary_hash,
|
||||||
shard_block_hash,
|
shard_block_root,
|
||||||
latest_crosslink_hash,
|
latest_crosslink_root,
|
||||||
justified_slot,
|
justified_slot,
|
||||||
justified_block_hash,
|
justified_block_root,
|
||||||
};
|
};
|
||||||
Ok((attestation_data, i))
|
Ok((attestation_data, i))
|
||||||
}
|
}
|
||||||
@ -92,10 +92,10 @@ impl<T: RngCore> TestRandom<T> for AttestationData {
|
|||||||
shard: <_>::random_for_test(rng),
|
shard: <_>::random_for_test(rng),
|
||||||
beacon_block_hash: <_>::random_for_test(rng),
|
beacon_block_hash: <_>::random_for_test(rng),
|
||||||
epoch_boundary_hash: <_>::random_for_test(rng),
|
epoch_boundary_hash: <_>::random_for_test(rng),
|
||||||
shard_block_hash: <_>::random_for_test(rng),
|
shard_block_root: <_>::random_for_test(rng),
|
||||||
latest_crosslink_hash: <_>::random_for_test(rng),
|
latest_crosslink_root: <_>::random_for_test(rng),
|
||||||
justified_slot: <_>::random_for_test(rng),
|
justified_slot: <_>::random_for_test(rng),
|
||||||
justified_block_hash: <_>::random_for_test(rng),
|
justified_block_root: <_>::random_for_test(rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
|
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
|
||||||
use rand::RngCore;
|
|
||||||
use crate::test_utils::TestRandom;
|
|
||||||
use super::AttestationData;
|
use super::AttestationData;
|
||||||
|
use crate::test_utils::TestRandom;
|
||||||
|
use rand::RngCore;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub struct AttestationDataAndCustodyBit {
|
pub struct AttestationDataAndCustodyBit {
|
||||||
@ -12,19 +12,16 @@ pub struct AttestationDataAndCustodyBit {
|
|||||||
impl Encodable for AttestationDataAndCustodyBit {
|
impl Encodable for AttestationDataAndCustodyBit {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.data);
|
s.append(&self.data);
|
||||||
s.append(&self.custody_bit);
|
// TODO: deal with bools
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for AttestationDataAndCustodyBit {
|
impl Decodable for AttestationDataAndCustodyBit {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (custody_bit, i) = <_>::ssz_decode(bytes, i)?;
|
let custody_bit = false;
|
||||||
|
|
||||||
let attestation_data_and_custody_bit = AttestationDataAndCustodyBit {
|
let attestation_data_and_custody_bit = AttestationDataAndCustodyBit { data, custody_bit };
|
||||||
data,
|
|
||||||
custody_bit,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((attestation_data_and_custody_bit, i))
|
Ok((attestation_data_and_custody_bit, i))
|
||||||
}
|
}
|
||||||
@ -34,16 +31,17 @@ impl<T: RngCore> TestRandom<T> for AttestationDataAndCustodyBit {
|
|||||||
fn random_for_test(rng: &mut T) -> Self {
|
fn random_for_test(rng: &mut T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: <_>::random_for_test(rng),
|
data: <_>::random_for_test(rng),
|
||||||
custody_bit: <_>::random_for_test(rng),
|
// TODO: deal with bools
|
||||||
|
custody_bit: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
|
||||||
use super::*;
|
|
||||||
use super::super::ssz::ssz_encode;
|
use super::super::ssz::ssz_encode;
|
||||||
|
use super::*;
|
||||||
|
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_ssz_round_trip() {
|
pub fn test_ssz_round_trip() {
|
||||||
|
@ -10,7 +10,7 @@ pub struct BeaconBlock {
|
|||||||
pub slot: u64,
|
pub slot: u64,
|
||||||
pub parent_root: Hash256,
|
pub parent_root: Hash256,
|
||||||
pub state_root: Hash256,
|
pub state_root: Hash256,
|
||||||
pub randao_reveal: Hash256,
|
pub randao_reveal: Signature,
|
||||||
pub candidate_pow_receipt_root: Hash256,
|
pub candidate_pow_receipt_root: Hash256,
|
||||||
pub signature: Signature,
|
pub signature: Signature,
|
||||||
pub body: BeaconBlockBody,
|
pub body: BeaconBlockBody,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::candidate_pow_receipt_root_record::CandidatePoWReceiptRootRecord;
|
use crate::candidate_pow_receipt_root_record::CandidatePoWReceiptRootRecord;
|
||||||
use super::crosslink_record::CrosslinkRecord;
|
use crate::crosslink_record::CrosslinkRecord;
|
||||||
use super::fork_data::ForkData;
|
use crate::fork_data::ForkData;
|
||||||
use super::pending_attestation_record::PendingAttestationRecord;
|
use crate::pending_attestation_record::PendingAttestationRecord;
|
||||||
use super::validator_record::ValidatorRecord;
|
|
||||||
use super::Hash256;
|
|
||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
|
use crate::validator_record::ValidatorRecord;
|
||||||
|
use crate::Hash256;
|
||||||
use hashing::canonical_hash;
|
use hashing::canonical_hash;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
|
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
|
||||||
|
@ -7,6 +7,7 @@ pub mod test_utils;
|
|||||||
|
|
||||||
pub mod attestation;
|
pub mod attestation;
|
||||||
pub mod attestation_data;
|
pub mod attestation_data;
|
||||||
|
pub mod attestation_data_and_custody_bit;
|
||||||
pub mod beacon_block;
|
pub mod beacon_block;
|
||||||
pub mod beacon_block_body;
|
pub mod beacon_block_body;
|
||||||
pub mod beacon_state;
|
pub mod beacon_state;
|
||||||
@ -35,6 +36,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
pub use crate::attestation::Attestation;
|
pub use crate::attestation::Attestation;
|
||||||
pub use crate::attestation_data::AttestationData;
|
pub use crate::attestation_data::AttestationData;
|
||||||
|
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
|
||||||
pub use crate::beacon_block::BeaconBlock;
|
pub use crate::beacon_block::BeaconBlock;
|
||||||
pub use crate::beacon_block_body::BeaconBlockBody;
|
pub use crate::beacon_block_body::BeaconBlockBody;
|
||||||
pub use crate::beacon_state::BeaconState;
|
pub use crate::beacon_state::BeaconState;
|
||||||
|
@ -6,7 +6,7 @@ use rand::RngCore;
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct PendingAttestationRecord {
|
pub struct PendingAttestationRecord {
|
||||||
pub data: AttestationData,
|
pub data: AttestationData,
|
||||||
pub participation_bitfield: Bitfield,
|
pub aggregation_bitfield: Bitfield,
|
||||||
pub custody_bitfield: Bitfield,
|
pub custody_bitfield: Bitfield,
|
||||||
pub slot_included: u64,
|
pub slot_included: u64,
|
||||||
}
|
}
|
||||||
@ -14,7 +14,7 @@ pub struct PendingAttestationRecord {
|
|||||||
impl Encodable for PendingAttestationRecord {
|
impl Encodable for PendingAttestationRecord {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.data);
|
s.append(&self.data);
|
||||||
s.append(&self.participation_bitfield);
|
s.append(&self.aggregation_bitfield);
|
||||||
s.append(&self.custody_bitfield);
|
s.append(&self.custody_bitfield);
|
||||||
s.append(&self.slot_included);
|
s.append(&self.slot_included);
|
||||||
}
|
}
|
||||||
@ -23,14 +23,14 @@ impl Encodable for PendingAttestationRecord {
|
|||||||
impl Decodable for PendingAttestationRecord {
|
impl Decodable for PendingAttestationRecord {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (participation_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
let (aggregation_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (slot_included, i) = <_>::ssz_decode(bytes, i)?;
|
let (slot_included, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
participation_bitfield,
|
aggregation_bitfield,
|
||||||
custody_bitfield,
|
custody_bitfield,
|
||||||
slot_included,
|
slot_included,
|
||||||
},
|
},
|
||||||
@ -43,7 +43,7 @@ impl<T: RngCore> TestRandom<T> for PendingAttestationRecord {
|
|||||||
fn random_for_test(rng: &mut T) -> Self {
|
fn random_for_test(rng: &mut T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: <_>::random_for_test(rng),
|
data: <_>::random_for_test(rng),
|
||||||
participation_bitfield: <_>::random_for_test(rng),
|
aggregation_bitfield: <_>::random_for_test(rng),
|
||||||
custody_bitfield: <_>::random_for_test(rng),
|
custody_bitfield: <_>::random_for_test(rng),
|
||||||
slot_included: <_>::random_for_test(rng),
|
slot_included: <_>::random_for_test(rng),
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ fn status_flag_from_byte(flag: u8) -> Result<Option<StatusFlags>, StatusFlagsDec
|
|||||||
pub struct ValidatorRecord {
|
pub struct ValidatorRecord {
|
||||||
pub pubkey: PublicKey,
|
pub pubkey: PublicKey,
|
||||||
pub withdrawal_credentials: Hash256,
|
pub withdrawal_credentials: Hash256,
|
||||||
|
pub proposer_slots: u64,
|
||||||
pub randao_commitment: Hash256,
|
pub randao_commitment: Hash256,
|
||||||
pub randao_layers: u64,
|
pub randao_layers: u64,
|
||||||
pub activation_slot: u64,
|
pub activation_slot: u64,
|
||||||
@ -73,6 +74,7 @@ impl Default for ValidatorRecord {
|
|||||||
Self {
|
Self {
|
||||||
pubkey: PublicKey::default(),
|
pubkey: PublicKey::default(),
|
||||||
withdrawal_credentials: Hash256::default(),
|
withdrawal_credentials: Hash256::default(),
|
||||||
|
proposer_slots: 0,
|
||||||
randao_commitment: Hash256::default(),
|
randao_commitment: Hash256::default(),
|
||||||
randao_layers: 0,
|
randao_layers: 0,
|
||||||
activation_slot: std::u64::MAX,
|
activation_slot: std::u64::MAX,
|
||||||
@ -99,6 +101,7 @@ impl Encodable for ValidatorRecord {
|
|||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.pubkey);
|
s.append(&self.pubkey);
|
||||||
s.append(&self.withdrawal_credentials);
|
s.append(&self.withdrawal_credentials);
|
||||||
|
s.append(&self.proposer_slots);
|
||||||
s.append(&self.randao_commitment);
|
s.append(&self.randao_commitment);
|
||||||
s.append(&self.randao_layers);
|
s.append(&self.randao_layers);
|
||||||
s.append(&self.activation_slot);
|
s.append(&self.activation_slot);
|
||||||
@ -117,6 +120,7 @@ impl Decodable for ValidatorRecord {
|
|||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
|
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (proposer_slots, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
|
let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (activation_slot, i) = <_>::ssz_decode(bytes, i)?;
|
let (activation_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
@ -135,6 +139,7 @@ impl Decodable for ValidatorRecord {
|
|||||||
Self {
|
Self {
|
||||||
pubkey,
|
pubkey,
|
||||||
withdrawal_credentials,
|
withdrawal_credentials,
|
||||||
|
proposer_slots,
|
||||||
randao_commitment,
|
randao_commitment,
|
||||||
randao_layers,
|
randao_layers,
|
||||||
activation_slot,
|
activation_slot,
|
||||||
@ -157,6 +162,7 @@ impl<T: RngCore> TestRandom<T> for ValidatorRecord {
|
|||||||
Self {
|
Self {
|
||||||
pubkey: <_>::random_for_test(rng),
|
pubkey: <_>::random_for_test(rng),
|
||||||
withdrawal_credentials: <_>::random_for_test(rng),
|
withdrawal_credentials: <_>::random_for_test(rng),
|
||||||
|
proposer_slots: <_>::random_for_test(rng),
|
||||||
randao_commitment: <_>::random_for_test(rng),
|
randao_commitment: <_>::random_for_test(rng),
|
||||||
randao_layers: <_>::random_for_test(rng),
|
randao_layers: <_>::random_for_test(rng),
|
||||||
activation_slot: <_>::random_for_test(rng),
|
activation_slot: <_>::random_for_test(rng),
|
||||||
|
@ -3,10 +3,10 @@ use std::time::{Duration, SystemTime};
|
|||||||
|
|
||||||
pub use std::time::SystemTimeError;
|
pub use std::time::SystemTimeError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
SlotDurationIsZero,
|
SlotDurationIsZero,
|
||||||
SystemTimeError(SystemTimeError),
|
SystemTimeError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the present slot based upon the present system time.
|
/// Determines the present slot based upon the present system time.
|
||||||
@ -51,7 +51,7 @@ impl SlotClock for SystemTimeSlotClock {
|
|||||||
|
|
||||||
impl From<SystemTimeError> for Error {
|
impl From<SystemTimeError> for Error {
|
||||||
fn from(e: SystemTimeError) -> Error {
|
fn from(e: SystemTimeError) -> Error {
|
||||||
Error::SystemTimeError(e)
|
Error::SystemTimeError(format!("{:?}", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ pub fn process_deposit(
|
|||||||
let validator = ValidatorRecord {
|
let validator = ValidatorRecord {
|
||||||
pubkey: deposit_input.pubkey.clone(),
|
pubkey: deposit_input.pubkey.clone(),
|
||||||
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
||||||
|
proposer_slots: 0,
|
||||||
randao_commitment: deposit_input.randao_commitment,
|
randao_commitment: deposit_input.randao_commitment,
|
||||||
randao_layers: 0,
|
randao_layers: 0,
|
||||||
activation_slot: spec.far_future_slot,
|
activation_slot: spec.far_future_slot,
|
||||||
|
Loading…
Reference in New Issue
Block a user