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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ jobs:
run: cargo fmt --all --check
- name: Run clippy
run: cargo clippy --all-features --tests -- -D warnings
- name: Run clippy (no default features)
run: cargo clippy --no-default-features --tests -- -D warnings

unused_dependencies:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -63,3 +65,5 @@ jobs:
tool: protoc@${{ env.PROTOC_VERSION }}
- name: Run tests
run: cargo test --all-features --tests
- name: Run tests (no default features)
run: cargo test --no-default-features --tests
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ unchanged; re-check timeout scheduling if you relied on the earlier resolution p
could never reject a proposal whose proposer voted YES. In P2P mode a session still
undecided at the default round cap (`ceil(2n/3)` votes) now resolves only at the
timeout.
- `cargo test --no-default-features --tests` did not compile since 0.5.0: the unit tests
in `session.rs` and most integration tests imported `alloy` unconditionally. Those
tests are now gated behind the `ethereum` feature, and CI runs clippy and the test
suite with `--no-default-features` as well.

## 0.5.0

Expand Down
2 changes: 1 addition & 1 deletion src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ impl ConsensusSession {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "ethereum"))]
mod tests {
use std::time::Duration;

Expand Down
103 changes: 56 additions & 47 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,6 @@
//! subset of the helpers, so unused-code warnings are suppressed.
#![allow(dead_code)]

use alloy::signers::local::PrivateKeySigner;
use hashgraph_like_consensus::{
error::ConsensusError,
protos::consensus::v1::{Proposal, Vote},
scope::ScopeID,
service::DefaultConsensusService,
signing::EthereumConsensusSigner,
storage::ConsensusStorage,
utils::build_vote,
};

/// Current time in seconds since Unix epoch — the caller-supplied `now`
/// the library expects.
pub fn now_ts() -> u64 {
Expand All @@ -24,44 +13,64 @@ pub fn now_ts() -> u64 {
.as_secs()
}

/// A service with in-memory storage and a fresh random signer.
pub fn make_service() -> DefaultConsensusService {
DefaultConsensusService::new(EthereumConsensusSigner::new(PrivateKeySigner::random()))
}
#[cfg(feature = "ethereum")]
#[allow(unused_imports)]
pub use ethereum::*;

/// Wrap a raw key into the Ethereum signature scheme.
pub fn wrap(signer: PrivateKeySigner) -> EthereumConsensusSigner {
EthereumConsensusSigner::new(signer)
}
/// Helpers that need the alloy-backed signer; only built with the `ethereum` feature.
#[cfg(feature = "ethereum")]
mod ethereum {
use super::now_ts;
use alloy::signers::local::PrivateKeySigner;
use hashgraph_like_consensus::{
error::ConsensusError,
protos::consensus::v1::{Proposal, Vote},
scope::ScopeID,
service::DefaultConsensusService,
signing::EthereumConsensusSigner,
storage::ConsensusStorage,
utils::build_vote,
};

/// The signer's address bytes, as used for proposal/vote owner fields.
pub fn owner_bytes(signer: &PrivateKeySigner) -> Vec<u8> {
signer.address().as_slice().to_vec()
}
/// A service with in-memory storage and a fresh random signer.
pub fn make_service() -> DefaultConsensusService {
DefaultConsensusService::new(EthereumConsensusSigner::new(PrivateKeySigner::random()))
}

/// Build and process a vote as if it arrived from a remote peer, returning
/// the vote for further gossip.
pub fn cast_remote_vote(
service: &DefaultConsensusService,
scope: &ScopeID,
proposal_id: u32,
choice: bool,
signer: &EthereumConsensusSigner,
) -> Result<Vote, ConsensusError> {
let proposal = service.storage().get_proposal(scope, proposal_id)?;
let vote = build_vote(&proposal, choice, signer, now_ts())?;
service.process_incoming_vote(scope, vote.clone(), now_ts())?;
Ok(vote)
}
/// Wrap a raw key into the Ethereum signature scheme.
pub fn wrap(signer: PrivateKeySigner) -> EthereumConsensusSigner {
EthereumConsensusSigner::new(signer)
}

/// The signer's address bytes, as used for proposal/vote owner fields.
pub fn owner_bytes(signer: &PrivateKeySigner) -> Vec<u8> {
signer.address().as_slice().to_vec()
}

/// Build and process a vote as if it arrived from a remote peer, returning
/// the vote for further gossip.
pub fn cast_remote_vote(
service: &DefaultConsensusService,
scope: &ScopeID,
proposal_id: u32,
choice: bool,
signer: &EthereumConsensusSigner,
) -> Result<Vote, ConsensusError> {
let proposal = service.storage().get_proposal(scope, proposal_id)?;
let vote = build_vote(&proposal, choice, signer, now_ts())?;
service.process_incoming_vote(scope, vote.clone(), now_ts())?;
Ok(vote)
}

/// [`cast_remote_vote`], then return the updated proposal snapshot.
pub fn cast_remote_vote_and_get_proposal(
service: &DefaultConsensusService,
scope: &ScopeID,
proposal_id: u32,
choice: bool,
signer: &EthereumConsensusSigner,
) -> Result<Proposal, ConsensusError> {
cast_remote_vote(service, scope, proposal_id, choice, signer)?;
service.storage().get_proposal(scope, proposal_id)
/// [`cast_remote_vote`], then return the updated proposal snapshot.
pub fn cast_remote_vote_and_get_proposal(
service: &DefaultConsensusService,
scope: &ScopeID,
proposal_id: u32,
choice: bool,
signer: &EthereumConsensusSigner,
) -> Result<Proposal, ConsensusError> {
cast_remote_vote(service, scope, proposal_id, choice, signer)?;
service.storage().get_proposal(scope, proposal_id)
}
}
1 change: 1 addition & 0 deletions tests/concurrency_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{now_ts, wrap};

Expand Down
1 change: 1 addition & 0 deletions tests/consensus_service_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{cast_remote_vote, cast_remote_vote_and_get_proposal, make_service, now_ts, wrap};

Expand Down
1 change: 1 addition & 0 deletions tests/network_gossip_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{cast_remote_vote, make_service, now_ts, owner_bytes, wrap};

Expand Down
1 change: 1 addition & 0 deletions tests/rfc_compliance_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{
cast_remote_vote, cast_remote_vote_and_get_proposal, make_service, now_ts, owner_bytes, wrap,
Expand Down
1 change: 1 addition & 0 deletions tests/scope_config_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{make_service, now_ts};

Expand Down
1 change: 1 addition & 0 deletions tests/storage_stream_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::now_ts;

Expand Down
1 change: 1 addition & 0 deletions tests/vote_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{now_ts, wrap};

Expand Down
1 change: 1 addition & 0 deletions tests/vote_validation_tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg(feature = "ethereum")]
mod common;
use common::{cast_remote_vote_and_get_proposal, make_service, now_ts, owner_bytes, wrap};

Expand Down
Loading