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"
|
||||
checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"bitflags 2.4.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
@ -6165,7 +6165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.28",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6,6 +6,7 @@ use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStat
|
||||
use mediatype::{names, MediaType, MediaTypeList};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use ssz::{Decode, DecodeError};
|
||||
use ssz_derive::Encode;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display};
|
||||
@ -1356,6 +1357,8 @@ pub mod serde_status_code {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ssz::Encode;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn query_vec() {
|
||||
@ -1390,6 +1393,78 @@ mod tests {
|
||||
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`].
|
||||
@ -1524,13 +1599,13 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> SignedBlockContents<T, Payload
|
||||
blobs: Option<SignedSidecarList<T, Payload::Sidecar>>,
|
||||
) -> Self {
|
||||
match (Payload::block_type(), blobs) {
|
||||
(BlockType::Blinded, Some(blobs)) => {
|
||||
(BlockType::Full, Some(blobs)) => {
|
||||
Self::BlockAndBlobSidecars(SignedBeaconBlockAndBlobSidecars {
|
||||
signed_block: block,
|
||||
signed_blob_sidecars: blobs,
|
||||
})
|
||||
}
|
||||
(BlockType::Full, Some(blobs)) => {
|
||||
(BlockType::Blinded, Some(blobs)) => {
|
||||
Self::BlindedBlockAndBlobSidecars(SignedBlindedBeaconBlockAndBlobSidecars {
|
||||
signed_blinded_block: block,
|
||||
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.
|
||||
pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result<Self, ssz::DecodeError> {
|
||||
// FIXME(jimmy): SSZ decode not implemented for `SignedBeaconBlockAndBlobSidecars`
|
||||
SignedBeaconBlock::from_ssz_bytes(bytes, spec)
|
||||
.map(|block| SignedBlockContents::Block(block))
|
||||
let slot_len = <Slot as Decode>::ssz_fixed_len();
|
||||
let slot_bytes = bytes
|
||||
.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> {
|
||||
@ -1669,23 +1769,7 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> From<SignedBlockContentsTuple<
|
||||
for SignedBlockContents<T, Payload>
|
||||
{
|
||||
fn from(block_contents_tuple: SignedBlockContentsTuple<T, Payload>) -> Self {
|
||||
match block_contents_tuple {
|
||||
(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,
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
SignedBlockContents::new(block_contents_tuple.0, block_contents_tuple.1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,21 @@ pub struct BlindedBlobSidecar {
|
||||
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 {}
|
||||
|
||||
pub type SidecarList<T, Sidecar> = VariableList<Arc<Sidecar>, <T as EthSpec>::MaxBlobsPerBlock>;
|
||||
|
Loading…
Reference in New Issue
Block a user