Skip to content

Commit 704b858

Browse files
authored
feat: add cluster lock v1.10.0 support (#22)
* feat: setup initial project structure * feat: update CI to use nightly toolchain for rustfmt * feat: update CI to use nightly toolchain for rustfmt * fix: fmt * refactor: reorganize workspace members and remove charon-types crate * feat: add core types and dependencies for Charon * feat: add is_valid method and tests for DutyType * feat: enhance Charon core types with new methods and error handling for PubKey * chore: remove unused proptest dependency from workspace * feat: implement Default trait for UnsignedDataSet, ParSignedDataSet, and SignedDataSet * refactor: update PubKey methods for improved error handling and add try_from implementation * docs: clarify slot duration comment and add debug prints for PubKey serialization/deserialization tests * fix: remove unnecessary println * feat: add tbls crypto boilerplate * feat: add initial implementation of tbls * feat: add tests for the bls implementation * feat: init structure of charon-cluster * feat: integrate blsful implementation and refactor tbls module - Added `thiserror` dependency for improved error handling. - Introduced `blsful` module for TBLS implementation. - Refactored `tbls` module to utilize new types and error handling. - Created `tblsconv` module for type conversions between byte slices and cryptographic types. - Removed the old `herumi` implementation and replaced it with the new `blsful` based implementation. - Added utility functions for key and signature conversions. - Updated types and error definitions for better clarity and consistency. * style: improve code formatting and documentation in tblsconv module - Reformatted comments for better readability. - Adjusted spacing and alignment in error messages for consistency. - Ensured clarity in documentation regarding expected byte lengths for key and signature conversions. * chore: clean up Cargo.toml by removing duplicate dependencies and organizing workspace lints * chore: update Cargo.lock with new dependencies and versions * chore: fix clippy warnings * chore: apply fmt * refactor: replace blsful implementation with blst for threshold BLS signatures - Updated dependencies in Cargo.toml and Cargo.lock to use the blst library. - Removed blsful module and its associated code, including type conversions and utility functions. - Introduced a new blst_impl module for the BLST implementation of threshold BLS signatures. - Refactored tbls module to utilize the new blst implementation. - Cleaned up error handling and types to align with the new library. - Added workspace lints and improved documentation throughout the codebase. * fix: add protoc to workflow files * fix: add ignore files to typos config * feat: add support for cluster definition v1.10.0 * feat: add cluster lock v1.10.0 support * fix: linter errors
1 parent d6c82d6 commit 704b858

10 files changed

Lines changed: 401 additions & 7 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ prost-build = "0.14"
4040
rand = {version = "0.8", features = ["std_rng"]}
4141
uuid = {version = "1.16", features = ["serde"] }
4242
serde_with = { version = "3", features = ["hex"] }
43+
charon-crypto = { path = "crates/charon-crypto" }
4344

4445
[workspace.lints.rust]
4546
missing_docs = "deny"

crates/charon-cluster/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ serde.workspace = true
1515
serde_json.workspace = true
1616
hex.workspace = true
1717
serde_with.workspace = true
18+
charon-crypto.workspace = true
19+
thiserror.workspace = true
1820

1921
[build-dependencies]
2022
prost-build.workspace = true

crates/charon-cluster/src/definition.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ pub struct Definition {
3232
pub timestamp: DateTime<Utc>,
3333
/// NumValidators is the number of DVs to be created in the cluster lock
3434
/// file.
35-
pub num_validators: u32,
35+
pub num_validators: u64,
3636
/// Threshold required for signature reconstruction. Defaults to safe value
3737
/// for number of nodes/peers.
38-
pub threshold: u32,
38+
pub threshold: u64,
3939
/// DKGAlgorithm to use for key generation. Max 32 chars.
4040
pub dkg_algorithm: String,
4141
/// ForkVersion defines the cluster's 4 byte beacon chain fork version
@@ -59,7 +59,7 @@ pub struct Definition {
5959
/// cluster, e.g. "abft".
6060
pub consensus_protocol: String,
6161
/// TargetGasLimit is the target block gas limit for the cluster.
62-
pub target_gas_limit: u32,
62+
pub target_gas_limit: u64,
6363
/// Compounding flag enables compounding rewards for validators by using
6464
/// 0x02 withdrawal credentials.
6565
pub compounding: bool,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,28 @@
1+
use crate::helpers::EthHex;
2+
use serde::{Deserialize, Serialize};
3+
use serde_with::{DisplayFromStr, serde_as};
14

5+
/// DepositData defines the deposit data to activate a validator.
6+
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#depositdata
7+
#[serde_as]
8+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9+
pub struct DepositData {
10+
/// PubKey is the validator's public key.
11+
#[serde_as(as = "EthHex")]
12+
#[serde(rename = "pubkey")]
13+
pub pub_key: Vec<u8>,
14+
15+
/// WithdrawalCredentials included in the deposit.
16+
#[serde_as(as = "EthHex")]
17+
pub withdrawal_credentials: Vec<u8>,
18+
19+
/// Amount is the amount in Gwei to be deposited [1ETH..2048ETH].
20+
/// We use DisplayFromStr to allow for easy conversion from string to u64.
21+
#[serde_as(as = "DisplayFromStr")]
22+
pub amount: u64,
23+
24+
/// Signature is the BLS signature of the deposit message (above three
25+
/// fields).
26+
#[serde_as(as = "EthHex")]
27+
pub signature: Vec<u8>,
28+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,97 @@
1+
use charon_crypto::types::{PUBLIC_KEY_LENGTH, PublicKey};
2+
use serde::{Deserialize, Serialize};
13

4+
use crate::{deposit::DepositData, helpers::EthHex, registration::BuilderRegistration};
5+
use serde_with::serde_as;
6+
7+
/// DistValidator is a distributed validator managed by the cluster.
8+
#[serde_as]
9+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10+
pub struct DistValidator {
11+
/// PubKey is the distributed validator group public key.
12+
#[serde(rename = "distributed_public_key")]
13+
#[serde_as(as = "EthHex")]
14+
pub pub_key: Vec<u8>,
15+
16+
/// PubShares are the public keys corresponding to each node's secret key
17+
/// share. It can be used to verify a partial signature created by any
18+
/// node in the cluster.
19+
#[serde(rename = "public_shares")]
20+
#[serde_as(as = "Vec<EthHex>")]
21+
pub pub_shares: Vec<Vec<u8>>,
22+
23+
/// PartialDepositData is the list of partial deposit data.
24+
pub partial_deposit_data: Vec<DepositData>,
25+
26+
/// BuilderRegistration is the pre-generated signed validator builder
27+
/// registration.
28+
pub builder_registration: BuilderRegistration,
29+
}
30+
31+
/// DistValidatorError is an error type for DistValidator operations.
32+
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
33+
pub enum DistValidatorError {
34+
/// Invalid public key length.
35+
#[error("invalid public key length: got {0}, want {1}")]
36+
InvalidPublicKeyLength(usize, usize),
37+
/// Invalid public share index.
38+
#[error("invalid public share index: got {0}, want less than {1}")]
39+
InvalidPublicShareIndex(usize, usize),
40+
}
41+
42+
impl DistValidator {
43+
/// PublicKey returns the distributed validator group public key.
44+
pub fn public_key(&self) -> Result<PublicKey, DistValidatorError> {
45+
if self.pub_key.len() != PUBLIC_KEY_LENGTH {
46+
return Err(DistValidatorError::InvalidPublicKeyLength(
47+
self.pub_key.len(),
48+
PUBLIC_KEY_LENGTH,
49+
));
50+
}
51+
let mut pub_key = [0u8; PUBLIC_KEY_LENGTH];
52+
pub_key.copy_from_slice(&self.pub_key);
53+
Ok(pub_key)
54+
}
55+
56+
/// PublicKeyHex returns the validator hex group public key.
57+
pub fn public_key_hex(&self) -> Result<String, DistValidatorError> {
58+
let pub_key = self.public_key()?;
59+
Ok(format!("0x{}", hex::encode(pub_key)))
60+
}
61+
62+
/// PublicShare returns a peer's threshold BLS public share.
63+
pub fn public_share(&self, index: usize) -> Result<PublicKey, DistValidatorError> {
64+
if index >= self.pub_shares.len() {
65+
return Err(DistValidatorError::InvalidPublicShareIndex(
66+
index,
67+
self.pub_shares.len(),
68+
));
69+
}
70+
if self.pub_shares[index].len() != PUBLIC_KEY_LENGTH {
71+
return Err(DistValidatorError::InvalidPublicKeyLength(
72+
self.pub_shares[index].len(),
73+
PUBLIC_KEY_LENGTH,
74+
));
75+
}
76+
let mut pub_share = [0u8; PUBLIC_KEY_LENGTH];
77+
pub_share.copy_from_slice(&self.pub_shares[index]);
78+
Ok(pub_share)
79+
}
80+
81+
/// ZeroRegistration returns a true if the validator has zero valued
82+
/// registration.
83+
pub fn zero_registration(&self) -> bool {
84+
self.builder_registration.signature.is_empty()
85+
&& self.builder_registration.message.fee_recipient.is_empty()
86+
&& self.builder_registration.message.gas_limit == 0
87+
&& self.builder_registration.message.timestamp.timestamp() == 0
88+
&& self.builder_registration.message.pub_key.is_empty()
89+
}
90+
91+
/// Eth2Registration returns the validator's Eth2 registration.
92+
pub fn eth2_registration(&self) -> Result<(), DistValidatorError> {
93+
unimplemented!(
94+
"Eth2 registration requires to have ethereum types library which is not yet integrated in charon-cluster"
95+
)
96+
}
97+
}

crates/charon-cluster/src/examples/cluster-definition-005.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@
3232
],
3333
"uuid": "B6AE17B3-78F5-147B-2C37-2572B93437DF",
3434
"version": "v1.8.0",
35-
<<<<<<< HEAD
36-
"timestamp": "2023-05-18T15: 12: 46+02: 00",
37-
=======
3835
"timestamp": "2023-05-18T15:12:46+02:00",
39-
>>>>>>> origin/main
4036
"num_validators": 2,
4137
"threshold": 3,
4238
"validators": [

crates/charon-cluster/src/helpers.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use chrono::{DateTime, Utc};
12
use serde::{Deserialize, Deserializer, Serialize, Serializer};
23
use serde_with::{DeserializeAs, SerializeAs};
34
use std::borrow::Cow;
@@ -90,6 +91,29 @@ impl TryFrom<&str> for EthHex {
9091
}
9192
}
9293

94+
/// TimestampSeconds represents a timestamp in seconds since the Unix epoch.
95+
pub struct TimestampSeconds;
96+
97+
impl SerializeAs<DateTime<Utc>> for TimestampSeconds {
98+
fn serialize_as<S>(value: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
99+
where
100+
S: Serializer,
101+
{
102+
serializer.serialize_i64(value.timestamp())
103+
}
104+
}
105+
106+
impl<'de> DeserializeAs<'de, DateTime<Utc>> for TimestampSeconds {
107+
fn deserialize_as<D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
108+
where
109+
D: Deserializer<'de>,
110+
{
111+
let timestamp = i64::deserialize(deserializer)?;
112+
DateTime::<Utc>::from_timestamp(timestamp, 0)
113+
.ok_or(serde::de::Error::custom("invalid timestamp"))
114+
}
115+
}
116+
93117
#[cfg(test)]
94118
mod tests {
95119
use super::*;

0 commit comments

Comments
 (0)