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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions lean_client/Cargo.lock

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

8 changes: 5 additions & 3 deletions lean_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["chain", "containers", "fork_choice", "networking", "validator"]
members = ["chain", "containers", "env-config", "fork_choice", "networking", "validator"]
resolver = "2"

[workspace.package]
Expand All @@ -14,7 +14,7 @@ containers = { path = "./containers" }
fork_choice = { path = "./fork_choice" }
networking = { path = "./networking" }
validator = { path = "./validator" }
libp2p = {version = "0.56.0", default-features = false, features = [
libp2p = { version = "0.56.0", default-features = false, features = [
'dns',
'gossipsub',
'identify',
Expand Down Expand Up @@ -52,8 +52,10 @@ version = "0.1.0"
edition = "2021"

[features]
default = ["xmss-signing"]
default = ["devnet2", "xmss-signing"]
xmss-signing = ["validator/xmss-signing"]
devnet1 = ["containers/devnet1", "fork-choice/devnet1", "networking/devnet1", "validator/devnet1"]
devnet2 = ["containers/devnet2", "fork-choice/devnet2", "networking/devnet2", "validator/devnet2"]

[dependencies]
chain = { path = "./chain" }
Expand Down
26 changes: 26 additions & 0 deletions lean_client/ENVIRONMENT_SELECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
### To select which devnet you want to compile

#### Option A
- Change the default features in root `Cargo.toml`:
```toml
[features]
default = ["devnet1", "<...other features>"] # Change to "devnet2" if needed
devnet1 = [...]
devnet2 = [...]
```

#### Option B
- Use the `--no-default-features` flag and specify the desired devnet feature when building or running the project:
```bash
cargo build --no-default-features --features devnet1 # Change to devnet2
```


### Running tests for a specific devnet

From root directory, use the following command:
```bash
cargo test -p <crate_name> --no-default-features --features devnet1 # Change to devnet2
```

Use `<crate_name>` to specify the crate you want to test.
4 changes: 4 additions & 0 deletions lean_client/containers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ edition = "2021"

[features]
xmss-verify = ["leansig"]
default = []
devnet1 = ["env-config/devnet1"]
devnet2 = ["env-config/devnet2"]

[lib]
name = "containers"
path = "src/lib.rs"

[dependencies]
env-config = { path = "../env-config", default-features = false }
ssz = { git = "https://github.com/grandinetech/grandine", package = "ssz", branch = "develop", submodules = true }
ssz_derive = { git = "https://github.com/grandinetech/grandine", package = "ssz_derive", branch = "develop", submodules = false }
typenum = "1"
Expand Down
127 changes: 116 additions & 11 deletions lean_client/containers/src/attestation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{Checkpoint, Slot, Uint64};
use serde::{Deserialize, Serialize};
use ssz::BitList;
use ssz::ByteVector;
use ssz_derive::Ssz;
use typenum::{Prod, Sum, U100, U31, U12};
use typenum::{Prod, Sum, U100, U12, U31};

pub type U3100 = Prod<U31, U100>;

Expand All @@ -19,13 +20,66 @@ use typenum::U4096;
/// Limit is VALIDATOR_REGISTRY_LIMIT (4096).
pub type Attestations = ssz::PersistentList<Attestation, U4096>;

/// List of signatures corresponding to attestations in a block.
/// Limit is VALIDATOR_REGISTRY_LIMIT (4096).
pub type BlockSignatures = ssz::PersistentList<Signature, U4096>;
pub type AggregatedAttestations = ssz::PersistentList<AggregatedAttestation, U4096>;

#[cfg(feature = "devnet1")]
pub type AttestationSignatures = ssz::PersistentList<SignedAttestation, U4096>;

#[cfg(feature = "devnet2")]
pub type AttestationSignatures = ssz::PersistentList<NaiveAggregatedSignature, U4096>;

#[cfg(feature = "devnet2")]
pub type NaiveAggregatedSignature = ssz::PersistentList<Signature, U4096>;

/// Bitlist representing validator participation in an attestation.
/// Limit is VALIDATOR_REGISTRY_LIMIT (4096).
pub type AggregationBits = ssz::BitList<U4096>;
#[derive(Clone, Debug, PartialEq, Eq, Default, Ssz, Serialize, Deserialize)]
pub struct AggregationBits(pub BitList<U4096>);

impl AggregationBits {
pub const LIMIT: u64 = 4096;

pub fn from_validator_indices(indices: &[u64]) -> Self {
assert!(
!indices.is_empty(),
"Aggregated attestation must reference at least one validator"
);

let max_id = *indices.iter().max().unwrap();
assert!(
max_id < Self::LIMIT,
"Validator index out of range for aggregation bits"
);

let mut bits = BitList::<U4096>::with_length((max_id + 1) as usize);

for i in 0..=max_id {
bits.set(i as usize, false);
}

for &i in indices {
bits.set(i as usize, true);
}

AggregationBits(bits)
}

pub fn to_validator_indices(&self) -> Vec<u64> {
let indices: Vec<u64> = self
.0
.iter()
.enumerate()
.filter_map(|(i, bit)| if *bit { Some(i as u64) } else { None })
.collect();

assert!(
!indices.is_empty(),
"Aggregated attestation must reference at least one validator"
);

indices
}
}

/// Naive list of validator signatures used for aggregation placeholders.
/// Limit is VALIDATOR_REGISTRY_LIMIT (4096).
Expand Down Expand Up @@ -57,29 +111,80 @@ pub struct Attestation {
/// Validator attestation bundled with its signature.
#[derive(Clone, Debug, PartialEq, Eq, Ssz, Default, Serialize, Deserialize)]
pub struct SignedAttestation {
/// The attestation message signed by the validator.
#[cfg(feature = "devnet2")]
pub validator_id: u64,
#[cfg(feature = "devnet2")]
pub message: AttestationData,
#[cfg(feature = "devnet1")]
pub message: Attestation,
/// Signature aggregation produced by the leanVM (SNARKs in the future).
pub signature: Signature,
}

/// Aggregated attestation consisting of participation bits and message.
#[derive(Clone, Debug, PartialEq, Eq, Ssz, Default, Serialize, Deserialize)]
pub struct AggregatedAttestations {
pub struct AggregatedAttestation {
/// Bitfield indicating which validators participated in the aggregation.
pub aggregation_bits: AggregationBits,
/// Combined attestation data similar to the beacon chain format.
///
///
/// Multiple validator attestations are aggregated here without the complexity of
/// committee assignments.
pub data: AttestationData,
}

impl AggregatedAttestation {
pub fn aggregate_by_data(attestations: &[Attestation]) -> Vec<AggregatedAttestation> {
let mut groups: Vec<(AttestationData, Vec<u64>)> = Vec::new();

for attestation in attestations {
// Try to find an existing group with the same data
if let Some((_, validator_ids)) = groups
.iter_mut()
.find(|(data, _)| *data == attestation.data)
{
validator_ids.push(attestation.validator_id.0);
} else {
// Create a new group
groups.push((attestation.data.clone(), vec![attestation.validator_id.0]));
}
}

groups
.into_iter()
.map(|(data, validator_ids)| AggregatedAttestation {
aggregation_bits: AggregationBits::from_validator_indices(&validator_ids),
data,
})
.collect()
}
}

/// Trait for checking duplicate attestation data.
pub trait HasDuplicateData {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why trait? You can just add new function to impl block above?

/// Returns true if the list contains duplicate AttestationData.
fn has_duplicate_data(&self) -> bool;
}

impl HasDuplicateData for AggregatedAttestations {
fn has_duplicate_data(&self) -> bool {
use ssz::SszHash;
use std::collections::HashSet;
let mut seen: HashSet<ssz::H256> = HashSet::new();
for attestation in self {
let root = attestation.data.hash_tree_root();
if !seen.insert(root) {
return true;
}
}
false
}
}

/// Aggregated attestation bundled with aggregated signatures.
#[derive(Clone, Debug, PartialEq, Eq, Ssz, Default, Serialize, Deserialize)]
pub struct SignedAggregatedAttestations {
pub struct SignedAggregatedAttestation {
/// Aggregated attestation data.
pub message: AggregatedAttestations,
pub message: AggregatedAttestation,
/// Aggregated attestation plus its combined signature.
///
/// Stores a naive list of validator signatures that mirrors the attestation
Expand Down
Loading