Start work on attestation endpoint

This commit is contained in:
Paul Hauner
2019-11-21 09:17:06 +11:00
parent b60836be7c
commit 451f8e6767
5 changed files with 87 additions and 37 deletions

View File

@@ -28,6 +28,7 @@ sloggers = "0.3.4"
slot_clock = { path = "../../eth2/utils/slot_clock" }
eth2_hashing = "0.1.0"
eth2_ssz = "0.1.2"
eth2_ssz_types = { path = "../../eth2/utils/ssz_types" }
eth2_ssz_derive = "0.1.0"
state_processing = { path = "../../eth2/state_processing" }
tree_hash = "0.1.0"

View File

@@ -444,6 +444,42 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
}
/// Produce an `Attestation` that is valid for the given `slot` `shard`.
///
/// Always attests to the canonical chain.
pub fn produce_attestation(
&self,
shard: u64,
slot: Slot,
) -> Result<Attestation<T::EthSpec>, Error> {
let state = self.state_at_slot(slot)?;
let head = self.head();
let data = self.produce_attestation_data_for_block(
shard,
head.beacon_block_root,
head.beacon_block.slot,
&state,
)?;
let relative_epoch =
RelativeEpoch::from_slot(state.slot, slot, T::EthSpec::slots_per_epoch())?;
let committee_len = state
.get_crosslink_committee_for_shard(shard, relative_epoch)?
.committee
.len();
let empty_bitfield = BitList::with_capacity(committee_len)?;
Ok(Attestation {
aggregation_bits: empty_bitfield.clone(),
data,
custody_bits: empty_bitfield,
signature: AggregateSignature::new(),
})
}
/// Produce an `AttestationData` that is valid for the given `slot` `shard`.
///
/// Always attests to the canonical chain.

View File

@@ -1,5 +1,6 @@
use crate::eth1_chain::Error as Eth1ChainError;
use crate::fork_choice::Error as ForkChoiceError;
use ssz_types::Error as SszTypesError;
use state_processing::per_block_processing::errors::AttestationValidationError;
use state_processing::BlockProcessingError;
use state_processing::SlotProcessingError;
@@ -41,10 +42,14 @@ pub enum BeaconChainError {
AttestationValidationError(AttestationValidationError),
/// Returned when an internal check fails, indicating corrupt data.
InvariantViolated(String),
RelativeEpochError(RelativeEpochError),
SszTypesError(SszTypesError),
}
easy_from_to!(SlotProcessingError, BeaconChainError);
easy_from_to!(AttestationValidationError, BeaconChainError);
easy_from_to!(RelativeEpochError, BeaconChainError);
easy_from_to!(SszTypesError, BeaconChainError);
#[derive(Debug, PartialEq)]
pub enum BlockProductionError {

View File

@@ -38,6 +38,15 @@ pub fn parse_epoch(string: &str) -> Result<Epoch, ApiError> {
.map_err(|e| ApiError::BadRequest(format!("Unable to parse epoch: {:?}", e)))
}
/// Parse an shard.
///
/// E.g., `"18"`
pub fn parse_shard(string: &str) -> Result<u64, ApiError> {
string
.parse::<u64>()
.map_err(|e| ApiError::BadRequest(format!("Unable to parse shard: {:?}", e)))
}
/// Checks the provided request to ensure that the `content-type` header.
///
/// The content-type header should either be omitted, in which case JSON is assumed, or it should

View File

@@ -1,6 +1,6 @@
use crate::helpers::{
check_content_type_for_json, parse_epoch, parse_pubkey, parse_signature,
publish_attestation_to_network, publish_beacon_block_to_network,
check_content_type_for_json, parse_epoch, parse_pubkey, parse_shard, parse_signature,
parse_slot, publish_attestation_to_network, publish_beacon_block_to_network,
};
use crate::response_builder::ResponseBuilder;
use crate::{ApiError, ApiResult, BoxFut, NetworkChannel, UrlQuery};
@@ -82,44 +82,43 @@ pub fn get_validator_duties<T: BeaconChainTypes + 'static>(
let duties = query
.all_of("validator_pubkeys")?
.iter()
.map(|string| parse_pubkey(string))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(|validator_pubkey| {
if let Some(validator_index) = head_state
.get_validator_index(&validator_pubkey)
.map_err(|e| {
ApiError::ServerError(format!("Unable to read pubkey cache: {:?}", e))
})?
{
let duties = head_state
.get_attestation_duties(validator_index, relative_epoch)
.map(|validator_pubkey_str| {
parse_pubkey(validator_pubkey_str).and_then(|validator_pubkey| {
if let Some(validator_index) = head_state
.get_validator_index(&validator_pubkey)
.map_err(|e| {
ApiError::ServerError(format!(
"Unable to obtain attestation duties: {:?}",
e
))
})?;
ApiError::ServerError(format!("Unable to read pubkey cache: {:?}", e))
})?
{
let duties = head_state
.get_attestation_duties(validator_index, relative_epoch)
.map_err(|e| {
ApiError::ServerError(format!(
"Unable to obtain attestation duties: {:?}",
e
))
})?;
let block_proposal_slot = validator_proposers
.iter()
.find(|(i, _slot)| validator_index == *i)
.map(|(_i, slot)| *slot);
let block_proposal_slot = validator_proposers
.iter()
.find(|(i, _slot)| validator_index == *i)
.map(|(_i, slot)| *slot);
Ok(ValidatorDuty {
validator_pubkey,
attestation_slot: duties.map(|d| d.slot),
attestation_shard: duties.map(|d| d.shard),
block_proposal_slot,
})
} else {
Ok(ValidatorDuty {
validator_pubkey,
attestation_slot: None,
attestation_shard: None,
block_proposal_slot: None,
})
}
Ok(ValidatorDuty {
validator_pubkey,
attestation_slot: duties.map(|d| d.slot),
attestation_shard: duties.map(|d| d.shard),
block_proposal_slot,
})
} else {
Ok(ValidatorDuty {
validator_pubkey,
attestation_slot: None,
attestation_shard: None,
block_proposal_slot: None,
})
}
})
})
.collect::<Result<Vec<_>, ApiError>>()?;