## Issue Addressed Resolves #3379 ## Proposed Changes Remove instances of `InvalidTerminalBlock` in lighthouse and use `Invalid {latest_valid_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"}` to represent that status.
463 lines
14 KiB
Rust
463 lines
14 KiB
Rust
use super::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use types::{EthSpec, ExecutionBlockHash, FixedVector, Transaction, Unsigned, VariableList};
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonRequestBody<'a> {
|
|
pub jsonrpc: &'a str,
|
|
pub method: &'a str,
|
|
pub params: serde_json::Value,
|
|
pub id: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
pub struct JsonError {
|
|
pub code: i64,
|
|
pub message: String,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonResponseBody {
|
|
pub jsonrpc: String,
|
|
#[serde(default)]
|
|
pub error: Option<JsonError>,
|
|
#[serde(default)]
|
|
pub result: serde_json::Value,
|
|
pub id: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(transparent)]
|
|
pub struct TransparentJsonPayloadId(#[serde(with = "eth2_serde_utils::bytes_8_hex")] pub PayloadId);
|
|
|
|
impl From<PayloadId> for TransparentJsonPayloadId {
|
|
fn from(id: PayloadId) -> Self {
|
|
Self(id)
|
|
}
|
|
}
|
|
|
|
impl From<TransparentJsonPayloadId> for PayloadId {
|
|
fn from(wrapper: TransparentJsonPayloadId) -> Self {
|
|
wrapper.0
|
|
}
|
|
}
|
|
|
|
/// On the request, use a transparent wrapper.
|
|
pub type JsonPayloadIdRequest = TransparentJsonPayloadId;
|
|
|
|
/// On the response, expect without the object wrapper (non-transparent).
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonPayloadIdResponse {
|
|
#[serde(with = "eth2_serde_utils::bytes_8_hex")]
|
|
pub payload_id: PayloadId,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
|
|
#[serde(bound = "T: EthSpec", rename_all = "camelCase")]
|
|
pub struct JsonExecutionPayloadHeaderV1<T: EthSpec> {
|
|
pub parent_hash: ExecutionBlockHash,
|
|
pub fee_recipient: Address,
|
|
pub state_root: Hash256,
|
|
pub receipts_root: Hash256,
|
|
#[serde(with = "serde_logs_bloom")]
|
|
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
|
pub prev_randao: Hash256,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub block_number: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub gas_limit: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub gas_used: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub timestamp: u64,
|
|
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
|
|
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
|
#[serde(with = "eth2_serde_utils::u256_hex_be")]
|
|
pub base_fee_per_gas: Uint256,
|
|
pub block_hash: ExecutionBlockHash,
|
|
pub transactions_root: Hash256,
|
|
}
|
|
|
|
impl<T: EthSpec> From<JsonExecutionPayloadHeaderV1<T>> for ExecutionPayloadHeader<T> {
|
|
fn from(e: JsonExecutionPayloadHeaderV1<T>) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonExecutionPayloadHeaderV1 {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions_root,
|
|
} = e;
|
|
|
|
Self {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions_root,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Default, Serialize, Deserialize)]
|
|
#[serde(bound = "T: EthSpec", rename_all = "camelCase")]
|
|
pub struct JsonExecutionPayloadV1<T: EthSpec> {
|
|
pub parent_hash: ExecutionBlockHash,
|
|
pub fee_recipient: Address,
|
|
pub state_root: Hash256,
|
|
pub receipts_root: Hash256,
|
|
#[serde(with = "serde_logs_bloom")]
|
|
pub logs_bloom: FixedVector<u8, T::BytesPerLogsBloom>,
|
|
pub prev_randao: Hash256,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub block_number: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub gas_limit: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub gas_used: u64,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub timestamp: u64,
|
|
#[serde(with = "ssz_types::serde_utils::hex_var_list")]
|
|
pub extra_data: VariableList<u8, T::MaxExtraDataBytes>,
|
|
#[serde(with = "eth2_serde_utils::u256_hex_be")]
|
|
pub base_fee_per_gas: Uint256,
|
|
pub block_hash: ExecutionBlockHash,
|
|
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
|
pub transactions:
|
|
VariableList<Transaction<T::MaxBytesPerTransaction>, T::MaxTransactionsPerPayload>,
|
|
}
|
|
|
|
impl<T: EthSpec> From<ExecutionPayload<T>> for JsonExecutionPayloadV1<T> {
|
|
fn from(e: ExecutionPayload<T>) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let ExecutionPayload {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions,
|
|
} = e;
|
|
|
|
Self {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: EthSpec> From<JsonExecutionPayloadV1<T>> for ExecutionPayload<T> {
|
|
fn from(e: JsonExecutionPayloadV1<T>) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonExecutionPayloadV1 {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions,
|
|
} = e;
|
|
|
|
Self {
|
|
parent_hash,
|
|
fee_recipient,
|
|
state_root,
|
|
receipts_root,
|
|
logs_bloom,
|
|
prev_randao,
|
|
block_number,
|
|
gas_limit,
|
|
gas_used,
|
|
timestamp,
|
|
extra_data,
|
|
base_fee_per_gas,
|
|
block_hash,
|
|
transactions,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonPayloadAttributesV1 {
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub timestamp: u64,
|
|
pub prev_randao: Hash256,
|
|
pub suggested_fee_recipient: Address,
|
|
}
|
|
|
|
impl From<PayloadAttributes> for JsonPayloadAttributesV1 {
|
|
fn from(p: PayloadAttributes) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let PayloadAttributes {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
} = p;
|
|
|
|
Self {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<JsonPayloadAttributesV1> for PayloadAttributes {
|
|
fn from(j: JsonPayloadAttributesV1) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonPayloadAttributesV1 {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
} = j;
|
|
|
|
Self {
|
|
timestamp,
|
|
prev_randao,
|
|
suggested_fee_recipient,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonForkChoiceStateV1 {
|
|
pub head_block_hash: ExecutionBlockHash,
|
|
pub safe_block_hash: ExecutionBlockHash,
|
|
pub finalized_block_hash: ExecutionBlockHash,
|
|
}
|
|
|
|
impl From<ForkChoiceState> for JsonForkChoiceStateV1 {
|
|
fn from(f: ForkChoiceState) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let ForkChoiceState {
|
|
head_block_hash,
|
|
safe_block_hash,
|
|
finalized_block_hash,
|
|
} = f;
|
|
|
|
Self {
|
|
head_block_hash,
|
|
safe_block_hash,
|
|
finalized_block_hash,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<JsonForkChoiceStateV1> for ForkChoiceState {
|
|
fn from(j: JsonForkChoiceStateV1) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonForkChoiceStateV1 {
|
|
head_block_hash,
|
|
safe_block_hash,
|
|
finalized_block_hash,
|
|
} = j;
|
|
|
|
Self {
|
|
head_block_hash,
|
|
safe_block_hash,
|
|
finalized_block_hash,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
pub enum JsonPayloadStatusV1Status {
|
|
Valid,
|
|
Invalid,
|
|
Syncing,
|
|
Accepted,
|
|
InvalidBlockHash,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonPayloadStatusV1 {
|
|
pub status: JsonPayloadStatusV1Status,
|
|
pub latest_valid_hash: Option<ExecutionBlockHash>,
|
|
pub validation_error: Option<String>,
|
|
}
|
|
|
|
impl From<PayloadStatusV1Status> for JsonPayloadStatusV1Status {
|
|
fn from(e: PayloadStatusV1Status) -> Self {
|
|
match e {
|
|
PayloadStatusV1Status::Valid => JsonPayloadStatusV1Status::Valid,
|
|
PayloadStatusV1Status::Invalid => JsonPayloadStatusV1Status::Invalid,
|
|
PayloadStatusV1Status::Syncing => JsonPayloadStatusV1Status::Syncing,
|
|
PayloadStatusV1Status::Accepted => JsonPayloadStatusV1Status::Accepted,
|
|
PayloadStatusV1Status::InvalidBlockHash => JsonPayloadStatusV1Status::InvalidBlockHash,
|
|
}
|
|
}
|
|
}
|
|
impl From<JsonPayloadStatusV1Status> for PayloadStatusV1Status {
|
|
fn from(j: JsonPayloadStatusV1Status) -> Self {
|
|
match j {
|
|
JsonPayloadStatusV1Status::Valid => PayloadStatusV1Status::Valid,
|
|
JsonPayloadStatusV1Status::Invalid => PayloadStatusV1Status::Invalid,
|
|
JsonPayloadStatusV1Status::Syncing => PayloadStatusV1Status::Syncing,
|
|
JsonPayloadStatusV1Status::Accepted => PayloadStatusV1Status::Accepted,
|
|
JsonPayloadStatusV1Status::InvalidBlockHash => PayloadStatusV1Status::InvalidBlockHash,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<PayloadStatusV1> for JsonPayloadStatusV1 {
|
|
fn from(p: PayloadStatusV1) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let PayloadStatusV1 {
|
|
status,
|
|
latest_valid_hash,
|
|
validation_error,
|
|
} = p;
|
|
|
|
Self {
|
|
status: status.into(),
|
|
latest_valid_hash,
|
|
validation_error,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<JsonPayloadStatusV1> for PayloadStatusV1 {
|
|
fn from(j: JsonPayloadStatusV1) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonPayloadStatusV1 {
|
|
status,
|
|
latest_valid_hash,
|
|
validation_error,
|
|
} = j;
|
|
|
|
Self {
|
|
status: status.into(),
|
|
latest_valid_hash,
|
|
validation_error,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct JsonForkchoiceUpdatedV1Response {
|
|
pub payload_status: JsonPayloadStatusV1,
|
|
pub payload_id: Option<TransparentJsonPayloadId>,
|
|
}
|
|
|
|
impl From<JsonForkchoiceUpdatedV1Response> for ForkchoiceUpdatedResponse {
|
|
fn from(j: JsonForkchoiceUpdatedV1Response) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let JsonForkchoiceUpdatedV1Response {
|
|
payload_status: status,
|
|
payload_id,
|
|
} = j;
|
|
|
|
Self {
|
|
payload_status: status.into(),
|
|
payload_id: payload_id.map(Into::into),
|
|
}
|
|
}
|
|
}
|
|
impl From<ForkchoiceUpdatedResponse> for JsonForkchoiceUpdatedV1Response {
|
|
fn from(f: ForkchoiceUpdatedResponse) -> Self {
|
|
// Use this verbose deconstruction pattern to ensure no field is left unused.
|
|
let ForkchoiceUpdatedResponse {
|
|
payload_status: status,
|
|
payload_id,
|
|
} = f;
|
|
|
|
Self {
|
|
payload_status: status.into(),
|
|
payload_id: payload_id.map(Into::into),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct TransitionConfigurationV1 {
|
|
#[serde(with = "eth2_serde_utils::u256_hex_be")]
|
|
pub terminal_total_difficulty: Uint256,
|
|
pub terminal_block_hash: ExecutionBlockHash,
|
|
#[serde(with = "eth2_serde_utils::u64_hex_be")]
|
|
pub terminal_block_number: u64,
|
|
}
|
|
|
|
/// Serializes the `logs_bloom` field of an `ExecutionPayload`.
|
|
pub mod serde_logs_bloom {
|
|
use super::*;
|
|
use eth2_serde_utils::hex::PrefixedHexVisitor;
|
|
use serde::{Deserializer, Serializer};
|
|
|
|
pub fn serialize<S, U>(bytes: &FixedVector<u8, U>, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
U: Unsigned,
|
|
{
|
|
let mut hex_string: String = "0x".to_string();
|
|
hex_string.push_str(&hex::encode(&bytes[..]));
|
|
|
|
serializer.serialize_str(&hex_string)
|
|
}
|
|
|
|
pub fn deserialize<'de, D, U>(deserializer: D) -> Result<FixedVector<u8, U>, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
U: Unsigned,
|
|
{
|
|
let vec = deserializer.deserialize_string(PrefixedHexVisitor)?;
|
|
|
|
FixedVector::new(vec)
|
|
.map_err(|e| serde::de::Error::custom(format!("invalid logs bloom: {:?}", e)))
|
|
}
|
|
}
|