Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use serde::{Deserialize, Serialize};
use strum::EnumString;
use types::{EthSpec, ExecutionBlockHash, FixedVector, Transaction, Unsigned, VariableList};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -311,8 +312,9 @@ impl From<JsonForkChoiceStateV1> for ForkChoiceState {
}
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, EnumString)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
pub enum JsonPayloadStatusV1Status {
Valid,
Invalid,
Expand Down
14 changes: 14 additions & 0 deletions beacon_node/execution_layer/src/test_utils/handle_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ pub async fn handle_rpc<T: EthSpec>(
ENGINE_NEW_PAYLOAD_V1 => {
let request: JsonExecutionPayloadV1<T> = get_param(params, 0)?;

// Canned responses set by block hash take priority.
if let Some(status) = ctx.get_new_payload_status(&request.block_hash) {
return Ok(serde_json::to_value(JsonPayloadStatusV1::from(status)).unwrap());
}

let (static_response, should_import) =
if let Some(mut response) = ctx.static_new_payload_response.lock().clone() {
if response.status.status == PayloadStatusV1Status::Valid {
Expand Down Expand Up @@ -120,6 +125,15 @@ pub async fn handle_rpc<T: EthSpec>(

let head_block_hash = forkchoice_state.head_block_hash;

// Canned responses set by block hash take priority.
if let Some(status) = ctx.get_fcu_payload_status(&head_block_hash) {
let response = JsonForkchoiceUpdatedV1Response {
payload_status: JsonPayloadStatusV1::from(status),
payload_id: None,
};
return Ok(serde_json::to_value(response).unwrap());
}

let mut response = ctx
.execution_block_generator
.write()
Expand Down
46 changes: 46 additions & 0 deletions beacon_node/execution_layer/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use parking_lot::{Mutex, RwLock, RwLockWriteGuard};
use serde::{Deserialize, Serialize};
use serde_json::json;
use slog::{info, Logger};
use std::collections::HashMap;
use std::convert::Infallible;
use std::future::Future;
use std::marker::PhantomData;
Expand Down Expand Up @@ -98,6 +99,8 @@ impl<T: EthSpec> MockServer<T> {
static_new_payload_response: <_>::default(),
static_forkchoice_updated_response: <_>::default(),
static_get_block_by_hash_response: <_>::default(),
new_payload_statuses: <_>::default(),
fcu_payload_statuses: <_>::default(),
_phantom: PhantomData,
});

Expand Down Expand Up @@ -370,6 +373,25 @@ impl<T: EthSpec> MockServer<T> {
pub fn drop_all_blocks(&self) {
self.ctx.execution_block_generator.write().drop_all_blocks()
}

pub fn set_payload_statuses(&self, block_hash: ExecutionBlockHash, status: PayloadStatusV1) {
self.set_new_payload_status(block_hash, status.clone());
self.set_fcu_payload_status(block_hash, status);
}

pub fn set_new_payload_status(&self, block_hash: ExecutionBlockHash, status: PayloadStatusV1) {
self.ctx
.new_payload_statuses
.lock()
.insert(block_hash, status);
}

pub fn set_fcu_payload_status(&self, block_hash: ExecutionBlockHash, status: PayloadStatusV1) {
self.ctx
.fcu_payload_statuses
.lock()
.insert(block_hash, status);
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -419,9 +441,33 @@ pub struct Context<T: EthSpec> {
pub static_new_payload_response: Arc<Mutex<Option<StaticNewPayloadResponse>>>,
pub static_forkchoice_updated_response: Arc<Mutex<Option<PayloadStatusV1>>>,
pub static_get_block_by_hash_response: Arc<Mutex<Option<Option<ExecutionBlock>>>>,

// Canned responses by block hash.
//
// This is a more flexible and less stateful alternative to `static_new_payload_response`
// and `preloaded_responses`.
pub new_payload_statuses: Arc<Mutex<HashMap<ExecutionBlockHash, PayloadStatusV1>>>,
pub fcu_payload_statuses: Arc<Mutex<HashMap<ExecutionBlockHash, PayloadStatusV1>>>,

pub _phantom: PhantomData<T>,
}

impl<T: EthSpec> Context<T> {
pub fn get_new_payload_status(
&self,
block_hash: &ExecutionBlockHash,
) -> Option<PayloadStatusV1> {
self.new_payload_statuses.lock().get(block_hash).cloned()
}

pub fn get_fcu_payload_status(
&self,
block_hash: &ExecutionBlockHash,
) -> Option<PayloadStatusV1> {
self.fcu_payload_statuses.lock().get(block_hash).cloned()
}
}

/// Configuration for the HTTP server.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct Config {
Expand Down
1 change: 1 addition & 0 deletions testing/ef_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ fs2 = "0.4.3"
beacon_chain = { path = "../../beacon_node/beacon_chain" }
store = { path = "../../beacon_node/store" }
fork_choice = { path = "../../consensus/fork_choice" }
execution_layer = { path = "../../beacon_node/execution_layer" }
2 changes: 1 addition & 1 deletion testing/ef_tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
TESTS_TAG := v1.2.0-rc.3
TESTS_TAG := v1.2.0
TESTS = general minimal mainnet
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))

Expand Down
17 changes: 8 additions & 9 deletions testing/ef_tests/src/cases/bls_aggregate_sigs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde_derive::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct BlsAggregateSigs {
pub input: Vec<String>,
pub output: String,
pub output: Option<String>,
}

impl BlsCase for BlsAggregateSigs {}
Expand All @@ -29,14 +29,13 @@ impl Case for BlsAggregateSigs {
aggregate_signature.add_assign(&sig);
}

// Check for YAML null value, indicating invalid input. This is a bit of a hack,
// as our mutating `aggregate_signature.add` API doesn't play nicely with aggregating 0
// inputs.
let output_bytes = if self.output == "~" {
AggregateSignature::infinity().serialize().to_vec()
} else {
hex::decode(&self.output[2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?
let output_bytes = match self.output.as_deref() {
// Check for YAML null value, indicating invalid input. This is a bit of a hack,
// as our mutating `aggregate_signature.add` API doesn't play nicely with aggregating 0
// inputs.
Some("~") | None => AggregateSignature::infinity().serialize().to_vec(),
Some(output) => hex::decode(&output[2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?,
};
let aggregate_signature = Ok(aggregate_signature.serialize().to_vec());

Expand Down
69 changes: 61 additions & 8 deletions testing/ef_tests/src/cases/fork_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use beacon_chain::{
test_utils::{BeaconChainHarness, EphemeralHarnessType},
BeaconChainTypes, CachedHead, CountUnrealized,
};
use serde_derive::Deserialize;
use execution_layer::{json_structures::JsonPayloadStatusV1Status, PayloadStatusV1};
use serde::Deserialize;
use ssz_derive::Decode;
use state_processing::state_advance::complete_state_advance;
use std::future::Future;
Expand Down Expand Up @@ -50,16 +51,53 @@ pub struct Checks {
proposer_boost_root: Option<Hash256>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PayloadStatus {
status: JsonPayloadStatusV1Status,
latest_valid_hash: Option<ExecutionBlockHash>,
validation_error: Option<String>,
}

impl From<PayloadStatus> for PayloadStatusV1 {
fn from(status: PayloadStatus) -> Self {
PayloadStatusV1 {
status: status.status.into(),
latest_valid_hash: status.latest_valid_hash,
validation_error: status.validation_error,
}
}
}

#[derive(Debug, Clone, Deserialize)]
#[serde(untagged, deny_unknown_fields)]
pub enum Step<B, A, AS, P> {
Tick { tick: u64 },
ValidBlock { block: B },
MaybeValidBlock { block: B, valid: bool },
Attestation { attestation: A },
AttesterSlashing { attester_slashing: AS },
PowBlock { pow_block: P },
Checks { checks: Box<Checks> },
Tick {
tick: u64,
},
ValidBlock {
block: B,
},
MaybeValidBlock {
block: B,
valid: bool,
},
Attestation {
attestation: A,
},
AttesterSlashing {
attester_slashing: AS,
},
PowBlock {
pow_block: P,
},
OnPayloadInfo {
block_hash: ExecutionBlockHash,
payload_status: PayloadStatus,
},
Checks {
checks: Box<Checks>,
},
}

#[derive(Debug, Clone, Deserialize)]
Expand Down Expand Up @@ -119,6 +157,13 @@ impl<E: EthSpec> LoadCase for ForkChoiceTest<E> {
ssz_decode_file(&path.join(format!("{}.ssz_snappy", pow_block)))
.map(|pow_block| Step::PowBlock { pow_block })
}
Step::OnPayloadInfo {
block_hash,
payload_status,
} => Ok(Step::OnPayloadInfo {
block_hash,
payload_status,
}),
Step::Checks { checks } => Ok(Step::Checks { checks }),
})
.collect::<Result<_, _>>()?;
Expand Down Expand Up @@ -168,6 +213,14 @@ impl<E: EthSpec> Case for ForkChoiceTest<E> {
tester.process_attester_slashing(attester_slashing)
}
Step::PowBlock { pow_block } => tester.process_pow_block(pow_block),
Step::OnPayloadInfo {
block_hash,
payload_status,
} => {
let el = tester.harness.mock_execution_layer.as_ref().unwrap();
el.server
.set_payload_statuses(*block_hash, payload_status.clone().into());
}
Step::Checks { checks } => {
let Checks {
head,
Expand Down
5 changes: 5 additions & 0 deletions testing/ef_tests/src/cases/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ impl<E: EthSpec> Operation<E> for Deposit {
ssz_decode_file(path)
}

fn is_enabled_for_fork(_: ForkName) -> bool {
// Some deposit tests require signature verification but are not marked as such.
cfg!(not(feature = "fake_crypto"))
}

fn apply_to(
&self,
state: &mut BeaconState<E>,
Expand Down
31 changes: 31 additions & 0 deletions testing/ef_tests/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,37 @@ impl<E: EthSpec + TypeName> Handler for ForkChoiceHandler<E> {
}
}

#[derive(Derivative)]
#[derivative(Default(bound = ""))]
pub struct OptimisticSyncHandler<E>(PhantomData<E>);

impl<E: EthSpec + TypeName> Handler for OptimisticSyncHandler<E> {
type Case = cases::ForkChoiceTest<E>;

fn config_name() -> &'static str {
E::name()
}

fn runner_name() -> &'static str {
"sync"
}

fn handler_name(&self) -> String {
"optimistic".into()
}

fn use_rayon() -> bool {
// The opt sync tests use `block_on` which can cause panics with rayon.
false
}

fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool {
fork_name != ForkName::Base
&& fork_name != ForkName::Altair
&& cfg!(not(feature = "fake_crypto"))
}
}

#[derive(Derivative)]
#[derivative(Default(bound = ""))]
pub struct GenesisValidityHandler<E>(PhantomData<E>);
Expand Down
6 changes: 6 additions & 0 deletions testing/ef_tests/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,12 @@ fn fork_choice_ex_ante() {
ForkChoiceHandler::<MainnetEthSpec>::new("ex_ante").run();
}

#[test]
fn optimistic_sync() {
OptimisticSyncHandler::<MinimalEthSpec>::default().run();
OptimisticSyncHandler::<MainnetEthSpec>::default().run();
}

#[test]
fn genesis_initialization() {
GenesisInitializationHandler::<MinimalEthSpec>::default().run();
Expand Down