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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ path = "tests/consensus/view_change_partition_test.rs"
name = "byzantine_equivocation_recovery_test"
path = "tests/consensus/byzantine_equivocation_recovery_test.rs"

[[test]]
name = "pg_pool_health_probe_test"
path = "tests/pg_pool_health_probe_test.rs"

# ── Lint policy ──────────────────────────────────────────────────────────────
# Enforced via `cargo clippy -- -D warnings` in CI. The lints below are the
# style/pedantic ones we deliberately do not churn on:
Expand Down
14 changes: 8 additions & 6 deletions src/attestation/bls_aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,12 @@ impl BLSBatchVerificationCache {

self.next_seq = self.next_seq.wrapping_add(1);
let new_seq = self.next_seq;
let entry =
BLSCacheEntry::new(key.message_root_256, key.aggregator_index, is_valid, new_seq);
let entry = BLSCacheEntry::new(
key.message_root_256,
key.aggregator_index,
is_valid,
new_seq,
);
self.entries.insert(key, (entry, new_seq));
self.lru_order.insert((new_seq, key), ());
}
Expand Down Expand Up @@ -321,10 +325,8 @@ pub fn truncated_prefix_32(root: &[u8; 32]) -> u32 {
/// Provided for vulnerability regression and collision analysis.
pub fn xor_fold_32(root: &[u8; 32]) -> u32 {
let mut folded = 0u32;
for chunk in root.chunks_exact(4) {
let mut bytes = [0u8; 4];
bytes.copy_from_slice(chunk);
folded ^= u32::from_le_bytes(bytes);
for chunk in root.as_chunks::<4>().0 {
folded ^= u32::from_le_bytes(*chunk);
}
folded
}
Expand Down
7 changes: 4 additions & 3 deletions src/consensus/engine/consensus_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use alloc::vec::Vec;
use crate::consensus::leader_election::timeout_leader::TimeoutLeader;
use crate::consensus::proposal::equivocation_detector::{EquivocationDetector, EquivocationProof};
use crate::consensus::recovery::fallback_sync::{
FallbackSyncEngine, FallbackSyncError, LockedValue, DEADLOCK_VIEW_THRESHOLD,
FallbackSyncEngine, FallbackSyncError, LockedValue,
};
use crate::consensus::view_change::types::{BlockHash, PublicKey};

Expand All @@ -59,7 +59,7 @@ pub enum ConsensusEngineEvent {
/// A Byzantine equivocation was detected; view was immediately advanced.
EquivocationDetected {
/// The equivocation proof.
proof: EquivocationProof,
proof: Box<EquivocationProof>,
/// View advanced to.
new_view: u64,
},
Expand Down Expand Up @@ -176,7 +176,7 @@ impl ConsensusEngine {
let new_view = self.timeout_leader.current_view();
self.events
.push(ConsensusEngineEvent::EquivocationDetected {
proof: proof.clone(),
proof: Box::new(proof.clone()),
new_view,
});
} else {
Expand Down Expand Up @@ -278,6 +278,7 @@ impl ConsensusEngine {
mod tests {
use super::*;
use crate::consensus::proposal::equivocation_detector::Proposal;
use crate::consensus::recovery::fallback_sync::DEADLOCK_VIEW_THRESHOLD;
use crate::consensus::view_change::types::AggregateSignature;

fn pk(id: u8) -> PublicKey {
Expand Down
5 changes: 3 additions & 2 deletions src/consensus/leader_election/timeout_leader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ impl TimeoutLeader {
///
/// `timeout(v) = min(BASE_TIMEOUT_MS * 2^v, MAX_TIMEOUT_MS)`
pub fn timeout_for_view(view: u64) -> u64 {
// Use saturating_mul + saturating_shl to avoid overflow on large views.
// Use saturating_mul + checked_shl to avoid overflow on large views.
let shift = view.min(63); // 2^63 already overflows u64, cap the shift
let raw = BASE_TIMEOUT_MS.saturating_mul(1u64.saturating_shl(shift as u32));
let pow2 = 1u64.checked_shl(shift as u32).unwrap_or(u64::MAX);
let raw = BASE_TIMEOUT_MS.saturating_mul(pow2);
raw.min(MAX_TIMEOUT_MS)
}

Expand Down
2 changes: 1 addition & 1 deletion src/consensus/view_change/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ pub use quarantine::{QuarantineBuffer, QuarantinedQc};
pub use resolver::{create_conflict_event, QcProcessOutcome, ViewChangeResolver};
pub use types::{
compute_public_key_set_hash, AggregateSignature, BlockHash, PublicKey, QcConflictDetected,
QuorumCertificate, ViewChangeEvent, ViewChangeError, CONVERGENCE_ROUND_LIMIT, QC,
QuorumCertificate, ViewChangeError, ViewChangeEvent, CONVERGENCE_ROUND_LIMIT, QC,
QUARANTINE_ROUND_LIMIT,
};
10 changes: 2 additions & 8 deletions src/consensus/view_change/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use core::cmp::Ordering;

use crate::consensus::view_change::quarantine::QuarantineBuffer;
use crate::consensus::view_change::types::{
AggregateSignature, BlockHash, PublicKey, QcConflictDetected, ViewChangeEvent, ViewChangeError,
AggregateSignature, BlockHash, PublicKey, QcConflictDetected, ViewChangeError, ViewChangeEvent,
QC,
};

Expand Down Expand Up @@ -88,13 +88,7 @@ impl ViewChangeResolver {
.checked_add(1)
.ok_or(ViewChangeError::EpochOverflow)?;

let qc = QC::new(
view,
self.current_qc_epoch,
block_hash,
signers,
signature,
);
let qc = QC::new(view, self.current_qc_epoch, block_hash, signers, signature);

Ok(qc)
}
Expand Down
1 change: 0 additions & 1 deletion src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ pub mod committee_cache;
pub mod migrations;
#[path = "slashing-store.rs"]
pub mod slashing_store;

50 changes: 36 additions & 14 deletions src/db/slashing-store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

extern crate alloc;

use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use crate::slashing::accumulator::SlashingAccumulator;
use crate::slashing::types::{
EpochIndex, GenerationalTag, SlashingRecord, ValidatorIndex, WindowOffset,
DEFAULT_SLASHING_WINDOW,
};
use alloc::collections::BTreeMap;
use alloc::vec::Vec;

/// Binary serialization format identifier.
pub const SLASHING_STORE_MAGIC: [u8; 8] = *b"VNSLASH1";
Expand Down Expand Up @@ -41,7 +41,6 @@ pub struct SlashingStoreSnapshot {
/// Store for persisting and querying generational slashing accumulator data.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SlashingStore {

records: BTreeMap<(ValidatorIndex, EpochIndex), SlashingRecord>,
generational_tags: BTreeMap<ValidatorIndex, GenerationalTag>,
bit_states: BTreeMap<ValidatorIndex, bool>,
Expand All @@ -58,7 +57,11 @@ impl SlashingStore {

/// Create a new empty SlashingStore with specified window size.
pub fn with_window_size(window_size: u16) -> Self {
let size = if window_size == 0 { DEFAULT_SLASHING_WINDOW as u16 } else { window_size };
let size = if window_size == 0 {
DEFAULT_SLASHING_WINDOW as u16
} else {
window_size
};
Self {
records: BTreeMap::new(),
generational_tags: BTreeMap::new(),
Expand Down Expand Up @@ -122,7 +125,11 @@ impl SlashingStore {
}

/// Retrieve a slashing record by validator index and epoch.
pub fn get_record(&self, validator_index: ValidatorIndex, epoch: EpochIndex) -> Option<&SlashingRecord> {
pub fn get_record(
&self,
validator_index: ValidatorIndex,
epoch: EpochIndex,
) -> Option<&SlashingRecord> {
self.records.get(&(validator_index, epoch))
}

Expand All @@ -133,7 +140,10 @@ impl SlashingStore {

/// Check if a validator has bit state marked.
pub fn is_slashed_bit(&self, validator_index: ValidatorIndex) -> bool {
self.bit_states.get(&validator_index).copied().unwrap_or(false)
self.bit_states
.get(&validator_index)
.copied()
.unwrap_or(false)
}

/// Current epoch recorded in store.
Expand Down Expand Up @@ -215,7 +225,7 @@ impl SlashingStore {
return Err(SlashingStoreError::PayloadTruncated);
}

if &bytes[0..8] != &SLASHING_STORE_MAGIC {
if bytes[0..8] != SLASHING_STORE_MAGIC {
return Err(SlashingStoreError::InvalidMagic);
}

Expand All @@ -225,12 +235,12 @@ impl SlashingStore {
}

let current_epoch = u64::from_be_bytes([
bytes[12], bytes[13], bytes[14], bytes[15],
bytes[16], bytes[17], bytes[18], bytes[19],
bytes[12], bytes[13], bytes[14], bytes[15], bytes[16], bytes[17], bytes[18], bytes[19],
]);
let window_generation = u16::from_be_bytes([bytes[20], bytes[21]]);
let window_size = u16::from_be_bytes([bytes[22], bytes[23]]);
let record_count = u32::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]) as usize;
let record_count =
u32::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]) as usize;

let record_stride = 20; // 8 + 8 + 2 + 2
let expected_len = 28 + record_count * record_stride;
Expand All @@ -245,12 +255,24 @@ impl SlashingStore {
let mut offset = 28;
for _ in 0..record_count {
let val_idx = u64::from_be_bytes([
bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3],
bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], bytes[offset + 7],
bytes[offset],
bytes[offset + 1],
bytes[offset + 2],
bytes[offset + 3],
bytes[offset + 4],
bytes[offset + 5],
bytes[offset + 6],
bytes[offset + 7],
]);
let epoch = u64::from_be_bytes([
bytes[offset + 8], bytes[offset + 9], bytes[offset + 10], bytes[offset + 11],
bytes[offset + 12], bytes[offset + 13], bytes[offset + 14], bytes[offset + 15],
bytes[offset + 8],
bytes[offset + 9],
bytes[offset + 10],
bytes[offset + 11],
bytes[offset + 12],
bytes[offset + 13],
bytes[offset + 14],
bytes[offset + 15],
]);
let gen = u16::from_be_bytes([bytes[offset + 16], bytes[offset + 17]]);
let win_offset = u16::from_be_bytes([bytes[offset + 18], bytes[offset + 19]]);
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ pub mod cross_chain;
// conservative estimate when the two models diverge by more than 10% for 3
// consecutive sync cycles.
pub mod pool;

// Memory management primitives for the shard connection-pool (issue #141).
// Buddy-system allocator that tracks contiguous free regions and coalesces
// adjacent free blocks to eliminate pathological external fragmentation under
// high-frequency tenant churn. Dependency-free and pure Rust.
pub mod mem;

// PostgreSQL connection-pool health probe with adaptive sizing (issue #134).
// Deterministic, dependency-free primitives for probing connection-pool
// health, evaluating pool utilisation, and producing adaptive sizing
// decisions. Implements blue-green / canary deployment gates, P99 latency
// monitoring, consecutive-unhealthy-probe degradation detection, and
// system-wide dashboard snapshots. All math is pure Rust so on-chain
// contracts, off-chain monitoring agents, and deployment gates share the
// same thresholds.
pub mod pg_pool;
// --- ERROR CODES ---

#[contracterror]
Expand Down
Loading
Loading