Skip to content
Merged
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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: CI
on:
- pull_request

jobs:
ci:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Check formatting
run: make check-format

- name: Build client
run: make build

- name: Run tests
run: make test
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.PHONY: build format check-format test

all:
$(MAKE) -C lean_client all

build:
$(MAKE) -C lean_client build

format:
$(MAKE) -C lean_client format

check-format:
$(MAKE) -C lean_client check-format

test:
$(MAKE) -C lean_client test
15 changes: 15 additions & 0 deletions lean_client/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.PHONY: build format check-format test

all: build check-format test

build:
cargo build --release

format:
cargo fmt

check-format:
cargo fmt --check

test:
cargo test --workspace --all-features --no-fail-fast
38 changes: 29 additions & 9 deletions lean_client/chain/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ pub struct BasisPoint(pub u64);
impl BasisPoint {
pub const MAX: u64 = 10_000;
pub const fn new(value: u64) -> Option<Self> {
if value <= Self::MAX { Some(BasisPoint(value)) } else { None }
if value <= Self::MAX {
Some(BasisPoint(value))
} else {
None
}
}
#[inline]
pub fn get(&self) -> u64 {
self.0
}
#[inline] pub fn get(&self) -> u64 { self.0 }
}

pub const INTERVALS_PER_SLOT: u64 = 4;
Expand All @@ -15,12 +22,24 @@ pub const SECONDS_PER_SLOT: u64 = SLOT_DURATION_MS / 1_000;
pub const SECONDS_PER_INTERVAL: u64 = SECONDS_PER_SLOT / INTERVALS_PER_SLOT;
pub const JUSTIFICATION_LOOKBACK_SLOTS: u64 = 3;

pub const PROPOSER_REORG_CUTOFF_BPS: BasisPoint = match BasisPoint::new(2_500) { Some(x) => x, None => panic!() };
pub const VOTE_DUE_BPS: BasisPoint = match BasisPoint::new(5_000) { Some(x) => x, None => panic!() };
pub const FAST_CONFIRM_DUE_BPS: BasisPoint = match BasisPoint::new(7_500) { Some(x) => x, None => panic!() };
pub const VIEW_FREEZE_CUTOFF_BPS: BasisPoint= match BasisPoint::new(7_500) { Some(x) => x, None => panic!() };
pub const PROPOSER_REORG_CUTOFF_BPS: BasisPoint = match BasisPoint::new(2_500) {
Some(x) => x,
None => panic!(),
};
pub const VOTE_DUE_BPS: BasisPoint = match BasisPoint::new(5_000) {
Some(x) => x,
None => panic!(),
};
pub const FAST_CONFIRM_DUE_BPS: BasisPoint = match BasisPoint::new(7_500) {
Some(x) => x,
None => panic!(),
};
pub const VIEW_FREEZE_CUTOFF_BPS: BasisPoint = match BasisPoint::new(7_500) {
Some(x) => x,
None => panic!(),
};

pub const HISTORICAL_ROOTS_LIMIT: u64 = 1u64 << 18;
pub const HISTORICAL_ROOTS_LIMIT: u64 = 1u64 << 18;
pub const VALIDATOR_REGISTRY_LIMIT: u64 = 1u64 << 12;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -51,9 +70,10 @@ pub const DEVNET_CONFIG: ChainConfig = ChainConfig {
#[cfg(test)]
mod tests {
use super::*;
#[test] fn time_math_is_consistent() {
#[test]
fn time_math_is_consistent() {
assert_eq!(SLOT_DURATION_MS, 4_000);
assert_eq!(SECONDS_PER_SLOT, 4);
assert_eq!(SECONDS_PER_INTERVAL, 1);
}
}
}
4 changes: 2 additions & 2 deletions lean_client/containers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ name = "containers"
path = "src/lib.rs"

[dependencies]
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 }
ssz = { git = "https://github.com/grandinetech/grandine", package = "ssz", branch = "develop" }
ssz_derive = { git = "https://github.com/grandinetech/grandine", package = "ssz_derive", branch = "develop" }
typenum = "1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion lean_client/containers/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{Checkpoint, Slot, Uint64};
use serde::{Deserialize, Serialize};
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 Down
43 changes: 27 additions & 16 deletions lean_client/containers/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{Attestation, Attestations, BlockSignatures, Bytes32, Signature, Slot, State, ValidatorIndex};
use crate::{
Attestation, Attestations, BlockSignatures, Bytes32, Signature, Slot, State, ValidatorIndex,
};
use serde::{Deserialize, Serialize};
use ssz_derive::Ssz;

Expand Down Expand Up @@ -123,7 +125,7 @@ impl SignedBlockWithAttestation {
// 1. Block body attestations (from other validators)
// 2. Proposer attestation (from the block producer)
let mut all_attestations: Vec<Attestation> = Vec::new();

// Collect block body attestations
let mut i: u64 = 0;
loop {
Expand All @@ -133,7 +135,7 @@ impl SignedBlockWithAttestation {
}
i += 1;
}

// Append proposer attestation
all_attestations.push(self.message.proposer_attestation.clone());

Expand Down Expand Up @@ -193,49 +195,58 @@ impl SignedBlockWithAttestation {
// - The validator possesses the secret key for their public key
// - The attestation has not been tampered with
// - The signature was created at the correct epoch (slot)

#[cfg(feature = "xmss-verify")]
{
use leansig::signature::SignatureScheme;
use leansig::serialization::Serializable;

use leansig::signature::SignatureScheme;

// Compute the message hash from the attestation
let message_bytes: [u8; 32] = hash_tree_root(attestation).0.into();
let epoch = attestation.data.slot.0 as u32;

// Get public key bytes - use as_bytes() method
let pubkey_bytes = validator.pubkey.0.as_bytes();

// Deserialize the public key using Serializable trait
type PubKey = <SIGTargetSumLifetime20W2NoOff as SignatureScheme>::PublicKey;
let pubkey = match PubKey::from_bytes(pubkey_bytes) {
Ok(pk) => pk,
Err(e) => {
eprintln!("Failed to deserialize public key at slot {:?}: {:?}", attestation.data.slot, e);
eprintln!(
"Failed to deserialize public key at slot {:?}: {:?}",
attestation.data.slot, e
);
return false;
}
};

// Get signature bytes - use as_bytes() method
let sig_bytes = signature.as_bytes();

// Deserialize the signature using Serializable trait
type Sig = <SIGTargetSumLifetime20W2NoOff as SignatureScheme>::Signature;
let sig = match Sig::from_bytes(sig_bytes) {
Ok(s) => s,
Err(e) => {
eprintln!("Failed to deserialize signature at slot {:?}: {:?}", attestation.data.slot, e);
eprintln!(
"Failed to deserialize signature at slot {:?}: {:?}",
attestation.data.slot, e
);
return false;
}
};

// Verify the signature
if !SIGTargetSumLifetime20W2NoOff::verify(&pubkey, epoch, &message_bytes, &sig) {
eprintln!("XMSS signature verification failed at slot {:?}", attestation.data.slot);
eprintln!(
"XMSS signature verification failed at slot {:?}",
attestation.data.slot
);
return false;
}
}

#[cfg(not(feature = "xmss-verify"))]
{
// Placeholder: XMSS verification disabled
Expand All @@ -249,4 +260,4 @@ impl SignedBlockWithAttestation {

true
}
}
}
6 changes: 3 additions & 3 deletions lean_client/containers/src/checkpoint.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{Bytes32, Slot};
use ssz_derive::Ssz;
use serde::{Deserialize, Serialize};
use ssz_derive::Ssz;

/// Represents a checkpoint in the chain's history.
///
///
/// A checkpoint marks a specific moment in the chain. It combines a block
/// identifier with a slot number. Checkpoints are used for justification and
/// finalization.
Expand Down Expand Up @@ -45,4 +45,4 @@ mod tests {
};
assert_eq!(cp1, cp2);
}
}
}
4 changes: 2 additions & 2 deletions lean_client/containers/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ssz_derive::Ssz;
use serde::{Deserialize, Serialize};
use ssz_derive::Ssz;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
Expand All @@ -26,4 +26,4 @@ impl GenesisConfig {
let config = serde_yaml::from_reader(reader)?;
Ok(config)
}
}
}
4 changes: 2 additions & 2 deletions lean_client/containers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub use slot::Slot;
pub use state::State;
pub use status::Status;
pub use types::{
Bytes32, HistoricalBlockHashes, JustificationRoots, JustificationsValidators, JustifiedSlots, Validators,
Uint64, ValidatorIndex,
Bytes32, HistoricalBlockHashes, JustificationRoots, JustificationsValidators, JustifiedSlots,
Uint64, ValidatorIndex, Validators,
};

pub use types::Bytes32 as Root;
Expand Down
Loading
Loading