Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
584f4a0
feat: add empty block vrf validator module
golddydev Oct 21, 2025
70b3eb4
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 21, 2025
ec6e5bf
refactor: change module name
golddydev Oct 21, 2025
c130403
fix: move assert_header
golddydev Oct 22, 2025
28f7f5d
fix: merge conflicts
golddydev Oct 22, 2025
6231c47
wip: add tpraos vrf proof validadtion step
golddydev Oct 23, 2025
6119aca
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 23, 2025
5fa68e9
refactor: move ouroboros to common
golddydev Oct 23, 2025
9d7b9fe
refactor: vrf validation errors
golddydev Oct 23, 2025
570414d
refactor: restructure ouroboros tpraos validation logic
golddydev Oct 23, 2025
cb25214
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 24, 2025
c2880e5
feat: add stake threshold check
golddydev Oct 24, 2025
6c0124d
revert: omnibus
golddydev Oct 24, 2025
9bec09a
refactor: read epoch nonce in block vrf validator and update types fo…
golddydev Oct 24, 2025
46b3501
refactor: add validation for non obft slots
golddydev Oct 24, 2025
2475252
chore: add spo state subscription
golddydev Oct 28, 2025
fe41c0f
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 28, 2025
3cdc3c4
feat: implement snapshot state for vrf validation
golddydev Oct 29, 2025
0a07b2c
fix: cargo fmt
golddydev Oct 29, 2025
4fec204
fix: typo
golddydev Oct 29, 2025
0cba1a7
chore: simplify is_tpraos bool check
golddydev Oct 29, 2025
a64ae1f
feat: add vrf validation publisher
golddydev Oct 29, 2025
91c7a87
chore: remove unused var
golddydev Oct 29, 2025
f591f6f
refactor: publish only active epoch nonce
golddydev Oct 29, 2025
7d3d5ee
refactor: check block info sync in vrf validator
golddydev Oct 29, 2025
d968c88
refactor: epoch nonce publisher to publish nonces when there are not …
golddydev Oct 30, 2025
2b5dcd4
refactor: add move test cases to tpraos validation
golddydev Oct 30, 2025
6c148fb
revert: git ignore file
golddydev Oct 30, 2025
d19c1d8
fix: update praos vrf validation to use one vrf
golddydev Oct 30, 2025
10c70c0
fix: typo
golddydev Oct 30, 2025
59aa122
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 30, 2025
a0c0045
test: add praos test case
golddydev Oct 30, 2025
22fd669
Merge branch 'main' into golddydev/vrf-validation
golddydev Oct 30, 2025
9c6e29d
Merge branch 'main' into golddydev/vrf-validation
golddydev Nov 5, 2025
c82b74b
fix: build errors
golddydev Nov 5, 2025
7604607
fix: clippy
golddydev Nov 5, 2025
5fd8bf0
fix: move ouroboros to block_vrf_validator
golddydev Nov 7, 2025
f5d1745
fix: merge conflicts
golddydev Nov 7, 2025
f897a27
fix: only save mark and set snapshots
golddydev Nov 7, 2025
9fedc00
fix: only use active_slots_coeff in block_vrf_validator
golddydev Nov 7, 2025
1796892
fix: add not active slot in overlay error
golddydev Nov 7, 2025
b60f211
fix: use Hash for shelley genesis hash type
golddydev Nov 8, 2025
0829d16
Merge branch 'main' into golddydev/vrf-validation
golddydev Nov 8, 2025
f4a7a3e
fix: skip decode before shelley era
golddydev Nov 10, 2025
0f98236
Merge branch 'main' into golddydev/vrf-validation
golddydev Nov 11, 2025
57bf63e
fix: cargo shear
golddydev Nov 11, 2025
a77a3ed
fix: cargo audit issue with vrf dalek
golddydev Nov 11, 2025
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
267 changes: 247 additions & 20 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ members = [
"modules/consensus", # Chooses favoured chain across multiple options
"modules/chain_store", # Tracks historical information about blocks and TXs
"modules/tx_submitter", # Submits TXs to peers
"modules/block_vrf_validator", # Validate the VRF calculation in the block header

# Process builds
"processes/omnibus", # All-inclusive omnibus process
Expand All @@ -52,6 +53,7 @@ opentelemetry = { version = "0.30.0", features = ["trace"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "trace", "tls"] }
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] }
pallas = "0.33.0"
pallas-math = "0.33.0"
pallas-primitives = "0.33.0"
pallas-traverse = "0.33.0"
serde = { version = "1.0.214", features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ rayon = "1.11.0"
cryptoxide = "0.5.1"
thiserror = "2.0.17"
sha2 = "0.10.8"
caryatid_process.workspace = true
config.workspace = true
caryatid_process = { workspace = true }
config = { workspace = true }

[lib]
crate-type = ["rlib"]
Expand Down
72 changes: 64 additions & 8 deletions common/src/genesis_values.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use crate::calculations::{
epoch_to_first_slot_with_shelley_params, slot_to_epoch_with_shelley_params,
slot_to_timestamp_with_params,
use std::str::FromStr;

use crate::{
calculations::{
epoch_to_first_slot_with_shelley_params, slot_to_epoch_with_shelley_params,
slot_to_timestamp_with_params,
},
hash::Hash,
GenesisDelegates,
};
const MAINNET_SHELLEY_GENESIS_HASH: &str =
"1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81";
Expand All @@ -10,7 +16,8 @@ pub struct GenesisValues {
pub byron_timestamp: u64,
pub shelley_epoch: u64,
pub shelley_epoch_len: u64,
pub shelley_genesis_hash: [u8; 32],
pub shelley_genesis_hash: Hash<32>,
pub genesis_delegs: GenesisDelegates,
}

impl GenesisValues {
Expand All @@ -19,10 +26,59 @@ impl GenesisValues {
byron_timestamp: 1506203091,
shelley_epoch: 208,
shelley_epoch_len: 432000,
shelley_genesis_hash: hex::decode(MAINNET_SHELLEY_GENESIS_HASH)
.unwrap()
.try_into()
.unwrap(),
shelley_genesis_hash: Hash::<32>::from_str(MAINNET_SHELLEY_GENESIS_HASH).unwrap(),
genesis_delegs: GenesisDelegates::try_from(vec![
(
"ad5463153dc3d24b9ff133e46136028bdc1edbb897f5a7cf1b37950c",
(
"d9e5c76ad5ee778960804094a389f0b546b5c2b140a62f8ec43ea54d",
"64fa87e8b29a5b7bfbd6795677e3e878c505bc4a3649485d366b50abadec92d7",
),
),
(
"b9547b8a57656539a8d9bc42c008e38d9c8bd9c8adbb1e73ad529497",
(
"855d6fc1e54274e331e34478eeac8d060b0b90c1f9e8a2b01167c048",
"66d5167a1f426bd1adcc8bbf4b88c280d38c148d135cb41e3f5a39f948ad7fcc",
),
),
(
"60baee25cbc90047e83fd01e1e57dc0b06d3d0cb150d0ab40bbfead1",
(
"7f72a1826ae3b279782ab2bc582d0d2958de65bd86b2c4f82d8ba956",
"c0546d9aa5740afd569d3c2d9c412595cd60822bb6d9a4e8ce6c43d12bd0f674",
),
),
(
"f7b341c14cd58fca4195a9b278cce1ef402dc0e06deb77e543cd1757",
(
"69ae12f9e45c0c9122356c8e624b1fbbed6c22a2e3b4358cf0cb5011",
"6394a632af51a32768a6f12dac3485d9c0712d0b54e3f389f355385762a478f2",
),
),
(
"162f94554ac8c225383a2248c245659eda870eaa82d0ef25fc7dcd82",
(
"4485708022839a7b9b8b639a939c85ec0ed6999b5b6dc651b03c43f6",
"aba81e764b71006c515986bf7b37a72fbb5554f78e6775f08e384dbd572a4b32",
),
),
(
"2075a095b3c844a29c24317a94a643ab8e22d54a3a3a72a420260af6",
(
"6535db26347283990a252313a7903a45e3526ec25ddba381c071b25b",
"fcaca997b8105bd860876348fc2c6e68b13607f9bbd23515cd2193b555d267af",
),
),
(
"268cfc0b89e910ead22e0ade91493d8212f53f3e2164b2e4bef0819b",
(
"1d4f2e1fda43070d71bb22a5522f86943c7c18aeb4fa47a362c27e23",
"63ef48bc5355f3e7973100c371d6a095251c80ceb40559f4750aa7014a6fb6db",
),
),
])
.unwrap(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions common/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::commands::transactions::{TransactionsCommand, TransactionsCommandResponse};
use crate::genesis_values::GenesisValues;
use crate::ledger_state::SPOState;
use crate::protocol_params::{NonceHash, ProtocolParams};
use crate::protocol_params::{Nonce, ProtocolParams};
use crate::queries::parameters::{ParametersStateQuery, ParametersStateQueryResponse};
use crate::queries::spdd::{SPDDStateQuery, SPDDStateQueryResponse};
use crate::queries::utxos::{UTxOStateQuery, UTxOStateQueryResponse};
Expand Down Expand Up @@ -182,7 +182,7 @@ pub struct EpochActivityMessage {
pub spo_blocks: Vec<(PoolId, usize)>,

/// Nonce
pub nonce: Option<NonceHash>,
pub nonce: Option<Nonce>,
}

#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
Expand Down
39 changes: 38 additions & 1 deletion common/src/protocol_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use anyhow::{bail, Result};
use blake2::{digest::consts::U32, Blake2b, Digest};
use chrono::{DateTime, Utc};
use serde_with::{hex::Hex, serde_as};
use std::collections::HashMap;
use std::ops::Deref;
use std::{collections::HashMap, fmt::Display};

#[derive(Debug, Default, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct ProtocolParams {
Expand Down Expand Up @@ -272,6 +272,15 @@ pub struct Nonce {
pub hash: Option<NonceHash>,
}

impl Display for Nonce {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.hash {
Some(hash) => write!(f, "{}", hex::encode(hash)),
None => write!(f, "NeutralNonce"),
}
}
}

impl Default for Nonce {
fn default() -> Self {
Self {
Expand All @@ -290,6 +299,34 @@ impl From<NonceHash> for Nonce {
}
}

impl Nonce {
pub fn from_number(n: u64) -> Self {
let mut hasher = Blake2b::<U32>::new();
hasher.update(n.to_be_bytes());
let hash: NonceHash = hasher.finalize().into();
Self::from(hash)
}

pub fn neutral() -> Self {
Self {
tag: NonceVariant::NeutralNonce,
hash: None,
}
}

/// Seed constant for eta (randomness/entropy) computation
/// Used when generating the epoch nonce
pub fn seed_eta() -> Self {
Self::from_number(0)
}

/// Seed constant for leader (L) computation
/// Used when determining if a stake pool is the slot leader
pub fn seed_l() -> Self {
Self::from_number(1)
}
}

impl From<BlockHash> for Nonce {
fn from(hash: BlockHash) -> Self {
Self {
Expand Down
2 changes: 1 addition & 1 deletion common/src/rational_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ mod tests {
fn test_chameleon_serialization() -> Result<()> {
for n in 0..=1000 {
let ch = [
&ChameleonFraction::Float(f32::from_str(&format!("0.{:03}", n))?),
&ChameleonFraction::Float(f32::from_str(&format!("0.{n:03}"))?),
&ChameleonFraction::Fraction {
numerator: n,
denominator: 1000,
Expand Down
63 changes: 45 additions & 18 deletions common/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use hex::decode;
use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_with::{hex::Hex, serde_as};
use std::collections::BTreeMap;
use std::{
cmp::Ordering,
collections::{HashMap, HashSet},
Expand Down Expand Up @@ -115,7 +116,7 @@ impl TryFrom<u8> for Era {

impl Display for Era {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
write!(f, "{self:?}")
}
}

Expand Down Expand Up @@ -656,6 +657,9 @@ impl TxOutRef {
}
}

/// Slot
pub type Slot = u64;

/// Amount of Ada, in Lovelace
pub type Lovelace = u64;
pub type LovelaceDelta = i64;
Expand Down Expand Up @@ -735,14 +739,10 @@ impl Credential {
let key_hash = decode(hex_str.to_owned().into_bytes())?;
if key_hash.len() != 28 {
Err(anyhow!(
"Invalid hash length for {:?}, expected 28 bytes",
hex_str
"Invalid hash length for {hex_str:?}, expected 28 bytes"
))
} else {
key_hash
.as_slice()
.try_into()
.map_err(|e| anyhow!("Failed to convert to KeyHash {}", e))
key_hash.as_slice().try_into().map_err(|e| anyhow!("Failed to convert to KeyHash {e}"))
}
}

Expand All @@ -753,16 +753,15 @@ impl Credential {
Ok(Credential::AddrKeyHash(Self::hex_string_to_hash(hash)?))
} else {
Err(anyhow!(
"Incorrect credential {}, expected scriptHash- or keyHash- prefix",
credential
"Incorrect credential {credential}, expected scriptHash- or keyHash- prefix"
))
}
}

pub fn to_json_string(&self) -> String {
match self {
Self::ScriptHash(hash) => format!("scriptHash-{}", hash),
Self::AddrKeyHash(hash) => format!("keyHash-{}", hash),
Self::ScriptHash(hash) => format!("scriptHash-{hash}"),
Self::AddrKeyHash(hash) => format!("keyHash-{hash}"),
}
}

Expand All @@ -788,8 +787,7 @@ impl Credential {
"drep" => Ok(Credential::AddrKeyHash(hash)),
"drep_script" => Ok(Credential::ScriptHash(hash)),
_ => Err(anyhow!(
"Invalid HRP for DRep Bech32, expected 'drep' or 'drep_script', got '{}'",
hrp
"Invalid HRP for DRep Bech32, expected 'drep' or 'drep_script', got '{hrp}'"
)),
}
}
Expand Down Expand Up @@ -1296,7 +1294,7 @@ impl GovActionId {
let (hrp, data) = bech32::decode(bech32_str)?;

if hrp != Hrp::parse("gov_action")? {
return Err(anyhow!("Invalid HRP, expected 'gov_action', got: {}", hrp));
return Err(anyhow!("Invalid HRP, expected 'gov_action', got: {hrp}"));
}

if data.len() < 33 {
Expand Down Expand Up @@ -1328,7 +1326,7 @@ impl GovActionId {
impl Display for GovActionId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.to_bech32() {
Ok(s) => write!(f, "{}", s),
Ok(s) => write!(f, "{s}"),
Err(e) => {
tracing::error!("GovActionId to_bech32 failed: {:?}", e);
write!(f, "<invalid-govactionid>")
Expand Down Expand Up @@ -1426,7 +1424,36 @@ pub struct GenesisDelegate {
#[serde_as(as = "Hex")]
pub delegate: Hash<28>,
#[serde_as(as = "Hex")]
pub vrf: Vec<u8>,
pub vrf: VrfKeyHash,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GenesisDelegates(pub BTreeMap<GenesisKeyhash, GenesisDelegate>);

impl TryFrom<Vec<(&str, (&str, &str))>> for GenesisDelegates {
type Error = anyhow::Error;
fn try_from(entries: Vec<(&str, (&str, &str))>) -> Result<Self, Self::Error> {
Ok(GenesisDelegates(
entries
.into_iter()
.map(|(genesis_key_str, (delegate_str, vrf_str))| {
let genesis_key = GenesisKeyhash::from_str(genesis_key_str)
.map_err(|e| anyhow::anyhow!("Invalid genesis key hash: {e}"))?;
let delegate = Hash::<28>::from_str(delegate_str)
.map_err(|e| anyhow::anyhow!("Invalid genesis delegate: {e}"))?;
let vrf = VrfKeyHash::from_str(vrf_str)
.map_err(|e| anyhow::anyhow!("Invalid genesis VRF: {e}"))?;
Ok((genesis_key, GenesisDelegate { delegate, vrf }))
})
.collect::<Result<_, Self::Error>>()?,
))
}
}

impl AsRef<BTreeMap<GenesisKeyhash, GenesisDelegate>> for GenesisDelegates {
fn as_ref(&self) -> &BTreeMap<GenesisKeyhash, GenesisDelegate> {
&self.0
}
}

#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -1767,8 +1794,8 @@ impl Voter {
impl Display for Voter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.to_bech32() {
Ok(addr) => write!(f, "{}", addr),
Err(e) => write!(f, "<invalid voter: {}>", e),
Ok(addr) => write!(f, "{addr}"),
Err(e) => write!(f, "<invalid voter: {e}>"),
}
}
}
Expand Down
Loading