diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aa5f4093..904db239b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Enhancements +- Added `miden-genesis` tool for generating canonical AggLayer genesis accounts and configuration ([#1797](https://github.com/0xMiden/node/pull/1797)). +- Expose per-tree RocksDB tuning options ([#1782](https://github.com/0xMiden/node/pull/1782)). - Expose per-tree RocksDB tuning options ([#1782](https://github.com/0xMiden/node/pull/1782)). - Added a gRPC server to the NTX builder, configurable via `--ntx-builder.url` / `MIDEN_NODE_NTX_BUILDER_URL` (https://github.com/0xMiden/node/issues/1758). - Added `GetNoteError` gRPC endpoint to query the latest execution error for network notes (https://github.com/0xMiden/node/issues/1758). diff --git a/Cargo.lock b/Cargo.lock index 8e1d31e0b..d2a98a359 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2681,9 +2681,9 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miden-agglayer" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e492a6044cf8875a64d7eec130d260f2eda1c783795261f00d5d52837ed027bd" +checksum = "563f709601fc773bcb1782f0f5f1930894dbc627341df4af2bbd5040f21f4532" dependencies = [ "fs-err", "miden-assembly", @@ -2753,9 +2753,9 @@ dependencies = [ [[package]] name = "miden-block-prover" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9564dfb23c529aad68369845b6897a6f62bacdeab7c00db432a5f16670764d4" +checksum = "af7a73ebc8160af69c330a722263a83bd7f01103ff3c91b47b8ee7fb6b887726" dependencies = [ "miden-protocol", "thiserror 2.0.18", @@ -2871,9 +2871,28 @@ dependencies = [ "unicode-width 0.1.14", ] +[[package]] +name = "miden-genesis" +version = "0.14.0-alpha.8" +dependencies = [ + "anyhow", + "clap", + "fs-err", + "hex", + "miden-agglayer", + "miden-node-store", + "miden-node-utils", + "miden-protocol", + "miden-standards", + "rand", + "rand_chacha", + "tempfile", + "tokio", +] + [[package]] name = "miden-large-smt-backend-rocksdb" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "miden-crypto", "miden-node-rocksdb-cxx-linkage-fix", @@ -2939,7 +2958,7 @@ dependencies = [ [[package]] name = "miden-network-monitor" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "axum", @@ -2967,7 +2986,7 @@ dependencies = [ [[package]] name = "miden-node" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "clap", @@ -2987,7 +3006,7 @@ dependencies = [ [[package]] name = "miden-node-block-producer" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -3023,7 +3042,7 @@ dependencies = [ [[package]] name = "miden-node-db" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "deadpool", "deadpool-diesel", @@ -3036,7 +3055,7 @@ dependencies = [ [[package]] name = "miden-node-grpc-error-macro" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "quote", "syn 2.0.114", @@ -3044,7 +3063,7 @@ dependencies = [ [[package]] name = "miden-node-ntx-builder" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "build-rs", @@ -3077,7 +3096,7 @@ dependencies = [ [[package]] name = "miden-node-proto" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -3102,7 +3121,7 @@ dependencies = [ [[package]] name = "miden-node-proto-build" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "build-rs", "fs-err", @@ -3113,11 +3132,11 @@ dependencies = [ [[package]] name = "miden-node-rocksdb-cxx-linkage-fix" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" [[package]] name = "miden-node-rpc" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "futures", @@ -3149,7 +3168,7 @@ dependencies = [ [[package]] name = "miden-node-store" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -3196,7 +3215,7 @@ dependencies = [ [[package]] name = "miden-node-stress-test" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "clap", "fs-err", @@ -3225,7 +3244,7 @@ dependencies = [ [[package]] name = "miden-node-utils" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "bytes", @@ -3258,7 +3277,7 @@ dependencies = [ [[package]] name = "miden-node-validator" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "aws-config", @@ -3303,9 +3322,9 @@ dependencies = [ [[package]] name = "miden-protocol" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a88effeac994eb55b8dc4f93fbfd71a5d916dfaba1099896e27a0ee42c488c1" +checksum = "9fa3569c557146d3c4a4f48449f5c14ec94c43b6d22491d79c2b87617ac06ce8" dependencies = [ "bech32", "fs-err", @@ -3334,9 +3353,9 @@ dependencies = [ [[package]] name = "miden-protocol-macros" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb28b730005e5f8b08d615ea9216f8cab77b3a7439fa54d5e39d2ec43ef53a3" +checksum = "6e32fb40b2bc29e534da52691d3cd32d0207878171128d0ce5c2d2ecfa019fc5" dependencies = [ "proc-macro2", "quote", @@ -3359,7 +3378,7 @@ dependencies = [ [[package]] name = "miden-remote-prover" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -3396,7 +3415,7 @@ dependencies = [ [[package]] name = "miden-remote-prover-client" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" dependencies = [ "build-rs", "fs-err", @@ -3417,9 +3436,9 @@ dependencies = [ [[package]] name = "miden-standards" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cef036bbfec29acba92751a13d05844bbcf080140201097b419c9ad1927e367" +checksum = "d83ef3e49765ac3aa2a1defc853e0b130dfbd8480d91c9e49696d51186cdf839" dependencies = [ "fs-err", "miden-assembly", @@ -3435,9 +3454,9 @@ dependencies = [ [[package]] name = "miden-testing" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e980777d0f7e6069942b14d4e7cb3d4d137b323ddfa15722a3bd21e9d13fdd2e" +checksum = "98fb3700334c2b30c1e92966e3585c6790efb647b70c9eeef7c02423137c1782" dependencies = [ "anyhow", "itertools 0.14.0", @@ -3459,9 +3478,9 @@ dependencies = [ [[package]] name = "miden-tx" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c67e0df9adcf29c9111df65acf408ae05952b8bc6569f571963676f97668d83f" +checksum = "396e32105298b8fc6d0b9ae9f037c3243bcca5a1f31c27f90310856e468c01f8" dependencies = [ "miden-processor", "miden-protocol", @@ -3473,9 +3492,9 @@ dependencies = [ [[package]] name = "miden-tx-batch-prover" -version = "0.14.0-alpha.1" +version = "0.14.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba29f8f6ecae671eff8b52b4c19eca8db5964c0b45b5d68c3ce38a57a8367931" +checksum = "d4d4ac3e1778203c3336630311c8cfd0af77672356f96cd623d3c3e2398456fd" dependencies = [ "miden-protocol", "miden-tx", diff --git a/Cargo.toml b/Cargo.toml index 47fc2cbcf..93c0e9105 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "bin/genesis", "bin/network-monitor", "bin/node", "bin/remote-prover", @@ -31,7 +32,7 @@ license = "MIT" readme = "README.md" repository = "https://github.com/0xMiden/node" rust-version = "1.93" -version = "0.14.0-alpha.5" +version = "0.14.0-alpha.8" # Optimize the cryptography for faster tests involving account creation. [profile.test.package.miden-crypto] @@ -46,30 +47,30 @@ debug = true [workspace.dependencies] # Workspace crates. -miden-large-smt-backend-rocksdb = { path = "crates/large-smt-backend-rocksdb", version = "=0.14.0-alpha.5" } -miden-node-block-producer = { path = "crates/block-producer", version = "=0.14.0-alpha.5" } -miden-node-db = { path = "crates/db", version = "=0.14.0-alpha.5" } -miden-node-grpc-error-macro = { path = "crates/grpc-error-macro", version = "=0.14.0-alpha.5" } -miden-node-ntx-builder = { path = "crates/ntx-builder", version = "=0.14.0-alpha.5" } -miden-node-proto = { path = "crates/proto", version = "=0.14.0-alpha.5" } -miden-node-proto-build = { path = "proto", version = "=0.14.0-alpha.5" } -miden-node-rpc = { path = "crates/rpc", version = "=0.14.0-alpha.5" } -miden-node-store = { path = "crates/store", version = "=0.14.0-alpha.5" } +miden-large-smt-backend-rocksdb = { path = "crates/large-smt-backend-rocksdb", version = "=0.14.0-alpha.8" } +miden-node-block-producer = { path = "crates/block-producer", version = "=0.14.0-alpha.8" } +miden-node-db = { path = "crates/db", version = "=0.14.0-alpha.8" } +miden-node-grpc-error-macro = { path = "crates/grpc-error-macro", version = "=0.14.0-alpha.8" } +miden-node-ntx-builder = { path = "crates/ntx-builder", version = "=0.14.0-alpha.8" } +miden-node-proto = { path = "crates/proto", version = "=0.14.0-alpha.8" } +miden-node-proto-build = { path = "proto", version = "=0.14.0-alpha.8" } +miden-node-rpc = { path = "crates/rpc", version = "=0.14.0-alpha.8" } +miden-node-store = { path = "crates/store", version = "=0.14.0-alpha.8" } miden-node-test-macro = { path = "crates/test-macro" } -miden-node-utils = { path = "crates/utils", version = "=0.14.0-alpha.5" } -miden-node-validator = { path = "crates/validator", version = "=0.14.0-alpha.5" } -miden-remote-prover-client = { path = "crates/remote-prover-client", version = "=0.14.0-alpha.5" } +miden-node-utils = { path = "crates/utils", version = "=0.14.0-alpha.8" } +miden-node-validator = { path = "crates/validator", version = "=0.14.0-alpha.8" } +miden-remote-prover-client = { path = "crates/remote-prover-client", version = "=0.14.0-alpha.8" } # Temporary workaround until # is part of `rocksdb-rust` release -miden-node-rocksdb-cxx-linkage-fix = { path = "crates/rocksdb-cxx-linkage-fix", version = "=0.14.0-alpha.5" } +miden-node-rocksdb-cxx-linkage-fix = { path = "crates/rocksdb-cxx-linkage-fix", version = "=0.14.0-alpha.8" } # miden-base aka protocol dependencies. These should be updated in sync. -miden-block-prover = { version = "=0.14.0-alpha.1" } -miden-protocol = { default-features = false, version = "=0.14.0-alpha.1" } -miden-standards = { version = "=0.14.0-alpha.1" } -miden-testing = { version = "=0.14.0-alpha.1" } -miden-tx = { default-features = false, version = "=0.14.0-alpha.1" } -miden-tx-batch-prover = { version = "=0.14.0-alpha.1" } +miden-block-prover = { version = "=0.14.0-alpha.2" } +miden-protocol = { default-features = false, version = "=0.14.0-alpha.2" } +miden-standards = { version = "=0.14.0-alpha.2" } +miden-testing = { version = "=0.14.0-alpha.2" } +miden-tx = { default-features = false, version = "=0.14.0-alpha.2" } +miden-tx-batch-prover = { version = "=0.14.0-alpha.2" } # Other miden dependencies. These should align with those expected by miden-base. miden-air = { features = ["std", "testing"], version = "0.20" } diff --git a/bin/genesis/Cargo.toml b/bin/genesis/Cargo.toml new file mode 100644 index 000000000..ac4296120 --- /dev/null +++ b/bin/genesis/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors.workspace = true +description = "A tool for generating canonical Miden genesis accounts and configuration" +edition.workspace = true +exclude.workspace = true +homepage.workspace = true +keywords = ["genesis", "miden"] +license.workspace = true +name = "miden-genesis" +publish = false +readme.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[lints] +workspace = true + +[dependencies] +anyhow = { workspace = true } +clap = { workspace = true } +fs-err = { workspace = true } +hex = { workspace = true } +miden-agglayer = { version = "=0.14.0-alpha.2" } +miden-protocol = { features = ["std"], workspace = true } +miden-standards = { workspace = true } +rand = { workspace = true } +rand_chacha = { workspace = true } + +[dev-dependencies] +miden-node-store = { workspace = true } +miden-node-utils = { workspace = true } +tempfile = { workspace = true } +tokio = { features = ["macros", "rt-multi-thread"], workspace = true } diff --git a/bin/genesis/README.md b/bin/genesis/README.md new file mode 100644 index 000000000..ddd9f0a5f --- /dev/null +++ b/bin/genesis/README.md @@ -0,0 +1,60 @@ +# Miden Genesis + +A tool for generating canonical Miden genesis accounts and configuration. + +## Usage + +Generate all genesis accounts with fresh keypairs: + +```bash +miden-genesis --output-dir ./genesis +``` + +Provide existing Falcon512 public keys (both must be specified together): + +```bash +miden-genesis --output-dir ./genesis \ + --bridge-admin-public-key \ + --ger-manager-public-key +``` + +## Output + +The tool generates the following files in the output directory: + +- `bridge_admin.mac` - Bridge admin wallet (nonce=0, deployed later via transaction) +- `ger_manager.mac` - GER manager wallet (nonce=0, deployed later via transaction) +- `bridge.mac` - AggLayer bridge account (nonce=1, included in genesis block) +- `genesis.toml` - Genesis configuration referencing only `bridge.mac` + +When public keys are omitted, the `.mac` files for bridge admin and GER manager include generated secret keys. When public keys are provided, no secret keys are included. + +The bridge account always uses NoAuth and has no secret keys. + +## Bootstrapping a node + +```bash +# 1. Generate genesis accounts +miden-genesis --output-dir ./genesis + +# 2. Bootstrap the genesis block +miden-node validator bootstrap \ + --genesis-block-directory ./data \ + --accounts-directory ./accounts \ + --genesis-config-file ./genesis/genesis.toml \ + --validator.key.hex + +# 3. Bootstrap the store +miden-node store bootstrap --data-directory ./data + +# 4. Start the node +miden-node bundled start --data-directory ./data ... +``` + +## TODO + +- Support ECDSA (secp256k1) public keys in addition to Falcon512 (e.g. `--bridge-admin-public-key ecdsa:`) + +## License + +This project is [MIT licensed](../../LICENSE). diff --git a/bin/genesis/src/main.rs b/bin/genesis/src/main.rs new file mode 100644 index 000000000..425dc159d --- /dev/null +++ b/bin/genesis/src/main.rs @@ -0,0 +1,254 @@ +use std::path::{Path, PathBuf}; +use std::time::{SystemTime, UNIX_EPOCH}; + +use anyhow::Context; +use clap::Parser; +use miden_agglayer::create_bridge_account; +use miden_protocol::account::auth::{AuthScheme, AuthSecretKey}; +use miden_protocol::account::delta::{AccountStorageDelta, AccountVaultDelta}; +use miden_protocol::account::{ + Account, + AccountDelta, + AccountFile, + AccountStorageMode, + AccountType, +}; +use miden_protocol::crypto::dsa::falcon512_rpo::{self, SecretKey as RpoSecretKey}; +use miden_protocol::crypto::rand::RpoRandomCoin; +use miden_protocol::utils::Deserializable; +use miden_protocol::{Felt, ONE, Word}; +use miden_standards::AuthMethod; +use miden_standards::account::wallets::create_basic_wallet; +use rand::Rng; +use rand_chacha::ChaCha20Rng; +use rand_chacha::rand_core::SeedableRng; + +/// Generate canonical Miden genesis accounts (bridge, bridge admin, GER manager) +/// and a genesis.toml configuration file. +#[derive(Parser)] +#[command(name = "miden-genesis")] +struct Cli { + /// Output directory for generated files. + #[arg(long, default_value = "./genesis")] + output_dir: PathBuf, + + /// Hex-encoded Falcon512 public key for the bridge admin account. + /// If omitted, a new keypair is generated and the secret key is included in the .mac file. + #[arg(long, value_name = "HEX", requires = "ger_manager_public_key")] + bridge_admin_public_key: Option, + + /// Hex-encoded Falcon512 public key for the GER manager account. + /// If omitted, a new keypair is generated and the secret key is included in the .mac file. + #[arg(long, value_name = "HEX", requires = "bridge_admin_public_key")] + ger_manager_public_key: Option, +} + +fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + run( + &cli.output_dir, + cli.bridge_admin_public_key.as_deref(), + cli.ger_manager_public_key.as_deref(), + ) +} + +fn run( + output_dir: &Path, + bridge_admin_public_key: Option<&str>, + ger_manager_public_key: Option<&str>, +) -> anyhow::Result<()> { + fs_err::create_dir_all(output_dir).context("failed to create output directory")?; + + // Generate or parse bridge admin key. + let (bridge_admin_pub, bridge_admin_secret) = + resolve_pubkey(bridge_admin_public_key, "bridge admin")?; + + // Generate or parse GER manager key. + let (ger_manager_pub, ger_manager_secret) = + resolve_pubkey(ger_manager_public_key, "GER manager")?; + + // Create bridge admin wallet (nonce=0, local account to be deployed later). + let bridge_admin = create_basic_wallet( + rand::random(), + AuthMethod::SingleSig { + approver: (bridge_admin_pub.into(), AuthScheme::Falcon512Rpo), + }, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Public, + ) + .context("failed to create bridge admin account")?; + let bridge_admin_id = bridge_admin.id(); + + // Create GER manager wallet (nonce=0, local account to be deployed later). + let ger_manager = create_basic_wallet( + rand::random(), + AuthMethod::SingleSig { + approver: (ger_manager_pub.into(), AuthScheme::Falcon512Rpo), + }, + AccountType::RegularAccountImmutableCode, + AccountStorageMode::Public, + ) + .context("failed to create GER manager account")?; + let ger_manager_id = ger_manager.id(); + + // Create bridge account (NoAuth, nonce=0), then bump nonce to 1 for genesis. + let mut rng = ChaCha20Rng::from_seed(rand::random()); + let bridge_seed: [u64; 4] = rng.random(); + let bridge_seed = Word::from(bridge_seed.map(Felt::new)); + let bridge = create_bridge_account(bridge_seed, bridge_admin_id, ger_manager_id); + + // Bump bridge nonce to 1 (required for genesis accounts). + // File-loaded accounts via [[account]] in genesis.toml are included as-is, + // so we must set nonce=1 before writing the .mac file. + let bridge = bump_nonce_to_one(bridge).context("failed to bump bridge account nonce")?; + + // Write .mac files. + let bridge_admin_secrets = bridge_admin_secret + .map(|sk| vec![AuthSecretKey::Falcon512Rpo(sk)]) + .unwrap_or_default(); + AccountFile::new(bridge_admin, bridge_admin_secrets) + .write(output_dir.join("bridge_admin.mac")) + .context("failed to write bridge_admin.mac")?; + + let ger_manager_secrets = ger_manager_secret + .map(|sk| vec![AuthSecretKey::Falcon512Rpo(sk)]) + .unwrap_or_default(); + AccountFile::new(ger_manager, ger_manager_secrets) + .write(output_dir.join("ger_manager.mac")) + .context("failed to write ger_manager.mac")?; + + let bridge_id = bridge.id(); + AccountFile::new(bridge, vec![]) + .write(output_dir.join("bridge.mac")) + .context("failed to write bridge.mac")?; + + // Write genesis.toml. + let timestamp = u32::try_from( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time before UNIX epoch") + .as_secs(), + ) + .expect("timestamp should fit in a u32 before the year 2106"); + + let genesis_toml = format!( + r#"version = 1 +timestamp = {timestamp} + +[fee_parameters] +verification_base_fee = 0 + +[[account]] +path = "bridge.mac" +"#, + ); + + fs_err::write(output_dir.join("genesis.toml"), genesis_toml) + .context("failed to write genesis.toml")?; + + println!("Genesis files written to {}", output_dir.display()); + println!(" bridge_admin.mac (id: {})", bridge_admin_id.to_hex()); + println!(" ger_manager.mac (id: {})", ger_manager_id.to_hex()); + println!(" bridge.mac (id: {})", bridge_id.to_hex()); + println!(" genesis.toml"); + + Ok(()) +} + +/// Generates a new Falcon512 keypair using a random seed. +fn generate_falcon_keypair() -> (falcon512_rpo::PublicKey, RpoSecretKey) { + let mut rng = ChaCha20Rng::from_seed(rand::random()); + let auth_seed: [u64; 4] = rng.random(); + let mut coin = RpoRandomCoin::new(Word::from(auth_seed.map(Felt::new))); + let secret_key = RpoSecretKey::with_rng(&mut coin); + let public_key = secret_key.public_key(); + (public_key, secret_key) +} + +/// Resolves a Falcon512 key pair: either parses the provided hex public key or generates a new +/// keypair. +fn resolve_pubkey( + hex_pubkey: Option<&str>, + label: &str, +) -> anyhow::Result<(falcon512_rpo::PublicKey, Option)> { + if let Some(hex_str) = hex_pubkey { + let bytes = + hex::decode(hex_str).with_context(|| format!("invalid hex for {label} public key"))?; + let pubkey = falcon512_rpo::PublicKey::read_from_bytes(&bytes) + .with_context(|| format!("failed to deserialize {label} public key"))?; + Ok((pubkey, None)) + } else { + let (public_key, secret_key) = generate_falcon_keypair(); + Ok((public_key, Some(secret_key))) + } +} + +/// Bumps an account's nonce from 0 to 1 using an `AccountDelta`. +fn bump_nonce_to_one(mut account: Account) -> anyhow::Result { + let delta = AccountDelta::new( + account.id(), + AccountStorageDelta::default(), + AccountVaultDelta::default(), + ONE, + )?; + account.apply_delta(&delta)?; + Ok(account) +} + +#[cfg(test)] +mod tests { + use miden_node_store::genesis::config::GenesisConfig; + use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SecretKey; + use miden_protocol::utils::Serializable; + + use super::*; + + /// Parses the generated genesis.toml, builds a genesis block, and asserts the bridge account + /// is included with nonce=1. + async fn assert_valid_genesis_block(dir: &Path) { + let bridge_id = AccountFile::read(dir.join("bridge.mac")).unwrap().account.id(); + + let config = GenesisConfig::read_toml_file(&dir.join("genesis.toml")).unwrap(); + let signer = SecretKey::read_from_bytes(&[0x01; 32]).unwrap(); + let (state, _) = config.into_state(signer).unwrap(); + + let bridge = state.accounts.iter().find(|a| a.id() == bridge_id).unwrap(); + assert_eq!(bridge.nonce(), ONE); + + state.into_block().await.expect("genesis block should build"); + } + + #[tokio::test] + async fn default_mode_includes_secret_keys() { + let dir = tempfile::tempdir().unwrap(); + run(dir.path(), None, None).unwrap(); + + let admin = AccountFile::read(dir.path().join("bridge_admin.mac")).unwrap(); + assert_eq!(admin.auth_secret_keys.len(), 1); + + let ger = AccountFile::read(dir.path().join("ger_manager.mac")).unwrap(); + assert_eq!(ger.auth_secret_keys.len(), 1); + + assert_valid_genesis_block(dir.path()).await; + } + + #[tokio::test] + async fn custom_public_keys_excludes_secret_keys() { + let dir = tempfile::tempdir().unwrap(); + + let (admin_pub, _) = generate_falcon_keypair(); + let (ger_pub, _) = generate_falcon_keypair(); + let admin_hex = hex::encode((&admin_pub).to_bytes()); + let ger_hex = hex::encode((&ger_pub).to_bytes()); + + run(dir.path(), Some(&admin_hex), Some(&ger_hex)).unwrap(); + + let admin = AccountFile::read(dir.path().join("bridge_admin.mac")).unwrap(); + assert!(admin.auth_secret_keys.is_empty()); + + let ger = AccountFile::read(dir.path().join("ger_manager.mac")).unwrap(); + assert!(ger.auth_secret_keys.is_empty()); + + assert_valid_genesis_block(dir.path()).await; + } +} diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 7c8135d97..e6ec70f79 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -53,7 +53,7 @@ url = { workspace = true } [build-dependencies] build-rs = { workspace = true } fs-err = { workspace = true } -miden-agglayer = { features = ["testing"], version = "=0.14.0-alpha.1" } +miden-agglayer = { features = ["testing"], version = "=0.14.0-alpha.2" } miden-protocol = { features = ["std"], workspace = true } miden-standards = { workspace = true }