diff --git a/beacon_node/rest_api/tests/test.rs b/beacon_node/rest_api/tests/test.rs index 345cb8974e..37d03b4f20 100644 --- a/beacon_node/rest_api/tests/test.rs +++ b/beacon_node/rest_api/tests/test.rs @@ -60,6 +60,44 @@ fn sign_block( block.signature = Signature::new(&message, domain, &keypair.sk); } +#[test] +fn validator_produce_attestation() { + let mut env = build_env(); + + let node = LocalBeaconNode::production(env.core_context()); + 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 state = beacon_chain.head().beacon_state.clone(); + + let validator_index = 0; + let validator_pubkey = state.validators[validator_index].pubkey.clone(); + let duties = state + .get_attestation_duties(validator_index, RelativeEpoch::Current) + .expect("should have attestation duties cache") + .expect("should have attestation duties"); + + let attestation = env + .runtime() + .block_on(remote_node.http.validator().produce_attestation( + duties.slot, + duties.shard, + &validator_pubkey, + false, + )) + .expect("should fetch attestation from http api"); + + assert_eq!( + attestation.data.crosslink.shard, duties.shard, + "should have same shard" + ); + + // TODO: try to push the attestation. +} + #[test] fn validator_duties() { let mut env = build_env(); diff --git a/eth2/utils/remote_beacon_node/src/lib.rs b/eth2/utils/remote_beacon_node/src/lib.rs index 538218ccc8..9fd8ec2294 100644 --- a/eth2/utils/remote_beacon_node/src/lib.rs +++ b/eth2/utils/remote_beacon_node/src/lib.rs @@ -13,7 +13,9 @@ use ssz::Encode; use std::marker::PhantomData; use std::net::SocketAddr; use std::time::Duration; -use types::{BeaconBlock, BeaconState, Epoch, EthSpec, Hash256, PublicKey, Signature, Slot}; +use types::{ + Attestation, BeaconBlock, BeaconState, Epoch, EthSpec, Hash256, PublicKey, Signature, Slot, +}; use url::Url; pub use rest_api::{HeadResponse, ValidatorDuty}; @@ -161,6 +163,30 @@ impl Validator { .map_err(Into::into) } + /// Produces an unsigned attestation. + pub fn produce_attestation( + &self, + slot: Slot, + shard: u64, + validator_pubkey: &PublicKey, + poc_bit: bool, + ) -> impl Future, Error = Error> { + let query_params = vec![ + ("slot".into(), format!("{}", slot)), + ("shard".into(), format!("{}", shard)), + ("poc_bit".into(), format!("{}", poc_bit as u8)), + ( + "validator_pubkey".into(), + pubkey_as_string(validator_pubkey), + ), + ]; + + let client = self.0.clone(); + self.url("attestation") + .into_future() + .and_then(move |url| client.json_get(url, query_params)) + } + /// Returns the duties required of the given validator pubkeys in the given epoch. pub fn get_duties( &self,