From c493d832e33704f98f297bd3ea63ce77e19c7b79 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 6 Apr 2023 14:53:58 +0200 Subject: [PATCH] fix: always serialize validationError (#2139) --- .../rpc/rpc-types/src/eth/engine/payload.rs | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/crates/rpc/rpc-types/src/eth/engine/payload.rs b/crates/rpc/rpc-types/src/eth/engine/payload.rs index 2844e874dc..6f9fe95fdc 100644 --- a/crates/rpc/rpc-types/src/eth/engine/payload.rs +++ b/crates/rpc/rpc-types/src/eth/engine/payload.rs @@ -5,7 +5,7 @@ use reth_primitives::{ H256, U256, U64, }; use reth_rlp::{Decodable, Encodable}; -use serde::{Deserialize, Serialize}; +use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer}; /// This structure maps on the ExecutionPayload structure of the beacon chain spec. /// @@ -199,7 +199,7 @@ pub struct PayloadAttributes { } /// This structure contains the result of processing a payload -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PayloadStatus { #[serde(flatten)] @@ -223,6 +223,19 @@ impl PayloadStatus { } } +impl Serialize for PayloadStatus { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(3))?; + map.serialize_entry("status", self.status.as_str())?; + map.serialize_entry("latestValidHash", &self.latest_valid_hash)?; + map.serialize_entry("validationError", &self.status.validation_error())?; + map.end() + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "status", rename_all = "SCREAMING_SNAKE_CASE")] pub enum PayloadStatusEnum { @@ -253,6 +266,28 @@ pub enum PayloadStatusEnum { }, } +impl PayloadStatusEnum { + /// Returns the string representation of the payload status. + pub fn as_str(&self) -> &'static str { + match self { + PayloadStatusEnum::Valid => "VALID", + PayloadStatusEnum::Invalid { .. } => "INVALID", + PayloadStatusEnum::Syncing => "SYNCING", + PayloadStatusEnum::Accepted => "ACCEPTED", + PayloadStatusEnum::InvalidBlockHash { .. } => "INVALID_BLOCK_HASH", + } + } + + /// Returns the validation error if the payload status is invalid. + pub fn validation_error(&self) -> Option<&str> { + match self { + PayloadStatusEnum::InvalidBlockHash { validation_error } | + PayloadStatusEnum::Invalid { validation_error } => Some(validation_error), + _ => None, + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -378,4 +413,22 @@ mod tests { let valid_block = block; assert_matches!(TryInto::::try_into(valid_block), Ok(_)); } + + #[test] + fn serde_payload_status() { + let s = r#"{"status":"SYNCING","latestValidHash":null,"validationError":null}"#; + let status: PayloadStatus = serde_json::from_str(s).unwrap(); + assert_eq!(status.status, PayloadStatusEnum::Syncing); + assert!(status.latest_valid_hash.is_none()); + assert!(status.status.validation_error().is_none()); + assert_eq!(serde_json::to_string(&status).unwrap(), s); + + let full = s; + let s = r#"{"status":"SYNCING","latestValidHash":null}"#; + let status: PayloadStatus = serde_json::from_str(s).unwrap(); + assert_eq!(status.status, PayloadStatusEnum::Syncing); + assert!(status.latest_valid_hash.is_none()); + assert!(status.status.validation_error().is_none()); + assert_eq!(serde_json::to_string(&status).unwrap(), full); + } }