From 376602706a9774567fa4bf38901f5c014f82ef99 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 14 Sep 2020 18:43:56 +1000 Subject: [PATCH] Delete rest_api tests --- beacon_node/rest_api/tests/test.rs | 1345 ---------------------------- 1 file changed, 1345 deletions(-) delete mode 100644 beacon_node/rest_api/tests/test.rs diff --git a/beacon_node/rest_api/tests/test.rs b/beacon_node/rest_api/tests/test.rs deleted file mode 100644 index 160ee667ccf..00000000000 --- a/beacon_node/rest_api/tests/test.rs +++ /dev/null @@ -1,1345 +0,0 @@ -#![cfg(test)] - -#[macro_use] -extern crate assert_matches; - -use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig}; -use node_test_rig::{ - environment::{Environment, EnvironmentBuilder}, - testing_client_config, ClientConfig, ClientGenesis, LocalBeaconNode, -}; -use remote_beacon_node::{ - Committee, HeadBeaconBlock, PersistedOperationPool, PublishStatus, ValidatorResponse, -}; -use rest_types::ValidatorDutyBytes; -use std::convert::TryInto; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; -use types::{ - test_utils::{ - build_double_vote_attester_slashing, build_proposer_slashing, - generate_deterministic_keypair, AttesterSlashingTestTask, ProposerSlashingTestTask, - }, - BeaconBlock, BeaconState, ChainSpec, Domain, Epoch, EthSpec, MinimalEthSpec, PublicKey, - RelativeEpoch, Signature, SignedAggregateAndProof, SignedBeaconBlock, SignedRoot, Slot, - SubnetId, Validator, -}; - -type E = MinimalEthSpec; - -fn build_env() -> Environment { - EnvironmentBuilder::minimal() - .null_logger() - .expect("should build env logger") - .single_thread_tokio_runtime() - .expect("should start tokio runtime") - .build() - .expect("environment should build") -} - -fn build_node(env: &mut Environment, config: ClientConfig) -> LocalBeaconNode { - let context = env.core_context(); - env.runtime() - .block_on(LocalBeaconNode::production(context, config)) - .expect("should block until node created") -} - -/// Returns the randao reveal for the given slot (assuming the given `beacon_chain` uses -/// deterministic keypairs). -fn get_randao_reveal( - beacon_chain: Arc>, - slot: Slot, - spec: &ChainSpec, -) -> Signature { - let head = beacon_chain.head().expect("should get head"); - let fork = head.beacon_state.fork; - let genesis_validators_root = head.beacon_state.genesis_validators_root; - let proposer_index = beacon_chain - .block_proposer(slot) - .expect("should get proposer index"); - let keypair = generate_deterministic_keypair(proposer_index); - let epoch = slot.epoch(E::slots_per_epoch()); - let domain = spec.get_domain(epoch, Domain::Randao, &fork, genesis_validators_root); - let message = epoch.signing_root(domain); - keypair.sk.sign(message) -} - -/// Signs the given block (assuming the given `beacon_chain` uses deterministic keypairs). -fn sign_block( - beacon_chain: Arc>, - block: BeaconBlock, - spec: &ChainSpec, -) -> SignedBeaconBlock { - let head = beacon_chain.head().expect("should get head"); - let fork = head.beacon_state.fork; - let genesis_validators_root = head.beacon_state.genesis_validators_root; - let proposer_index = beacon_chain - .block_proposer(block.slot) - .expect("should get proposer index"); - let keypair = generate_deterministic_keypair(proposer_index); - block.sign(&keypair.sk, &fork, genesis_validators_root, spec) -} - -#[test] -fn validator_produce_attestation() { - let mut env = build_env(); - - let spec = &E::default_spec(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - let genesis_validators_root = beacon_chain.genesis_validators_root; - let state = beacon_chain.head().expect("should get head").beacon_state; - - // Find a validator that has duties in the current slot of the chain. - let mut validator_index = 0; - let duties = loop { - let duties = state - .get_attestation_duties(validator_index, RelativeEpoch::Current) - .expect("should have attestation duties cache") - .expect("should have attestation duties"); - - if duties.slot == node.client.beacon_chain().unwrap().slot().unwrap() { - break duties; - } else { - validator_index += 1 - } - }; - - let mut attestation = env - .runtime() - .block_on( - remote_node - .http - .validator() - .produce_attestation(duties.slot, duties.index), - ) - .expect("should fetch attestation from http api"); - - assert_eq!( - attestation.data.index, duties.index, - "should have same index" - ); - assert_eq!(attestation.data.slot, duties.slot, "should have same slot"); - assert_eq!( - attestation.aggregation_bits.num_set_bits(), - 0, - "should have empty aggregation bits" - ); - - let keypair = generate_deterministic_keypair(validator_index); - - // Fetch the duties again, but via HTTP for authenticity. - let duties = env - .runtime() - .block_on(remote_node.http.validator().get_duties( - attestation.data.slot.epoch(E::slots_per_epoch()), - &[keypair.pk.clone()], - )) - .expect("should fetch duties from http api"); - let duties = &duties[0]; - let committee_count = duties - .committee_count_at_slot - .expect("should have committee count"); - let subnet_id = SubnetId::compute_subnet::( - attestation.data.slot, - attestation.data.index, - committee_count, - spec, - ) - .unwrap(); - // Try publishing the attestation without a signature or a committee bit set, ensure it is - // raises an error. - let publish_status = env - .runtime() - .block_on( - remote_node - .http - .validator() - .publish_attestations(vec![(attestation.clone(), subnet_id)]), - ) - .expect("should publish unsigned attestation"); - assert!( - !publish_status.is_valid(), - "the unsigned published attestation should be invalid" - ); - - // Set the aggregation bit. - attestation - .aggregation_bits - .set( - duties - .attestation_committee_position - .expect("should have committee position"), - true, - ) - .expect("should set attestation bit"); - - // Try publishing with an aggreagation bit set, but an invalid signature. - let publish_status = env - .runtime() - .block_on( - remote_node - .http - .validator() - .publish_attestations(vec![(attestation.clone(), subnet_id)]), - ) - .expect("should publish attestation with invalid signature"); - assert!( - !publish_status.is_valid(), - "the unsigned published attestation should not be valid" - ); - - // Un-set the aggregation bit, so signing doesn't error. - attestation - .aggregation_bits - .set( - duties - .attestation_committee_position - .expect("should have committee position"), - false, - ) - .expect("should un-set attestation bit"); - - attestation - .sign( - &keypair.sk, - duties - .attestation_committee_position - .expect("should have committee position"), - &state.fork, - state.genesis_validators_root, - spec, - ) - .expect("should sign attestation"); - - // Try publishing the valid attestation. - let publish_status = env - .runtime() - .block_on( - remote_node - .http - .validator() - .publish_attestations(vec![(attestation.clone(), subnet_id)]), - ) - .expect("should publish attestation"); - assert!( - publish_status.is_valid(), - "the signed published attestation should be valid" - ); - - // Try obtaining an aggregated attestation with a matching attestation data to the previous - // one. - let aggregated_attestation = env - .runtime() - .block_on( - remote_node - .http - .validator() - .produce_aggregate_attestation(&attestation.data), - ) - .expect("should fetch aggregated attestation from http api"); - - let signed_aggregate_and_proof = SignedAggregateAndProof::from_aggregate( - validator_index as u64, - aggregated_attestation, - None, - &keypair.sk, - &state.fork, - genesis_validators_root, - spec, - ); - - // Publish the signed aggregate. - let publish_status = env - .runtime() - .block_on( - remote_node - .http - .validator() - .publish_aggregate_and_proof(vec![signed_aggregate_and_proof]), - ) - .expect("should publish aggregate and proof"); - assert!( - publish_status.is_valid(), - "the signed aggregate and proof should be valid" - ); -} - -#[test] -fn validator_duties() { - let mut env = build_env(); - - let spec = &E::default_spec(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - - let mut epoch = Epoch::new(0); - - let validators = beacon_chain - .head() - .expect("should get head") - .beacon_state - .validators - .iter() - .map(|v| (&v.pubkey).try_into().expect("pubkey should be valid")) - .collect::>(); - - let duties = env - .runtime() - .block_on(remote_node.http.validator().get_duties(epoch, &validators)) - .expect("should fetch duties from http api"); - - // 1. Check at the current epoch. - check_duties( - duties, - epoch, - validators.clone(), - beacon_chain.clone(), - spec, - ); - - epoch += 4; - let duties = env - .runtime() - .block_on(remote_node.http.validator().get_duties(epoch, &validators)) - .expect("should fetch duties from http api"); - - // 2. Check with a long skip forward. - check_duties(duties, epoch, validators, beacon_chain, spec); - - // TODO: test an epoch in the past. Blocked because the `LocalBeaconNode` cannot produce a - // chain, yet. -} - -fn check_duties( - duties: Vec, - epoch: Epoch, - validators: Vec, - beacon_chain: Arc>, - spec: &ChainSpec, -) { - assert_eq!( - validators.len(), - duties.len(), - "there should be a duty for each validator" - ); - - // Are the duties from the current epoch of the beacon chain, and thus are proposer indices - // known? - let proposers_known = epoch == beacon_chain.epoch().unwrap(); - - let mut state = beacon_chain - .state_at_slot( - epoch.start_slot(T::EthSpec::slots_per_epoch()), - StateSkipConfig::WithStateRoots, - ) - .expect("should get state at slot"); - - state.build_all_caches(spec).expect("should build caches"); - - validators - .iter() - .zip(duties.iter()) - .for_each(|(validator, duty)| { - assert_eq!( - *validator, - (&duty.validator_pubkey) - .try_into() - .expect("should be valid pubkey"), - "pubkey should match" - ); - - let validator_index = state - .get_validator_index(&validator.clone().into()) - .expect("should have pubkey cache") - .expect("pubkey should exist"); - - let attestation_duty = state - .get_attestation_duties(validator_index, RelativeEpoch::Current) - .expect("should have attestation duties cache") - .expect("should have attestation duties"); - - assert_eq!( - Some(attestation_duty.slot), - duty.attestation_slot, - "attestation slot should match" - ); - - assert_eq!( - Some(attestation_duty.index), - duty.attestation_committee_index, - "attestation index should match" - ); - - if proposers_known { - let block_proposal_slots = duty.block_proposal_slots.as_ref().unwrap(); - - if !block_proposal_slots.is_empty() { - for slot in block_proposal_slots { - let expected_proposer = state - .get_beacon_proposer_index(*slot, spec) - .expect("should know proposer"); - assert_eq!( - expected_proposer, validator_index, - "should get correct proposal slot" - ); - } - } else { - epoch.slot_iter(E::slots_per_epoch()).for_each(|slot| { - let slot_proposer = state - .get_beacon_proposer_index(slot, spec) - .expect("should know proposer"); - assert_ne!( - slot_proposer, validator_index, - "validator should not have proposal slot in this epoch" - ) - }) - } - } else { - assert_eq!(duty.block_proposal_slots, None); - } - }); - - if proposers_known { - // Validator duties should include a proposer for every slot of the epoch. - let mut all_proposer_slots: Vec = duties - .iter() - .flat_map(|duty| duty.block_proposal_slots.clone().unwrap()) - .collect(); - all_proposer_slots.sort(); - - let all_slots: Vec = epoch.slot_iter(E::slots_per_epoch()).collect(); - assert_eq!(all_proposer_slots, all_slots); - } -} - -#[test] -fn validator_block_post() { - let mut env = build_env(); - - let spec = &E::default_spec(); - - let two_slots_secs = (spec.milliseconds_per_slot / 1_000) * 2; - - let mut config = testing_client_config(); - config.genesis = ClientGenesis::Interop { - validator_count: 8, - genesis_time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() - - two_slots_secs, - }; - - let node = build_node(&mut env, config); - let remote_node = node.remote_node().expect("should produce remote node"); - - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - - let slot = Slot::new(1); - let randao_reveal = get_randao_reveal(beacon_chain.clone(), slot, spec); - - let block = env - .runtime() - .block_on( - remote_node - .http - .validator() - .produce_block(slot, randao_reveal, None), - ) - .expect("should fetch block from http api"); - - // Try publishing the block without a signature, ensure it is flagged as invalid. - let empty_sig_block = SignedBeaconBlock { - message: block.clone(), - signature: Signature::empty(), - }; - let publish_status = env - .runtime() - .block_on(remote_node.http.validator().publish_block(empty_sig_block)) - .expect("should publish block"); - if cfg!(not(feature = "fake_crypto")) { - assert!( - !publish_status.is_valid(), - "the unsigned published block should not be valid" - ); - } - - let signed_block = sign_block(beacon_chain.clone(), block, spec); - let block_root = signed_block.canonical_root(); - - let publish_status = env - .runtime() - .block_on(remote_node.http.validator().publish_block(signed_block)) - .expect("should publish block"); - - if cfg!(not(feature = "fake_crypto")) { - assert_eq!( - publish_status, - PublishStatus::Valid, - "the signed published block should be valid" - ); - } - - let head = env - .runtime() - .block_on(remote_node.http.beacon().get_head()) - .expect("should get head"); - - assert_eq!( - head.block_root, block_root, - "the published block should become the head block" - ); - - // Note: this heads check is not super useful for this test, however it is include so it get - // _some_ testing. If you remove this call, make sure it's tested somewhere else. - let heads = env - .runtime() - .block_on(remote_node.http.beacon().get_heads()) - .expect("should get heads"); - - assert_eq!(heads.len(), 1, "there should be only one head"); - assert_eq!( - heads, - vec![HeadBeaconBlock { - beacon_block_root: head.block_root, - beacon_block_slot: head.slot, - }], - "there should be only one head" - ); -} - -#[test] -fn validator_block_get() { - let mut env = build_env(); - - let spec = &E::default_spec(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - - let slot = Slot::new(1); - let randao_reveal = get_randao_reveal(beacon_chain, slot, spec); - - let block = env - .runtime() - .block_on( - remote_node - .http - .validator() - .produce_block(slot, randao_reveal.clone(), None), - ) - .expect("should fetch block from http api"); - - let (expected_block, _state) = node - .client - .beacon_chain() - .expect("client should have beacon chain") - .produce_block(randao_reveal, slot, None) - .expect("should produce block"); - - assert_eq!( - block, expected_block, - "the block returned from the API should be as expected" - ); -} - -#[test] -fn validator_block_get_with_graffiti() { - let mut env = build_env(); - - let spec = &E::default_spec(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - - let slot = Slot::new(1); - let randao_reveal = get_randao_reveal(beacon_chain, slot, spec); - - let block = env - .runtime() - .block_on(remote_node.http.validator().produce_block( - slot, - randao_reveal.clone(), - Some(*b"test-graffiti-test-graffiti-test"), - )) - .expect("should fetch block from http api"); - - let (expected_block, _state) = node - .client - .beacon_chain() - .expect("client should have beacon chain") - .produce_block( - randao_reveal, - slot, - Some(*b"test-graffiti-test-graffiti-test"), - ) - .expect("should produce block"); - - assert_eq!( - block, expected_block, - "the block returned from the API should be as expected" - ); -} - -#[test] -fn beacon_state() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let (state_by_slot, root) = env - .runtime() - .block_on(remote_node.http.beacon().get_state_by_slot(Slot::new(0))) - .expect("should fetch state from http api"); - - let (state_by_root, root_2) = env - .runtime() - .block_on(remote_node.http.beacon().get_state_by_root(root)) - .expect("should fetch state from http api"); - - let mut db_state = node - .client - .beacon_chain() - .expect("client should have beacon chain") - .state_at_slot(Slot::new(0), StateSkipConfig::WithStateRoots) - .expect("should find state"); - db_state.drop_all_caches(); - - assert_eq!( - root, root_2, - "the two roots returned from the api should be identical" - ); - assert_eq!( - root, - db_state.canonical_root(), - "root from database should match that from the API" - ); - assert_eq!( - state_by_slot, db_state, - "genesis state by slot from api should match that from the DB" - ); - assert_eq!( - state_by_root, db_state, - "genesis state by root from api should match that from the DB" - ); -} - -#[test] -fn beacon_block() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let (block_by_slot, root) = env - .runtime() - .block_on(remote_node.http.beacon().get_block_by_slot(Slot::new(0))) - .expect("should fetch block from http api"); - - let (block_by_root, root_2) = env - .runtime() - .block_on(remote_node.http.beacon().get_block_by_root(root)) - .expect("should fetch block from http api"); - - let db_block = node - .client - .beacon_chain() - .expect("client should have beacon chain") - .block_at_slot(Slot::new(0)) - .expect("should find block") - .expect("block should not be none"); - - assert_eq!( - root, root_2, - "the two roots returned from the api should be identical" - ); - assert_eq!( - root, - db_block.canonical_root(), - "root from database should match that from the API" - ); - assert_eq!( - block_by_slot, db_block, - "genesis block by slot from api should match that from the DB" - ); - assert_eq!( - block_by_root, db_block, - "genesis block by root from api should match that from the DB" - ); -} - -#[test] -fn genesis_time() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let genesis_time = env - .runtime() - .block_on(remote_node.http.beacon().get_genesis_time()) - .expect("should fetch genesis time from http api"); - - assert_eq!( - node.client - .beacon_chain() - .expect("should have beacon chain") - .head() - .expect("should get head") - .beacon_state - .genesis_time, - genesis_time, - "should match genesis time from head state" - ); -} - -#[test] -fn genesis_validators_root() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let genesis_validators_root = env - .runtime() - .block_on(remote_node.http.beacon().get_genesis_validators_root()) - .expect("should fetch genesis time from http api"); - - assert_eq!( - node.client - .beacon_chain() - .expect("should have beacon chain") - .head() - .expect("should get head") - .beacon_state - .genesis_validators_root, - genesis_validators_root, - "should match genesis time from head state" - ); -} - -#[test] -fn fork() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let fork = env - .runtime() - .block_on(remote_node.http.beacon().get_fork()) - .expect("should fetch from http api"); - - assert_eq!( - node.client - .beacon_chain() - .expect("should have beacon chain") - .head() - .expect("should get head") - .beacon_state - .fork, - fork, - "should match head state" - ); -} - -#[test] -fn eth2_config() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let eth2_config = env - .runtime() - .block_on(remote_node.http.spec().get_eth2_config()) - .expect("should fetch eth2 config from http api"); - - // TODO: check the entire eth2_config, not just the spec. - - assert_eq!( - node.client - .beacon_chain() - .expect("should have beacon chain") - .spec, - eth2_config.spec, - "should match genesis time from head state" - ); -} - -#[test] -fn get_version() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let version = env - .runtime() - .block_on(remote_node.http.node().get_version()) - .expect("should fetch version from http api"); - - assert_eq!( - lighthouse_version::version_with_platform(), - version, - "result should be as expected" - ); -} - -#[test] -fn get_genesis_state_root() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let slot = Slot::new(0); - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_state_root(slot)) - .expect("should fetch from http api"); - - let expected = node - .client - .beacon_chain() - .expect("should have beacon chain") - .rev_iter_state_roots() - .expect("should get iter") - .map(Result::unwrap) - .find(|(_cur_root, cur_slot)| slot == *cur_slot) - .map(|(cur_root, _)| cur_root) - .expect("chain should have state root at slot"); - - assert_eq!(result, expected, "result should be as expected"); -} - -#[test] -fn get_genesis_block_root() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let slot = Slot::new(0); - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_block_root(slot)) - .expect("should fetch from http api"); - - let expected = node - .client - .beacon_chain() - .expect("should have beacon chain") - .rev_iter_block_roots() - .expect("should get iter") - .map(Result::unwrap) - .find(|(_cur_root, cur_slot)| slot == *cur_slot) - .map(|(cur_root, _)| cur_root) - .expect("chain should have state root at slot"); - - assert_eq!(result, expected, "result should be as expected"); -} - -#[test] -fn get_validators() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - let state = &chain.head().expect("should get head").beacon_state; - - let validators = state.validators.iter().take(2).collect::>(); - let pubkeys = validators - .iter() - .map(|v| (&v.pubkey).try_into().expect("should decode pubkey bytes")) - .collect(); - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_validators(pubkeys, None)) - .expect("should fetch from http api"); - - result - .iter() - .zip(validators.iter()) - .for_each(|(response, validator)| compare_validator_response(state, response, validator)); -} - -#[test] -fn get_all_validators() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - let state = &chain.head().expect("should get head").beacon_state; - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_all_validators(None)) - .expect("should fetch from http api"); - - result - .iter() - .zip(state.validators.iter()) - .for_each(|(response, validator)| compare_validator_response(state, response, validator)); -} - -#[test] -fn get_active_validators() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - let state = &chain.head().expect("should get head").beacon_state; - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_active_validators(None)) - .expect("should fetch from http api"); - - /* - * This test isn't comprehensive because all of the validators in the state are active (i.e., - * there is no one to exclude. - * - * This should be fixed once we can generate more interesting scenarios with the - * `NodeTestRig`. - */ - - let validators = state - .validators - .iter() - .filter(|validator| validator.is_active_at(state.current_epoch())); - - result - .iter() - .zip(validators) - .for_each(|(response, validator)| compare_validator_response(state, response, validator)); -} - -#[test] -fn get_committees() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - - let epoch = Epoch::new(0); - - let result = env - .runtime() - .block_on(remote_node.http.beacon().get_committees(epoch)) - .expect("should fetch from http api"); - - let expected = chain - .head() - .expect("should get head") - .beacon_state - .get_beacon_committees_at_epoch(RelativeEpoch::Current) - .expect("should get committees") - .iter() - .map(|c| Committee { - slot: c.slot, - index: c.index, - committee: c.committee.to_vec(), - }) - .collect::>(); - - assert_eq!(result, expected, "result should be as expected"); -} - -#[test] -fn get_fork_choice() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let fork_choice = env - .runtime() - .block_on(remote_node.http.advanced().get_fork_choice()) - .expect("should not error when getting fork choice"); - - assert_eq!( - fork_choice, - *node - .client - .beacon_chain() - .expect("node should have beacon chain") - .fork_choice - .read() - .proto_array() - .core_proto_array(), - "result should be as expected" - ); -} - -#[test] -fn get_operation_pool() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - let result = env - .runtime() - .block_on(remote_node.http.advanced().get_operation_pool()) - .expect("should not error when getting fork choice"); - - let expected = PersistedOperationPool::from_operation_pool( - &node - .client - .beacon_chain() - .expect("node should have chain") - .op_pool, - ); - - assert_eq!(result, expected, "result should be as expected"); -} - -fn compare_validator_response( - state: &BeaconState, - response: &ValidatorResponse, - validator: &Validator, -) { - let response_validator = response.validator.clone().expect("should have validator"); - let i = response - .validator_index - .expect("should have validator index"); - let balance = response.balance.expect("should have balance"); - - assert_eq!(response.pubkey, validator.pubkey, "pubkey"); - assert_eq!(response_validator, *validator, "validator"); - assert_eq!(state.balances[i], balance, "balances"); - assert_eq!(state.validators[i], *validator, "validator index"); -} - -#[test] -fn proposer_slashing() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - - let state = chain - .head() - .expect("should have retrieved state") - .beacon_state; - - let spec = &chain.spec; - - // Check that there are no proposer slashings before insertion - let (proposer_slashings, _attester_slashings) = chain.op_pool.get_slashings(&state); - assert_eq!(proposer_slashings.len(), 0); - - let slot = state.slot; - let proposer_index = chain - .block_proposer(slot) - .expect("should get proposer index"); - let keypair = generate_deterministic_keypair(proposer_index); - let key = &keypair.sk; - let fork = &state.fork; - let proposer_slashing = build_proposer_slashing::( - ProposerSlashingTestTask::Valid, - proposer_index as u64, - &key, - fork, - state.genesis_validators_root, - spec, - ); - - let result = env - .runtime() - .block_on( - remote_node - .http - .beacon() - .proposer_slashing(proposer_slashing.clone()), - ) - .expect("should fetch from http api"); - 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); - assert_eq!(proposer_slashings.len(), 1); - assert_eq!(proposer_slashing.clone(), proposer_slashings[0]); - - let mut invalid_proposer_slashing = build_proposer_slashing::( - ProposerSlashingTestTask::Valid, - proposer_index as u64, - &key, - fork, - state.genesis_validators_root, - spec, - ); - invalid_proposer_slashing.signed_header_2 = invalid_proposer_slashing.signed_header_1.clone(); - - let result = env.runtime().block_on( - remote_node - .http - .beacon() - .proposer_slashing(invalid_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); - assert_eq!(proposer_slashings.len(), 1); - assert_eq!(proposer_slashing, proposer_slashings[0]); -} - -#[test] -fn attester_slashing() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let chain = node - .client - .beacon_chain() - .expect("node should have beacon chain"); - - let state = chain - .head() - .expect("should have retrieved state") - .beacon_state; - let slot = state.slot; - let spec = &chain.spec; - - let proposer_index = chain - .block_proposer(slot) - .expect("should get proposer index"); - let keypair = generate_deterministic_keypair(proposer_index); - - let secret_keys = vec![&keypair.sk]; - let validator_indices = vec![proposer_index as u64]; - let fork = &state.fork; - - // Checking there are no attester slashings before insertion - 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( - AttesterSlashingTestTask::Valid, - &validator_indices[..], - &secret_keys[..], - fork, - state.genesis_validators_root, - spec, - ); - - let result = env - .runtime() - .block_on( - remote_node - .http - .beacon() - .attester_slashing(attester_slashing.clone()), - ) - .expect("should fetch from http api"); - 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); - assert_eq!(attester_slashings.len(), 1); - assert_eq!(attester_slashing, attester_slashings[0]); - - // Building an invalid attester slashing - let mut invalid_attester_slashing = build_double_vote_attester_slashing( - AttesterSlashingTestTask::Valid, - &validator_indices[..], - &secret_keys[..], - fork, - state.genesis_validators_root, - spec, - ); - invalid_attester_slashing.attestation_2 = invalid_attester_slashing.attestation_1.clone(); - - let result = env.runtime().block_on( - remote_node - .http - .beacon() - .attester_slashing(invalid_attester_slashing), - ); - 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); - assert_eq!(attester_slashings.len(), 1); - assert_eq!(attester_slashing, attester_slashings[0]); -} - -mod validator_attestation { - use super::*; - use http::StatusCode; - use node_test_rig::environment::Environment; - use remote_beacon_node::{Error::DidNotSucceed, HttpClient}; - use types::{Attestation, AttestationDuty, MinimalEthSpec}; - use url::Url; - - fn setup() -> ( - Environment, - LocalBeaconNode, - HttpClient, - Url, - AttestationDuty, - ) { - let mut env = build_env(); - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - let client = remote_node.http.clone(); - let socket_addr = node - .client - .http_listen_addr() - .expect("A remote beacon node must have a http server"); - let url = Url::parse(&format!( - "http://{}:{}/validator/attestation", - socket_addr.ip(), - socket_addr.port() - )) - .expect("should be valid endpoint"); - - // Find a validator that has duties in the current slot of the chain. - let mut validator_index = 0; - let beacon_chain = node - .client - .beacon_chain() - .expect("client should have beacon chain"); - let state = beacon_chain.head().expect("should get head").beacon_state; - let duties = loop { - let duties = state - .get_attestation_duties(validator_index, RelativeEpoch::Current) - .expect("should have attestation duties cache") - .expect("should have attestation duties"); - - if duties.slot == node.client.beacon_chain().unwrap().slot().unwrap() { - break duties; - } else { - validator_index += 1 - } - }; - - (env, node, client, url, duties) - } - - #[test] - fn requires_query_parameters() { - let (mut env, _node, client, url, _duties) = setup(); - - let attestation = env.runtime().block_on( - // query parameters are missing - client.json_get::>(url.clone(), vec![]), - ); - - assert_matches!( - attestation.expect_err("should not succeed"), - DidNotSucceed { status, body } => { - assert_eq!(status, StatusCode::BAD_REQUEST); - assert_eq!(body, "URL query must be valid and contain at least one of the following keys: [\"slot\"]".to_owned()); - } - ); - } - - #[test] - fn requires_slot() { - let (mut env, _node, client, url, duties) = setup(); - - let attestation = env.runtime().block_on( - // `slot` is missing - client.json_get::>( - url.clone(), - vec![("committee_index".into(), format!("{}", duties.index))], - ), - ); - - assert_matches!( - attestation.expect_err("should not succeed"), - DidNotSucceed { status, body } => { - assert_eq!(status, StatusCode::BAD_REQUEST); - assert_eq!(body, "URL query must be valid and contain at least one of the following keys: [\"slot\"]".to_owned()); - } - ); - } - - #[test] - fn requires_committee_index() { - let (mut env, _node, client, url, duties) = setup(); - - let attestation = env.runtime().block_on( - // `committee_index` is missing. - client.json_get::>( - url.clone(), - vec![("slot".into(), format!("{}", duties.slot))], - ), - ); - - assert_matches!( - attestation.expect_err("should not succeed"), - DidNotSucceed { status, body } => { - assert_eq!(status, StatusCode::BAD_REQUEST); - assert_eq!(body, "URL query must be valid and contain at least one of the following keys: [\"committee_index\"]".to_owned()); - } - ); - } -} - -#[cfg(target_os = "linux")] -#[test] -fn get_health() { - let mut env = build_env(); - - let node = build_node(&mut env, testing_client_config()); - let remote_node = node.remote_node().expect("should produce remote node"); - - env.runtime() - .block_on(remote_node.http.node().get_health()) - .unwrap(); -}