Skip to content

Commit 0723ded

Browse files
authored
feat: add ssz support (#26)
* 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 * feat: add support for legacy cluster definitions * fix: linter errors * feat: add legacy locks support * fix: linter warnings * feat: implement some of the cluster config function, ENR functionality, k1util, RLP, p2p.name etc. * feat: improve error handling * feat: improve error handling in cluster * refactor: k1util, add utility methods to cluster * feat: add eip712 utils * feat: implement part of ssz-related logics * feat: add lock & definition hash hash verification * feat: add timestamp method * feat: implement some todos, polish code * chore: minor polishes * fix: remove unused deps * fix: remove unused macro, add error handling for some calls * fix: comments from review
1 parent ff03ea9 commit 0723ded

8 files changed

Lines changed: 1826 additions & 52 deletions

File tree

crates/charon-cluster/src/definition.rs

Lines changed: 126 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::collections::HashSet;
33
use crate::{
44
helpers::{EthHex, from_0x_hex_str},
55
operator::{Operator, OperatorV1X1, OperatorV1X2OrLater},
6+
ssz::{SSZError, hash_definition},
7+
ssz_hasher::Hasher,
68
version::{CURRENT_VERSION, DKG_ALGO, versions::*},
79
};
810
use charon_eth2::enr::{Record, RecordError};
@@ -38,15 +40,15 @@ pub struct NodeIdx {
3840
#[derive(Debug, Clone, PartialEq, Eq)]
3941
pub struct Definition {
4042
/// Human-readable random unique identifier. Max 64 chars.
41-
pub uuid: Uuid,
43+
pub uuid: String,
4244
/// Human-readable cosmetic identifier. Max 256 chars.
4345
pub name: String,
4446
/// Schema version of this definition. Max 16 chars.
4547
pub version: String,
4648
/// Human-readable timestamp of this definition. Max 32
4749
/// chars. Note that this was added in v1.1.0, so may be empty for older
4850
/// versions.
49-
pub timestamp: DateTime<Utc>,
51+
pub timestamp: String,
5052
/// Number of DVs to be created in the cluster lock
5153
/// file.
5254
pub num_validators: u64,
@@ -227,6 +229,32 @@ pub enum DefinitionError {
227229
/// Failed to create peer
228230
#[error("Failed to create peer: {0}")]
229231
FailedToCreatePeer(#[from] PeerError),
232+
233+
/// Invalid config hash
234+
#[error("Invalid config hash")]
235+
InvalidConfigHash {
236+
/// Expected config hash
237+
expected: Vec<u8>,
238+
/// Actual config hash
239+
actual: Vec<u8>,
240+
},
241+
242+
/// SSZ error
243+
#[error("SSZ error: {0}")]
244+
SSZError(#[from] Box<SSZError<Hasher>>),
245+
246+
/// Invalid definition hash
247+
#[error("Invalid definition hash")]
248+
InvalidDefinitionHash {
249+
/// Expected definition hash
250+
expected: Vec<u8>,
251+
/// Actual definition hash
252+
actual: Vec<u8>,
253+
},
254+
255+
/// Failed to convert timestamp
256+
#[error("Failed to convert timestamp")]
257+
FailedToConvertTimestamp(#[from] serde_json::Error),
230258
}
231259

232260
/// InvalidGasLimitError is an error type for invalid gas limit errors.
@@ -276,10 +304,10 @@ impl Definition {
276304
let uuid = Uuid::new_v4();
277305

278306
let mut def = Definition {
279-
uuid,
307+
uuid: uuid.to_string(),
280308
name,
281309
version: CURRENT_VERSION.to_string(),
282-
timestamp: Utc::now(),
310+
timestamp: Utc::now().to_string(),
283311
num_validators,
284312
threshold,
285313
dkg_algorithm: DKG_ALGO.to_string(),
@@ -326,10 +354,21 @@ impl Definition {
326354
return Err(InvalidGasLimitError::GasLimitNotSet.into());
327355
}
328356

329-
// TODO: Construct and return a Definition. Placeholder for now.
330357
def.set_definition_hashes()
331358
}
332359

360+
/// Returns the timestamp of the definition.
361+
pub fn timestamp(&self) -> Result<Option<DateTime<Utc>>, DefinitionError> {
362+
if self.timestamp.is_empty() {
363+
return Ok(None);
364+
}
365+
366+
let timestamp = serde_json::from_str::<DateTime<Utc>>(&self.timestamp)
367+
.map_err(DefinitionError::FailedToConvertTimestamp)?;
368+
369+
Ok(Some(timestamp))
370+
}
371+
333372
/// Returns the node index for a given peer ID.
334373
pub fn node_idx(&self, pid: &PeerId) -> Result<NodeIdx, DefinitionError> {
335374
let peers = self.peers()?;
@@ -417,16 +456,44 @@ impl Definition {
417456
}
418457

419458
/// Sets the definition hashes.
420-
pub fn set_definition_hashes(self) -> Result<Self, DefinitionError> {
421-
// todo
459+
pub fn set_definition_hashes(mut self) -> Result<Self, DefinitionError> {
460+
let config_hash =
461+
hash_definition(&self, true).map_err(|e| DefinitionError::SSZError(Box::new(e)))?;
462+
463+
self.config_hash = config_hash.to_vec();
464+
465+
let definition_hash =
466+
hash_definition(&self, false).map_err(|e| DefinitionError::SSZError(Box::new(e)))?;
467+
468+
self.definition_hash = definition_hash.to_vec();
469+
422470
Ok(self)
423471
}
424472

425473
/// `verify_hashes` returns an error if hashes populated from json object
426474
/// doesn't matches actual hashes.
427-
pub fn verify_hashes(self) -> Result<Self, DefinitionError> {
428-
// todo
429-
Ok(self)
475+
pub fn verify_hashes(&self) -> Result<(), DefinitionError> {
476+
let config_hash =
477+
hash_definition(self, true).map_err(|e| DefinitionError::SSZError(Box::new(e)))?;
478+
479+
if config_hash != self.config_hash.as_slice() {
480+
return Err(DefinitionError::InvalidConfigHash {
481+
expected: self.config_hash.clone(),
482+
actual: config_hash.to_vec(),
483+
});
484+
}
485+
486+
let definition_hash =
487+
hash_definition(self, false).map_err(|e| DefinitionError::SSZError(Box::new(e)))?;
488+
489+
if definition_hash != self.definition_hash.as_slice() {
490+
return Err(DefinitionError::InvalidDefinitionHash {
491+
expected: self.definition_hash.clone(),
492+
actual: definition_hash.to_vec(),
493+
});
494+
}
495+
496+
Ok(())
430497
}
431498

432499
/// Returns true if the provided definition version supports EIP712
@@ -494,13 +561,13 @@ pub struct DefinitionV1x0or1 {
494561
/// Max 256 operators.
495562
pub operators: Vec<OperatorV1X1>,
496563
/// Human-readable random unique identifier. Max 64 chars.
497-
pub uuid: Uuid,
564+
pub uuid: String,
498565
/// Schema version of this definition. Max 16 chars.
499566
pub version: String,
500567
/// Human-readable timestamp of this definition. Max 32
501568
/// chars. Note that this was added in v1.1.0, so may be empty for older
502569
/// versions.
503-
pub timestamp: DateTime<Utc>,
570+
pub timestamp: String,
504571
/// Number of DVs to be created in the cluster lock
505572
/// file.
506573
pub num_validators: u64,
@@ -605,13 +672,13 @@ pub struct DefinitionV1x2or3 {
605672
/// Max 256 operators.
606673
pub operators: Vec<OperatorV1X2OrLater>,
607674
/// Human-readable random unique identifier. Max 64 chars.
608-
pub uuid: Uuid,
675+
pub uuid: String,
609676
/// Schema version of this definition. Max 16 chars.
610677
pub version: String,
611678
/// Human-readable timestamp of this definition. Max 32
612679
/// chars. Note that this was added in v1.1.0, so may be empty for older
613680
/// versions.
614-
pub timestamp: DateTime<Utc>,
681+
pub timestamp: String,
615682
/// Number of DVs to be created in the cluster lock
616683
/// file.
617684
pub num_validators: u64,
@@ -719,13 +786,13 @@ pub struct DefinitionV1x4 {
719786
/// Max 256 operators.
720787
pub operators: Vec<OperatorV1X2OrLater>,
721788
/// Human-readable random unique identifier. Max 64 chars.
722-
pub uuid: Uuid,
789+
pub uuid: String,
723790
/// Schema version of this definition. Max 16 chars.
724791
pub version: String,
725792
/// Human-readable timestamp of this definition. Max 32
726793
/// chars. Note that this was added in v1.1.0, so may be empty for older
727794
/// versions.
728-
pub timestamp: DateTime<Utc>,
795+
pub timestamp: String,
729796
/// Number of DVs to be created in the cluster lock
730797
/// file.
731798
pub num_validators: u64,
@@ -834,13 +901,13 @@ pub struct DefinitionV1x5to7 {
834901
/// Max 256 operators.
835902
pub operators: Vec<OperatorV1X2OrLater>,
836903
/// Human-readable random unique identifier. Max 64 chars.
837-
pub uuid: Uuid,
904+
pub uuid: String,
838905
/// Schema version of this definition. Max 16 chars.
839906
pub version: String,
840907
/// Human-readable timestamp of this definition. Max 32
841908
/// chars. Note that this was added in v1.1.0, so may be empty for older
842909
/// versions.
843-
pub timestamp: DateTime<Utc>,
910+
pub timestamp: String,
844911
/// Number of DVs to be created in the cluster lock
845912
/// file.
846913
pub num_validators: u64,
@@ -931,13 +998,13 @@ pub struct DefinitionV1x8 {
931998
/// Max 256 operators.
932999
pub operators: Vec<OperatorV1X2OrLater>,
9331000
/// UUID is a human-readable random unique identifier. Max 64 chars.
934-
pub uuid: Uuid,
1001+
pub uuid: String,
9351002
/// Version is the schema version of this definition. Max 16 chars.
9361003
pub version: String,
9371004
/// Timestamp is the human-readable timestamp of this definition. Max 32
9381005
/// chars. Note that this was added in v1.1.0, so may be empty for older
9391006
/// versions.
940-
pub timestamp: DateTime<Utc>,
1007+
pub timestamp: String,
9411008
/// NumValidators is the number of DVs to be created in the cluster lock
9421009
/// file.
9431010
pub num_validators: u64,
@@ -1033,13 +1100,13 @@ pub struct DefinitionV1x9 {
10331100
/// Max 256 operators.
10341101
pub operators: Vec<OperatorV1X2OrLater>,
10351102
/// UUID is a human-readable random unique identifier. Max 64 chars.
1036-
pub uuid: Uuid,
1103+
pub uuid: String,
10371104
/// Version is the schema version of this definition. Max 16 chars.
10381105
pub version: String,
10391106
/// Timestamp is the human-readable timestamp of this definition. Max 32
10401107
/// chars. Note that this was added in v1.1.0, so may be empty for older
10411108
/// versions.
1042-
pub timestamp: DateTime<Utc>,
1109+
pub timestamp: String,
10431110
/// NumValidators is the number of DVs to be created in the cluster lock
10441111
/// file.
10451112
pub num_validators: u64,
@@ -1139,13 +1206,13 @@ pub struct DefinitionV1x10 {
11391206
/// Max 256 operators.
11401207
pub operators: Vec<OperatorV1X2OrLater>,
11411208
/// Human-readable random unique identifier. Max 64 chars.
1142-
pub uuid: Uuid,
1209+
pub uuid: String,
11431210
/// Schema version of this definition. Max 16 chars.
11441211
pub version: String,
11451212
/// Human-readable timestamp of this definition. Max 32
11461213
/// chars. Note that this was added in v1.1.0, so may be empty for older
11471214
/// versions.
1148-
pub timestamp: DateTime<Utc>,
1215+
pub timestamp: String,
11491216
/// Number of DVs to be created in the cluster lock
11501217
/// file.
11511218
pub num_validators: u64,
@@ -1354,6 +1421,8 @@ mod tests {
13541421
hex::decode("59a8d3ffa9010f54965a11248e2835e716049d508f4f64bf43bd5a6ca56037c0")
13551422
.unwrap()
13561423
);
1424+
1425+
assert!(definition.verify_hashes().is_ok());
13571426
}
13581427

13591428
#[test]
@@ -1362,7 +1431,9 @@ mod tests {
13621431

13631432
let _ = serde_json::from_str::<DefinitionV1x0or1>(json_str).unwrap();
13641433

1365-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1434+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1435+
1436+
assert!(definition.verify_hashes().is_ok());
13661437
}
13671438

13681439
#[test]
@@ -1371,7 +1442,9 @@ mod tests {
13711442

13721443
let _ = serde_json::from_str::<DefinitionV1x0or1>(json_str).unwrap();
13731444

1374-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1445+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1446+
1447+
assert!(definition.verify_hashes().is_ok());
13751448
}
13761449

13771450
#[test]
@@ -1380,7 +1453,9 @@ mod tests {
13801453

13811454
let _ = serde_json::from_str::<DefinitionV1x2or3>(json_str).unwrap();
13821455

1383-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1456+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1457+
1458+
assert!(definition.verify_hashes().is_ok());
13841459
}
13851460

13861461
#[test]
@@ -1389,7 +1464,9 @@ mod tests {
13891464

13901465
let _ = serde_json::from_str::<DefinitionV1x2or3>(json_str).unwrap();
13911466

1392-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1467+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1468+
1469+
assert!(definition.verify_hashes().is_ok());
13931470
}
13941471

13951472
#[test]
@@ -1398,7 +1475,9 @@ mod tests {
13981475

13991476
let _ = serde_json::from_str::<DefinitionV1x4>(json_str).unwrap();
14001477

1401-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1478+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1479+
1480+
assert!(definition.verify_hashes().is_ok());
14021481
}
14031482

14041483
#[test]
@@ -1407,7 +1486,9 @@ mod tests {
14071486

14081487
let _ = serde_json::from_str::<DefinitionV1x5to7>(json_str).unwrap();
14091488

1410-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1489+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1490+
1491+
assert!(definition.verify_hashes().is_ok());
14111492
}
14121493

14131494
#[test]
@@ -1416,7 +1497,9 @@ mod tests {
14161497

14171498
let _ = serde_json::from_str::<DefinitionV1x5to7>(json_str).unwrap();
14181499

1419-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1500+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1501+
1502+
assert!(definition.verify_hashes().is_ok());
14201503
}
14211504

14221505
#[test]
@@ -1425,7 +1508,9 @@ mod tests {
14251508

14261509
let _ = serde_json::from_str::<DefinitionV1x5to7>(json_str).unwrap();
14271510

1428-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1511+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1512+
1513+
assert!(definition.verify_hashes().is_ok());
14291514
}
14301515

14311516
#[test]
@@ -1434,7 +1519,9 @@ mod tests {
14341519

14351520
let _ = serde_json::from_str::<DefinitionV1x8>(json_str).unwrap();
14361521

1437-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1522+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1523+
1524+
assert!(definition.verify_hashes().is_ok());
14381525
}
14391526

14401527
#[test]
@@ -1443,7 +1530,9 @@ mod tests {
14431530

14441531
let _ = serde_json::from_str::<DefinitionV1x9>(json_str).unwrap();
14451532

1446-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1533+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1534+
1535+
assert!(definition.verify_hashes().is_ok());
14471536
}
14481537

14491538
#[test]
@@ -1452,7 +1541,9 @@ mod tests {
14521541

14531542
let _ = serde_json::from_str::<DefinitionV1x10>(json_str).unwrap();
14541543

1455-
let _ = serde_json::from_str::<Definition>(json_str).unwrap();
1544+
let definition = serde_json::from_str::<Definition>(json_str).unwrap();
1545+
1546+
assert!(definition.verify_hashes().is_ok());
14561547
}
14571548

14581549
// test incorrect version

0 commit comments

Comments
 (0)