Do not skip Block::id during ser/de

Block.id is a necessary piece of information in the context
of the consensus engine since there it's not possible to recover
the id of the block since the contents are not available.
Instead, we should only skip that field when serializing/deserializing
a full block.
This commit is contained in:
Giacomo Pasini 2023-11-02 15:16:37 +01:00
parent ea1862864b
commit c5d5983ab5
No known key found for this signature in database
GPG Key ID: FC08489D2D895D4B
3 changed files with 85 additions and 5 deletions

View File

@ -103,7 +103,6 @@ impl TimeoutQc {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct Block {
#[cfg_attr(feature = "serde", serde(skip))]
pub id: BlockId,
pub view: View,
pub parent_qc: Qc,

View File

@ -6,17 +6,19 @@ use indexmap::IndexSet;
use core::hash::Hash;
// crates
use crate::wire;
use ::serde::{
de::{DeserializeOwned, Deserializer},
Deserialize, Serialize, Serializer,
};
use bytes::Bytes;
pub use consensus_engine::BlockId;
use consensus_engine::{LeaderProof, NodeId, Qc, View};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
// internal
pub type TxHash = [u8; 32];
/// A block
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug)]
pub struct Block<Tx: Clone + Eq + Hash, BlobCertificate: Clone + Eq + Hash> {
header: consensus_engine::Block,
beacon: RandomBeaconState,
@ -107,3 +109,82 @@ impl<
result
}
}
mod serde {
use super::*;
// use ::serde::{de::Deserializer, Deserialize, Serialize};
/// consensus_engine::Block but without the id field, which will be computed
/// from the rest of the block.
#[derive(Serialize, Deserialize)]
struct StrippedHeader {
pub view: View,
pub parent_qc: Qc,
pub leader_proof: LeaderProof,
}
#[derive(Serialize, Deserialize)]
struct StrippedBlock<Tx: Clone + Eq + Hash, BlobCertificate: Clone + Eq + Hash> {
header: StrippedHeader,
beacon: RandomBeaconState,
cl_transactions: IndexSet<Tx>,
bl_blobs: IndexSet<BlobCertificate>,
}
impl<
'de,
Tx: Clone + Eq + Hash + Serialize + DeserializeOwned,
BlobCertificate: Clone + Eq + Hash + Serialize + DeserializeOwned,
> Deserialize<'de> for Block<Tx, BlobCertificate>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let StrippedBlock {
header,
beacon,
cl_transactions,
bl_blobs,
} = StrippedBlock::deserialize(deserializer)?;
let header = consensus_engine::Block {
id: BlockId::zeros(),
view: header.view,
parent_qc: header.parent_qc,
leader_proof: header.leader_proof,
};
let mut block = Block {
beacon,
cl_transactions,
bl_blobs,
header,
};
block.header.id = block_id_from_wire_content(&block);
Ok(block)
}
}
impl<
Tx: Clone + Eq + Hash + Serialize + DeserializeOwned,
BlobCertificate: Clone + Eq + Hash + Serialize + DeserializeOwned,
> Serialize for Block<Tx, BlobCertificate>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// TODO: zero copy serialization
let block = StrippedBlock {
header: StrippedHeader {
view: self.header.view,
parent_qc: self.header.parent_qc.clone(),
leader_proof: self.header.leader_proof.clone(),
},
beacon: self.beacon.clone(),
cl_transactions: self.cl_transactions.clone(),
bl_blobs: self.bl_blobs.clone(),
};
block.serialize(serializer)
}
}
}

View File

@ -1160,7 +1160,7 @@ mod tests {
eprintln!("{serialized}");
assert_eq!(
serialized,
r#"{"id":"0x0000000000000000000000000000000000000000000000000000000000000000","current_view":1,"highest_voted_view":-1,"local_high_qc":{"view":0,"id":"0x0000000000000000000000000000000000000000000000000000000000000000"},"safe_blocks":[["0x0000000000000000000000000000000000000000000000000000000000000000",{"view":0,"parent_qc":{"Standard":{"view":0,"id":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"leader_proof":{"LeaderId":{"leader_id":"0x0000000000000000000000000000000000000000000000000000000000000000"}}}]],"last_view_timeout_qc":null,"committed_blocks":["0x0000000000000000000000000000000000000000000000000000000000000000"]}"#
r#"{"id":"0x0000000000000000000000000000000000000000000000000000000000000000","current_view":1,"highest_voted_view":-1,"local_high_qc":{"view":0,"id":"0x0000000000000000000000000000000000000000000000000000000000000000"},"safe_blocks":[["0x0000000000000000000000000000000000000000000000000000000000000000",{"id":"0x0000000000000000000000000000000000000000000000000000000000000000","view":0,"parent_qc":{"Standard":{"view":0,"id":"0x0000000000000000000000000000000000000000000000000000000000000000"}},"leader_proof":{"LeaderId":{"leader_id":"0x0000000000000000000000000000000000000000000000000000000000000000"}}}]],"last_view_timeout_qc":null,"committed_blocks":["0x0000000000000000000000000000000000000000000000000000000000000000"]}"#
);
let deserialized: CarnotInfo = serde_json::from_str(&serialized).unwrap();