Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
852dd12
feat(stm): add SNARK aggregate verification key to protocol layer
jpraynaud Mar 6, 2026
17f72f7
feat(common): wire SNARK AVK into crypto helper types and protocol me…
jpraynaud Mar 6, 2026
8acf1c8
feat(common): add SNARK AVK to genesis certificate and certificate ve…
jpraynaud Mar 6, 2026
7b4846e
feat(common): add SNARK AVK to signable builder and test infrastructure
jpraynaud Mar 6, 2026
e4308b2
feat(aggregator): add SNARK AVK persistence and era-gated certificate…
jpraynaud Mar 6, 2026
52c55de
feat(signer): add SNARK AVK computation with era gating
jpraynaud Mar 6, 2026
1bc9e0e
feat(client): add SNARK AVK verification when present in protocol mes…
jpraynaud Mar 6, 2026
6244161
feat(signer): strip SNARK keys from initializer and signers in Pythag…
jpraynaud Mar 10, 2026
2e4c153
fix(stm): backward compatibility for Concatenation proof
jpraynaud Mar 12, 2026
a9bb7b8
feat(common): support Mithril era in genesis certificate
jpraynaud Mar 13, 2026
8f3369c
feat(aggregator): support Mithirl era in genesis commands
jpraynaud Mar 13, 2026
9fd1bf3
feat(e2e): support Mithril era in genesis commands
jpraynaud Mar 13, 2026
1d75848
docs(website): update genesis commands of aggregator
jpraynaud Mar 13, 2026
3c93f7b
chore: apply review comments
jpraynaud Mar 13, 2026
f4fb528
feat(aggregator): add logger in genesis tools
jpraynaud Mar 13, 2026
dd48413
docs: update runbook for manual genesis
jpraynaud Mar 13, 2026
c57a142
chore: fix clippy warning
jpraynaud Mar 15, 2026
4853aa2
docs: update CHANGELOG
jpraynaud Mar 13, 2026
4949549
chore: upgrade crate versions
jpraynaud Mar 13, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ As a minor extension, we have adopted a slightly different versioning convention
- **UNSTABLE**:
- Support for **DMQ consumer deduplication** to prevent processing the same message multiple times upon reconnection to the DMQ server.
- Support for SNARK-friendly signer registration.
- Support for SNARK-friendly certificate chain.

| Crate | Version |
| ----- | ------- |
Expand Down
14 changes: 7 additions & 7 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion docs/runbook/genesis-manually/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export NETWORK_MAGIC=**NETWORK_MAGIC**
export DATA_STORES_DIRECTORY=**DATA_STORES_DIRECTORY**
export CARDANO_NODE_SOCKET_PATH=**CARDANO_NODE_SOCKET_PATH**
export CHAIN_OBSERVER_TYPE=**CHAIN_OBSERVER_TYPE**
export MITHRIL_ERA=**MITHRIL_ERA**
```

And create genesis dir:
Expand All @@ -49,9 +50,11 @@ docker exec -it mithril-aggregator bash
Once connected to the aggregator container, export the genesis payload to sign:

```bash
/app/bin/mithril-aggregator -vvv genesis export --target-path /mithril-aggregator/mithril/genesis/genesis-payload-to-sign.txt
/app/bin/mithril-aggregator -vvv genesis export --target-path /mithril-aggregator/mithril/genesis/genesis-payload-to-sign.txt [--mithril-era $MITHRIL_ERA]
```

> The `--mithril-era` parameter is optional when only one era exists, and required when multiple eras are supported. It specifies which Mithril era to use for the genesis certificate (e.g. `pythagoras`, `lagrange`).

Then disconnect from the aggregator container:

```bash
Expand Down
40 changes: 22 additions & 18 deletions docs/website/root/manual/develop/nodes/mithril-aggregator.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,27 +550,31 @@ Here is a list of the available parameters for the serve command:

`genesis bootstrap` command:

| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
| -------------------------- | ------------------- | :------------------: | -------------------------- | ------------------------------------------------------------------ | ------------- | ---------------------------------- | :----------------: |
| `genesis_secret_key` | - | - | `GENESIS_SECRET_KEY` | Genesis secret key, :warning: for test only | - | - | :heavy_check_mark: |
| `data_stores_directory` | - | - | `DATA_STORES_DIRECTORY` | Directory to store aggregator databases | - | `./mithril-aggregator/stores` | :heavy_check_mark: |
| `cardano_node_socket_path` | - | - | `CARDANO_NODE_SOCKET_PATH` | Path of the socket opened by the Cardano node | - | `/ipc/node.socket` | :heavy_check_mark: |
| `cardano_cli_path` | - | - | `CARDANO_CLI_PATH` | Cardano CLI tool path | - | `cardano-cli` | - |
| `chain_observer_type` | - | - | `CHAIN_OBSERVER_TYPE` | Chain observer type that can be `cardano-cli`, `pallas` or `fake`. | `pallas` | - | :heavy_check_mark: |
| `network` | - | - | `NETWORK` | Cardano network | - | `mainnet` or `preprod` or `devnet` | :heavy_check_mark: |
| `network_magic` | - | - | `NETWORK_MAGIC` | Cardano network magic number (for `testnet` and `devnet`) | - | `1097911063` or `42` | - |
| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
| -------------------------- | ---------------------- | :------------------: | -------------------------- | -------------------------------------------------------------------------------------- | ------------- | ---------------------------------- | :----------------: |
| `genesis_secret_key` | `--genesis-secret-key` | - | `GENESIS_SECRET_KEY` | Genesis Secret Key (test only) | - | - | :heavy_check_mark: |
| `mithril_era` | `--mithril-era` | - | - | Mithril era to use for the genesis certificate | - | - | - |
| `help` | `--help` | `-h` | - | Print help (see more with '--help') | - | - | - |
| `cardano_cli_path` | - | - | `CARDANO_CLI_PATH` | Cardano CLI tool path | - | `cardano-cli` | - |
| `cardano_node_socket_path` | - | - | `CARDANO_NODE_SOCKET_PATH` | Path of the socket opened by the Cardano node | - | `/ipc/node.socket` | :heavy_check_mark: |
| `network_magic` | - | - | `NETWORK_MAGIC` | Cardano Network Magic number<br/><br/>useful for TestNet & DevNet | - | `1097911063` or `42` | - |
| `network` | - | - | `NETWORK` | Cardano network | - | `mainnet` or `preprod` or `devnet` | :heavy_check_mark: |
| `chain_observer_type` | - | - | `CHAIN_OBSERVER_TYPE` | Cardano chain observer type | - | - | :heavy_check_mark: |
| `data_stores_directory` | - | - | `DATA_STORES_DIRECTORY` | Directory to store aggregator data (Certificates, Snapshots, Protocol Parameters, ...) | - | `./mithril-aggregator/stores` | :heavy_check_mark: |

`genesis export` command:

| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
| -------------------------- | ------------------- | :------------------: | -------------------------- | ------------------------------------------------------------------ | ------------- | ---------------------------------- | :----------------: |
| `target_path` | `--target-path` | - | - | Path of the file to export the payload to. | - | - | :heavy_check_mark: |
| `data_stores_directory` | - | - | `DATA_STORES_DIRECTORY` | Directory to store aggregator databases | - | `./mithril-aggregator/stores` | :heavy_check_mark: |
| `cardano_node_socket_path` | - | - | `CARDANO_NODE_SOCKET_PATH` | Path of the socket opened by the Cardano node | - | `/ipc/node.socket` | :heavy_check_mark: |
| `cardano_cli_path` | - | - | `CARDANO_CLI_PATH` | Cardano CLI tool path | - | `cardano-cli` | - |
| `chain_observer_type` | - | - | `CHAIN_OBSERVER_TYPE` | Chain observer type that can be `cardano-cli`, `pallas` or `fake`. | `pallas` | - | :heavy_check_mark: |
| `network` | - | - | `NETWORK` | Cardano network | - | `mainnet` or `preprod` or `devnet` | :heavy_check_mark: |
| `network_magic` | - | - | `NETWORK_MAGIC` | Cardano network magic number (for `testnet` and `devnet`) | - | `1097911063` or `42` | - |
| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
| -------------------------- | ------------------- | :------------------: | -------------------------- | -------------------------------------------------------------------------------------- | ------------- | ---------------------------------- | :----------------: |
| `target_path` | `--target-path` | - | - | Target path | - | - | :heavy_check_mark: |
| `mithril_era` | `--mithril-era` | - | - | Mithril era to use for the genesis certificate | - | - | - |
| `help` | `--help` | `-h` | - | Print help (see more with '--help') | - | - | - |
| `cardano_cli_path` | - | - | `CARDANO_CLI_PATH` | Cardano CLI tool path | - | `cardano-cli` | - |
| `cardano_node_socket_path` | - | - | `CARDANO_NODE_SOCKET_PATH` | Path of the socket opened by the Cardano node | - | `/ipc/node.socket` | :heavy_check_mark: |
| `network_magic` | - | - | `NETWORK_MAGIC` | Cardano Network Magic number<br/><br/>useful for TestNet & DevNet | - | `1097911063` or `42` | - |
| `network` | - | - | `NETWORK` | Cardano network | - | `mainnet` or `preprod` or `devnet` | :heavy_check_mark: |
| `chain_observer_type` | - | - | `CHAIN_OBSERVER_TYPE` | Cardano chain observer type | - | - | :heavy_check_mark: |
| `data_stores_directory` | - | - | `DATA_STORES_DIRECTORY` | Directory to store aggregator data (Certificates, Snapshots, Protocol Parameters, ...) | - | `./mithril-aggregator/stores` | :heavy_check_mark: |

`genesis import` command:

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.8.33"
version = "0.8.34"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
85 changes: 74 additions & 11 deletions mithril-aggregator/src/commands/genesis_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use mithril_common::{
crypto_helper::{
ProtocolGenesisSecretKey, ProtocolGenesisSigner, ProtocolGenesisVerificationKey,
},
entities::{HexEncodedGenesisSecretKey, HexEncodedGenesisVerificationKey},
entities::{HexEncodedGenesisSecretKey, HexEncodedGenesisVerificationKey, SupportedEra},
};
use mithril_doc::{Documenter, StructDoc};

Expand All @@ -21,6 +21,27 @@ use crate::{
extract_all, tools::GenesisTools,
};

/// Resolve the Mithril era for the genesis command.
///
/// If the era is explicitly provided, it is returned as-is.
/// If not provided and only one era exists, that era is used automatically.
/// If not provided and multiple eras exist, an error is returned.
fn resolve_mithril_era(mithril_era: Option<SupportedEra>) -> StdResult<SupportedEra> {
match mithril_era {
Some(era) => Ok(era),
None => {
let eras = SupportedEra::eras();
if eras.len() == 1 {
Ok(eras[0])
} else {
Err(anyhow::anyhow!(
"Multiple Mithril eras are supported ({eras:?}), please specify which era to use with --mithril-era"
))
}
}
}
}

#[derive(Debug, Clone, Deserialize, Documenter)]
pub struct GenesisCommandConfiguration {
/// Cardano CLI tool path
Expand Down Expand Up @@ -163,6 +184,12 @@ pub struct ExportGenesisSubCommand {
/// Target path
#[clap(long)]
target_path: PathBuf,

/// Mithril era to use for the genesis certificate
///
/// Optional when only one era exists, required when multiple eras are supported.
#[clap(long)]
mithril_era: Option<SupportedEra>,
}

impl ExportGenesisSubCommand {
Expand All @@ -181,11 +208,15 @@ impl ExportGenesisSubCommand {
"Genesis export payload to sign to {}",
self.target_path.display()
);
let mithril_era = resolve_mithril_era(self.mithril_era)?;
let mut dependencies_builder =
DependenciesBuilder::new(root_logger.clone(), Arc::new(config.clone()));
let dependencies = dependencies_builder.create_genesis_container().await.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;
let dependencies = dependencies_builder
.create_genesis_container(mithril_era)
.await
.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;

let genesis_tools = GenesisTools::from_dependencies(dependencies)
.await
Expand Down Expand Up @@ -228,11 +259,15 @@ impl ImportGenesisSubCommand {
"Genesis import signed payload from {}",
self.signed_payload_path.to_string_lossy()
);
let mithril_era = resolve_mithril_era(None)?;
let mut dependencies_builder =
DependenciesBuilder::new(root_logger.clone(), Arc::new(config.clone()));
let dependencies = dependencies_builder.create_genesis_container().await.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;
let dependencies = dependencies_builder
.create_genesis_container(mithril_era)
.await
.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;

let genesis_tools = GenesisTools::from_dependencies(dependencies)
.await
Expand Down Expand Up @@ -296,6 +331,12 @@ pub struct BootstrapGenesisSubCommand {
/// Genesis Secret Key (test only)
#[clap(long, env = "GENESIS_SECRET_KEY")]
genesis_secret_key: HexEncodedGenesisSecretKey,

/// Mithril era to use for the genesis certificate
///
/// Optional when only one era exists, required when multiple eras are supported.
#[clap(long)]
mithril_era: Option<SupportedEra>,
}

impl BootstrapGenesisSubCommand {
Expand All @@ -311,11 +352,15 @@ impl BootstrapGenesisSubCommand {
.with_context(|| "configuration deserialize error")?;
debug!(root_logger, "BOOTSTRAP GENESIS command"; "config" => format!("{config:?}"));
println!("Genesis bootstrap for test only!");
let mithril_era = resolve_mithril_era(self.mithril_era)?;
let mut dependencies_builder =
DependenciesBuilder::new(root_logger.clone(), Arc::new(config.clone()));
let dependencies = dependencies_builder.create_genesis_container().await.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;
let dependencies = dependencies_builder
.create_genesis_container(mithril_era)
.await
.with_context(
|| "Dependencies Builder can not create genesis command dependencies container",
)?;

let genesis_tools = GenesisTools::from_dependencies(dependencies)
.await
Expand Down Expand Up @@ -372,6 +417,24 @@ mod tests {

use super::*;

#[test]
fn resolve_mithril_era_returns_provided_era() {
let era = resolve_mithril_era(Some(SupportedEra::Lagrange)).unwrap();
assert_eq!(SupportedEra::Lagrange, era);
}

#[test]
fn resolve_mithril_era_returns_error_when_multiple_eras_and_none_provided() {
let eras = SupportedEra::eras();
if eras.len() > 1 {
let result = resolve_mithril_era(None);
assert!(
result.is_err(),
"Should error when multiple eras exist and none is provided"
);
}
}

#[tokio::test]
async fn create_container_does_not_panic() {
let config = GenesisCommandConfiguration {
Expand All @@ -386,7 +449,7 @@ mod tests {
DependenciesBuilder::new(TestLogger::stdout(), Arc::new(config));

dependencies_builder
.create_genesis_container()
.create_genesis_container(SupportedEra::Pythagoras)
.await
.expect("Expected container creation to succeed without panicking");
}
Expand Down
8 changes: 8 additions & 0 deletions mithril-aggregator/src/database/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,5 +302,13 @@ alter table signer_registration add column verification_key_for_snark text;
alter table signer_registration add column verification_key_signature_for_snark text;
"#,
),
// Migration 41
// Add `aggregate_verification_key_snark` column to `certificate` table.
SqlMigration::new(
41,
r#"
alter table certificate add column aggregate_verification_key_snark text;
"#,
),
]
}
Loading
Loading