From 2f3b79e3af2eeb2560ab3e184d181954b31ed032 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Wed, 8 Oct 2025 15:45:14 +0800
Subject: [PATCH 01/13] feat: setup initial project structure
---
Cargo.toml | 15 ++--
cargo-generate.toml | 14 ----
{examples => crates/charon-cli}/Cargo.toml | 9 +--
crates/charon-cli/src/lib.rs | 40 +++++++++++
crates/charon-cluster/Cargo.toml | 12 ++++
crates/charon-cluster/src/lib.rs | 39 +++++++++++
crates/charon-consensus/Cargo.toml | 12 ++++
crates/charon-consensus/src/lib.rs | 39 +++++++++++
crates/charon-core/Cargo.toml | 12 ++++
crates/charon-core/src/lib.rs | 39 +++++++++++
crates/charon-crypto/Cargo.toml | 12 ++++
crates/charon-crypto/src/lib.rs | 39 +++++++++++
crates/charon-db/Cargo.toml | 12 ++++
crates/charon-db/src/lib.rs | 39 +++++++++++
crates/charon-dkg/Cargo.toml | 12 ++++
crates/charon-dkg/src/lib.rs | 39 +++++++++++
crates/charon-errors/Cargo.toml | 12 ++++
crates/charon-errors/src/lib.rs | 39 +++++++++++
crates/charon-eth2/Cargo.toml | 12 ++++
crates/charon-eth2/src/lib.rs | 39 +++++++++++
crates/charon-observability/Cargo.toml | 12 ++++
crates/charon-observability/src/lib.rs | 39 +++++++++++
crates/charon-p2p/Cargo.toml | 12 ++++
crates/charon-p2p/src/lib.rs | 39 +++++++++++
crates/charon-serde/Cargo.toml | 12 ++++
crates/charon-serde/src/lib.rs | 39 +++++++++++
crates/charon-testutil/Cargo.toml | 12 ++++
crates/charon-testutil/src/lib.rs | 39 +++++++++++
crates/charon-types/Cargo.toml | 12 ++++
crates/charon-types/src/lib.rs | 39 +++++++++++
crates/charon/Cargo.toml | 12 ++++
crates/charon/src/lib.rs | 39 +++++++++++
examples/README.md | 12 ----
examples/src/bin/addition.rs | 6 --
katex-header.html | 15 ----
rust-toolchain.toml | 3 +-
template_crate/Cargo.toml | 24 -------
template_crate/README.md | 3 -
template_crate/doc/mainpage-doc.md | 1 -
template_crate/src/lib.rs | 81 ----------------------
40 files changed, 765 insertions(+), 172 deletions(-)
delete mode 100644 cargo-generate.toml
rename {examples => crates/charon-cli}/Cargo.toml (51%)
create mode 100644 crates/charon-cli/src/lib.rs
create mode 100644 crates/charon-cluster/Cargo.toml
create mode 100644 crates/charon-cluster/src/lib.rs
create mode 100644 crates/charon-consensus/Cargo.toml
create mode 100644 crates/charon-consensus/src/lib.rs
create mode 100644 crates/charon-core/Cargo.toml
create mode 100644 crates/charon-core/src/lib.rs
create mode 100644 crates/charon-crypto/Cargo.toml
create mode 100644 crates/charon-crypto/src/lib.rs
create mode 100644 crates/charon-db/Cargo.toml
create mode 100644 crates/charon-db/src/lib.rs
create mode 100644 crates/charon-dkg/Cargo.toml
create mode 100644 crates/charon-dkg/src/lib.rs
create mode 100644 crates/charon-errors/Cargo.toml
create mode 100644 crates/charon-errors/src/lib.rs
create mode 100644 crates/charon-eth2/Cargo.toml
create mode 100644 crates/charon-eth2/src/lib.rs
create mode 100644 crates/charon-observability/Cargo.toml
create mode 100644 crates/charon-observability/src/lib.rs
create mode 100644 crates/charon-p2p/Cargo.toml
create mode 100644 crates/charon-p2p/src/lib.rs
create mode 100644 crates/charon-serde/Cargo.toml
create mode 100644 crates/charon-serde/src/lib.rs
create mode 100644 crates/charon-testutil/Cargo.toml
create mode 100644 crates/charon-testutil/src/lib.rs
create mode 100644 crates/charon-types/Cargo.toml
create mode 100644 crates/charon-types/src/lib.rs
create mode 100644 crates/charon/Cargo.toml
create mode 100644 crates/charon/src/lib.rs
delete mode 100644 examples/README.md
delete mode 100644 examples/src/bin/addition.rs
delete mode 100644 katex-header.html
delete mode 100644 template_crate/Cargo.toml
delete mode 100644 template_crate/README.md
delete mode 100644 template_crate/doc/mainpage-doc.md
delete mode 100644 template_crate/src/lib.rs
diff --git a/Cargo.toml b/Cargo.toml
index 45ca2194..2704e388 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,16 +1,13 @@
-
-# TODO(template) update for the crate name
[workspace]
-members = ["examples", "template_crate"]
+name = "charon-rs"
+members = [ "crates/charon", "crates/charon-cli", "crates/charon-cluster", "crates/charon-consensus", "crates/charon-core", "crates/charon-crypto", "crates/charon-db", "crates/charon-dkg", "crates/charon-errors", "crates/charon-eth2", "crates/charon-observability", "crates/charon-p2p", "crates/charon-serde", "crates/charon-testutil", "crates/charon-types"]
resolver = "3"
-default-members = ["template_crate"]
[workspace.package]
version = "0.1.0"
edition = "2024"
-# TODO(template) update for your repository
-repository = "https://github.com/NethermindEth/rust-template"
-license = "Apache-2.0" # TODO(template) update license if needed
+repository = "https://github.com/NethermindEth/charon-rs"
+license = "Apache-2.0" # TODO(template) update license
publish = false
[workspace.dependencies]
@@ -18,10 +15,6 @@ proptest = "1"
[workspace.lints.rust]
missing_docs = "deny"
-# TODO(template) if you use any unsafe code, then running miri in CI is a must
-# if for a crate in the workspace you need an unsafe code
-# prefer to preserve forbid for the workspace
-# and allowing only at a specific crate level
unsafe_code = "forbid"
[workspace.lints.clippy]
diff --git a/cargo-generate.toml b/cargo-generate.toml
deleted file mode 100644
index 12c6a7c4..00000000
--- a/cargo-generate.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[template]
-name = "rust-template"
-description = "A template for a new Rust project"
-author = "Nethermind"
-license = "Apache-2.0"
-cargo_generate_version = ">=0.23.0"
-
-# Exclude files from the placeholder generated for the template
-exclude = [
- ".github/workflows/dependency-audit.yml",
- ".github/workflows/coverage-pr.yml",
- ".github/workflows/semver-checks.yml",
- "target",
-]
diff --git a/examples/Cargo.toml b/crates/charon-cli/Cargo.toml
similarity index 51%
rename from examples/Cargo.toml
rename to crates/charon-cli/Cargo.toml
index b8924ed3..37a9cea3 100644
--- a/examples/Cargo.toml
+++ b/crates/charon-cli/Cargo.toml
@@ -1,11 +1,12 @@
[package]
-name = "examples"
-publish = false
+name = "charon-cli"
version.workspace = true
edition.workspace = true
repository.workspace = true
license.workspace = true
+publish.workspace = true
[dependencies]
-# TODO(template) update the crate name
-template_crate = { path = "../template_crate" }
+
+[lints]
+workspace = true
diff --git a/crates/charon-cli/src/lib.rs b/crates/charon-cli/src/lib.rs
new file mode 100644
index 00000000..5cfbd16e
--- /dev/null
+++ b/crates/charon-cli/src/lib.rs
@@ -0,0 +1,40 @@
+
+//! # Charon CLI
+//!
+//! Command-line interface for the Charon distributed validator node.
+//! This crate provides the CLI tools and commands for managing and operating
+//! Charon validator nodes.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_cli::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-cluster/Cargo.toml b/crates/charon-cluster/Cargo.toml
new file mode 100644
index 00000000..7cfc7292
--- /dev/null
+++ b/crates/charon-cluster/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-cluster"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-cluster/src/lib.rs b/crates/charon-cluster/src/lib.rs
new file mode 100644
index 00000000..7050d743
--- /dev/null
+++ b/crates/charon-cluster/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Cluster
+//!
+//! Cluster management and coordination for Charon distributed validator nodes.
+//! This crate handles the formation, management, and coordination of validator
+//! clusters in the Charon network.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_cluster::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-consensus/Cargo.toml b/crates/charon-consensus/Cargo.toml
new file mode 100644
index 00000000..b95b8877
--- /dev/null
+++ b/crates/charon-consensus/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-consensus"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-consensus/src/lib.rs b/crates/charon-consensus/src/lib.rs
new file mode 100644
index 00000000..cd038604
--- /dev/null
+++ b/crates/charon-consensus/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Consensus
+//!
+//! Consensus mechanisms and protocols for Charon distributed validator nodes.
+//! This crate implements the consensus algorithms and protocols required for
+//! coordinating validator operations across the distributed network.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_consensus::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-core/Cargo.toml b/crates/charon-core/Cargo.toml
new file mode 100644
index 00000000..3b92ed1a
--- /dev/null
+++ b/crates/charon-core/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-core"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-core/src/lib.rs b/crates/charon-core/src/lib.rs
new file mode 100644
index 00000000..a3ed9a9d
--- /dev/null
+++ b/crates/charon-core/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Core
+//!
+//! Core functionality and utilities for the Charon distributed validator node.
+//! This crate provides the fundamental building blocks, data structures, and
+//! core algorithms used throughout the Charon system.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_core::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-crypto/Cargo.toml b/crates/charon-crypto/Cargo.toml
new file mode 100644
index 00000000..0787a13c
--- /dev/null
+++ b/crates/charon-crypto/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-crypto"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-crypto/src/lib.rs b/crates/charon-crypto/src/lib.rs
new file mode 100644
index 00000000..4a219bc9
--- /dev/null
+++ b/crates/charon-crypto/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Crypto
+//!
+//! Cryptographic primitives and utilities for the Charon distributed validator node.
+//! This crate provides cryptographic functions, key management, and security
+//! operations required for distributed validator operations.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_crypto::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-db/Cargo.toml b/crates/charon-db/Cargo.toml
new file mode 100644
index 00000000..e0d33eb6
--- /dev/null
+++ b/crates/charon-db/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-db"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-db/src/lib.rs b/crates/charon-db/src/lib.rs
new file mode 100644
index 00000000..b3317219
--- /dev/null
+++ b/crates/charon-db/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Database
+//!
+//! Database layer and persistence for the Charon distributed validator node.
+//! This crate provides database abstractions, storage backends, and data
+//! persistence mechanisms for validator state and operations.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_db::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-dkg/Cargo.toml b/crates/charon-dkg/Cargo.toml
new file mode 100644
index 00000000..07652833
--- /dev/null
+++ b/crates/charon-dkg/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-dkg"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-dkg/src/lib.rs b/crates/charon-dkg/src/lib.rs
new file mode 100644
index 00000000..907ce5f9
--- /dev/null
+++ b/crates/charon-dkg/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon DKG
+//!
+//! Distributed Key Generation (DKG) protocols for Charon distributed validator nodes.
+//! This crate implements the cryptographic protocols required for generating,
+//! distributing, and managing validator keys across the distributed network.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_dkg::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-errors/Cargo.toml b/crates/charon-errors/Cargo.toml
new file mode 100644
index 00000000..322b8b77
--- /dev/null
+++ b/crates/charon-errors/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-errors"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-errors/src/lib.rs b/crates/charon-errors/src/lib.rs
new file mode 100644
index 00000000..a8fe4963
--- /dev/null
+++ b/crates/charon-errors/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Errors
+//!
+//! Error types and error handling utilities for the Charon distributed validator node.
+//! This crate defines the error types, error codes, and error handling mechanisms
+//! used throughout the Charon system.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_errors::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-eth2/Cargo.toml b/crates/charon-eth2/Cargo.toml
new file mode 100644
index 00000000..0474ba6f
--- /dev/null
+++ b/crates/charon-eth2/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-eth2"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-eth2/src/lib.rs b/crates/charon-eth2/src/lib.rs
new file mode 100644
index 00000000..eb124245
--- /dev/null
+++ b/crates/charon-eth2/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon ETH2
+//!
+//! Ethereum 2.0 integration and utilities for the Charon distributed validator node.
+//! This crate provides interfaces, types, and utilities for interacting with
+//! Ethereum 2.0 networks and validator operations.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_eth2::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-observability/Cargo.toml b/crates/charon-observability/Cargo.toml
new file mode 100644
index 00000000..7e69b12f
--- /dev/null
+++ b/crates/charon-observability/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-observability"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-observability/src/lib.rs b/crates/charon-observability/src/lib.rs
new file mode 100644
index 00000000..ae536441
--- /dev/null
+++ b/crates/charon-observability/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Observability
+//!
+//! Observability and monitoring utilities for the Charon distributed validator node.
+//! This crate provides logging, metrics, tracing, and monitoring capabilities
+//! for tracking and debugging validator operations.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_observability::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-p2p/Cargo.toml b/crates/charon-p2p/Cargo.toml
new file mode 100644
index 00000000..0795dc28
--- /dev/null
+++ b/crates/charon-p2p/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-p2p"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-p2p/src/lib.rs b/crates/charon-p2p/src/lib.rs
new file mode 100644
index 00000000..083992d0
--- /dev/null
+++ b/crates/charon-p2p/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon P2P
+//!
+//! Peer-to-peer networking and communication for the Charon distributed validator node.
+//! This crate provides networking protocols, peer discovery, and communication
+//! mechanisms for validator nodes to coordinate and exchange information.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_p2p::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-serde/Cargo.toml b/crates/charon-serde/Cargo.toml
new file mode 100644
index 00000000..1d33e20f
--- /dev/null
+++ b/crates/charon-serde/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-serde"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-serde/src/lib.rs b/crates/charon-serde/src/lib.rs
new file mode 100644
index 00000000..ca27ddb4
--- /dev/null
+++ b/crates/charon-serde/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Serde
+//!
+//! Serialization and deserialization utilities for the Charon distributed validator node.
+//! This crate provides custom serialization logic, format support, and data
+//! transformation utilities for validator operations and communication.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_serde::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-testutil/Cargo.toml b/crates/charon-testutil/Cargo.toml
new file mode 100644
index 00000000..8959f5f0
--- /dev/null
+++ b/crates/charon-testutil/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-testutil"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-testutil/src/lib.rs b/crates/charon-testutil/src/lib.rs
new file mode 100644
index 00000000..3e8f9f9d
--- /dev/null
+++ b/crates/charon-testutil/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Test Utilities
+//!
+//! Testing utilities and mock implementations for the Charon distributed validator node.
+//! This crate provides test helpers, mock objects, and testing utilities
+//! for unit tests, integration tests, and development.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_testutil::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon-types/Cargo.toml b/crates/charon-types/Cargo.toml
new file mode 100644
index 00000000..0851da72
--- /dev/null
+++ b/crates/charon-types/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon-types"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon-types/src/lib.rs b/crates/charon-types/src/lib.rs
new file mode 100644
index 00000000..e2e368ee
--- /dev/null
+++ b/crates/charon-types/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon Types
+//!
+//! Common types and data structures for the Charon distributed validator node.
+//! This crate defines the core types, enums, and data structures used
+//! throughout the Charon system for type safety and consistency.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon_types::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/crates/charon/Cargo.toml b/crates/charon/Cargo.toml
new file mode 100644
index 00000000..fc437a8a
--- /dev/null
+++ b/crates/charon/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "charon"
+version.workspace = true
+edition.workspace = true
+repository.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+
+[lints]
+workspace = true
diff --git a/crates/charon/src/lib.rs b/crates/charon/src/lib.rs
new file mode 100644
index 00000000..1359319b
--- /dev/null
+++ b/crates/charon/src/lib.rs
@@ -0,0 +1,39 @@
+//! # Charon
+//!
+//! The main Charon library providing distributed validator key management and coordination
+//! for Ethereum 2.0 validators. This crate serves as the primary entry point for the
+//! Charon distributed validator node implementation.
+
+/// Adds two numbers together.
+///
+/// # Arguments
+///
+/// * `left` - The first number to add
+/// * `right` - The second number to add
+///
+/// # Returns
+///
+/// The sum of the two numbers
+///
+/// # Examples
+///
+/// ```
+/// use charon::add;
+///
+/// let result = add(2, 2);
+/// assert_eq!(result, 4);
+/// ```
+pub fn add(left: u64, right: u64) -> u64 {
+ left.wrapping_add(right)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index d2886b2b..00000000
--- a/examples/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Examples
-
-TODO(template) describe your examples here
-
-To run an example
-
-```sh
-# TODO(template) update an example name
-cargo run -p examples --bin addition
-```
-
-* `addition` - shows how to add two bounded integers with the [`template_crate`](../template_crate/) library.
\ No newline at end of file
diff --git a/examples/src/bin/addition.rs b/examples/src/bin/addition.rs
deleted file mode 100644
index 5d90fb75..00000000
--- a/examples/src/bin/addition.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// TODO(template) - remove/change the code below and rename the example
-use template_crate::add_small_integers;
-
-fn main() {
- println!("{:?}", add_small_integers(6, 8));
-}
diff --git a/katex-header.html b/katex-header.html
deleted file mode 100644
index 32ac35a4..00000000
--- a/katex-header.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 73cb934d..2936be92 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,4 @@
[toolchain]
channel = "stable"
-components = ["rustfmt", "clippy"]
+version = "1.89.0"
+components = ["rustfmt", "clippy"]
\ No newline at end of file
diff --git a/template_crate/Cargo.toml b/template_crate/Cargo.toml
deleted file mode 100644
index e0b327d2..00000000
--- a/template_crate/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-# TODO(template) rename
-name = "template_crate"
-version.workspace = true
-edition.workspace = true
-repository.workspace = true
-license.workspace = true
-
-[dependencies]
-# TODO(template) prefer workspace level dependencies
-# to keep DRY if you have a binary crate
-# Use `default-features = false`
-# and explicitly list features to prevent code bloat and
-# code break after upgrades
-thiserror = { version = "1.0", default-features = false }
-
-[dev-dependencies]
-proptest = { workspace = true }
-
-# TODO(template)
-# don't forget to put this at every crate
-# to inherit workspace's lints
-[lints]
-workspace = true
diff --git a/template_crate/README.md b/template_crate/README.md
deleted file mode 100644
index 80857559..00000000
--- a/template_crate/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO(template) update crate name here
-
-TODO(template) A short description of this specific crate
\ No newline at end of file
diff --git a/template_crate/doc/mainpage-doc.md b/template_crate/doc/mainpage-doc.md
deleted file mode 100644
index e86bdddc..00000000
--- a/template_crate/doc/mainpage-doc.md
+++ /dev/null
@@ -1 +0,0 @@
-# TODO(template) main doc section heading
\ No newline at end of file
diff --git a/template_crate/src/lib.rs b/template_crate/src/lib.rs
deleted file mode 100644
index f3b62def..00000000
--- a/template_crate/src/lib.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// TODO(template) additional documentation files
-#![doc = include_str!("../doc/mainpage-doc.md")]
-
-// TODO(template) - remove/change the code below
-
-use thiserror::Error;
-
-/// Parameter error
-#[derive(Debug, Error, PartialEq)]
-pub enum ParameterError {
- /// One of the arguments is greater than the `UPPER_BOUND`
- #[error("the integer {0} is too large")]
- TooLarge(u8),
-}
-
-/// For constants prefer to provide
-/// a reference to a paper section
-/// where the constant is defined
-/// or justify the value logically
-pub const UPPER_BOUND: u8 = 2u8.pow(7);
-
-/// Adds two small integers together.
-pub fn add_small_integers(a: u8, b: u8) -> Result {
- if a.max(b) >= UPPER_BOUND {
- return Err(ParameterError::TooLarge(a.max(b)));
- }
- Ok(a.checked_add(b)
- .expect("the upper bound ensures non-overflow"))
-}
-
-/// Subtracts one small integer from another.
-/// This function is intentionally not used in tests to reduce code coverage.
-pub fn sub_small_integers(a: u8, b: u8) -> Result {
- if a.max(b) >= UPPER_BOUND {
- return Err(ParameterError::TooLarge(a.max(b)));
- }
-
- if b > a {
- return Err(ParameterError::TooLarge(b));
- }
-
- Ok(a.checked_sub(b)
- .expect("the upper bound ensures non-overflow"))
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use proptest::proptest;
-
- #[test]
- fn addition_of_bounded() {
- assert_eq!(Ok(8), add_small_integers(3, 5));
- }
-
- #[test]
- fn addition_bound_check() {
- assert_eq!(
- Err(ParameterError::TooLarge(200)),
- add_small_integers(200, 5)
- );
- }
-
- #[test]
- fn addition_edge_case() {
- assert_eq!(
- Ok(254),
- add_small_integers(UPPER_BOUND - 1, UPPER_BOUND - 1)
- );
- }
-
- proptest! {
- #[test]
- fn addition_proptest(a in 0_u8..20, b in 0_u8..20) {
- assert_eq!(
- a.checked_add(b),
- add_small_integers(a, b).ok()
- );
- }
- }
-}
From a05777180aa78bb547d11c13a56f350f3ae9cd74 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Wed, 8 Oct 2025 15:47:39 +0800
Subject: [PATCH 02/13] feat: update CI to use nightly toolchain for rustfmt
---
.github/workflows/linter.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 2f437c36..4a0b061d 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run Fmt
- run: cargo fmt --all -- --check
+ run: cargo +nightly fmt --all -- --check
- name: Run Clippy
run: cargo clippy --all-targets --all-features
From 05287a52ede17f87528994a9b48782454c13ce8e Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Wed, 8 Oct 2025 15:49:21 +0800
Subject: [PATCH 03/13] feat: update CI to use nightly toolchain for rustfmt
---
.github/workflows/linter.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
index 4a0b061d..b1ee0724 100644
--- a/.github/workflows/linter.yml
+++ b/.github/workflows/linter.yml
@@ -13,6 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
+ - run: rustup +nightly component add rustfmt
- name: Run Fmt
run: cargo +nightly fmt --all -- --check
From 30c33ef9c4b1edadedd60021852cc827a54e5380 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Wed, 8 Oct 2025 15:51:30 +0800
Subject: [PATCH 04/13] fix: fmt
---
crates/charon-cli/src/lib.rs | 1 -
crates/charon-crypto/src/lib.rs | 6 +++---
crates/charon-dkg/src/lib.rs | 7 ++++---
crates/charon-errors/src/lib.rs | 6 +++---
crates/charon-eth2/src/lib.rs | 6 +++---
crates/charon-observability/src/lib.rs | 6 +++---
crates/charon-p2p/src/lib.rs | 7 ++++---
crates/charon-serde/src/lib.rs | 7 ++++---
crates/charon-testutil/src/lib.rs | 6 +++---
crates/charon/src/lib.rs | 6 +++---
10 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/crates/charon-cli/src/lib.rs b/crates/charon-cli/src/lib.rs
index 5cfbd16e..338a369a 100644
--- a/crates/charon-cli/src/lib.rs
+++ b/crates/charon-cli/src/lib.rs
@@ -1,4 +1,3 @@
-
//! # Charon CLI
//!
//! Command-line interface for the Charon distributed validator node.
diff --git a/crates/charon-crypto/src/lib.rs b/crates/charon-crypto/src/lib.rs
index 4a219bc9..5eb6f3e5 100644
--- a/crates/charon-crypto/src/lib.rs
+++ b/crates/charon-crypto/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon Crypto
//!
-//! Cryptographic primitives and utilities for the Charon distributed validator node.
-//! This crate provides cryptographic functions, key management, and security
-//! operations required for distributed validator operations.
+//! Cryptographic primitives and utilities for the Charon distributed validator
+//! node. This crate provides cryptographic functions, key management, and
+//! security operations required for distributed validator operations.
/// Adds two numbers together.
///
diff --git a/crates/charon-dkg/src/lib.rs b/crates/charon-dkg/src/lib.rs
index 907ce5f9..e5ba56a5 100644
--- a/crates/charon-dkg/src/lib.rs
+++ b/crates/charon-dkg/src/lib.rs
@@ -1,8 +1,9 @@
//! # Charon DKG
//!
-//! Distributed Key Generation (DKG) protocols for Charon distributed validator nodes.
-//! This crate implements the cryptographic protocols required for generating,
-//! distributing, and managing validator keys across the distributed network.
+//! Distributed Key Generation (DKG) protocols for Charon distributed validator
+//! nodes. This crate implements the cryptographic protocols required for
+//! generating, distributing, and managing validator keys across the distributed
+//! network.
/// Adds two numbers together.
///
diff --git a/crates/charon-errors/src/lib.rs b/crates/charon-errors/src/lib.rs
index a8fe4963..938ced88 100644
--- a/crates/charon-errors/src/lib.rs
+++ b/crates/charon-errors/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon Errors
//!
-//! Error types and error handling utilities for the Charon distributed validator node.
-//! This crate defines the error types, error codes, and error handling mechanisms
-//! used throughout the Charon system.
+//! Error types and error handling utilities for the Charon distributed
+//! validator node. This crate defines the error types, error codes, and error
+//! handling mechanisms used throughout the Charon system.
/// Adds two numbers together.
///
diff --git a/crates/charon-eth2/src/lib.rs b/crates/charon-eth2/src/lib.rs
index eb124245..da8e769e 100644
--- a/crates/charon-eth2/src/lib.rs
+++ b/crates/charon-eth2/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon ETH2
//!
-//! Ethereum 2.0 integration and utilities for the Charon distributed validator node.
-//! This crate provides interfaces, types, and utilities for interacting with
-//! Ethereum 2.0 networks and validator operations.
+//! Ethereum 2.0 integration and utilities for the Charon distributed validator
+//! node. This crate provides interfaces, types, and utilities for interacting
+//! with Ethereum 2.0 networks and validator operations.
/// Adds two numbers together.
///
diff --git a/crates/charon-observability/src/lib.rs b/crates/charon-observability/src/lib.rs
index ae536441..6d097efd 100644
--- a/crates/charon-observability/src/lib.rs
+++ b/crates/charon-observability/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon Observability
//!
-//! Observability and monitoring utilities for the Charon distributed validator node.
-//! This crate provides logging, metrics, tracing, and monitoring capabilities
-//! for tracking and debugging validator operations.
+//! Observability and monitoring utilities for the Charon distributed validator
+//! node. This crate provides logging, metrics, tracing, and monitoring
+//! capabilities for tracking and debugging validator operations.
/// Adds two numbers together.
///
diff --git a/crates/charon-p2p/src/lib.rs b/crates/charon-p2p/src/lib.rs
index 083992d0..9144de5e 100644
--- a/crates/charon-p2p/src/lib.rs
+++ b/crates/charon-p2p/src/lib.rs
@@ -1,8 +1,9 @@
//! # Charon P2P
//!
-//! Peer-to-peer networking and communication for the Charon distributed validator node.
-//! This crate provides networking protocols, peer discovery, and communication
-//! mechanisms for validator nodes to coordinate and exchange information.
+//! Peer-to-peer networking and communication for the Charon distributed
+//! validator node. This crate provides networking protocols, peer discovery,
+//! and communication mechanisms for validator nodes to coordinate and exchange
+//! information.
/// Adds two numbers together.
///
diff --git a/crates/charon-serde/src/lib.rs b/crates/charon-serde/src/lib.rs
index ca27ddb4..81789bf5 100644
--- a/crates/charon-serde/src/lib.rs
+++ b/crates/charon-serde/src/lib.rs
@@ -1,8 +1,9 @@
//! # Charon Serde
//!
-//! Serialization and deserialization utilities for the Charon distributed validator node.
-//! This crate provides custom serialization logic, format support, and data
-//! transformation utilities for validator operations and communication.
+//! Serialization and deserialization utilities for the Charon distributed
+//! validator node. This crate provides custom serialization logic, format
+//! support, and data transformation utilities for validator operations and
+//! communication.
/// Adds two numbers together.
///
diff --git a/crates/charon-testutil/src/lib.rs b/crates/charon-testutil/src/lib.rs
index 3e8f9f9d..76bcca44 100644
--- a/crates/charon-testutil/src/lib.rs
+++ b/crates/charon-testutil/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon Test Utilities
//!
-//! Testing utilities and mock implementations for the Charon distributed validator node.
-//! This crate provides test helpers, mock objects, and testing utilities
-//! for unit tests, integration tests, and development.
+//! Testing utilities and mock implementations for the Charon distributed
+//! validator node. This crate provides test helpers, mock objects, and testing
+//! utilities for unit tests, integration tests, and development.
/// Adds two numbers together.
///
diff --git a/crates/charon/src/lib.rs b/crates/charon/src/lib.rs
index 1359319b..5ef0c7fe 100644
--- a/crates/charon/src/lib.rs
+++ b/crates/charon/src/lib.rs
@@ -1,8 +1,8 @@
//! # Charon
//!
-//! The main Charon library providing distributed validator key management and coordination
-//! for Ethereum 2.0 validators. This crate serves as the primary entry point for the
-//! Charon distributed validator node implementation.
+//! The main Charon library providing distributed validator key management and
+//! coordination for Ethereum 2.0 validators. This crate serves as the primary
+//! entry point for the Charon distributed validator node implementation.
/// Adds two numbers together.
///
From d4147f3f0827458f064b4cc5d0a593855c7b23a6 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Wed, 8 Oct 2025 16:55:41 +0800
Subject: [PATCH 05/13] refactor: reorganize workspace members and remove
charon-types crate
---
Cargo.toml | 20 ++++++++++++++---
crates/charon-types/Cargo.toml | 12 -----------
crates/charon-types/src/lib.rs | 39 ----------------------------------
3 files changed, 17 insertions(+), 54 deletions(-)
delete mode 100644 crates/charon-types/Cargo.toml
delete mode 100644 crates/charon-types/src/lib.rs
diff --git a/Cargo.toml b/Cargo.toml
index 2704e388..3be35481 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,13 +1,27 @@
[workspace]
-name = "charon-rs"
-members = [ "crates/charon", "crates/charon-cli", "crates/charon-cluster", "crates/charon-consensus", "crates/charon-core", "crates/charon-crypto", "crates/charon-db", "crates/charon-dkg", "crates/charon-errors", "crates/charon-eth2", "crates/charon-observability", "crates/charon-p2p", "crates/charon-serde", "crates/charon-testutil", "crates/charon-types"]
+members = [
+ "crates/charon",
+ "crates/charon-cli",
+ "crates/charon-cluster",
+ "crates/charon-consensus",
+ "crates/charon-core",
+ "crates/charon-crypto",
+ "crates/charon-db",
+ "crates/charon-dkg",
+ "crates/charon-errors",
+ "crates/charon-eth2",
+ "crates/charon-observability",
+ "crates/charon-p2p",
+ "crates/charon-serde",
+ "crates/charon-testutil",
+]
resolver = "3"
[workspace.package]
version = "0.1.0"
edition = "2024"
repository = "https://github.com/NethermindEth/charon-rs"
-license = "Apache-2.0" # TODO(template) update license
+license = "Apache-2.0" # TODO(template) update license
publish = false
[workspace.dependencies]
diff --git a/crates/charon-types/Cargo.toml b/crates/charon-types/Cargo.toml
deleted file mode 100644
index 0851da72..00000000
--- a/crates/charon-types/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "charon-types"
-version.workspace = true
-edition.workspace = true
-repository.workspace = true
-license.workspace = true
-publish.workspace = true
-
-[dependencies]
-
-[lints]
-workspace = true
diff --git a/crates/charon-types/src/lib.rs b/crates/charon-types/src/lib.rs
deleted file mode 100644
index e2e368ee..00000000
--- a/crates/charon-types/src/lib.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//! # Charon Types
-//!
-//! Common types and data structures for the Charon distributed validator node.
-//! This crate defines the core types, enums, and data structures used
-//! throughout the Charon system for type safety and consistency.
-
-/// Adds two numbers together.
-///
-/// # Arguments
-///
-/// * `left` - The first number to add
-/// * `right` - The second number to add
-///
-/// # Returns
-///
-/// The sum of the two numbers
-///
-/// # Examples
-///
-/// ```
-/// use charon_types::add;
-///
-/// let result = add(2, 2);
-/// assert_eq!(result, 4);
-/// ```
-pub fn add(left: u64, right: u64) -> u64 {
- left.wrapping_add(right)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn it_works() {
- let result = add(2, 2);
- assert_eq!(result, 4);
- }
-}
From 27267735da8c0df59bc8e5eea61d6595ef25c808 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Thu, 9 Oct 2025 15:30:07 +0800
Subject: [PATCH 06/13] feat: add core types and dependencies for Charon
---
Cargo.toml | 9 +-
crates/charon-core/Cargo.toml | 4 +
crates/charon-core/src/lib.rs | 35 +--
crates/charon-core/src/types.rs | 539 ++++++++++++++++++++++++++++++++
4 files changed, 551 insertions(+), 36 deletions(-)
create mode 100644 crates/charon-core/src/types.rs
diff --git a/Cargo.toml b/Cargo.toml
index 3be35481..e7428797 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,13 +24,16 @@ repository = "https://github.com/NethermindEth/charon-rs"
license = "Apache-2.0" # TODO(template) update license
publish = false
-[workspace.dependencies]
-proptest = "1"
-
[workspace.lints.rust]
missing_docs = "deny"
unsafe_code = "forbid"
+[workspace.dependencies]
+serde = { version = "1.0", features = ["derive"] }
+serde_json = { version = "^1.0" }
+hex = { version = "^0.4.3" }
+chrono = { version = "0.4", features = ["serde"] }
+
[workspace.lints.clippy]
arithmetic_side_effects = "deny"
cast_lossless = "deny"
diff --git a/crates/charon-core/Cargo.toml b/crates/charon-core/Cargo.toml
index 3b92ed1a..baba8427 100644
--- a/crates/charon-core/Cargo.toml
+++ b/crates/charon-core/Cargo.toml
@@ -7,6 +7,10 @@ license.workspace = true
publish.workspace = true
[dependencies]
+serde.workspace = true
+serde_json.workspace = true
+hex.workspace = true
+chrono.workspace = true
[lints]
workspace = true
diff --git a/crates/charon-core/src/lib.rs b/crates/charon-core/src/lib.rs
index a3ed9a9d..7a6c37d5 100644
--- a/crates/charon-core/src/lib.rs
+++ b/crates/charon-core/src/lib.rs
@@ -4,36 +4,5 @@
//! This crate provides the fundamental building blocks, data structures, and
//! core algorithms used throughout the Charon system.
-/// Adds two numbers together.
-///
-/// # Arguments
-///
-/// * `left` - The first number to add
-/// * `right` - The second number to add
-///
-/// # Returns
-///
-/// The sum of the two numbers
-///
-/// # Examples
-///
-/// ```
-/// use charon_core::add;
-///
-/// let result = add(2, 2);
-/// assert_eq!(result, 4);
-/// ```
-pub fn add(left: u64, right: u64) -> u64 {
- left.wrapping_add(right)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn it_works() {
- let result = add(2, 2);
- assert_eq!(result, 4);
- }
-}
+/// Types for the Charon core.
+pub mod types;
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
new file mode 100644
index 00000000..088cf44a
--- /dev/null
+++ b/crates/charon-core/src/types.rs
@@ -0,0 +1,539 @@
+//! Types for the Charon core.
+
+use std::{collections::HashMap, fmt::Display, iter, time::Duration};
+
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use std::fmt::Debug as StdDebug;
+
+/// The type of duty.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum DutyType {
+ /// Unknown duty type.
+ Unknown,
+ /// Proposer duty type.
+ Proposer,
+ /// Attester duty type.
+ Attester,
+ /// Signature duty type.
+ Signature,
+ /// Exit duty type.
+ Exit,
+ /// Builder proposer duty type.
+ BuilderProposer,
+ /// Builder registration duty type.
+ BuilderRegistration,
+ /// Randao duty type.
+ Randao,
+ /// Prepare aggregator duty type.
+ PrepareAggregator,
+ /// Aggregator duty type.
+ Aggregator,
+ /// Sync message duty type.
+ SyncMessage,
+ /// Prepare sync contribution duty type.
+ PrepareSyncContribution,
+ /// Sync contribution duty type.
+ SyncContribution,
+ /// Info sync duty type.
+ InfoSync,
+ /// Duty sentinel duty type. Must always be last.
+ DutySentinel(Box),
+}
+
+impl Display for DutyType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ // safe to unwrap because we know the duty type is valid
+ let v = serde_json::to_value(self).expect("failed to serialize duty type");
+ if let Some(s) = v.as_str() {
+ write!(f, "{}", s)
+ } else {
+ // fallback for non-string variants (structs, numbers, etc.)
+ write!(f, "{}", v)
+ }
+ }
+}
+
+/// SlotNumber struct
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct SlotNumber(u64);
+
+impl Display for SlotNumber {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl From for SlotNumber {
+ fn from(slot: u64) -> Self {
+ Self::new(slot)
+ }
+}
+
+impl From for u64 {
+ fn from(slot: SlotNumber) -> Self {
+ slot.inner()
+ }
+}
+
+impl SlotNumber {
+ /// Create a new slot number.
+ pub fn new(slot: u64) -> Self {
+ SlotNumber(slot)
+ }
+
+ /// Inner slot number.
+ pub fn inner(&self) -> u64 {
+ self.0
+ }
+
+ /// Next slot number.
+ pub fn next(&self) -> Self {
+ Self::new(self.inner().saturating_add(1))
+ }
+}
+
+/// Duty struct
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Duty {
+ /// Ethereum consensus layer slot.
+ pub slot: SlotNumber,
+ /// Duty type performed in the slot.
+ pub duty_type: DutyType,
+}
+
+impl Display for Duty {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}/{}", self.slot, self.duty_type)
+ }
+}
+
+impl Duty {
+ /// Create a new duty.
+ pub fn new(slot: SlotNumber, duty_type: DutyType) -> Self {
+ Self { slot, duty_type }
+ }
+
+ /// Create a new attester duty.
+ pub fn new_attester_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Attester)
+ }
+
+ /// Create a new randao duty.
+ pub fn new_randao_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Randao)
+ }
+
+ /// Create a new proposer duty.
+ pub fn new_proposer_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Proposer)
+ }
+
+ /// Create a new builder proposer duty.
+ pub fn new_builder_proposer_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::BuilderProposer)
+ }
+
+ /// Create a new builder registration duty.
+ pub fn new_builder_registration_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::BuilderRegistration)
+ }
+
+ /// Create a new sync contribution duty.
+ pub fn new_sync_contribution_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::SyncContribution)
+ }
+
+ /// Create a new signature duty.
+ pub fn new_signature_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Signature)
+ }
+
+ /// Create a new prepare aggregator duty.
+ pub fn new_prepare_aggregator_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::PrepareAggregator)
+ }
+
+ /// Create a new aggregator duty.
+ pub fn new_aggregator_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Aggregator)
+ }
+
+ /// Create a new sync message duty.
+ pub fn new_sync_message_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::SyncMessage)
+ }
+
+ /// Create a new prepare sync contribution duty.
+ pub fn new_prepare_sync_contribution_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::PrepareSyncContribution)
+ }
+
+ /// Create a new info sync duty.
+ pub fn new_info_sync_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::InfoSync)
+ }
+}
+
+/// The type of proposal.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum ProposalType {
+ /// Full proposal type.
+ Full,
+ /// Builder proposal type.
+ Builder,
+ /// Synthetic proposal type.
+ Synthetic,
+}
+
+// In golang implementation they use pk_len = 98, which is 0x + [48 bytes]
+// We use pk_len = 48, which is [48 bytes], the main difference is that we store
+// the pub key as [u8; 48] instead of string.
+const PK_LEN: usize = 48;
+// const SIG_LEN: usize = 96;
+
+/// Public key struct
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct PubKey(pub(crate) [u8; PK_LEN]);
+
+impl Serialize for PubKey {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_str(&self.to_string())
+ }
+}
+
+impl<'de> Deserialize<'de> for PubKey {
+ fn deserialize(deserializer: D) -> Result
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let hex_str = String::deserialize(deserializer)?;
+ let hex_str = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
+
+ let bytes = hex::decode(hex_str).map_err(serde::de::Error::custom)?;
+
+ if bytes.len() != PK_LEN {
+ return Err(serde::de::Error::custom(format!(
+ "invalid public key length: got {}, want {}",
+ bytes.len(),
+ PK_LEN
+ )));
+ }
+
+ let mut pk = [0u8; PK_LEN];
+ pk.copy_from_slice(&bytes);
+ Ok(PubKey(pk))
+ }
+}
+
+impl From<[u8; PK_LEN]> for PubKey {
+ fn from(pk: [u8; PK_LEN]) -> Self {
+ PubKey(pk)
+ }
+}
+
+impl PubKey {
+ /// Create a new public key.
+ pub fn new(pk: [u8; PK_LEN]) -> Self {
+ PubKey(pk)
+ }
+}
+
+impl Display for PubKey {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "0x{}", hex::encode(self.0))
+ }
+}
+
+/// Implement AsRef<[u8]> for PubKey to allow for easy conversion to bytes.
+impl AsRef<[u8]> for PubKey {
+ fn as_ref(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+// todo: add toEth2Format for the pub key
+// https://github.com/ObolNetwork/charon/blob/b3008103c5429b031b63518195f4c49db4e9a68d/core/types.go#L311
+
+/// Duty definition type
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct DutyDefinition(T);
+
+/// Duty definition set
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct DutyDefinitionSet(HashMap>)
+where
+ T: Clone + Serialize + StdDebug;
+
+/// Unsigned data type
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct UnsignedData(T);
+
+/// Unsigned data set
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct UnsignedDataSet(HashMap>)
+where
+ T: Clone + Serialize + StdDebug;
+
+// todo: add proper signature type
+/// Signature type
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Signature(pub(crate) [u8; 1]);
+
+/// Signed data type
+pub trait SignedData: Clone + Serialize + StdDebug {
+ /// The error type
+ type Error: std::error::Error;
+
+ /// signature returns the signed duty data's signature.
+ fn signature(&self) -> Signature;
+
+ /// set_signature returns a copy of signed duty data with the signature
+ /// replaced.
+ fn set_signature(&mut self, signature: Signature) -> Result<(), Self::Error>;
+
+ /// message_root returns the message root for the unsigned data.
+ fn message_root(&self) -> [u8; 32];
+}
+
+// todo: add Eth2SignedData type
+// https://github.com/ObolNetwork/charon/blob/b3008103c5429b031b63518195f4c49db4e9a68d/core/types.go#L396
+
+/// ParSignedData is a partially signed duty data only signed by a single
+/// threshold BLS share.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ParSignedData {
+ /// Partially signed duty data.
+ pub signed_data: T,
+
+ /// Threshold BLS share index.
+ pub share_idx: u64,
+}
+
+/// ParSignedDataSet is a set of partially signed duty data only signed by a
+/// single threshold BLS share.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ParSignedDataSet(HashMap>);
+
+/// SignedDataSet is a set of signed duty data.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct SignedDataSet(HashMap);
+
+/// Slot struct
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Slot {
+ /// The slot number.
+ pub slot: SlotNumber,
+
+ /// The time.
+ pub time: DateTime,
+
+ /// The slot type.
+ pub slot_duration: Duration,
+
+ /// Slots per epoch.
+ pub slots_per_epoch: u64,
+}
+
+impl Slot {
+ /// Get the epoch of the slot
+ pub fn epoch(&self) -> u64 {
+ #[allow(clippy::arithmetic_side_effects)]
+ self.slot.inner().saturating_div(self.slots_per_epoch)
+ }
+
+ /// Returns true if this is the last slot in the epoch.
+ #[allow(clippy::arithmetic_side_effects)]
+ pub fn last_in_epoch(&self) -> bool {
+ self.slot.inner().wrapping_rem(self.slots_per_epoch)
+ == self.slots_per_epoch.saturating_sub(1)
+ }
+
+ /// Returns true if this is the first slot in the epoch.
+ #[allow(clippy::arithmetic_side_effects)]
+ pub fn first_in_epoch(&self) -> bool {
+ self.slot.inner().wrapping_rem(self.slots_per_epoch) == 0
+ }
+
+ /// Returns the next slot
+ #[allow(clippy::arithmetic_side_effects)]
+ pub fn next_slot(&self) -> Slot {
+ Slot {
+ slot: self.slot.next(),
+ time: self.time + self.slot_duration,
+ slot_duration: self.slot_duration,
+ slots_per_epoch: self.slots_per_epoch,
+ }
+ }
+
+ /// Returns an iterator over slots starting from this one
+ pub fn iter(&self) -> impl Iterator- {
+ iter::successors(Some(self.clone()), |slot| Some(slot.next_slot()))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_pub_key_to_string() {
+ const ORIGINAL_PK_LEN: usize = 98;
+
+ let key = PubKey::new([0; PK_LEN]);
+
+ // Check whether the string representation is the same as the go's public key
+ // length
+ assert_eq!(key.to_string().len(), ORIGINAL_PK_LEN);
+ assert_eq!(
+ key.to_string(),
+ "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ );
+ }
+
+ #[test]
+ fn test_new_builder_registration_duty() {
+ let duty = Duty::new_builder_registration_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::BuilderRegistration);
+ assert_eq!(duty.to_string(), "1/builder_registration");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_signature_duty() {
+ let duty = Duty::new_signature_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::Signature);
+ assert_eq!(duty.to_string(), "1/signature");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_prepare_aggregator_duty() {
+ let duty = Duty::new_prepare_aggregator_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::PrepareAggregator);
+ assert_eq!(duty.to_string(), "1/prepare_aggregator");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_aggregator_duty() {
+ let duty = Duty::new_aggregator_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::Aggregator);
+ assert_eq!(duty.to_string(), "1/aggregator");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_sync_contribution_duty() {
+ let duty = Duty::new_sync_contribution_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::SyncContribution);
+ assert_eq!(duty.to_string(), "1/sync_contribution");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_sync_message_duty() {
+ let duty = Duty::new_sync_message_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::SyncMessage);
+ assert_eq!(duty.to_string(), "1/sync_message");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_prepare_sync_contribution_duty() {
+ let duty = Duty::new_prepare_sync_contribution_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::PrepareSyncContribution);
+ assert_eq!(duty.to_string(), "1/prepare_sync_contribution");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_new_info_sync_duty() {
+ let duty = Duty::new_info_sync_duty(SlotNumber(1));
+ assert_eq!(duty.duty_type, DutyType::InfoSync);
+ assert_eq!(duty.to_string(), "1/info_sync");
+ assert_eq!(u64::from(duty.slot), 1);
+ }
+
+ #[test]
+ fn test_slot() {
+ let slot = Slot {
+ slot: SlotNumber(123),
+ time: DateTime::from_timestamp(100, 100).unwrap(),
+ slot_duration: Duration::from_secs(4),
+ slots_per_epoch: 32,
+ };
+
+ assert_eq!(u64::from(slot.slot), 0x7b);
+ assert_eq!(slot.epoch(), 3);
+ assert!(!slot.last_in_epoch());
+ assert!(!slot.first_in_epoch());
+
+ let next = slot.next_slot();
+ assert_eq!(next.slot, SlotNumber(124));
+ assert_eq!(next.time, DateTime::from_timestamp(104, 100).unwrap());
+ assert_eq!(next.slot_duration, Duration::from_secs(4));
+ assert_eq!(next.slots_per_epoch, 32);
+ }
+
+ #[test]
+ fn test_serialize_pubkey() {
+ let pk = PubKey::new([42u8; PK_LEN]);
+ let serialized = serde_json::to_string(&pk).unwrap();
+ assert_eq!(serialized, format!("\"0x{}\"", hex::encode([42u8; PK_LEN])));
+ }
+
+ #[test]
+ fn test_deserialize_pubkey() {
+ let serialized = format!("\"0x{}\"", hex::encode([42u8; PK_LEN]));
+ let deserialized: PubKey = serde_json::from_str(&serialized).unwrap();
+ assert_eq!(deserialized, PubKey::new([42u8; PK_LEN]));
+ }
+
+ #[test]
+ fn test_slot_iter() {
+ let slot = Slot {
+ slot: SlotNumber(123),
+ time: DateTime::from_timestamp(100, 100).unwrap(),
+ slot_duration: Duration::from_secs(4),
+ slots_per_epoch: 32,
+ };
+
+ assert_eq!(slot.iter().nth(10).unwrap().slot, SlotNumber(133));
+ assert_eq!(slot.iter().nth(31).unwrap().slot, SlotNumber(154));
+ assert_eq!(slot.iter().nth(32).unwrap().slot, SlotNumber(155));
+ assert_eq!(slot.iter().nth(33).unwrap().slot, SlotNumber(156));
+ }
+
+ #[test]
+ fn test_display_duty_type() {
+ assert_eq!(DutyType::Unknown.to_string(), "unknown");
+ assert_eq!(DutyType::Proposer.to_string(), "proposer");
+ assert_eq!(DutyType::Attester.to_string(), "attester");
+ assert_eq!(DutyType::Signature.to_string(), "signature");
+ assert_eq!(DutyType::Exit.to_string(), "exit");
+ assert_eq!(DutyType::BuilderProposer.to_string(), "builder_proposer");
+ assert_eq!(
+ DutyType::BuilderRegistration.to_string(),
+ "builder_registration"
+ );
+ assert_eq!(DutyType::Randao.to_string(), "randao");
+ assert_eq!(
+ DutyType::PrepareAggregator.to_string(),
+ "prepare_aggregator"
+ );
+ assert_eq!(DutyType::Aggregator.to_string(), "aggregator");
+ assert_eq!(DutyType::SyncMessage.to_string(), "sync_message");
+ assert_eq!(
+ DutyType::PrepareSyncContribution.to_string(),
+ "prepare_sync_contribution"
+ );
+ assert_eq!(DutyType::SyncContribution.to_string(), "sync_contribution");
+ assert_eq!(DutyType::InfoSync.to_string(), "info_sync");
+ }
+}
From b44afb68df0f0722a00d867020153a0f5c73cb29 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Thu, 9 Oct 2025 15:36:40 +0800
Subject: [PATCH 07/13] feat: add is_valid method and tests for DutyType
---
crates/charon-core/src/types.rs | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index 088cf44a..c487f2e3 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -55,6 +55,13 @@ impl Display for DutyType {
}
}
+impl DutyType {
+ /// Returns true if the duty type is valid.
+ pub fn is_valid(&self) -> bool {
+ !matches!(self, DutyType::Unknown | DutyType::DutySentinel(_))
+ }
+}
+
/// SlotNumber struct
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SlotNumber(u64);
@@ -536,4 +543,15 @@ mod tests {
assert_eq!(DutyType::SyncContribution.to_string(), "sync_contribution");
assert_eq!(DutyType::InfoSync.to_string(), "info_sync");
}
+
+ #[test]
+ fn test_duty_type_is_valid() {
+ assert!(!DutyType::Unknown.is_valid());
+ assert!(DutyType::Proposer.is_valid());
+ assert!(DutyType::Attester.is_valid());
+ assert!(DutyType::Signature.is_valid());
+ assert!(DutyType::Exit.is_valid());
+ assert!(!DutyType::DutySentinel(Box::new(DutyType::Unknown)).is_valid());
+ assert!(!DutyType::DutySentinel(Box::new(DutyType::Attester)).is_valid());
+ }
}
From 20bd80947b1a2013038a758e25ce841cef2c3b22 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Thu, 9 Oct 2025 18:50:08 +0800
Subject: [PATCH 08/13] feat: enhance Charon core types with new methods and
error handling for PubKey
---
crates/charon-core/src/types.rs | 330 +++++++++++++++++++++++++++++++-
1 file changed, 322 insertions(+), 8 deletions(-)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index c487f2e3..9280c497 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -1,8 +1,8 @@
//! Types for the Charon core.
-use std::{collections::HashMap, fmt::Display, iter, time::Duration};
+use std::{collections::HashMap, fmt::Display, iter};
-use chrono::{DateTime, Utc};
+use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use std::fmt::Debug as StdDebug;
@@ -132,6 +132,11 @@ impl Duty {
Self::new(slot, DutyType::Randao)
}
+ /// Create a new voluntary exit duty.
+ pub fn new_voluntary_exit_duty(slot: SlotNumber) -> Self {
+ Self::new(slot, DutyType::Exit)
+ }
+
/// Create a new proposer duty.
pub fn new_proposer_duty(slot: SlotNumber) -> Self {
Self::new(slot, DutyType::Proposer)
@@ -199,7 +204,7 @@ pub enum ProposalType {
// We use pk_len = 48, which is [48 bytes], the main difference is that we store
// the pub key as [u8; 48] instead of string.
const PK_LEN: usize = 48;
-// const SIG_LEN: usize = 96;
+const SIG_LEN: usize = 96;
/// Public key struct
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -214,6 +219,15 @@ impl Serialize for PubKey {
}
}
+impl TryFrom for PubKey {
+ type Error = PubKeyError;
+
+ fn try_from(value: String) -> Result {
+ let value = value.strip_prefix("0x").unwrap_or(&value);
+ PubKey::from_bytes(&hex::decode(value).map_err(|_| PubKeyError::InvalidString)?)
+ }
+}
+
impl<'de> Deserialize<'de> for PubKey {
fn deserialize(deserializer: D) -> Result
where
@@ -244,11 +258,36 @@ impl From<[u8; PK_LEN]> for PubKey {
}
}
+/// Public key error type
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum PubKeyError {
+ /// Invalid public key length.
+ InvalidLength,
+ /// Invalid public key string.
+ InvalidString,
+}
+
impl PubKey {
/// Create a new public key.
pub fn new(pk: [u8; PK_LEN]) -> Self {
PubKey(pk)
}
+
+ /// Create a new public key from bytes.
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != PK_LEN {
+ return Err(PubKeyError::InvalidLength);
+ }
+ let mut arr = [0u8; PK_LEN];
+ arr.copy_from_slice(bytes);
+ Ok(PubKey(arr))
+ }
+
+ /// Returns logging-friendly abbreviated form: "b82_97f"
+ pub fn abbreviated(&self) -> String {
+ let hex = hex::encode(self.0);
+ format!("{}_{}", &hex[0..3], &hex[93..96])
+ }
}
impl Display for PubKey {
@@ -271,26 +310,122 @@ impl AsRef<[u8]> for PubKey {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DutyDefinition(T);
+impl DutyDefinition
+where
+ T: Clone + Serialize + StdDebug,
+{
+ /// Create a new duty definition.
+ pub fn new(duty_definition: T) -> Self {
+ Self(duty_definition)
+ }
+}
+
/// Duty definition set
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct DutyDefinitionSet(HashMap>)
where
T: Clone + Serialize + StdDebug;
+impl DutyDefinitionSet
+where
+ T: Clone + Serialize + StdDebug,
+{
+ /// Create a new duty definition set.
+ pub fn new() -> Self {
+ Self(HashMap::default())
+ }
+
+ /// Get a duty definition by duty type.
+ pub fn get(&self, duty_type: &DutyType) -> Option<&DutyDefinition> {
+ self.0.get(duty_type)
+ }
+
+ /// Insert a duty definition.
+ pub fn insert(&mut self, duty_type: DutyType, duty_definition: DutyDefinition) {
+ self.0.insert(duty_type, duty_definition);
+ }
+
+ /// Remove a duty definition by duty type.
+ pub fn remove(&mut self, duty_type: &DutyType) -> Option> {
+ self.0.remove(duty_type)
+ }
+
+ /// Inner duty definition set.
+ pub fn inner(&self) -> &HashMap> {
+ &self.0
+ }
+
+ /// Inner duty definition set.
+ pub fn inner_mut(&mut self) -> &mut HashMap> {
+ &mut self.0
+ }
+}
+
/// Unsigned data type
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnsignedData(T);
+impl UnsignedData
+where
+ T: Clone + Serialize + StdDebug,
+{
+ /// Create a new unsigned data.
+ pub fn new(unsigned_data: T) -> Self {
+ Self(unsigned_data)
+ }
+}
/// Unsigned data set
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnsignedDataSet(HashMap>)
where
T: Clone + Serialize + StdDebug;
+impl UnsignedDataSet
+where
+ T: Clone + Serialize + StdDebug,
+{
+ /// Create a new unsigned data set.
+ pub fn new() -> Self {
+ Self(HashMap::default())
+ }
+
+ /// Get an unsigned data by duty type.
+ pub fn get(&self, duty_type: &DutyType) -> Option<&UnsignedData> {
+ self.0.get(duty_type)
+ }
+
+ /// Insert an unsigned data.
+ pub fn insert(&mut self, duty_type: DutyType, unsigned_data: UnsignedData) {
+ self.0.insert(duty_type, unsigned_data);
+ }
+
+ /// Remove an unsigned data by duty type.
+ pub fn remove(&mut self, duty_type: &DutyType) -> Option> {
+ self.0.remove(duty_type)
+ }
+
+ /// Inner unsigned data set.
+ pub fn inner(&self) -> &HashMap> {
+ &self.0
+ }
+
+ /// Inner unsigned data set.
+ pub fn inner_mut(&mut self) -> &mut HashMap> {
+ &mut self.0
+ }
+}
+
// todo: add proper signature type
/// Signature type
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Signature(pub(crate) [u8; 1]);
+pub struct Signature(pub(crate) [u8; SIG_LEN]);
+
+impl Signature {
+ /// Create a new signature.
+ pub fn new(signature: [u8; SIG_LEN]) -> Self {
+ Signature(signature)
+ }
+}
/// Signed data type
pub trait SignedData: Clone + Serialize + StdDebug {
@@ -322,15 +457,98 @@ pub struct ParSignedData {
pub share_idx: u64,
}
+impl ParSignedData
+where
+ T: SignedData,
+{
+ /// Create a new partially signed data.
+ pub fn new(partially_signed_data: T, share_idx: u64) -> Self {
+ Self {
+ signed_data: partially_signed_data,
+ share_idx,
+ }
+ }
+}
+
/// ParSignedDataSet is a set of partially signed duty data only signed by a
/// single threshold BLS share.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParSignedDataSet(HashMap>);
+impl ParSignedDataSet
+where
+ T: SignedData,
+{
+ /// Create a new partially signed data set.
+ pub fn new() -> Self {
+ Self(HashMap::default())
+ }
+
+ /// Get a partially signed data by public key.
+ pub fn get(&self, pub_key: &PubKey) -> Option<&ParSignedData> {
+ self.inner().get(pub_key)
+ }
+
+ /// Insert a partially signed data.
+ pub fn insert(&mut self, pub_key: PubKey, partially_signed_data: ParSignedData) {
+ self.inner_mut().insert(pub_key, partially_signed_data);
+ }
+
+ /// Remove a partially signed data by public key.
+ pub fn remove(&mut self, pub_key: &PubKey) -> Option> {
+ self.inner_mut().remove(pub_key)
+ }
+
+ /// Inner partially signed data set.
+ pub fn inner(&self) -> &HashMap> {
+ &self.0
+ }
+
+ /// Inner partially signed data set.
+ pub fn inner_mut(&mut self) -> &mut HashMap> {
+ &mut self.0
+ }
+}
+
/// SignedDataSet is a set of signed duty data.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SignedDataSet(HashMap);
+impl SignedDataSet
+where
+ T: SignedData,
+{
+ /// Create a new signed data set.
+ pub fn new() -> Self {
+ Self(HashMap::default())
+ }
+
+ /// Get a signed data by public key.
+ pub fn get(&self, pub_key: &PubKey) -> Option<&T> {
+ self.0.get(pub_key)
+ }
+
+ /// Insert a signed data.
+ pub fn insert(&mut self, pub_key: PubKey, signed_data: T) {
+ self.0.insert(pub_key, signed_data);
+ }
+
+ /// Remove a signed data by public key.
+ pub fn remove(&mut self, pub_key: &PubKey) -> Option {
+ self.0.remove(pub_key)
+ }
+
+ /// Inner signed data set.
+ pub fn inner(&self) -> &HashMap {
+ &self.0
+ }
+
+ /// Inner signed data set.
+ pub fn inner_mut(&mut self) -> &mut HashMap {
+ &mut self.0
+ }
+}
+
/// Slot struct
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Slot {
@@ -472,7 +690,7 @@ mod tests {
let slot = Slot {
slot: SlotNumber(123),
time: DateTime::from_timestamp(100, 100).unwrap(),
- slot_duration: Duration::from_secs(4),
+ slot_duration: Duration::seconds(4),
slots_per_epoch: 32,
};
@@ -484,7 +702,7 @@ mod tests {
let next = slot.next_slot();
assert_eq!(next.slot, SlotNumber(124));
assert_eq!(next.time, DateTime::from_timestamp(104, 100).unwrap());
- assert_eq!(next.slot_duration, Duration::from_secs(4));
+ assert_eq!(next.slot_duration, Duration::seconds(4));
assert_eq!(next.slots_per_epoch, 32);
}
@@ -507,7 +725,7 @@ mod tests {
let slot = Slot {
slot: SlotNumber(123),
time: DateTime::from_timestamp(100, 100).unwrap(),
- slot_duration: Duration::from_secs(4),
+ slot_duration: Duration::seconds(4),
slots_per_epoch: 32,
};
@@ -554,4 +772,100 @@ mod tests {
assert!(!DutyType::DutySentinel(Box::new(DutyType::Unknown)).is_valid());
assert!(!DutyType::DutySentinel(Box::new(DutyType::Attester)).is_valid());
}
+
+ #[test]
+ fn test_pub_key_from_bytes() {
+ let bytes = [42u8; PK_LEN];
+ let pk = PubKey::from_bytes(&bytes).unwrap();
+ assert_eq!(pk, PubKey::new(bytes));
+ }
+
+ #[test]
+ fn test_pub_key_from_bytes_invalid_length() {
+ let bytes = [42u8; PK_LEN + 1];
+ let result = PubKey::from_bytes(&bytes);
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn test_pub_key_abbreviated() {
+ let pk = PubKey::new([42u8; PK_LEN]);
+ assert_eq!(pk.abbreviated(), "2a2_a2a");
+ }
+
+ #[test]
+ fn test_duty_definition_set() {
+ let mut duty_definition_set = DutyDefinitionSet::new();
+ duty_definition_set.insert(DutyType::Proposer, DutyDefinition::new(DutyType::Proposer));
+ assert_eq!(
+ duty_definition_set.get(&DutyType::Proposer),
+ Some(&DutyDefinition::new(DutyType::Proposer))
+ );
+ }
+
+ #[test]
+ fn test_unsigned_data_set() {
+ let mut unsigned_data_set = UnsignedDataSet::new();
+ unsigned_data_set.insert(DutyType::Proposer, UnsignedData::new(DutyType::Proposer));
+ assert_eq!(
+ unsigned_data_set.get(&DutyType::Proposer),
+ Some(&UnsignedData::new(DutyType::Proposer))
+ );
+ }
+
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+ struct MockSignedData;
+
+ impl SignedData for MockSignedData {
+ type Error = std::io::Error;
+
+ fn signature(&self) -> Signature {
+ Signature::new([42u8; SIG_LEN])
+ }
+
+ fn set_signature(&mut self, _signature: Signature) -> Result<(), std::io::Error> {
+ Ok(())
+ }
+
+ fn message_root(&self) -> [u8; 32] {
+ [42u8; 32]
+ }
+ }
+
+ #[test]
+ fn test_partially_signed_data_set() {
+ let mut partially_signed_data_set = ParSignedDataSet::new();
+ partially_signed_data_set.insert(
+ PubKey::new([42u8; PK_LEN]),
+ ParSignedData::new(MockSignedData, 0),
+ );
+ assert_eq!(
+ partially_signed_data_set.get(&PubKey::new([42u8; PK_LEN])),
+ Some(&ParSignedData::new(MockSignedData, 0))
+ );
+ }
+
+ #[test]
+ fn test_signed_data_set() {
+ let mut signed_data_set = SignedDataSet::new();
+ signed_data_set.insert(PubKey::new([42u8; PK_LEN]), MockSignedData);
+ assert_eq!(
+ signed_data_set.get(&PubKey::new([42u8; PK_LEN])),
+ Some(&MockSignedData)
+ );
+ }
+
+ #[test]
+ fn test_pub_key_from_string() {
+ let pk_str = "0x7f790ba343adf8891fac21a94b02d6ca93d0bc2199a5ec083ff6676e8c2f9f78b08bb122f1093675f9d24c8b5e7af241".to_string();
+ let pk = PubKey::try_from(pk_str).unwrap();
+ assert_eq!(pk, PubKey::new([127, 121, 11, 163, 67, 173, 248, 137, 31, 172, 33, 169, 75, 2, 214, 202, 147, 208, 188, 33, 153, 165, 236, 8, 63, 246, 103, 110, 140, 47, 159, 120, 176, 139, 177, 34, 241, 9, 54, 117, 249, 210, 76, 139, 94, 122, 242, 65]));
+ }
+
+ #[test]
+ fn test_pub_key_from_string_invalid_length() {
+ let pk_str = "0x7f790ba343adf8891fac21a94b02d6ca93d0bc2199a5ec083ff6676e8c2f9f78b08bb121093675f9d24c8b5e7af241".to_string();
+ let result = PubKey::try_from(pk_str);
+ assert!(result.is_err());
+ }
}
From cb28a3a3c7d749112960b8cbde6d3cafb3418dec Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Thu, 9 Oct 2025 18:52:14 +0800
Subject: [PATCH 09/13] chore: remove unused proptest dependency from workspace
---
Cargo.toml | 3 ---
1 file changed, 3 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 3be35481..03f294c0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,9 +24,6 @@ repository = "https://github.com/NethermindEth/charon-rs"
license = "Apache-2.0" # TODO(template) update license
publish = false
-[workspace.dependencies]
-proptest = "1"
-
[workspace.lints.rust]
missing_docs = "deny"
unsafe_code = "forbid"
From df5d4aeefe83cf1a6f3d2895ff159e774a7c670e Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Thu, 9 Oct 2025 19:56:53 +0800
Subject: [PATCH 10/13] feat: implement Default trait for UnsignedDataSet,
ParSignedDataSet, and SignedDataSet
---
crates/charon-core/src/types.rs | 42 +++++++++++++++++++++++++++++----
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index 9280c497..389f071e 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -380,13 +380,22 @@ pub struct UnsignedDataSet(HashMap>)
where
T: Clone + Serialize + StdDebug;
+impl Default for UnsignedDataSet
+where
+ T: Clone + Serialize + StdDebug,
+{
+ fn default() -> Self {
+ Self(HashMap::default())
+ }
+}
+
impl UnsignedDataSet
where
T: Clone + Serialize + StdDebug,
{
/// Create a new unsigned data set.
pub fn new() -> Self {
- Self(HashMap::default())
+ Self::default()
}
/// Get an unsigned data by duty type.
@@ -475,13 +484,22 @@ where
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParSignedDataSet(HashMap>);
+impl Default for ParSignedDataSet
+where
+ T: SignedData,
+{
+ fn default() -> Self {
+ Self(HashMap::default())
+ }
+}
+
impl ParSignedDataSet
where
T: SignedData,
{
/// Create a new partially signed data set.
pub fn new() -> Self {
- Self(HashMap::default())
+ Self::default()
}
/// Get a partially signed data by public key.
@@ -514,13 +532,22 @@ where
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SignedDataSet(HashMap);
+impl Default for SignedDataSet
+where
+ T: SignedData,
+{
+ fn default() -> Self {
+ Self(HashMap::default())
+ }
+}
+
impl SignedDataSet
where
T: SignedData,
{
/// Create a new signed data set.
pub fn new() -> Self {
- Self(HashMap::default())
+ Self::default()
}
/// Get a signed data by public key.
@@ -859,7 +886,14 @@ mod tests {
fn test_pub_key_from_string() {
let pk_str = "0x7f790ba343adf8891fac21a94b02d6ca93d0bc2199a5ec083ff6676e8c2f9f78b08bb122f1093675f9d24c8b5e7af241".to_string();
let pk = PubKey::try_from(pk_str).unwrap();
- assert_eq!(pk, PubKey::new([127, 121, 11, 163, 67, 173, 248, 137, 31, 172, 33, 169, 75, 2, 214, 202, 147, 208, 188, 33, 153, 165, 236, 8, 63, 246, 103, 110, 140, 47, 159, 120, 176, 139, 177, 34, 241, 9, 54, 117, 249, 210, 76, 139, 94, 122, 242, 65]));
+ assert_eq!(
+ pk,
+ PubKey::new([
+ 127, 121, 11, 163, 67, 173, 248, 137, 31, 172, 33, 169, 75, 2, 214, 202, 147, 208,
+ 188, 33, 153, 165, 236, 8, 63, 246, 103, 110, 140, 47, 159, 120, 176, 139, 177, 34,
+ 241, 9, 54, 117, 249, 210, 76, 139, 94, 122, 242, 65
+ ])
+ );
}
#[test]
From 2a2fdf88c943d8a200abf2298dde1cd6c74338c2 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Fri, 10 Oct 2025 18:00:31 +0800
Subject: [PATCH 11/13] refactor: update PubKey methods for improved error
handling and add try_from implementation
---
crates/charon-core/src/types.rs | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index 389f071e..8c89b7a1 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -203,6 +203,7 @@ pub enum ProposalType {
// In golang implementation they use pk_len = 98, which is 0x + [48 bytes]
// We use pk_len = 48, which is [48 bytes], the main difference is that we store
// the pub key as [u8; 48] instead of string.
+// [original implementation](https://github.com/ObolNetwork/charon/blob/b3008103c5429b031b63518195f4c49db4e9a68d/core/types.go#L264)
const PK_LEN: usize = 48;
const SIG_LEN: usize = 96;
@@ -224,7 +225,8 @@ impl TryFrom for PubKey {
fn try_from(value: String) -> Result {
let value = value.strip_prefix("0x").unwrap_or(&value);
- PubKey::from_bytes(&hex::decode(value).map_err(|_| PubKeyError::InvalidString)?)
+ let hex_value = hex::decode(value).map_err(|_| PubKeyError::InvalidString)?;
+ PubKey::try_from(hex_value.as_slice())
}
}
@@ -273,8 +275,17 @@ impl PubKey {
PubKey(pk)
}
- /// Create a new public key from bytes.
- pub fn from_bytes(bytes: &[u8]) -> Result {
+ /// Returns logging-friendly abbreviated form: "b82_97f"
+ pub fn abbreviated(&self) -> String {
+ let hex = hex::encode(self.0);
+ format!("{}_{}", &hex[0..3], &hex[93..96])
+ }
+}
+
+impl TryFrom<&[u8]> for PubKey {
+ type Error = PubKeyError;
+
+ fn try_from(bytes: &[u8]) -> Result {
if bytes.len() != PK_LEN {
return Err(PubKeyError::InvalidLength);
}
@@ -282,12 +293,6 @@ impl PubKey {
arr.copy_from_slice(bytes);
Ok(PubKey(arr))
}
-
- /// Returns logging-friendly abbreviated form: "b82_97f"
- pub fn abbreviated(&self) -> String {
- let hex = hex::encode(self.0);
- format!("{}_{}", &hex[0..3], &hex[93..96])
- }
}
impl Display for PubKey {
@@ -803,14 +808,14 @@ mod tests {
#[test]
fn test_pub_key_from_bytes() {
let bytes = [42u8; PK_LEN];
- let pk = PubKey::from_bytes(&bytes).unwrap();
+ let pk = PubKey::try_from(&bytes[..]).unwrap();
assert_eq!(pk, PubKey::new(bytes));
}
#[test]
fn test_pub_key_from_bytes_invalid_length() {
let bytes = [42u8; PK_LEN + 1];
- let result = PubKey::from_bytes(&bytes);
+ let result = PubKey::try_from(&bytes[..]);
assert!(result.is_err());
}
From 319cfac5e8bbb68a9a9d97da25c11666b76c4f54 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Fri, 10 Oct 2025 18:02:43 +0800
Subject: [PATCH 12/13] docs: clarify slot duration comment and add debug
prints for PubKey serialization/deserialization tests
---
crates/charon-core/src/types.rs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index 8c89b7a1..a5b8b5e1 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -590,7 +590,7 @@ pub struct Slot {
/// The time.
pub time: DateTime,
- /// The slot type.
+ /// The slot duration.
pub slot_duration: Duration,
/// Slots per epoch.
@@ -742,6 +742,7 @@ mod tests {
fn test_serialize_pubkey() {
let pk = PubKey::new([42u8; PK_LEN]);
let serialized = serde_json::to_string(&pk).unwrap();
+ println!("serialized: {}", serialized);
assert_eq!(serialized, format!("\"0x{}\"", hex::encode([42u8; PK_LEN])));
}
@@ -749,6 +750,7 @@ mod tests {
fn test_deserialize_pubkey() {
let serialized = format!("\"0x{}\"", hex::encode([42u8; PK_LEN]));
let deserialized: PubKey = serde_json::from_str(&serialized).unwrap();
+ println!("deserialized: {}", deserialized);
assert_eq!(deserialized, PubKey::new([42u8; PK_LEN]));
}
From 5e7ff968dc91456ff01cbf2baaa8db0b761587a0 Mon Sep 17 00:00:00 2001
From: Bohdan Ohorodnii <35969035+varex83@users.noreply.github.com>
Date: Sun, 19 Oct 2025 12:49:41 +0800
Subject: [PATCH 13/13] fix: remove unnecessary println
---
crates/charon-core/src/types.rs | 2 --
1 file changed, 2 deletions(-)
diff --git a/crates/charon-core/src/types.rs b/crates/charon-core/src/types.rs
index a5b8b5e1..9328ded2 100644
--- a/crates/charon-core/src/types.rs
+++ b/crates/charon-core/src/types.rs
@@ -742,7 +742,6 @@ mod tests {
fn test_serialize_pubkey() {
let pk = PubKey::new([42u8; PK_LEN]);
let serialized = serde_json::to_string(&pk).unwrap();
- println!("serialized: {}", serialized);
assert_eq!(serialized, format!("\"0x{}\"", hex::encode([42u8; PK_LEN])));
}
@@ -750,7 +749,6 @@ mod tests {
fn test_deserialize_pubkey() {
let serialized = format!("\"0x{}\"", hex::encode([42u8; PK_LEN]));
let deserialized: PubKey = serde_json::from_str(&serialized).unwrap();
- println!("deserialized: {}", deserialized);
assert_eq!(deserialized, PubKey::new([42u8; PK_LEN]));
}