Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"crates/app",
"crates/parsigex",
"crates/build-proto",
"crates/cli",
"crates/cluster",
Expand Down Expand Up @@ -98,6 +99,7 @@ wiremock = "0.6"

# Crates in the workspace
pluto-app = { path = "crates/app" }
pluto-parsigex = { path = "crates/parasigex" }
pluto-build-proto = { path = "crates/build-proto" }
pluto-cli = { path = "crates/cli" }
pluto-cluster = { path = "crates/cluster" }
Expand Down
8 changes: 8 additions & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ cancellation.workspace = true
chrono.workspace = true
crossbeam.workspace = true
futures.workspace = true
futures-timer.workspace = true
dyn-clone.workspace = true
dyn-eq.workspace = true
hex.workspace = true
Expand All @@ -31,18 +32,25 @@ tokio-util.workspace = true
tracing.workspace = true
pluto-eth2util.workspace = true
tree_hash.workspace = true
unsigned-varint.workspace = true

[dev-dependencies]
anyhow.workspace = true
alloy.workspace = true
clap.workspace = true
rand.workspace = true
libp2p.workspace = true
k256.workspace = true
prost.workspace = true
prost-types.workspace = true
hex.workspace = true
chrono.workspace = true
test-case.workspace = true
pluto-eth2util.workspace = true
pluto-cluster.workspace = true
pluto-p2p.workspace = true
pluto-testutil.workspace = true
pluto-tracing.workspace = true

[build-dependencies]
pluto-build-proto.workspace = true
Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub mod deadline;
/// parsigdb
pub mod parsigdb;

mod parsigex_codec;

pub use parsigex_codec::ParSigExCodecError;

/// Test utilities.
#[cfg(test)]
pub mod testutils;
116 changes: 116 additions & 0 deletions crates/core/src/parsigex_codec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//! Partial signature exchange codec helpers used by core types.

use std::any::Any;

use crate::{
signeddata::{
Attestation, BeaconCommitteeSelection, SignedAggregateAndProof, SignedRandao,
SignedSyncContributionAndProof, SignedSyncMessage, SignedVoluntaryExit,
SyncCommitteeSelection, VersionedAttestation, VersionedSignedAggregateAndProof,
VersionedSignedProposal, VersionedSignedValidatorRegistration,
},
types::{DutyType, Signature, SignedData},
};

/// Error type for partial signature exchange codec operations.
#[derive(Debug, thiserror::Error)]
pub enum ParSigExCodecError {
/// Missing duty or data set fields.
#[error("invalid parsigex msg fields")]
InvalidMessageFields,

/// Invalid partial signed data set proto.
#[error("invalid partial signed data set proto fields")]
InvalidParSignedDataSetFields,

/// Invalid partial signed proto.
#[error("invalid partial signed proto")]
InvalidParSignedProto,

/// Invalid duty type.
#[error("invalid duty")]
InvalidDuty,

/// Unsupported duty type.
#[error("unsupported duty type")]
UnsupportedDutyType,

/// Deprecated builder proposer duty.
#[error("deprecated duty builder proposer")]
DeprecatedBuilderProposer,

/// Failed to parse a public key.
#[error("invalid public key: {0}")]
InvalidPubKey(String),

/// Invalid share index.
#[error("invalid share index")]
InvalidShareIndex,

/// Serialization failed.
#[error("marshal signed data: {0}")]
Serialize(#[from] serde_json::Error),
}

pub(crate) fn serialize_signed_data(data: &dyn SignedData) -> Result<Vec<u8>, ParSigExCodecError> {
let any = data as &dyn Any;

macro_rules! serialize_as {
($ty:ty) => {
if let Some(value) = any.downcast_ref::<$ty>() {
return Ok(serde_json::to_vec(value)?);
}
};
}

serialize_as!(Attestation);
serialize_as!(VersionedAttestation);
serialize_as!(VersionedSignedProposal);
serialize_as!(VersionedSignedValidatorRegistration);
serialize_as!(SignedVoluntaryExit);
serialize_as!(SignedRandao);
serialize_as!(Signature);
serialize_as!(BeaconCommitteeSelection);
serialize_as!(SignedAggregateAndProof);
serialize_as!(VersionedSignedAggregateAndProof);
serialize_as!(SignedSyncMessage);
serialize_as!(SyncCommitteeSelection);
serialize_as!(SignedSyncContributionAndProof);

Err(ParSigExCodecError::UnsupportedDutyType)
}

pub(crate) fn deserialize_signed_data(
duty_type: &DutyType,
bytes: &[u8],
) -> Result<Box<dyn SignedData>, ParSigExCodecError> {
macro_rules! deserialize_json {
($ty:ty) => {
serde_json::from_slice::<$ty>(bytes)
.map(|value| Box::new(value) as Box<dyn SignedData>)
.map_err(ParSigExCodecError::from)
};
}

match duty_type {
DutyType::Attester => deserialize_json!(VersionedAttestation)
.or_else(|_| deserialize_json!(Attestation))
.map_err(|_| ParSigExCodecError::UnsupportedDutyType),
DutyType::Proposer => deserialize_json!(VersionedSignedProposal),
DutyType::BuilderProposer => Err(ParSigExCodecError::DeprecatedBuilderProposer),
DutyType::BuilderRegistration => deserialize_json!(VersionedSignedValidatorRegistration),
DutyType::Exit => deserialize_json!(SignedVoluntaryExit),
DutyType::Randao => deserialize_json!(SignedRandao),
DutyType::Signature => deserialize_json!(Signature),
DutyType::PrepareAggregator => deserialize_json!(BeaconCommitteeSelection),
DutyType::Aggregator => deserialize_json!(VersionedSignedAggregateAndProof)
.or_else(|_| deserialize_json!(SignedAggregateAndProof))
.map_err(|_| ParSigExCodecError::UnsupportedDutyType),
DutyType::SyncMessage => deserialize_json!(SignedSyncMessage),
DutyType::PrepareSyncContribution => deserialize_json!(SyncCommitteeSelection),
DutyType::SyncContribution => deserialize_json!(SignedSyncContributionAndProof),
DutyType::Unknown | DutyType::InfoSync | DutyType::DutySentinel(_) => {
Err(ParSigExCodecError::UnsupportedDutyType)
}
}
}
Loading
Loading