Implement SSZ decoding for SignedBlockContents
(#4744)
* Implement `SignedBlockContent` decoding and fixed bug in `SignedBlockContent::new` * Update Cargo.lock file * Use `make_genesis_spec` to simplify test setup. * Fix syntax errors.
This commit is contained in:
parent
5f98a7b8ad
commit
665334e936
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -753,7 +753,7 @@ version = "0.66.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
|
checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.3.3",
|
"bitflags 2.4.0",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
"clang-sys",
|
"clang-sys",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -6165,7 +6165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
|
checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.28",
|
"syn 2.0.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -6,6 +6,7 @@ use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStat
|
|||||||
use mediatype::{names, MediaType, MediaTypeList};
|
use mediatype::{names, MediaType, MediaTypeList};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use ssz::{Decode, DecodeError};
|
||||||
use ssz_derive::Encode;
|
use ssz_derive::Encode;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
@ -1356,6 +1357,8 @@ pub mod serde_status_code {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ssz::Encode;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn query_vec() {
|
fn query_vec() {
|
||||||
@ -1390,6 +1393,78 @@ mod tests {
|
|||||||
Accept::Any
|
Accept::Any
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ssz_signed_block_contents_pre_deneb() {
|
||||||
|
type E = MainnetEthSpec;
|
||||||
|
let spec = ForkName::Capella.make_genesis_spec(E::default_spec());
|
||||||
|
|
||||||
|
let block: SignedBlockContents<E, FullPayload<E>> = SignedBeaconBlock::from_block(
|
||||||
|
BeaconBlock::<E>::Capella(BeaconBlockCapella::empty(&spec)),
|
||||||
|
Signature::empty(),
|
||||||
|
)
|
||||||
|
.try_into()
|
||||||
|
.expect("should convert into signed block contents");
|
||||||
|
|
||||||
|
let decoded: SignedBlockContents<E> =
|
||||||
|
SignedBlockContents::from_ssz_bytes(&block.as_ssz_bytes(), &spec)
|
||||||
|
.expect("should decode Block");
|
||||||
|
assert!(matches!(decoded, SignedBlockContents::Block(_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ssz_signed_block_contents_with_blobs() {
|
||||||
|
type E = MainnetEthSpec;
|
||||||
|
let spec = ForkName::Deneb.make_genesis_spec(E::default_spec());
|
||||||
|
|
||||||
|
let block = SignedBeaconBlock::from_block(
|
||||||
|
BeaconBlock::<E>::Deneb(BeaconBlockDeneb::empty(&spec)),
|
||||||
|
Signature::empty(),
|
||||||
|
);
|
||||||
|
let blobs = SignedSidecarList::from(vec![SignedSidecar {
|
||||||
|
message: Arc::new(BlobSidecar::empty()),
|
||||||
|
signature: Signature::empty(),
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}]);
|
||||||
|
let signed_block_contents = SignedBlockContents::new(block, Some(blobs));
|
||||||
|
|
||||||
|
let decoded: SignedBlockContents<E, FullPayload<E>> =
|
||||||
|
SignedBlockContents::from_ssz_bytes(&signed_block_contents.as_ssz_bytes(), &spec)
|
||||||
|
.expect("should decode BlockAndBlobSidecars");
|
||||||
|
assert!(matches!(
|
||||||
|
decoded,
|
||||||
|
SignedBlockContents::BlockAndBlobSidecars(_)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ssz_signed_blinded_block_contents_with_blobs() {
|
||||||
|
type E = MainnetEthSpec;
|
||||||
|
let mut spec = E::default_spec();
|
||||||
|
spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||||
|
spec.deneb_fork_epoch = Some(Epoch::new(0));
|
||||||
|
|
||||||
|
let blinded_block = SignedBeaconBlock::from_block(
|
||||||
|
BeaconBlock::<E, BlindedPayload<E>>::Deneb(BeaconBlockDeneb::empty(&spec)),
|
||||||
|
Signature::empty(),
|
||||||
|
);
|
||||||
|
let blinded_blobs = SignedSidecarList::from(vec![SignedSidecar {
|
||||||
|
message: Arc::new(BlindedBlobSidecar::empty()),
|
||||||
|
signature: Signature::empty(),
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}]);
|
||||||
|
let signed_block_contents = SignedBlockContents::new(blinded_block, Some(blinded_blobs));
|
||||||
|
|
||||||
|
let decoded: SignedBlockContents<E, BlindedPayload<E>> =
|
||||||
|
SignedBlockContents::from_ssz_bytes(&signed_block_contents.as_ssz_bytes(), &spec)
|
||||||
|
.expect("should decode BlindedBlockAndBlobSidecars");
|
||||||
|
assert!(matches!(
|
||||||
|
decoded,
|
||||||
|
SignedBlockContents::BlindedBlockAndBlobSidecars(_)
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper over a [`BeaconBlock`] or a [`BeaconBlockAndBlobSidecars`].
|
/// A wrapper over a [`BeaconBlock`] or a [`BeaconBlockAndBlobSidecars`].
|
||||||
@ -1524,13 +1599,13 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> SignedBlockContents<T, Payload
|
|||||||
blobs: Option<SignedSidecarList<T, Payload::Sidecar>>,
|
blobs: Option<SignedSidecarList<T, Payload::Sidecar>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match (Payload::block_type(), blobs) {
|
match (Payload::block_type(), blobs) {
|
||||||
(BlockType::Blinded, Some(blobs)) => {
|
(BlockType::Full, Some(blobs)) => {
|
||||||
Self::BlockAndBlobSidecars(SignedBeaconBlockAndBlobSidecars {
|
Self::BlockAndBlobSidecars(SignedBeaconBlockAndBlobSidecars {
|
||||||
signed_block: block,
|
signed_block: block,
|
||||||
signed_blob_sidecars: blobs,
|
signed_blob_sidecars: blobs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(BlockType::Full, Some(blobs)) => {
|
(BlockType::Blinded, Some(blobs)) => {
|
||||||
Self::BlindedBlockAndBlobSidecars(SignedBlindedBeaconBlockAndBlobSidecars {
|
Self::BlindedBlockAndBlobSidecars(SignedBlindedBeaconBlockAndBlobSidecars {
|
||||||
signed_blinded_block: block,
|
signed_blinded_block: block,
|
||||||
signed_blinded_blob_sidecars: blobs,
|
signed_blinded_blob_sidecars: blobs,
|
||||||
@ -1542,9 +1617,34 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> SignedBlockContents<T, Payload
|
|||||||
|
|
||||||
/// SSZ decode with fork variant determined by slot.
|
/// SSZ decode with fork variant determined by slot.
|
||||||
pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result<Self, ssz::DecodeError> {
|
pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result<Self, ssz::DecodeError> {
|
||||||
// FIXME(jimmy): SSZ decode not implemented for `SignedBeaconBlockAndBlobSidecars`
|
let slot_len = <Slot as Decode>::ssz_fixed_len();
|
||||||
SignedBeaconBlock::from_ssz_bytes(bytes, spec)
|
let slot_bytes = bytes
|
||||||
.map(|block| SignedBlockContents::Block(block))
|
.get(0..slot_len)
|
||||||
|
.ok_or(DecodeError::InvalidByteLength {
|
||||||
|
len: bytes.len(),
|
||||||
|
expected: slot_len,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
||||||
|
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
||||||
|
|
||||||
|
match fork_at_slot {
|
||||||
|
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||||
|
SignedBeaconBlock::from_ssz_bytes(bytes, spec)
|
||||||
|
.map(|block| SignedBlockContents::Block(block))
|
||||||
|
}
|
||||||
|
ForkName::Deneb => {
|
||||||
|
let mut builder = ssz::SszDecoderBuilder::new(bytes);
|
||||||
|
builder.register_anonymous_variable_length_item()?;
|
||||||
|
builder.register_type::<SignedSidecarList<T, Payload::Sidecar>>()?;
|
||||||
|
|
||||||
|
let mut decoder = builder.build()?;
|
||||||
|
let block = decoder
|
||||||
|
.decode_next_with(|bytes| SignedBeaconBlock::from_ssz_bytes(bytes, spec))?;
|
||||||
|
let blobs = decoder.decode_next()?;
|
||||||
|
Ok(SignedBlockContents::new(block, Some(blobs)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signed_block(&self) -> &SignedBeaconBlock<T, Payload> {
|
pub fn signed_block(&self) -> &SignedBeaconBlock<T, Payload> {
|
||||||
@ -1669,23 +1769,7 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> From<SignedBlockContentsTuple<
|
|||||||
for SignedBlockContents<T, Payload>
|
for SignedBlockContents<T, Payload>
|
||||||
{
|
{
|
||||||
fn from(block_contents_tuple: SignedBlockContentsTuple<T, Payload>) -> Self {
|
fn from(block_contents_tuple: SignedBlockContentsTuple<T, Payload>) -> Self {
|
||||||
match block_contents_tuple {
|
SignedBlockContents::new(block_contents_tuple.0, block_contents_tuple.1)
|
||||||
(signed_block, None) => SignedBlockContents::Block(signed_block),
|
|
||||||
(signed_block, Some(signed_blob_sidecars)) => match Payload::block_type() {
|
|
||||||
BlockType::Blinded => SignedBlockContents::BlindedBlockAndBlobSidecars(
|
|
||||||
SignedBlindedBeaconBlockAndBlobSidecars {
|
|
||||||
signed_blinded_block: signed_block,
|
|
||||||
signed_blinded_blob_sidecars: signed_blob_sidecars,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
BlockType::Full => {
|
|
||||||
SignedBlockContents::BlockAndBlobSidecars(SignedBeaconBlockAndBlobSidecars {
|
|
||||||
signed_block,
|
|
||||||
signed_blob_sidecars,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +197,21 @@ pub struct BlindedBlobSidecar {
|
|||||||
pub kzg_proof: KzgProof,
|
pub kzg_proof: KzgProof,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BlindedBlobSidecar {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
block_root: Hash256::zero(),
|
||||||
|
index: 0,
|
||||||
|
slot: Slot::new(0),
|
||||||
|
block_parent_root: Hash256::zero(),
|
||||||
|
proposer_index: 0,
|
||||||
|
blob_root: Hash256::zero(),
|
||||||
|
kzg_commitment: KzgCommitment::empty_for_testing(),
|
||||||
|
kzg_proof: KzgProof::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SignedRoot for BlindedBlobSidecar {}
|
impl SignedRoot for BlindedBlobSidecar {}
|
||||||
|
|
||||||
pub type SidecarList<T, Sidecar> = VariableList<Arc<Sidecar>, <T as EthSpec>::MaxBlobsPerBlock>;
|
pub type SidecarList<T, Sidecar> = VariableList<Arc<Sidecar>, <T as EthSpec>::MaxBlobsPerBlock>;
|
||||||
|
Loading…
Reference in New Issue
Block a user