Skip to content
8 changes: 4 additions & 4 deletions Cargo.lock

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

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-cardano-node-chain"
version = "0.1.7"
version = "0.1.8"
authors.workspace = true
documentation.workspace = true
edition.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::fs;
use std::path::PathBuf;
use tokio::process::Command;

use mithril_common::crypto_helper::{KesPeriod, OpCert, SerDeShelleyFileFormat, encode_bech32};
use mithril_common::crypto_helper::{KesPeriod, encode_bech32};
use mithril_common::entities::{BlockNumber, ChainPoint, Epoch, SlotNumber, StakeDistribution};
use mithril_common::{CardanoNetwork, StdResult};

Expand Down Expand Up @@ -38,7 +38,7 @@ pub trait CliRunner {
/// Launches the chain point.
async fn launch_chain_point(&self) -> StdResult<String>;
/// Launches the kes period.
async fn launch_kes_period(&self, opcert_file: &str) -> StdResult<String>;
async fn launch_kes_period(&self) -> StdResult<(String, u64)>;
}

/// A runner able to request data from a Cardano node using the
Expand Down Expand Up @@ -141,14 +141,9 @@ impl CardanoCliRunner {
command
}

fn command_for_kes_period(&self, opcert_file: &str) -> Command {
fn command_for_kes_period(&self) -> Command {
let mut command = self.get_command();
command
.arg(CARDANO_ERA)
.arg("query")
.arg("kes-period-info")
.arg("--op-cert-file")
.arg(opcert_file);
command.arg(CARDANO_ERA).arg("query").arg("tip");
self.post_config_command(&mut command);

command
Expand All @@ -172,6 +167,20 @@ impl CardanoCliRunner {
}
}
}

/// Get slots per kes period
///
/// This implementation is aligned with current value for the KES period on the testnet and mainnet networks of Cardano.
/// If this value changes in the future, the implementation should be updated accordingly.
/// The value can be retrieved in the 'slotsPerKESPeriod' field of the 'shelly-genesis.json' configuration file.
fn get_slots_per_kes_period(&self) -> u64 {
match self.network {
CardanoNetwork::MainNet => 129600,
CardanoNetwork::TestNet(1) => 129600,
CardanoNetwork::TestNet(2) => 129600,
CardanoNetwork::TestNet(_) => 129600,
}
}
}

#[async_trait]
Expand Down Expand Up @@ -289,17 +298,20 @@ impl CliRunner for CardanoCliRunner {
}
}

async fn launch_kes_period(&self, opcert_file: &str) -> StdResult<String> {
let output = self.command_for_kes_period(opcert_file).output().await?;
async fn launch_kes_period(&self) -> StdResult<(String, u64)> {
let output = self.command_for_kes_period().output().await?;

if output.status.success() {
Ok(std::str::from_utf8(&output.stdout)?.trim().to_string())
Ok((
std::str::from_utf8(&output.stdout)?.trim().to_string(),
self.get_slots_per_kes_period(),
))
} else {
let message = String::from_utf8_lossy(&output.stderr);

Err(anyhow!(
"Error launching command {:?}, error = '{}'",
self.command_for_kes_period(opcert_file),
self.command_for_kes_period(),
message
))
}
Expand Down Expand Up @@ -526,29 +538,26 @@ impl ChainObserver for CardanoCliChainObserver {
}
}

async fn get_current_kes_period(
&self,
opcert: &OpCert,
) -> Result<Option<KesPeriod>, ChainObserverError> {
async fn get_current_kes_period(&self) -> Result<Option<KesPeriod>, ChainObserverError> {
let dir = std::env::temp_dir().join("mithril_kes_period");
fs::create_dir_all(&dir).map_err(|e| ChainObserverError::General(e.into()))?;
let opcert_file = dir.join(format!("opcert_kes_period-{}", opcert.compute_hash()));
opcert
.to_file(&opcert_file)
.map_err(|e| ChainObserverError::General(e.into()))?;
let output = self
let (output, slots_per_kes_period) = self
.cli_runner
.launch_kes_period(opcert_file.to_str().unwrap())
.launch_kes_period()
.await
.map_err(ChainObserverError::General)?;
if slots_per_kes_period == 0 {
return Err(anyhow!("slots_per_kes_period must be greater than 0"))
.with_context(|| "CardanoCliChainObserver failed to calculate kes period")?;
}
let first_left_curly_bracket_index = output.find('{').unwrap_or_default();
let output_cleaned = output.split_at(first_left_curly_bracket_index).1;
let v: Value = serde_json::from_str(output_cleaned)
.with_context(|| format!("output was = '{output}'"))
.map_err(ChainObserverError::InvalidContent)?;

if let Value::Number(kes_period) = &v["qKesCurrentKesPeriod"] {
Ok(kes_period.as_u64().map(|p| p as KesPeriod))
if let Value::Number(slot) = &v["slot"] {
Ok(slot.as_u64().map(|slot| (slot / slots_per_kes_period) as KesPeriod))
} else {
Ok(None)
}
Expand All @@ -557,12 +566,9 @@ impl ChainObserver for CardanoCliChainObserver {

#[cfg(test)]
mod tests {
use kes_summed_ed25519::{kes::Sum6Kes, traits::KesSk};
use std::collections::BTreeMap;
use std::ffi::OsStr;

use mithril_common::crypto_helper::ColdKeyGenerator;

use crate::test::test_cli_runner::{TestCliRunner, test_expected};

use super::*;
Expand Down Expand Up @@ -807,17 +813,12 @@ mod tests {

#[tokio::test]
async fn test_get_current_kes_period() {
let keypair = ColdKeyGenerator::create_deterministic_keypair([0u8; 32]);
let mut dummy_key_buffer = [0u8; Sum6Kes::SIZE + 4];
let mut dummy_seed = [0u8; 32];
let (_, kes_verification_key) = Sum6Kes::keygen(&mut dummy_key_buffer, &mut dummy_seed);
let operational_certificate = OpCert::new(kes_verification_key, 0, 0, keypair);
let observer = CardanoCliChainObserver::new(Box::<TestCliRunner>::default());
let kes_period = observer
.get_current_kes_period(&operational_certificate)
.await
.unwrap()
.unwrap();
assert_eq!(test_expected::launch_kes_period::KES_PERIOD, kes_period);
let kes_period = observer.get_current_kes_period().await.unwrap().unwrap();
assert_eq!(
(test_expected::launch_chain_point::SLOT_NUMBER.0
/ test_expected::launch_kes_period::SLOTS_PER_KES_PERIOD) as u32,
kes_period
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use async_trait::async_trait;
use thiserror::Error;

use mithril_common::StdError;
use mithril_common::crypto_helper::{KesPeriod, OpCert};
use mithril_common::crypto_helper::KesPeriod;
use mithril_common::entities::{ChainPoint, Epoch, StakeDistribution};

use crate::entities::{ChainAddress, TxDatum};
Expand Down Expand Up @@ -43,11 +43,8 @@ pub trait ChainObserver: Sync + Send {
&self,
) -> Result<Option<StakeDistribution>, ChainObserverError>;

/// Retrieve the KES period of an operational certificate
async fn get_current_kes_period(
&self,
_opcert: &OpCert,
) -> Result<Option<KesPeriod>, ChainObserverError> {
/// Retrieve the current KES period
async fn get_current_kes_period(&self) -> Result<Option<KesPeriod>, ChainObserverError> {
Ok(None)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use pallas_network::{
use pallas_primitives::ToCanonicalJson;
use pallas_traverse::Era;

use mithril_common::crypto_helper::{KesPeriod, OpCert, encode_bech32};
use mithril_common::crypto_helper::{KesPeriod, encode_bech32};
use mithril_common::entities::{BlockNumber, ChainPoint, Epoch, SlotNumber, StakeDistribution};
use mithril_common::{CardanoNetwork, StdResult};

Expand Down Expand Up @@ -491,10 +491,7 @@ impl ChainObserver for PallasChainObserver {
Ok(stake_distribution)
}

async fn get_current_kes_period(
&self,
_opcert: &OpCert,
) -> Result<Option<KesPeriod>, ChainObserverError> {
async fn get_current_kes_period(&self) -> Result<Option<KesPeriod>, ChainObserverError> {
let mut client = self.get_client().await?;

let current_kes_period = self.get_kes_period(&mut client).await?;
Expand All @@ -512,7 +509,6 @@ impl ChainObserver for PallasChainObserver {
mod tests {
use std::fs;

use kes_summed_ed25519::{kes::Sum6Kes, traits::KesSk};
use pallas_codec::utils::{AnyCbor, AnyUInt, KeyValuePairs, TagWrap};
use pallas_crypto::hash::Hash;
use pallas_network::facades::NodeServer;
Expand All @@ -528,7 +524,6 @@ mod tests {
};
use tokio::net::UnixListener;

use mithril_common::crypto_helper::ColdKeyGenerator;
use mithril_common::test::TempDir;

use super::*;
Expand Down Expand Up @@ -781,15 +776,7 @@ mod tests {
let observer =
PallasChainObserver::new(socket_path.as_path(), CardanoNetwork::TestNet(10));

let keypair = ColdKeyGenerator::create_deterministic_keypair([0u8; 32]);
let mut dummy_key_buffer = [0u8; Sum6Kes::SIZE + 4];
let mut dummy_seed = [0u8; 32];
let (_, kes_verification_key) = Sum6Kes::keygen(&mut dummy_key_buffer, &mut dummy_seed);
let operational_certificate = OpCert::new(kes_verification_key, 0, 0, keypair);
observer
.get_current_kes_period(&operational_certificate)
.await
.unwrap()
observer.get_current_kes_period().await.unwrap()
});

let (_, client_res) = tokio::join!(server, client);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use async_trait::async_trait;
use tokio::sync::RwLock;

use mithril_common::crypto_helper::{KesPeriod, OpCert};
use mithril_common::crypto_helper::KesPeriod;
use mithril_common::entities::{
BlockNumber, ChainPoint, Epoch, SignerWithStake, SlotNumber, StakeDistribution, TimePoint,
};
Expand Down Expand Up @@ -202,10 +202,7 @@ impl ChainObserver for FakeChainObserver {
))
}

async fn get_current_kes_period(
&self,
_opcert: &OpCert,
) -> Result<Option<KesPeriod>, ChainObserverError> {
async fn get_current_kes_period(&self) -> Result<Option<KesPeriod>, ChainObserverError> {
Ok(Some(0))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(crate) mod test_expected {
pub(crate) const BYTES: &str = "5b0a20207b0a20202020226e616d65223a20227468616c6573222c0a202020202265706f6368223a203132330a20207d2c0a20207b0a20202020226e616d65223a20227079746861676f726173222c0a202020202265706f6368223a206e756c6c0a20207d0a5d0a";
}
pub(crate) mod launch_kes_period {
pub(crate) const KES_PERIOD: u32 = 404;
pub(crate) const SLOTS_PER_KES_PERIOD: u64 = 10000;
}
pub(crate) mod launch_stake_snapshot {
pub(crate) const DEFAULT_POOL_STAKE_MARK: u64 = 3_000_000;
Expand Down Expand Up @@ -256,25 +256,27 @@ pool1qz2vzszautc2c8mljnqre2857dpmheq7kgt6vav0s38tvvhxm6w 1.051e-6
}

/// launches the kes period.
async fn launch_kes_period(&self, _opcert_file: &str) -> StdResult<String> {
async fn launch_kes_period(&self) -> StdResult<(String, u64)> {
let output = format!(
r#"
✓ The operational certificate counter agrees with the node protocol state counter
✓ Operational certificate's kes period is within the correct KES period interval
{{
"qKesNodeStateOperationalCertificateNumber": 6,
"qKesCurrentKesPeriod": {},
"qKesOnDiskOperationalCertificateNumber": 6,
"qKesRemainingSlotsInKesPeriod": 3760228,
"qKesMaxKESEvolutions": 62,
"qKesKesKeyExpiry": "2022-03-20T21:44:51Z",
"qKesEndKesInterval": 434,
"qKesStartKesInterval": 372,
"qKesSlotsPerKesPeriod": 129600
"block": {},
"epoch": 299,
"era": "Conway",
"hash": "{}",
"slot": {},
"slotInEpoch": 53017,
"slotsToEpochEnd": 33383,
"syncProgress": "100.00"
}}"#,
test_expected::launch_kes_period::KES_PERIOD
test_expected::launch_chain_point::BLOCK_NUMBER,
test_expected::launch_chain_point::BLOCK_HASH,
test_expected::launch_chain_point::SLOT_NUMBER,
);

Ok(output)
Ok((
output,
test_expected::launch_kes_period::SLOTS_PER_KES_PERIOD,
))
}
}
2 changes: 1 addition & 1 deletion internal/mithril-dmq/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "mithril-dmq"
description = "Mechanisms to publish and consume messages of a 'Decentralized Message Queue network' through a DMQ node"
version = "0.1.8"
version = "0.1.9"
authors.workspace = true
documentation.workspace = true
edition.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion internal/mithril-dmq/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl DmqMessageBuilder {
.with_context(|| "Failed to KES sign message while building DMQ message")?;
let kes_period = self
.chain_observer
.get_current_kes_period(&operational_certificate)
.get_current_kes_period()
.await
.with_context(|| "Failed to get KES period while building DMQ message")?
.unwrap_or_default();
Expand Down
2 changes: 1 addition & 1 deletion mithril-aggregator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-aggregator"
version = "0.7.81"
version = "0.7.82"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl SignerRegistrationVerifier for MithrilSignerRegistrationVerifier {
let kes_period = match &signer.operational_certificate {
Some(operational_certificate) => Some(
self.chain_observer
.get_current_kes_period(operational_certificate)
.get_current_kes_period()
.await?
.unwrap_or_default()
- operational_certificate.start_kes_period as KesPeriod,
Expand Down
Loading