Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add an era subcommand to create keypair #2274

Merged
merged 3 commits into from
Feb 4, 2025
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: 2 additions & 2 deletions Cargo.lock

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

8 changes: 8 additions & 0 deletions docs/website/root/manual/develop/nodes/mithril-aggregator.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ Usage: mithril-aggregator era <COMMAND>
Commands:
list Era list command
generate-tx-datum Era tx datum generate command
generate-keypair Era keypair generation command
help Print this message or the help of the given subcommand(s)

Options:
Expand Down Expand Up @@ -401,6 +402,7 @@ Here are the available subcommands:
| **genesis generate-keypair** | Generates a genesis keypair |
| **era list** | Lists the supported eras |
| **era generate-tx-datum** | Generates the era markers transaction datum to be stored on-chain |
| **era generate-keypair** | Generates an era keypair |
| **tools recompute-certificates-hash** | Loads all certificates in the database, recomputing their hash, and updating all related entities |

## Configuration parameters
Expand Down Expand Up @@ -506,4 +508,10 @@ Here is a list of the available parameters:
| `era_markers_secret_key` | `--era-markers-secret-key` | - | `ERA_MARKERS_SECRET_KEY` | Era markers secret key that is used to verify the authenticity of the era markers on the chain. | - | - | :heavy_check_mark: |
| `target_path` | `--target-path` | - | - | Path of the file to export the payload to. | - | - | - |

`era generate-keypair` command:

| Parameter | Command line (long) | Command line (short) | Environment variable | Description | Default value | Example | Mandatory |
| ------------- | ------------------- | :------------------: | -------------------- | ------------------------------------- | ------------- | ------- | :----------------: |
| `target_path` | `--target-path` | - | - | Target path for the generated keypair | - | - | :heavy_check_mark: |

The `tools recompute-certificates-hash` command has no dedicated parameters.
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.6.26"
version = "0.6.27"
description = "A Mithril Aggregator server"
authors = { workspace = true }
edition = { workspace = true }
Expand Down
31 changes: 31 additions & 0 deletions mithril-aggregator/src/commands/era_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ pub enum EraSubCommand {

/// Era tx datum generate command.
GenerateTxDatum(GenerateTxDatumEraSubCommand),

/// Era keypair generation command.
GenerateKeypair(GenerateKeypairEraSubCommand),
}

impl EraSubCommand {
Expand All @@ -51,6 +54,7 @@ impl EraSubCommand {
match self {
Self::List(cmd) => cmd.execute(root_logger, config_builder).await,
Self::GenerateTxDatum(cmd) => cmd.execute(root_logger, config_builder).await,
Self::GenerateKeypair(cmd) => cmd.execute(root_logger, config_builder).await,
}
}
}
Expand Down Expand Up @@ -129,3 +133,30 @@ impl GenerateTxDatumEraSubCommand {
Ok(())
}
}

/// Era keypair generation command.
#[derive(Parser, Debug, Clone)]
pub struct GenerateKeypairEraSubCommand {
/// Target path for the generated keypair
#[clap(long)]
target_path: PathBuf,
}

impl GenerateKeypairEraSubCommand {
pub async fn execute(
&self,
root_logger: Logger,
_config_builder: ConfigBuilder<DefaultState>,
) -> StdResult<()> {
debug!(root_logger, "GENERATE KEYPAIR ERA command");
println!(
"Era generate keypair to {}",
self.target_path.to_string_lossy()
);

EraTools::create_and_save_era_keypair(&self.target_path)
.with_context(|| "era-tools: keypair generation error")?;

Ok(())
}
}
48 changes: 48 additions & 0 deletions mithril-aggregator/src/tools/era.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::{Path, PathBuf};

use anyhow::anyhow;
use mithril_common::{
chain_observer::{TxDatumBuilder, TxDatumFieldValue},
Expand Down Expand Up @@ -56,16 +58,41 @@ impl EraTools {
.build()?;
Ok(tx_datum.0)
}

/// Export the era keypair to a folder and returns the paths to the files (secret key, verification_key)
pub fn create_and_save_era_keypair(keypair_path: &Path) -> StdResult<(PathBuf, PathBuf)> {
let era_signer = EraMarkersSigner::create_non_deterministic_signer();
let era_secret_key_path = keypair_path.join("era.sk");
era_signer
.secret_key()
.write_json_hex_to_file(&era_secret_key_path)?;
let era_verification_key_path = keypair_path.join("era.vk");
era_signer
.verification_key()
.write_json_hex_to_file(&era_verification_key_path)?;

Ok((era_secret_key_path, era_verification_key_path))
}
}

#[cfg(test)]
mod tests {
use mithril_common::{
crypto_helper::{EraMarkersVerifierSecretKey, EraMarkersVerifierVerificationKey},
test_utils::TempDir,
};
use std::fs::read_to_string;

use super::*;

fn build_tools() -> EraTools {
EraTools {}
}

fn get_temp_dir(dir_name: &str) -> PathBuf {
TempDir::create("era", dir_name)
}

#[test]
fn get_supported_eras_list() {
let era_tools = build_tools();
Expand All @@ -92,4 +119,25 @@ mod tests {
.generate_tx_datum(Epoch(3), Some(Epoch(2)), &era_markers_signer)
.expect_err("generate_tx_datum should have failed");
}

#[test]
fn test_create_and_save_era_keypair() {
let temp_dir = get_temp_dir("test_create_and_save_era_keypair");
let (era_secret_key_path, era_verification_key_path) =
EraTools::create_and_save_era_keypair(&temp_dir)
.expect("Failed to create and save era keypair");
let era_secret_key = EraMarkersVerifierSecretKey::from_json_hex(
&read_to_string(&era_secret_key_path).expect("Failed to read era secret key file"),
)
.expect("Failed to parse era secret key");
let era_verification_key = EraMarkersVerifierVerificationKey::from_json_hex(
&read_to_string(&era_verification_key_path)
.expect("Failed to read era verification key file"),
)
.expect("Failed to parse era verification key");
let era_verifier = EraMarkersSigner::from_secret_key(era_secret_key).create_verifier();

let expected_era_verification_key = era_verifier.to_verification_key();
assert_eq!(expected_era_verification_key, era_verification_key);
}
}
2 changes: 1 addition & 1 deletion mithril-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-common"
version = "0.4.112"
version = "0.4.113"
description = "Common types, interfaces, and utilities for Mithril nodes."
authors = { workspace = true }
edition = { workspace = true }
Expand Down
11 changes: 10 additions & 1 deletion mithril-common/src/crypto_helper/era.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,22 @@ impl EraMarkersSigner {
Self::create_test_signer(rng)
}

#[cfg(test)]
/// [EraMarkersSigner] non deterministic
pub fn create_non_deterministic_signer() -> Self {
let rng = rand_core::OsRng;
Self::create_test_signer(rng)
}

/// Get the [EraMarkersVerifierSecretKey]
pub fn secret_key(&self) -> EraMarkersVerifierSecretKey {
self.secret_key.clone()
}

/// Get the [EraMarkersVerifierVerificationKey]
pub fn verification_key(&self) -> EraMarkersVerifierVerificationKey {
self.secret_key.verifying_key().into()
}

/// [EraMarkersSigner] from [EraMarkersVerifierSecretKey]
pub fn from_secret_key(secret_key: EraMarkersVerifierSecretKey) -> Self {
Self { secret_key }
Expand Down
Loading