Skip to content

Commit

Permalink
Merge branch 'unstable' into peer-store
Browse files Browse the repository at this point in the history
  • Loading branch information
dknopik committed Feb 20, 2025
2 parents dc4a881 + f027e46 commit 55a6a60
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 52 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions anchor/common/ssv_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = { workspace = true }
authors = ["Sigma Prime <contact@sigmaprime.io>"]

[dependencies]
alloy = { workspace = true }
base64 = { workspace = true }
derive_more = { workspace = true }
ethereum_ssz = { workspace = true }
Expand Down
9 changes: 9 additions & 0 deletions anchor/common/ssv_types/src/cluster.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::committee::CommitteeId;
use crate::OperatorId;
use derive_more::{Deref, From};
use indexmap::IndexSet;
Expand Down Expand Up @@ -36,6 +37,14 @@ impl Cluster {
pub fn get_f(&self) -> u64 {
(self.cluster_members.len().saturating_sub(1) / 3) as u64
}

pub fn committee_id(&self) -> CommitteeId {
self.cluster_members
.iter()
.cloned()
.collect::<Vec<_>>()
.into()
}
}

/// A member of a Cluster.
Expand Down
33 changes: 33 additions & 0 deletions anchor/common/ssv_types/src/committee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::OperatorId;
use alloy::primitives::keccak256;
use derive_more::{Deref, From};

const COMMITTEE_ID_LEN: usize = 32;

/// Unique identifier for a committee
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, From, Deref)]
pub struct CommitteeId(pub [u8; COMMITTEE_ID_LEN]);

impl From<Vec<OperatorId>> for CommitteeId {
fn from(mut operator_ids: Vec<OperatorId>) -> Self {
// Sort the operator IDs
operator_ids.sort();
let mut data: Vec<u8> = Vec::with_capacity(operator_ids.len() * 4);

// Add the operator IDs as 32 byte values
for id in operator_ids {
data.extend_from_slice(&id.to_le_bytes());
}

// Hash it all
keccak256(data).0.into()
}
}

impl TryFrom<&[u8]> for CommitteeId {
type Error = ();

fn try_from(value: &[u8]) -> Result<Self, ()> {
value.try_into().map(CommitteeId).map_err(|_| ())
}
}
13 changes: 2 additions & 11 deletions anchor/common/ssv_types/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::message::*;
use crate::msgid::MessageId;
use crate::{OperatorId, ValidatorIndex};
use crate::ValidatorIndex;
use sha2::{Digest, Sha256};
use ssz::{Decode, DecodeError, Encode};
use ssz_derive::{Decode, Encode};
Expand All @@ -26,7 +26,7 @@ use types::{
// MsgType FullData
// --------- -----------
// ConsensusMsg QBFTMessage SSZ
// PartialSigMsg PartialSignatureMessage SSZ
// PartialSigMsg PartialSignatureMessages SSZ

pub trait QbftData: Debug + Clone + Encode + Decode {
type Hash: Debug + Clone + Eq + Hash;
Expand Down Expand Up @@ -144,15 +144,6 @@ impl Decode for QbftMessageType {
}
}

// A partial signature specific message
#[derive(Clone, Debug)]
pub struct PartialSignatureMessage {
pub partial_signature: Signature,
pub signing_root: Hash256,
pub signer: OperatorId,
pub validator_index: ValidatorIndex,
}

#[derive(Clone, Debug, PartialEq, Encode, Decode)]
pub struct ValidatorConsensusData {
pub duty: ValidatorDuty,
Expand Down
3 changes: 3 additions & 0 deletions anchor/common/ssv_types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
pub use cluster::{Cluster, ClusterId, ClusterMember, ValidatorIndex, ValidatorMetadata};
pub use committee::CommitteeId;
pub use operator::{Operator, OperatorId};
pub use share::Share;
mod cluster;
mod committee;
pub mod consensus;
pub mod domain_type;
pub mod message;
pub mod msgid;
mod operator;
pub mod partial_sig;
mod share;
mod sql_conversions;
mod util;
4 changes: 2 additions & 2 deletions anchor/common/ssv_types/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl SSVMessage {
///
/// ```
/// use ssv_types::message::{MessageId, MsgType, SSVMessage};
/// let message_id = MessageId::new([0u8; 56]);
/// let message_id = MessageId::from([0u8; 56]);
/// let msg = SSVMessage::new(MsgType::SSVConsensusMsgType, message_id, vec![1, 2, 3]);
/// ```
pub fn new(msg_type: MsgType, msg_id: MessageId, data: Vec<u8>) -> Self {
Expand Down Expand Up @@ -154,7 +154,7 @@ impl SignedSSVMessage {
/// ```
/// use ssv_types::message::{MessageId, MsgType, SSVMessage, SignedSSVMessage};
/// use ssv_types::OperatorId;
/// let ssv_msg = SSVMessage::new(MsgType::SSVConsensusMsgType, MessageId::new([0u8; 56]), vec![1,2,3]);
/// let ssv_msg = SSVMessage::new(MsgType::SSVConsensusMsgType, MessageId::from([0u8; 56]), vec![1,2,3]);
/// let signed_msg = SignedSSVMessage::new(vec![vec![0; 256]], vec![OperatorId(1)], ssv_msg, vec![4,5,6]).unwrap();
/// ```
pub fn new(
Expand Down
53 changes: 43 additions & 10 deletions anchor/common/ssv_types/src/msgid.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::committee::CommitteeId;
use crate::domain_type::DomainType;
use derive_more::From;
use ssz::{Decode, DecodeError, Encode};
use types::PublicKeyBytes;

const MESSAGE_ID_LEN: usize = 56;

Expand Down Expand Up @@ -37,26 +40,54 @@ impl TryFrom<&[u8]> for Role {
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum Executor {
Committee([u8; 32]),
Validator([u8; 48]),
pub enum DutyExecutor {
Committee(CommitteeId),
Validator(PublicKeyBytes),
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
#[derive(Debug, Clone, Hash, Eq, PartialEq, From)]
pub struct MessageId([u8; 56]);

impl MessageId {
pub fn new(domain: &DomainType, role: Role, duty_executor: &Executor) -> Self {
pub fn new(domain: &DomainType, role: Role, duty_executor: &DutyExecutor) -> Self {
let mut id = [0; 56];
id[0..4].copy_from_slice(&domain.0);
id[4..8].copy_from_slice(&<[u8; 4]>::from(role));
match duty_executor {
Executor::Committee(slice) => id[24..].copy_from_slice(slice),
Executor::Validator(slice) => id[8..].copy_from_slice(slice),
DutyExecutor::Committee(committee_id) => {
id[24..].copy_from_slice(committee_id.as_slice())
}
DutyExecutor::Validator(public_key) => {
id[8..].copy_from_slice(public_key.as_serialized())
}
}

MessageId(id)
}

pub fn domain(&self) -> DomainType {
DomainType(
self.0[0..4]
.try_into()
.expect("we know the slice has the correct length"),
)
}

pub fn role(&self) -> Option<Role> {
self.0[4..8].try_into().ok()
}

pub fn duty_executor(&self) -> Option<DutyExecutor> {
// which kind of executor we need to get depends on the role
match self.role()? {
Role::Committee => self.0[24..].try_into().ok().map(DutyExecutor::Committee),
Role::Aggregator | Role::Proposer | Role::SyncCommittee => {
PublicKeyBytes::deserialize(&self.0[8..])
.ok()
.map(DutyExecutor::Validator)
}
}
}
}

impl AsRef<[u8]> for MessageId {
Expand All @@ -65,9 +96,11 @@ impl AsRef<[u8]> for MessageId {
}
}

impl From<[u8; MESSAGE_ID_LEN]> for MessageId {
fn from(value: [u8; MESSAGE_ID_LEN]) -> Self {
MessageId(value)
impl TryFrom<&[u8]> for MessageId {
type Error = ();

fn try_from(value: &[u8]) -> Result<Self, ()> {
value.try_into().map(MessageId).map_err(|_| ())
}
}

Expand Down
93 changes: 93 additions & 0 deletions anchor/common/ssv_types/src/partial_sig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::{OperatorId, ValidatorIndex};
use ssz::{Decode, DecodeError, Encode};
use ssz_derive::{Decode, Encode};
use types::{Hash256, Signature, Slot};

#[derive(Clone, Copy, Debug)]
pub enum PartialSignatureKind {
// PostConsensusPartialSig is a partial signature over a decided duty (attestation data, block, etc)
PostConsensus = 0,
// RandaoPartialSig is a partial signature over randao reveal
RandaoPartialSig = 1,
// SelectionProofPartialSig is a partial signature for aggregator selection proof
SelectionProofPartialSig = 2,
// ContributionProofs is the partial selection proofs for sync committee contributions (it's an array of sigs)
ContributionProofs = 3,
// ValidatorRegistrationPartialSig is a partial signature over a ValidatorRegistration object
ValidatorRegistration = 4,
// VoluntaryExitPartialSig is a partial signature over a VoluntaryExit object
VoluntaryExit = 5,
}

impl TryFrom<u64> for PartialSignatureKind {
type Error = ();

fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0 => Ok(PartialSignatureKind::PostConsensus),
1 => Ok(PartialSignatureKind::RandaoPartialSig),
2 => Ok(PartialSignatureKind::SelectionProofPartialSig),
3 => Ok(PartialSignatureKind::ContributionProofs),
4 => Ok(PartialSignatureKind::ValidatorRegistration),
5 => Ok(PartialSignatureKind::VoluntaryExit),
_ => Err(()),
}
}
}

const U64_SIZE: usize = 8; // u64 is 8 bytes

impl Encode for PartialSignatureKind {
fn is_ssz_fixed_len() -> bool {
true
}

fn ssz_append(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&(*self as u64).to_le_bytes());
}

fn ssz_fixed_len() -> usize {
U64_SIZE
}

fn ssz_bytes_len(&self) -> usize {
U64_SIZE
}
}

impl Decode for PartialSignatureKind {
fn is_ssz_fixed_len() -> bool {
true
}

fn ssz_fixed_len() -> usize {
U64_SIZE
}

fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
if bytes.len() != U64_SIZE {
return Err(DecodeError::InvalidByteLength {
len: bytes.len(),
expected: U64_SIZE,
});
}
let value = u64::from_le_bytes(bytes.try_into().unwrap());
value.try_into().map_err(|_| DecodeError::NoMatchingVariant)
}
}

// A partial signature specific message
#[derive(Clone, Debug, Encode, Decode)]
pub struct PartialSignatureMessages {
pub kind: PartialSignatureKind,
pub slot: Slot,
pub messages: Vec<PartialSignatureMessage>,
}

#[derive(Clone, Debug, Encode, Decode)]
pub struct PartialSignatureMessage {
pub partial_signature: Signature,
pub signing_root: Hash256,
pub signer: OperatorId,
pub validator_index: ValidatorIndex,
}
6 changes: 3 additions & 3 deletions anchor/qbft_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::error::Error;

use ssv_types::message::SignedSSVMessage;
use ssv_types::OperatorId as QbftOperatorId;
use ssv_types::{Cluster, ClusterId, OperatorId};
use ssv_types::{Cluster, CommitteeId, OperatorId};
use ssz::Encode;
use std::fmt::Debug;
use std::hash::Hash;
Expand All @@ -40,10 +40,10 @@ const QBFT_SIGNER_NAME: &str = "qbft_signer";
/// Number of slots to keep before the current slot
const QBFT_RETAIN_SLOTS: u64 = 1;

// Unique Identifier for a Cluster and its corresponding QBFT instance
// Unique Identifier for a committee and its corresponding QBFT instance
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct CommitteeInstanceId {
pub committee: ClusterId,
pub committee: CommitteeId,
pub instance_height: InstanceHeight,
}

Expand Down
4 changes: 2 additions & 2 deletions anchor/qbft_manager/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use processor::Senders;
use slot_clock::{ManualSlotClock, SlotClock};
use ssv_types::consensus::{BeaconVote, QbftMessage, QbftMessageType};
use ssv_types::message::SignedSSVMessage;
use ssv_types::{Cluster, ClusterId, OperatorId};
use ssv_types::{Cluster, ClusterId, CommitteeId, OperatorId};
use ssz::Decode;
use std::collections::HashMap;
use std::sync::LazyLock;
Expand Down Expand Up @@ -550,7 +550,7 @@ mod manager_tests {
fn generate_test_data(id: usize) -> (BeaconVote, CommitteeInstanceId) {
// setup mock data
let id = CommitteeInstanceId {
committee: ClusterId([0; 32]),
committee: CommitteeId([0; 32]),
instance_height: id.into(),
};

Expand Down
Loading

0 comments on commit 55a6a60

Please sign in to comment.