Process exits and slashings off the network (#1253)

* Process exits and slashings off the network

* Fix rest_api tests

* Add op verification tests

* Add tests for pruning of slashings in the op pool

* Address Paul's review comments
This commit is contained in:
Michael Sproul
2020-06-18 21:06:34 +10:00
committed by GitHub
parent 3199b1a6f2
commit bcb6afa0aa
27 changed files with 956 additions and 273 deletions

View File

@@ -2,7 +2,9 @@ use crate::helpers::*;
use crate::response_builder::ResponseBuilder;
use crate::validator::get_state_for_epoch;
use crate::{ApiError, ApiResult, UrlQuery};
use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig};
use beacon_chain::{
observed_operations::ObservationOutcome, BeaconChain, BeaconChainTypes, StateSkipConfig,
};
use bus::BusReader;
use futures::executor::block_on;
use hyper::body::Bytes;
@@ -504,31 +506,23 @@ pub async fn proposer_slashing<T: BeaconChainTypes>(
.map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e)))?;
serde_json::from_slice::<ProposerSlashing>(&chunks)
.map_err(|e| {
ApiError::BadRequest(format!(
"Unable to parse JSON into ProposerSlashing: {:?}",
e
))
})
.map_err(|e| format!("Unable to parse JSON into ProposerSlashing: {:?}", e))
.and_then(move |proposer_slashing| {
let spec = &beacon_chain.spec;
let state = &beacon_chain.head().unwrap().beacon_state;
if beacon_chain.eth1_chain.is_some() {
beacon_chain
.op_pool
.insert_proposer_slashing(proposer_slashing, state, spec)
.map_err(|e| {
ApiError::BadRequest(format!(
"Error while inserting proposer slashing: {:?}",
e
))
})
let obs_outcome = beacon_chain
.verify_proposer_slashing_for_gossip(proposer_slashing)
.map_err(|e| format!("Error while verifying proposer slashing: {:?}", e))?;
if let ObservationOutcome::New(verified_proposer_slashing) = obs_outcome {
beacon_chain.import_proposer_slashing(verified_proposer_slashing);
Ok(())
} else {
Err("Proposer slashing for that validator index already known".into())
}
} else {
return Err(ApiError::BadRequest(
"Cannot insert proposer slashing on node without Eth1 connection.".to_string(),
));
Err("Cannot insert proposer slashing on node without Eth1 connection.".to_string())
}
})
.map_err(ApiError::BadRequest)
.and_then(|_| response_builder?.body(&true))
}
@@ -551,18 +545,24 @@ pub async fn attester_slashing<T: BeaconChainTypes>(
))
})
.and_then(move |attester_slashing| {
let spec = &beacon_chain.spec;
let state = &beacon_chain.head().unwrap().beacon_state;
if beacon_chain.eth1_chain.is_some() {
beacon_chain
.op_pool
.insert_attester_slashing(attester_slashing, state, spec)
.map_err(|e| {
ApiError::BadRequest(format!(
"Error while inserting attester slashing: {:?}",
e
))
.verify_attester_slashing_for_gossip(attester_slashing)
.map_err(|e| format!("Error while verifying attester slashing: {:?}", e))
.and_then(|outcome| {
if let ObservationOutcome::New(verified_attester_slashing) = outcome {
beacon_chain
.import_attester_slashing(verified_attester_slashing)
.map_err(|e| {
format!("Error while importing attester slashing: {:?}", e)
})
} else {
Err(format!(
"Attester slashing only covers already slashed indices"
))
}
})
.map_err(ApiError::BadRequest)
} else {
Err(ApiError::BadRequest(
"Cannot insert attester slashing on node without Eth1 connection.".to_string(),

View File

@@ -1019,7 +1019,7 @@ fn proposer_slashing() {
let spec = &chain.spec;
// Check that there are no proposer slashings before insertion
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(proposer_slashings.len(), 0);
let slot = state.slot;
@@ -1050,7 +1050,7 @@ fn proposer_slashing() {
assert!(result, true);
// Length should be just one as we've inserted only one proposer slashing
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(proposer_slashings.len(), 1);
assert_eq!(proposer_slashing.clone(), proposer_slashings[0]);
@@ -1073,7 +1073,7 @@ fn proposer_slashing() {
assert!(result.is_err());
// Length should still be one as we've inserted nothing since last time.
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(proposer_slashings.len(), 1);
assert_eq!(proposer_slashing, proposer_slashings[0]);
}
@@ -1106,7 +1106,7 @@ fn attester_slashing() {
let fork = &state.fork;
// Checking there are no attester slashings before insertion
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(attester_slashings.len(), 0);
let attester_slashing = build_double_vote_attester_slashing(
@@ -1130,7 +1130,7 @@ fn attester_slashing() {
assert!(result, true);
// Length should be just one as we've inserted only one attester slashing
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(attester_slashings.len(), 1);
assert_eq!(attester_slashing, attester_slashings[0]);
@@ -1151,10 +1151,10 @@ fn attester_slashing() {
.beacon()
.attester_slashing(invalid_attester_slashing),
);
assert!(result.is_err());
result.unwrap_err();
// Length should still be one as we've failed to insert the attester slashing.
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state, spec);
let (_proposer_slashings, attester_slashings) = chain.op_pool.get_slashings(&state);
assert_eq!(attester_slashings.len(), 1);
assert_eq!(attester_slashing, attester_slashings[0]);
}