Merge branch 'unstable' of https://github.com/sigp/lighthouse into merge-unstable-deneb-aug-24
This commit is contained in:
commit
8ed77d4550
13
Makefile
13
Makefile
@ -71,13 +71,13 @@ install-lcli:
|
|||||||
# optimized CPU functions that may not be available on some systems. This
|
# optimized CPU functions that may not be available on some systems. This
|
||||||
# results in a more portable binary with ~20% slower BLS verification.
|
# results in a more portable binary with ~20% slower BLS verification.
|
||||||
build-x86_64:
|
build-x86_64:
|
||||||
cross build --bin lighthouse --target x86_64-unknown-linux-gnu --features "modern,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
|
cross build --bin lighthouse --target x86_64-unknown-linux-gnu --features "modern,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)" --locked
|
||||||
build-x86_64-portable:
|
build-x86_64-portable:
|
||||||
cross build --bin lighthouse --target x86_64-unknown-linux-gnu --features "portable,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
|
cross build --bin lighthouse --target x86_64-unknown-linux-gnu --features "portable,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)" --locked
|
||||||
build-aarch64:
|
build-aarch64:
|
||||||
cross build --bin lighthouse --target aarch64-unknown-linux-gnu --features "$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
|
cross build --bin lighthouse --target aarch64-unknown-linux-gnu --features "$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)" --locked
|
||||||
build-aarch64-portable:
|
build-aarch64-portable:
|
||||||
cross build --bin lighthouse --target aarch64-unknown-linux-gnu --features "portable,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
|
cross build --bin lighthouse --target aarch64-unknown-linux-gnu --features "portable,$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)" --locked
|
||||||
|
|
||||||
# Create a `.tar.gz` containing a binary for a specific target.
|
# Create a `.tar.gz` containing a binary for a specific target.
|
||||||
define tarball_release_binary
|
define tarball_release_binary
|
||||||
@ -214,8 +214,9 @@ arbitrary-fuzz:
|
|||||||
|
|
||||||
# Runs cargo audit (Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database)
|
# Runs cargo audit (Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database)
|
||||||
audit:
|
audit:
|
||||||
cargo install --force cargo-audit
|
# cargo install --force cargo-audit
|
||||||
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2022-0093
|
cargo audit --ignore RUSTSEC-2020-0071 --ignore RUSTSEC-2022-0093 \
|
||||||
|
--ignore RUSTSEC-2023-0052 --ignore RUSTSEC-2023-0053
|
||||||
|
|
||||||
# Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose.
|
# Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose.
|
||||||
vendor:
|
vendor:
|
||||||
|
72
beacon_node/http_api/src/builder_states.rs
Normal file
72
beacon_node/http_api/src/builder_states.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use crate::StateId;
|
||||||
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||||
|
use safe_arith::SafeArith;
|
||||||
|
use state_processing::per_block_processing::get_expected_withdrawals;
|
||||||
|
use state_processing::state_advance::partial_state_advance;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use types::{BeaconState, EthSpec, ForkName, Slot, Withdrawals};
|
||||||
|
|
||||||
|
const MAX_EPOCH_LOOKAHEAD: u64 = 2;
|
||||||
|
|
||||||
|
/// Get the withdrawals computed from the specified state, that will be included in the block
|
||||||
|
/// that gets built on the specified state.
|
||||||
|
pub fn get_next_withdrawals<T: BeaconChainTypes>(
|
||||||
|
chain: &Arc<BeaconChain<T>>,
|
||||||
|
mut state: BeaconState<T::EthSpec>,
|
||||||
|
state_id: StateId,
|
||||||
|
proposal_slot: Slot,
|
||||||
|
) -> Result<Withdrawals<T::EthSpec>, warp::Rejection> {
|
||||||
|
get_next_withdrawals_sanity_checks(chain, &state, proposal_slot)?;
|
||||||
|
|
||||||
|
// advance the state to the epoch of the proposal slot.
|
||||||
|
let proposal_epoch = proposal_slot.epoch(T::EthSpec::slots_per_epoch());
|
||||||
|
let (state_root, _, _) = state_id.root(chain)?;
|
||||||
|
if proposal_epoch != state.current_epoch() {
|
||||||
|
if let Err(e) =
|
||||||
|
partial_state_advance(&mut state, Some(state_root), proposal_slot, &chain.spec)
|
||||||
|
{
|
||||||
|
return Err(warp_utils::reject::custom_server_error(format!(
|
||||||
|
"failed to advance to the epoch of the proposal slot: {:?}",
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match get_expected_withdrawals(&state, &chain.spec) {
|
||||||
|
Ok(withdrawals) => Ok(withdrawals),
|
||||||
|
Err(e) => Err(warp_utils::reject::custom_server_error(format!(
|
||||||
|
"failed to get expected withdrawal: {:?}",
|
||||||
|
e
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_next_withdrawals_sanity_checks<T: BeaconChainTypes>(
|
||||||
|
chain: &BeaconChain<T>,
|
||||||
|
state: &BeaconState<T::EthSpec>,
|
||||||
|
proposal_slot: Slot,
|
||||||
|
) -> Result<(), warp::Rejection> {
|
||||||
|
if proposal_slot <= state.slot() {
|
||||||
|
return Err(warp_utils::reject::custom_bad_request(
|
||||||
|
"proposal slot must be greater than the pre-state slot".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let fork = chain.spec.fork_name_at_slot::<T::EthSpec>(proposal_slot);
|
||||||
|
if let ForkName::Base | ForkName::Altair | ForkName::Merge = fork {
|
||||||
|
return Err(warp_utils::reject::custom_bad_request(
|
||||||
|
"the specified state is a pre-capella state.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let look_ahead_limit = MAX_EPOCH_LOOKAHEAD
|
||||||
|
.safe_mul(T::EthSpec::slots_per_epoch())
|
||||||
|
.map_err(warp_utils::reject::arith_error)?;
|
||||||
|
if proposal_slot >= state.slot() + look_ahead_limit {
|
||||||
|
return Err(warp_utils::reject::custom_bad_request(format!(
|
||||||
|
"proposal slot is greater than or equal to the look ahead limit: {look_ahead_limit}"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -11,6 +11,7 @@ mod block_id;
|
|||||||
mod block_packing_efficiency;
|
mod block_packing_efficiency;
|
||||||
mod block_rewards;
|
mod block_rewards;
|
||||||
mod build_block_contents;
|
mod build_block_contents;
|
||||||
|
mod builder_states;
|
||||||
mod database;
|
mod database;
|
||||||
mod metrics;
|
mod metrics;
|
||||||
mod proposer_duties;
|
mod proposer_duties;
|
||||||
@ -33,6 +34,7 @@ use beacon_chain::{
|
|||||||
};
|
};
|
||||||
use beacon_processor::BeaconProcessorSend;
|
use beacon_processor::BeaconProcessorSend;
|
||||||
pub use block_id::BlockId;
|
pub use block_id::BlockId;
|
||||||
|
use builder_states::get_next_withdrawals;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use directory::DEFAULT_ROOT_DIR;
|
use directory::DEFAULT_ROOT_DIR;
|
||||||
use eth2::types::{
|
use eth2::types::{
|
||||||
@ -2332,6 +2334,60 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* builder/states
|
||||||
|
*/
|
||||||
|
|
||||||
|
let builder_states_path = eth_v1
|
||||||
|
.and(warp::path("builder"))
|
||||||
|
.and(warp::path("states"))
|
||||||
|
.and(chain_filter.clone());
|
||||||
|
|
||||||
|
// GET builder/states/{state_id}/expected_withdrawals
|
||||||
|
let get_expected_withdrawals = builder_states_path
|
||||||
|
.clone()
|
||||||
|
.and(task_spawner_filter.clone())
|
||||||
|
.and(warp::path::param::<StateId>())
|
||||||
|
.and(warp::path("expected_withdrawals"))
|
||||||
|
.and(warp::query::<api_types::ExpectedWithdrawalsQuery>())
|
||||||
|
.and(warp::path::end())
|
||||||
|
.and(warp::header::optional::<api_types::Accept>("accept"))
|
||||||
|
.then(
|
||||||
|
|chain: Arc<BeaconChain<T>>,
|
||||||
|
task_spawner: TaskSpawner<T::EthSpec>,
|
||||||
|
state_id: StateId,
|
||||||
|
query: api_types::ExpectedWithdrawalsQuery,
|
||||||
|
accept_header: Option<api_types::Accept>| {
|
||||||
|
task_spawner.blocking_response_task(Priority::P1, move || {
|
||||||
|
let (state, execution_optimistic, finalized) = state_id.state(&chain)?;
|
||||||
|
let proposal_slot = query.proposal_slot.unwrap_or(state.slot() + 1);
|
||||||
|
let withdrawals =
|
||||||
|
get_next_withdrawals::<T>(&chain, state, state_id, proposal_slot)?;
|
||||||
|
|
||||||
|
match accept_header {
|
||||||
|
Some(api_types::Accept::Ssz) => Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("Content-Type", "application/octet-stream")
|
||||||
|
.body(withdrawals.as_ssz_bytes().into())
|
||||||
|
.map_err(|e| {
|
||||||
|
warp_utils::reject::custom_server_error(format!(
|
||||||
|
"failed to create response: {}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
_ => Ok(warp::reply::json(
|
||||||
|
&api_types::ExecutionOptimisticFinalizedResponse {
|
||||||
|
data: withdrawals,
|
||||||
|
execution_optimistic: Some(execution_optimistic),
|
||||||
|
finalized: Some(finalized),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.into_response()),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* beacon/rewards
|
* beacon/rewards
|
||||||
*/
|
*/
|
||||||
@ -4529,6 +4585,7 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
.uor(get_lighthouse_block_packing_efficiency)
|
.uor(get_lighthouse_block_packing_efficiency)
|
||||||
.uor(get_lighthouse_merge_readiness)
|
.uor(get_lighthouse_merge_readiness)
|
||||||
.uor(get_events)
|
.uor(get_events)
|
||||||
|
.uor(get_expected_withdrawals)
|
||||||
.uor(lighthouse_log_events.boxed())
|
.uor(lighthouse_log_events.boxed())
|
||||||
.recover(warp_utils::reject::handle_rejection),
|
.recover(warp_utils::reject::handle_rejection),
|
||||||
)
|
)
|
||||||
|
@ -28,6 +28,7 @@ use sensitive_url::SensitiveUrl;
|
|||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use state_processing::per_block_processing::get_expected_withdrawals;
|
use state_processing::per_block_processing::get_expected_withdrawals;
|
||||||
use state_processing::per_slot_processing;
|
use state_processing::per_slot_processing;
|
||||||
|
use state_processing::state_advance::partial_state_advance;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::time::Duration;
|
use tokio::time::Duration;
|
||||||
@ -4443,6 +4444,72 @@ impl ApiTester {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn test_get_expected_withdrawals_invalid_state(self) -> Self {
|
||||||
|
let state_id = CoreStateId::Root(Hash256::zero());
|
||||||
|
|
||||||
|
let result = self.client.get_expected_withdrawals(&state_id).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(e) => {
|
||||||
|
assert_eq!(e.status().unwrap(), 404);
|
||||||
|
}
|
||||||
|
_ => panic!("query did not fail correctly"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_get_expected_withdrawals_capella(self) -> Self {
|
||||||
|
let slot = self.chain.slot().unwrap();
|
||||||
|
let state_id = CoreStateId::Slot(slot);
|
||||||
|
|
||||||
|
// calculate the expected withdrawals
|
||||||
|
let (mut state, _, _) = StateId(state_id).state(&self.chain).unwrap();
|
||||||
|
let proposal_slot = state.slot() + 1;
|
||||||
|
let proposal_epoch = proposal_slot.epoch(E::slots_per_epoch());
|
||||||
|
let (state_root, _, _) = StateId(state_id).root(&self.chain).unwrap();
|
||||||
|
if proposal_epoch != state.current_epoch() {
|
||||||
|
let _ = partial_state_advance(
|
||||||
|
&mut state,
|
||||||
|
Some(state_root),
|
||||||
|
proposal_slot,
|
||||||
|
&self.chain.spec,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let expected_withdrawals = get_expected_withdrawals(&state, &self.chain.spec).unwrap();
|
||||||
|
|
||||||
|
// fetch expected withdrawals from the client
|
||||||
|
let result = self.client.get_expected_withdrawals(&state_id).await;
|
||||||
|
match result {
|
||||||
|
Ok(withdrawal_response) => {
|
||||||
|
assert_eq!(withdrawal_response.execution_optimistic, Some(false));
|
||||||
|
assert_eq!(withdrawal_response.finalized, Some(false));
|
||||||
|
assert_eq!(withdrawal_response.data, expected_withdrawals.to_vec());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{:?}", e);
|
||||||
|
panic!("query failed incorrectly");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_get_expected_withdrawals_pre_capella(self) -> Self {
|
||||||
|
let state_id = CoreStateId::Head;
|
||||||
|
|
||||||
|
let result = self.client.get_expected_withdrawals(&state_id).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Err(e) => {
|
||||||
|
assert_eq!(e.status().unwrap(), 400);
|
||||||
|
}
|
||||||
|
_ => panic!("query did not fail correctly"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test_get_events_altair(self) -> Self {
|
pub async fn test_get_events_altair(self) -> Self {
|
||||||
let topics = vec![EventTopic::ContributionAndProof];
|
let topics = vec![EventTopic::ContributionAndProof];
|
||||||
let mut events_future = self
|
let mut events_future = self
|
||||||
@ -5245,3 +5312,37 @@ async fn optimistic_responses() {
|
|||||||
.test_check_optimistic_responses()
|
.test_check_optimistic_responses()
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn expected_withdrawals_invalid_pre_capella() {
|
||||||
|
let mut config = ApiTesterConfig::default();
|
||||||
|
config.spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
ApiTester::new_from_config(config)
|
||||||
|
.await
|
||||||
|
.test_get_expected_withdrawals_pre_capella()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn expected_withdrawals_invalid_state() {
|
||||||
|
let mut config = ApiTesterConfig::default();
|
||||||
|
config.spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||||
|
config.spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||||
|
ApiTester::new_from_config(config)
|
||||||
|
.await
|
||||||
|
.test_get_expected_withdrawals_invalid_state()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn expected_withdrawals_valid_capella() {
|
||||||
|
let mut config = ApiTesterConfig::default();
|
||||||
|
config.spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||||
|
config.spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||||
|
ApiTester::new_from_config(config)
|
||||||
|
.await
|
||||||
|
.test_get_expected_withdrawals_capella()
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
@ -1289,6 +1289,23 @@ impl BeaconNodeHttpClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET builder/states/{state_id}/expected_withdrawals
|
||||||
|
pub async fn get_expected_withdrawals(
|
||||||
|
&self,
|
||||||
|
state_id: &StateId,
|
||||||
|
) -> Result<ExecutionOptimisticFinalizedResponse<Vec<Withdrawal>>, Error> {
|
||||||
|
let mut path = self.eth_path(V1)?;
|
||||||
|
|
||||||
|
path.path_segments_mut()
|
||||||
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||||
|
.push("builder")
|
||||||
|
.push("states")
|
||||||
|
.push(&state_id.to_string())
|
||||||
|
.push("expected_withdrawals");
|
||||||
|
|
||||||
|
self.get(path).await
|
||||||
|
}
|
||||||
|
|
||||||
/// `POST validator/contribution_and_proofs`
|
/// `POST validator/contribution_and_proofs`
|
||||||
pub async fn post_validator_contribution_and_proofs<T: EthSpec>(
|
pub async fn post_validator_contribution_and_proofs<T: EthSpec>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -586,6 +586,11 @@ pub struct SyncingData {
|
|||||||
pub sync_distance: Slot,
|
pub sync_distance: Slot,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct ExpectedWithdrawalsQuery {
|
||||||
|
pub proposal_slot: Option<Slot>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Deserialize)]
|
||||||
#[serde(try_from = "String", bound = "T: FromStr")]
|
#[serde(try_from = "String", bound = "T: FromStr")]
|
||||||
pub struct QueryVec<T: FromStr> {
|
pub struct QueryVec<T: FromStr> {
|
||||||
|
Loading…
Reference in New Issue
Block a user