Fix issues with old state information
This commit is contained in:
parent
5ef02688d5
commit
138fcd6275
@ -68,7 +68,8 @@ where
|
||||
},
|
||||
};
|
||||
|
||||
let state = self.state_transition(parent_state, &block)?;
|
||||
let state =
|
||||
self.state_transition_without_verifying_block_signature(parent_state, &block)?;
|
||||
|
||||
let state_root = state.canonical_root();
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
use crate::{BeaconChain, CheckPoint, ClientDB, SlotClock};
|
||||
use std::sync::RwLockReadGuard;
|
||||
use types::{BeaconBlock, BeaconState, Hash256};
|
||||
use types::{beacon_state::SlotProcessingError, BeaconBlock, BeaconState, Hash256};
|
||||
|
||||
pub enum Error {
|
||||
PastSlot,
|
||||
UnableToDetermineProducer,
|
||||
}
|
||||
|
||||
impl<T, U> BeaconChain<T, U>
|
||||
where
|
||||
@ -31,4 +36,37 @@ where
|
||||
.read()
|
||||
.expect("CRITICAL: CanonicalHead poisioned.")
|
||||
}
|
||||
|
||||
pub fn state(&self, slot: u64) -> Result<BeaconState, Error> {
|
||||
let mut state = self
|
||||
.canonical_head
|
||||
.read()
|
||||
.expect("CRITICAL: CanonicalHead poisioned.")
|
||||
.beacon_state
|
||||
.clone();
|
||||
let previous_block_root = self
|
||||
.canonical_head
|
||||
.read()
|
||||
.expect("CRITICAL: CanonicalHead poisioned.")
|
||||
.beacon_block_root
|
||||
.clone();
|
||||
|
||||
match slot.checked_sub(state.slot) {
|
||||
None => Err(Error::PastSlot),
|
||||
Some(distance) => {
|
||||
for _ in 0..distance {
|
||||
state.per_slot_processing(previous_block_root.clone(), &self.spec)?
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SlotProcessingError> for Error {
|
||||
fn from(e: SlotProcessingError) -> Error {
|
||||
match e {
|
||||
SlotProcessingError::UnableToDetermineProducer => Error::UnableToDetermineProducer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,10 @@ where
|
||||
}
|
||||
|
||||
pub fn proposer_slots(&self, validator_index: usize) -> Option<u64> {
|
||||
if let Some(validator) = self
|
||||
.canonical_head()
|
||||
.beacon_state
|
||||
.validator_registry
|
||||
.get(validator_index)
|
||||
{
|
||||
let slot = self.present_slot()?;
|
||||
let state = self.state(slot).ok()?;
|
||||
|
||||
if let Some(validator) = state.validator_registry.get(validator_index) {
|
||||
Some(validator.proposer_slots)
|
||||
} else {
|
||||
None
|
||||
@ -42,8 +40,8 @@ where
|
||||
}
|
||||
|
||||
pub fn block_proposer(&self, slot: u64) -> Option<usize> {
|
||||
//TODO: this is a stub; fix.
|
||||
let validator_count = self.canonical_head().beacon_state.validator_registry.len();
|
||||
Some((slot as usize) % validator_count)
|
||||
let present_slot = self.present_slot()?;
|
||||
let state = self.state(present_slot).ok()?;
|
||||
state.get_beacon_proposer_index(slot, &self.spec)
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ use boolean_bitfield::BooleanBitfield;
|
||||
use slot_clock::{SystemTimeSlotClockError, TestingSlotClockError};
|
||||
use ssz::ssz_encode;
|
||||
use types::{
|
||||
readers::BeaconBlockReader, AttestationData, AttestationDataAndCustodyBit, BeaconBlock,
|
||||
BeaconState, Exit, Fork, Hash256, PendingAttestation, ProposalSignedData,
|
||||
beacon_state::SlotProcessingError, readers::BeaconBlockReader, AttestationData,
|
||||
AttestationDataAndCustodyBit, BeaconBlock, BeaconState, Exit, Fork, Hash256,
|
||||
PendingAttestation,
|
||||
};
|
||||
|
||||
// TODO: define elsehwere.
|
||||
@ -58,14 +59,31 @@ where
|
||||
U: SlotClock,
|
||||
{
|
||||
pub fn state_transition(
|
||||
&self,
|
||||
state: BeaconState,
|
||||
block: &BeaconBlock,
|
||||
) -> Result<BeaconState, Error> {
|
||||
self.internal_state_transition(state, block, true)
|
||||
}
|
||||
|
||||
pub fn state_transition_without_verifying_block_signature(
|
||||
&self,
|
||||
state: BeaconState,
|
||||
block: &BeaconBlock,
|
||||
) -> Result<BeaconState, Error> {
|
||||
self.internal_state_transition(state, block, false)
|
||||
}
|
||||
|
||||
fn internal_state_transition(
|
||||
&self,
|
||||
mut state: BeaconState,
|
||||
block: &BeaconBlock,
|
||||
verify_block_signature: bool,
|
||||
) -> 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)?;
|
||||
state.per_slot_processing(block.parent_root.clone(), &self.spec)?;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -78,44 +96,35 @@ where
|
||||
* 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_index = state
|
||||
.get_beacon_proposer_index(block.slot, &self.spec)
|
||||
.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
|
||||
);
|
||||
if verify_block_signature {
|
||||
ensure!(
|
||||
bls_verify(
|
||||
&block_proposer.pubkey,
|
||||
&block.proposal_root(&self.spec)[..],
|
||||
&block.signature,
|
||||
get_domain(&state.fork_data, state.slot, DOMAIN_PROPOSAL)
|
||||
),
|
||||
Error::BadBlockSignature
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* RANDAO
|
||||
*/
|
||||
|
||||
println!("proposer pubkey: {:?}", &block_proposer.pubkey);
|
||||
ensure!(
|
||||
bls_verify(
|
||||
&block_proposer.pubkey,
|
||||
&ssz_encode(&block_proposer.proposer_slots),
|
||||
// TODO: https://github.com/ethereum/eth2.0-specs/pull/496
|
||||
//
|
||||
// &ssz_encode(&block_proposer.proposer_slots),
|
||||
&ssz_encode(&block.slot),
|
||||
&block.randao_reveal,
|
||||
get_domain(&state.fork_data, state.slot, DOMAIN_RANDAO)
|
||||
),
|
||||
@ -358,35 +367,6 @@ where
|
||||
|
||||
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) {
|
||||
@ -450,20 +430,6 @@ fn hash_tree_root<T>(_input: &T) -> Hash256 {
|
||||
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)
|
||||
@ -481,3 +447,11 @@ impl From<SystemTimeSlotClockError> for Error {
|
||||
Error::SlotClockError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SlotProcessingError> for Error {
|
||||
fn from(e: SlotProcessingError) -> Error {
|
||||
match e {
|
||||
SlotProcessingError::UnableToDetermineProducer => Error::NoBlockProducer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
use super::BeaconChain;
|
||||
use db::ClientDB;
|
||||
use state_transition::{extend_active_state, StateTransitionError};
|
||||
use types::{ActiveState, BeaconBlock, CrystallizedState, Hash256};
|
||||
|
||||
impl<T, U> BeaconChain<T, U>
|
||||
where
|
||||
T: ClientDB + Sized,
|
||||
{
|
||||
pub(crate) fn transition_states(
|
||||
&self,
|
||||
act_state: &ActiveState,
|
||||
cry_state: &CrystallizedState,
|
||||
block: &BeaconBlock,
|
||||
block_hash: &Hash256,
|
||||
) -> Result<(ActiveState, Option<CrystallizedState>), StateTransitionError> {
|
||||
let state_recalc_distance = block
|
||||
.slot
|
||||
.checked_sub(cry_state.last_state_recalculation_slot)
|
||||
.ok_or(StateTransitionError::BlockSlotBeforeRecalcSlot)?;
|
||||
|
||||
if state_recalc_distance >= u64::from(self.spec.epoch_length) {
|
||||
panic!("Not implemented!")
|
||||
} else {
|
||||
let new_act_state = extend_active_state(act_state, block, block_hash)?;
|
||||
Ok((new_act_state, None))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +1,15 @@
|
||||
use self::utils::TestRig;
|
||||
use beacon_chain::BeaconChain;
|
||||
#[cfg(test)]
|
||||
use block_producer::{test_utils::TestSigner, BlockProducer};
|
||||
use db::{
|
||||
stores::{BeaconBlockStore, BeaconStateStore},
|
||||
MemoryDB,
|
||||
};
|
||||
use slot_clock::TestingSlotClock;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use types::{ChainSpec, Keypair, Validator};
|
||||
use types::ChainSpec;
|
||||
|
||||
mod utils;
|
||||
|
||||
#[test]
|
||||
fn rig_can_generate_validators() {
|
||||
/*
|
||||
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||
let validators = generate_validators(2, &chain);
|
||||
chain.spec = inject_validators_into_spec(chain.spec.clone(), &validators[..]);
|
||||
*/
|
||||
fn it_can_produce_blocks() {
|
||||
let validator_count = 2;
|
||||
let blocks = 3;
|
||||
|
||||
let mut rig = TestRig::new(ChainSpec::foundation(), validator_count);
|
||||
rig.produce_next_slot();
|
||||
for _ in 0..blocks {
|
||||
rig.produce_next_slot();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[test]
|
||||
fn it_produces() {
|
||||
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||
let (_block, _state) = chain.produce_block().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_processes_a_block_it_produces() {
|
||||
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||
let (block, _state) = chain.produce_block().unwrap();
|
||||
let (outcome, new_block_hash) = chain.process_block(block).unwrap();
|
||||
assert_eq!(outcome, BlockProcessingOutcome::Processed);
|
||||
assert_eq!(chain.canonical_leaf_block, new_block_hash);
|
||||
}
|
||||
*/
|
||||
|
@ -134,14 +134,23 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
|
||||
/// slashing.
|
||||
fn produce_block(&mut self, slot: u64) -> Result<PollOutcome, Error> {
|
||||
let randao_reveal = {
|
||||
/*
|
||||
* TODO:
|
||||
* https://github.com/ethereum/eth2.0-specs/pull/496
|
||||
*
|
||||
let producer_nonce = self.beacon_node.proposer_nonce(&self.pubkey)?;
|
||||
// TODO: add domain, etc to this message.
|
||||
let message = ssz_encode(&producer_nonce);
|
||||
*/
|
||||
// TODO: add domain, etc to this message.
|
||||
let message = ssz_encode(&slot);
|
||||
println!("validator randao: {:?}", &message);
|
||||
match self.signer.bls_sign(&message) {
|
||||
None => return Ok(PollOutcome::SignerRejection(slot)),
|
||||
Some(signature) => signature,
|
||||
}
|
||||
};
|
||||
println!("validator pubkey: {:?}", &self.pubkey);
|
||||
|
||||
if let Some(block) = self
|
||||
.beacon_node
|
||||
@ -169,21 +178,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
|
||||
fn sign_block(&mut self, mut block: BeaconBlock) -> Option<BeaconBlock> {
|
||||
self.store_produce(&block);
|
||||
|
||||
let proposal_root = {
|
||||
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 = ProposalSignedData {
|
||||
slot: block.slot,
|
||||
shard: self.spec.beacon_chain_shard_number,
|
||||
block_root: block_without_signature_root,
|
||||
};
|
||||
hash_tree_root(&proposal)
|
||||
};
|
||||
|
||||
match self.signer.bls_sign(&proposal_root[..]) {
|
||||
match self.signer.bls_sign(&block.proposal_root(&self.spec)[..]) {
|
||||
None => None,
|
||||
Some(signature) => {
|
||||
block.signature = signature;
|
||||
@ -214,11 +209,6 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
|
||||
}
|
||||
}
|
||||
|
||||
fn hash_tree_root<T>(_input: &T) -> Hash256 {
|
||||
// TODO: stubbed out.
|
||||
Hash256::zero()
|
||||
}
|
||||
|
||||
impl From<BeaconNodeError> for Error {
|
||||
fn from(e: BeaconNodeError) -> Error {
|
||||
Error::BeaconNodeError(e)
|
||||
|
19
eth2/types/src/beacon_block/signing.rs
Normal file
19
eth2/types/src/beacon_block/signing.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::{BeaconBlock, ChainSpec, Hash256, ProposalSignedData};
|
||||
use hashing::hash_tree_root;
|
||||
|
||||
impl BeaconBlock {
|
||||
pub fn proposal_root(&self, spec: &ChainSpec) -> Hash256 {
|
||||
let block_without_signature_root = {
|
||||
let mut block_without_signature = self.clone();
|
||||
block_without_signature.signature = spec.empty_signature.clone();
|
||||
block_without_signature.canonical_root()
|
||||
};
|
||||
|
||||
let proposal = ProposalSignedData {
|
||||
slot: self.slot,
|
||||
shard: spec.beacon_chain_shard_number,
|
||||
block_root: block_without_signature_root,
|
||||
};
|
||||
Hash256::from_slice(&hash_tree_root(&proposal)[..])
|
||||
}
|
||||
}
|
@ -10,6 +10,10 @@ use hashing::canonical_hash;
|
||||
use rand::RngCore;
|
||||
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
|
||||
|
||||
mod slot_advance;
|
||||
|
||||
pub use self::slot_advance::Error as SlotProcessingError;
|
||||
|
||||
// Custody will not be added to the specs until Phase 1 (Sharding Phase) so dummy class used.
|
||||
type CustodyChallenge = usize;
|
||||
|
||||
@ -203,9 +207,9 @@ impl<T: RngCore> TestRandom<T> for BeaconState {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ssz::ssz_encode;
|
||||
use super::*;
|
||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||
use ssz::ssz_encode;
|
||||
|
||||
#[test]
|
||||
pub fn test_ssz_round_trip() {
|
45
eth2/types/src/beacon_state/slot_advance.rs
Normal file
45
eth2/types/src/beacon_state/slot_advance.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use crate::{BeaconState, ChainSpec, Hash256};
|
||||
|
||||
pub enum Error {
|
||||
UnableToDetermineProducer,
|
||||
}
|
||||
|
||||
impl BeaconState {
|
||||
pub fn per_slot_processing(
|
||||
&mut self,
|
||||
previous_block_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
self.slot += 1;
|
||||
|
||||
let block_proposer = self
|
||||
.get_beacon_proposer_index(self.slot, spec)
|
||||
.ok_or_else(|| Error::UnableToDetermineProducer)?;
|
||||
|
||||
self.validator_registry[block_proposer].proposer_slots += 1;
|
||||
self.latest_randao_mixes[(self.slot % spec.latest_randao_mixes_length) as usize] =
|
||||
self.latest_randao_mixes[((self.slot - 1) % spec.latest_randao_mixes_length) as usize];
|
||||
|
||||
// Block roots.
|
||||
self.latest_block_roots[((self.slot - 1) % spec.latest_block_roots_length) as usize] =
|
||||
previous_block_root;
|
||||
|
||||
if self.slot % spec.latest_block_roots_length == 0 {
|
||||
let root = merkle_root(&self.latest_block_roots[..]);
|
||||
self.batched_block_roots.push(root);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_beacon_proposer_index(&self, slot: u64, spec: &ChainSpec) -> Option<usize> {
|
||||
// TODO: this is a stub; implement it properly.
|
||||
//
|
||||
// https://github.com/sigp/lighthouse/pull/148/files
|
||||
let validator_count = self.validator_registry.len();
|
||||
Some((slot as usize) % validator_count)
|
||||
}
|
||||
}
|
||||
|
||||
fn merkle_root(_input: &[Hash256]) -> Hash256 {
|
||||
Hash256::zero()
|
||||
}
|
@ -6,3 +6,4 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
tiny-keccak = "1.4.2"
|
||||
ssz = { path = "../ssz" }
|
||||
|
@ -1,5 +1,4 @@
|
||||
extern crate tiny_keccak;
|
||||
|
||||
use ssz::{ssz_encode, Encodable as SszEncodable};
|
||||
use tiny_keccak::Keccak;
|
||||
|
||||
pub fn canonical_hash(input: &[u8]) -> Vec<u8> {
|
||||
@ -10,6 +9,10 @@ pub fn canonical_hash(input: &[u8]) -> Vec<u8> {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn hash_tree_root<T: SszEncodable>(input: &T) -> Vec<u8> {
|
||||
canonical_hash(&ssz_encode(input))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
Loading…
Reference in New Issue
Block a user