mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 09:16:00 +00:00
Fix builder API electra json response (#7285)
#7277 Implement `ForkVersionDeserialize` for `ExecutionPayloadAndBlobs` so we get fork hinting when deserializing
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -2615,6 +2615,7 @@ dependencies = [
|
|||||||
"mediatype",
|
"mediatype",
|
||||||
"pretty_reqwest_error",
|
"pretty_reqwest_error",
|
||||||
"proto_array",
|
"proto_array",
|
||||||
|
"rand 0.8.5",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"reqwest-eventsource",
|
"reqwest-eventsource",
|
||||||
"sensitive_url",
|
"sensitive_url",
|
||||||
@@ -2623,6 +2624,7 @@ dependencies = [
|
|||||||
"slashing_protection",
|
"slashing_protection",
|
||||||
"ssz_types",
|
"ssz_types",
|
||||||
"store",
|
"store",
|
||||||
|
"test_random_derive",
|
||||||
"tokio",
|
"tokio",
|
||||||
"types",
|
"types",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ lighthouse_network = { workspace = true }
|
|||||||
mediatype = "0.19.13"
|
mediatype = "0.19.13"
|
||||||
pretty_reqwest_error = { workspace = true }
|
pretty_reqwest_error = { workspace = true }
|
||||||
proto_array = { workspace = true }
|
proto_array = { workspace = true }
|
||||||
|
rand = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
reqwest-eventsource = "0.5.0"
|
reqwest-eventsource = "0.5.0"
|
||||||
sensitive_url = { workspace = true }
|
sensitive_url = { workspace = true }
|
||||||
@@ -26,6 +27,7 @@ serde_json = { workspace = true }
|
|||||||
slashing_protection = { workspace = true }
|
slashing_protection = { workspace = true }
|
||||||
ssz_types = { workspace = true }
|
ssz_types = { workspace = true }
|
||||||
store = { workspace = true }
|
store = { workspace = true }
|
||||||
|
test_random_derive = { path = "../../common/test_random_derive" }
|
||||||
types = { workspace = true }
|
types = { workspace = true }
|
||||||
zeroize = { workspace = true }
|
zeroize = { workspace = true }
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ use std::fmt::{self, Display};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use test_random_derive::TestRandom;
|
||||||
use types::beacon_block_body::KzgCommitments;
|
use types::beacon_block_body::KzgCommitments;
|
||||||
|
use types::test_utils::TestRandom;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
#[cfg(feature = "lighthouse")]
|
#[cfg(feature = "lighthouse")]
|
||||||
@@ -2017,11 +2019,11 @@ impl<E: EthSpec> ForkVersionDeserialize for FullPayloadContents<E> {
|
|||||||
fork_name: ForkName,
|
fork_name: ForkName,
|
||||||
) -> Result<Self, D::Error> {
|
) -> Result<Self, D::Error> {
|
||||||
if fork_name.deneb_enabled() {
|
if fork_name.deneb_enabled() {
|
||||||
serde_json::from_value(value)
|
ExecutionPayloadAndBlobs::deserialize_by_fork::<'de, D>(value, fork_name)
|
||||||
.map(Self::PayloadAndBlobs)
|
.map(Self::PayloadAndBlobs)
|
||||||
.map_err(serde::de::Error::custom)
|
.map_err(serde::de::Error::custom)
|
||||||
} else if fork_name.bellatrix_enabled() {
|
} else if fork_name.bellatrix_enabled() {
|
||||||
serde_json::from_value(value)
|
ExecutionPayload::deserialize_by_fork::<'de, D>(value, fork_name)
|
||||||
.map(Self::Payload)
|
.map(Self::Payload)
|
||||||
.map_err(serde::de::Error::custom)
|
.map_err(serde::de::Error::custom)
|
||||||
} else {
|
} else {
|
||||||
@@ -2039,6 +2041,28 @@ pub struct ExecutionPayloadAndBlobs<E: EthSpec> {
|
|||||||
pub blobs_bundle: BlobsBundle<E>,
|
pub blobs_bundle: BlobsBundle<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> ForkVersionDeserialize for ExecutionPayloadAndBlobs<E> {
|
||||||
|
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||||
|
value: Value,
|
||||||
|
fork_name: ForkName,
|
||||||
|
) -> Result<Self, D::Error> {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(bound = "E: EthSpec")]
|
||||||
|
struct Helper<E: EthSpec> {
|
||||||
|
execution_payload: serde_json::Value,
|
||||||
|
blobs_bundle: BlobsBundle<E>,
|
||||||
|
}
|
||||||
|
let helper: Helper<E> = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
|
||||||
|
Ok(Self {
|
||||||
|
execution_payload: ExecutionPayload::deserialize_by_fork::<'de, D>(
|
||||||
|
helper.execution_payload,
|
||||||
|
fork_name,
|
||||||
|
)?,
|
||||||
|
blobs_bundle: helper.blobs_bundle,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> ForkVersionDecode for ExecutionPayloadAndBlobs<E> {
|
impl<E: EthSpec> ForkVersionDecode for ExecutionPayloadAndBlobs<E> {
|
||||||
fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result<Self, DecodeError> {
|
fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result<Self, DecodeError> {
|
||||||
let mut builder = ssz::SszDecoderBuilder::new(bytes);
|
let mut builder = ssz::SszDecoderBuilder::new(bytes);
|
||||||
@@ -2069,7 +2093,7 @@ pub enum ContentType {
|
|||||||
Ssz,
|
Ssz,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode, Decode)]
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
|
||||||
#[serde(bound = "E: EthSpec")]
|
#[serde(bound = "E: EthSpec")]
|
||||||
pub struct BlobsBundle<E: EthSpec> {
|
pub struct BlobsBundle<E: EthSpec> {
|
||||||
pub commitments: KzgCommitments<E>,
|
pub commitments: KzgCommitments<E>,
|
||||||
@@ -2080,6 +2104,10 @@ pub struct BlobsBundle<E: EthSpec> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2093,4 +2121,107 @@ mod test {
|
|||||||
let y: ValidatorId = serde_json::from_str(pubkey_str).unwrap();
|
let y: ValidatorId = serde_json::from_str(pubkey_str).unwrap();
|
||||||
assert_eq!(serde_json::to_string(&y).unwrap(), pubkey_str);
|
assert_eq!(serde_json::to_string(&y).unwrap(), pubkey_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_execution_payload_execution_payload_deserialize_by_fork() {
|
||||||
|
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||||
|
|
||||||
|
let payloads = [
|
||||||
|
ExecutionPayload::Bellatrix(
|
||||||
|
ExecutionPayloadBellatrix::<MainnetEthSpec>::random_for_test(rng),
|
||||||
|
),
|
||||||
|
ExecutionPayload::Capella(ExecutionPayloadCapella::<MainnetEthSpec>::random_for_test(
|
||||||
|
rng,
|
||||||
|
)),
|
||||||
|
ExecutionPayload::Deneb(ExecutionPayloadDeneb::<MainnetEthSpec>::random_for_test(
|
||||||
|
rng,
|
||||||
|
)),
|
||||||
|
ExecutionPayload::Electra(ExecutionPayloadElectra::<MainnetEthSpec>::random_for_test(
|
||||||
|
rng,
|
||||||
|
)),
|
||||||
|
ExecutionPayload::Fulu(ExecutionPayloadFulu::<MainnetEthSpec>::random_for_test(rng)),
|
||||||
|
];
|
||||||
|
let merged_forks = &ForkName::list_all()[2..];
|
||||||
|
assert_eq!(
|
||||||
|
payloads.len(),
|
||||||
|
merged_forks.len(),
|
||||||
|
"we should test every known fork; add new fork variant to payloads above"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (payload, &fork_name) in payloads.into_iter().zip(merged_forks) {
|
||||||
|
assert_eq!(payload.fork_name(), fork_name);
|
||||||
|
let payload_str = serde_json::to_string(&payload).unwrap();
|
||||||
|
let mut de = serde_json::Deserializer::from_str(&payload_str);
|
||||||
|
generic_deserialize_by_fork(&mut de, payload, fork_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_execution_payload_and_blobs_deserialize_by_fork() {
|
||||||
|
let rng = &mut XorShiftRng::from_seed([42; 16]);
|
||||||
|
|
||||||
|
let payloads = [
|
||||||
|
{
|
||||||
|
let execution_payload =
|
||||||
|
ExecutionPayload::Deneb(
|
||||||
|
ExecutionPayloadDeneb::<MainnetEthSpec>::random_for_test(rng),
|
||||||
|
);
|
||||||
|
let blobs_bundle = BlobsBundle::random_for_test(rng);
|
||||||
|
ExecutionPayloadAndBlobs {
|
||||||
|
execution_payload,
|
||||||
|
blobs_bundle,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let execution_payload =
|
||||||
|
ExecutionPayload::Electra(
|
||||||
|
ExecutionPayloadElectra::<MainnetEthSpec>::random_for_test(rng),
|
||||||
|
);
|
||||||
|
let blobs_bundle = BlobsBundle::random_for_test(rng);
|
||||||
|
ExecutionPayloadAndBlobs {
|
||||||
|
execution_payload,
|
||||||
|
blobs_bundle,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let execution_payload =
|
||||||
|
ExecutionPayload::Fulu(
|
||||||
|
ExecutionPayloadFulu::<MainnetEthSpec>::random_for_test(rng),
|
||||||
|
);
|
||||||
|
let blobs_bundle = BlobsBundle::random_for_test(rng);
|
||||||
|
ExecutionPayloadAndBlobs {
|
||||||
|
execution_payload,
|
||||||
|
blobs_bundle,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let blob_forks = &ForkName::list_all()[4..];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payloads.len(),
|
||||||
|
blob_forks.len(),
|
||||||
|
"we should test every known fork; add new fork variant to payloads above"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (payload, &fork_name) in payloads.into_iter().zip(blob_forks) {
|
||||||
|
assert_eq!(payload.execution_payload.fork_name(), fork_name);
|
||||||
|
let payload_str = serde_json::to_string(&payload).unwrap();
|
||||||
|
let mut de = serde_json::Deserializer::from_str(&payload_str);
|
||||||
|
generic_deserialize_by_fork(&mut de, payload, fork_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generic_deserialize_by_fork<
|
||||||
|
'de,
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
O: ForkVersionDeserialize + PartialEq + Debug,
|
||||||
|
>(
|
||||||
|
deserializer: D,
|
||||||
|
original: O,
|
||||||
|
fork_name: ForkName,
|
||||||
|
) {
|
||||||
|
let val = Value::deserialize(deserializer).unwrap();
|
||||||
|
let roundtrip = O::deserialize_by_fork::<'de, D>(val, fork_name).unwrap();
|
||||||
|
assert_eq!(original, roundtrip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user