diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index b7fd3f581..2c7b90e3f 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -173,7 +173,7 @@ pub fn start_server( helpers::implementation_pending_response(req) } (&Method::GET, "/beacon/validator/attestation") => { - helpers::implementation_pending_response(req) + validator::get_new_attestation::(req) } (&Method::POST, "/beacon/validator/attestation") => { helpers::implementation_pending_response(req) diff --git a/beacon_node/rest_api/src/validator.rs b/beacon_node/rest_api/src/validator.rs index 645a35837..450ef5e5f 100644 --- a/beacon_node/rest_api/src/validator.rs +++ b/beacon_node/rest_api/src/validator.rs @@ -62,7 +62,6 @@ pub fn get_validator_duties(req: Request) - e )) })?; - //TODO: Handle an array of validators, currently only takes one let validators: Vec = match query.all_of("validator_pubkeys") { Ok(v) => v .iter() @@ -197,7 +196,70 @@ pub fn get_new_beacon_block(req: Request) - let body = Body::from( serde_json::to_string(&new_block) - .expect("We should always be able to serialize a new block that we created."), + .expect("We should always be able to serialize a new block that we produced."), + ); + Ok(success_response(body)) +} + +/// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator. +pub fn get_new_attestation(req: Request) -> ApiResult { + // Get beacon state + let beacon_chain = req + .extensions() + .get::>>() + .ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?; + //TODO Surely this state_cache thing is not necessary? + let _ = beacon_chain + .ensure_state_caches_are_built() + .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?; + + let query = UrlQuery::from_request(&req)?; + let validator: PublicKey = match query.first_of(&["validator_pubkey"]) { + Ok((_, v)) => parse_pubkey(v.as_str())?, + Err(e) => { + return Err(e); + } + }; + let poc_bit: bool = match query.first_of(&["poc_bit"]) { + Ok((_, v)) => v.parse::().map_err(|e| ApiError::InvalidQueryParams(format!("poc_bit is not a valid boolean value: {:?}", e)))?, + Err(e) => { + return Err(e); + } + }; + //TODO: this is probably unnecessary if we're always doing it by current slot. + let _slot = match query.first_of(&["slot"]) { + Ok((_, v)) => { + let requested_slot = v.parse::().map_err(|e| { + ApiError::InvalidQueryParams(format!("Invalid slot parameter, must be a u64. {:?}", e)) + })?; + let current_slot = beacon_chain.head().beacon_state.slot.as_u64(); + if requested_slot != current_slot { + return Err(ApiError::InvalidQueryParams(format!("Attestation data can only be requested for the current slot ({:?}), not your requested slot ({:?})", current_slot, requested_slot))); + } + Slot::new(requested_slot) + }, + Err(e) => { + return Err(e); + } + }; + let shard: Shard = match query.first_of(&["shard"]) { + Ok((_, v)) => v.parse::().map_err(|e| ApiError::InvalidQueryParams(format!("Shard is not a valid u64 value: {:?}", e)))?, + Err(e) => { + return Err(e); + } + }; + + let attestation_data = match beacon_chain.produce_attestation_data(shard) { + Ok(v) => v, + Err(e) => { + return Err(ApiError::ServerError(format!("Could not produce an attestation: {:?}", e))); + } + }; + + //TODO: This is currently AttestationData, but should be IndexedAttestation? + let body = Body::from( + serde_json::to_string(&attestation_data) + .expect("We should always be able to serialize a new attestation that we produced."), ); Ok(success_response(body)) } diff --git a/docs/api_spec.yaml b/docs/api_spec.yaml index b43d99b8a..42b394e69 100644 --- a/docs/api_spec.yaml +++ b/docs/api_spec.yaml @@ -839,8 +839,6 @@ paths: $ref: '#/components/schemas/ValidatorDuty' 400: $ref: '#/components/responses/InvalidRequest' - 406: - description: "Duties cannot be provided for the requested epoch." 500: $ref: '#/components/responses/InternalError' 503: @@ -867,6 +865,8 @@ paths: schema: type: string format: byte + pattern: "^0x[a-fA-F0-9]{192}$" + description: "A valid BLS signature." responses: 200: description: Success response